From 344bbd57f458fbd7f37f287c32a01f2b38c8aec1 Mon Sep 17 00:00:00 2001 From: "Matthijs S. Berends" Date: Thu, 25 Jun 2020 17:34:50 +0200 Subject: [PATCH] (v1.2.0.9014) ab_from_text() --- DESCRIPTION | 4 +- NEWS.md | 12 +- R/ab.R | 286 ++++++++++++++--------- R/ab_from_text.R | 74 ++++++ R/like.R | 2 +- R/proportion.R | 2 +- R/rsi_calc.R | 26 ++- data-raw/antibiotics.txt | 2 +- data-raw/reproduction_of_antibiotics.R | 4 + data/antibiotics.rda | Bin 37114 -> 37134 bytes docs/404.html | 2 +- docs/LICENSE-text.html | 2 +- docs/articles/index.html | 2 +- docs/authors.html | 2 +- docs/index.html | 2 +- docs/news/index.html | 98 ++++---- docs/pkgdown.yml | 2 +- docs/reference/ab_from_text.html | 305 +++++++++++++++++++++++++ docs/reference/as.ab.html | 9 +- docs/reference/as.rsi.html | 2 +- docs/reference/count.html | 6 +- docs/reference/ggplot_rsi.html | 4 +- docs/reference/index.html | 2 +- docs/reference/mo_property.html | 2 +- docs/reference/proportion.html | 4 +- docs/sitemap.xml | 3 + man/ab_from_text.Rd | 38 +++ man/as.ab.Rd | 5 +- man/count.Rd | 2 +- man/ggplot_rsi.Rd | 2 +- man/proportion.Rd | 2 +- tests/testthat/test-ab_from_text.R | 32 +++ 32 files changed, 749 insertions(+), 191 deletions(-) create mode 100644 R/ab_from_text.R create mode 100644 docs/reference/ab_from_text.html create mode 100644 man/ab_from_text.Rd create mode 100644 tests/testthat/test-ab_from_text.R diff --git a/DESCRIPTION b/DESCRIPTION index e5a0937b..c44e49c6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: AMR -Version: 1.2.0.9013 -Date: 2020-06-22 +Version: 1.2.0.9014 +Date: 2020-06-25 Title: Antimicrobial Resistance Analysis Authors@R: c( person(role = c("aut", "cre"), diff --git a/NEWS.md b/NEWS.md index c3daabc8..ebe195af 100755 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,12 @@ -# AMR 1.2.0.9013 -## Last updated: 22-Jun-2020 +# AMR 1.2.0.9014 +## Last updated: 25-Jun-2020 ### New +* Function `ab_from_text()` to retrieve antimicrobial drugs from clinical texts in e.g. health care records, which also corrects for misspelling since it uses `as.ab()` internally: + ```r + ab_from_text("28/03/2020 regular amoxiciliin 500mg po tds") + #> [1] "Amoxicillin" + ``` * [Tidyverse selections](https://tidyselect.r-lib.org/reference/language.html) for antibiotic classes, that help to select the columns of antibiotics that are of a specific antibiotic class, without the need to define the columns or antibiotic abbreviations. They can be used in any function that allows Tidyverse selections, like `dplyr::select()` and `tidyr::pivot_longer()`: ```r library(dplyr) @@ -26,6 +31,7 @@ * Added antibiotics code "FOX1" for cefoxitin screening (abbreviation "cfsc") to the `antibiotics` data set ### Changed +* Fixed a bug for using `susceptibility` or `resistance()` outside `summarise()` * Fixed a bug where `eucast_rules()` would not work on a tibble when the `tibble` or `dplyr` package was loaded * All `*_join_microorganisms()` functions and `bug_drug_combinations()` now return the original data class (e.g. `tibble`s and `data.table`s) * Fixed a bug where `as.ab()` would return an error on invalid input values @@ -34,6 +40,8 @@ * Fixed a bug in `bug_drug_combinations()` for when only one antibiotic was in the input data * Changed the summary for class ``, to highlight the %SI vs. %R * Improved error handling, giving more useful info when functions return an error +* Algorithm improvements to `as.ab()` +* Added Monuril as trade name for fosfomycin # AMR 1.2.0 diff --git a/R/ab.R b/R/ab.R index baf11e39..31da9d82 100755 --- a/R/ab.R +++ b/R/ab.R @@ -30,6 +30,7 @@ #' @details All entries in the [antibiotics] data set have three different identifiers: a human readable EARS-Net code (column `ab`, used by ECDC and WHONET), an ATC code (column `atc`, used by WHO), and a CID code (column `cid`, Compound ID, used by PubChem). The data set contains more than 5,000 official brand names from many different countries, as found in PubChem. #' #' Use the [ab_property()] functions to get properties based on the returned antibiotic ID, see Examples. +#' #' @section Source: #' World Health Organization (WHO) Collaborating Centre for Drug Statistics Methodology: \url{https://www.whocc.no/atc_ddd_index/} #' @@ -38,7 +39,9 @@ #' European Commission Public Health PHARMACEUTICALS - COMMUNITY REGISTER: \url{http://ec.europa.eu/health/documents/community-register/html/atc.htm} #' @aliases ab #' @return Character (vector) with class [`ab`]. Unknown values will return `NA`. -#' @seealso [antibiotics] for the dataframe that is being used to determine ATCs. +#' @seealso +#' * [antibiotics] for the dataframe that is being used to determine ATCs +#' * [ab_from_text()] for a function to retrieve antimicrobial drugs from clinical text (from health care records) #' @inheritSection AMR Read more on our website! #' @export #' @examples @@ -72,6 +75,9 @@ as.ab <- function(x, ...) { return(x) } + initial <- is.null(list(...)$initial) + already_regex <- isTRUE(list(...)$already_regex) + if (all(toupper(x) %in% antibiotics$ab)) { # valid AB code, but not yet right class return(structure(.Data = toupper(x), @@ -79,26 +85,30 @@ as.ab <- function(x, ...) { } x_bak <- x + x <- toupper(x) # remove diacritics x <- iconv(x, from = "UTF-8", to = "ASCII//TRANSLIT") x <- gsub('"', "", x, fixed = TRUE) - # remove suffices - x_bak_clean <- gsub("_(mic|rsi|dis[ck])$", "", x, ignore.case = TRUE) - # remove disk concentrations, like LVX_NM -> LVX - x_bak_clean <- gsub("_[A-Z]{2}[0-9_.]{0,3}$", "", x_bak_clean, ignore.case = TRUE) - # remove part between brackets if that's followed by another string - x_bak_clean <- gsub("(.*)+ [(].*[)]", "\\1", x_bak_clean) - # keep only max 1 space - x_bak_clean <- trimws(gsub(" +", " ", x_bak_clean, ignore.case = TRUE)) - # non-character, space or number should be a slash - x_bak_clean <- gsub("[^A-Za-z0-9 -]", "/", x_bak_clean) - # spaces around non-characters must be removed: amox + clav -> amox/clav - x_bak_clean <- gsub("(.*[a-zA-Z0-9]) ([^a-zA-Z0-9].*)", "\\1\\2", x_bak_clean) - x_bak_clean <- gsub("(.*[^a-zA-Z0-9]) ([a-zA-Z0-9].*)", "\\1\\2", x_bak_clean) - # remove hyphen after a starting "co" - x_bak_clean <- gsub("^co-", "co", x_bak_clean, ignore.case = TRUE) - # replace text 'and' with a slash - x_bak_clean <- gsub(" and ", "/", x_bak_clean, ignore.case = TRUE) + x_bak_clean <- x + if (already_regex == FALSE) { + # remove suffices + x_bak_clean <- gsub("_(MIC|RSI|DIS[CK])$", "", x_bak_clean) + # remove disk concentrations, like LVX_NM -> LVX + x_bak_clean <- gsub("_[A-Z]{2}[0-9_.]{0,3}$", "", x_bak_clean) + # remove part between brackets if that's followed by another string + x_bak_clean <- gsub("(.*)+ [(].*[)]", "\\1", x_bak_clean) + # keep only max 1 space + x_bak_clean <- trimws(gsub(" +", " ", x_bak_clean)) + # non-character, space or number should be a slash + x_bak_clean <- gsub("[^A-Z0-9 -]", "/", x_bak_clean) + # spaces around non-characters must be removed: amox + clav -> amox/clav + x_bak_clean <- gsub("(.*[A-Z0-9]) ([^A-Z0-9].*)", "\\1\\2", x_bak_clean) + x_bak_clean <- gsub("(.*[^A-Z0-9]) ([A-Z0-9].*)", "\\1\\2", x_bak_clean) + # remove hyphen after a starting "co" + x_bak_clean <- gsub("^CO-", "CO", x_bak_clean) + # replace text 'and' with a slash + x_bak_clean <- gsub(" AND ", "/", x_bak_clean) + } x <- unique(x_bak_clean) x_new <- rep(NA_character_, length(x)) @@ -118,14 +128,14 @@ as.ab <- function(x, ...) { } # exact AB code - found <- antibiotics[which(antibiotics$ab == toupper(x[i])), ]$ab + found <- antibiotics[which(antibiotics$ab == x[i]), ]$ab if (length(found) > 0) { x_new[i] <- found[1L] next } # exact ATC code - found <- antibiotics[which(antibiotics$atc == toupper(x[i])), ]$ab + found <- antibiotics[which(antibiotics$atc == x[i]), ]$ab if (length(found) > 0) { x_new[i] <- found[1L] next @@ -139,7 +149,7 @@ as.ab <- function(x, ...) { } # exact name - found <- antibiotics[which(toupper(antibiotics$name) == toupper(x[i])), ]$ab + found <- antibiotics[which(toupper(antibiotics$name) == x[i]), ]$ab if (length(found) > 0) { x_new[i] <- found[1L] next @@ -147,11 +157,7 @@ as.ab <- function(x, ...) { # exact LOINC code loinc_found <- unlist(lapply(antibiotics$loinc, - function(s) if (x[i] %in% s) { - TRUE - } else { - FALSE - })) + function(s) x[i] %in% s)) found <- antibiotics$ab[loinc_found == TRUE] if (length(found) > 0) { x_new[i] <- found[1L] @@ -160,11 +166,7 @@ as.ab <- function(x, ...) { # exact synonym synonym_found <- unlist(lapply(antibiotics$synonyms, - function(s) if (toupper(x[i]) %in% toupper(s)) { - TRUE - } else { - FALSE - })) + function(s) x[i] %in% toupper(s))) found <- antibiotics$ab[synonym_found == TRUE] if (length(found) > 0) { x_new[i] <- found[1L] @@ -173,90 +175,87 @@ as.ab <- function(x, ...) { # exact abbreviation abbr_found <- unlist(lapply(antibiotics$abbreviations, - function(a) if (toupper(x[i]) %in% toupper(a)) { - TRUE - } else { - FALSE - })) + function(a) x[i] %in% toupper(a))) found <- antibiotics$ab[abbr_found == TRUE] if (length(found) > 0) { x_new[i] <- found[1L] next } - # first >=4 characters of name - if (nchar(x[i]) >= 4) { - found <- antibiotics[which(toupper(antibiotics$name) %like% paste0("^", x[i])), ]$ab - if (length(found) > 0) { - x_new[i] <- found[1L] - next - } - } - # allow characters that resemble others, but only continue when having more than 3 characters if (nchar(x[i]) <= 3) { x_unknown <- c(x_unknown, x_bak[x[i] == x_bak_clean][1]) next } - x_spelling <- tolower(x[i]) - x_spelling <- gsub("[iy]+", "[iy]+", x_spelling) - x_spelling <- gsub("(c|k|q|qu|s|z|x|ks)+", "(c|k|q|qu|s|z|x|ks)+", x_spelling) - x_spelling <- gsub("(ph|f|v)+", "(ph|f|v)+", x_spelling) - x_spelling <- gsub("(th|t)+", "(th|t)+", x_spelling) - x_spelling <- gsub("a+", "a+", x_spelling) - x_spelling <- gsub("e+", "e+", x_spelling) - x_spelling <- gsub("o+", "o+", x_spelling) - # allow any ending of -in/-ine and -im/-ime - x_spelling <- gsub("(\\[iy\\]\\+(n|m)|\\[iy\\]\\+(n|m)e\\+)$", "[iy]+(n|m)e*", x_spelling) - # allow any ending of -ol/-ole - x_spelling <- gsub("(o\\+l|o\\+le\\+)$", "o+le*", x_spelling) - # allow any ending of -on/-one - x_spelling <- gsub("(o\\+n|o\\+ne\\+)$", "o+ne*", x_spelling) - # replace multiple same characters to single one with '+', like "ll" -> "l+" - x_spelling <- gsub("(.)\\1+", "\\1+", x_spelling) - # replace spaces and slashes with a possibility on both - x_spelling <- gsub("[ /]", "( .*|.*/)", x_spelling) - + x_spelling <- x[i] + if (already_regex == FALSE) { + x_spelling <- gsub("[IY]+", "[IY]+", x_spelling) + x_spelling <- gsub("(C|K|Q|QU|S|Z|X|KS)+", "(C|K|Q|QU|S|Z|X|KS)+", x_spelling) + x_spelling <- gsub("(PH|F|V)+", "(PH|F|V)+", x_spelling) + x_spelling <- gsub("(TH|T)+", "(TH|T)+", x_spelling) + x_spelling <- gsub("A+", "A+", x_spelling) + x_spelling <- gsub("E+", "E+", x_spelling) + x_spelling <- gsub("O+", "O+", x_spelling) + # allow any ending of -in/-ine and -im/-ime + x_spelling <- gsub("(\\[IY\\]\\+(N|M)|\\[IY\\]\\+(N|M)E\\+)$", "[IY]+(N|M)E*", x_spelling) + # allow any ending of -ol/-ole + x_spelling <- gsub("(O\\+L|O\\+LE\\+)$", "O+LE*", x_spelling) + # allow any ending of -on/-one + x_spelling <- gsub("(O\\+N|O\\+NE\\+)$", "O+NE*", x_spelling) + # replace multiple same characters to single one with '+', like "ll" -> "l+" + x_spelling <- gsub("(.)\\1+", "\\1+", x_spelling) + # replace spaces and slashes with a possibility on both + x_spelling <- gsub("[ /]", "( .*|.*/)", x_spelling) + # correct for digital reading text (OCR) + x_spelling <- gsub("[NRD]", "[NRD]", x_spelling) + } + # try if name starts with it found <- antibiotics[which(antibiotics$name %like% paste0("^", x_spelling)), ]$ab if (length(found) > 0) { x_new[i] <- found[1L] next } + # try if name ends with it + found <- antibiotics[which(antibiotics$name %like% paste0(x_spelling, "$")), ]$ab + if (nchar(x[i]) >= 4 & length(found) > 0) { + x_new[i] <- found[1L] + next + } # and try if any synonym starts with it synonym_found <- unlist(lapply(antibiotics$synonyms, - function(s) if (any(s %like% paste0("^", x_spelling))) { - TRUE - } else { - FALSE - })) + function(s) any(s %like% paste0("^", x_spelling)))) found <- antibiotics$ab[synonym_found == TRUE] if (length(found) > 0) { x_new[i] <- found[1L] next } - - # try by removing all spaces - if (x[i] %like% " ") { - found <- suppressWarnings(as.ab(gsub(" +", "", x[i]))) - if (length(found) > 0 & !is.na(found)) { - x_new[i] <- found[1L] - next + + # INITIAL - More uncertain results ---- + + if (initial == TRUE) { + # only run on first try + + # try by removing all spaces + if (x[i] %like% " ") { + found <- suppressWarnings(as.ab(gsub(" +", "", x[i]), initial = FALSE)) + if (length(found) > 0 & !is.na(found)) { + x_new[i] <- found[1L] + next + } } - } - - # try by removing all spaces and numbers - if (x[i] %like% " " | x[i] %like% "[0-9]") { - found <- suppressWarnings(as.ab(gsub("[ 0-9]", "", x[i]))) - if (length(found) > 0 & !is.na(found)) { - x_new[i] <- found[1L] - next + + # try by removing all spaces and numbers + if (x[i] %like% " " | x[i] %like% "[0-9]") { + found <- suppressWarnings(as.ab(gsub("[ 0-9]", "", x[i]), initial = FALSE)) + if (length(found) > 0 & !is.na(found)) { + x_new[i] <- found[1L] + next + } } - } - - if (!isFALSE(list(...)$initial_search)) { + # transform back from other languages and try again - x_translated <- paste(lapply(strsplit(x[i], "[^a-zA-Z0-9 ]"), + x_translated <- paste(lapply(strsplit(x[i], "[^A-Z0-9 ]"), function(y) { for (i in seq_len(length(y))) { y[i] <- ifelse(tolower(y[i]) %in% tolower(translations_file$replacement), @@ -267,41 +266,102 @@ as.ab <- function(x, ...) { y })[[1]], collapse = "/") - x_translated_guess <- suppressWarnings(as.ab(x_translated, initial_search = FALSE)) + x_translated_guess <- suppressWarnings(as.ab(x_translated, initial = FALSE)) if (!is.na(x_translated_guess)) { x_new[i] <- x_translated_guess next } - if (!isFALSE(list(...)$initial_search2)) { - # now also try to coerce brandname combinations like "Amoxy/clavulanic acid" - x_translated <- paste(lapply(strsplit(x_translated, "[^a-zA-Z0-9 ]"), - function(y) { - for (i in seq_len(length(y))) { - y_name <- suppressWarnings(ab_name(y[i], language = NULL, initial_search = FALSE, initial_search2 = FALSE)) - y[i] <- ifelse(!is.na(y_name), - y_name, - y[i]) - } - y - })[[1]], - collapse = "/") - x_translated_guess <- suppressWarnings(as.ab(x_translated, initial_search = FALSE)) - if (!is.na(x_translated_guess)) { - x_new[i] <- x_translated_guess + # now also try to coerce brandname combinations like "Amoxy/clavulanic acid" + x_translated <- paste(lapply(strsplit(x_translated, "[^A-Z0-9 ]"), + function(y) { + for (i in seq_len(length(y))) { + y_name <- suppressWarnings(ab_name(y[i], language = NULL, initial = FALSE)) + y[i] <- ifelse(!is.na(y_name), + y_name, + y[i]) + } + y + })[[1]], + collapse = "/") + x_translated_guess <- suppressWarnings(as.ab(x_translated, initial = FALSE)) + if (!is.na(x_translated_guess)) { + x_new[i] <- x_translated_guess + next + } + + # try by removing all trailing capitals + if (x[i] %like_case% "[a-z]+[A-Z]+$") { + found <- suppressWarnings(as.ab(gsub("[A-Z]+$", "", x[i]), initial = FALSE)) + if (!is.na(found)) { + x_new[i] <- found[1L] next } } - } - - # try by removing all trailing capitals - if (x[i] %like_case% "[a-z]+[A-Z]+$") { - found <- suppressWarnings(as.ab(gsub("[A-Z]+$", "", x[i]))) - if (length(found) > 0 & !is.na(found)) { + + # keep only letters + found <- suppressWarnings(as.ab(gsub("[^A-Z]", "", x[i]), initial = FALSE)) + if (!is.na(found)) { x_new[i] <- found[1L] next } - } + + # try from a bigger text, like from a health care record, see ?ab_from_text + found <- suppressWarnings(ab_from_text(x[i], initial = FALSE, translate_ab = FALSE)[1L]) + if (!is.na(found)) { + x_new[i] <- found[1L] + next + } + + # first 5 except for cephalosporins, then first 7 (those cephalosporins all start quite the same!) + found <- suppressWarnings(as.ab(substr(x[i], 1, 5), initial = FALSE)) + if (!is.na(found) && !ab_group(found, initial = FALSE) %like% "cephalosporins") { + x_new[i] <- found[1L] + next + } + found <- suppressWarnings(as.ab(substr(x[i], 1, 7), initial = FALSE)) + if (!is.na(found)) { + x_new[i] <- found[1L] + next + } + + # make all consonants facultative + search_str <- gsub("([BCDFGHJKLMNPQRSTVWXZ])", "\\1*", x[i]) + found <- suppressWarnings(as.ab(search_str, initial = FALSE, already_regex = TRUE)) + # keep at least 4 normal characters + if (nchar(gsub(".\\*", "", search_str)) < 4) { + found <- NA + } + if (!is.na(found)) { + x_new[i] <- found[1L] + next + } + + # make all vowels facultative + search_str <- gsub("([AEIOUY])", "\\1*", x[i]) + found <- suppressWarnings(as.ab(search_str, initial = FALSE, already_regex = TRUE)) + # keep at least 5 normal characters + if (nchar(gsub(".\\*", "", search_str)) < 5) { + found <- NA + } + if (!is.na(found)) { + x_new[i] <- found[1L] + next + } + + # allow misspelling of vowels + x_spelling <- gsub("A+", "[AEIOU]+", x_spelling, fixed = TRUE) + x_spelling <- gsub("E+", "[AEIOU]+", x_spelling, fixed = TRUE) + x_spelling <- gsub("I+", "[AEIOU]+", x_spelling, fixed = TRUE) + x_spelling <- gsub("O+", "[AEIOU]+", x_spelling, fixed = TRUE) + x_spelling <- gsub("U+", "[AEIOU]+", x_spelling, fixed = TRUE) + found <- suppressWarnings(as.ab(x_spelling, initial = FALSE, already_regex = TRUE)) + if (!is.na(found)) { + x_new[i] <- found[1L] + next + } + + } # end of initial = TRUE # not found x_unknown <- c(x_unknown, x_bak[x[i] == x_bak_clean][1]) @@ -316,7 +376,7 @@ as.ab <- function(x, ...) { ".", call. = FALSE) } - + if (length(x_unknown) > 0) { warning("These values could not be coerced to a valid antimicrobial ID: ", paste('"', sort(unique(x_unknown)), '"', sep = "", collapse = ", "), diff --git a/R/ab_from_text.R b/R/ab_from_text.R new file mode 100644 index 00000000..2edef087 --- /dev/null +++ b/R/ab_from_text.R @@ -0,0 +1,74 @@ +# ==================================================================== # +# TITLE # +# Antimicrobial Resistance (AMR) Analysis # +# # +# SOURCE # +# https://gitlab.com/msberends/AMR # +# # +# LICENCE # +# (c) 2018-2020 Berends MS, Luz CF et al. # +# # +# This R package is free software; you can freely use and distribute # +# it for both personal and commercial purposes under the terms of the # +# GNU General Public License version 2.0 (GNU GPL-2), as published by # +# the Free Software Foundation. # +# # +# We created this package for both routine data analysis and academic # +# research and it was publicly released in the hope that it will be # +# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. # +# Visit our website for more info: https://msberends.gitlab.io/AMR. # +# ==================================================================== # + +#' Retrieve antimicrobial drugs from text +#' +#' Use this function on e.g. clinical texts from health care records. It returns a vector of antimicrobial drugs found in the texts. +#' @param text text to analyse +#' @param collapse character to pass on to `paste(..., collapse = ...)` to only return one character per element of `text`, see Examples +#' @param translate_ab a column name of the [antibiotics] data set to translate the antibiotic abbreviations to, using [ab_property()]. Defaults to "name", which is equal to using `TRUE`. Use a value `FALSE`, `NULL` or `NA` to prevent translation of the `` code. +#' @param ... parameters passed on to [as.ab()] +#' @details To use this for creating a new variable in a data set (e.g. with `mutate()`), it could be convenient to paste the outcome together with the `collapse` parameter so every value in your new variable will be a character of length 1:\cr +#' `df %>% mutate(abx = ab_from_text(clinical_text, collapse = "|"))` +#' +#' This function is also internally used by [as.ab()], although it then only returns the first hit. +#' @examples +#' # mind the bad spelling of amoxicillin in this line, +#' # straight from a true health care record: +#' ab_from_text("28/03/2020 regular amoxicilliin 500mg po tds") +#' +#' ab_from_text("administered amoxi/clav and cipro") +#' ab_from_text("administered amoxi/clav and cipro", collapse = ", ") +#' +#' # if you want to know which antibiotic groups were administered, check it: +#' abx <- ab_from_text("administered amoxi/clav and cipro") +#' ab_group(abx) +ab_from_text <- function(text, collapse = NULL, translate_ab = "name", ...) { + + text <- tolower(text) + + abbr <- unlist(antibiotics$abbreviations) + abbr <- abbr[nchar(abbr) >= 4] + names <- substr(antibiotics$name, 1, 5) + synonyms <- unlist(antibiotics$synonyms) + synonyms <- synonyms[nchar(synonyms) >= 4] + to_regex <- function(x) { + paste0("^(", + paste0(unique(gsub("[^a-z0-9]", ".*", sort(tolower(x)))), collapse = "|"), + ").*") + } + + text_split <- unlist(strsplit(text, "[ ;.,:/\\|-]")) + result <- as.ab(unique(c(text_split[grep(to_regex(abbr), text_split)], + text_split[grep(to_regex(names), text_split)], + # regular expression must not be too long, so split synonyms in two: + text_split[grep(to_regex(synonyms[c(1:0.5 * length(synonyms))]), text_split)], + text_split[grep(to_regex(synonyms[c(0.5 * length(synonyms):length(synonyms))]), text_split)])), + ...) + translate_ab <- get_translate_ab(translate_ab) + if (!isFALSE(translate_ab)) { + result <- ab_property(result, property = translate_ab) + } + if (!is.null(collapse)) { + result <- paste0(result, collapse = collapse) + } + result +} diff --git a/R/like.R b/R/like.R index 964fea10..68d38c4f 100755 --- a/R/like.R +++ b/R/like.R @@ -64,7 +64,7 @@ #' } like <- function(x, pattern, ignore.case = TRUE) { # set to fixed if no regex found - fixed <- all(!grepl("[$.^*?+}{|)(]", pattern)) + fixed <- all(!grepl("[\\[$.^*?+-}{|)(]", pattern)) if (ignore.case == TRUE) { # set here, otherwise if fixed = TRUE, this warning will be thrown: argument 'ignore.case = TRUE' will be ignored x <- tolower(x) diff --git a/R/proportion.R b/R/proportion.R index 3bae3a7a..5392b2d1 100755 --- a/R/proportion.R +++ b/R/proportion.R @@ -30,7 +30,7 @@ #' @param as_percent a logical to indicate whether the output must be returned as a hundred fold with % sign (a character). A value of `0.123456` will then be returned as `"12.3%"`. #' @param only_all_tested (for combination therapies, i.e. using more than one variable for `...`): a logical to indicate that isolates must be tested for all antibiotics, see section *Combination therapy* below #' @param data a [`data.frame`] containing columns with class [`rsi`] (see [as.rsi()]) -#' @param translate_ab a column name of the [antibiotics] data set to translate the antibiotic abbreviations to, using [ab_property()] +#' @param translate_ab a column name of the [antibiotics] data set to translate the antibiotic abbreviations to, using [ab_property()]. Use a value #' @inheritParams ab_property #' @param combine_SI a logical to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the parameter `combine_IR`, but this now follows the redefinition by EUCAST about the interpretion of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is `TRUE`. #' @param combine_IR a logical to indicate whether all values of I and R must be merged into one, so the output only consists of S vs. I+R (susceptible vs. non-susceptible). This is outdated, see parameter `combine_SI`. diff --git a/R/rsi_calc.R b/R/rsi_calc.R index 1a182f62..ee1ada71 100755 --- a/R/rsi_calc.R +++ b/R/rsi_calc.R @@ -56,8 +56,10 @@ rsi_calc <- function(..., # for complete data.frames, like example_isolates %>% select(AMC, GEN) %>% proportion_S() # and the old rsi function, which has "df" as name of the first parameter x <- dots_df + } else if (length(dots) == 1 | all(!dots %in% colnames(dots_df))) { + x <- dots_df } else { - x <- dots_df[, dots[dots %in% colnames(dots_df)]] + x <- dots_df[, dots[dots %in% colnames(dots_df)], drop = FALSE] } } else if (ndots == 1) { # only 1 variable passed (can also be data.frame), like: proportion_S(example_isolates$AMC) and example_isolates$AMC %>% proportion_S() @@ -111,7 +113,7 @@ rsi_calc <- function(..., base::all(y %in% other_values) & base::any(is.na(y)) }) numerator <- sum(as.logical(by(x, seq_len(nrow(x)), function(row) any(unlist(row) %in% ab_result, na.rm = TRUE)))) - denominator <- nrow(x[!other_values_filter, ]) + denominator <- nrow(x[!other_values_filter, , drop = FALSE]) } } else { # x is not a data.frame @@ -168,9 +170,7 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both" } stop_if(isTRUE(combine_SI) & isTRUE(combine_IR), "either `combine_SI` or `combine_IR` can be TRUE, not both", call = -2) - if (as.character(translate_ab) %in% c("TRUE", "official")) { - translate_ab <- "name" - } + translate_ab <- get_translate_ab(translate_ab) # select only groups and antibiotics if (has_groups(data)) { @@ -292,3 +292,19 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both" rownames(out) <- NULL out } + +get_translate_ab <- function(translate_ab) { + translate_ab <- as.character(translate_ab)[1L] + if (translate_ab %in% c("TRUE", "official")) { + return("name") + } else if (translate_ab %in% c(NA_character_, "FALSE")) { + return(FALSE) + } else { + translate_ab <- tolower(translate_ab) + stop_ifnot(translate_ab %in% colnames(AMR::antibiotics), + "invalid value for 'translate_ab', this must be a column name of the antibiotics data set\n", + "or TRUE (equals 'name') or FALSE to not translate at all.", + call = FALSE) + translate_ab + } +} diff --git a/data-raw/antibiotics.txt b/data-raw/antibiotics.txt index 78647a6a..92a57f41 100644 --- a/data-raw/antibiotics.txt +++ b/data-raw/antibiotics.txt @@ -200,7 +200,7 @@ "FLM" "J01MB07" 3374 "Flumequine" "Quinolones" "Quinolone antibacterials" "Other quinolones" "" "c(\"apurone\", \"fantacin\", \"flumequine\", \"flumequino\", \"flumequinum\", \"flumigal\", \"flumiquil\", \"flumisol\", \"flumix\", \"imequyl\")" 1.2 "g" "character(0)" "FLR1" "J01FA14" 71260 "Flurithromycin" "Macrolides/lincosamides" "Macrolides, lincosamides and streptogramins" "Macrolides" "" "c(\"flurithromicina\", \"flurithromycime\", \"flurithromycin\", \"flurithromycine\", \"flurithromycinum\", \"fluritromicina\", \"fluritromycinum\", \"flurizic\")" 0.75 "g" "character(0)" "FFL" 214356 "Fosfluconazole" "Antifungals/antimycotics" "" "c(\"fosfluconazole\", \"phosfluconazole\", \"procif\", \"prodif\")" "character(0)" -"FOS" "J01XX01" 446987 "Fosfomycin" "Other antibacterials" "Other antibacterials" "Other antibacterials" "c(\"ff\", \"fm\", \"fo\", \"fos\", \"fosf\")" "c(\"fosfocina\", \"fosfomicina\", \"fosfomycin\", \"fosfomycin sodium\", \"fosfomycine\", \"fosfomycinum\", \"fosfonomycin\", \"phosphonemycin\", \"phosphonomycin\", \"veramina\")" 3 "g" 8 "g" "character(0)" +"FOS" "J01XX01" 446987 "Fosfomycin" "Other antibacterials" "Other antibacterials" "Other antibacterials" "c(\"ff\", \"fm\", \"fo\", \"fos\", \"fosf\")" "c(\"fosfocina\", \"fosfomicina\", \"fosfomycin\", \"fosfomycin sodium\", \"fosfomycine\", \"fosfomycinum\", \"fosfonomycin\", \"monuril\", \"monurol\", \"phosphonemycin\", \"phosphonomycin\", \"veramina\")" 3 "g" 8 "g" "character(0)" "FMD" 572 "Fosmidomycin" "Other antibacterials" "" "c(\"fosmidomycin\", \"fosmidomycina\", \"fosmidomycine\", \"fosmidomycinum\")" "character(0)" "FRM" 8378 "Framycetin" "Aminoglycosides" "c(\"\", \"fram\")" "c(\"actilin\", \"actiline\", \"antibiotique\", \"bycomycin\", \"endomixin\", \"enterfram\", \"fradiomycin\", \"fradiomycin b\", \"fradiomycinum\", \"framicetina\", \"framycetin\", \"framycetin sulfate\", \"framycetine\", \"framycetinum\", \"framygen\", \"fraquinol\", \"jernadex\", \"myacine\", \"myacyne\", \"mycerin\", \"mycifradin\", \"neobrettin\", \"neolate\", \"neomas\", \"neomcin\", \"neomicina\", \"neomin\", \"neomycin\", \"neomycin b\", \"neomycin b sulfate\", \"neomycin solution\", \"neomycin sulfate\", \"neomycin sulphate\", \"neomycinb\", \"neomycine\", \"neomycinum\", \"nivemycin\", \"pimavecort\", \"soframycin\", \"soframycine\", \"tuttomycin\", \"vonamycin\", \"vonamycin powder v\")" "character(0)" diff --git a/data-raw/reproduction_of_antibiotics.R b/data-raw/reproduction_of_antibiotics.R index 3f065606..fac3b94f 100644 --- a/data-raw/reproduction_of_antibiotics.R +++ b/data-raw/reproduction_of_antibiotics.R @@ -488,6 +488,10 @@ antibiotics[which(antibiotics$ab == "SLT4"), "abbreviations"][[1]] <- list(c(ant antibiotics[which(antibiotics$ab == "SXT"), "abbreviations"][[1]] <- list(c(antibiotics[which(antibiotics$ab == "SXT"), "abbreviations"][[1]], "trsx")) antibiotics[which(antibiotics$ab == "VAN"), "abbreviations"][[1]] <- list(c(antibiotics[which(antibiotics$ab == "VAN"), "abbreviations"][[1]], "vanc")) antibiotics[which(antibiotics$ab == "VOR"), "abbreviations"][[1]] <- list(c(antibiotics[which(antibiotics$ab == "VOR"), "abbreviations"][[1]], "vori")) + +antibiotics[which(antibiotics$ab == "FOS"), "synonyms"][[1]] <- list(sort(c(antibiotics[which(antibiotics$ab == "FOS"), "synonyms"][[1]], "Monuril"))) +antibiotics[which(antibiotics$ab == "FOS"), "synonyms"][[1]] <- list(sort(c(antibiotics[which(antibiotics$ab == "FOS"), "synonyms"][[1]], "Monurol"))) + antibiotics <- antibiotics %>% mutate(ab = as.character(ab)) %>% rbind(antibiotics %>% diff --git a/data/antibiotics.rda b/data/antibiotics.rda index bed5645a53212db3ab16c0f2b8c230e58c33998a..ca57f4df6f216c79a894467e5ade275214d1f21d 100755 GIT binary patch delta 36787 zcmV)lK%c+*p#qMg0ue%5XgM)KSte6iQ**Fs0L$u;5hH)J9?!mXgaGJBCxDBN_5c`g z00*QA0Ehq~3VI)V&QK0!1wHO}Kr{oO^e)L&I$VR`5-11&0F;KO+s$>2$KCO}3|duG~GjDz5iC*0#Cm2_#b;=agN+6}swybUEpiy-nt~ zY0bj(Db>o_8EeaGvDrIsE4ACJyEfW$uJ#Vsdv)Ld1D@{f-A5-tX!EZ%-u7sD!KN5( zXt)6G>w0EAZ*!~Fb=}_Aw%V&}+5w*TbFQ_!-nxIfcTKH1!+SWOkpx1_yShL<%~N~Z zZu8#m1-N7jYi$kPyW6+`WTvREZk&wAx4oV26(e@-tI&1QOMBhYIymoL-DS)T>^dnl z?0eckJm7NZay{>R!;*qft?mYryF+bjHrpFv2R_e_mijK)-J%vgddAUC6?<@U^>1+M zJ}ZBsfN7!u00;npLqRfP0-hwwpQA>U{HgkSqf_*cQV%G4nrPaAvYynyQK0oR)jdyB z(^JxVC#V26lgc#E^gT3@qabJi0BPy~XfzB!(;z|!AV8ReWiU*D)X9oyZB0E#sQpj? z&;V!v&;vjK0000001W^D000000000Io{4`XNr+VPYG#v0O&VoAKx77hXaMy900000 z000000B8UJ000000001J0006_B!nYMW~LF8^;7*+{StXKJZfT|OsAwVKT>1>XaE`j z27u9{KmZK@13>iv00000000000B8UNN=c#!Gy@=$^%K(J5`K{NJf@6|8XlBAGBqEm zJV~`Yr>35!&{Jqn)M|Ljf=x(4Gy(vP36N?N)Y??^@@ga6r{tQRqttmPsAvEH001;J z&;S4c00E!?000000000Q01a>-sZdb_h}@_VDvC@wmHqZk6nzL?NQO;%o#cNutqwe+m7w+m+92O17& zlW_x4f7A+rKu#zCDI!2@APVA00LX-bG({^x0Ff~iTy2C=##9PcD3K8|62OB25lWQ{ zF%bZwrAPsHQUJ6?ATbbv3bhmfOC$gkAV3C40SW}sgpv@HAjkxe`P~AjqN4?Zh{RS3 zq9TvWeb~Yn#RXXw3PlkG1%RrEeWH~WMhpDre~AQsfEiF0B8Z@?0Z5>X1wL1XhN3Le zv0|zyqXke^7BFC>L|BTdsIfr#e`@XXH`+C)Z269R{YzUp&{04{BEeJdv{Iedw82C| zEJ0E#!9|f|5sHjhD6v$EA_|Nch{Z(|=Xd$5HsNX}o&cCzuheD$sh1oP2N9PGU=iSe ze~2QAqAH@Qs;Sg!DzQ+;nP{Rh777ebjaE*gutWtGD5PTrSPDf2RU(TPC@~dQDHbUO zg2WI;3Mi}r1&JAgv%1dZErJ7cjB?;yQ|;?y zV{G50<()fA-AfTt+6_XYL{*5a5fudye-Q-{Dp)K?#Zf4f7{m}_h$^cDwpgU@LbC>f zELLSLrL3!$ypVh02_z^m0FY!5BqY{h43L2)v*7AY0|sU+3ormS`)$VjxlXz$GtXMH z7)AyzYUbqLI-3aOW_)oH49 zeXO?+!_!`_I9*NEYOP&H&im&FQ$AWj(<3cayE^I z__WsRYr4K#x!J>)J(9+4mL&09+00ul=RSt7ZrDv_a9Z_m=vCQx zm^akSS+NWp5<9Ghl;wjaJ;v6 z+Pa}EZDTN@NvX!pQ+q7C`j*5~6WT;VZ{ZexR6FrQZR2S4wBYl_KB@N1f7udRNynTc zXVX~3DR;-otDN~EXQe-(qnd;3FPeSMOyLt0__Zgq_UC$NGzcWQ*uUbd>d|a~Rg@e- z5!S(nWzBP{EKJB^$0ZiH+WR416A3CREN+f1jqXzklT4V15nv$2fGbf(h%5*yq>6+f zAqb+dim4#Ph{h-cAi^rhe+UpG1`tL`7D$Ye2#^&jp-9NV84##2M1KW-919e2+jcPm zNePdpeN`O!VL@}y1s+-;s+C~qAR=-oD!QIFtN)=vP!CopC;;C1KQq?0tq>I6MFCoT zx&!>0y)`OP1^94PUxncP+JHqJWK_;XdFYBfNSk=7o=?A`=W_jZe?Tkp|K5P0;~*n( zzRi5@2ba3SR=kpzG5y`nw5H9D$dVu7O3`MpKmXW4+L-o@Z&C@2r$?5Hb` zhQ=!Xn1T7=D1Uqg+6T#r@gkWDspm^m;?D93rGf2Frx4SB2eta{`)emt?bq%3_2q8+ zJ++OmiO%M{e;ZHie|Wx**XQtl?+f4T>*Vn6znaHXf}nm~&F6LKX?PvSi?QI`s2m-h z)ARG1FG|*)2lr*RnC}|A?uYPTv3n8^hJ>?s5|IV?*^pKnyhSpqoj_ z{0a-&=Q%329e3%&*cC&x=&8eiChj7iN1C9bcpfiL*4Xg*e_A4{nfMO&0wMRH054|{ z0tgu{*ilENH&xGiia``uf~t@fD-dEag8c#&0Yp|KBBDi#A}FH~L{%7~g25QYMln%} zDv?1&f-zKpsH)G;ep`Q@=kB=rAIWv!cbdt+a=y2GAh-8tqwrVu|Cir)_fU82GR)We zm4D_+N3qr&f7??Z*kmr%Ro7IsKaqvHXNyTL56NYa%I)p-e@FNn{;#?F_4huH@IIf% z{1~(3>faBk4@vyP_v7^6`dD9$Od3C`zHMYyH;b!p+x=(L2w+Tdcl1`u={3%-sxD5> zH7(I)gUvs8bacv2c6C->Uu7YN7F|`sl&=U>`lmZze~vfR62jFBRoPCV`g-zwbzw@N zYiH`RR%1t0>+{1&SRU){Ty#157h!dHI;O^st+KwFpKcgn&Y`}m z1dHioO96fXr?QpbeB)Zb22q8!V<~3+F{;Nly6ni=X1ZaRgX2tbTjO1~w6VH6uEfHc zm`Zl%e_Wi|PP;U!6RMXS>mm!PmdEHCQ{Z)fHmFX!*9`Biqc;5Nu(GAw1lF#~-PcD7 zt~Ft+gj;rX(&;#~BTdTHYsT6~6v^8>e!pybJU-uH_Fd@l27vK;U-0|>&z_!tcJS9& z<#WfY+ng@4*n3yQ)mr?E;U&5iW$)Ts-1lo4f4D}ehq|q}U#o5z8*8$4LX}s0tXJNB z+w8G$(rFyGX|rpu*x~QzO(r!$hhCOjeihRjA6}7*3UlxtU0##q_PYFUgLg(ho$B_M zZ}z`!_@2eq`T1q!;@r4(c{?G`rQR;(9xDY^_xJcJ?DF`#^6{Gc;d4#h^U0Yz-1rH~ ze>y04jta(08&pt-{t|`B$7{3l?X}E*#xARKRcgkuZQ49%H4ZspIW1KP?UG0o4ti`v_KTf&msNZV@f4odG~7PV{hS0Ne-?*n zf#)-e6kn=)X%00wT)?BBn_1UMisZjeZ&N9XCCh|?3)6`FL^ZX^{6&{rXr{rP*MVvq z!-zNs1YX#AZcyqVAqN*0UumNUMdLGgqr__%sJui$S#gL1DWc)?jO&uY&t|;F5ESXd zA4jZoarWNy=Kn{q{?7-P^!h9Ie>~K&dc79n{7u-cD~R*BMaz7Q6g|$b(d^#PgVf&Z zl-o-v>Dc(~u^8n)D>WqFOXhjvduU|T^PFMpe$mil7~dl$=ySIuKMQI$HjLWY4Q-ut z>hL%@Dn?Vvy_WH+iW{BVO<28#3~>0y`)`V?z?>U{cY9&*Z4F(;fn}tDe_2QG2`65- zdf{T{OLLb%9nvBm-v-O6S$*VS8Pr`>Q8;&Kj83R!?T$41)(goRI4s(Lq@y;p3poUd zD&J9@D_2gllP<9$FrO48m&^*J)l~VVPAIy@KPqmTOJOTIEdkbwB%;8U)69sFTLj7k zx85{q>kz9JoScElGR!y0fA;Co^}l)kUr_qPhCkH%Tt5T%`Q7@z%HGiNcpKaKo*v75 z|H1IfI+xi$%{Kr;OT+N6bHd-`QN#R|`?E^-ntM-9pJ+Qzt1FM`bDc&-E+teNOVi+o zuK2)_ddJ)qbjXiw1bIp6 z<~MYD6tUhAjJvo95R;qT2j+zZ`3Xx)ug<0VWz;~)M?F^X9->XrheC#(7PavCp&UiI zEA-o*xu&xZPK?C*;A}F9Qnxt#%uEY(*ZDmmqZ3d}5;OTJ{5J{qzbRUf%$KP?vWO@y@XTnzSGh!88qF2Rl!9^`71H zz1>DogStXU0{H0>); z5hFV%6F`85&&0em@7Cx}h&tO3GT@4i#vz23R=6#(5kt43StG;h%1DK!M*ZQIQ0zbm_DEPHk@}1_+-x8T?L&f2lvR_P%>qF}KU!xnCcvD?7J)uySTS-;~26?i)oTyWw!Kn0a@5JM`AF z5f+f7;I>Vf?iE<*GrfJXp`_--ax|KVEOtIs#vW@Y*IL2^=%KxX;PmKVzW9EGa`N3b z&bj{v;97;3J449cURT|O9_ONtX-U8;dnXQvMI=FSfB65Z)z+}R(GeQ$ea`G#p`pgU zFLaKT!faX}dZ2ufzH?kp;l|D~{~=BXu0j!>TvOjWTv98o`aruzmXZ+;!=r*Q%Kph$$tP_$G%mQ>i(D(ZuOZA!Gzc-5pT4 zK^>2)f0%hduVL8r?M^y+CYV@V6Y^|>#0StduO8hCZH%IuBI}mc3zwBcTP2GFYSF)9 zR(&o6AXZS9P)mZ#k5ZB$0=oweI1m&=_;q*lTD)Q)P(xzov=Dg&5SYMBFw>~_WAqY zhuC!n`YxPreyaGz^BQ=>qlbL25RxhA@O`wyqPF-M$?bVo84#$Qq(QTDnakKq!Dhs4bY+J74i_;kgN2hB!#LX z3>W4gmp+PM^sz+Za^n1xGs#m(RvpDvJ#edqw2_w=+Ney7@D@y zo_%#B*dT<2sUaUp8gT>@)p{4rBa{Nu&Kk#m@`JzX&( z5g2mB(Pt3@b*=cOp}||`$igoSi%=s+D`{3TRR;7{8ygQRntS}t z>DckyMD2#mmCt)CfpNU-Ip34-;|S|gp=YUtCU&*Cc|)$AOx;6knF-L$xOms6&%V|4 zZ3PC}#PWMoxJT%8)T3wU@hhqDJC1sKt&XYEK}rDkcMv!ACxQ`z@1Ls?8c2|xhlh0- zH}u2gw@^vcbxW)u`=MG<^=qd0j$!A^D7w?6?i~#~l32PI2T~?ks zUF|&tH-~hPQPUF#!{;#ofA+-@w5bF+B~g&_nbbmgGX^0*P~pXPfNt&MA@o*YOic`v!=+J$+c`5Z@Vo`MIgT+(z7T-&HXlbBXme{b@q#^#KC`$Rw@ zo!QRwa5get6|IZ!@Ae0*Y;HdGcKFb;eh4dBS?$A*JzMwKb2#a3V`R%uyTdq#a@&H3 zm(1>B^@)D#@t)e@DvcR(Uvn=KXt*mOORnfFP+w|1F*t^U^IDCLqAT992;J`PXR%)E z`iC2M(2G2g)#2N}f0O1!*@)O(M>3j%KseP77aBU>(C_oyN7U6<`Y6(KMiYud4R&%;E9^gPz-&zG=5EPg*K>Ob(*?AvvE!T1O z{ruBPO+kAL;dITnY6W{;&xwI)B7#h{^&B{aemeFDk}WuYe{G0xi1`DJJ0z45&yvj{ z@*eh^1ylTw4iSong1q^D#x$V#LP|Qv$-g7p7Eb8tD0e8Q=WT|k6nx0VoEi~GeGU*g z+I|4Q!0B%Y_`7rvx0K-!3ELqko>y--oH#+emT3w?XR!O>&wtk|)!otI@cHi#Lz$u< z<)ke|y+g4-e-qo|a|D9lC|Grr$OJ+gYwX0&o^duursDi!a~MV>h_2JU%fhW8gP1p* zYAjH>v-8lYY|Ht+8e)b4XR$6E5>RmzfT|MIZQb~x0qIm!;mD9ECDMEYuUT^^Cm5ba zklnrZ2x#LaJLtiJivl7RDO_2-p1DtTDI}99QYLw~e~{Zn&M_4bL4)8|f3m)Q5yb=L z9Uw;P53w#I4g?L8kR0*k6F;>;^R1z%*g_qGL22*b91uZl0?iVgQOjvS@m>}>LTS7q zC`m?DNT_p*Cm*Bj;^2KA7T=u!EHzb&@GnOIw~*XkuOnmiYjX~`GZ?6>h9I#roEOHqTI!yg^iM_qYO4BvBj~#&hS~bL#%}$mf4*VYDz%=UJ=J*|b(vW{b55st zzn}`>CNXj9aUOY6%Bx=}SIFCQvF3c<&Em>~utVFgE4u~k+h7=j`(Sg65NMG-|& zOKOTmdF{;28`)|~4^*oL-ZDz4#8m|m6kBS+L}JAhVkYTP1=*rHwH_&0=}RSt;?R)& zI!OsXc#0kL5LMs)?w6zVx7K}r4>5WFTC1yDf8HGc4K)4I+6pSXNQj`hg;5m(Dk_{v z2#OeP6*aH{6a(3ciUz+sL)3zwHe&fLzlEx}vSh2G25t!Cw4DWCbMf?Crw?!4eBY0# zv*6$0k8|VPeSQ^q%(XHkz>cSdM?pC3)iNDFt<>vvl*;$o%~zkwZ~d*MtSRX4DYM*t ze~N<>!Jq~IW#D)HO?@}7ORIh@PD|WzKBsBXo*&uG^;w^x`afi-@um49N(t%;$Css_RUHX^U~N;as8le3jO9HM3Kj!zg00izJ1MpygI_QdY5LA5b-kziZ6-<;Q2tkl! zWK@w!84-*XMHNV(umymm7>b}kfg=cjqB1Cmie5qMARKfQ>LP$T9p2CWb>01We_rO; zRLx6zP$UESV4;wTfocMx^KbwW{g4DOA_9PJMY!*(LF6@@3=W>WoE1cQ$f_csUqDSH zP!%$hJq1)lcLh4wfFBAdhcA+%0-rAen6dy;2_mP}iXt^Z zH4qV9EPpkbu&NxHB!-ZIKG(@n5s1ZruoPIaREq^t3>dLwRw%3yK|xSZ7_o|oh_F>v7?4IRQDVVXEMh342r7vc zP+1jJMnz;nL{%6o5mpE)poqjpREWh;Kt&cRtb-V%BBG-ZMIs{x3M&Q(e~dwq5kXNP zs3M|@qQzB$f{_qdh^i1&6jhO8tQIH;j8#}8BL*s>A|iq;QYyh>t00jeh={8g3Jj4L zs>DQMs3@#dRxFTFim?$8RxFAt#6@B;V-boA0fNROAf!YT77$pl5d{=dEK(>e1tNmM z5k(b9K}d{(F<`LU^%fsDf7?+&KJ&dTctO5ZPzyiBa9Z+fZ2~5D1m_^hsjEe|&m?RIufj1~|h= z8cjNJg+4wLNbkPil^~lP9Q_IL@ZWTIBqki5O>T}_tya`7>2igFQj997->R}L#7k-{ zkjt2`fl@(<6`7J1gvQFL1alJLV4TM~<>6HDWa|E(!fIy|pvnvrm_mM*8BNc+nKom> zy!YJN0bEcrp6!o=f7P>tZ>N%;WSqm(4=H01n6eDMe=!apeC~MQ;@?@#^!<>9-b^Q- zufV|jK3wnow@o#z@BrN}o-|9YO^X*o^OEDIdPjo_ElMORK^3V|TR}!DyZ3Y92O{J< z4+jaqs5BPPV;D*`zY!#fNzk_-%X8?Yd@jB2>fB14TLUZC6_t-ESc)gun zv(p<}e*1#2KkI9imn^Q{tn<>vwh7FLF<`(r$Xd;BLr`JLtiZ{Ge9GLq;X11RtaZ6^%fIOa_Ds#NI!LnxehV$J|2 zd4vu)+7K%%a?)-b6i_#u@HsOBMIT?4-5KU!UGejxhjnmxeCYN!bX2&SKK_N& zKsS@Kiu1nB{Y=_rzWy&^WCXU}--Hzkvh*8z>XzA$e@+5MTGKG;AB2la~Yb&Jt{B11T4afyw29Bs!d*rzaCP^=b^yo{OxNkzBbACXhT?5 zWG2+*me;vR{zF0|#B(H{g7(S02_D3@n%F=P94=-kjD0+jKKT%S@As_80&`J^XJ1RY z-OYOkOnV+6WK~1m7(CIH9WY1e{m;ky*81C?@2bWBhR#TSE6?qm|DqtX0bk}gnU_ag zfBAGrzgGV{p#ipK)!cvs26ew~ygT&X*j}qDJ;{2!nM6GvNoU~L<&LdKCt?Mp0fkm< z+zy=Lq<5~dZtvcMy6xf9vo91Ttc%@7Ql0kPr5tjvfxC49nl~ar7|ZRlgtm#>hw0=; znB_4jav(@qU2N6Z>Wmp*S(W+aVgmX}e`!F>Sgmr>l>seAh*`?Wi`yQ6>t$Hh+dk4r zJ8yz}Ej#Z8I4l+|P*1;d%q+bqp%yQh54YF5jd^%2>-rA+%|A+ZRsaUVKm-toN)kJH zwi%r_C~getYhG_2tP@pYZek$ac=?ZKwR?M|eFpmZmpnr>5*Uy$G+SCne<#|!}ZN2XojiD+EiBobiZY!N+vMwq(#J1a{f>&LIL%`hq6w)iqQ} z-vjg?r1j&o*^m<1hUSIChgn(-%ylH!2AK?B^hmFV>gvdwlbhl?;7~L1QuM-pF zimWIzSn-?wMd-;sK2TUWB)KV?DaJyaWYp=-@mDw?h<6MwqAyelveTM*GDE^5b1p;9 zXjDXA?PEYQcmO{!43X8FzjPP}!G8crVpxzq_WO0=7Y_X}@E2TBr^ zBCf-V%5{w1Rbf$_z1(2ayM%JO;$|q!$S*h{18^{5uxcwHH9`d|QIy@Ct(suc)83dv zfdkp>=U|1&j%N+~ZM``$%71+2LN@&~n6jY=Uz+zd*o2rih+v#!D&7PnGa8Jrs%SG5 zoH$c}%@LT00%sZZ5IGDw5X=w*p!NRu&pNK11MZ)gNgM5bBCY6~#z7SmBN)LXCn6n_ zmY3_OnW~8r5fYug`9#uZ53*__G9mpf6J@3|4OpRzO+*KD0UrIY+<(pc(B-jNjL)&y zWBX2O(s~o~Or70b=6jyo7a9Anf_ByQ}l-40&cZA=Pa!5yjpf1{SH z>eVoi0AEVB!S~+=MaEZ3*h4okYiJmE4@(u{>JN9GzRzraH-DH8=vT6O%|?cU{C2vI z*K>hoPYky{)F4a3B3c4}T}hAOs*^TmujzDnJ9@g?yS;l4o1^%x_P}@}?0i3*dbD?U zdClF9-J`cjEw;9ZslO%jFPf~BE-&aV4ojLhzUr9b_x&;+015HU`nePrCzQzC+{<`3 z?bJ2xa_9U;_J27T$EGa_?r%&_-E)h*o-(`kzmm5kT6b6l^~IVeenuE z7Np<8u&A?6npig`X$#+2T2G51fiCsRr2H@Ae8L|v$~k$suva|$eGz}5dc5K>{E7$= zWcr@Wdp%7LaYZ38#=gVE6u#*(j7=KW$MH+g9NYbX!GD1JLYyDJwDsfnXMm1bfHB!UMKydYTB zW0QN;0Dt_FiFdf=<2J4BHNG@XtY0@FB9q7BSycq~$aQtD{{DYo&B2LZA41z_%{<+_ z_?{i!7pi5+JV`q&%Qh7GYZXN9a%%nyYKHtTb9ws&DGHW9_97`%oX7rPlx9w{YKTk1LKV2j*|zh)4(VqSv$cRei zdbhX`4uGnNbYykPiPBzBkPe3@xf80Tet%Jun}|gFz<_(f5jzK!-Mzk!!2%o=S>w5$ zTi#W3xBXA!-PNx!SEaW(oWvw!AwZM2j>NT__TL`B8qeHLeYk%zs zJCP6~e++$+d!QgjAI}8yqF2wy@ME6+H~2hV9Zk8*!=>V-_GQXdzMWA$Qt>WZ@4KW6 z*cmm%2QBP_2PiLdC(9wkM8T_I1I|U)nlE{2uTpUjV}l8$xo_r{@R?Kde$?@+_6|T>V?}xh;g(NulVSSj5Vfy!Y zm3o6Olk)v;fgZ}0@WslT_Qs*Wq7^h&%ufM)-R%Q^UQ@?1%hraEYs~604>jlCqOJp!$0LjO9t&HJL~J zXb~%B`dK1u;n%m1z1zXg?F@VcT+7s1%;~J%MEhRjdOsyXn5HeRmp%1@(qzs0>0b^VV=ME#g{E3WgcokO@0*sBcu-1l+)$H|B5zgz41 z9*@-MA48r)e&0TC*G-)p);^A3G6JSkWU6wns{LP%899(pfdg4wet*3aqa{RVMyqmU ze!u>IbLxIKm@5375Pd(m{BOO7?!KqggnzfLKYdSr2>7!mCVz+acRT7>R~j(3_y{A* z$sm|n#~R+r!O@2SI)4``4OOqVJg`w)?IE?dwA2Uy=vC zyWJ@USq*#jjhvO?h)YebcOUE4|DkN5(}diTMAMWm7Nj(Az_z_~4k9W%gjNupL3rHl zBDU74WFpGo>sG+@OF49YDiBlhZltzDtjusJ@%gNw59U$>Pn(2yEVLpl6l={o3MrN< zfu5o_s6<96fPX_OE*~C0Zb*Uo&Q~)i{;0v^Z>xCWlN>_lmP+|#A%GOeL~j(2~lO=pm$@H z>^ay{%rp=QUHE(!7$cIr2ugFc$C^|WCXym+3Z#0s1b;Q#Jr-0{zWAHhRK4eCo>2B( zaOq?MgesbZivdAkte&o!&IInq5-hp^DUbrbQ)Bu(Oc z`1!ZB!GYe-SA9qbNd!p+fg?0Ltz54O2pvuHrH!gr@*xbpza04QcG741f>qKPGk<62 z-n(d7@PB8whg){quEN+Z)sHp{2@51?>^chVz>2VQBhj#_$c@kIsNf<@7RDWYSO?H% zP%UrjcSUA>%qmMHA|cy~(Ln`MwuXv`f@br28%7Tv%X`!bhdW zTL9tAI?TEG1qRI>0)V2L@zg+o%G7<)*%T63TYrYEs~x;wm_{Z{PRYta+`jteeUwPD zFG2i<03d=20x1!yDS(^mkbNF6E=8$@Z&@JxmrHJ$c|3HktjbvFyesO(Fc*kqsD&%j z%RC{1_TW*$n*=)>g*n-U@LwCQU-<~-qM z&3_P}iYeZ9httEEs)msm0z=>;zX?YUHVbAe8pScmep^-1gI0rkpKVAN1niewEWl)ql|1 z^Qi%~P()S&hXXXRh=XVq6pIfs$J;U(!gAH$1r7&!Tb*(9DulDj z(aARJ`-~=>`gPdh+BXYp(*_q`K1ogNp~sVC-ix4fcU07Lb?DamDHO|Dd4KV5@N3FT zhgkzZ=Pao2=^iaI)jPE~5)HVM>s9OQcZX$BCt$?lA0CplGJwiw^!1^B;V zGILUaruRM9Za^?!77%BqaAd8xcVz*(@X>TdK`P)-1W7)`ocJ(tJ|5aQ?SFZXg5LP&D8VkbDX3~jarDi1=7NC(wq_4PjJgH#;sGOr zBlG0(Jtvr;{R`ekL-NWcevx~2~Kv_ z*+eK`5d&m?#-R&=^@-^b(+!z#vaJGuF>9DuKOkCqo$*XdG=^cX z3!(A|ag0kivk+%M%#+j(Aco~2#RaQU78Z!P!juXa4SzDdbw7%G9>zXRYB0k~T$kqc zuLtgdd?Y4i8T5`#(iaZEcf|y&I2T{G)o?1YMTqq?F+dcc#w*rD`R$YsJVN*gSZZ%x zXtrAv7pb%;dpxn%%qts8us&7{87CERAe@+m7ZbsOnupViEF5HJs9n5|7WQqS1Py$E zRI@hc*nc_dhi$SsTj*wQ)qZ->Hz8yv2t*FR0F)gM*V$5rKg~CbzxA&=wO)NH2{JvJHb)GatmD|_pCOb zIDz!D#Y=q#6*$ugAe5yo@3wpnIE6rf>#E#m!GCjh#%mzFDtVUJha?PKR2F0q)9wq` zPo4>`0|LPM{knor8nL`^!!YN5L7oXjmBJ#D6pg@^DXV&j#P$Q3N!dUbZj3GjHIxYD z(<`y8LmEkm+*n|tdJ3T^P0Ac_QWRP)?lJ)Ok7)X5xS^K_k2T;J><)y5xPc?n?QdOW z@P8U!j^#q@sU62pQEq!_@1*R53oio^ftBox8;2M=E?lVz5(p$_o!U2%VKIqpQ9>fV zbX0z>onMbq!{_6Yb;f7stpk`eQJ&{qamS7sw8ULU?=EprONvR#G@`&42uU5n1dl}q zK7u%PW=q(^jmE)1ssUUQ4k8DxWqD^t-G7>QdDl4Tpt_w2_=B4D@qT_&^wHDNbCy@By6}m1 zL_dYhlOWP$LzZ78&EhTqYxMivW516czcv6}?!9d`hUllr8#0e@p7mDs3oC}2e1H1q z5kyh-30l=AK-gx=PNBDH@S3Y6H5OH11YiZcIlM9p;&Fas13>nP1 zYgFUU&tecXf`FnRD#1b|Siw|^Dk6d~MiEv7CdGmY-UGP&v3 zc3>diruoYKr+f|8dGyv@bGf)~I)CjryR2?8s418Z7}!MnL23uzKqEkl2_zB)j8~+% zII%a7F<42!9MjA^Rt{dnA9$8K2UMm8!U0kZT}D$1aTY8EKdx507%i9t9B zYfv@5!wsAiWj#G@cpb-eGqaNYy=T)I(!yj;0ep_Sp$cg^@$Fb(>;oW<9DhL1V>w}R zo0;a4L#`sKZ18X^VOiBhdVq$qifToR6!D=|zQ5 z=qJgT-l$LzPh>jk1;8D;CL9hmXRmb4qQu7tV1$wd5C}te88LAI1CAGEaX7f8RI*{# z%uXw83BV}9FH36U6zGBiGJh!=0*O=*SR5=A55-UnLD4YS`)YQp9^aMtpRwzGeS%c` zW)?%xOZ2;Qcqw0mkXEckYN+68qqCW5XAMOXhMMI@TTleoOW1+&$f>}{ zooW|gp=2Dy$nFs7&_p%2av(JdJfR`@=sCbX74nMp_2Mp!?CWZ;1An!IA%;lzJrIIW zmw|Awcp~tUUDAk*SR@UrLsk0kxMQ?lH8!nYfTwliQ4$Y8sWRj+8kxzxcbOL)w&~!- z^@Agc6**9$a<4U4m2%vy%Y@W0CCEj3X{>iQhu^{&2Zm=xFvl1^I(NW}I3D#Dep36T zQsfZv?{sH}ko6*>M}MUJC{BZz`ANDihaHiB29SkhZhU&s#fR{NLdY+vBc$9IdM8JW zT?)H6kAYJhtZx;Rgr{)vvhGz0%n9#Rt?^_T+Jr|WPVnL6Kjjz^SGCY|5aPw%R8%1$ z(5G3hD{56bcgV-9 zan|;>>NFB%`II?VzuZrHt*AcJEWsHG3_%2l+qI004M&Y}1{{YR;o$uEVIg?&#>1lt z$qvVd^XR?=?te)PH_~(C3};2(HwLj>9?q4WFP(a5E|jHI07xZAUv^pAAtkh4b@DX^ z<6{RG7UImLD~k8{x?$_2+ly`CFw2g6dowRQDvG|7vuv7b1ypUUtcpq`h|4IqbJ3l7 zoV^cJm{ggMu=A&u9GO{x=jyteW7gy3>$ti$G?Nk?TYurl+WCGQ(Cw5#vJcXibc7ZR zJLVYjc8mDM2I@T!eF=`v^*DMMyckx;1Is$xj$f?^#aCse;4!A#lJ z?{JH!z`o|{`VwgP)3(o4haoybSdL71-fezMZdoH3oI;@a%rvlkJ8rs>7$elkmm?Mu zcadPYK46}=o8@I#Gqc-Z>od|h66~%90FWvaBrPE($}WNgl6!fj;CQ{e`Gg|b7W7P> ziEdPmT90X0dZ!iD)(Eb7H4f?cUCgn;W#)60fg$=kvzA5<$R|+jJD2Ar5jdXBn)#Cv zJ2ih66oN>u9w}(SWRYGBMZ(#a#!ZkB5<1pdiys$JEXb>@7Yia{gT@LVhR8U`!YU?6 zj3&~GBU1?C;wdI6EE_7Kn+RDZCN5&Cg5eWvvSbmgD8vNYD}-_&tBO_?sy2Y2 zqR8p8Tgv1#g=AT?E0%h0R}FF4QNw-47dd~NML9@R)XRvn3xo}UvRfsXxJE3aT(VUK zRAQq`L?gBaWb`D5e}5Zpdip&2(-(m)DyS+dih*fcXpL&4H!{pE3R)81K4*7fPe-=v z*Q4w8K?PfQ^(SMI_$okBs`iM$E~Se{2#)7JHS+}N8W4u}UnU@a-% zD=n0qPK>%fQz^2h#~$j{?ioNlsRVx|L{W+f9Qd7lAdUd>4ZJW#fb+h2_P&ENeDsF8 zyETQ;Yk}eEnsz$VIaN8m#3f}&fkIviki`&okb?&;K$DC`2Ekp!fc=QzJVQuIyR5jQ zfe832Y;);un~!&{aW*b_b{@M53T_bPb8EOuwZ8sHaA(qley;*U!&V$j;$eTmFe&9k zC{YO1)l0#8AY+AR7uN_XB4YcSY(xnl*IFU(XGGW8p*F#Rt zuWh%NHbLxa00{O}Dl<*p$18sq4ru~*_Eo+vvg#xvl1V!f08^<#5(kY8WP(MB81Jh# zhM>bco3&QC1QP+RkZcbgdy_Cd25nS%%9lfUv!c4y_imFU&2|zLkV*r+LxU9-hDDsS zD&(^Jiz^0dLO63_>^VyVFxJ?VT?N+~{f66jV<$p`ru$w&@8_kCOv8VnHWARNT?@e( zjD&Oafkf|`yxdZjDtOxfz7Gj{4PcN`3Uq2fP~*1a$tOk!zIE%>g&1;VD>~(bF^djp zP1yqwStQdWoG@UuTuPv^Kvj@MN|<8|AW{WF0^qSkL|Cj?czgb1XwBwtLkNOHr(SOD z5#0J8K(7!lb;;-mN8f*btZCa{8py2k*yxMLov@97;4RIv(#fyY4V4N=oUUo$RprRmp!gAVj*$PO>0b9L}v< zkcncRd2uW^rC7P>Yp&+FayvP3A;s0_RGVwZGl}lZJkmf9FNv%*u2`J$DTyRr=wFqa z0VOxE(BO!hC&hmWyi16P3JMO` zeSizyNLq*!#0W&hwUrPcQifr*s(q`&4Cq%+l*j_tFJXT`-D_N}D84*$QX|zpI;mqL zm!5b|*aU5Rmjtl{lawJZQj9ZuNGud}ycpQBSF>&Ys-xIzx2JaO-%b>QFP=_7ExL9q zuBqo-w+m?W=We{i%OMDlRZ7ZYY+^TRSxV`?_asO%dV*kM7R71d%3=tB%&bOU`YFWr zi9W0VJwU?04!F*LMC|(#!wGGcjNnI?h;Ilxx;PyB`7e-<3Gzi^K_{VIz0h<4CG52q z5M%9kJx(|LA~jOIQBMp#zl;@;1&O`_V%8)$mV}cmsRuoK3$dQX-&{34XL-jF7uVmb zoO6tI2__X$Jdo{9u0_jAPm3@TzTbQZAmtNwX{>}a2CK5asq>z0d( zD2%dYW3{s>A=NDnnG}tsv|4;obmuu;2w574=D7<4azIgRf+f#{>$)R$VY$%2}i#Jd2l z(m^sgtZbTpgmB%hFzA}fd6;7f$u#4-Ov@yv6^T=uCfhWgCL1$MlSx!&CM7`;d=#RB zxlp zUm*(TIXE|QbhD|cxu1^fo{n@%+oP?>h^mZOFhyd?MsUMTblRvXFMYMe*_qDylDZE} z9&(+JBMwnJbWX7HOduQHMJAFI&b%dXyPhTQgR2NH6&L6+f*QL^h8`9p3LHfEYcELobow5YuOrmK|6jd0)u{@K$D!7 z>J)95^>Q!=N<~xU5o6cE)#2=lAT`A+5AssC{?Zo&O~^nBQ2@d*(5}r2`Jm-N(D3%1 zYB_6IdraEW z3P4%2BGf%kYQkd$B9Ta}V4}@EtS}J~6XedU#fLtT9sD|D7mPe2459=(yX8DP z93cyov1R#ehH0H2vlr!A80cQkbddHcC7YJy9=fEO6G%u9!BXYxv{^w1iQ-j+ z9W&A9$(7i$O_f7sUeG<=%L4;p7UaxO1Bd` ze&E9#FW963jJW)w1XxrwAX{sL)fNTJsV<7|k{}s^n_*KVHwV>xeUp*1Nedq@(;Ww5j!>@_fvKtUFu$nrN6T!sVgd<0pq4h_4Mco7vI zC`fuS05BUQgL>o=4-nj{(XN&(XOdJDMjfLfSx6F60}3Y_7|BFWS(RXd0*t=e+`Y`w zX8YXzwJ*Hhx{kj$JDs0Z9L{~R7!MiZXq|D`e*qLrJ!9Itm;@liXNKCBvqnS+9_Csn z%8C@un9kl<_#KBLyerwJ^Uk!`QB!Bp14g~TFbu6F)0JBex4jTq-U>{F9`3z>>QvOh z7+4kx6~~w4T*PFGE$Euq$8GbxE|Z{K_82JcYcYjg(AODSuZ|VZOhEcr5-^Yu(WVm& zf26mO-Q8*QZIUcpvNHDaGWN1s-F+y>QhDcoM}J8|qN=wkddV3qf~zvu~>+&UIe03IveY&Rn#Z9i%*x{H@qyk23mn-w&bO%A zPzuzt1YM`RqpeqkHR#PFHd+HP97elFe}oD|b@k~xFadz4L4ki42Fk=M3l##DE7nxN zZmP=rcxPmgA{4;hfsQJHIN78T*$Au6rrz<8z=}$A+SO1yEwqD^RZ19YjdOiqd5REI zqrxWsD28`Tb3)(*(C8&=q7#wjuBal#f_l0GwfMSJlG9cqJKpNw&)Vu8ENb^Xf6pTc zYK3Dq&frK3Go1X=`l7>jISfR$g zo?2mmus)_ifd)|K6s1I22O!f(bP4*O zXkZ@&)fWgl&5D??v_RHme+|fCqKF=&08;ve5z{f(>=7V?yw$|uDTK}pl_ksJ<{*Lz zk_3exBttOy%->$8Pc{*iZTZYw#ha6Yve{DGjah+aDDU63pO@+&V}_B|zET>s$7p0g zYX-}ENF*-$_rsD6NDeRG^lCfB4zBnoca{5mqboO3#~zH;94}DbY(~7@bdesIs7?hrLu#WG{$efJ?7X$%c|biF zLttSDzcBqTS1oc4MSizUgo{v5Y>@!215GPL?g9uAL<~f;e+!4H?=B(`v+1lhY@o?z zJ>9EP9)~vxmHt{Heu3pKrkq{qPX+TQVBWj1fjW( zFqdj5iAdlnh6do%mc4A8-~d!H3%LLQFm1{O!I(95fmAzq?Ra$n8?tL{tuxnV{=PlU zT3jPEy4|+8Aj=g9Ga=8xfCLdv?<@B=Sq}zN0Z5>qL4n_6F`W)!qgr)PeE5w+Xi=zW z2LWYb>=R_|ag2`^LDV(D8(0ff1KHzmE7Q6p7C_{XEXc;*KAbppyT4uD6PS|%OEQ17 zbW35H^P|h3(pa33U74dQwH>Q)V)wgnOn{hl;EYGKsT4r7i9{meT(1b*lrN5lj$SB4 z8GxXo^)+q;fFjMSRuTdnA&d8h(QK7yC%4Et^ee+EM;~H9hqZv95Lg)gdVnGCwNqOG zp>u=Yq&TvuZ?R-VOg3;BP(PtjO$~ooovcWB019blsLCWbFoy@O_^MznS&{Zx!oA2p3S-RNO~%3hu+t zBD@Q~PlvSPoObhrCS;h$9%ujgf!wNpBj4_o($eyl(?x3LFtx4~mCRl&~NSKt~`%0U%1k zLc7gR56%{GpH7;2Am)8pHN)RXpdG*`7|F|bJ90g@>7LN|#1p=|^}>e5ww07*Il6|reNOVz2j121=mIj~}fV(eYd59S;ZH}b?gkgntaUI+t-!G=Ef zz}82J^Ldo3`*9zve5!%xTb)OBMR&%K){po1$iWJKJL_xy8s!6n2dn~PyCGcsVs?%gf0>O>#`cC@v;zbiOf%N6TNMeabpdCY86xprpU09uFT zz>f&CQ9q#~EVoAdbH%n9x%hgVd3g?87etPycuau{oWw|pl#zd8L%ErWmf~4-$}D9K zm6)A=b{o?=+aJ7^qnym69g+Jx%M)|?#>QPhFWPB+%QyE~DRSZ)d! zgJh2ASAE=@gw|=h>6Gi15bU0N)jB#P*S$N^YHgRf3(1_M6nB#@2)VH8n%O5roJ+BF z4pB*fU<5iM3Mqdmq>`FA+4VAZO@~^q8gYB=Gb5dL;o-TvkP^ZrTG z&k6=I{6n_%<>o!|8uy(qaR4G4f&fGY$>fYa@3Rka4c-?OxR~Aw3u`S!hliCFW36P0 z0?8i@xHHPoch_t!a#}1Y$o3^&jSjk0nvxUpud|xxTIPS~FCaA>fYEEyJ%M@!;dq6l zgfhHdC9n*cdn%`S?pxCp6*(j9H^Lm`*hc%`iMshsp4|atAaR+mqNpMS2P%I81VI?5 ze3S`ez8!9c)|h$owGJgtnx2B@+#rpFabnLqD-KTWr6(QMc~e{7?8ROkbD^Fy7cm&+ zdbbW1BT~h>J39a1@9V-(XWc5VzoLozECCf~8OYAaWNR z#pjKk?Kyoxf4GY=^d-OJ)QyJp1MuxpuOEMI(0bsKk?QV`12#zrQG6?mk zu8)7MqI1P~=|EdPr&aPOsuB{2qN#cG#u$#R-s#v*hYg#69AP=W!aYdnABdL z2;z8Qqmzw?e1*anh@{#%cJi^VkzxY$d_I48RXWLwmUynUaO&d-Vd0!ZjL%&Kn7k7< z;l?TDQb1T{Zmccw0sfC9H>CSCKL-2eBpzOF!-+I=$^(;5gOC^wdgz)E!jcC@1Stt5 zhFRF0P_dSq^6bYgacvBI{l7QZs&UJpqYQ3*0cLA1atFTWpm_-52GSUzf}nR=h<1N7 za|2YnCDLf*$#f)GDGIKR3A1JJSvK0kz0an#J=1*r=_ktTrh}U0HXTTLytr$|rbMG0 zPcG-Yy@P!r?r(Dog#bc`d?=`8MFf85JuSN0ZtbJj#`|lg#^C^xLIY_e7^(oO2`4sI z;f|aATs>_)b*+~mt=+iel}nMGiuZqUu91X`HFB-Vs$9q1x!K>1?T?eMbVN^}?Qq14 zG-Mfmp_#cMg9{NQ-QCP2o-@S7Am`A*0?y@}5@QHCH0keE5Zs!q_o-xspE@ohdA>3+HMpC4k8@=2af%kI{GExYFp8_1h2pmv-v%8EL>CVC+ z9f;V#1P+u0$TB31t9jlL*dTvIY-OOl$-$7|APKu!Cw|L90LCLB;fOLq;W90*mxyST z;rh7RyX}pdC}V7;Y0GJ<52;`68o%XoK6tPMKU2oKG+*OXt5bWu;D$BAe|vO zx6V|)pGz&YFzc1RoI5cvSSG@30!#3MEgRa6(bz^UsE2gUO{N>~;W~et8cxLLgz$DP zZOTQQ*rJ+&6N!6N?1?-T6x~b-Dw3XG8b>D&ZD6JyB?lmpg38cAi91Wg41}%gS9f`J zR3y5FKvlc9Sp_?jZpr1=2tcVp$!$}(!porw2zRPb&<#t;5jb+_f+*_b#|}B(+IgjL z6>OQ{^2cF4Q;&B!$P<4YSe;3%eJD+y&zEb)S!(%Qq6z4A{vzF|8JgnwPdODGcuJQA(Y--tZ#81RFjc3I!I|FN&H3u_p;+ znL9A2gsxrjJMK<$npmy%HsU_a$h@eemvUPaOO4oBj>*0n+~0qF1+)=2Nr)79;)iCg z@XphNgxU%lURZD@JP?gzc!Pk46$a3NLxh~ZA9!gj7G0W)5d>l+U71s3v6C=)jV2&< zX@vqwkZvsCxG^sHg$NwWyk*`bP9*~Y&@kgz-l)hnEeI*^Fe_T91z^llXL+#zI4Rx1 z4>c5I4!4(J|hW{GWA`qg71-^^@^cUw@Gt zE*MWbE)d54n-lM-4qca+8>_I!OV0_$%}@exWkB%C)()8iWqv4gED0F zr*e}_gT+fvdsbEf65#|@U?#rmWS}VL-Ah72&PFg~w*3L;iUEcT1_tVd?oFh7UL@@k zs?RKS=(T`@t$BbLUf7~G<^wV$QGea!XPg7UN%TWj=wMGrX8GzV$fPR@5C^Ih@e~;H zqC#-nT{4cGJ-1Q&G!P{-O&tq5*t}1Aib)Kd;i=9*j8Ig|r0fhVB8}+esO?>`WQb4< zRf@}RTZ)#_U=3lrG{J0Pr%4tXK*kl2n5rsZ185D40U8Mbk{0mGoxc9<=YN-F9d&$9 zpWs~PW%5@}Wi0YhwM9f?f#lxnQt9-jD+j}|bA*&FGnXI{r-h;vB#pJZ6w4rDvNaDO591gh%|he45V zl!oDpXokeBK5$w^Ne5*EXrH%_uh4isV3)>bCP)StS8Rae9+{KD4q69t9=YR@EZr>gLnLfKRi52Pd0W={F)>cncYITRjJ;(#XACV)`f#4W(|>F3{z`4p%g z1R#%i?j8qQeXSAAuzw-I!9d;>Mi`iCVLLci;f#X5>!olJtq){YLF3+v0t_5dju=rj@7!@J*UIrL=&EPE@Dd=^^Ob*sB3dD7s4FAf~s-4IA&<)H)!sZ{h@jF9CAE&M&e=UeLp zP#;2hlnTqkIc4Jv6N>MSGe{ug)p;LOYc6ZXD_X6TjhNc^=tpjN7LEza16bb zR4KOfvLYaWK?D*(1UFjvy4(gf&gsmGQ9$>q)qcO15v@m}5eL`TgT92OK8<|jUxR4z z5FC)DauvX>~sn@xnxytc4`HI2-v z6E}Ns+rz6%q_?T@+smm76gb|Yv`OCccO)B>j#I9t>Z;*5Tbtu9jx!c#7)GVzHHog( zAb;3R-8WI#QbKw+P4qLJ?q>&%vXJl8!l!nqjFjnyrRQ$0@y1%nsvS9zGq*FNi8Eb* zM@yu*tKkT783ht{q@;89|4O-YahyCmZbO8J2Dy8bG_QbSQ?WW@rJ<+X!L9^RkcxX6q>>mHqJnSD^;>zUajl>>>=S5hx%dpC_e9TKW3f;cX3Xcd~YJ2tUo(r8K8 z=JrCe8zB_O5>Ell&Fe=7C1`TfcG4)UNhHZDQD!otilbWEG3kDnqG(S}{>P)f-@0Xe z;z{ZtX|c07h`T2q6e+=29Yu^ZW!zh`_;$#})eA<&7fDfy3ltV82^D1|q$z<8^UtR| zyfMJiZHk(`mcimfY=nR&_DZ7!RXcACS%Sn8h4ZoyG5KbbfnF1Tcz4A$(T=|lp2A78J;^>f{};<9wU3kn>CYmEgFvfDWG+~%B9VyOiR z397B?wmQbuTo{9qDUm?fyg75GwUeW;lV%m2d^ospm5b`3SfI`PI+iDf{_$;<9ngVS z$sr`ckHq~xXWNexjFN;S>mgt=INiB~AJROY*OQ->)~Akt`iU*6RD>lI%=K`v?$rQD zO_c&gkQPWRg>9p~1CC{N>^+)h21M{lA&}V!G|Rf!AWjAfLM#A^NGu2&8ZO$)6(*N3 zh&yF#WHk$<6~K8v7JFDMJ-XD1Z6`E}6RI6D$u#YENsN?%=Ih3dB)NtprUDu8%2041 zQx}FszFhHta&bRHA`lQI%mhK|-O|X3S>n1{?wpo_6J&><1-w9nC}$p9L>Gnz-w)XG zXrAxIz7a{$B<6);ktn1o3_=CXKzIADzss}L16LYVWNvDMrt9r_0SpZ8olUq`j&X6b zX-a>A(ZZEHEWlLj0zpqW&Eo7r5BA|}~IJvXXriXJI9rdDFx zk!jmz=Brxfrlez8VH{kJQBxy&n?f-sEH%lb&3Nv}#}^cd$s3#-3n-BSa%3FT6vI$? z2wfpViIpk>qD@Ll6~f37l4h|gV2Cnrp4@Wmpp4IQvX+2!p+vN~OwO-@+9)3*fxDk8n6p3x%H2!l#HJ zvdhsObLbfXEDYK)d@kb!_9cXhfEJV4Tf?fChk3D6n##2S z(gGmgC#qH}fGh)zbbK>H2#_z1IdS(7LVpYI{@p;dv5}zJk+SFZ0+qS=T&?G;Si7Wu zblNNzS_Z%fv=N}QI@~O-mNy47p^kfbS55gA+OpP(t0oTPs^{3qp^g%~CSYzHW zxaq1is;g}F*fuympPHnWTwumtir7F>?vDxj>e6YD<=t?Fk%=wtJq1DG{dJzybk0^udr6;~mzPO@mst3mM3_i`el2-=b_u?@X6^68H=yk{&1NvbbG4VR zr+*)VuI9PChL{=Sw8chzhY=oQZQClmJ~lX=^B0d@4?5S9jEN{-dV5PaZc3kb#AIqS zGg|GJUL8=}h;JcEi!COiK26tUPe73TnO@UHeUT2{b@jNEX2?E1b_%(FMZ^sVovf5e zBEV1~a*-NDn91GQ;NocXP&5KD6^hzIM0BxVXRxm(6T!_zZ3`%(9Tq@mz50d~U4`;{ zGw22F==j8X-Up@c@bvh3=5yPA$wI~?PWBWcaq3jGVUsBpXRfW`o+ZVaR4}REY75hg zd@p+UnQP)AImt4V{qj#9)CRkWi8ip7yZm2FlkpwiJs9a^kJ zV=~IbMkuQlqKZ2EzK;xvCwYxDzsZ+VOOS@`8K#@bi{S_PpPhGqtK&-Vbz<@mFIOF2 z`{~$6o4~1%qK{DlvV~_1@S&z@a+PwJl>}Jbxng?azy7 zRdW>ZN;tV?^lY%zN~>lH8?z0Sp{nTXsFoU-xmd_U6sa6tWTccMr^PcWB1Ge40xM*~ z$%12whn>u_s!sNQ6Pr4tlK844j)2#aP8 z5n`+`v`j1vNfu&7QH>K4IaHKN$re`zV3?Bfxt0R!oJoj(>kPI9LP?P@uGyKc8z2=G zR!NajawY+^gi5JUiIoW0PM`DU(N`Y)65E4wPhNcI* zKq_XSDJlyrVOSHBEF>9@;z+WxvK1g!ESB1=g>i(zAPQjPFkrC3qEQG?kPwF;@1Sed zvQ5);oY)nH+N2^OG?JtdBFI5Q6fhKQju^R6A_{tckO25D1>Q0d02#LV9dM1OuyWr$ z{0C)xo&<;!72K@dtiX`n%pS_*t}EcWtgTVpxH%T~XW?nER6rn-K?bF?p8w?d#NTB~ z)K|%9y4GTe7^{dw#gl8uSYpX8%0(cgRe+=F;i_C138`$t%2Os8!;+}&qAH3aqCkk< zn{ppH39BR~NNyQwU?J0S!**sQfKXg2C@2e+#z^2IPNhV3AhJXXBt;Z!TNiBru;Lu_?{$j#~8IDz@sIA26mt&TDaG_IGwMncE$YcSg}U~ zBk3PQK{5*%@hK>zGw$LN9XMAimIVYAgA|IQDn&*j2&kffuuxS|K~WYf(#b9yl4-9U zj_!OjHm*Kc*At3~4z`MNa=T`oCzYr}2zd2>04o+re2d!V2wh1Wd#Ju?KqeUq+dn-o zk_sT1RC3&L=Y1=d*WAGknIJ+M*$e24>CVAPJlwmQPH`O69*Q1S7Lgd(Nc-6ZS@ z1(l#kQhfm(O47Bd=<+LIFei&sdGjmkY<+e)%SKu$QybdaDqO68%9qiYFAYFAS0RM9e`K}wXG^7=dPk8_A9K}al{ zpgdSgfJKBB3M^6)L13hdNIa_6Yold3r>CBu9wz&3u8zg+QBagaS2%CFaCXsq)b4=i zUtNnu0FbtYL>BYk(Z}4=)6_qI3#UZuEA9QY^{TULzu)oR0{u-9Z2x$l-lFC-@BY(ot#GWd9v_LE!hQv^I z*W3ekXK+$NIEXmkIk$qe8cnk^ElVI(%I~c0Ev;zpilZ?TXH7eHG70K`{CWirqo+)z z96jlV+nOgN=*h!RG@1EdJ!@TDudK(1tuXQ10^pp3k(14j8Q>c0}=E{T_->BJWX z{fC&DMI3d2U??)O<8HMqwjB1}BD&yoGn0+qLknaz67C&soaHFUcTctI&u=wdIp0xq z&iQ_ar6D%EPDOJxo%@)7+=O$&auNyGQGB7x_Zn2y1Of{JM+xlj@!$^rKOQrYm*<&& zCv$xzP8_`S-mWfqe&@fJalA0mhgpD1c!1|So<~Wo=HV(@8l(1E#g{iA2kK}WXQ3=_ z&@;XqfEQRM8dx`X6hHu#rZ1gJ5$?#;{7-Ycb-01CM^imfDYfr^&`yWi`W}%`W+C9g ze`78#61|p1qAmGAOc$3wYHN#p^2Z~t=mK;)WT@fb)L&z~gG(R=&sUnUpKBOsw z^)(VEcEIMDLNvJcINV0tN4V|2UTtiVbF;RHfJ8__dZb&3Q-l$myNwpeAUGC8xCDoE zK{xDr^_`q*=)N;$;)D#%?pucbr-0>-dFE-j3?!cxL!%*oqX4=nC<3hWn(AZ%Y{|nk z$txS|-t_hpeVBCJ$1&BduEBKE01#Vdb*R+#xIxN@p%DqR)8ZEJzq zBht8_Wy5@bl_5pMnzQf>7+$$EeR^LrH@DYrF3-D=lL*u*xyUJ2Km_Fw_?ej-19JOF z0kf+KM|21*3l7QxTl;t&?_OqbqlSOv;qSU=^Tvb{9Z` z-iRPefM=%y;wVrN(C9spxR0H?{E66bX_|r$gambeX8TKzN!~cM4~G|&VK_c1bi&+{ z0S9Sq2!>x?H^5VZS=Wo~{7CNNHqFLyup#P(AIKLoVQOz_mb%m2{Z6-Hv!R_ph)pt@ zGY$?liM{iTsS}wHGy-{p6Bsp_4+Q}5CWNAI7AgV}qm5xwHLYZ5q7@=CL|e?fA!AdE z8K%~M_}IcdcbCTMmR;)e=O|k98P@fI#-C`t%|8271-|urtJFQ5WDxLh6z___gTZVI zl2UzKUU9m8ajTizU{ou%aLz%$u;PMHGWZ(}_E zTc)reK3K}2y8P0@s70TPUzJ;**O4>#syBD3(k->!de2 ziTNw5g^id7@XQf2(7+ryJf-4LG%Cf0hg*dwH{gOm5GG)3n4raMfN>cJhqCP%V<`3C zxXReAxCoQ+Zxes*>*Og!5kN`{GF0MG?^|GR4**qcK$yS~7hGqFp2q~v&R(c1k2Gpn zBFq4SW+q}C1>8@sq~Oh7Q?Wj*p>?yi zBqz1j69Y^D0RinJ*O9za3ZyQT&6dnB%9`t-KpsrgfVzJ%7d^FB75Ry;i^hgN5F=iD z?wBu02$p<6fO&EGg}uJtXuQgg&8lSCp0Yz8-Bx%lRO(d=)bzQYZLoxq`%6ZL74pjq z)MqwuwE%cfq^OS_kahq;K#3a2P4=l|xD?sP9a`AM;Efshyr20#OW z04xF;+4z4bc!YKu@qD8D`}>q&B=iXQgaJ7I10sQltghf_au!?CRUE=VuA(?w8c|e< z!`HaEj(i1sNG8axfkz&i&!Ss0ED401 zun2!$bgm#=`1Z!M%0;m8<(u9d04TPwP#8kabt8QubGTn)$69ZkvjHUUyC<#Ik3h3d zzXznipipusx}vg_sk2(Xojf$>C1w;ze4nr3Y4BY2XHZ7T?`Oq_%8=g4liyqIPaXMM zHmEgOA+s<^r152&B!yuX4w_@L0L?UUaR7fK6k>r{T@{;gCZl&5D8s6`YJ!`M5ezQvAO-^Xn%%$(cZ zxUR@}K929Pa*|bx35Z!~FNa=}16L$>>p|*P{axJc3J8Y*%?yGo@&1GD`|BJtR}+6A z=IgLHGzVac4NyU+qoEn|7_v-~iJ<{V>4s?iR=6|-oE%4#fr2>*!&*9Xm5!iry+W3#;1F^K%+beoQ!3wE!g=&<+%j{CPr)RmL1 zV$InffTD*d4;WC90Y_Z%?U+~+B6Tnltb{&+y!5Z5^YSkdbP$ZU6`6p{o5R}m`(26T+XA@0zGd~iB>VC)0T~2jkpf$v zZ+AoRyn68-IdF5i)t&iML=AtK*yvU$DvF{e_&a$3V$V&ap$JD4(RjzA>cfs+e<*<& zhdHgcx!@{035LNP*@$F2YTT%V0_2Mkg_;uEJv%kT483I(m;Pf zUp`FGML>{M#_>TxuAQ8{T`E!?ci(?7;!EUQuqiEqjE5|3ytRNJl#G9Ept(muB{f2q3^a8etrohOy^st#+Gu~86w00%TWTQIB&S=F_&jK#B3L~}rLCO4Zk~o~Hft9HH0H6g z2nN6-16U&*F_ufc?|Yq=fy@VBlluXa_`amI1{%tt0H7o?NtiP?GsY*tTH|yFgJ?4I zt;dS=^-yPC&0HAz6*Y#=x#ri-r4!*fN;>KYu~NNEI^EeNM@)POO!CIBpIXn<&X|qja6yR+Zrk)UfVj2ziMRndC^!S4)lHrr?;>jw3Yh6Xy5SCx@mWYQWj84{}QqMNibKO%RbwRRFO{ zWLY799^Qo3yE%VXe(n=4IpvJ}Zs7y2XQXF-By_hiVVK<)cBx><@|RlBd%>>Fy+Z#u zKWX`{8+8}zzWp7M=Yj>_B|tCHQQ}ZmVpV}xmI#_v#GwP)h%i;1LzaFVHOjT!$85h@ z`DtZ({5AGI?#t+h$}#wJFP`9tins-x_W5E6pn@`rXo*Ea%7 zz(d*d`)MQLn*eC6k&vIwFcAkk!~BSRn7z4HE>Ni)vBcqndo<2~14q+B@>&kotiIb7 z!Fx%EPr-kggF>N70fVe1e4^mX|_w%oqfys6hKn8!oS;XjcX5NAfVP+4%J$&i#K%;4q zXe`_BrlT# z=VX5aX#$3rDlSW{?1IQ~A!!J2PI)J8URqZ8c5dh2j}u_!<-!&2OZnqs2-7?xH@py! z&nUB_7+e%=jKC)*pENxM{K_!y){HQKKFDy_6+3tL^WBd9UoCt7pI#?{;52&nUT@Tf z!6dvOpUjI8C}DzNjT9nVMQCO;%)5fgOgDejfI#vkHYf+zgf~J)PVv8^Uc8U0AZ#@p zD^L=!m(unq1(1}vO5+$aZEv>Mmw-WXQqm=;)Ku$HbXsturuz>%?#o^w<{yLF4k_M+ z`U{(-M2c4-2z`03yQbC#VlT{iG*^~f5(iUV!uO;kv2?IRL`E=t=}}}9Rah~SC;)%3 z6r45YTC#qL$rHka><^y9eOP~b#7Bx7 zynLSf_GepfvD>FF5JD}$;9?*oye^4BL34B}C#+?5p@-OEUX%U3fKCY8Czl^|f=MKt z?JavKAOM{L4D1w)@;*MZ;f(u_VZR4xJ!#(Wiiz!I^pZ(@4qmhF+F8z@J^gy%!D~Em zFR|Aq!M;O9tbl9`7s zspsuMG31>Ct+1!V7tf5DK;q3!FWqYvt6jk=2{S$dWKC+jj@#}h9V*(} z=lhq*4g!KmfW-%$XQVPT4JJhk|4l{DTU!BN8lT4oI;ijkBpH%aRb1Gg3DvR#AGPR1q?>1qsyZ z^QpPeoU)51v4QnDuI*s{L`Hr?@KFPn!V$s7? zsNLPNY*rF3?AKBYR@);oMFs>Uf-s2WP|ixSLfN<4KoE){er~voI3o5KPGdao;Fp zyx`r?8c->=I zLI8|I8If-`zgxpdC_GEoTiuO^!o7GdPQ=zOs-ZmOJTciNb)v?WLY6495g%mI1XCS5 zyY}v>;--I5OqI=WEWz=3%pfTMP!gm9NI+2@Q4i zD}9_>0D-{;2-ZNj)G#UIvgZfv6)P-FiqKM{8VT*0_1<~PHT4WG=TE< zWeoK57ksAsELa0B`kp!GbmqqN764$-;3gyyT_Ar*>z6%8DT%O{Aw$U|s;}&-g9`PJ zhskvwJ{xi4LM;(*jG5x z34?R!y9$i*TJ?z_Ks_2qT!$Gsvq7(I_Et6M5J6`k1Vm=7)3MxP0BQ+~XQGFT$_)YL zQeuBsFdJ9^2MqSVZI{KQ7;6ybMu!}**yoYMMCJ%_i31z%;)#z2d)^2-b=KzEAM5Y% z1HQVP*l5CYR!-aZ*lp=nF^VW`+Ni5rwyp=MfKc&Cht&6`EgIbF28@Lm(HpXuj2B%W6(@TK!7U_?Rtp}A?x;+2XVm8KGdaZ*E?tN@k*mX` z8@B;gxND|~%JFscMO7i2jWip@b>x4gU~s%BP`o(F9N9cTI51G4D3HWf_sBs6Hv{C( z(9qZzU5eyuM2?t1PMmNqUEywD%tsKX&Y!FuZZ3slH6s*rm>tI8jk=fDPJnegfaeIp z?ZFU~72AwuB^AmzE&^)ki02tX0kjw0aDogWaL(b^Kmu2k?2K@5zBpJ~(SUz(y)S+Z zY*s7>qz#+Tssn&R5GWCCz}m%unl?CIK7St(tfpX?oDT}RnzKX`s`|BP8{d2|6Wa!O zTyMI7avdlg2_>+%ShXA!I1Os&xdp4UbB5I5l7pzjAcR8S}!{cvn{Y_}mnWSTka zI>g}T7eiLC9|%!(~T(ReXQM<6y*9N7N{Y z5Fm4t7@Q{wz+*vM3E{_1F4i5*o&gpQ>G1aB;$X=G4>)k|)9Z&61w+rVG)jP6iM>a{ zoJIA0r5yYR!|H8yepvZqZ~y>V48w2{VcZ16q$#x2j!JOo6Rj*Urf;JlGd3ns8709^ zi@a1iPl<#}r_ECl^~*KX5Ue$Sf`N#r%d)5EnurUWA#R|%Ad65o)qTxahztzspfG0^ zs=?>j?87$Cfz;<)4oeIHke>^={F%Wao`2Sb3#$sz(*)O5!hI(8kJ7Y#J$)7$L| z#l$K_A#Ey3$tw!U3LyzeS2tAIgKONtwzA9#I^ZUJ>c$X~X=L~G@83pLm>$q*06AJ7m=5OOe2qZRi=EReXs z-jlQOpg^6yhhH46P2CLk^KlUp9RorJ=eZINS)oM$EmYyLUXHLy^J(H}2`KS8O~cE| z;nh%usd;^4R(h7SNG=V*?_gC>$g^Ep0vo-R0%KF_;>WHR1(dCSDgw$XQp7_ZXi0ye z<RS!{Kh8z$kRO%MTpb1a``7ksIzONRyUSCbcF9JmPS(4z6Lt!!DiH zu7+H8Dh7y>1fCoMj=Oc4=^eKg1-RgH>jh31V9Ce@kky^3d#fGq#dy$`y5{F zF+o%zF+tC*m@$`!WnzpM?zy?_n35l16ah$}iXktzVTG2hOtys$R?2G}hmnL%luO1;q>Ul8pvNwDVqFo%m4R6sCPs`Za-bNPoNv4j8fqax06VO` z=7ULpA_dN+vB8~Pn{cktCEI+>z)j+Ot7H$LULxCX&ycHH1OgDD8;b>hWdW8rYqtw+ZL;H2_W^jjUUcD*6RcWj zKvygrO}Lok#gapGYMpd{U%|JZ=YQ4p&Q5k%Kb8N={Ae`;EACX~ov~5Vv|;$^Bt3Yk zOfo#f)y5iI*}_sjMN5sm5?k!Ix93=)vJUeNq0>L7;lt+8^KF?Az4CLnJ?Yz?zn4{i z%j8N`&tA!u1!6)Q&4_bkhwktr2*@Zg1&~q$0DLyEZs*dwEO3%i25@$+=mopHQiJM1 zQ06k3j^e@?kYWOo2+0;jfS@T6kz`m30)Vg-P>6(!Bv4|qAV{ksNTNs}NGTCwiFAIA zLvfwxi%tWP5g2!-l?WYjyd(`AA@inxp0Awq;JxaiV!85`@;%25-IQEt1&RSQy-ou#n)B{t&t{UK`d;6EKYlZ65d^)~|JUO-(sukB{ z5#m8a5zQbagP zjfHYFu-8#{;~_x>N+LlRV$SPT64K1Dim@7Zo{yiVpKA25=Z<%Q#EKPKlBKq(QX*0s zFWZgwK!AZZ0pA^a`igzXHA(0z2z;DR6!}!gVd{rD8*_XeKQ#)-Gx6a!X+oJYL*9_j z(uvK7ViL)c0w-!i*4eT`p2UHF`l|?THa$1`>ee{q!Fle=Uy|>9j9r9ZbA~+EBO)F^ zdE#eTr53RujJksgoVZ}_t-V}#-_M9VLSi1zZbmMwDWEYkY7a!h`1$SiAUh7I8YI6B z-R0rekcE~A!1Z|bBs-6OL4?5EP--1rFr5FVsC;Y$g@btr!wKh!ctTiz0S5`Vc}gRQ zL0tvYuZ1||9cNLj8H7Bw`|~qvd_~&is5% zxieuO4_F9PJ=@h{FV2`mf%s4NZo_T&PtCCT{_D>j(p#p?~yN*vv6)QDKZdfBMMX)LJHwZbpUp;$<;oe%<~B#R>LXbK2=ER+*{ zW>e3sSrju?OcJmKkin3mgsxvl!q`kQR*hJqjx5nHG4Aza3}g>WW63yMPi@M>Ljo-L zdzW>s2GZCOB0(dBRmBjJMB5MRnO6lK^9P2p2MU#RDa}5Y91Y#@F$la3z8BZ6BwAPTl zJz7W@W_k3!im;PbWU1JYn=|$vzkkQOcU&};ZP+b><#?A8?XvvacX`)8N;^|>V_JaP zp#iGdJ(jnBrN|ga0+5pKj0gh2f`AJN35ZCYdm*|>0MI1+BP@VAABbBv(nSbH5*az` zafiDt4EfdVrVOOIUICL2+z=-p9j4Qc+b2DBzS9Q$sviAKcwgbAIUkMG3-H1fB&Z<5 zcGyeJzrDuTnywWM2<9xq>NaP^OUORY8Ni7JfGL1~%qS3nc5%pGlv<-ik_FfgAfgBr zs^IYGaz8?6U^aHlLk9t@bjkd9Tuhv!5{3%|=CEiv7j^}>bPy5P<7@Hotxg75-{)Ij zGXbDz>gLbQNj!9@69z4mZPo*;{Km;r~N50Jf$oY@MJkTcGiJI-7$ z(Q?jzHe`*{_HG?KvhI2H6|PS##V%^zo9}-p#HM6+lz|T^+(&#A)+JXmQT zUw(PjnL)HggY$1ev>-027Tg<3+OoP}b=3iPX3S%QD^-TQ&&0?Yei9U&ws4*n>Xt2~ zx22X&cejm9cV$)^r5}3Hj7+pDsFS(D6=I5iDFol-oF;PRkS~kiVKjoA*+e&GETYAj zD4~eo2X`%R-PeVYb!4L%(F3P_81SPQFS)!qrY%w< zTauu%?Iws8NMj%@*^*HO1I%k#I5L=!*+h#mKoJB?1u;TME&z#JELymbs6k1Loz|>> zfS_Voz1x)yGVPS&R=K!(TXST>Nf^h)3W7L$SE1fe8P*FI;ZyLiUf*V_3m9k9ye}tF z!Xwp0&DK^N;Zh{on1Oo_<^HFy=l*|B-uqlXUl#WNtqKVtKK9EGq7fRvo@+@zK-OzU zW+KAn%&RdmBrzuz#gQ4SV|9}lB17?i)~SOE!Yr88K~zy-xal!#_-vJnnz%7RL@8in zA&Hi$7=to=y@u%miELcRfmK{lN|6;Z%w`CogG2?XSgrSO@;a?m-WO|qcT2_nEm27hk)7%h>52uxhFN zORX|G>?vF`Qp_`+xAfm(^89}t$>g#8&E;56eZk7=v3i>(XBA7`CL3*_;#%YJIRm@I z3&?!Rwet#%kCB0_?r^j;_2odf*!Ns*s=zxPX?-*mOwJ?>Czmk{)9vo?)+?E>ue9R~ z-|zg^5_dh3A6xj?#S^-J-=$B|+Xu3z>OcF5e~0xqKknp+2j~8l^!j9UmcAYSCl|?A z^YBVjM?0GBRso`?lR4g2ml_RSuy8oa0hh_$cDS=GxcWb@9iQYw57yh%LkSKpvitpX zn2vL5r~+G{o-{H2=cA~@dKN_TFt{G3Q#Wsl!+QD3hF?oY2_Jzpyx-@1zrB?A9e&E| r3*ung&J6L&-Ms3gLprH4CKHGKMciZc(sPAK-4z$|>@~}JWx4l)~)R67&dhaj{qyPmQSW)ijwsPLt z%o5lzS22G(y-u}28dc-aJ!*Hg&J&WV-OJwUZh8XtG+R#ddPUq3TexK%Vb4tIwLC`F zHw(30iXtr000000000q00000 z02*ngfEoY+5|R@_4FG5p)YSCyOhZjHo~i9MPckU{sqGWVPsmRwVKB;{ik@jFw5NaR zl`?x&{7q4^dW_LcKPHVSnLRW~`b|$$@~7%DPbP<@4^zr*P3cb(ZBHrbr|O$QP3jZ$ zr>X5Spp#J$KoCIG$OvjdDEL{a$vcQA%AK~_bAkwig3U@D>?X{AL`g8xZ>qCp>> z22=%zq9`iBQYa$5}^+|v#Wyb_T#AU+R1b85SA_$_Wim0lps&)-URw@|NEfhu~!9j`C)nx1yf*>fd zMI#t0z)~nGsT5eTL5QlcNU=yP79fH!QAJ<~EJ(~1oz{0LY!DlqW0wNroSZsiiFeKe zg=$G4N#vpt0S76|Y1GSyV;YJp8)p4imUVTPww5BLv>Js(h^rA;A}R`hA|eVRRIpf) zilR{{F^C|=5LH$QY_Un&g=P%|SgguhOIcShe2{zL2_z^m0FX!^NJ*^186g5qXTa2& z1`Nzt7GMBv_S=p5a-DQgXP&iYFpLab)y>Jgbv6;n%A8eOj`^IJm=FfCF*7<3`Y+LT z{pa`3(T~;a{6-&#Pt%`&)vG7!mF7p_Q}6^o2c#C(TSS(}seh@Ewl=MH-CX3*|0$7vH zbZ27O@j7+2oA<_xJHpwsk6Nzm1p&ggV$G0X?wt6#!n@uz*2$CN!|=^U$00{nBRJ=7 z?vtWawpVO1f@X7dL(N{rae;3g_4dYjT*iSylUt3PruJEP^(}~|C$xx!-=3t?XUew7s!w?`Vb^CN!9 zCO||8un=Ov6{w>`76cViMM4k|gi%;URFGmsV-x}qVHIS51PBp>2qPqmBt}UDND7ru zq-0=>h*TINKZ3sw1(bB-!#RN@gwNGJx{h$Hpt-mLk1r5aO0TpK5ji9kT|XaIOYBfo z1KolO05@KTbMINMhzfYnKvthpfc)K8SxS^adYCG&%klp8Kq8K=DrO=*1VtV!PWCFN zq4FrXoUdhnPzwD|$3ReU&=I!Y<^Hz=)9HOpcdg`f{T=tufW}YKCA}J52X{Tiel=gtt}_;PXY;}fyAF` zA=ZBH6ZK*Hiw9frSNOep`8+>swXNNGeEwg~^K_qo2bt{mUtag`aDGP4zbS!r{N^U4 z6$A2aZhOyTN5Jm<&5iB4fqS#ser|g|?OJIde@;_riSujbbKi#fh1*y@4&P6e=xr}? z96eUP-xn@+G(Suf0KiWo3ACK2$)LTyW0R|4*?x=-VN^SAlAJgKZsIB6^OO`#_nFo9 zHN2jGT8OHqas#}8h<*3~3);j0f(74jD5KMxs`K8WkVO_Cs-y*q#2AcVzdD6LQ5A^D zsF7lbiYUZU6-FqautqUaj8tNZq)<^{j8z~iDzo%o%IW*Y|7&05KauCAj_Wr4vitA! z0dMWkU+UNPKeO}S{j^{7x#(>DvcvYXneTglPYvmp>2nwCuKVj+kK*HYx@6N!#4}mu zGrx;|Pw&5h)AD{V->=2@f57|?t^64@CiX%AGOdG4^LSCMlFI>o zjr$+Ug;>WDWt;ywbnly9_E%Eo`bxFFOtFEh_czO2=I^C;7#LeramL&0yj4}0#<*91 zN?i=H!nqa~C|d8%m5ZOuq`@J6j!act) z!`^+z_WZ%3Jl^a+hs*AJD)xMM2ENx4yKWh8Eomu*Mw^uITPkefIKbyrzn$caJ ze?OAG|5uyOpP7#(^SmM{IclN(5mqxzpVf(M2^160^pR$fyAfb1U z&;7%s|9ckuv*qv~+%TyA_uH$}?Cg)t>sspag<#R$TH)@*YZx<5j?PUBRDCT`K_?1m zphrwp#IoV!Kw?5hpXhOm+3bo(es+5wWcKJG*k+H{6U`1ciiVXD82i7WPb;_ev7D{@ zMb5j+s=fvIicf2rZXaiV{>}msi$k=)^O?npFV#J?hZ>wNU{TM@tm~x3a$l!6sg%VM z<-$OP>BN2#8rtOk63eZ$Q((^Pz_ktG#2f>HFKj%wD0L7JgNutVw9$j2@tM3);x&v^ zULqi@xWoaJ(sA`oESkmO&4H9+D(uHEZ{Hn!{un_zL)-SD-{kdwp3iR2Yu8n)<@>z% zp691^t?Yfs7YnWpAu${M-@xkiQjb{Zk2>Q~J0BgkBOIsYW~7_xe9t^jZ48>8bBsN2 z+Bytl8{}lY4tC^+;cZ67(VJT#t+TG3UIzyyNXmIvvfedOLvy=ns~51rjvpA`ZShrj z6N7MW?`%E|p{uxmuq?EYD=7WpBam*D>YOaD3hE-fE7k-i_a^7q~B{tuRVR=(l<%W?!X{J%kiz%Cw@9KU$KermIc ztKfomd;#_Rncjbe(v_K%yp>RDpS$Fbzl5Sl!D#L9L7=cn1+HGmnmBkhlVv{=#AAk7iOG~fDOZ5w=fs&4Tt>8UGo1+ee4LU7rza-_J&kl42#lU9XwoesHV?8d^3J_* zi|a&cCzZKrjo+AuvD{j}8D~39L`9&igyFw3zz1dz^LJvl15& zq~f;GnhqlLH6a4*B~Pr~;fG z_NKAbPJg>fPN@5UyfC>h)5-y4CchNO-+OI)5)dT)>UclfEzG-bR_oUL^upp9_BH zdn-h2dCG&Q7kR}AHj^%kRr>hF%Il{m;ysR>D)K9zC)|#Ed@MQV%!E%jIDsL;5F?cB z#0q|ZkEq0D*F7d7rb=M8=*tcE94=yAy?^0Nefg&7%$90 zE`1ci>0*h*<;D3XXOgCntUHRTdf`_KX(KK#wNRNE_@Z$)$6VqM& z)43NbTewi7I8!ARJsoq5LQUTeaSw1PjeqK*8A?v)lM~kt)IhiB=RZ@3JLuGR`m;?I z(fOMZ5b2gvM zHZqfS6o6T7qOK(mldXKvr)Lgw6gez`7{GkTH4nk^_Udtrc^JSGmxvq6!XI01w=*6~ zI7NEZcRM)E+mzDqR4kDu3qbkn>^%DFNw7f)2~t8nk~HE7C#v)>nnx%m$_u3*M}dO} zMa@d}kg#juA4A-b#c|qPy3O6G?SE&pJnumwno&!SU2mHE>61dFEhKuu^3&(!&6)2` z3|B7tmk-~i)Kl>uCGqaUyvpa!zMqP@Cw6?z{X5twuWIP$!sYWcyy3RHy?g~1$3+P& zAil$oUyjZOx{fMmBwXe!k5^1cghm{(G+D$z-D`d+sBl*KvM`IoBGd@cr+?b4(OTPU z^M44~MG*w9`u-D{kPY;~mQokRv_~hQ_Vo5yc~K)Vh%cSXSahf=c^~L;!0PEEbNVV> zvd&W`aSfqUv41!iZft!{)Z^=Z&CnhsQt0l@UJzw)T;O*dFwPirjJByzwAjKhhSs+) zD0S1xo2YGbAvzhC4;u9Ow}0Bcjq>n|lbbPvpB$!2s*jOVFLtIpiIsda=ObSp|edg;C6n16Zl$}Y6&JBLF~ zDnSlORAfA+br7CR z!H7^4IB{K|8@q**eh?@%WC}Jp>O}xuobE zxwlY(CortA-{en?%^3N%h=4^qvz_MPY-GGETNmHr_6MwNZa(&Q_)xNbG!?9@_Tk5# zt^4dboOHIavSp{;;haOcZNWp!<##c9#J_d;k8N<3MvS>Hxqp|5G+Y&srPp*8C@;4j z7@R{v`E5qWQ5EqlLN|N6ne11({;|g1G$PL=b$E8~2C=5yL1q@lz-t62)u-%d0o8TaN!2>S)?fm zp1beIK1Z%s)m_oy@cHi#Lz$u<WQB`;%tvi z#rVYLFpNnNU8j4Og<3-gFmE{2SfO)g=AlyAm-Boy#S8+^Vq7>RpyDY3R3(M0ekeeC zRTVgLB!3D7K9k^`dW)GkIK=WahVAdLLq{1Y-%3!T(1?YKStf6Dx^&@HQ%SOgB8Q`T zP1P=vkgS3X9|F7mOXlGmP(D%81a6@F65=r6K-oC~&mKWD`&17)+8T|7A=o4qp8hD{ zf(u|4Xq4+vt|%ZZ#@CplaR^EhQI%3k9m^*_yCnE>aDBfkanhg*4VC2#OcB6b2ySp# z5xN^TyAJ5H87Q!ZAfc0Q7!`l+^pO4=dn2^ZTBD+va16Q>@tlkuQL#`u7df70rwV6- z2Xq;GPnZ_{3kdbg$wWrU@&F$>3_oKb;C=_6EvQPC={;`EkyFIr$W{zAX}hqRymv>n zyk~^DXexlBoeny6y~zgfh6`O&(|(2MzwNbOPr!W_WU$*mK5?7BY43lSb;_-0r_FU< zM%`vsPn^@K-Y@6^xCx6B)`}1+MSyvb6eUU&+gi$$d6b=r`f(brwDH8xflaALZ(?zx z5de}dUj`ew1Fyx09SLk-Ea!58pWI~*g|$Kf?+>g7W?F^IQUo%zCj?n-R7Sd{XL%G+ zLlMDoa1_N17-_UBy;y%%-*%kdPTf;SNq0&nq{ZXqNFi7_?^#43#7rQl>eec%#A6Ud zMk^H8^g!ldjoyo*tIGUc zCo9A6d(QjkX>54;E8+3H>u>Mi*TZEgjwXgWehnP##^vdY>izDwTdSr|!`13Nepi3Q z+FD=FXU3+_arS@e3?1zNGF_(o#OrJI94cH|@v3h4?k|hmbf=T|Ih{{2_CG)Dzc*3q z;qK8(G@`0KnAo`{&`3Qh=3YDKXpHbPQHca%#TG0T zV#XqhAcCloRRxh%L}XS(6h%>ju@zu~stAlkRY;6g1O!oHs>m^lGAb%D1X3a}V4|>K zh{S&x5fl{?3W6#qsw`DlC@B#Ih>D>FK}A^>D#2oah{aWcGB9GQA|fav#UiX0DzXU@ z2#AWYfS}0{imXINDuRl|MPkVX7^@Kx1!BmetVC8L7BLv0uox_2G73aNL16`p0T5AQ zkz&C?U?~(92#P4GLJCA=5sL+e->tCuj=O&dfy+Tf_PfTCV`T_}w({B%IQWX=?&z$L z`aTLAAfTj?__p%(K3Cy2v?KXjL(!+?Qw9VSd@%SKF_4lW&Ys^Vb^t=MPYtH$8ANI# zItu4yZ`ap-C=TW-IoJiMrT0>!1r=#)O@^dIHd)G|RCn+6R2B&Y0wsO55>}#T#)y9e zNr!tV<6JcZQ(bF>J~cB@>#lxK!8mv~^asYLT_e$$Wjnpt%{%O3wxM@Rlq?dIVO2)` zWsz{Mn9VbJElt|3FZzA!2{N1pP+*+G6ZKHa zZhhFvvmO=azUI&h#RDntSoxlOx28@HSvrm+B@t z{iGoADT3p!Ljn6`b&ut{?Y(k<2MLXHvSD;=vj}2!T=(@Pd9a~sQ6W+YtxA&G3NcmR zx1VJki;(O*947vt&|5)_VJO!8M3N;ZLfnHhwuUC03jG*M1N3_Bo*W9h+S7k@t9*#~ zaUgN_K0Xf}cF!B-%K)p}`r7MjrkHV7_S(zh6R{AC3}J z1dNs?7E%qhsIsFH9te3l_0sap%)>3EZvw|2N!mut$sN-L9ldVRigVa_vVHWd1|!nm zN#f}iii^eJT2YME$a%8)1!E=@ z!_m7_hpEXqN?sJrU@T&BH4rW?aX3$xQWN79Dogd3>XK zKPJRCg=#`^r%gEH1ta;!gh!z2Nk0ZJM-U`@Quf}>0t1WLiX$I)sT1`mgZDq49mC{0-xx{Ree?YT-Vxn*dvFaZ(lA^?fetF2vD zw}p1K`jN0)s7f5j7#wfAzWheUolfT+e0(@yXINU$cP@Wc`101kOHra0a(T&tSN$5iUY=#vy|T9n%WglR%si+h^N2V8JKR z1Wv75+eti7KDYR9F5ZvQHv(q?)X{)>2ebBXlRY9be-Z={6hPjncvT{ojARW1OG^}*X+RqFq#PdPkZt0 z<&DvMdhsznII6;fHIEs;LT?(n=Lt~ zlO#MMCo<$b=7mH>?$$H|H-H24=wyzp-TR=xe?ABTOA^F^_qW@x2)K9Yhk&}`jXct# zSMc4Ya{Ykc?!49|IuJGV+}9L~H5LF2sCeK95l2e^ciw5x41_#gzy`{I|KT#3aGALj>a)R`4Mq znABy3Q$d)d;li8-XpF=_6FASPfyiOdhG2jl2e0?;dDV32A9Vb}NZ)Je6>mh|G6<-d z7{&=9IS}lew7*?M%~VK`h?MR1)J-OE`zE3@A|KMxHd$>hLpt2Gq9BTzsRrtsxg#DI{qc$g37eq$^S)e-%H# z;tC((Xo8r$kRye#L`77IWMrC6OD08;NGPf=%jF^OJM7t6!D^pRwM1r8#Rj6#Pvf)| z%e0C3zuofvJMzBIpIFc5e<#%rUJds{mzQl! zD;5a*A^NRdYtp@x2@nPqSH3XA2(m6yzIR4CI|jKxz_=P#uYssOK5p|jf3fSmKzBmD zqu6P4)E}8?rtSAS8wzkW;NI+y-*l7voacY*|7DXxRt8m7P@suDQU=8E zGFb$S6XS?e*|K%^U6mGX-)jyDszVsw7bnulWK2F9RG)YF-*7|h7e`mGn+13uhptfe z*SFXuFU6=tgE&_PW8d#IekBz~fsB0(5K{ayV;Gt>t&iqQ&m7zRf1tsD`(m6QzO?n@ z_;jQ?*c$AAiWBr9KIsR>i60M~`hA|yBs*Fo%j}1z)i`|M7iU&h#Z^^a7#}n2`?>1` z^}TOf01Yb*m{2JmvSC!SvGn7ITJ?3Fj#fS)K7s(Bq=$Z)^Y}g0Y~A{Oj~z9AZC%4GO1_M4jP(0F_5JV(sNDV~ zz2JZ_Sp6WXKWW?ad?UsmLmmE*SBT&UL9tOh*+J17i`#UGf$zek;Mn zGHxtt_IvmJe>wN{Tg$>7Eth*|;||y_&s-W0?up3fTM96Hi9m{{MS)~0qWF9d17vKJ zks1uKHENwc&tHLi7(;UIKp(T0?R}qprWo>U`DgS!ZMeo0 zA;PObc(eAzx@~X?a&qMZVt}H{O<NNTlVP)Zt>aaSFD{g(~i7+o^HO@;Oon>0=4%i)jJ_qY>#aG z%by%C>;nb{ZFvFL20@FcFm_L|A;^)7SilGz%i*0JCkBJ<>+I_(k3Xsq4o?|*eUn&u z-D-WoXZI?C4m^j^7%=q5_}=0oe0%wF{U7ooe>YygG60tV0${*?@F#zVhhg$z;os(r z=O{Y(D)+lWZr)iub+W3zlP`Rdj`&CA8wIki7b!>Yu*2_FJAFheU7r`<4|XdGNOA7M z`l2<5`MsZESF|$ve`oK!NcR-4mR}zGw%>j^^%zI!`;6nSVgD1Wawiv7BHvHG2oxk{ ze^Y+-4cp^WO}+iGCh5o7@p|j?5*|PYx5hr?l=Abtdx9TX+(_5m8Q0k#bgbsjScP8y z-O_bZ>MaUG>mWq2o9{D3-OIawKa<0gzkp-pD(t^yT1qb zeqs1uH}XG6_n*&y$?<)E*LuRQ(!~eheedhPr;p?Pf3F#TXJo%qSIZQHnUf<=)_t|_ z_3bN_OfJGADFXsXB?CF>T$wq$e=z1Ja|J=Fym9TON-LGfalTEML2abjIv{Sq(kFtD zm77J%6*Q3PZ!SfK$)^<}$X0hV7-$(kD3h8PLTH3C#X7Rk$MhF*9!xZOGEQz7dMR~4 z-qL3)BFTtUk#%l%cVX5FRTvu3(lNn0gaG};Y#R?5fQS%$0C+OFS50i(+QY^C@cBqAgI!zN^sNOC}>f;jIcGMh+ zDD;tFLUsk`d+Q~-#Yq(;9}8E{$Z zM3^YsqIHy0Je31MM6ghZe~eK8j&&|STQAQNB7Uo@vnc+I#sqP%h~=9cg6W=X23LxL zy@o^%y`%?IZYS+xJzpxVp?$7*f2~btkfr3E5abiIBj+LVT_;>GY0a3my9(yHuYOE2 zBphy<&q#M<{aw9>I|^Bbf&nYP4}!x4V3&ajPIkESN`i#aL``8-e~)8ehP!8ll@%|) zCiT@XdD-WbJ%?O6Spb3+O+rP0ps;iE82S3@d)z)BFMm@zq1>-pRZ_}CtCkok2O=%% z6A!9{`auy8ivb=m@UYi52dSQ(s*n(p2$Bl|Mr?a-y5bT910iB!!nH;E;2@7rEUvKE zG?&;Au0jZuvp=SCf39V|wtRg2FUso-FD4qZ+`(ZXX&QV^;^DZx`kfiIWqu za*%f~zPX=e5-f|*e<6SfAcBC3q&7)06oqpTssjS(wXm`aG#`xf->!b2MOIg#OJ0x* z3i3=w0y(N7OEvXV7~;NO-060vd0Zpo8n(yD!#-MhAhHFWlWpHPrq8nvC1vzs@`O!^ z5cpbjwVv}He{i#Ah)_io?>j^3;mp-TNQ?m@Xi0v7M;z@JP*^sKvdwVJ5qRHr*@4(>I9=>eZNYLP6=f7QXv1QjWf= z5?52h+CoV*A_N%;?dR?84?ZK%hIQH94}tl5K>303bkz>@0naEs3%3+WJx+D(aNKUC zD~y%J<=t0sQ!_Bsk-~+5_Hl(nQk4TlL<@Tz_(;b%pkA!>sD<)ygYWYR-T@+e>wkw` zn*3RYegPJpj1*UJvEP&kj4|1uJ}_x@hf}YeQKdH>fP>3 z-;VN@fsO~M`SgixTOycg3aW!0Tzp>~?Rz-4^m&Ag4ar9G=i*XblHJ?ni*Pi1dGN%* zf{5u|j#cYs9$FNNk7KQzs<(7aJ+%y3Q6}2ye~cX~IJt~Ntdb!Vi2;ECjCYEHoC2%@ zPHNp-chA-3^z0qbpHkP7o;VEw;hY#rR4({&>v-s~Gc)UYwm@(!Jo)P}jotUS(K>c*wa0+qF0))%Uxhl7t}LO?Q)b@X@j5?k6m|D%*L!tI ze>2)(eB6ASbDHDaK-2kaYdm`gn_Tu%{f-F+?1}f)d%NGuy18{(=y6hE;`Q&G6r6LK|XrdJkbY_ zsEV~93K8AUVaGNqV(O$GevAi|f8olx43$x!yXK?%<%0)^BS3Fogn?`j0r7D`wDWq%y$-|!dLRS@)7#<=j{*h*)KPn7 zlQ}`9cngL^L#!?ZhaHiSfA`A7a<0?pFm?NU|RDGZXOXE^vExeg^tGe{H1g0tUFWCqc@h{U&d9v8nODUvgZ2M1YOKRi;3XC%|q$MmJTvA zR4(2}i+eWEf(E`oe+rh)J-kO<(DJ#_R;U9&{jd)f8}+JMY>zjyrotV^dJ=+l^x=A&O;%6aome z@dZaE%q^8l5LoX%!4vMZ1#5*v8r;>4&`xuo7+p?BEP|jwe|Fb)ROGro=4)cStAU>R z2S}MYS7f4&7szi;zdjdEWEei*P8e684Nh3+4e@WMh-d;)CwP#mVyRvUVw*Uql#h5i z6s5HQyY*psA+4w*uDRcpf;m+-CxKy#h3hJWp*N^=ijc1*EX*hX;y8~aG7%JDq-3e>ef%G%z_IsxG*1lberDi&W28KNkcl0#vE=o3I$LK;E-_;e+_dh%Q`mf)4R^O$3+Fy=uaLH zMb3vTE^Od7y|a<3n9{}!wr{Boy@r^%O+C-JZ(}1}LxyIPV1BJc2?=ZUH;5Z%l&W{T?8Qc`q4sq0_^ckT1GzxSRQmUw`7~@Y~YSt#q`+Co&Go^&coPPrO9d$w!(sSe5u)){{K^!=Np2l**HH>dmEp2w{~X6pISXPhQdQ^<~R}|fJdSC<0Lh2s&YPjS4u1@he19}#`Qvg zf_ov?P%Z%N(J=Pv*f;FI5A@y8v%F5P&bZ>f=`-ci z*#Azq`-njHAef@w1)YZJ$lWG@QAdwr<+*Aolr+~`G~+-MeX(Q@r$VR1>`v7SxKvpO zK|(x4do>abb^SyJsH6%KA%B*mq(mcURF}KEA$+NCb60>K3?m$KNIVe;B?*8Ri${`B z2{qw42}y!P+_f6;+lAvT;{ma@Z1%#Q7!8C>K?0= zC|y^gtO~l`tjmoQFeT87HP>kIZ!gP?aS#m8DMu`$32WzY_HaHW7Jq(1`=wIk5b^Ok zGsDPwkx?VkemWDN<~~Ahi=oG4U%{jySsR}ov@v1)AkeZ4>PYD~1|Esg;}=4%&LiV0 zW0j5KvXGSS9yVRdp*ev)>b1TsgF8@&tfEKS>~Jsp0-CyTDYHc@1>zv$N0P(GE@HPCK=g)0vq7wh^inLpyovGpd|~ zoBX{U@2l;}>Z;`rU6{cc6ha6jJ$T4aOjP>2+eL79lb`d-0fiH%X4N@ z6tQ0aOREneO}Mt+6AZZLt7c{Ag;7_|blWDHfmIu8DVje&A{9A)L4ujHtKQ)kPlJ8C ztKgGI#+|l$WH|}a62x+2#`A0Nw&jvBiNq=oo?)g@=YPhu=_)iwdn#nDT3gE1qQUfa zyx%J-!JVGl2U(th$d_esFa-*Q2@6O`vWuXBB%a=Bcpfiq{$U8VMYNiDOLC-g)O$+1 z)i|!MutjspscL=~b1ZN|^Et}Eko_Im%OeM56R36_%gm}GaXpJQ^U`>+DD8_F^zE1> zhRGx>gp)2iC4XxQK_piX6trNnNUsJW;cUy}Cddeh9cwJbkBg|5WL4G+g^@8q;{^~y zWE^B+6%!;z6KQcoYGE8)MI^-~gJo1xVGAV0#mrSuTq13jOoBCq7=WNyN6n?exJM!i zxTIlPqi6~WERLHcyskq?Rzm*=YKPZrzr}WnQ<0DaDlKkOJuVb z2*s3ZWR*cx7^u?G2-h4uejIU)o-7{AW{i`WZ*^h?zJw} zM$Ch-R1CEhWz;DkaQ1lkH13>^3RH;Hzs8Ca5H0`Y~zHu*D>>^_R>wajirm15D`W3bX`f0F`qT*z4OnqA ziGPO#z^9cEp+qB7RWb|_0~~BQLdeBY6DVHWxt#Avqkq z*p!-eJL|6+UY*Z4UN2b;`s6~aY6BF00{WhDl={#XMbBT9g+m{@vHh><`hUpB$9Zf0H5(kA0 zWP(MB81Jh#hM>}SH)^eN2qpttAlM!}_RPTWGi=U2JUZ#HDpbQ5VFHjU5EliCA|l0N!_e>f8%aDy zRSBsChE`pS$nTNbc7>GOO2xR|2!B)6Ez{T82v>4eDSfU2=;JAN(~n^5YUhwtBo2Cq zsBD(Hi!c)7-tXbUps?V_odnSUp(hV<{?T$6VY>)>Pyu8S1qmTwlf|ENu~XU2()DCw zFMC1(At7*v7xv=X*ek3D-u2mB$ECaWLcyjZfw~i6e&=sJS5{eL^J+#_*?%~Z6#78?2fiFgTQg*Y%lt`#R)nkUqhoF}llAHHYY|E+JHvVI z`ea9{dUaC9M=w0^ov;Yn_bv%y2`4B*UZoOSlSnKScf=UkXev4TW{C!kD>V%b}I`pm+R zA}oW^rFz0}#o%{LVShSMLbj}w6IHH=^q75o!-zrS*U0JT>R(A7Q|SOPK+eCC$bwH= zzZZ+d5@5?&atye$9;X}rV2xC-R8zwbZ{h`HL1J%!n6-%xC7^{e%8+x_u)7)S-StCL z)OVb55q(|yxyLxiP?BL)6Uh$L>f~Isr3bViy^SW@OO`ewc?X_V=G1?aYgm}@D55gSm5$cTq=!_rHe^yZmeFbJ7fy4P(1nqxj%$#xHzWlX$Rb?$Zo8s4 zW*e-?yRnD^OCQ zZcG%^)+N{lc9IE^&0~LL)FX!NVTV#{De17r6Ow7ibeWb(PAd|pHcaKBc`(Z`$uN|o zEiEYoMeRij3zan#mdQr5GqfRI=~d1mwn|7Ri=5e$Hf1au0*V)H6Qqu_&TY+1iI7bY ziI71^%w&Q*bs(HlaE8wDg;r4tD8xu_OTo@|+Lg@d&XTbXbaH>1^dTk_q^yhu=OEDu7zn1NeTmd$fVLjnb(?E3%TN6_&TtH@lt&+zR5K2n<3+= zji6|7!JtSm*O-51X{2&hyu_6AU}49_N9MHCK*0Pi`gEv|j;@qtlHP|y#=ViJv=g`H zU=$nkqzO66ZlOlmk5?lAbfi;$bc`fzcxG*OERcHHbTa_x>SSF;6WJce(MwS2B_3I|$2D26vhs^+dOV-hO&H6WcPZ z5I`gpdg$TYNQ9B?GU%xG3kje!@WIA@#TX1Un8bPyGg5a;aDN0;miy!2zn}yl$Z3xH z*S}Uo2q5gL6TE^zQkcR`z8%9ccwMX2I|l`wV30`_o@4`4VBjzetu@!Gy~k`Ih%NJi zlpzPlw{SZZHZVpE0>MJMb^PWG#z>;#iM^Tf#<+$OcMKl`B_3^RFswTp=S!?-op#$W zKBfeWBm_1pP=6!}DGj`9t0$7UkV+F6i1fTip+siOnuug4yIgfWUF8ajs^F#Yk}_He z07QVq6;de;e22mrs01d!ruFkG1)G9J{&Tk$i~v5mX(huU~M zae9EvK5vd=3vkwx0lF^1m#qDg(aMmH{!aKaW?+yx<9~;Ia4=~}+uOpfKp<&!LBA^< zTGUn+ss$=nxT%QYUAA~~(%GOyDT%=Y9F+odw^*a*B(OIdyyG#66;73JYU&T3`l9Kw zwG1{&%0j?BWe6$PL+u^CsFF#Tv24fJ?^mkeBFvkYAX>gFnb}> z;O!lZYk&B@FG~sRje|zg@JIyhV!?%}O4TacR*3k#?ezHck9Cmc$XM=C5rYL<*sfBF zipD4^oER>T$JjXI&6E|yMNvf*R8fjsRRu&8VuA`Q6-iQzqPEeZHI1^Z5Ry~^W(^w2 zhhYN8g`|27p&){J3B~Nep|6T8T%kH(XSK z6%InHvlKG62u~m&ix?0tdcP^7-$ioPjvH5PazWd1g$fJ22(ZWOcd83*ngm`%3djr~ zEF9Ph^HJDPVe9eW>2V2pL>ZKs99dKo-o3TYs=C<3WI|&nw&KYlHuKpJh=I?p^J=Qc z)PK)h&vtuBIUnIw+LZ}ib+TsRz2r@@!EK`1v)%(rRDHE_UZ}s zcRmAkB^e^YVuwoly6u(%!1~z+1Q|Icq)Q zQwf|IDodBc%s~VbBnb*V@eIS}GktoUJlH~)AH~i48NoTLFG^eKR=~C>^5w?gqw64N zoXOiyl_s1y_r#Yw`NPZrzYO2I-y)#}$!3)PT~tZ*vW5!~C7!2*}Z>hWowQ zD7Wdm0@wxWh=MSV;KDM7f*RniwoElk4X;KMEl{TUq5)(^y4Z>01W+P~nSTlB7aw{M zE<|H*;4F7;sAjYu9`&tq*4p3%E>o*Z$v8YqGxET=A(NJ4P$ zDFO+Zac7^uH=kX%uY1*d_KZ5wPPdN*D_WXtQZZ@6A>Rh=jexb__o3`#CY zu6k&x6j*8!hUPfJU8tfZBY>tD8-rhC+uF&}AO%Apybu5b2H>Dx8G~71701J#_y?!~ z!#29>6HT`9?&spxCE`>|?%#8S8RVe`ggh}|0RW15`*G&sWIb%A0!5KQKLg6mMt3_0 zo%A~@A9EqFZwfXIK;$j3Uy5#}&Sf*rkamr+M%n=@P(B{Z_TruqAhHKkfozO#+3)Ai z!w)U^c;|SN2}?46Q0|wOZ`zMX|$L3p!fRc<_MfM*!PfX+ZnI&elK+Ej`lS;V3d zaV}ScZORwNL&q{SL|K5SRK2ZZfmw zv}@O&YvVnLtg8*ihGrXT5E0hkh|myb7^-hkuouBcj0S=Rxu$2qY#bRWZ?N&!7%*>+ z{h()C1Rd~ydE2HhiSj<_0t^yiH-gNBOUrb%0UTt{!NJRki0XjxbygOf03Jifx;&q ztb_FnFF*zWfH{m5CFqlUHgA4SYNj_@g*Yp zp3bd4ipg%p8*Gy+@utD zlP(Cku{I1=(3DLSjg1lBYZ<7|ZOPcdM7Cd*n6mI)Ce-MQ4m~W$>p%!2)ITfW>uzwNPtgoU3uu}alLG$G?hhvwD_iY0ot9n zdt1*PH@NX$!l?t0xaKcBZN#&kX?m9AL36SdR{Vv6DN=UyrewYKp&`SQ44KM#-k60v zG_9%8p;)u!tuj3_Or^Ij3wlEf&gch8)9M3}q7Z0a&@Vi?C7tgCkd@=XJfPl066@!wej_5INjfHX&T+v_cE+OS zxbi$LojRN2<9N(!FHZze|@4c+tWh-W=> z45Y#y)V4ZQ4?CiN9xUL%-7v|7n>sRK2^I=MtAk=}*?X*;ZDHQ$!)kpkzNb1#@wL^U z=DAIWNk=y~3^{EjC5kGsRzjK9$}uk!J3d!8c49{A?aR ztnzL1y7xpx`VQ9&NV7&km+Bdtk{B?t5?$Tg!b#&iOi~Vg3=k~tS-~bSgOg64^-&GU zs?U0slANGRIb1Ftrq>+Bzu>dZw%A7WYK7=iWbAU}OQ3+x{`oFo7?HtMqJ&b#z^Q{Fm4X**Ee*I98rRo3O{<9;U6YsEOF4~zu>%Ih%Yr6Y?D z2=VC<#u)-_aOAMWFA1yC6B>Xy!~*d1vKKQjLy+z@DWfS;O^x2}48Z(6!_1U|Ag92G zFoFjZA8hX926}U_hzDXeFaZOl0Wu7UBP!l^gmwsj5gQq3FEVgsI0yo6)=A&8(10_)W{Mc#ojnv#AUII`sd&^taRk2W8K)D3G7(IOQ4h8T z&e|+SP^>slWC$lnPHpp*FQ?MWZ45f)Z>J8-Ocn{Sn*fshAd5!!qjYu=i)ta=Gm~kC z`}j_OrpA-8IpI7Vi(7J$XErFNphV(c)jJ|j1w}Vg0!pN(m&TFF!`oOXhe<)mBw(_% z5MoZ!@dF_%dez?}LYWBG=EbfqJAy+&p++k(Vg#R{>VZo@bUj3F(}Bxz0d;nBv6hO=IXnZ1z06UNXy9%H(s2Sdih^FQ*IFyFCyJ)3O+;4ahU;+)F z4+R2?YnR1M0$7uTnI@f>Q_U-vd`|n5oTip5eJ!|;u`(~F5hfiL$|eU4EsqrC4e)Y* z#=_hYG)agQc;bgmUE!T)2MM$kHoUOlOn6GxH;6b0aZqgt1UN~{;rE7;!DZQ~u>=HS zBwd+PW1}Wu^BPP*>}iDyYarZN!Ej<-@d^+*mw3y(NSsOr1E68XvAt1{Y+4Xg-e6X> zPzu4Aq|WnV0B}>gf*xup$Q^GlElPtnpmOjdp$^)r#7I!!yrC3aRI7DDtfpNZZldMN zYU$HX?-b`qc1k`Ay|)O4`e6lLnYq?5q3e@fRT(tVU9rP(@1Zu`oOY^Vei*kDENZ^P zpnJE4@qsF8chkOyj|1ij`C0;y767CRSUZe4d;blSs#Q$^)sy&DUw=r4IP<(U1;X&o z`gv^U9O`;$!;wg6`9_LT<}asvg}CcdRBW0YjjYB@zL!ossM_jA49Szyoytuz4;3vv z?O9j^ON0?sfSUWMl7OS1bu9@8IT*o`+w=#XC&xmgJg)@7!3%SM}PB?rjZZ@Dc2pGBZ)nI{AsYKQApSnAP`h3<|rY(M1<$ZeYB3; z{yZrC>If2G z1tm5p+M=Q{K=E&NsdV|%6@%z(T;W<;XD&b^#~$c`(Lgp}5s!_-wD(SQknbo93HBMD zwU+tTm(j;8mJ2zjP4Q^9Z+0UTkSOJ-??-9jyLDAea5Y<7rN1=qBmz!73|$g%2>gUb z$1XjNzW0J+TkYc=25_;uKz!5eiyNWLhj-2dK7ZhqU16~3GA;5D+%ats*p-LQ z3rMLT?4WHE_xSrg2ZPoKiL*0A11u}bKy#mdr1hcKVDm%M=c;DHPF~(AS;iD8yn^%M z=n@15il88Y>H!WllueY`+mP98vnV}9$^e_xnt-U@#4X_VYwY8cI*L{gA`nZ?JV%l4 z!sd|Z*ng1V#X#Z}MmZSlVM}>g<&?t0`{#HPvFCem4Sx*y>85_s%?Ti|yrVHPu^c@Z zVP<}xvH?iTQK**Y9zQEh;ZrCfW#44H@mcLv+f;!W0kmuiMAR@M1BKNcSvfCnC*ckP zm&21Fp-9OD1h~p(iSu?QwYhLs7uyy*d0aIdx__>^CYa?@*86nCJTljl{&bQVGpgx52C>586 za?8dTCl&z(6`x3hVrYjjNoR2oDR1D!Tz_;}79>qlk#_azQ|pQD?iy8!{gXkCKWLxb z{Qo&_{=ZLGLFZMzD+fL7V^%io&3;H$jAQs$oBAJmVy_?aQT2HIyu(k0RSI$BmWYTT zgb+yt5Z%k>?r<`?m(qk)Qi1YUvkkvvA+<-h7jwU_2Ym@leH!`5zXs9bAUPzoWPf{E ze0DQ{deT2t-_GG)+woimuL;9J9I*=^dyWhe0_8Yi?#3e7<2xMYqLFI6@RoT2vdC72 z$T7?|^ng^6h)^*Eg&>6`w5e#nPR`FyF}Km>s5d)rln{}4d>N7e<=CQu4l(|M6+H59m<+X$ftZrpUnY-JD-W^(9 zCB095yt?#0>kn>9O$1Q+lQhI)4xWuZvjJN4`1>Ej)I{tnOQo`T86_pwFjGIByP`a*1Hpv6 zKV4U2Q@`S4IP1_Q7L*8@m1$9jx!(6XF++YWVQv{i#$n4_TMEyxCV#kv7-Hm2SzvvJ z9TL?tkOd@)5D91@KH#9HMRVMCwiO!cop>ZSR~##V-xiSv0lO2BUsAZxVql>vkz6hs zaQ)xEn*nD8_DSf3q<>s6SV2M}NT4D~77_|9P(*;C0boT40x|_;Db+k2&TM#UaY-ai+ZiHoqB+l-r{9{b z!<6Bm=_j(&XkZF35+IRts2D1y%%J&9JU-Y$!C*^lKoSVD9)B-THDOGI1u@Lg);&7c zGWub`*E6z5DhCs!uB2Yj_AeTEbV{hE2;jNBpjS3P>9va{lR{38Z)7VWvJp&iB<3qiD9XmZnb(kQG+B*`lga~V-ZQLSwl^ekH z+#~@vvQ-!&sn>X7%oZTDT+O}ul7DFf=s~7+_VM>+NbNwfni@$s z&2N9h4KC9)nKpogV|19a?v6_(5J#_M$cJy${yp_|$@cnv1L%r7l;Yfl&LBnk_T}Xx z#(0U$7ObFm6jIDMXR>#~E<%I=CvoM=aN~tl)D|Xh0Kkwh1eLi!Qa4?1KAat?B;2Y& zLV}8`f`6^AYizPCLCloQpk^jTs`z6UI5`q!g)^UfTQy2z_@PWtXD)sPlh@1CE$K&` zAXYR;Nit{gKO$@8pJCH!!6YmpVlz2k!GvMhJwFGhr>X8wMir71bvK6+TBo3OD;o^KY)C~#iNg<%x5PxZycd&sq7%2#_0x2M{AY{Q=#ne=r zV9Fr$-!pNr(m`E=$o(;%b_)+bJ0e?2xq zR(}cjURqfcoDxmYrYROuQ4B%_(LjIp-w#&rdM3VgS8T6p!_n}%1OzcFG9tRjW3x6` z<@kBNN_kmT6hzyKPFvZtJ<|%Ky|t|7;!GHD%7SH5ZXCG;f2VwUarm9^_`T0h+<%CzOp!kD|fV^AqEPrc& ziVJPQ5$}aTkP^Vrr6@-JabIe9%%}lsrt2Ucx%r2h?IUsauDG-c*_nlI{o$^&9#|FC zbt1v{riot{e+$8=@=ImDUzwpE&JtTj$YS{1NKU!1GKBg(3)g!HQHk@-ErK)C-r-GP z%sqzkecxZT7ZO#S1wknRy7+g3mOL@NTiIUGe_-sm zS}(W_z!7jGQErwvw#t}P1_eVsxch6rEeqpXZ$#e-jN>r!X@LPC!AJtY{C`7ofLo3S z;UVHI#;rHpEf`~6l~&enTxu04USM}&X`8o+aO}i+ro*xWuZo51Pr4iEg3$@aUU7}* zU6QK0?ziD!*<)oNkr4tUC?paSDzY0k=a##keYnXN=LK@P#bl@lEc%|fhnCfWtNAFm z%$zFrmDx2Xnq0Z+(EIl@e&w%yJ>%QH%ZqIk2beVG`#FC`@92=A>1rtdp2@Ay*mckz73Db{$za}fg zNeE6m@v2NTHSykgk;x!~h>Rf?3{}UEmXq7VN@@~`nznt0Ebe)oOMl|ShH_^f&whp4 zaI&IiVD!~;j6}2x5dl#IV#(y=tE+|f#-6n15s?TYLDe@vxX&hGJH(768qXU_Jx`GY zk}UL(a=no4Y^aEKYx7d_=`!md1BjCe5D&qxFHXTX*(}|@EHioz(`BLDpkNDFQEllR zaJC`nW(tM@wN(sB1%Er_@32>6Wmkv7#}mF{@#~@ITJlkmCiBzUS;KNw`@RDsQJI?8 zY`XC3hU7ze3RGEXH4*RKc2x8U2jr-B!C!NsOJnJGh!W)DA#KBC%YMkserIf9RLU!g$^kSBh}fkblZiK&DdMCb5))^WjaP zO1-T)zV>mpR&?jx!b1w|=#*H*iQ-{IPTum&j5lRPS>?Io?abUe%s8p;tPPJZ$!^q9 zUhs{WN4i4H1qdM|jGgTSVep}IW<^CGiOF>!&6!(}A_ymkcy+w7%i%T6Vk5Ix5^T&7 zK@?+xUTI>Y!GGPN42XcJBc@Q*q`}?CDPjn!+EIeVV#uJ%wyPCTX=tMk#;Xw+%(Af& ziYmn@Acud4)9FE(yu{-X@>g+)3>a$#v5m>Os-M1}8!%W(t1x>81R!4Cdp=lI-bb&< zshFupyg+796r_rJ$ZMLm5o{_%5sJn+l>u`jgu+$PhJP4EFYBt~ub z18E4AQlS$n5<^^Okz^K0qy=q&TdXFN8igxnnSWRYINM7dFrq_Rpt2JfD6n#dB4t@H zVO1*#u$aY?+Xa$g5L_zBlGv3+0_6h zK%lbqX7FYNhVfwrS4$+mOY6?%9xIEY;D5~wZZ?X@1QJLf*0%)qd=g?K1xnOc#b~|?ZscLDSrX7N78r^O0?cD1a1kd`qB@XSA_Wp6iabiNSfI$Bc9ZaDZhsSM zHW|$ZLcH4kJWR8tc1{++TWzzFz(@#~6aWb_fDu}{SIC_YC)0-$9_uW!j%J6{KJ#HT z3p4B~D5N#>=n@_I*IJee2rC9D6+~2uj6@MpMFC)-s-l9TELXjxz;#Ks{WzX|x$1GQ zp4{)5(L{$jp-%0OF1nuE5W<*yTYrEN#mvp<+ouR&NgVu?V^p9MEQN8`-L^DAL=#Gm zoDQ9_wRPi;3=rbU0vUK?jb{P!piNj!DC`SktSc{^u%ZPI9~ihoDqWq@PT-JTJt<5P z;T>=4xi;w6Dt=G9SKRKt`{C&GE$ZDptaHhpssJQ`(;dO}_|46d0|62$On-{C@IIFV zP~vSFu%#3#rg}_wIEFaX%Ex)h?w1&~SHoRuHS8XU4yg5YVJbsn)Ei5Mqb3WObAxPE z4WX>ucG#jlo@_LpMCFYx_61?fRzuZl`8#R5qKU&QP0YIKwKd?{nq@rZ%?M8(wUcb3 zhT~YT7Z^Z`4TM%|$0bJSQGa7qCG6J8o(_f6N4ln);m^B|kBR57q2m=;6ogoO?7@K@ z5(#h0+-E}o@guL#Lymn*E|J=_zfQjXykTnoyHp~pzs_G#CKWXAeavjk;DnASg`ohH z1Z0JgTcMVaXuBVDf$x?;n1Tu}Sp-Q@;@O3i-8Jv!hC0b}zMB|ZHh%~Jda*!EDOHe( z5=h8Iixe8iizvZXwjv`0+KsFw9jRSQty4tGi3KWBYscpAz8%gWp#>naZh-M&DghP{ zSSYbbMFoPAEkHM_oJx`~BcBQRZWc9EnXEf15S* zh%V{Jub;)QyV^b5?|)WWFSYG2*s9I0|9!`J3-xEXx6`ks2r{Bn1sHdYv(3X(MU$Hb z$gj+&nvvOr_N*u(y-b)YoGc-vAdX8ZTeyw?F{6n*RQG6rSUU}fpzW`?2JFt@q=a!0 zalUhJ1!y#zW@cFqKneo$t!`fRv&t%r%uX)bd2uue>G`?^4}SsMzLJH#q(HSrLS9BC z64~$}CB5ZEr3_w>eD|siE0~lMka9A4vEw`gU3_-f-38Gy^j$cD;NP(G6DXsOunYwT zR$Oh?rIy2<+r(E~4u*1ZyXawThN4}=t+Sk^84l_8y;<$%tEW5aE}7pi(DbAx*J;SE zW|O~j8<388PJco{I_fW!Iez0xnxKF|U`XLTo&FpF-^by`ax(n$FU0O|q^ZM~o}1Oh z&kx-9^6oc=8ZhfH2~Q9l=X1#ED{-JgXJNWOd7T-9f&hMb1CF~A&RYh!&LBAEZeG~8 zk2F94oyJh5Y7!5bt{EQ}@Y>`J$}lj&NmQ$F)Bq^4VX16S*YymyeS>$dGJl z#Xxb5NPonqRM!n@KprV%Dp+wz!E{8N5f3262+;hux}=IYxcbnh57yL3ncD-JWeC#a z*yC{do~u#YsexFrBfWUo$jnnlzs?&Bu*Ux(P@vZ0|(;lphRy ziS|>jhc|)RO@svXS$&5Mvoo$OG@ZFj10mN_hgmnvt@J6fb~xh$gs$qv1AflAEQK@( zN`Dmmz$gj_Tgq6x-awOC-X_9Titlt4SC|1hq#+|iGiYwFw}>0Nah$kBg214~ zTq@bd(Uf`{=wH+nLI~g>^o{#`Y{-MfrgUX)@Clhxn5+V{4-UfU5L?j%32+Sb;9Nxt z0y-TBvNsX)H-CC|92#bzgW&-kS-#ri(tmf3EkohOs1HhURiM&{-2u6-Ig-F)5k)nuHh{+LeGVq0sPAq1dTjOI0^?%-9 z8>(4%tIwRFYs_a`)(0AWqW3iW?NAo`)$XrQ_HmFy!N60#D*_J%ur5hS^>KN|>Gj60 zXKjI6*xb#H>7BV)2aGY#nNk}WNU>M9UjMK$2?IkF@qNsukL zDTx&!A{oZP()V@Wf@_#h1PRDV4u6lodW;q4u0{zwo~Lp;5+>bl_G2dmCmGBV_!y|T zM-nn&gWhX1$wHBYCQu&ALP%AlpAekO&Z2ggld}NNW$8L(3xU0i^Z92PU>F1I&X_$Q zFwZfB)J`R(c_Dh9ObfcMuZ2)8cseDrivvz6IIu3d^g^xa0O85yFA{;9933A>8OA5G34lPX#M?no$!&;oGZGMG-ZRQ_!pwyhvbEY2mSBfe zA{DbX{YD69Zf7&l@x-Y4{%?qDOf7*dIPgvHEi$>I)JOwvYz&UTfW0p`ne1>(?B(i$ zxbsG(f-JxYCSqnG-a|7)Jby(TZ=55+5J|4l?D)7RM_n_yg1|SNjrcC&eSIeeYVw_l z-9-|OY?FXilHlrq#Q*>(97x}pz*UWN7tZ$2b~tBN+bReI38Ih}RwDQ|%L2neMeAp% zPosycXD(F=_2i|OwhRwTKPjG`o`$>TvH5yYb1e2GE#-=5YNbwPD1TQo<8J-gvJyw~ z`W|nEeOq_!N0#@4qzsf&(XYSRraOj|8mFx%E2(LOhaTla1P6ZHY@Yr2I~bnsvT-lC zXcipL5FY3OVi4HS#Y6;UxY?8^C}HREQHY!nBqR_7=lCp&2XVPxz;t{E9Q=heIKV5+ zk9Rk%Bt-I=YtQnK1b?vFfMD5S^r6r;avnZ-+7zVp?gB=Wx*}cOFkm+uYy|4$-IPAb zY8;PK;D#dKpjD>cnotN45bsf5-4=v=zB?Y#y#-@swDPdN?Y2k>A8q+Bj!^f6yh&TXIZD61&kdOl6ktb;(z*ir$Y*zHBnhgRN1XxMxJds$ytRGA1UhidVHIn=V^j9K1H8P51}E+ zlSkEDuAZE^Hd`E=8xo2JR z?BlhwMq>7ED~h3$tRC*p5^_-}CLlU@3G-Zx4P24mtp}(rm@_f0)yQ@Mj70$v`8-b_ zEQP3+NX$ETS{yV-c#;i~L9e&gjS38zC`m-rfTVUuM25?pG(_Av9-;;)=tetH=}Fr4 z2N)>ont#%&$e(N%tEe6g!|Wr+MI46$0b#^*?DTDnf}FP00Jx+C2by9+Zels8FRQy2 zaX9_#pLN_>yJufrSAU%!x zyxd8%<%*(|L8(BQlt3aZ%uCqW>>19Tco6MMd_!%u=VMk|p+{P<`f^jB4Qt<=mX101 z#ed?Wb3D&py8XYo=i|6==g#a}ZMMZks#IbtWCqKvj}Lc;g7vwSFKgxQHP29!=%N%L z0tz4?q9PCiHX3V)^zO>x=$|KkmFb3cYJs#Ho;C`Fa#Td)7vew}G!uC!LJ@2)T_0-T zgN|N*B!L-+Ijy(3;3_)_hQS@#h%Cd!KYv6RFc>6Qj4h!ri{Hn5z|-O=sod>dceUEH z5`njEU7MvUvBI59(M3R!Rm%ZTsBNn|_~NLf46J@#gP}2@g2737DA07z9!1y)vt77U zvc`>scyzv3V_w>jQqI{k7a=FbLpq>RfdZ8w6>3bdF4Du((>It^GQ76d-V@YTsed(V zv?~1znIh3smfoRovu`a@y~BS9M|SOrW*9lOv_X1~vPx`?SB!OfpK2|YvK`v`SD8h$^OD-ib$Z-^k42WB|;i;-3^4Mf3;0jGZD1TYPiC4tK z35OW8STgs{Ol1*~6UEwr&2oh7s`G#;z$R7YkdYe!9v!NIJ%0Sa-GRlekC7#kMNiY} zO^}gGssT`tr4W=v54%i4QFFa^Rcc1*MiSiaB6iUB4KT=##^^0H93=h*lpqd-5DEfGOn|;y zZKPI}U0i=P-lV~I=U1cQt$bamjD8Hu=eQywt^sF#zDR;7AdII|5P?qa=UeeMoM8w< zVUDKmj&ij~C$y80nSLX@)~&@~mGfC4hy;gmY3vCfkY*7O5&$P!>wolLJa^6Y=6K^I ztZ9k9wi#~)9`B#hl0F%*28ziU3H;Lm5Ocggy$^mN`YC{cBu7m2IppNcwV(jm_v~Uz zgU0JmzQuB43^T@Cf+OXukoo|etjFZ^0Cj<(w?OhbZv2)& zu}BTe$W`7Pm)=9t`&Krqa!@Q3GKW;OCA;Et)Q2 zu#mni51Wt;qzW9iEM3>0uz*S+xFBReg2FI~8b^HA#2M9w%(9GgGT2lSXXw4meE=lZ5MT*ERE!s;ymlSEqI5R zeh+9kr+OFYE^d_)DO`jh_2#`{?eNXeabTCksghV~nXG6CODXMcZw`*p0? z;*3;4fqxKJxW0&tD4{P z5czYR#gc+aB(sL=`I_2+AlY={w~)-(5-_$r@qe0*jy&?haZMf52Q9>gq6-5B5tk0v zPXy%%i-@j6i7q^nn~=-u(q)m6gA#koOt93s$q>`t&fDLfzd61U4oOuQz*y;gQYl{m z)Wlg-gGO%pD6yZPRJc;A?5yq6mxv)2;BYYz5?&WXprEWKtMAappRI}C4zG?DIx)o7%!864u=7@^=R-trM*L86XtX-rCfKmi0Fmk; z9TsFj!|el&Q_tJzv7K!LbrLnn_DglvwSPC37nDb;)J4kRi(pZ8BVFZyBqGazCuMSC2NvZRRp?^23 z^E|P@oi?l9{?FrML^+BHA_Ej0={f|az`=A$Q|?g%CWT=Uu%hqnU2E&}@;G19>pqXk zf#j+vsH-GrugBsy!b874mIry7G4zgax$&Pr9N`e~DuB^G14vyQY_zSqdyH!QwL z?~}HEqxl>28nSsH`u%Uj`a}vGNFv5p*sha|1u1VH0{iA`sg6z!%#5AaUJavfdrPM2 zl!&Mxf(mzVNY55 zj3|f(5O5e6KrWc)i$eH+%EJ&yNTz)D!BX3NyZ55;%J^4Mh^8ur-{iU)6|2c#iNF)QMtz9u5XcluwPwbnoN0Rx@z|eT6v1CQEX&B)usrmEqr|Y_*Vg2DB0R-@#HM@73KzVzAGKPA2i@sBROjrXh`kp!G zm0PLHLbeD@SX5Co>w_n4@tQsxo7uROB$7%?_r0mc{)6&w6jM=evJAlZZ2)Xsh6M!NGt{nUv%cz$_~}k^ z5Nl*5zRb`)#{h%TCSOO?oDQ@@bl^^90Et7uV0@x~aS#q76gor~!-Kz43Wrxsn=I}< z@T<*uoSzQPud7^RXV2<=&_O{hLIA8hcI+fDk3}1sL%d%c^io!#PYU=nkr|hLG`R^U zY@d$K{Kwkr&!0PYWoEUyEuk$aO9$U!hx8#c@q~3B0S%q1jeZ9C@j9!qm&4ibKu^Cv z8Wh5R2J}3{4N%+_^!)eoT5;-oJ*`CQ?RC!WqT-@e*=c91z4k~L(-6kFJ=rlk>txj_ zlA{MpTa8g=mic4D+2(kditZdwE5g*uQae|&{IT*xM*#qURgL>*Pdc_Aug>K$PXL5<3S9%VAglzKb7VyMZwmWLoIVi;=>I18Te- z1B!rFo*f z>9$~Z{M`I0RcUeaydC(sy4%#?NW+H>H%Bp1KnAw?d+_6+mnVd4qy0b2^Lg=HYdW|5 z$F~=+hy-bCN;dh{4pYC6v4jZ`S0#*!BPb0z@JU0qG7F z@c>eTAQgv5Q)#Ijl;O}PT3BOD-$p=Ye{4*mGE0LjZQi!Yd-G!1eBE`4@f^_ANG!FAMSzZ{+Og~G%@0s$oALR?;QpjJWjh!Ziv zD~z}-V}#iV;=5o1;f2^+BzvI?e<0+|+J!7u;%F$$CZr+pYNS;06P%ES1-zxi&-5{48fy1&~QM8vsEa(A%?Qe*{HD0flQdg+ex{ zY3vn>!z?9-mFqp+IU=VvQ1gU__Np;Tff#V3#*17FZ9$xb=bDDbdN8)E_RmUENHW4T zQy9wizBLGW+WU~8q)-JWoV~d6#}VAEAz9Pp+t;;7L!2^{#LTdsq31rU6MpQ*(|ZPv z*605YCD{I@fXl6R^Z+m#8+R4I*d6YOc2gNE^!%;cSpN&?Rb1G)7S+Lmsw%s zn*fg4O_C#h#OV;-DFQN?q!~#FwTcXkfVXUM)t3<)s|tWje}tGM^5hhEUAGAExyPtU zqJR{qu!w)bEa8{|!+a74lESip_$dc$NWRAxyG&432ux6O>t+lq)4@s-BgzJ!8JQvX z5kM4*2%-}n-(#mfmB#C#Mc2Bmqo{}ior)-V3nvRkF@u!9D8Xh!QRgE8n<*n$?afA&+S)v8fwY9@NmhZ+mybC(;B^7d5 z&N=A*eJpYS&Z9%5nx=7tI3oZKTKn_m*7g`0Q6WL|`9EgN8v_*8D7x+N&97}V>cC@S zbf~PT40q{fHpEy`NQOz4QbYjXAu09HcR21S&?#=_e_$yAPOBLNDhteAb{cgG_Mku` z8i?RnD<}-I$8Ff%b8nwI;lK<9`*f?8U{b+xsDQ4qa&E}WHY}4IC0#749p5(opOODR z*gAB!(f{x9*XtnI3NOH^e3}Y|dIlexNg?rOr7+O<2d7AFe-3hy_LVR<>q&ojyL@E{ z0ViWLXvh zfS@b|6e1xa$rKhyumzGug2+Kg0+I|QWFdrpf7ao^*AzvkA=HSBJxR4f2Zor0fwPo8 z%5CZPPj@x@{(7GuXhM!eJI@AkeL_>`bSY}Lt%kbc@0{S7=8!mrFpZKmG1Yj z%yiO#!fx9PFj9QiFHby|rP+=2z6{?uu)R>OyC9De3LuW0opeq|Qsz8?-;nbsf^?m6 zf0z8ah!?1RWJo7wN!*R&^6B@&}yT#YO>)Lr)>K?O=8K^!?>3n7;) zFhy96de1ZI`MG-fs}AkEwGAoM+tPHsy(d(J<~3i>4mQMqfj0r?mfk(3Kbr=*oIxc5 z4$Fq(eF|s9^oMC1?E2lmK80u+`#H`Ve^923kol4t`{y${OOazK3iB-&*y+&UwcCQekB}+8vxzigH;XSpE?}ednjMn?P;K5G%f8~M(Zih!A6@mj$+D6nmcLIkThl8=EItAUg0p@p{ zjfAk4W@CxwCCST=LC()jh{~0#c&ppy{PyfGKZ((Ev+!$w9xNR~2*rua+2gw4f!@Zn zn_>YVNmQ7bnyt#xK4Qh?bKh`h8AL#82gotDc<;757ItSp$gRq$P|ieIe>9&}b^BjE z$mDVkZS^~GNwj%b7`Z3g(8^bT zR(+b*v4V>yG!Hfy5LO7pSA|H{Qo`9smzN_LLb!TuAZ42C-y15zP1&NSib8Q`>;506 z`#kt~Wu&X&lJa1$e_??z-k+bpKXrEZ(d3*HJJbg15E`y2@VocmftCO%2{7!CfGh|o z0I-mjgo)3LG)W*B1fQ=mqygCcLiKJ)p$Ni5M_uqR`83$qwPN8YUj@B&%QL|{s}1{1czUTyv-e;Z`4ITv;XxO5NdHoRxZe z(Z_+;U8mVBe-1i8IcDJaPC7gt%!QJmam6T`1@^uq#zC~(H0NOy#~;Lx};lhQV66= zBL#r$)d6>A%wvNqRffISvye3W6e&9F;XMZGmMx{Xf2zwTJJ-ghJF=?{(vQ7p#wJ=7 zR7u+4im^o$f^YBKCUWJFFQx0@G=iMjL^owDqQ#giAx#VfWVQvNtKns2K@%=}pI_ql z%-!68b<;8B--jTamSiT-U^{uCK8Q?+(S{vJ+boFQq_A10rz8wWV<0Tql2HW%++!Ct zE{jNIe?*HSfFcNx6vYW3xB?|?v1-)9A%dA)&qRxu3I$1>PIrN>U9y}?*EbJCZfuxI zBN+IhP)84IVEGUZ(}g#kPrH*B_o|?=hQ0kki981>GgNN%=g7tmGFsJDP%bJyE8br} z;_>>wkBZY;RhHEhB!jD?MB9*rq(eRIhG)yMf6da`i-fY+xl*QKQ#(nEA~ROT>n1Qn zhvY3&1{H)^F{*;7qTsdEs~^H#jxE_o6cj=e0=b1tBADV1S@QN9qzWamb0P&*aYZUb zRI@9TMG7=PT9u0evWXE;F#@$|`1`d)RM&)wm98_hM3_w{aijz?#dw3<#IUs$c`eVj+OGpx$#Z@mXKxa~e2u49R0 z)oA{Xr%{K$_g9#DT%L}9(cRTmY$sj$e=csNa=w3iQh1R*D_S3S5m8i!PchMYJ?@8d za;jIdVdX-p=;Jta^vb1GNmWv+BFtNtF;%&7QoA4P;zs|%bW^6oTz=P=vhngZ zyFOgf88`x_0wRLLkFkHNg>!9ic|OgX_78(1PmJbWb*ZTLxDWIEr_Laah^zvh^jI!?x>NxzP){}(QLh8p(%?Od z0(tlS54n-%ZE%wk#dp1$nGpd@6hT#^ Z6;wh&RS@Y#R73y8+>uTcBmn+WvVdw}z=Z$+ diff --git a/docs/404.html b/docs/404.html index 0a28af01..d99ed4d5 100644 --- a/docs/404.html +++ b/docs/404.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 5887367b..a3c366c0 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 diff --git a/docs/articles/index.html b/docs/articles/index.html index d5bd305a..d8d1ea9f 100644 --- a/docs/articles/index.html +++ b/docs/articles/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 diff --git a/docs/authors.html b/docs/authors.html index d89dfd3c..add975f4 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 diff --git a/docs/index.html b/docs/index.html index 7e872990..62dd4c9e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -43,7 +43,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 diff --git a/docs/news/index.html b/docs/news/index.html index 88cd6c66..fe6d6366 100644 --- a/docs/news/index.html +++ b/docs/news/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014 @@ -229,21 +229,26 @@ Source: NEWS.md -
-

-AMR 1.2.0.9013 Unreleased +
+

+AMR 1.2.0.9014 Unreleased

-
+

-Last updated: 22-Jun-2020 +Last updated: 25-Jun-2020

New

  • +

    Function ab_from_text() to retrieve antimicrobial drugs from clinical texts in e.g. health care records, which also corrects for misspelling since it uses as.ab() internally:

    +
    ab_from_text("28/03/2020 regular amoxiciliin 500mg po tds")
    +#> [1] "Amoxicillin"
    +
  • +
  • Tidyverse selections for antibiotic classes, that help to select the columns of antibiotics that are of a specific antibiotic class, without the need to define the columns or antibiotic abbreviations. They can be used in any function that allows Tidyverse selections, like dplyr::select() and tidyr::pivot_longer():

    -
    library(dplyr)
    +
    library(dplyr)
     
     # Columns 'IPM' and 'MEM' are in the example_isolates data set
     example_isolates %>%
    @@ -269,6 +274,8 @@
     

    Changed

      +
    • Fixed a bug for using susceptibility or resistance() outside summarise() +
    • Fixed a bug where eucast_rules() would not work on a tibble when the tibble or dplyr package was loaded
    • All *_join_microorganisms() functions and bug_drug_combinations() now return the original data class (e.g. tibbles and data.tables)
    • Fixed a bug where as.ab() would return an error on invalid input values
    • @@ -278,6 +285,9 @@
    • Fixed a bug in bug_drug_combinations() for when only one antibiotic was in the input data
    • Changed the summary for class <mo>, to highlight the %SI vs. %R
    • Improved error handling, giving more useful info when functions return an error
    • +
    • Algorithm improvements to as.ab() +
    • +
    • Added Monuril as trade name for fosfomycin
    @@ -399,7 +409,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
  • Fixed important floating point error for some MIC comparisons in EUCAST 2020 guideline

  • Interpretation from MIC values (and disk zones) to R/SI can now be used with mutate_at() of the dplyr package:

    -
    yourdata %>%
    +
    yourdata %>%
       mutate_at(vars(antibiotic1:antibiotic25), as.rsi, mo = "E. coli")
     
     yourdata %>%
    @@ -426,7 +436,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
     
    • Support for LOINC codes in the antibiotics data set. Use ab_loinc() to retrieve LOINC codes, or use a LOINC code for input in any ab_* function:

      -
      ab_loinc("ampicillin")
      +
      ab_loinc("ampicillin")
       #> [1] "21066-6" "3355-5"  "33562-0" "33919-2" "43883-8" "43884-6" "87604-5"
       ab_name("21066-6")
       #> [1] "Ampicillin"
      @@ -435,7 +445,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
       
    • Support for SNOMED CT codes in the microorganisms data set. Use mo_snomed() to retrieve SNOMED codes, or use a SNOMED code for input in any mo_* function:

      -
      mo_snomed("S. aureus")
      +
      mo_snomed("S. aureus")
       #> [1] 115329001   3092008 113961008
       mo_name(115329001)
       #> [1] "Staphylococcus aureus"
      @@ -498,9 +508,9 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
       
      • If you were dependent on the old Enterobacteriaceae family e.g. by using in your code:

        -
        if (mo_family(somebugs) == "Enterobacteriaceae") ...
        +
        if (mo_family(somebugs) == "Enterobacteriaceae") ...

        then please adjust this to:

        -
        if (mo_order(somebugs) == "Enterobacterales") ...
        +
        if (mo_order(somebugs) == "Enterobacterales") ...
    • @@ -512,7 +522,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
      • Functions susceptibility() and resistance() as aliases of proportion_SI() and proportion_R(), respectively. These functions were added to make it more clear that “I” should be considered susceptible and not resistant.

        -
        library(dplyr)
        +
        library(dplyr)
         example_isolates %>%
           group_by(bug = mo_name(mo)) %>%
           summarise(amoxicillin = resistance(AMX),
        @@ -539,7 +549,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
         
      • More intelligent way of coping with some consonants like “l” and “r”

      • Added a score (a certainty percentage) to mo_uncertainties(), that is calculated using the Levenshtein distance:

        -
        as.mo(c("Stafylococcus aureus",
        +
        as.mo(c("Stafylococcus aureus",
                 "staphylokok aureuz"))
         #> Warning: 
         #> Results of two values were guessed with uncertainty. Use mo_uncertainties() to review them.
        @@ -596,12 +606,12 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
         
        • Determination of first isolates now excludes all ‘unknown’ microorganisms at default, i.e. microbial code "UNKNOWN". They can be included with the new parameter include_unknown:

          -
          first_isolate(..., include_unknown = TRUE)
          +
          first_isolate(..., include_unknown = TRUE)

          For WHONET users, this means that all records/isolates with organism code "con" (contamination) will be excluded at default, since as.mo("con") = "UNKNOWN". The function always shows a note with the number of ‘unknown’ microorganisms that were included or excluded.

        • For code consistency, classes ab and mo will now be preserved in any subsetting or assignment. For the sake of data integrity, this means that invalid assignments will now result in NA:

          -
          # how it works in base R:
          +
          # how it works in base R:
           x <- factor("A")
           x[1] <- "B"
           #> Warning message:
          @@ -624,7 +634,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
           
          • Function bug_drug_combinations() to quickly get a data.frame with the results of all bug-drug combinations in a data set. The column containing microorganism codes is guessed automatically and its input is transformed with mo_shortname() at default:

            -
            x <- bug_drug_combinations(example_isolates)
            +
            x <- bug_drug_combinations(example_isolates)
             #> NOTE: Using column `mo` as input for `col_mo`.
             x[1:4, ]
             #>             mo  ab S I R total
            @@ -645,11 +655,11 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             #> 4 Gram-negative AMX 227  0 405   632
             #> NOTE: Use 'format()' on this result to get a publicable/printable format.

            You can format this to a printable format, ready for reporting or exporting to e.g. Excel with the base R format() function:

            -
            format(x, combine_IR = FALSE)
            +
            format(x, combine_IR = FALSE)
          • Additional way to calculate co-resistance, i.e. when using multiple antimicrobials as input for portion_* functions or count_* functions. This can be used to determine the empiric susceptibility of a combination therapy. A new parameter only_all_tested (which defaults to FALSE) replaces the old also_single_tested and can be used to select one of the two methods to count isolates and calculate portions. The difference can be seen in this example table (which is also on the portion and count help pages), where the %SI is being determined:

            -
            # --------------------------------------------------------------------
            +
            # --------------------------------------------------------------------
             #                     only_all_tested = FALSE  only_all_tested = TRUE
             #                     -----------------------  -----------------------
             #  Drug A    Drug B   include as  include as   include as  include as
            @@ -669,7 +679,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             
          • tibble printing support for classes rsi, mic, disk, ab mo. When using tibbles containing antimicrobial columns, values S will print in green, values I will print in yellow and values R will print in red. Microbial IDs (class mo) will emphasise on the genus and species, not on the kingdom.

            -
            # (run this on your own console, as this page does not support colour printing)
            +
            # (run this on your own console, as this page does not support colour printing)
             library(dplyr)
             example_isolates %>%
               select(mo:AMC) %>%
            @@ -750,7 +760,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             
            • Function rsi_df() to transform a data.frame to a data set containing only the microbial interpretation (S, I, R), the antibiotic, the percentage of S/I/R and the number of available isolates. This is a convenient combination of the existing functions count_df() and portion_df() to immediately show resistance percentages and number of available isolates:

              -
              septic_patients %>%
              +
              septic_patients %>%
                 select(AMX, CIP) %>%
                 rsi_df()
               #      antibiotic  interpretation      value  isolates
              @@ -775,7 +785,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
               
            • UPEC (Uropathogenic E. coli)

            All these lead to the microbial ID of E. coli:

            -
            as.mo("UPEC")
            +
            as.mo("UPEC")
             # B_ESCHR_COL
             mo_name("UPEC")
             # "Escherichia coli"
            @@ -882,7 +892,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             
          • when all values are unique it now shows a message instead of a warning

          • support for boxplots:

            -
            septic_patients %>%
            +
            septic_patients %>%
               freq(age) %>%
               boxplot()
             # grouped boxplots:
            @@ -973,7 +983,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             
          • New filters for antimicrobial classes. Use these functions to filter isolates on results in one of more antibiotics from a specific class:

            -
            filter_aminoglycosides()
            +
            filter_aminoglycosides()
             filter_carbapenems()
             filter_cephalosporins()
             filter_1st_cephalosporins()
            @@ -985,14 +995,14 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             filter_macrolides()
             filter_tetracyclines()

            The antibiotics data set will be searched, after which the input data will be checked for column names with a value in any abbreviations, codes or official names found in the antibiotics data set. For example:

            -
            septic_patients %>% filter_glycopeptides(result = "R")
            +
            septic_patients %>% filter_glycopeptides(result = "R")
             # Filtering on glycopeptide antibacterials: any of `vanc` or `teic` is R
             septic_patients %>% filter_glycopeptides(result = "R", scope = "all")
             # Filtering on glycopeptide antibacterials: all of `vanc` and `teic` is R
          • All ab_* functions are deprecated and replaced by atc_* functions:

            -
            ab_property -> atc_property()
            +
            ab_property -> atc_property()
             ab_name -> atc_name()
             ab_official -> atc_official()
             ab_trivial_nl -> atc_trivial_nl()
            @@ -1011,17 +1021,17 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
             
          • New function age_groups() to split ages into custom or predefined groups (like children or elderly). This allows for easier demographic antimicrobial resistance analysis per age group.

          • New function ggplot_rsi_predict() as well as the base R plot() function can now be used for resistance prediction calculated with resistance_predict():

            -
            x <- resistance_predict(septic_patients, col_ab = "amox")
            +
            x <- resistance_predict(septic_patients, col_ab = "amox")
             plot(x)
             ggplot_rsi_predict(x)
          • Functions filter_first_isolate() and filter_first_weighted_isolate() to shorten and fasten filtering on data sets with antimicrobial results, e.g.:

            -
            septic_patients %>% filter_first_isolate(...)
            +
            septic_patients %>% filter_first_isolate(...)
             # or
             filter_first_isolate(septic_patients, ...)

            is equal to:

            -
            septic_patients %>%
            +
            septic_patients %>%
               mutate(only_firsts = first_isolate(septic_patients, ...)) %>%
               filter(only_firsts == TRUE) %>%
               select(-only_firsts)
            @@ -1052,7 +1062,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
            • Now handles incorrect spelling, like i instead of y and f instead of ph:

              -
              # mo_fullname() uses as.mo() internally
              +
              # mo_fullname() uses as.mo() internally
               
               mo_fullname("Sthafilokockus aaureuz")
               #> [1] "Staphylococcus aureus"
              @@ -1062,7 +1072,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
               
            • Uncertainty of the algorithm is now divided into four levels, 0 to 3, where the default allow_uncertain = TRUE is equal to uncertainty level 2. Run ?as.mo for more info about these levels.

              -
              # equal:
              +
              # equal:
               as.mo(..., allow_uncertain = TRUE)
               as.mo(..., allow_uncertain = 2)
               
              @@ -1075,7 +1085,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
               
            • All microbial IDs that found are now saved to a local file ~/.Rhistory_mo. Use the new function clean_mo_history() to delete this file, which resets the algorithms.

            • Incoercible results will now be considered ‘unknown’, MO code UNKNOWN. On foreign systems, properties of these will be translated to all languages already previously supported: German, Dutch, French, Italian, Spanish and Portuguese:

              -
              mo_genus("qwerty", language = "es")
              +
              mo_genus("qwerty", language = "es")
               # Warning: 
               # one unique value (^= 100.0%) could not be coerced and is considered 'unknown': "qwerty". Use mo_failures() to review it.
               #> [1] "(género desconocido)"
              @@ -1123,7 +1133,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
              • Support for tidyverse quasiquotation! Now you can create frequency tables of function outcomes:

                -
                # Determine genus of microorganisms (mo) in `septic_patients` data set:
                +
                # Determine genus of microorganisms (mo) in `septic_patients` data set:
                 # OLD WAY
                 septic_patients %>%
                   mutate(genus = mo_genus(mo)) %>%
                @@ -1206,7 +1216,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                 
              • Fewer than 3 characters as input for as.mo will return NA

              • Function as.mo (and all mo_* wrappers) now supports genus abbreviations with “species” attached

                -
                as.mo("E. species")        # B_ESCHR
                +
                as.mo("E. species")        # B_ESCHR
                 mo_fullname("E. spp.")     # "Escherichia species"
                 as.mo("S. spp")            # B_STPHY
                 mo_fullname("S. species")  # "Staphylococcus species"
                @@ -1221,13 +1231,13 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                • Support for grouping variables, test with:

                  -
                  septic_patients %>%
                  +
                  septic_patients %>%
                     group_by(hospital_id) %>%
                     freq(gender)
                • Support for (un)selecting columns:

                  -
                  septic_patients %>%
                  +
                  septic_patients %>%
                     freq(hospital_id) %>%
                     select(-count, -cum_count) # only get item, percent, cum_percent
                • @@ -1305,7 +1315,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/

                They also come with support for German, Dutch, French, Italian, Spanish and Portuguese:

                -
                mo_gramstain("E. coli")
                +
                mo_gramstain("E. coli")
                 # [1] "Gram negative"
                 mo_gramstain("E. coli", language = "de") # German
                 # [1] "Gramnegativ"
                @@ -1314,7 +1324,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                 mo_fullname("S. group A", language = "pt") # Portuguese
                 # [1] "Streptococcus grupo A"

                Furthermore, former taxonomic names will give a note about the current taxonomic name:

                -
                mo_gramstain("Esc blattae")
                +
                mo_gramstain("Esc blattae")
                 # Note: 'Escherichia blattae' (Burgess et al., 1973) was renamed 'Shimwellia blattae' (Priest and Barker, 2010)
                 # [1] "Gram negative"
              • @@ -1327,14 +1337,14 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
              • Function is.rsi.eligible to check for columns that have valid antimicrobial results, but do not have the rsi class yet. Transform the columns of your raw data with: data %>% mutate_if(is.rsi.eligible, as.rsi)

              • Functions as.mo and is.mo as replacements for as.bactid and is.bactid (since the microoganisms data set not only contains bacteria). These last two functions are deprecated and will be removed in a future release. The as.mo function determines microbial IDs using intelligent rules:

                -
                as.mo("E. coli")
                +
                as.mo("E. coli")
                 # [1] B_ESCHR_COL
                 as.mo("MRSA")
                 # [1] B_STPHY_AUR
                 as.mo("S group A")
                 # [1] B_STRPTC_GRA

                And with great speed too - on a quite regular Linux server from 2007 it takes us less than 0.02 seconds to transform 25,000 items:

                -
                thousands_of_E_colis <- rep("E. coli", 25000)
                +
                thousands_of_E_colis <- rep("E. coli", 25000)
                 microbenchmark::microbenchmark(as.mo(thousands_of_E_colis), unit = "s")
                 # Unit: seconds
                 #         min       median         max  neval
                @@ -1366,7 +1376,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                 
              • Added three antimicrobial agents to the antibiotics data set: Terbinafine (D01BA02), Rifaximin (A07AA11) and Isoconazole (D01AC05)

              • Added 163 trade names to the antibiotics data set, it now contains 298 different trade names in total, e.g.:

                -
                ab_official("Bactroban")
                +
                ab_official("Bactroban")
                 # [1] "Mupirocin"
                 ab_name(c("Bactroban", "Amoxil", "Zithromax", "Floxapen"))
                 # [1] "Mupirocin" "Amoxicillin" "Azithromycin" "Flucloxacillin"
                @@ -1381,7 +1391,7 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                 
              • Added parameters minimum and as_percent to portion_df

              • Support for quasiquotation in the functions series count_* and portions_*, and n_rsi. This allows to check for more than 2 vectors or columns.

                -
                septic_patients %>% select(amox, cipr) %>% count_IR()
                +
                septic_patients %>% select(amox, cipr) %>% count_IR()
                 # which is the same as:
                 septic_patients %>% count_IR(amox, cipr)
                 
                @@ -1399,10 +1409,10 @@ This works for all drug combinations, such as ampicillin/sulbactam, ceftazidime/
                 
              • Added longest en shortest character length in the frequency table (freq) header of class character

              • Support for types (classes) list and matrix for freq

                -
                my_matrix = with(septic_patients, matrix(c(age, gender), ncol = 2))
                +
                my_matrix = with(septic_patients, matrix(c(age, gender), ncol = 2))
                 freq(my_matrix)

                For lists, subsetting is possible:

                -
                my_list = list(age = septic_patients$age, gender = septic_patients$gender)
                +
                my_list = list(age = septic_patients$age, gender = septic_patients$gender)
                 my_list %>% freq(age)
                 my_list %>% freq(gender)
              • diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index 31d91fe1..bce17854 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -10,7 +10,7 @@ articles: WHONET: WHONET.html benchmarks: benchmarks.html resistance_predict: resistance_predict.html -last_built: 2020-06-22T11:18Z +last_built: 2020-06-25T15:34Z urls: reference: https://msberends.gitlab.io/AMR/reference article: https://msberends.gitlab.io/AMR/articles diff --git a/docs/reference/ab_from_text.html b/docs/reference/ab_from_text.html new file mode 100644 index 00000000..6cac6cf6 --- /dev/null +++ b/docs/reference/ab_from_text.html @@ -0,0 +1,305 @@ + + + + + + + + +Retrieve antimicrobial drugs from text — ab_from_text • AMR (for R) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                +
                + + + + +
                + +
                +
                + + +
                +

                Use this function on e.g. clinical texts from health care records. It returns a vector of antimicrobial drugs found in the texts.

                +
                + +
                ab_from_text(text, collapse = NULL, translate_ab = "name", ...)
                + +

                Arguments

                + + + + + + + + + + + + + + + + + + +
                text

                text to analyse

                collapse

                character to pass on to paste(..., collapse = ...) to only return one character per element of text, see Examples

                translate_ab

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property(). Defaults to "name", which is equal to using TRUE. Use a value FALSE, NULL or NA to prevent translation of the <ab> code.

                ...

                parameters passed on to as.ab()

                + +

                Details

                + +

                To use this for creating a new variable in a data set (e.g. with mutate()), it could be convenient to paste the outcome together with the collapse parameter so every value in your new variable will be a character of length 1:
                +df %>% mutate(abx = ab_from_text(clinical_text, collapse = "|"))

                +

                This function is also internally used by as.ab(), although it then only returns the first hit.

                + +

                Examples

                +
                # mind the bad spelling of amoxicillin in this line, 
                +# straight from a true health care record:
                +ab_from_text("28/03/2020 regular amoxicilliin 500mg po tds")
                +
                +ab_from_text("administered amoxi/clav and cipro")
                +ab_from_text("administered amoxi/clav and cipro", collapse = ", ")
                +
                +# if you want to know which antibiotic groups were administered, check it:
                +abx <- ab_from_text("administered amoxi/clav and cipro")
                +ab_group(abx)
                +
                + +
                + + + +
                + + + + + + + + diff --git a/docs/reference/as.ab.html b/docs/reference/as.ab.html index 566ceae5..31309376 100644 --- a/docs/reference/as.ab.html +++ b/docs/reference/as.ab.html @@ -82,7 +82,7 @@ AMR (for R) - 1.2.0 + 1.2.0.9014
                @@ -288,7 +288,12 @@ This package contains all ~550 antibiotic, antimycotic and antiviral dru

                On our website https://msberends.gitlab.io/AMR you can find a comprehensive tutorial about how to conduct AMR analysis, the complete documentation of all functions (which reads a lot easier than here in R) and an example analysis using WHONET data.

                See also

                -

                antibiotics for the dataframe that is being used to determine ATCs.

                +
                +
                  +
                • antibiotics for the dataframe that is being used to determine ATCs

                • +
                • ab_from_text() for a function to retrieve antimicrobial drugs from clinical text (from health care records)

                • +
                +

                Examples

                # these examples all return "ERY", the ID of erythromycin:
                diff --git a/docs/reference/as.rsi.html b/docs/reference/as.rsi.html
                index 18b4879e..87c8ae26 100644
                --- a/docs/reference/as.rsi.html
                +++ b/docs/reference/as.rsi.html
                @@ -82,7 +82,7 @@
                       
                       
                         AMR (for R)
                -        1.2.0.9013
                +        1.2.0.9014
                       
                     
                diff --git a/docs/reference/count.html b/docs/reference/count.html index c2ddf447..b077baca 100644 --- a/docs/reference/count.html +++ b/docs/reference/count.html @@ -83,7 +83,7 @@ count_resistant() should be used to count resistant isolates, count_susceptible( AMR (for R) - 1.2.0 + 1.2.0.9014
              • @@ -280,7 +280,7 @@ count_resistant() should be used to count resistant isolates, count_susceptible( translate_ab -

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property()

                +

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property(). Use a value

                language @@ -400,7 +400,7 @@ A microorganism is categorised as Susceptible, Increased exposure when S = count_S(CIP), n1 = count_all(CIP), # the actual total; sum of all three n2 = n_rsi(CIP), # same - analogous to n_distinct - total = n()) # NOT the number of tested isolates! + total = n()) # NOT the number of tested isolates! # Count co-resistance between amoxicillin/clav acid and gentamicin, # so we can see that combination therapy does a lot more than mono therapy. diff --git a/docs/reference/ggplot_rsi.html b/docs/reference/ggplot_rsi.html index e060340d..20599a41 100644 --- a/docs/reference/ggplot_rsi.html +++ b/docs/reference/ggplot_rsi.html @@ -82,7 +82,7 @@ AMR (for R) - 1.2.0 + 1.2.0.9014
                @@ -326,7 +326,7 @@ translate_ab -

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property()

                +

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property(). Use a value

                combine_SI diff --git a/docs/reference/index.html b/docs/reference/index.html index fb04aa9c..6f6480ea 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.2.0.9013 + 1.2.0.9014
              • diff --git a/docs/reference/mo_property.html b/docs/reference/mo_property.html index 53d40444..7e9d3b80 100644 --- a/docs/reference/mo_property.html +++ b/docs/reference/mo_property.html @@ -82,7 +82,7 @@ AMR (for R) - 1.2.0.9011 + 1.2.0.9014
                diff --git a/docs/reference/proportion.html b/docs/reference/proportion.html index 9bd826a5..79f5d734 100644 --- a/docs/reference/proportion.html +++ b/docs/reference/proportion.html @@ -83,7 +83,7 @@ resistance() should be used to calculate resistance, susceptibility() should be AMR (for R) - 1.2.0.9011 + 1.2.0.9014
                @@ -296,7 +296,7 @@ resistance() should be used to calculate resistance, susceptibility() should be translate_ab -

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property()

                +

                a column name of the antibiotics data set to translate the antibiotic abbreviations to, using ab_property(). Use a value

                language diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 320f21f0..5dd3ef71 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -15,6 +15,9 @@ https://msberends.gitlab.io/AMR/reference/WHONET.html + + https://msberends.gitlab.io/AMR/reference/ab_from_text.html + https://msberends.gitlab.io/AMR/reference/ab_property.html diff --git a/man/ab_from_text.Rd b/man/ab_from_text.Rd new file mode 100644 index 00000000..be1bdcb8 --- /dev/null +++ b/man/ab_from_text.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ab_from_text.R +\name{ab_from_text} +\alias{ab_from_text} +\title{Retrieve antimicrobial drugs from text} +\usage{ +ab_from_text(text, collapse = NULL, translate_ab = "name", ...) +} +\arguments{ +\item{text}{text to analyse} + +\item{collapse}{character to pass on to \code{paste(..., collapse = ...)} to only return one character per element of \code{text}, see Examples} + +\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}. Defaults to "name", which is equal to using \code{TRUE}. Use a value \code{FALSE}, \code{NULL} or \code{NA} to prevent translation of the \verb{} code.} + +\item{...}{parameters passed on to \code{\link[=as.ab]{as.ab()}}} +} +\description{ +Use this function on e.g. clinical texts from health care records. It returns a vector of antimicrobial drugs found in the texts. +} +\details{ +To use this for creating a new variable in a data set (e.g. with \code{mutate()}), it could be convenient to paste the outcome together with the \code{collapse} parameter so every value in your new variable will be a character of length 1:\cr +\code{df \%>\% mutate(abx = ab_from_text(clinical_text, collapse = "|"))} + +This function is also internally used by \code{\link[=as.ab]{as.ab()}}, although it then only returns the first hit. +} +\examples{ +# mind the bad spelling of amoxicillin in this line, +# straight from a true health care record: +ab_from_text("28/03/2020 regular amoxicilliin 500mg po tds") + +ab_from_text("administered amoxi/clav and cipro") +ab_from_text("administered amoxi/clav and cipro", collapse = ", ") + +# if you want to know which antibiotic groups were administered, check it: +abx <- ab_from_text("administered amoxi/clav and cipro") +ab_group(abx) +} diff --git a/man/as.ab.Rd b/man/as.ab.Rd index fc3d097a..e2a9d9d3 100644 --- a/man/as.ab.Rd +++ b/man/as.ab.Rd @@ -83,5 +83,8 @@ ab_name("J01FA01") # "Erythromycin" ab_name("eryt") # "Erythromycin" } \seealso{ -\link{antibiotics} for the dataframe that is being used to determine ATCs. +\itemize{ +\item \link{antibiotics} for the dataframe that is being used to determine ATCs +\item \code{\link[=ab_from_text]{ab_from_text()}} for a function to retrieve antimicrobial drugs from clinical text (from health care records) +} } diff --git a/man/count.Rd b/man/count.Rd index 74e7a636..e772a1c7 100644 --- a/man/count.Rd +++ b/man/count.Rd @@ -47,7 +47,7 @@ count_df( \item{data}{a \code{\link{data.frame}} containing columns with class \code{\link{rsi}} (see \code{\link[=as.rsi]{as.rsi()}})} -\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}} +\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}. Use a value} \item{language}{language of the returned text, defaults to system language (see \code{\link[=get_locale]{get_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.} diff --git a/man/ggplot_rsi.Rd b/man/ggplot_rsi.Rd index 392861c2..2116a72f 100644 --- a/man/ggplot_rsi.Rd +++ b/man/ggplot_rsi.Rd @@ -83,7 +83,7 @@ labels_rsi_count( \item{limits}{numeric vector of length two providing limits of the scale, use \code{NA} to refer to the existing minimum or maximum} -\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}} +\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}. Use a value} \item{combine_SI}{a logical to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the parameter \code{combine_IR}, but this now follows the redefinition by EUCAST about the interpretion of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is \code{TRUE}.} diff --git a/man/proportion.Rd b/man/proportion.Rd index bd7be656..22ea1a55 100644 --- a/man/proportion.Rd +++ b/man/proportion.Rd @@ -62,7 +62,7 @@ rsi_df( \item{data}{a \code{\link{data.frame}} containing columns with class \code{\link{rsi}} (see \code{\link[=as.rsi]{as.rsi()}})} -\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}} +\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}. Use a value} \item{language}{language of the returned text, defaults to system language (see \code{\link[=get_locale]{get_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.} diff --git a/tests/testthat/test-ab_from_text.R b/tests/testthat/test-ab_from_text.R new file mode 100644 index 00000000..ce9be46e --- /dev/null +++ b/tests/testthat/test-ab_from_text.R @@ -0,0 +1,32 @@ +# ==================================================================== # +# TITLE # +# Antimicrobial Resistance (AMR) Analysis # +# # +# SOURCE # +# https://gitlab.com/msberends/AMR # +# # +# LICENCE # +# (c) 2018-2020 Berends MS, Luz CF et al. # +# # +# This R package is free software; you can freely use and distribute # +# it for both personal and commercial purposes under the terms of the # +# GNU General Public License version 2.0 (GNU GPL-2), as published by # +# the Free Software Foundation. # +# # +# We created this package for both routine data analysis and academic # +# research and it was publicly released in the hope that it will be # +# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. # +# Visit our website for more info: https://msberends.gitlab.io/AMR. # +# ==================================================================== # + +context("ab_from_text.R") + +test_that("ab_from_text works", { + + expect_identical(ab_from_text("28/03/2020 regular amoxicilliin 500mg po tds"), + "Amoxicillin") + expect_identical(ab_from_text("28/03/2020 regular amoxicilliin 500mg po tds", translate_ab = FALSE), + as.ab("AMX")) + expect_identical(ab_from_text("administered amoxi/clav and cipro", collapse = ", "), + "Amoxicillin, Ciprofloxacin") +})