From fc86790b9d23fe3bb460c563d5e494cd1b62d3bf Mon Sep 17 00:00:00 2001 From: spegg Date: Mon, 4 Feb 2019 10:50:05 +0000 Subject: [PATCH] cpdist integrated into model --- Parses.R | 14 ++ app.R | 366 +++++++++++++++++++++++------------ data/WorkingTestHabitat.xlsx | Bin 18732 -> 16844 bytes 3 files changed, 260 insertions(+), 120 deletions(-) diff --git a/Parses.R b/Parses.R index 312582d..c71bfc5 100644 --- a/Parses.R +++ b/Parses.R @@ -30,6 +30,20 @@ delNA <- function(vec) { return(vec[!is.na(vec)]) } +buildExpr <- function(pressStatus) { + #pressStatus is a two column DF of name of pressure and status Ii.e. on or off) + MEANPRESS = 0 + expr <- "(" + for (p in 1:nrow(pressStatus)) { + if (pressStatus$status[p] == 'On') symbol='>=' else symbol='<=' + expr <- paste0(expr, "(\"", pressStatus$code[p], "\"", symbol, MEANPRESS, ") & ") + } + expr<-substr(expr, 1, nchar(expr)-2) + expr<-paste0(expr, ')') + + return(expr) +} + parseScenario <- function(press, prefix = 'p') { pressNames <- colnames(press)[2:length(colnames(press))] coefs <- matrix(data=NA, nrow=length(pressNames), ncol=2, dimnames=list(NULL, c('growth', 'confidence'))) diff --git a/app.R b/app.R index c36f58c..0ac85d8 100644 --- a/app.R +++ b/app.R @@ -3,6 +3,7 @@ modules::import(shiny) modules::import(shinyBS) modules::import(shinyjs) modules::import(shinydashboard) +modules::import(shinydashboardPlus) modules::import(htmltools) modules::import(DiagrammeR) modules::import(magrittr) @@ -12,7 +13,6 @@ modules::import(Rgraphviz) modules::import(knitr) modules::import(shinycssloaders) modules::import(googleway) -modules::import(Rgraphviz) modules::import(bnlearn) parser <- modules::use('Parses.R') @@ -21,13 +21,21 @@ layers <- c("Pressures to Bio-Assemblages", "Bio-Assemblages to Output Processes transitions <- c("Pressures to Bio-Assemblages", "Pressures to Output Processes", "Pressures to Eco-system services") addResourcePath("js", "./www/js") + + + ui<-dashboardPage( dashboardHeader(title = "JNCC MESO online"), + + #tags$style(.times-circle {color:800000 }), + #tags$style(.check-square {color:008000 }), + dashboardSidebar( sidebarMenu(id = "tabs", menuItem("Pressure Test", tabName = "1", icon = icon("arrow-down")), menuItem("Bayesian Network", tabName = "2", icon = icon("atom")), menuItem("Habitats", tabName = "3", icon = icon("atlas")), + menuItem("Ingestion", tabName = "4", icon = icon("utensils")), selectInput("modelSelect", "Select MESO model", choices=c(""), selected=NULL, multiple=FALSE), selectInput("layerSelect", "Select Transition", choices=transitions, @@ -37,56 +45,54 @@ ui<-dashboardPage( dashboardBody( tabItems( tabItem(tabName = "1", - fluidRow( - column(width=2, - h4('Pressure Test'), - radioButtons("pressure1", 'Sediment type', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure2", 'Seabed type', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure3", 'Material extraction', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure4", 'Abrasion of seabed', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure5", 'Penetration of seabed', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure6", 'Siltation', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure7", 'Wave exposure', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure8", 'Suspended sediment', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure9", 'Generic contamination', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure10", 'Deoxygenation', choices=c('On', 'Off'), inline=TRUE), - radioButtons("pressure11", 'Removal of target species', choices=c('On', 'Off'), inline=TRUE), - actionButton("calcAB", "Calc") - ), - column(width=10, - h4('Effect on bio-assemblage'), - plotlyOutput("layer1", height="270px") %>% withSpinner(), - h4('Effect on Output Processes'), - plotlyOutput("layer2", height="270px") %>% withSpinner(), - h4('Effect on Eco-system services'), - plotlyOutput("layer3", height="270px") %>% withSpinner() - ) - ) + fluidRow( + column(width=2, + h4('Pressure Test'), + uiOutput("pressureList"), + actionButton("calcAB", icon('calculator')) + ), + column(width=10, + h4('Effect on bio-assemblage'), + plotlyOutput("layer1", height="270px") %>% withSpinner(), + h4('Effect on Output Processes'), + plotlyOutput("layer2", height="270px") %>% withSpinner(), + h4('Effect on Eco-system services'), + plotlyOutput("layer3", height="270px") %>% withSpinner() + ) + ) ), tabItem(tabName = "2",h4("Bayesian Network"), - fluidPage( - fluidRow( - plotOutput("bbnGraphPlot") + fluidPage( + fluidRow( + plotOutput("bbnGraphPlot") + ), + fluidRow( + column( + width=6, + h4('Ecoservice nodes'), + DT::dataTableOutput('nodeTable') ), - fluidRow( - column( - width=6, - h4('Ecoservice nodes'), - DT::dataTableOutput('nodeTable') - ), - column( - width=6, - h4('Ecoservice influences'), - DT::dataTableOutput('edgeTable') - ) + column( + width=6, + h4('Ecoservice influences'), + DT::dataTableOutput('edgeTable') ) ) + ) ), tabItem(tabName = "3",h4("Habitats"), fluidPage( google_mapOutput(outputId = "map", width = "100%", height = "750px") ) - ) + ), + tabItem(tabName = "4",h4("Ingestion"), + fluidPage( + p("Select a spreadsheet from your network for input into the JNCC Bayesian Network Analyser:"), + fileInput("fileSelect", "Choose Excel Spreadsheet File (xlsx format)", multiple = FALSE, accept = "xlsx"), + fluidRow(renderUI('status')), + actionButton('loadAB', 'Load') # icon='upload') + ) + ) ) ) ) @@ -100,6 +106,30 @@ server <- function(input, output, session) { dataStorage <- 'data/' models<-NULL + pressures <- NULL + + #disable(input$loadAb) + + .loadStatus <- reactiveValues( + valid = c(p=FALSE, ba=FALSE, op=FALSE, es=FALSE), + msgs = NULL + ) + + .likelihoods <-reactiveValues( + p_ba = NULL, + ba_os = NULL, + os_es = NULL + ) + + setPressures <- function(newPressures) { + pressures <<- newPressures + } + + validateSheets <- function() { + req(inputs$selectFile) + + ##TO DO - run parser on it and output the errors to + } getAvailableModels <- function() { fileList <- list.files(dataStorage, pattern='.xlsx') @@ -114,14 +144,11 @@ server <- function(input, output, session) { if (!is.null(tmp)) { modelList[[cnt]] <- tmp - - #tidy up the list for displaying - + models <<- c(models, substr(fileList[idx], 1, (nchar(fileList[idx])-5))) print(paste('Model file successfully loaded', fileList[idx])) cnt=cnt+1 - - + } } @@ -133,91 +160,172 @@ server <- function(input, output, session) { .selections <- reactiveValues(model=1, layer=1) - #parse on load sheets in the input sheet folder + #parse on load sheets in the input sheet folder - replace with R Data modelList <- getAvailableModels() - calcLikelihood <- function(layer) { + calcLikelihood <- function(layer, pressStatus) { - isolate({ - if (layer==1) layerStr='ba' else if (layer==2) layerStr='op' else layerStr ='es' - nodeList <- modelList[[.selections$model]][[.selections$layer]]$nodes - str(nodeList) - nodeNames <- nodeList$name[startsWith(nodeList$code, layerStr)] - mean = runif(length(nodeNames), min=-1, max=1) - sd = runif(length(nodeNames), min=-0.25, max=0.25) - - df <- data.frame( - nodeNames = nodeNames, - range = c((mean - (3*sd)), (mean - (2*sd)), (mean - sd), mean, - (mean + sd), (mean + (2*sd)), (mean + (3*sd))), - stringsAsFactors=FALSE - ) - print(df) - }) - return( - df - ) - # isolate({ - # - # if (layer==1) layerStr='ba' else if (layer==2) layerStr='op' else if (layer==3) layerStr='es' - # - # layerRange <- which(startsWith(modelList[[.selections$model]][[layer]]$nodes, layerStr)) - # distList <- modelList[[.selections$model]][[layer]]$summDist[,layerRange] - # nodeNames <- modelList[[.selections$model]][[layer]]$nodes$name[layerRange] - # - # } - - # print(paste('Length of layer & node names',layer, length(nodeNames))) - # - # distList <- modelList[[.selections$model]][[layer]]$summDist - # colNames <- c('min', 'q1', 'q1', 'mean', 'q3', 'q3', 'max') - # distM <- matrix(data=NA, nrow=ncol(distList), ncol=length(colNames)) - # - # print(paste('Length of distributions',nrow(distM))) - - # for (col in 1:ncol(distList)) { - # valsAsStrs <- unlist(strsplit(distList[,col], ":")) - # valIdxs <- seq(from=2, to=length(valsAsStrs), by=2) - # distVals <- as.numeric(valsAsStrs[valIdxs]) - # distM[col,] <- c(distVals[1], distVals[2], distVals[2], distVals[4], distVals[5], distVals[5], distVals[6]) - # } - # }) - # - # df <- data.frame( - # nodeNames = nodeNames, - # dist = distM, - # stringsAsFactors=FALSE - # ) - # print(df) + # isolate({ + # if (layer==1) layerStr='ba' else if (layer==2) layerStr='op' else layerStr ='es' + # nodeList <- modelList[[.selections$model]][[.selections$layer]]$nodes + # str(nodeList) + # nodeNames <- nodeList$name[startsWith(nodeList$code, layerStr)] + # mean = runif(length(nodeNames), min=-1, max=1) + # sd = runif(length(nodeNames), min=-0.25, max=0.25) # + # df <- data.frame( + # nodeNames = nodeNames, + # range = c((mean - (3*sd)), (mean - (2*sd)), (mean - sd), mean, + # (mean + sd), (mean + (2*sd)), (mean + (3*sd))), + # stringsAsFactors=FALSE + # ) + # print(df) + # }) # return( - # df - # ) + # df + # ) + isolate({ + + if (layer==1) layerStr='ba' else if (layer==2) layerStr='op' else if (layer==3) layerStr='es' + + layerRange <- which(startsWith(modelList[[.selections$model]][[layer]]$nodes$code, layerStr)) + + nodeCodes <- modelList[[.selections$model]][[layer]]$nodes$code[layerRange] + nodeNames <- modelList[[.selections$model]][[layer]]$nodes$name[layerRange] + + MEANPOS=1 + MEANNEG=0 + + # expr <- "(" + # for (p in 1:nrow(pressStatus)) { + # if (pressStatus$status[p] == 'On') { + # threshold = MEANPOS + # } else { + # threshold = MEANNEG + # } + # + # expr <- paste0(expr, "(\"", pressStatus$code[p], "\">=", threshold, ") & ") + # } + # expr <-substr(expr, 1, nchar(expr)-2) + # expr<-paste0(expr, ')') + # + # print(expr) + + expr <- "list(" + for (p in 1:nrow(pressStatus)) { + if (pressStatus$status[p] == 'On') { + threshold = MEANPOS + } else { + threshold = MEANNEG + } + + expr <- paste0(expr, "\"", pressStatus$code[p], "\"=", threshold, ", ") + } + expr <-substr(expr, 1, nchar(expr)-2) + expr<-paste0(expr, ')') + + print(expr) + + #txtStringWkg = "((\"p1\">=0.5) & (\"p10\">=0.5) & (\"p2\">=0.5))" + + print(bnlearn::nodes(modelList[[.selections$model]][[layer]]$cfit)) + + sampleDists <- cpdist( + fitted = modelList[[.selections$model]][[layer]]$cfit, + nodes = bnlearn::nodes(modelList[[.selections$model]][[layer]]$cfit), + #evidence = eval(parse(text = expr)), + evidence = eval(parse(text = expr)), + method = "lw", + n = 10000, + debug=TRUE + ) + }) + + #print (sum(res[, 1] * attr(res, "weights")) / sum(attr(res, "weights"))) + + print("Sample dists") + print(sampleDists) + + print("Weights") + print(unique(attr(sampleDists, "weights"))) + displayCols <- match(nodeCodes, colnames(sampleDists)) + sampleDists <- sampleDists[,displayCols] + means <- apply(sampleDists, 2, mean) + stdDev <- apply(sampleDists, 2, sd) + + print(modelList[[.selections$model]][[layer]]$nodes$name) + + return(data.frame( + nodeNames = nodeNames, + range = c( + apply(sampleDists, 2, min), + means - 2*stdDev, + means - stdDev, + means, + means + stdDev, + means + 2*stdDev, + apply(sampleDists, 2, max) + ), + stringsAsFactors=FALSE + )) + } + + renderStatus <- function(layer) { + isolate({ + if (.loadStatus$valid[layer]) return('check-square') else return('times-circle') + }) } + output$status <- renderUI({ + + tagList( + fluidRow( + column(width=3, h4('Pressures')), + column(width=3, h4('Bio-assemblages')), + column(width=3, h4('Output processes')), + column(width=3, h4('Eco-system services')) + ), + fluidRow( + column(width=3, icon(renderStatus(1))), + column(width=3, icon(renderStatus(2))), + column(width=3, icon(renderStatus(3))), + column(width=3, icon(renderStatus(4))) + )#, + #fluidRow( + # verbatimTextOutput("msgBoard", .loadStatus$msg, placeholder=TRUE) + #) + ) + }) - .likelihoods <-reactiveValues( - p_ba = calcLikelihood(1), - ba_os = calcLikelihood(2), - os_es = calcLikelihood(3) - ) + + observeEvent(input$loadAB, { + #TO DO get spreadsheet + #copy validated sheet into the data folder and either add or replace the sheet in the RData file + #reload the RData file + print('Load button pressed') + }) observeEvent(input$modelSelect, { .selections$model <<- match(input$modelSelect, models) - #print(.selections$model) }) observeEvent(input$layerSelect, { .selections$layer <<- match(input$layerSelect, transitions) - #print(.selections$layer) }) + observeEvent(input$calcAB, { - #print(paste('Action button pressed', input$calcAB)) + #get the status of action buttons + isolate(myList <- reactiveValuesToList(input)) + matches <- match(pressures$code, names(myList)) + status <-NULL + for (n in 1:length(matches)) status[n] = myList[[matches[n]]] - .likelihoods$p_ba <<- calcLikelihood(1) - .likelihoods$ba_os <<- calcLikelihood(2) - .likelihoods$os_es <<- calcLikelihood(3) + pressStatus <- data.frame(code=pressures$code, status=status, stringsAsFactors = FALSE) + + .likelihoods$p_ba <<- calcLikelihood(1, pressStatus) + .likelihoods$ba_os <<- calcLikelihood(2, pressStatus) + .likelihoods$os_es <<- calcLikelihood(3, pressStatus) }) @@ -225,19 +333,32 @@ server <- function(input, output, session) { google_map(location = c(55, 0), zoom = 7) }) - + makeRadioButtons <- function(row) { + radioButtons(row['code'], row['name'], choices=c('Off', 'On'), selected='Off', inline=TRUE) + } + + output$pressureList <- renderUI({ + #isolate({ + if (!is.null(modelList[[.selections$model]][[1]]$nodes)) { + pressCodes <- which(startsWith(modelList[[.selections$model]][[1]]$nodes$code, 'p')) + pressures <- data.frame(code = modelList[[.selections$model]][[1]]$nodes$code[pressCodes], + name = modelList[[.selections$model]][[1]]$nodes$name[pressCodes], stringsAsFactors=FALSE) + setPressures(pressures) + btnList <- apply(pressures, 1, makeRadioButtons) + } + }) output$nodeTable <- DT::renderDataTable( modelList[[.selections$model]][[.selections$layer]]$nodes, - selection = 'single',options = list(searching = TRUE, pageLength = 10),server = TRUE, escape = FALSE,rownames= TRUE + selection = 'single',options = list(searching = TRUE, pageLength = 10, editable=TRUE),server = TRUE, escape = FALSE,rownames= TRUE ) output$edgeTable <- DT::renderDataTable( modelList[[.selections$model]][[.selections$layer]]$edges, - selection = 'single',options = list(searching = TRUE, pageLength = 10),server = TRUE, escape = FALSE,rownames= TRUE + selection = 'single',options = list(searching = TRUE, pageLength = 10, editable=TRUE),server = TRUE, escape = FALSE,rownames= TRUE ) output$bbnGraphPlot <- renderPlot({ @@ -245,21 +366,26 @@ server <- function(input, output, session) { }) output$layer1 <- renderPlotly({ - plot_ly(.likelihoods$p_ba, y = ~range, color = ~nodeNames, type = "box") + plot_ly(.likelihoods$p_ba, y = ~range, color = ~nodeNames, type = "box") %>% + layout(xaxis = list(zerolinewidth=2)) #%>% + #withSpinner() + }) output$layer2 <- renderPlotly({ - #print(.likelihoods) - if (.selections$layer>1) { - plot_ly(.likelihoods$ba_os, y = ~range, color = ~nodeNames, type = "box") + plot_ly(.likelihoods$ba_os, y = ~range, color = ~nodeNames, type = "box") %>% + layout(xaxis = list(zerolinewidth=2)) #%>% + #withSpinner() } }) output$layer3 <- renderPlotly({ if (.selections$layer>2) { - plot_ly(.likelihoods$os_es, y = ~range, color = ~nodeNames, type = "box") + plot_ly(.likelihoods$os_es, y = ~range, color = ~nodeNames, type = "box") %>% + layout(xaxis = list(zerolinewidth=2)) #%>% + #withSpinner() } }) } diff --git a/data/WorkingTestHabitat.xlsx b/data/WorkingTestHabitat.xlsx index 702d6e9e376174c8307b929404d02a65490f139a..d62c03148fa19fb7e4ac061619f11cdc302b5536 100644 GIT binary patch literal 16844 zcmbWe1yo(h(l!i9fMCHTNN^4APH+wy+}+*X65QqB9^BnM1U(QSxI=Jv_YabpJIT!4 z`>+3P);b*6UDZ`j)$XpUz3aXB^B1UKFJHa{!xa&f0{dlPJ$`pKr`57GFt?+1va&VP zwX!m!aken0dHPRF^pI%>9bCYH2Taz@GVxv?rj6@sAI-Xb@X)Nzj35i*1L;N2H`r=0 zB)jiz8Gw5S7r5D`7xb@|;e*@`P*GK0Jxe{3Jm7$!4d_YcoEk6MhK9l&MXB}Bj=E=4 z)YgN$kgcp>GaYn)7jLO5ofTe?Ed^;2-YB55ex*1P1Ag{eZWkM(+6o3SK<@KHxyS4| zBwn)%?r;|@5^%-jos^&?t}w)+LmV4EZBP7UsMm$PehB6RoTnOKe}{Zse*(5Y#*QJ` z&tSrip$@j+d|kg*30I{EI(b9XMtf91QIJ ze}xP6CtP;MI<^M-a`v_+mPU3@XyqtNTFtT{wj7k<+s`~J*vp=hl$oNrj&gj?Wb)0h z!blZMO^^b(7U_6)~m=U1wdlRb65Wr})K5$5XGU=46pcZW2tR|lqt&-C_-b!y- zm4DxIcX(@%!)7vRyn{WE7K_ROkmG@`P&Z?d?e8iyU|jV!l^n|gZ9XS|$G19occD0w zhWWi`Nxc&_Llc3>Ve~#VR5gQdH!1b2L*5pW4=`zVT!y{|o(w+7@IV)>Q2KQ|aQY-H zbsKaR%(3=NWhZ%{Jv43%JH;Gec|sJm#!47pkyb=oJWSy0sOeC#F6{F?17^C9`c1r8 zeEE9P#7tpBsoT4dUhl(rb}C)9XqXhw{7MAgK!3EC@8P%$mx z_;;fny-LFn7S4U5{#Y%tnlGR6%$##}Hf!dMU#EvgGdgUhcL`ji+%b3Wp9VRKcvWh) zSSOqoA`a9?qO3%SmFU3fTumKF8oX^Pcjie>>Bs2Th7&icq~Y>bkaFtuvzuly6#|nA zK9Vv~2~+;A_4ko~msi z&8sY&4qR&0aN|I{8Z+plj5M~zsbVT!IjyllFzamX3M=s8CHVDgjumDyJZHiPmF`Z@ z0=PMYrS#`;E?V5VyY2N7mw7T5#~al3)HkO6np=pXJvwq66ZL-21aa%>^hG8J+v7Dp ze;pA@aXAYk=lYgUxBNNkt3gD$5@H6WHgR+)#Q|^8&QRU^Du|Ph(clmV`DM=jgh6dD zoMfL(As9dv40KXYoYEJYW-|LT|bkl`TyN|~K*KB!~gI_*F8Cw ziVq*m8%X{L?a8D@+~bP`=)=7E3`jB$gr%ktNj(^;_vC_FDDgbF8RTva&5*B<-^B2O zyuakefVWYY$GEn>c4CO&2#i?9G=)G)s>bM}Nw-x8;7OSlcqh&-9Bm{{pBHpP9IA9_0X{%T3(I&_7JJwL@R1xh>l=Cq@dLBX?&Fj z^?rcYI|X$@@rGLeobkpHI0NlFDd(!*9fzS$ttJj)tCcAS2i8`ht!;fWr+42z`>FIs zBh(Y&l}<`5G9KNb_%)2{Q7=GD!n&?hPT4$Ja0djb>@}fs+#p@&uXy{pe*1@LRzkm>T z?x}WXbc9T{IKr)$_=PiY#K0=upa;Q+uW`D{C;fbdDC9CqBL(L+v`r!na*JN)zSh|O zC6ql|%BxqNh-ZCoc!=vxkq#W&{Y{S6?X_hT9f9TFhAt0BJ**|%iiD7s>@s(~>GVJc zM{x*l8vzt6J>mB#Zram$JhG6I@6}!Tr_-$r)M%QRNqZaR>S6nAXIvcO7Zx_hs)3WwVm*P1mW)R4};L|aY2lz#qKHwTep zO_a+TPCURRmyd93e2YX?tCf@n{lI3qZzo@fD`Nrc2PpQUWEgpk|F0XFlLdhzif@%kM!WlWI*&o!XBZvf*eSz5qN0=6u<^U7_<=ab-2be|1( z-&lPOF=GKnOH=to!;vxLSVQ$u2_wlcn$fSxSXm~ znTQDDY<#+#`Sj*LRakvvV>O<`W?I-u>PE$M;DQidL(Lx=j4D^1Kn}x~F_?b|D~26( zA`GP~dYuRpGWe5DpNjOlx- zAQ4B7bf^03cVDruD?Y_~2)u<-ZFtuVNOl?xFH0D$a@fcy$wSWa^~)Dy(vA@%qIu;3 zBMeUeQMod$i^RdF`(v60{zCOYzDkeqz~}tLPI8^`0%UkhW)x}FCnY{QF&GUmTD76m>m7bmbSk;w}6X&p9&(|%4=N-() zQrT|LQai~r@Z}!oie-MhzzehldtCdSIsPj|jKGWQm)Nzd7fOvKs{z_y(Z*Adc%%9S zwc#C0`)7i7`XYlni?AIn2`Z7;1JwmJpEGlB-&(@*MFe&dQMwW%Wr%!hpfQ8OYpqBP z>gCrbvPEnNY=$)D7&%LY=O0F*w9zN#AVkU_dYVP%>Bw0A_i15}&vH(&qJl*QvWXZF z69cIPSqPz`LVAfxoSyZX)jeAvsZ-EVYl~tN(knihZdJB#GSs(+xUx~XSSg#34%yTIH|k@rpguumj^2j=Eai5hW2}6W z5i=n!+_McUs}Tv^5oIQ5N^P_#e^C*Ae1>1-C~_EaXpkz`Bzr$q7|0~ZLHIoCKd^9( zsA@--zBTtIVIlkn>Eycss6-7VP&Fmw!L}0glHt`gWurcJlw!s;8NMK-pZD04JU?vk z#-hZ@Wb%xL1ZY-yxf#U&F`sY*aqCe_QbO3MuwK4Z!ee7IYH_V1gT*!KNLfH*SDp}R zA@4ty6j6g!m~qGut9UPz{VyCc#F}X2DNr5F1StvOqr!XN=@V8WP6y%$(hx?}#^qG+ zRL1aE)Cm6@X@O{y=el@?uqu%(l1ZSwAS5A5lwYs#D!wg}OLfhcEDhe=ocD+&NCp3Z zXhwB#xU`=g24eVMTq3Jv4QH=0B};jb;GcX^`y2T7lE3y42UgzbRdk6?Gx9EC$7&v* z+s`i&0iohFTFr6E+K1TsZr>ZobOUFUs?t?}5ZGLFAue){UzVo^7TWn) zaF}}k0=-maCjx^fOh(()IsMFi4MJtVFttJQWev9sHoCv5d#{sk&Q)n{V3k}SoQ?g4 zgUt~?CuIKuId60ov{GeI1fL}(C|V}BpB$KN?lT{bjbEaDh>-T00NOvLyjCYn>TOBO}{ zd~|V#O3D3ow3Gx(V>fiK;H6CfF`AKM;dz+oRIV^G*1L1!bkBxO$cOHt8L?gg^E>-Z z%WM2>o-cFv=NGQyZqU(8!K_XmYo=2Ne#t`3p)Ar)cZ+S94~_d5BUDpVJ_^my2iJ>V zsvl}H*eCn8 zSI!x?UwVdW6@SJlxmrF3F9! zg(|8fTplsto$Hm0b=)>s9HR30P9Mx3U+s$DQUr92`rOR6d#>Ef8pK?@|0+fcjdyT; z5bM*}3T5k7adQf8u{IPHvYgCWQ=B7H@PT2tl9ewESd zzSHXqF%Lg7H}{6X>6f0}DSdQzkC#eIgs|~7mOT5F3Jd)mb!U^#4(2+qc_5n<6hjFP zXr*4=0}-xD+bBpKW9wd9h455c*EH^!iM7>{>+UuCfbth_-t_DQ2$lEcnK1CUU1rQR ze(bV$ZLf1y8Wi(<2Y>RskWI0*`zRd(t>je*aV)2d!~qL=c+nl^bqoGvd^uJ~j>KTb zOl|zVf?>AvaY9Ar*2yA51AU(!ne@3Q>2Xlq7hTnpjG&_1srxkPOTP2b*Gh6*ezZ%J z5wtg4b?&4^9++c|^=$)r)YK2Oq}FKWqg6Q6jwa}34}o#hCj`(#!?v$2v*+VHN`2Z+ zWY&4JB(E3;TG0UHq}8T|OfAS+y01LV<8>EvBJC-OY^xaLxJnrp+Mo|reVgR+q^4|IMPX|Z%4$W^XhR)+ zIOTO%w9Pd4Io;w>X46F%!F%CVYz(~Tn)_&Hj)$_L)_4p>{DRbm@)5)O^ee7kn}aEi zy+U6j?9ew-2^aKWR$|IT&>PT)-Bq6JDGusk-5B)iV%@Cu>XM#eDxou$^f*^0?6`)~ zhBUBu!yWr_eDTL+^(yo1co`|a#jBqeZrG0XPRHBZ5k(0^x1&X*zu_CoN1Gw%Djy2QmgMiA_u-Vjl%n z{Z{#ko_G(RdaCbFF}+6P;xbD|_hdZ-J5x5P7{i7XlBix5=&W#nBANYmtvN&Vqj7-Z z$D*EL+koxng-kj?Ffo9(7-@OElxEG)^Ddx@_Vj=8138b0OVsZ zC}9Lp;YI#fvUNmN;Qaz6;cX1D&NLU1Nj5v+kyEsO)E{h=RAIsU)M7uRGt4XB42oiz zNR0p>LBuM=$*Ym-K#}9viSg!AF-ZsyIqCEb)Oj|EepR6gEjB=>SH3@KHxVWi~F0zoi!PsygzjCi1FH!lP*LkD@{4 zuM{mI(ArVnF<8u#I!kgAnC zzB?9eH7>yoEH#7Tw*~)_?*i@}sqyif`)p)qXzoBAJUWi(ujmVzwe#6)SR(?(5rhZC z5qwvZz}<=CA?N{AazByzk6a9Xn~f3#<^JiZn_)u(mH4^7ez1?O06+(kvJ=OzM%`kK z%Z)fJ@oVRBqf|0L@PPNjyb*=&Mr2U7j?D2$St7sF>c5YKjwUIT~*06)$9(+z}n z`ZVl4JU)Dfct#w?M7H%C*;}KUo!F|rSjNAo{&M)y`Lh{?wVBxLsCD90{YVL*P$l3M zh{T0h%R-~6P@_ykp;QC#54RhiSSy~n%DKFSO#L^)p+`a^1y2mA5m7s!6oV)!i13e_ zr>vGna=bJ?m$D6(?4QoAhLLDG86puIA^{Xminjk1Aom&v@B+t{5AqEki2sFfGQ@Op zM<{kj=-&vT9|?Ws8+`wTu%Qqq<&OK3C5UCZ$HFBfZov){^&$=sA$Mip$SWrI=F9FS z*^UjeM+B=%`N$VZbW$U)@At^0D%Iane6}rVJtMhAb&(gq$ zt#7`fjn$)BpUuz5fs+QXfe06bg=AxO849-;`T*P1Sv@^mGReie-twmha z`N%N}g^X+8x1omswqo17D3j;w95~q)hi;dSNC6iQ5Kj>*vv#(hIt&hTo9W`_R&gbOOQh9^!`)X&&0=7o zr}ErjpJWtiNUd>ANj!-SZJas}9?LzG~ zfmd^_|C6Q2{M8-VeLVWrtKi-9QXZk`1^FfcMNqu-7DG$vNLPr-!lF{YYn-%}lGgFs z{>zY4(grQX0rs(zwXSI1u{?Jk4c0J?iJq^l12{@sw$shuwpJToV^5&qOpk)OW=CrOj?IM zaO^tLaYJ|Pex=l2_I`mz^lr|wCF%Kr*L^jErrX+>c*~x^{5ifwl4^PaM}FC^l|xgy z{_NLgvups~hyizNs_o)7k7Jqkxo&VsRilZ)jninWK_$h7;^uX0@$q=sbY`QQs&|ul zh3I6N)a+n`*nR#`<$XfQY=psCjf!_}>b#EBtMKq-^xFZ(?Y$UN)|{H;5e}~Mi2IN1 z2;;X~elu3hBPx^2wFgqNBp60Q_iPk1jJxamih8UXRmHBJ)@(gN_8p7L*N&deo!7Cf zC(K$z2D6!s^;dBx);7*8ZpMSwoXeHi85hFJv?A&@zOL+FmR{c3`t~E8_anU#`KlFu z$iBR}7WjcETr2z~`||2qU?7o{R(PP+R)TTimjBd^Kw1+=5v~6`TE;>>;qFyC=o{Lw zMvK>-_xruXf!VS!$2(588D52oW~B~+lqG`wLqsd*Kwd6l%s0rd5Q6*zIy(fu9!5IN zNABNr-^XSw)-yEX!FV0i!L+n6B*|&Coris|#I~tyax5igLso}Qd!faTPY{C$2qZ~( zB{eMPwwgAxS)hC;u6BM3?Hb=6MN;}g+MAXj5>YIWxDz>aesuM!S28UNw467zrq1HR zGo`PxEOtnIiTn&Y!&j7_s{N~5k~@=abi_CPqvyBBqAXX&<)F&W*zbTtk{8JQ&{4k1 z-t5~Z$49-AJi^gk2k+v0DnUIyl5u}5gqcDTL-J$N{?;|9SA&;tvg;r=o~&|*%ts^s zACtDWuD2d12|Z5Qj?b&yK~5RXfNZGj#HKnj0MIET_W_?|N;#+UabP>>U>y~asa;PlDDxtS!0>HZF-WcA4o?LI*36c2vhz!lsEy-scTz8* zRei6B44pb^Cb@SfVpXit#A?a++lbB&Ke0>!EpAY8rL7k@&h1EI8KB z#DSn)YQdOYm+^-P?2juLg-lNam!|n$|6)L<{|AGZ;%+HW@RNut1f)L`1Rmn|9R!#^ zR2awb9-ksmrhlQv0P!|kJMg&;!JE#27p810KTyrOW+=ttT%j~nCt)n*@AmscLojH9 zC;i7Ul*gw&D$tixzE(zi_V#B^A@EG}WzZwc`K_k~-BRh>u@82!TXF;*{6BIN9^wza zkuQ-2LbpSJrn}??m?W{GKo}Y1KNJHe_7!|oTVBgnUXM(qYc*frR$esxXAXn_jZZ-Q zXz8qL?@TOCa!N=c5}!=|_r8CVDIRuws^L9724x~Fnk~WKWx~ww4*wWT{~m;ykNEs& z_J)W2j$icA(}d4*c(@(6MbkzCca#M z0u_mf%%>YT?2#xHk-Ejim>QQTMKsFyyQ=&B_O7ScMu}TYmZ@tkRn0DOPD97%Dhs^* z*v2kU)K(d5+||uNwX~yK6^yBdxuXoDCi)!zy1?mM*5N*hyr?bwA9?40B)>4=;C9R% z{c5jj$Pp&-56S<(8UGK-cO~)?x2nI|V@4h^D2mGROHm##nS?c9E0c?`T zQD|r3qhBF}ONVdFYQ&`BDPHByZWe=j%+u$#IN z;=CaAQuk^VpFG%kHKwE!H4bll(ae!2*;G8UXTq$43R*aq zncT8O(zGDeUP{IS$EC^Xo>@ zxUSqNuEZW8_S-Y@M%9Z0tDQHV18&k=&7#M2$*~=t!5cf-?v`l0WD$U)*+S3O%a}XW zFZ)~VcYE4yhj)8a)Nc8uVzkm}``2x7UZM6feq%@vlF=7u!$U1+;^&sJ&plFmb~N0W zXIwa7M+{_5quMNw^v-!e>ryW4eQ&*PJ0E~tvjS;6Z7~9Hz&zbWeIzeWiFHu5s9{f! zhcorM0a=6=dV1AW>qnJi)V9G8)0YNLDy=7Vww+FQ1`Zk<2GP@n+q%H78{;nLZljbF z)U$XycMFqLYFtt)E-ta%Sy=%x9@W0%<8aHg(`FtreOLA>gL$Tf?t_)Ql!dA-#V6$w zu3p@w>n1Lys%;l*hkAN!xtkZuCQ+@il1ifoc8aLe%X$tv+b$~dp#G{dP^FZlhe2UV z$@Zp&TodUlBWLI4*YBbdD zs}Zm?<`&}^Ei@i91{z$NRh6n-XE#qBG}2ZMwu+sn2WI2#S;XV|EO&S?jg#4W0u8i|DJ zCNWluT>UMMRmo-pLoV-Gh8EmhQlljolPSs%_UW3kZOk*JCF&a8QgmFF6`aOPG+Qwh zF9coe&lV0Hc~R?p>P!P?69Ozk9dWW)^+*d7WEi`rx&v1dY#6)cyVRNWs1&|BFm@|; z%`xfW2!%RMhuSF6cNm7|1rI0Dw^9l>4t{+4$awmQqFlF5g<6xCm1Zqj*~+!>&&5NK z6g%i(F_d3SJzMq0RC|qAM4wag@P ztiyLcMo~)R@iAx!B3Dnxf99wMb0z0CTN9CxV-Ci*fGFKdSw{r|TSo=@SoWg<#U$`{# zrQxG@D%Mb)?SCi7ST2}}I^J8!f9DW$Tk4;cnOv)`Sfn#g^F^I7nUjNuZ0jN+h!XOO z>%|_5SY?bPs4JL3v=w{E1hn>&Yt3c^^;m(gQN9Y&oQuooz06Aey6>jDf@Lo>{VK&= zFA6_W$Ky9&u%89gHOy6h-=3@N52(OQug&tr-qOh?e=L*&Wx3ayeTnka&G^w+jL?-o z%8PyU_|a^GWDwbrsLc6^b)^{b{@yNf)TE#yKq3A*{0?jGG251^8rL8x`v%im8p>)a z%4#|aY6=Q!8Vc&2z z62BE10pJwGLLC!mNjj6_OdWf`jw2DS#%7u}SdQz^0R7!fHZt`%f4!Gg;AK|B@mi)yX0vEF}@9m`jx3 zN_evGU;t4QjW`(&EjSrA?EC@*JOsZMyZ;3D<6s+Whr0tvA!a*vD#P$*7R{t)TxyN0SnR#)-2F0wzxaem%+G3Zy>_Goor{ zTe4%tVSHQY)BP;vAHI@ZgZ@2p=b3sr7zWj60OT*v1Age8Sp$Zlf$`lNqFx*PpUja< zAnG?8pC}<1vMc0^oq^!`El=z3YBbP8&EI3FOSCLMrp!`$t)5nz$8lSH1{2OmqGs$8n zji+l46P-WH>%V$WOAYBnQ|Z$+4l~_<`U0^S;1eX1j-9id3aG-r{9UAbka=1iMR25M-kYiNbl za>nAmL7(0(oe{Up*4TT9snV-5i``C)cO|P9crLA?h{OG6m(|iu<4p005`;He2Dn>9 zo=h$QZHINIjks&bt3?Wxg$$i7-3^dh&8CL?&j#Gw6<@a$P9wO?Ur@PedAb7P@cQ1q z9~|MLrhV5^HmBhgyC(D|Psj!4#QD01wtxD7)}&&QwUo7gC5w6{7v#&?@HMyNP&?%bK+!?%K`+++84ewHkIwr;i9#?hAq34)kgR;~(x5xY`C++)wmz zS;w}$JR5Lvk_uGk;MO0^DjLaKt~a!H4C^fBUxg1lOl~%Oh7Qr=KuORuK)oInQ3nFN`mF=3>gGO?EfCtqX1A9GwtBnG z2^eWnNH`YId9FVAH6`&iZwjMji_eGzOnSXVfHFSeYsQKTP~Bc7GkzS4d}oX}I8Va| zQiN#fm1y~Z_kBKo_xv}+%%phJwc)b8`Ih}SFHDgO7)%cf&T9wJzA5K{k*?Hkuz7H1 zNkqcvWZy#xkV1!O(`4yEev!wAVPj5cky0rI>8H@WDpTM?A2=yv>ZpF+N2DvwGotzS zZT9d|0`2e&8T1-f`8WAA#U-aeI7LBrGDQjadVxH(=cvW3YRCI48NU}Q-EiUm+ zk%B1%3b?goQNW;w?${9)JPI>aW6m_HpoK}k+0s>5kaC*4H+3V^e%|qQw{EoV^P5z@ zx;XA776{EGQ8k5P{D9I1!M3KlJ<_y&h!V+aAalPrxlEvcE&FPl2?$&5@-gF*p za}IoS;hA!YQ;6jAPi|13lo;ejKU#!XhbMshoqyzl$sVDuSBT{5$0W$@?NNB3*Ppz= zsm~Dgn6*g(+OQ?l&ctjukkohH@S3%&;4nGoxtzugC zEQjOlJX=fwPeK=;qbD544(eiZG8`nmOI^N8t(4;NGV#cr@qV`=Rl)GsGoEkh&aBUV9B=r?I3yK8EW2*^_4{U*Nlk_6_uekDp z1eHHB@wrj#!tzyvGi|g)8~UL@JAi+3(_0rW(6)#5+YeqvWu=FM<{zgEeWGXhjG67+ zj#u1qkmu3egM0!a(Ft~Z7(0G_3zLUfw3ZZd=T~4P3`N3r&Xyw16Yzr`1to~n@Yv5_r=Q4dZ{n>m%T3D#bnv2$sC1! zNB#1oWL=yeUr+_MQdg>25Lta62&RvzeDf|8zmNq8#r{jR3aw)VhwYJU5Y z$vXtf(-^tI^O7R!6#{<$H&4D7q80OE?E=HuBuQENVRBO@mmiTKi4<`LVUEn7_4!Zu ze_O>4KuJ>bQ|z&BOobv3$)Q4sS!7`5m_7OLcgF{)Pxs-$pz~GSI1OhNFph{ zLddj-kzq*9$3&yDIuoqEG>vEHK#;znqQ~VfH@@H{rWB=;W zkI--R{S2S?m;V!0GB zb6`(Whs4W!+8Y~?#PmhX2=|UBRn+p9a!#1~N`>WCy*9J(RWB(p3y}95V{w3ZuY~d< zZR4gf3RWOiI7X|$<-|j#&8z@}5jdg{B8n!e52X zaLzm&#vIt^jxIMVJ5Rjdl_0TfzvPn6Lz>Q?+$2P#-(*TF#@Q}jlxisDba;KbtMzm! zd(5nI9X@W8;@tmht9(4Q!G3ns{pg}A0k%s$cG3ACxCK*QFwehxnUUKhA=*U1^yV|M zC3a0vR;SPLxgZKMTv%mCxQ(aRy>8BegeBDi9jUlxkb+9kvldc4kG#(Qdm9&8mVr#q zZX`AlSt|ib+X!i~)2~Z>ec5jIkzz2LCz9gB;2V0o`e5Ae0&F!DoEYx)1J`|3c0-YE zj1)7cyk0c>N?MpPTLSQKTzMFml?bB=9DBtivfT67nvvlR{9#-c3_Ke87Y|}yy@sO` zl|+gsSl{nOAFT@~xQprEN=QIyY*@Fo);)zBXh!y>GqQJ+B=QiI*iT2pWz-T2QBAw; zUq^X@$uEg1Y5x&~!N*hOzn>^5k2CbG^xoTAS=-U-IoR1-Sv(aFYeprlyy-BZ4sUoM zws6(n%fo4-GI8#fcgDLZ1vB~7niOHHoX;!yZw~8^&W^_4dhJECBzaB5+GUC{w(EU| zN3m}{B~*^_V1nQ_t7$C&lA#~9XTv7JH3@05$x3sp4U-lYxqE-xR>0r*S^Cl?)iu~ z)Jx~JZ#R74U|>c6vz-y?Hw#$V8a(0eC#xa-g$~u@LW#-)Z~g=IRA|(vb_{?-!tkYH z6Rdn)sR=FIeapNyN^EDH+YmeVMGFc7z2K35V{PbSjiMWXzw#c4AEpP1$*O|dH(ux zwAF`KKKQvL_(SZrGnm(nPQ*t2>Zft8M!^&K7^pDhd>J`Q_}Po9FXU#55LDOsRm8YV z>nZnoH9g8JF(w?i^F>O=&hSPi*H#K~$KwlCV!?o<8^Q^6pOI{bUYE-?guA?+pErU9 zzVbPoK;ZYnG}7t(qQ(-wfPB5h0sT#CtbHHf$hvW+;cI+U(%(v{N8Z(7ULT)W43uu8xJ@H8=qu zm6=oAJIS?Za(e*#n3s6n*+pLQ0cFn5%hTZc#|tG54xUCA((?s3O zIVyYYpgGi83?n!YfQn(y7*izcJ4HU|qljydviMTqcjirww2!M1^*rCbGC1HqPt-Pbc=y$OhOycb{4g)HSA*r1teqXzQvA~{~V?CLkxZGlM zFP_QJkXM2g031QUQ0RpZydl$b(CD3HlcF6D`jHlqql$mrdj!Jk5w8EewWtYLS=t*| z+H1+XSR2@BJfSrZtM%mCU5j_9;#vcW@AN{azqfaakRYW?TF@5j+(j>VAMUl_X37xh zeKxeZ-CU#yEL3l1@>q7hkmIAW&^^QbcGlFjLv=eO&pG&p(>6|IXpphJvS7%D+Yq#19Vt+F1E_ zF2BC?^*fh_SO3c8M=QeLx%~QU?RPF}um6?HkJrWi&gIwI!0%i*i2s$#kEe2f=kjab z_f$vtYka2t50^iy3V$d5H4=JC4gVUH3_pnN{*x&Fo%Gk};3-u4Ybdb(7C8N#@Yh4_ zDR}s6xU>ChDDig&zwWb7XWw7rp8Zz_f1HGWC;xTtdD@Ks8pWKykpHnY|DF2Ro8@=u fC%M4D{$;m%FAni|Ux9(aKmN!*p5yvFPk;SCQ2Na) literal 18732 zcmcJ%1yo$g7A{N(5?q42H11Atf;R315AN=sAi=G15AG1$AqnmThem=s1b6r$Gjk_1 zckcb)yKB8-tpiO}eYNY`CA;?NT?*3Ap)ep`ym$fO5+@)B@k_#c{M*fnNzcL9%8|*{ z*1^)i*4C2I&Dx6b=|8O#l{OtDs4(C8<=@*>RHk=Ekgd|I=9XGtL%hh0z{E$5u5-Up zsnu1EW0=xEG+q<`kbzJgCH#{y%wZc^ZSC$b>hM7eD#y!D<}nN z*caiU&u32_iP?aHfKd34)M5Naouiq)gRzmalY_a9spAuK>FQt`d@fY)Lv_@f3CMCl zvzY-D2$HKFFPM8cjVsig}$^{PD>YLhz>$>tU9kz|BTTVkG^I)ZE$ z7sYgWlXwHIW^wRP_Vw=lYDHpvXo!_aw}!5YXXGS!UH$|o)~_%ktXQ_MJz36h!9l`) zg-`3Y+9fL|pyyMvIB`qt+C%Ks!jFwJ_u4dx z*0c+?MNxTB0LHC>AxoqqvDC5sFR2M)ClF;T|LuQruQUvU{ zT_`jP>CtL2^OLj+UxXTKLtD*bW(c)Dq@Pm15~T}MNEJ1JeaL4Zr#>`5?gfw0-PZ4_tA+Ca%Iqn(G*-Wj#6 zfpj*{Pw(;+b)DNL7dc+{I~#@X%uC_haTqy$O6h~wL6}!?(610sl=%`;mH~CwyJZ6- zKfB9eEZtAc-j^!~RW3X_6=-ydl>=3q~q zg`h!8KUYEf-E!A4^irv45-nYEG0anOwr`lpDA3#438=Bdja5@+J`uW1R1)kOn(go^ zJ+jn)_u4nhxI~BXb<)QjQ~qT*kb#3~P)>WV_6*NLApy&rYV!qy77n6_p-9Pdy@AhP zX+OF!bO6vpY>3bLKc`(6yWp`vox^y9=@BkM!HltBcLdpdI^ilja_F zdF-ohxBu=Yt%24lC`2yiLPlSqUxHe5kGt2JUg%&32e99CLM=tR8>GCHd~(v^fMU zZ@hauB>{su-@_EBSH2#(6n+Bv7t$x54aGCxATGo4ZojlO67x6SRH*lcYF3-xk8UrJ zdBC+n#v2RU&fy8B0L#uVUx7cY4lp_M!hfWG6)#$Ew$Cx0 z$bD7ri_`N%p`g{S!j2{=-pk!zsKZQ0ll~}z#So7+mbZa&pbt*jiVII0;TUT706L-E z6FrhJD{LHwcDGS5xUUCU&^M6bV7TeS7TpW_J%mgpgVc476Xg1m@7D+@u+v;b+H`^1H^HfE%jkHx ziI?Cx%53$M!VJ>D07tm8lHq1lG&%P1a&W!{zMGA z_6J+dTWY235;2l-LRMSC7s<$zJX(XBn;Hyp%M4%fFW7M2Box21q))+*Lo4*s zquITpmB&3Gpo>TTE|8sDC7s2uFc|uLkHo8rhKT4#B!M@#*1CqPTfDRwE*agRaO0Y~ zDN9=R12y+mAKM9L2B(TqPT*lB=)|^QErL~O@q5a!dsG3(&V?v+r2x_`0y1ona!_c0 z^LtjrXyHBAk6ABB+JV*9e);sx1s+izLeUDL;z4houZv9IM5!EuQYDKiWolS@@M`1| zjl{ezo>Oo?_*a{DdZ@pU#n5TXNUGmHMKH}h7U$ECeM8DJ1e8&v^6c!{3N1XD`REiP zS%#^otb>#WcTA*TYFq=(8T3tNC&%Yu_CDaP1{P;=y7Hm!ACiKk0vSxOEA3XAU7f8A z2G)=WgvZ~(9nFjWw!3u2&;%` zhgQ`n;ZC%Fk!gTWmd7x*zIRLZZFEBpS|^O8*EpS3-*Q~xQ)ry{I3Mi^bMbLrkhmc= zTDph$%K+W+-1n*4!Bb)iT^H|5(<`FB5@JwH0h>=|yNr#%wW1f4XMAO;(_vxDA|)nK z?;EZabETfMLB<8^8<=)jaU~cTf7zd4J36CcnTF@?t5g{dqMiWfFBYt}EIilo9OiM1 zhBrlX*;TR$p*m4`Ka2i+f}M4$JTv^yaN|HYX5|z)<+mSF4ay8Q)y$ATA_b zNT5OYaFhtQc)RpW^B2bzsd=WNUQPRHeX&g{x~{wlAzjOWEE^ zh`cS3?Hf>#YrBG8B=k=?UFX%^M= zZPCZcg}as~$XhkE1Q1g5pvEG5iyAwIoB|`=#akLL32{{B8-!zz=iEzuB$o%u5%Mq~ zPxZ#T(=gjn5akN{r9Si_8eXE}p-Eat=jV)9ONzwuVmW=`r%J3;x`_`ljET$TNZIt~ ztcTSRxEQrNrO1wtD&$v3Na6V8kMQm557q~^XwH}C@!+!DPTFEuKAu#VI%^RpQ>E$E zudkBR&WJ6pVEFCN>Lqa{HXsy8uHUDhkL%#0Cp>FTi0YiyGANI+!!RN(I}t8ccdiZT z(Wr)-J13|&VZuy+nu(8Sgg!X4hVu|ZRG2OWK&~7ov-nSGF#@~syH1)N8GPc#E(R#j z5>QNDQOPoWg4Y@hG@n>2A*9b#pKkNn>I#fuJLj3twfy=eHYX;l$X=bpiGds#5-lbi zF(yFCJu%U!{@QDv@RWN*A=pH0D9X)vk!j`PTLs?Tjn-T^V`Fxgt3T#6lkHpS)Dg}v zmy1V$`!v(-XOtwIUAM#rBorYd(`a>F{bS4geR~f{8|}}YW*>sqkq7tV?3@2zW*__0 z>}yTca-8eM3S1hgP&i_i--NI@z#UW>y<@ef9UfFk=fdR>$0Rie=u=&tjWLqKFK_jPV*T+j@v*-Ks9#t7s;R^7SFMA{V2hN-whWr!*;{X@A1krNg$#M zke8u{%=3Yqm1smlf+-kAH2`Isfo0`RU`CN+F+GyKzl4MasWnYjkQWNbIa4}-n5k?| z9PmokH_DrHzZKggjz7^&{`CEZFJS%TYWkAx`DTGc>RBOCi^k2f0RqqKbYbHB}4cA=GlQLoy$yxIX*SLyZ_{ccLI1+r@NHA)|EuJ#m7Vs_l> zGB1X+s;TzbW)7dg5{aSx*hOKfS0kNRecr7caD*$LzKLyp{RTi7JNv3^>p&ZMa~+Gl z_`Jw)5t>&iR8uweF&9v3BRk{=JCM{qkdlIn^(h`iLeoV@bk`e7k92*aC7o! z-g{^d${&#>@noa#Tp^JT<2Y9>^PaQV1RH*(-uRH zdQC^F2(s<`3+$ zXWzscFV$Ibj3F!E%?J^Y9Apm!7>`iWe+kI@$b1Widk-V?NHg~wy45p-;EfJjOXhw^ zgXi`(!F!C&;hJYw6QP;+E)+=u7kGIu*x$xcBR^a}pLHgIL46qv-3hY-VXv2|Kaj9; z67R!%#e(A~7U2q`J(3kH`W6XhI$*WoMhZLRt!u}3N-~6)h+g5fIt6gfqM&umH*$^d z-_kB5NnS^hG*IHf+P2xJz3&w@BCSGu6+Dk+!8>+Ah0iK15&Ss@`Y>21AX3OqmOaw< zFn^W%c}z&}Ya?<8)JBF0m)t`XJR`Hb`d|!ES~8@V$X+2MvMSWsU;@$d`77YN+c}A6 zhf3h4N^75Ju4P@+y4qkF{7IPH{+Vs^G2^{GwB%rVQBE@07&_PUgJa8~n`RZQ38#@O z3k1moQ;WBpv^ z`d{#Aw!*FsxiGR`ga_zqh~$#9qCVn(Bl!5f#~zuiK5&k*b*eMA&+h7+k^zd6!9Dil zb2ZeWV0KX+vOhcJU|P?3u~0rRQ!y|)LmR9j`qcWrsCjJlOTx{;Cu6HhG@8F>KJw-p zGwYftvtwd6IZttUSXrJeU5i%4VbS*db?!?uNhHxf^Z*+6NjzORM8~~Y+fJ(BWDkZX z!;JYLDPcsyilz~4C5lXz=yYDSR;zoiqYDX#7MJ>vA0>2AK%#_Z9_%CvL-sNzuvdJI z!~tlUBXw<~0>@eW?;2p-wo(BuMbN(Qwh5CI&LtZ|-3~_lMS{Ax(}e_dv%0!}tcnR- zTDn5tiuuRfy&sZGdgJJ3!T*?RwJEu@Pw@VO**`Yx5_!5XjApfo`fvPc`|Zyc9wiO} z@kFn@m57)@$P;vO;>L+h{5tX%Ki1xFBns9=j(;~LSl2Bar7kdEm9Ne;Pl4t2GEhlZ zy7iO3IG z=)_?sZ#C@mX$3w?E)$!(PDQM_U9#vfo|Wnn~ICM zCx7QDU~9YZ-oNr_ww|gyREKTlYrX!TI`i8T3EK^`eEk4C+E_$LihB&<@MmD4dN%`NcqgbX!->N z1SR+Xa5Q22X&lXKIi^ZteLlLl!=U9K951K9)7cB(FM44g1i&*BPG*&ix9VNC$xJml!TMe5U4U|qhZd@xrGjN5bTcY-uc#Ec3m>m&Q2G=rY2_EpP zbM$(Ld}g-JTzfl%=Vjcf+BY7Amx8(*9lFrF?1PzL=%{6pq`Nk{%#pUvOb2d0{)TqK zJ+8KP9dUP*uF_MGo%6JBMa#)#Dp_v$r7K2TzG?f#Si$9FFYI*-@|cJxMGCOyG}}7K zGJ)^#$nmzg%aSfL(raTR^HM&kQ$jMkr@$*%x1m2$*5u1{kR2gom7ROrLeHjEy6f=| z>k|%LV*EEBO1`_NV~X@PhsFB0uaURy+J?F7Y|3^wXCp9ZR~%laj2$wBzTvg?W!<@G z>p9xcM=L$iXd=qwzg4hV_-w%0`d#Z*TTaS{59wsJh+Czt`zR9{vkWIB ztULb9L;pQf?(+OG1ii1$M0)4$HdiugH_V03_P(j|TAKHIGT(V-^29>VBN#Kr=@)O& z7^(|I&@-~vS?8si8E)pGd^aC`8RFn$(-dzykb;ca6XRQg}u8 zIPucD*-{?uc9qmg)V^)Yq3!$vqujZU9M4?Wc3XQ6#;j@-O{GB#7!Z=2=eSU zX})^s^-CW9G~&=bD8&i7BeruDey6!fnry_bW%|A-%yV~d4w?~=u=6AxQ{V{+!hvn< zWo=@ddTH_D4y60ufz!TqcuuI#s)4pk6#t-W%hrLn{fjuXtM0DmcZr^2t%NNY9e*{e%0vxw8-VjR-`mlb?=Bqyzf zoBQm@&vdZHxuFm>WL8m`nap~c-twJ8vkXJC96+-yLbKe1S!z2(_b-_hOFE1kIN85( z=a_(S@?x-L(Q`P5n;Pl!?WeYTk~*H53CRRQSCS%k2D+g>Xj_EfwZ>3q>0%;;5~mg^ za)7q4_BhHVs$&4k5wS9{og~VjB>Pp((x_;fV7N*W&d&D@s3bJlQ2Jfo6;~zD0^7U;D9r2IX9_s>$5S`1fUh z%I!Oskgyv$?hsL2IozDS89DDpAgs8zA(I#VMENm70+@6%Ev)x8|K(@!c(Hz;@ zg&Zion(jv#BCI)Dh0J2K&pz%~_Ae>9tj%e5corDfgCqw-hFQnmOh5MdMdNXn$0C|5 z5AE6Uh8e{YfTWKleIj;%J1vXZ%)n3pkouFPUlM@*u@H#Hx;2I?3_J@6S_AQc^m05v zO^n9Wen4~(AR-kAf?@%hX;a|>l;?Or0sB@U5eFbqUxgw+PzM_wqcq(#w6tNAo}l+n zG(w=k)w{K5ZIHxq{1l$wu^QTP0RV1b0~bg>1mx)>Ne28OQQMg23x&mEsN1;h?m1WS zF-b>|9IGT{AKCA+RMeDj#FrYk|KGr?DTkKVIw(mwmx=(k?^m$Hv?LpJF) z&{c6<<|ab`6;AxAWU<&4Q!3!KhaWo$tjZO!bu!aKU(-fk(?wsiPkL+|Nnw!|ws5s% z8HLG_w#V=Dtbk1FY(gnGm6+6`io_&U6%r)O3dHJ5hwS^?9+{+Wk3|WsMy=mereKv^U{8N$m0*h;K|qp=Pr>?E5iTA2a~2H zcJ@hy{wJ5eDYRS<=z=%J&5 z4iUdIG_t<{8YKHYi7r+JMDC+-2k6x#(1=bO!@uXa-4nHKu}y#>rJ&c2e&Sq`vyZe9 z5Vba4m;owBz=ovTPmYeK`GNcfD`WUg`I3M9VQbWCi6=#D1YmIt@E=Ym)3VG zjqd>eP;olUVtQ9Bepl?DD#ATh3{Ytd_=k#(#RO@0{FjU&b+bJ>?m-EQ$~YMH3BV}j zE4L$Arlznor!lXZM(rwxeYG z%&Dclx_?_A>+m4db1A&*^pZ&sqpe#b!*iBRemz}F4ykm7o7a<%d(mveeHski%p;VHo$^%%3Iz?Oddj#Ts-ikMbL` z3keYAf!uv$i(+C*@dm8L+pPV-9fq7qTKNf1I$rLG z?a#!C(s%1lFpEpw1IEq;X*YU)LkH?*PZny%>fSWdH%b{#;;++-n{F?y9o01mlMez)gf{ho<*G+@f-C9w48r)Ojqgy|?fX z5T?NY!AfQM%}SMa1dC&RSiZZ3$HLYa3VzL1C{0F#31_BF*lcC0#KHR}0H7l2_l)H6 z)fEaOhFH2fs**BX%cssD@6qq(TgS6+Gw&{YEMB=whOrJzZz}J8x8ng$PhXK~EoI32 zURm8cvZlwWR_Ou;ywWq|+w<2?d%}Fv`8T?3*L70VVy_`~kG(w9RZ|a5tB_W$S6@JB>*k?W^ymR+jzq@F0NVUowezU5+@yJ zSeh|orO5)lMdMTl5BsU%A6ZHBMgz1Ai|b+6HMSt*xQ04Il#htdjJ&_IkQ8zDBLejnSJ-!LkVRigb_4`t(Bl!va~Y zU1eq1v)a2do6A@$aI$Mz_;`?$MwIR5e0@{wf@M-`(#lGyjn?e_0=r$ZRevi-QyWu> z*O_Hq;Xwx0GNTs#*jdSVontvjaHqOd&}8@AP{Z3AE6d!>H7V9VXEh(%_axkdH*ZeX zd_TVi8D%fW_wBFvn== zhk!eWfaTz;0W=~Bf>wfM$Ihbxv}Y1&Ed*!|o!bLw-{=Tm%0@Jkp5I4rmJjcQ>AQ** za+SaE^s!@g5_3{N)N3bE@iaL(x6ILbK#n|@SEWCk{DErf7R<}niHLIaA?UJ0#BZ5& z`A4*wnD?Ukp~!9_x;`^9_* z{-A(De+?HC(BQ9pIziM}!0AD&_Ar*f@9no}Y-bcg_eJst;1V4YE-OItwbcc?yMRON zrdieHw&SZr*$fm;jf4jDa42~{CemnBsbE0oNd_fx#QYjLyT&aaIbnzELYujz0^$|5t&`vdZT*T~OA2FRV#L{#Bsk3+_)@)%4uzy5&Z& zR;wvasskZ@9tMQ?g4<)cG$Usae~OS+R+&@XwP)4$!-|yuPXM?-0Ho9m3ygk>Sc)3^ zbY8)EJRwZly%7J|g&l-17JI0rIDQPtewa$kPv?^7M+6 z*dx@1Q)q;!68s(&cI7qVKQ}720SQrO5L7fO zy0F0l_VMWqsXW^n4el}fYogzY5&*mlcpQAYZ88Nt!%iv5asx62G20}+v;2EkFN}Hk zuOq4lo$%_1j~6u-`39Oz-EZg*GuM%7TKp60M~{g#7e&E|+ov3k-6*d)LDf5`PVUE8vaFv_n! z+K_DHMNdZlRf|@SYn6iz}vX0OGovA-^+mFj7leevmc>X%H>K=*Ycge4Q%=*92 zjoCKwys5MbwbE%_s<~m2Js8WKl`NijK0J441JGoSS=1ZL=o&2@JIB*kj5)_+dEyW9 z<%-4YoP=o9*N!*mHVo~ABD-`vbYb-fe^%QEl;>lMpk zX~EID)nq(JB#SjWB-<*tTg-odLc@P_)AiNc?LMWMdjLDkMyoXJ5Hz_FRC0cJ=+iz@ zLM&ifQj>O@CLkxUQDSs=7`45B$4b*g1-4JH5WIEb^c0YB>^v~KZzt#EPp--IHA89U zpPIFLaGpYO#n0Bcg?qAZ@ng%gQXcJF71{s6zGeNx3%jEBXy4vkVPar6rm%cuuu7Ye z%lmdUQS|ukpTpIH9IOJt^15#PZdU>wmb}$Zmjjaydw*lOx@OjM`FxJL>FTOtJ^KP= zl(Oz;ZC=zN#68ia@G3bVq~hF@@|nbO1;`GrW^#mpEeqQxH=%_sxUv_+@Jv- z>)OAY+^Bnq+uS9F^&h%Zt_tVE-saK39O28IWgQL+nq7TcJq&VF^B#9#8U4^P@P##_ z;u=hTn*@xE5#SpGto?H$T7{$zQ_LaJ%M2%c!a}N|$3@~l4*ac`DqY5$|J0NyljaeNsbw%6W zlsFh*cd?8+yGNQ=y@_M0S!!mgwz2nR}}$7F_hPv^`m}5Dwi$ z-c=>Kyga;#uPpATN$}u8>8jxczAEbaToaaE)s8vdnz&$;4-P>DB^oKNl_(Qwu|$E@ znG4fb4)T*~WY0`rd55{RzS7LP*_6#-d`KEOF1SPI8+v?!J?SyGlQwW!VG!3feN}wj z)YqOM%}l%L=taM_$d-t@XqetdcJN_F5>?YBUeJLF9Qi`BcmNG&TGl{<`9~mdYH^5;7+r3Gv-9HC7y-PCNvhCmevjCW>kV% zr_aL2LEk={g@Y4tC)sqh#7j(X>tqZw{GT2jPmi3sK`Xdz>IXG*(N5qo; zFi0o=8rZ_X7+e|q_!^&G>NAEBy>K^{5rJ?wrV*cTH?|R^FeQdj_DQlPO;MyY&^pM) znXjgs_tt;q2fpp1xwI&U&kG#uaCmquQ~l&D6pg(-P5i&Rs6 z^5-Tl4Y=={2V_kfi@H&+P&@{j^Av3u(BibT@-=My!YO)Z{KCn58~nnldN2KCNO}YO zWSj()>FVvL*Ewxy>NgIJR}+r7`pX!`=gG-kD!xh74{5Hr4-*{HZ>K$}o|Y)9)qwo_785^1>$U+diUg;O)hTpFr& zGQoT*fy5AwwT@)<1#3CUDjaJY$;%h4StKvhMdmrJ^gqC?3NVSDKDku?EDs)gH{Xy)q>vZ^U)KTFBwv>U)_||u z02q?5vj7<0R4Ns<<@FB|p|w+W3rq8dwg{C|0N#60GzHu&D4HCu5fn`YcLh=)feQpF zoTe+ZP7Pb%w@a68m)3S{94#wL{pMWz-7Tdg1P@e<*rBtt5xmt=dpn4U;|MJT^W@x$n5n<9l}}bj=Kfx+ z(MBT<=%`rUNKNvqGcWfY1}GbEk_md(14U+)D2cNZ{x7b{SV$$wPzx2k_vQ5;*lm!^ z$;%;rbC>?+G#8*D3Ct}NKf~O*^^iPBGQ(4c_$P7Uom!(l?&FR09knA4?Y_9k+Rfp3 zhMTgI^6p<=#oq;)&fWFVvTU4@Bj%jWT|X|{Fp<|1w+%pykmdQ8-&-DDl9Xmlj&pmi zk@8N*XJAaTTys1X8)&fy2L2oSbA4?(ywmmVBiY(@^in5EuaUeD;{Hv>+;pq?+H!o? z2y8KPtMPwA;ndl^?k9~%L^j{+`=|U2?cM8Zya?X|_SY8(KZ#VL;x(N->-m{q*Y{7=Wz}?iTgn(4A@@T5y=OZ{@}*4&A();9 zT^ULL&a2#cXYp>vn@TFR|E;peG=JrA#v4<4nST>}O#Zy{|6TU%OO!~Pn7ZMOlH1j$ zCOX4Invel7&<45s=F&yFGv7<*FS=`1B&G!s~=2R(%DT!J>lUe)lQs4SEn?L(lLrx5cK z5!f(ZwH%bKI)l7Ze5H#Ya9yffJq?_hI)mKn`UaW-;v)l0ll2$%T-oyrUu;6WYoJ1Sv|Qx)3o`Q-;Fe3J<*9!FmN68C@qWZg63j_al00)q)utSIdhD ztr}Rw3*yHD8ua6zP=e5xI0`1leP4DH)SM-@z7Ek z^6IE@09$8om$Tj!s_LeHx0dm|=T1##vbF7RPIcl0FA|;{1i3Zdn`_=(b@*nE-xiFV z7*}nJ^;sU)JK0`kGO(K{jQ!XV4bKD#SVuJA>sc4#Nn}K_-zodg?)s^w z$do&FFE`TkW~rV9CM3DYxJ%9VNz6&F1K7P6R2@$vCFL4n=xd^H#Ey}a{4o`WLt+)5 z-^X*A>D+&ehT&&HB$|R9K|H^%Z(Y>v_AHulr9oUTQ2`E<8%!MFAidnUmiTV4c` zfd;kOF$@k9nXpbCxTx1+%7;*&$q6Y~PFSJKD4ki8h&9}{x$9#G{y6<|Qav6UdtuPv zvCAtW^I8oXlW}ALZvVr~uOs=XT~#8Zf+Eb^VxQjF9Hl#&vQ- zCv+KI#y!nb&5MWBqU<6vfx)=$aiCHVZ=X^XzNco(P0GfSxRLNDzNr6LXH*t`OTmdHqc56!g(4cjX#WBLu`1@gq3M&E$ z0a5*5L-&w=58ZQew=(`2v$wCc5VgXI>U*e%w%(d3L=p|pT{)|CmdA5;o-3tFEMq{@ z)EP0Ghdk0b=R1b9fS4jlZM*tRFC? zd@?Y;vRP?vgz*uz6X#1&V^H#y{rNZ`=LW}TQAiT$!@H`Y#w_-`uBxiH&tFD+f2I+Y zss0Lh7RL{&jn9MfV_p>pTAf*gYtd0j9XW-;MlqvA5>>PN9r5s&sJ4m3%hYsUNff}35MH}n2>PVMhZc8our9E>O+I57ZLO`5&V!y zaCg(02hv{@vO(*{dI}w?>1e5F)Fm%%U^Ng?J+6`Tn@7hXMgbq542|4O z)Yu1DvgnbMw`*ZMT7ANzgLTd2QkMr(6_~vYmj^5D9wcMm8p;Z1#775V>#~|r{n5mY zcvMXg0m+EIz<~tsdMYpTUPzzCn~KES;HyOgImSk0G9x(pg}3+DutFualrdUF^6oF{ zI0?cw+0n_Inwrh3K{U-9MXrqUVre?rDJzu9>jB<^UrwEwL*EV$GZ2O&i^JylfBTa5 za`1CwUb@3*bCDSg7pCk(LiW)jH%^JW7k1Fq#w#DMgI7NFJczBhqk)y}^&)q4-}2pF zdSukTgCltr!@j&N%e~9>YPatd@AblwE~REz&3$0*!Vei4nQ%hhyT5sh-`LrPUD?@&hlvldeGVYFPrhcVZnG@T~X#Q|Z%QGj(JP&t-U zp#{37Z+p)huqmy0-kxE~bcXd2INnzzIh>WhCri_uI5Cm>Igg56cFumg$W=~uZZ~?v zVoXkNoZZ|snzL!=A>aVS!9UqqPdI5xcqKtpRvap2@dGcv=n9qzD-6Gdp6)N#4I3(u8@8DfdOYz6lc};CKJBjTDXx)$QtfF^^Ce?4%XOrr(8AdRjj!! zw;K8AAHGNGLb?cMg)qhKbA6#B7qjW|nS_XUD>0>sJ~tgcKI`#lgb@vEc<~X|iI{q< zg0wYNUNRdJHXZ8@LvLn@!9;W%+EfzCv*Gca+Kkf^(CVy$4yjF6#U)34J@z`2y;p5A z9hOsTEscy!N6|S&1|?yyk?-Or?Ry-{i1wQzf7G~t#2eo<2`()6cpifk(9+iCjn z!_G@ZV}(0|YT6Fp9V#+s?1z<#r3%^)92Go?I4$QX+Y;^RvL+X=bEc=olDTDN;P`Q& zd?)bVHfw~(#qziK@Sic^WuPx|9n6Ry4n0F@FE|#2US#Dr%SbkpvJ-s<*x=WOIeIvrdV?$7mfik5=kI+2zB_H5H|&j^BFD9Axa)s^+$D0m}4V=o-t-c&7n#uut3 zK-Sul!v;u9;32@aqD~e|>e4GEljBvu-GYu}`~lv5(b&6jVCgUp85faRQWhmrmfR}Xm@SOiB~M3w>y zhxcsVxwyBM6Q}0;%6dO#p@{eJH<31E7e#n5b2q-DP}@&!-T$)7CGGRbIP43z_0b#Q zXAlr2j}b)wSp$zDwZCY<*1`CR{|F@=`LE0v-WTfh-b+oaBr~5SN56*wDBrTTO&+io zYfaZAR`}X-&4{jlsrMXt#eY$-hjyBksc+%VLT*fV z(553Puyy(I(AvCy_XV7E@1cjEvC^L}9Y8n%LN1y`OsnbtC}=bnEeMf`{d!ZY{S3qD zlGzeKsIpXzii~}KYzaNPx5Z!n)>>;F_ohc1*kVAQf#@dKm{h`HMyoYbbp1RZSWz^$ z?hLlMxqpT(&*mHwrKtamssZWYw*T~}1s2M%-)Q})tL6VXTTp-1mA;+bld96Ahb%gn zQ3DRW;mI9p^VqxLgw@Pw_@U?gwLI90Yvfc;gKCk7!RpqeeU0^mCRZ+|mo_eS++UJp zelTdLg=2hI9qlI8Jf7lD#8(2u=}P1C)vO_g>~#|Q5{d+%A?1?2^s?wfW3i!;-FYFG zPYV{{6~RgGr0;o-)bSRB51QlE56MGZOX|TFy8eu-(31DT;FtH<#s1eJ$*K*!awA&a(ZPtP`*-J|AkNEtAS?G0_dU}{%4Q?9hoDZ}zyEogk0VfR+X z=0fn6JA#I%F^ps&qB3-DTsg(+*{BVYe{TtBTWS|YYKPR2G) zdMfUA#*R8qbPdJJ%YPL@?K<=cHL1wg5u)g>v12|e1gy-KHa}k&y^BqUUIz0rWGj;A zzBiLkb=hpa@C=eWIhs@HgNL**MVK1#pnpb}KIWqPsbE{jW2if)+NT2Ey@=N}f#%%t1=WcS(!yoX% z^Im);GW#xM3c8E447G?u@nv!$;3Y7lTvb<=U9>#=ZN%{8!k`F{o5u+}9jJz9r|R z+E^>eXP{;;>YcF7Lz@w|(rJ}|DM4r7bo6DVpm$8qHHK5$x3_-kq@u>8R{2pMUa(I( zc?O9A@#oDczg`UTbaTpI(|^844a@K=;b#D7Hj8PEB5lwZGI_E(e=%zs4r z8TjyblwV)s{S`%#