From 8f0c289495b45fdfc62b35bd6e49bd18e112ab2e Mon Sep 17 00:00:00 2001 From: cristinamullin <46969696+cristinamullin@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:26:53 -0400 Subject: [PATCH 1/7] usability update to flag prompt Result value is not numeric (text) OR result value is NA and no detection limit value is provided --- inst/flag_prompts.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/flag_prompts.csv b/inst/flag_prompts.csv index c972631d6..a1707b6e4 100644 --- a/inst/flag_prompts.csv +++ b/inst/flag_prompts.csv @@ -1,5 +1,5 @@ Order,Level,Prompt,flagType -1,Required,Result value is not numeric or NA and no detection limit value is provided (see TADA.ResultMeasureValueDataTypes.Flag),Result value is not numeric or NA and no detection limit value is provided +1,Required,Result value is not numeric (text) OR result value is NA and no detection limit value is provided (see TADA.ResultMeasureValueDataTypes.Flag),Result value is not numeric or NA and no detection limit value is provided 2,Required,Result value is not numeric or NA and the detection limit value cannot be interpreted because there is a conflict between the detection condition text and detection limit type provided by the data submitter [or the detection limit type is not in WQX domain tables (USGS/NWIS-specific)] (see TADA.CensoredData.Flag),Result value is not numeric or NA and the detection limit value cannot be interpreted because there is a conflict between the detection condition text and detection limit type provided by the data submitter [or the detection limit type is not in WQX domain tables (USGS/NWIS-specific)] 3,Recommended,Suspect characteristic and speciation combination (see TADA.MethodSpeciation.Flag),Suspect characteristic and speciation combination 4,Recommended,Suspect characteristic and fraction combination (see TADA.SampleFraction.Flag),Suspect characteristic and fraction combination From 2be6835a41d639c12b0705672037a5fa8a676981 Mon Sep 17 00:00:00 2001 From: cristinamullin <46969696+cristinamullin@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:03:37 -0400 Subject: [PATCH 2/7] Update mod_query_data.R --- R/mod_query_data.R | 77 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/R/mod_query_data.R b/R/mod_query_data.R index 2e8855cc8..e89f439f0 100644 --- a/R/mod_query_data.R +++ b/R/mod_query_data.R @@ -12,6 +12,17 @@ load("inst/extdata/statecodes_df.Rdata") load("inst/extdata/query_choices.Rdata") + +# new (2024-05-23) list for new Country/Ocean(s) Query the Water Quality Portal option. Not included in saved query_choices file +library(jsonlite) +library(dplyr) +url <- 'https://www.waterqualitydata.us/Codes/countrycode?mimeType=json' +countryocean_source <- fromJSON(txt=url) +countryocean_source <- countryocean_source$codes %>% select(-one_of('providers')) +countryocean_source <- countryocean_source[order(countryocean_source$desc),] +countryocean_choices <- countryocean_source$value +names(countryocean_choices) <- countryocean_source$desc + # Last run by EDH on 08/25/23 # county = readr::read_tsv(url("https://www2.census.gov/geo/docs/reference/codes/files/national_county.txt"), col_names = FALSE) # county = county%>%tidyr::separate(X1,into = c("STUSAB","STATE","COUNTY","COUNTY_NAME","COUNTY_ID"), sep=",") @@ -90,16 +101,19 @@ mod_query_data_ui <- function(id) { shiny::textInput(ns("huc"), "Hydrologic Unit", placeholder = "e.g. 020700100103") ) ), - shiny::fluidRow(column( - 4, - shiny::selectizeInput( - ns("siteid"), - "Monitoring Location ID(s)", - choices = NULL, - multiple = TRUE - ) - )), - htmltools::h4("Metadata Filters"), + shiny::fluidRow( + column(4, + shiny::selectizeInput(ns("siteid"), + "Monitoring Location ID(s)", + choices = NULL, + multiple = TRUE)), + column(4, + shiny::selectizeInput(ns("countryocean"), + "Country/Ocean(s)", + choices = NULL, + multiple = TRUE)) + ), + htmltools::h4("Metadata Filters"), shiny::fluidRow( column( 4, @@ -149,7 +163,12 @@ mod_query_data_ui <- function(id) { ), column( 4, - shiny::selectizeInput(ns("chargroup"), "Characteristic Group", choices = NULL) + shiny::selectizeInput( + ns("chargroup"), + "Characteristic Group", + choices = NULL, + multiple = TRUE + ) ), column( 4, @@ -161,6 +180,14 @@ mod_query_data_ui <- function(id) { ) ) ), + shiny::fluidRow( + column( + 4, + shiny::checkboxGroupInput(ns("providers"), + "Data Source", + c("NWIS (USGS)" = "NWIS", "WQX (EPA)" = "STORET")) + ) + ), shiny::fluidRow(column( 4, shiny::actionButton(ns("querynow"), "Run Query", shiny::icon("cloud"), @@ -317,6 +344,17 @@ mod_query_data_server <- function(id, tadat) { server = TRUE ) + + shiny::updateSelectizeInput( + session, + "countryocean", + choices = countryocean_choices, + selected = character(0), + options = list(placeholder = "Start typing or use drop down menu"), + server = TRUE + ) + + # this observes when the user inputs a state into the drop down and subsets the choices for counties to only those counties within that state. shiny::observeEvent(input$state, { state_counties <- subset(county, county$STUSAB == input$state) @@ -352,6 +390,17 @@ mod_query_data_server <- function(id, tadat) { } else { tadat$countycode <- input$county } + # this is an overloaded field which can be 2-character Country or Ocean + if (is.null(input$countryocean)) { + tadat$countrycode <- "null" + } else { + tadat$countrycode <- input$countryocean + } + if (is.null(input$providers)) { + tadat$providers <- "null" + } else { + tadat$providers <- input$providers + } if (input$huc == "") { tadat$huc <- "null" } else { @@ -362,7 +411,7 @@ mod_query_data_server <- function(id, tadat) { } else { tadat$siteType <- input$type } - if (input$chargroup == "") { + if (is.null(input$chargroup)) { tadat$characteristicType <- "null" } else { tadat$characteristicType <- input$chargroup @@ -380,7 +429,7 @@ mod_query_data_server <- function(id, tadat) { if (is.null(input$project)) { tadat$project <- "null" } else { - tadat$project <- input$project + tadat$project <- paste(input$project, collapse = ",") } if (is.null(input$org)) { tadat$organization <- "null" @@ -417,6 +466,7 @@ mod_query_data_server <- function(id, tadat) { raw <- EPATADA::TADA_DataRetrieval( statecode = tadat$statecode, countycode = tadat$countycode, + countrycode = tadat$countrycode, huc = tadat$huc, siteid = tadat$siteid, siteType = tadat$siteType, @@ -427,6 +477,7 @@ mod_query_data_server <- function(id, tadat) { organization = tadat$organization, startDate = tadat$startDate, endDate = tadat$endDate, + providers = tadat$providers, applyautoclean = TRUE ) From 409d8ce5fd2ebcf8b776dbc85d842d9527afc441 Mon Sep 17 00:00:00 2001 From: cristinamullin <46969696+cristinamullin@users.noreply.github.com> Date: Mon, 16 Sep 2024 09:36:45 -0400 Subject: [PATCH 3/7] remove development banner --- DESCRIPTION | 5 ++--- R/app_ui.R | 11 +++++++---- R/mod_query_data.R | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 2064f97a4..0af983a7e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,8 +43,7 @@ Imports: grDevices, lubridate, plotly, - shinyjs, - lwgeom + shinyjs Remotes: github::USEPA/EPATADA Suggests: @@ -67,5 +66,5 @@ Config/testthat/load-all: list(export_all = FALSE, helpers = FALSE) LazyData: true URL: https://github.com/USEPA/TADAShiny BugReports: https://github.com/USEPA/TADAShiny/issues -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Roxygen: list(markdown = TRUE) diff --git a/R/app_ui.R b/R/app_ui.R index 66c9629a4..6f13b0034 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -24,10 +24,13 @@ app_ui <- function(request) { # Your application UI logic shiny::fluidPage( tags$html(class = "no-js", lang = "en"), - HTML("
"), + + # adds development banner + # HTML(" "), + # adds epa header html from here: https://www.epa.gov/themes/epa_theme/pattern-lab/patterns/pages-standalone-template/pages-standalone-template.rendered.html shiny::includeHTML(app_sys("app/www/header.html")), shinyjs::useShinyjs(), diff --git a/R/mod_query_data.R b/R/mod_query_data.R index e89f439f0..4f4e23110 100644 --- a/R/mod_query_data.R +++ b/R/mod_query_data.R @@ -185,7 +185,8 @@ mod_query_data_ui <- function(id) { 4, shiny::checkboxGroupInput(ns("providers"), "Data Source", - c("NWIS (USGS)" = "NWIS", "WQX (EPA)" = "STORET")) + c("NWIS (USGS)" = "NWIS", "WQX (EPA)" = "STORET"), + selected = c("NWIS", "STORET")) ) ), shiny::fluidRow(column( From 467d41b1bb6797f83f2e387505448aeaee2aaa37 Mon Sep 17 00:00:00 2001 From: cristinamullin <46969696+cristinamullin@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:26:31 -0400 Subject: [PATCH 4/7] Add continuous data flag --- R/utils_flag_functions.R | 9 ++++----- inst/flag_prompts.csv | 1 + inst/flag_tests.csv | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/R/utils_flag_functions.R b/R/utils_flag_functions.R index b736f943f..8f5da43fa 100644 --- a/R/utils_flag_functions.R +++ b/R/utils_flag_functions.R @@ -114,11 +114,10 @@ applyFlags <- function(in_table, orgs) { out <- EPATADA::TADA_FindQAPPDoc(out, clean = FALSE) } - # Dataset includes depth profile data - no function for this yet - # out <- out - - # Aggregated continuous data - # out <- EPATADA::TADA_FlagContinuousData(out, clean = FALSE, flaggedonly = FALSE) + # Continuous data + out <- EPATADA::TADA_FlagContinuousData(out, clean = FALSE, + flaggedonly = FALSE, + time_difference = 4) # Above WQX Upper Threshold out <- EPATADA::TADA_FlagAboveThreshold(out, clean = FALSE) diff --git a/inst/flag_prompts.csv b/inst/flag_prompts.csv index a1707b6e4..47b35efee 100644 --- a/inst/flag_prompts.csv +++ b/inst/flag_prompts.csv @@ -15,3 +15,4 @@ Order,Level,Prompt,flagType 14,Optional,"Result value(s) below the national threshold for a given characteristic, possibly indicating non-sensical value(s) (see TADA.ResultValueBelowLowerThreshold.Flag)","Result value(s) below the national lower threshold for a given characteristic, possibly indicating non-sensical value(s)" 15,Optional,Coordinates are outside of the United States (see TADA.InvalidCoordinates.Flag),Coordinates are outside of the United States 16,Optional,Coordinates are imprecise (less than three decimal digits) (see TADA.InvalidCoordinates.Flag),Coordinates are imprecise (less than three decimal digits) +17,Optional,Metadata indicates result values are less than 4 hours apart and are likely from continuous monitoring probes (sensors). Continuous data may (or may not) be suitable for integration with discrete water quality data for analyses.,Continuous results diff --git a/inst/flag_tests.csv b/inst/flag_tests.csv index e6b8ea804..3d8ed451d 100644 --- a/inst/flag_tests.csv +++ b/inst/flag_tests.csv @@ -77,3 +77,5 @@ Suspect characteristic and fraction combination,TADA.SampleFraction.Flag,Accepte Suspect characteristic and fraction combination,TADA.SampleFraction.Flag,Rejected,0,1 Metadata indicates duplicative uploads of the same results within a single organization,TADA.SingleOrgDup.Flag,Duplicate,0,1 Metadata indicates duplicative uploads of the same results within a single organization,TADA.SingleOrgDup.Flag,Unique,0,0 +Continuous results,TADA.ContinuousData.Flag,Continuous,0,1 +Continuous results,TADA.ContinuousData.Flag,Discrete,0,0 From 0cf1ce8e1b4b3fe12b4dfa7457d7bb48250e3d84 Mon Sep 17 00:00:00 2001 From: cristinamullin <46969696+cristinamullin@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:42:15 -0400 Subject: [PATCH 5/7] update query choices the dropdown query options should be updated frequently the siteid list could not be updated. this is a WQP issue. for now, I removed the siteid option here. --- R/mod_query_data.R | 82 ++++++++++++++++--------------- inst/extdata/query_choices.Rdata | Bin 11807473 -> 556283 bytes 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/R/mod_query_data.R b/R/mod_query_data.R index 4f4e23110..0ac62b8c4 100644 --- a/R/mod_query_data.R +++ b/R/mod_query_data.R @@ -16,25 +16,27 @@ load("inst/extdata/query_choices.Rdata") # new (2024-05-23) list for new Country/Ocean(s) Query the Water Quality Portal option. Not included in saved query_choices file library(jsonlite) library(dplyr) -url <- 'https://www.waterqualitydata.us/Codes/countrycode?mimeType=json' -countryocean_source <- fromJSON(txt=url) +countrycode_url <- 'https://www.waterqualitydata.us/Codes/countrycode?mimeType=json' +countryocean_source <- fromJSON(txt=countrycode_url) countryocean_source <- countryocean_source$codes %>% select(-one_of('providers')) countryocean_source <- countryocean_source[order(countryocean_source$desc),] countryocean_choices <- countryocean_source$value names(countryocean_choices) <- countryocean_source$desc -# Last run by EDH on 08/25/23 +# Last run by CAM on 09/16/24 # county = readr::read_tsv(url("https://www2.census.gov/geo/docs/reference/codes/files/national_county.txt"), col_names = FALSE) # county = county%>%tidyr::separate(X1,into = c("STUSAB","STATE","COUNTY","COUNTY_NAME","COUNTY_ID"), sep=",") # orgs = unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/Organization.CSV"))$ID) # chars = unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/Characteristic.CSV"))$Name) # chargroup = unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/CharacteristicGroup.CSV"))$Name) # media = c(unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/ActivityMedia.CSV"))$Name),"water","Biological Tissue","No media") -# # sitetype = unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/MonitoringLocationType.CSV"))$Name) +# sitetype = unique(utils::read.csv(url("https://cdx.epa.gov/wqx/download/DomainValues/MonitoringLocationType.CSV"))$Name) # sitetype = c("Aggregate groundwater use","Aggregate surface-water-use","Aggregate water-use establishment","Atmosphere","Estuary","Facility","Glacier","Lake, Reservoir, Impoundment","Land","Not Assigned","Ocean","Spring","Stream","Subsurface","Well","Wetland") # projects = unique(data.table::fread("https://www.waterqualitydata.us/data/Project/search?mimeType=csv&zip=no&providers=NWIS&providers=STEWARDS&providers=STORET")$ProjectIdentifier) -# mlids = unique(data.table::fread("https://www.waterqualitydata.us/data/Station/search?mimeType=csv&zip=no&providers=NWIS&providers=STEWARDS&providers=STORET")$MonitoringLocationIdentifier) -# save(orgs, chars, chargroup, media, county, sitetype, projects, mlids, file = "inst/extdata/query_choices.Rdata") +# # not working +# # mlids = unique(data.table::fread("https://www.waterqualitydata.us/data/Station/search?mimeType=csv&zip=no&providers=NWIS&providers=STEWARDS&providers=STORET")$MonitoringLocationIdentifier) +# # removing mlids for now +# save(orgs, chars, chargroup, media, county, sitetype, projects, file = "inst/extdata/query_choices.Rdata") mod_query_data_ui <- function(id) { ns <- NS(id) @@ -102,11 +104,11 @@ mod_query_data_ui <- function(id) { ) ), shiny::fluidRow( - column(4, - shiny::selectizeInput(ns("siteid"), - "Monitoring Location ID(s)", - choices = NULL, - multiple = TRUE)), + # column(4, + # shiny::selectizeInput(ns("siteid"), + # "Monitoring Location ID(s)", + # choices = NULL, + # multiple = TRUE)), column(4, shiny::selectizeInput(ns("countryocean"), "Country/Ocean(s)", @@ -121,6 +123,7 @@ mod_query_data_ui <- function(id) { ns("org"), "Organization(s)", choices = NULL, + options = list(placeholder = "Start typing or use drop down menu"), multiple = TRUE ) ), @@ -130,6 +133,7 @@ mod_query_data_ui <- function(id) { ns("project"), "Project(s)", choices = NULL, + options = list(placeholder = "Start typing or use drop down menu"), multiple = TRUE ) ), @@ -139,6 +143,7 @@ mod_query_data_ui <- function(id) { ns("type"), "Site Type(s)", choices = c(sitetype), + options = list(placeholder = "Start typing or use drop down menu"), multiple = TRUE ) ) @@ -164,20 +169,22 @@ mod_query_data_ui <- function(id) { column( 4, shiny::selectizeInput( - ns("chargroup"), - "Characteristic Group", + ns("characteristic"), + "Characteristic(s)", choices = NULL, + options = list(placeholder = "Start typing or use drop down menu"), multiple = TRUE - ) + ) ), column( 4, shiny::selectizeInput( - ns("characteristic"), - "Characteristic(s)", + ns("chargroup"), + "Characteristic Group", choices = NULL, + options = list(placeholder = "Start typing or use drop down menu"), multiple = TRUE - ) + ) ) ), shiny::fluidRow( @@ -323,8 +330,9 @@ mod_query_data_server <- function(id, tadat) { session, "chargroup", choices = c(chargroup), - selected = character(0), - options = list(placeholder = ""), + # selected = character(0), + # options = list(placeholder = ""), + options = list(placeholder = "Start typing or use drop down menu"), server = TRUE ) shiny::updateSelectizeInput(session, @@ -335,17 +343,16 @@ mod_query_data_server <- function(id, tadat) { shiny::updateSelectizeInput(session, "project", choices = c(projects), - server = TRUE - ) - shiny::updateSelectizeInput( - session, - "siteid", - choices = c(mlids), options = list(placeholder = "Start typing or use drop down menu"), server = TRUE ) - - + # shiny::updateSelectizeInput( + # session, + # "siteid", + # choices = c(mlids), + # options = list(placeholder = "Start typing or use drop down menu"), + # server = TRUE + # ) shiny::updateSelectizeInput( session, "countryocean", @@ -407,6 +414,11 @@ mod_query_data_server <- function(id, tadat) { } else { tadat$huc <- input$huc } + # if (is.null(input$siteid)) { + # tadat$siteid <- "null" + # } else { + # tadat$siteid <- input$siteid + # } if (is.null(input$type)) { tadat$siteType <- "null" } else { @@ -437,12 +449,7 @@ mod_query_data_server <- function(id, tadat) { } else { tadat$organization <- input$org } - if (is.null(input$siteid)) { - tadat$siteid <- "null" - } else { - tadat$siteid <- input$siteid - # siteid = stringr::str_trim(unlist(strsplit(input$siteids,","))) - } + if (length(input$endDate) == 0) { # ensure if date is empty, the query receives a proper input ("null") tadat$endDate <- "null" @@ -469,7 +476,7 @@ mod_query_data_server <- function(id, tadat) { countycode = tadat$countycode, countrycode = tadat$countrycode, huc = tadat$huc, - siteid = tadat$siteid, + # siteid = tadat$siteid, siteType = tadat$siteType, characteristicName = tadat$characteristicName, characteristicType = tadat$characteristicType, @@ -513,12 +520,9 @@ mod_query_data_server <- function(id, tadat) { shiny::updateSelectizeInput(session, "state", selected = tadat$statecode) shiny::updateSelectizeInput(session, "county", selected = tadat$countycode) shiny::updateTextInput(session, "huc") - shiny::updateSelectizeInput(session, "siteid", selected = tadat$siteid) + # shiny::updateSelectizeInput(session, "siteid", selected = tadat$siteid) shiny::updateSelectizeInput(session, "type", selected = tadat$siteType) - shiny::updateSelectizeInput(session, - "characteristic", - selected = tadat$characteristicName - ) + shiny::updateSelectizeInput(session, "characteristic", selected = tadat$characteristicName) shiny::updateSelectizeInput(session, "chargroup", selected = tadat$characteristicType) shiny::updateSelectizeInput(session, "media", selected = tadat$sampleMedia) shiny::updateSelectizeInput(session, "project", selected = tadat$project) diff --git a/inst/extdata/query_choices.Rdata b/inst/extdata/query_choices.Rdata index b796ed2ab67cdf22f0b7b0402300a39f93e5538f..1956885ad520302a5aa3efd687cdd4d101aa7d46 100644 GIT binary patch literal 556283 zcmV)7K*zryiwFP!000002Gsr8Z=Bh-Cx~6&RAwrroab|LiX0h~;*%I7NhvdxF_95s zOo|AKDe>^|gviKLoI^2qN$OrI^Pa5RRW4VdtLk=@ySv=g=&o*b*+v6h)zyY!!0?;> zV#9{v1{$ydyZgcLAK(Z3!A~yld9SsHZwQ7muj{f-D!y;8-`?LI)?RDvwbt&}zRh3y z_R^pH$)7y)Cl@Y||9zJH^G}}L9Igc`fAS|6{*?Uq@BPVzKY4-t_rmn}`xEltSIPT- zD4xA`<;s?POFymmui8=h4?LAY!ha#J{583L=h^l<{>yVL5E7 zH=au>0$v2Q&(*``%@%+t2a|4_e$C7|yXd-=v6u|Rih;+(5!txkGRpG=p#QrPnu zy>{LdThPv~BJFR{lG^eS*()w 7P#se{g5^e~Feby)!;X5BWh3 z_osmQQ{k{VlQ*+zi;^NIIMHEU#WO2PYEM{3mjAi0xyi_@vbju|qkp7Lp_0@UE~kX^ z6?F0D)i@ORCe!O#Ht@^%vf`k`@71$mm4CnzWz2E7uCnNVe>p280AQEtYN$(^J+ zYR7=hlFEe0T16(+0t=-0FmNFl 5eqwpbA z;5A-AC`UMSrxY@Uf6ZUxy&NI`HY*J5U>3(|e?Ws-*d-m>M&nOodf!nCR-Edm=eslG zWmv-$#1obx_gK^)L~B`A9m?M8I^Kov9M@7K+B5o6vx`^gy9U3R3^cGnAM3j+GAVvm zq&KK#zqIoXrQP?AJ^A((ytMXZPKX>Mq|*&aBqd7Wh^6#S0z{p0QNv>e2hFbm4KzU^ z9=#H>SG@;cyAgiHi=f5js>0Wg@50xPQ5WBU*BGjRA;^t{+N}<$0aT|G|1EtlCqbe$ z$Zv&NA%D@9(wAW^Y6238Yn9y!DgCtE=a;zNxPIi)B5qtq;JnaHcj$jRpC%dMP4pCb zTRyT|@Mx^=uRs!_BA)LzzD&Qd!_MHqVDyPNDlWp(K#m-^Y_2Ve#NHwKa-r3gAm@X$ ziXCMJHo>Ju!bJKW+&Ll7*Cf|)WVdM~MwJ;g5v0PaB*pW#td +9k#dS z*boJm>Fz6igOa?o3ChMUrPc0+Oelyn052NW%2+g*wG3hrDeujcE{lzdBRj0Vk~I^8 zH!KlTJGAiOV16OYC=9hV6Nx8I=)ffTBXrZ}qRav?Wr6J4;C(YOl657>ax?_&?Fr!r z@cO}?gWPsEYFOD7&1OAKT(-Cc?qAP{8#Z~8WR-;N({oGDbvd)n4Bdrh!4N4R#$dyf z>Sj^g6hTEQnRYp^v->OKmzF4>h&$D%# (I7q{+5Gnz^ z>;4d^LC_tj{KNQ2CMRO?$ BN(i&MV_&1Nz^ zVBvv_B6@@0PntUPty?`&eg&}9X$j<-O;(^Mr@inVI6W4I7nuv4_6T=VGBk0)u5>>P zDPV*7Psj- eCOED<< z@)p eWzc&7J9$blBSpEW;dI`!E|2yVBP% zbz@62dC%=)hmc+J?}t_aN1~*d%lb=(SCB0ONy~g~;t7$mC?OKXC@K|8-Ef(ap+~T7 z+!AW7(3${|))y9`%js{@AnH*9|PnplG9Jgk!@`|0--@Y2}mt$JSC@DN8AJnZ^Ak z?_M_KK?NFtT-m{m%LmP^YJ`U?8c$zd=ROOM1yXS813@J56MgNqBwB++f%iLO&if?? zngQdy^)0XI%%ODTDnsM=tE_7d0bQLBOkG_(tpoePxs$wNi?a@!Y2Ica4dl$JE_5g$ za|GR;#EmOTa&;)5-DHSj5x4-6|0Lt?L5HQl!up%%jtt@9>+qGJlTj}wumj7h(0FHQ zjgGbyT3md@VsD_Akdc{4G eo#_4Z%WbA{$nk$O$yq&+;AHGuACCr6)YpjtbNncA^J`jR)tiLfrJu z`4OnbIB$J8ubMgw?Eizi{CIU#ngaE8&Q%| anq+K<&h5 zTmm+;Wz!l9=mbOi8o1oSusHCUpqIO~PUtG)5kLqNU+G14qLW;FSP=;OMr-44TU2$* z)8w=1v@tH~4yi>Zg40L %>K*g7c?X^4u{_%4_S-a(^9p;-Kg@qh;D2mT4_L*w{rk0I{8~-DJ3A9~FVV zRE`DKUHIYk_>hOn0LQW1R^ozNu+iU)Z<#VC%I{qW3GXV5xSi0b@g}RW>U0sno}her zIpo*^fJnMB)||AiFSfmFY&15SLi$TKNvYSdG25y$gE@8AA|F hXAZLf;EKU52_GR_)I@frMfTyu5m>y zOG6DLbgL35L`#)FHsa?5v8=-z;L!z0rvkLuvh=_;x<8htPB#>4NK@Cs<-=~RvbVog z2YpE90ULm>*$V9qMQ?S}*t#(SSQabtFaWy G2~i6h Q4{x!H2ci2XM9%jZaA5|;5}(;3bA4BCgp6} z5K+k#ay*ohwJsyK>LUZdF`|w{Zo*4{Y~04>A=NcQk>tom_{M=CV+IOnk{_w*N^Pws z&X);rd>A)lVh9!21rhgiWImbmevYsQI5EDCiNUvAAIeuTQJA3P1ED5~I?OKtByo=* z5S4M~8xDDHk)kPaoMH_$8c^XMyOutIcg#Va m*s4kh$Dwd?#BU$?{sBICh+6 zeTs`ogI9qWs4?OfzM@WH`bt=7qS>GD*g$aG&u2aghq2^iXITg6d#s=^o+`Vh5rIOA zXdceFy6e6^I+ollniIF=O|i>SJ6xKxxq2v(Z!5SSO5`QWhLME{ETN6`2^XQYg$V(n zwfQ#eTo_U4zDoDx?w&`3M -7CLYXg;wq-w4;hy# zCq*y!^-S*?Ma|}?;d^_cjfIb8$zc_}b(KRaA;3Ku-{m3!ANhjhjF?e|u{IWUlQ zXwiNzEqFW)ygJl!^$PC~mRD?g;J)dUT8(MmJ#Jf&PT0;}+%kJuCX`zauo;fysVQUV zh~Nk5>9RXkNcG2VDtrAcWL*)lUg!1yCQCl2W<{w0Q9-yexZNXVG;N~u3Yvf={8|hh z<6?Adp5Jbr4V+EIGx*JH!0u>M`51vD_8xsFBUQhDJUV2@N2zqJx2`i-1-E$4MmiVC zoT53UZ*6aH7s&snZTr A(Nb?@gEG5D zn g)YmLdA)_j@iyI5l9_zlsF_Y!KV*x&l zGaAVcA`bK#v}qg{GUKgjTT+D`rprVRk{L=<-;#aICA=pLbAzu6ZZ}0SXe%}*V~2)T zRu;EghWHd e(&wXXB&Ep^P&uO2>XOx_a_SFFpQoe68pS z&rkqAaHK%MtNDsebBMz~Oo~ODBAn|y)&xb{cIdc3SJHE4uWPf39oNell`nI8agDA+ zVPog{+P&D&I2R;2 Bobp_3Q7FIq_J8c{f zTbNd0kjcj(< wDS 2wjZR8CfAA=t6BcvT7e7&XP!Ego@9--{Z?n|h5MDM*61O#-xXR^{7Sj|4t8 z0N~J|@mLBe7#1h5ra^ut|C1ab50jYf`4`xf(UZ0Xh+;Wa8~Qvq&0@?2fNA?YS;apy zizA5?m;Dr!jaVd~gQAg%AivRtw-b1TSc|5har8Z3I)5Jxk&_~|<%j!@NsAZKuRX7W z{gNnAl_mVQX6D6(80L0i#wV%%i0ee K9u1q#tz;1f{R)XqKpq7a{76k_m;o4W9J zyot?R^`OxEHGuH29C;cgT(4aWX9J*w*!4VDA9BITfXr&hWZ97yHKEzp^0*w=bXyXv z2I(JHNl$vcV#I+5h1g*p8h=y=@W|lsl0Zc5dS5&Y^S_m&uYC^5zRssP(LfC&LdsQ` z<-#AK*1T<&L(Q_@BHDM%w^*2e*L-b6n7u6Dqdnw9@ziw On!WXOT6syR&$re8x!Jwq`20( c{30&U~bO9re)bqJ`s>nPp^MzM(HB&g;nRiJO5bEl@@GA)L7P zCTbPfuJ*<~b*P5JIn}VIZvoBG8z3h1bOhe~fNJf`rPfY>5Bo;*MFm&=rPA!cK{o%t zo_j@cuD_W5HY3iLget=Bc3%w8U0CND7Il&+c%?Zk)tOLn90#y(C5DnNTr3JAFqm8- zr0p0xmpYzi!+JV8IdQJLo3qr9`?Yrt2sRy!8?`0w_fA|IcOCo2<4z#m8$ucrI_Wwr z_Gllun~JETSg3pRMGd?7uI;HRMi)4^f&d+!2h?-nvWHK`+oY~sxpF){og9z%$-f?- zj8i= d#V9hIDS7@+T&1veOnGPz}#~Z_kFT4o?_!L5S ;A2I;ZOsXub6;9nJZh~pisFJ5q`m5j_ zG-@6Q>J>~)V{&N0=uOd3WMk07 5|QG-q#`5@(mX}! zm@JuTSVlNOd<_u`KgCF@&jD3r;ZLl>)={=7`5r8(CFyi-p!U#@K@s;H5(Pi93nJ^9 zA$`(fg&-}4nVkqGoax`jNAhPKlOCOXAQ1j{vGMIJWG+}C{(L_^Ou qcOp~J_*1@FN=H~=W6*~5BPkVo`L9|B_eMo)|Vea8kJ+u z+YUt^w+rRXj3y-edSQ`N35Q~IVJ{9iY;PLhC-1}ENQxWX4+t{v>sz)e(A0`Mff99T zoC(wjL!Y5fw_@X|_%W3oCPs6sap9wf>P|c;)vDNCFpLN6LdddIsQf-PDEBGsZ_k6h z?Q#(1e)O*S8>>&^E{U;7H5AWGE-jvVP@Q zaE1?8*z)}t0jZ(4=g1eJARca)^!!iam5y@*kZ(+9yTs@3&ADNgJ7ZQDpySQRe>q!o zWF6jCWKy!37)Cvnon&`cAoKyi4)ECi-I?0_l*W^<5x#2~alAL!E4F)WyRZC}&Wa$K zfriH^+fhR!$Q@A^ ~RViU1(7KSDhnOa%jEVCTn zY@Z HT6{ z-D)+-bjk5XcjBPmFQagB)|O&n)T1!qcFAwz{i*a*pd4cm*m4wDc)}~Qi$f$8N196H z_7Wf{pDUaZ$8aU=_7Q3*rh3@exbP(Oz7oB5CyvCIO9r)57R}nhAUB Zd*mJJJI5iZ5g#B=F&DK)ub`0(J_Ys(boEQ1ny`4QbG)<=FFS!6f%&BGnR& zF3tpI!+3)>n)gv@Ww%G{CJ)M(EKiTIGwpxICWS&T%FJ&MnLEnFvoTp*+D{$sz`q=V z5bRrVF5=)g*th0PE_BX>e+EL4;%ho7N(!LRr5mT5GG{mv*{rB?<~#s187CA#LtAvw z wL@YW+(Zj1zH8Ir(4y|wdOqYmsoxQHg7T}F@n93P@V3V0HZ>7K#=|(ui zI>y|BnDHD~QTE6P7gzYD+YUcv<)n&R^`Rmw1^&CFb*YuWe<|*wDh0(pv1VOI_Gz2I z$WxEYUvZQVr}*5a7=vpAabZXMdD^-J=)Buvek^yZjSmhTDRJSzF05j!yfrw8K%A|I z=&FN=FM}k*CVhfE6mLlic5m{CW#57h#QY_i|8K~rlAq~0{(*cI=4Sm7Dg<^t%${D? z#f(fjFT*!>vs{-%%U8yQaweZUigtc^*D5P!uJ=6_T|W1{cUAU^DvY+{Rq~jKMN|JN zEjs~LJ_p+4Q2^Yd0Mg}~AGL}I1}+CQ;0_{P5n-f{QUpt6V}LJ!?5t-8)gaS;IRntu z5uM6P&u_({%^aDTNZ@W);%+d&IlHRz+4!?<+L<^$5` Vu3%MzuM#RXz!FP z*%aAS_aE<_p74V?w=2dYB3ynq8Shhf;>n&&qxdCgMPivwVB`RXcfJdfB03L0R+P-( zoy}Ksa~%VJXx_T4nS1#Oub5o0Z5-CP^6jwyWtWIU2Nwc|tcCnH0bi1qDSHzGrbFB@ z-)s8$>@+w*Y^qK_0ofNxbx#h73PcCdzw4r7J|K5ZMluuNSly#dgO0Ra-J6agG&tun z!Jbk!tU2xz`e^^WIuXtzhgf}-rV^_GiK;jDgQy0)sTyD_E#K;QNtF!TCeH@=@G0So zbm&%;+^MI&bE+1xzIE5EdlrdU*CaBXS=Id3tR|^66zgLyt6J1b>VZeGr59WoO)_Uy z)j_!PpLugZWxn06JwvjdKmJ_xIdroexbYe^BF=CCK7zND-$AH3e2)AQQ=B3btv 86{*XVyDsktZIiE`^6O#Magmj3 z1si OUHiDK48TOn80 S~;KUFzvgUy$~h_!IS2|ptRinycfYzqxslf zsS(vq#RMo*eGyS7K7;s1mG(|wvR@fj+c-SsR!khcI@rlH$IyNq@TQHWF#40D$uYft zy|}|ueP_|7Sc)#82S?UT8o180OxF)d7 ~vk26coa6aJ9ygBXpVB_Ann*@|YDz6xIqVJ7o`8#fOn$U*)fuuInCimoU z%<|v6GTYD>-qbeXU#u-ZzNVZzw@$1E{Pi!^fUw*qo>iA5TTiU7fBdxT3A04*`YPvH z?as~0^akm!<{Y!e+w@s5{Z0SPe5-NtukYqtM?|KjAAg?O!VEx@IX8g^4)OyDemG?K zjr{(pREUz-88xmMHO?q~c(&%5Wf|9*-T(TjfP1|$p5BKX%?mtXf~x!Ts`r3Y=-iA< zE;MruA^D=dol_k?aXBVFMmI$&mj)gW-`#o>-(i^o-kolIH!{kbYq^SSdBAjEM7K30 zT>6#)A9?t)?9B6f+lGnfdE#Yc1&J7TIJ0b+{I%sOlGb^admR$S|N13JW|P2ZICLhl z4C$6(_7&JrE5JsQf2GJ}*u1yiybO@Bvg_Oo1A%orvXyABAPS*1`y1*39sGDhmqnje z1PJcoGgb{G&U4}?%wT7a2#&qOpYngmGN*9kcpI7%m>jd61}R0RXHzJvF*~^uZD=^T zlBHDyx$sn}JSJ=Tm Bi zy$wFewtXCdx9}FlIh|55TbAn}>LpmOG!uP~9?tEkj9ZZHBh^3tOx1 u(TyoNndWPS`n!&O}$6H!869(|AD)SIy1Z)gP@;~uEf U;_1ZZ>@rNHf(dKHZGMiw` zTvLNpnGJEU6TfU=wvTjApIIzYo^N^h)G8o~Ax}$cUMTR?>hl}d{_3gK%B7VYW(2^= z0ULb2^|T||H1wOucISj2VYf1PPNaJ3m>Q0)@P9sE)DWx3+?zf*H)=vVN8{WT;_S$S zbK`jpCf##GV@rvE{a?%(_GwKQXXC$22J2L%;|!T@7SiVE!FAaE?*$KZs0ilXvEtE& z2M!fb;Lz8zRA5 )HncXmL)&(&j8BZVgq+1EC;Dc0=Li2v zkgfQ>_J9;PVVS6=-#tDa9fAwZ=tiZp<{>ka&R{)DJlU^!oie{Dqd={`$_j{Nbkd1j z_wAv>|B&=gTb(VW+1MS!k>JfbnH(_NhLR0F(`30QU-dU&*$3z%5&)Brg84|7rS6x) z1{6^&=PULZDi&Vz=csH%im`8D;qBZx97V_6!QYtBnXHs4;*ZvQn#SCGfnU8S;uuen z`f+*y5;^)yTUQ{fqI{CG;8X5 o* 0S6;K+h)%Zq@tN zdwb7XP-SAV*3V$^h)($emW|vHQE4+i$1430lqPdu*yN?d_+oHQ9%XT;Em+_D8Q>ia z-=Hq@xlDn2$I^K)-7b)Qb+ogcWi+E7#z$ltmFNY2F=88r3b #o4tp}Pfn~|Q_n+`DUQF|pD+PL-ZE!RJbt2#R|Z`(;QpjHWm#5) zw$9Ns_D(;4Nj@ig!syU!uN@llj^kBO%PyHspx?my2L&*QcTbKTT%SBWCd;3O?#r9a zRiW3iK}XdGZ<>7@z8JG}1Ta!{>#ff0RtWZ3Mmz2mQ3&)!fAU&q 7v`|Xww?s0_?WcAWZxSIw#gk z0t>CPKs-F5=AEKU=^fD7Rb;LqKaA{M@ *J?DqT2O-!$^CCmgJnTU>= IfZkXS{mZEM%lOM 9^njs6PM1ikv^=GUjQPw-9A n->62#Z~zpo)wAn&{8{n@R4XB2x(>g%-$vKtt_7Vc zM%8i{T}!B=pGQoJ_W5JAI#XD6l^0~pU}SgZU-usUn>ph9A~?=q9kIe}c?}Jt2I@*w z(zisCva4(n6zMe25i}m*PBdk@ckNA2ME&bC*6-OwkLLsznwAd3y9VnVHHXEoZqKa_ zuanKr+^Pr(OS(6wN~rBdXyMrJ e2L=Y)%Ig+v)e)`Bmd|D&CqKzSF( Skq5Zs&eEa^;5 zd0SL4eQFhi-o6m0U#TuIJ%8sqU3UMkzf}ERTjMOvNnIoV&+~=9oeeVK^m*W^B|6PX zY*|mALON@bseor*;`cqk;xKfkkH7-ofxm{C@U7W1cuY?Wj|uQ4>C^U4=Uk^(UO9QZ zx5w4uLppAhfsxIKU3)$`;paBgC3b&&Jo)pJYoc}k`J7wlm^Kb^uP)D;jk3=B-B_D0 ziT3`Rr{7+02m5M)2jnh5BdqjXiCIE5m-BRkQ}lOh@#nAR36NnYbFU*J%IbgfvsLI! z5EOUE;mr{ni`&Ne!_W97?iS3Op~lH{^yq2TDNe(kmHq{;^c=>=C|jD-G5XuNRqwW~ z{%@Zaek>_#?w|Ah)52E)RY->3n`3nkjz@=k56Al+Ve({-RV9p#oM)%Ps+HFxR=EE0 z9ILbKyVi_si6Uu323a(ZId %fvx0=$WapeP zZnoS%H|m4Yv2(TTpBp(WP_~2uW&irzbv>G#oeJisx+yNTFV)QExmy)-Le)GcxaG@K z#elJVnLJbVj}}yXFQ$ajnaTn;yoU;*H3eX;@3|<|QeWf0p<8*ixfP@2h9Hj2e z41gs7=E^N56`FT>P{E8GED33}+g5uv)NqHb2Xh4tJA^o!sV0v(Buf)0OeQMoj=REU zQsX0`y)i4)VJ4N%n@0SfxBg?bj!x%UztEG9AD=MKHX^ ekI*J%g7 zzX{5lcLH2w@6bgy{CDDILK*Sdh~L9fxK`lzuo%}BnC_NlmQL*%)RW8na7-gJB)9qw zzKL;TWw_gzxF8;+h{N8CFX`HJ5B*9!gkFcp?O mj3Y1)d` W^1C8rkx8s%9-N!dBB~14b5{PI?b7ta{%IxJ#-_@?VP#jOfcdZzodtt zZt&kf74Wbl)%$U3jCuCw{-&X?hS)vtKL*>L19pU^`leAusJiIx0drL*fp9Bv|8RbY zUgMy<0&WU-wP}2=HYK!!ZJetzr&aG?%@HzTr_SE!TLxsL(&L_?mn4kZiWl?~ORsPw z*IA2M91k=NZ*-{~UqCe6dXPm!)}66S%d#N+5bqt|DjI%=b-EyPT#M_i+}By_B-Wnn zA0W#Zz?U6?QyTd)V%IpWyfTjTXFwA{vz#OBADj~hE>uT$?H 0A!IxWRI(a z(FW;9Myo -m`^tA`$ zQ}T~g;emWc5XC*;$T;dSL{Mcp75RvC9^^0~?Go}4i)vLj z_e~EZBYT4rx}wslP(bS${Xpt@G?w@3%Errp?vN}!X8Ku)$XY%Z#6^OL6AS4LCGT3J ze>XM(-Uuvjj*+c9kJvt<_bxSAK;NR)_hUE4r9@hnG8$YU8M1HreQF>%68_1eD=~_O zN&4j&^c`=?LD1$O3?P1R56|uW_L_LHiS$9*5uhkP<@6jaXpheq9a)8Svyd-mM`q~A z3x5V4IyT)mM`UV4DWSjy$de8E+V@2ACTsW_nMdD~|AKoRN >(vL~_< z2AlXPaozBno!2Wk8e*<8GgR{LpQ{z#;~U=hGqmSFbG7IE4bTRX0FQ=jnZqy{5!(76 zJf)V-t9}2Er_(;~P~rvV((N6sIcHtsQ~%qa`BULuWql~Cx-kndPnxK{LR14xT0j3c zx{P6(eg5Uo+$LIr$>6}N;-9 ior*9#qzs~sX7g!I z|1Bpt%{pY@^E7xeyU^5MMJl~oZOXR)9S1z4<6KGX6>hFXO5ActV_X?kEV-J^1zCCR zmKMx3OFIeKtyELO@(M7EeJ)%=EEp0ZwZ4%q3Tw~5vf5+zWG+2DPURQLc+dga*5)3N zgUX%bky!x(77l5rcog}{N%QDvaxHzwoH&^jFE7`PX!OI#Mmtxrkz&s=Q9VM|cTcZA zhtlx<)2q$Je*T-;s`DPdM)hg*zUr($QBC60{!dT+(?a*rIer-0NDrU-XSwFd|7G@C zV~hK9nk$KFI{z|A@Og8XFA3`LYNt=*(_C}r|9-xjozYoTB6xaJCuwEkL;t&<^F!w_ ziIP<%KJv-W`H`;aboZ%_;qWPT-Qejlt~*bQZNzNzEE{voHYeX2|CS$^nlmvm6>30?iQ3# zOXWYCW0Rm;F6qGW;dr8*aQA0y;6I7kz+A}TM0B@7qeIMw{U`HnSgg*Qp_%qkM^qZf zr@_zv^SQPnhAVi%bOM)7>G9foHcNY5BMtAM<6OcqhM)m{f%WI9Uv|KMe_joUJ|K*2 z%iIPd>HHD(|Chg1{hs;z^hWS$Nl U@zm+ib3L3=(w!M(m4sye(BEo8 zB!?Itm{Z(@BGYI)?A$$`L@?oL+^8FaaFQ2el@s;<)h|`Q;rsfRPp=)^86id+{_Zc? z2J?dGe|rv%i7#5j>7KvkZ;|>2+Bohs6X6+D2(l%3?t`k 24xvHLetDZj1s_hYo!JeK +{Xl!L|<#&9F5T*mEn<{54u0z0o^y@#$sk0QhqYbBb%Y$F<^ zMl?MfY#y@{;$>G!h9{F_O!hcZUL#$JLbAqp7gIP7z(O6#SwLK59+q42t1&}VSOo&+ z{~Qgo?X@6?4FE*Z* X=CTBeowwux6e#-HIV|X*FF|XKN?lT34 zgyPK}@KA(!qVIKIk`D_DiCPLJ_HQVw;dDxF^#ZITfSGklkk#cJaHv0faiQW`M+EL~ zXTVKh=rH{;MJ?H2TSoG1r=4qo56n)$7m~RS*s=@RVf3ypV)GWr-vVVD>fTU#lL-5n z&NVWHMyAwQq%Ua8=`9>Ch9SVm7@P) 2*MV(luy${%?b7v+3GJWiUtsV zz+DMK_Tjow8P&LAtOy~;3a?pk8886z?do A1jp&*k-b#Mrz7%#SGQ60h4 zI+x!=0gyTy6jJT7qNQ=rHYqhB2q7zzdN_SF6}u %I3vSQNlR3)Jn5f(JUM1Z 7v0(f)t0dE#gR>JO7#(+9`e8Zg&LJf$^Tj{ z $Ekoy6_`S=75&Q_k5e+vo+iYS13o9A7hT&(w^t5Bsm?hX}F_+4hGV z6l&4H>;4ZBXRLWrou%EzoE1=`IY7mlM6ouecon%d1#S_M)%}Y(RG0aAmRE9C>T9aA zmf5D*OpDEG)PsZR-XG>T( e 8Q8Nq)hX8qH- zn&)50dFL^LSi#or)=Jz8hrlA0ge1DE&>~b`R5ESU0->`A_U|Zaf$Sx&(KCOwx}&ri znb-^aP(9VE97^lyQ><23hI58UXSp?3-DVnu=o2!5R*HjWZ9U-Pg-Gh~bAFd`&a{o$ zQelW;FoTKpL=G{we~f5C4CU#_f;3@deKA@2`{vP5NO@|IcD &Tw z>?oe#3$Gw@AkTO|@w$t`)j&KezeHqW026l2M*t(FOTLIGmPNNe 11zokV-ceLtbvlm;Zpgl=tm~hN8~yhR!}0T&EKia(WiCNwYWTc;al1 zsQ>T%QuVvL;~m%>I{@wxdL85Tg+$F|iK#(jLn@7R$=)n+3m`N>S31>x`?G%?t&HkV zc3m%{x}@{Q4u1M{KJ( x$MmP VU>3q*DweU*yU`*?~DI zM@WR_>Vy^@iO^RhQ+#>|Cf&BOvH04*8W@?0NryA@3&>V)gck_-8in`Fi=Z~OQhEs} zp$uWHD#!9SQf(lrkpfX(aiO4=8B|bZdMlTySnjh!cnO<%-aRr}64a