From 0bb8f51be12141d8d8cb37966d56b3508995242a Mon Sep 17 00:00:00 2001 From: Aimee Gott Date: Wed, 9 Jan 2019 10:54:09 +0000 Subject: [PATCH] Upload materials --- .gitignore | 4 + README.md | 33 + RStudio-Conf-Intermediate-Shiny.Rproj | 13 + apps/add-2/add_2.R | 24 + apps/adv-reactivity/counter-solution.R | 34 + apps/adv-reactivity/counter.R | 22 + apps/adv-reactivity/cranlogs-solution.R | 52 + apps/adv-reactivity/cranlogs.R | 53 ++ apps/adv-reactivity/diamonds.csv | 1001 ++++++++++++++++++++ apps/adv-reactivity/dynamic-antisolution.R | 68 ++ apps/adv-reactivity/dynamic-solution.R | 57 ++ apps/adv-reactivity/dynamic.R | 53 ++ apps/adv-reactivity/points-solution.R | 48 + apps/adv-reactivity/points.R | 45 + apps/bookmark/bookmark_01.R | 21 + apps/bookmark/bookmark_02.R | 35 + apps/bookmark/bookmark_03.R | 28 + apps/bookmark/bookmark_04.R | 37 + apps/bookmark/bookmark_05.R | 38 + apps/dashboard/flexdashboard_01.Rmd | 61 ++ apps/dashboard/flexdashboard_02.Rmd | 71 ++ apps/dashboard/flexdashboard_03.Rmd | 78 ++ apps/gapminder/data.R | 11 + apps/gapminder/gapminder.R | 31 + apps/gapminder/gapmodule.R | 51 + apps/hist-med/hist_med.R | 33 + apps/left-right/left_right_01.R | 69 ++ apps/left-right/left_right_02.R | 102 ++ apps/movies/movies.Rdata | Bin 0 -> 64990 bytes apps/movies/movies_01.R | 46 + apps/movies/movies_02.R | 53 ++ apps/movies/movies_03.R | 59 ++ apps/movies/movies_04.R | 79 ++ apps/movies/movies_05.R | 99 ++ apps/movies/movies_06.R | 104 ++ apps/movies/movies_07.R | 134 +++ apps/movies/movies_08.R | 134 +++ apps/movies/movies_09.R | 145 +++ apps/movies/movies_10.R | 159 ++++ apps/movies/movies_11.R | 156 +++ apps/movies/movies_12.R | 165 ++++ apps/movies/movies_13.R | 169 ++++ apps/movies/movies_14.R | 165 ++++ apps/movies/movies_15.R | 179 ++++ apps/movies/movies_16.R | 189 ++++ apps/movies/movies_17.R | 203 ++++ apps/movies/movies_18.R | 196 ++++ apps/movies/movies_19.R | 232 +++++ apps/movies/movies_20.R | 169 ++++ apps/movies/movies_21.R | 104 ++ apps/movies/movies_broken_01.R | 164 ++++ apps/movies/movies_broken_02.R | 164 ++++ apps/movies/movies_broken_03.R | 164 ++++ apps/movies/movies_broken_04.R | 164 ++++ apps/movies/movies_broken_05.R | 143 +++ apps/movies/moviesmodule.R | 39 + apps/movies/moviesmodule_template.R | 25 + apps/nytimes/app.R | 15 + apps/nytimes/get_nyt_archive.R | 29 + apps/soi/soi.Rdata | Bin 0 -> 3147 bytes apps/soi/soi_01.R | 64 ++ apps/soi/soi_02.R | 68 ++ apps/soi/soi_03.R | 96 ++ apps/soi/soi_04.R | 47 + apps/soi/soi_05.R | 54 ++ apps/ui/ui_01.R | 25 + apps/ui/ui_02.R | 31 + apps/ui/ui_03.R | 14 + apps/ui/ui_04.R | 22 + apps/ui/ui_05.R | 42 + apps/ui/youtube_thumbnail.html | 9 + slides/01-fast-intro.pdf | Bin 0 -> 4238742 bytes slides/02-reactive-prog-pt1.pdf | Bin 0 -> 1629682 bytes slides/03-understanding-ui.pdf | Bin 0 -> 2090914 bytes slides/04-adv-react.pdf | Bin 0 -> 1269887 bytes slides/05-modules.pdf | Bin 0 -> 1811068 bytes slides/06-bookmarking.pdf | Bin 0 -> 1244739 bytes slides/07-troubleshooting.pdf | Bin 0 -> 911815 bytes slides/08-dashboards.pdf | Bin 0 -> 1468940 bytes 79 files changed, 6491 insertions(+) create mode 100644 .gitignore create mode 100644 RStudio-Conf-Intermediate-Shiny.Rproj create mode 100644 apps/add-2/add_2.R create mode 100644 apps/adv-reactivity/counter-solution.R create mode 100644 apps/adv-reactivity/counter.R create mode 100644 apps/adv-reactivity/cranlogs-solution.R create mode 100644 apps/adv-reactivity/cranlogs.R create mode 100644 apps/adv-reactivity/diamonds.csv create mode 100644 apps/adv-reactivity/dynamic-antisolution.R create mode 100644 apps/adv-reactivity/dynamic-solution.R create mode 100644 apps/adv-reactivity/dynamic.R create mode 100644 apps/adv-reactivity/points-solution.R create mode 100644 apps/adv-reactivity/points.R create mode 100644 apps/bookmark/bookmark_01.R create mode 100644 apps/bookmark/bookmark_02.R create mode 100644 apps/bookmark/bookmark_03.R create mode 100644 apps/bookmark/bookmark_04.R create mode 100644 apps/bookmark/bookmark_05.R create mode 100644 apps/dashboard/flexdashboard_01.Rmd create mode 100644 apps/dashboard/flexdashboard_02.Rmd create mode 100644 apps/dashboard/flexdashboard_03.Rmd create mode 100644 apps/gapminder/data.R create mode 100644 apps/gapminder/gapminder.R create mode 100644 apps/gapminder/gapmodule.R create mode 100644 apps/hist-med/hist_med.R create mode 100644 apps/left-right/left_right_01.R create mode 100644 apps/left-right/left_right_02.R create mode 100644 apps/movies/movies.Rdata create mode 100644 apps/movies/movies_01.R create mode 100644 apps/movies/movies_02.R create mode 100644 apps/movies/movies_03.R create mode 100644 apps/movies/movies_04.R create mode 100644 apps/movies/movies_05.R create mode 100644 apps/movies/movies_06.R create mode 100644 apps/movies/movies_07.R create mode 100644 apps/movies/movies_08.R create mode 100644 apps/movies/movies_09.R create mode 100644 apps/movies/movies_10.R create mode 100644 apps/movies/movies_11.R create mode 100644 apps/movies/movies_12.R create mode 100644 apps/movies/movies_13.R create mode 100644 apps/movies/movies_14.R create mode 100644 apps/movies/movies_15.R create mode 100644 apps/movies/movies_16.R create mode 100644 apps/movies/movies_17.R create mode 100644 apps/movies/movies_18.R create mode 100644 apps/movies/movies_19.R create mode 100644 apps/movies/movies_20.R create mode 100644 apps/movies/movies_21.R create mode 100644 apps/movies/movies_broken_01.R create mode 100644 apps/movies/movies_broken_02.R create mode 100644 apps/movies/movies_broken_03.R create mode 100644 apps/movies/movies_broken_04.R create mode 100644 apps/movies/movies_broken_05.R create mode 100644 apps/movies/moviesmodule.R create mode 100644 apps/movies/moviesmodule_template.R create mode 100644 apps/nytimes/app.R create mode 100644 apps/nytimes/get_nyt_archive.R create mode 100644 apps/soi/soi.Rdata create mode 100644 apps/soi/soi_01.R create mode 100644 apps/soi/soi_02.R create mode 100644 apps/soi/soi_03.R create mode 100644 apps/soi/soi_04.R create mode 100644 apps/soi/soi_05.R create mode 100644 apps/ui/ui_01.R create mode 100644 apps/ui/ui_02.R create mode 100644 apps/ui/ui_03.R create mode 100644 apps/ui/ui_04.R create mode 100644 apps/ui/ui_05.R create mode 100644 apps/ui/youtube_thumbnail.html create mode 100644 slides/01-fast-intro.pdf create mode 100644 slides/02-reactive-prog-pt1.pdf create mode 100644 slides/03-understanding-ui.pdf create mode 100644 slides/04-adv-react.pdf create mode 100644 slides/05-modules.pdf create mode 100644 slides/06-bookmarking.pdf create mode 100644 slides/07-troubleshooting.pdf create mode 100644 slides/08-dashboards.pdf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b6a065 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata diff --git a/README.md b/README.md index e587283..f25de31 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ # RStudio-Conf-Intermediate-Shiny Materials for the Intermediate Shiny Workshop at RStudio Conf 2019 + +## Pre-Installations + +In preparation for this workshop you will need a recent version of R and RStudio installed along with all of the following packages: + +- cranlogs +- DT +- flexdashboard +- gapminder +- jsonlite +- lubridate +- miniUI +- shiny +- shinyBS +- shinydashboard +- shinyjs +- shinythemes +- shinytoastr +- tidyverse (specifically using dplyr, ggplot2, stringr) + +If you are able to, these can be installed using a single package available on GitHub: + +remotes::install_github("jcheng5/ShinyWorkshopDeps") +or +devtools::install_github("jcheng5/ShinyWorkshopDeps") + +## Materials + +During the workshop there will be plenty of opportunity for hands on practice. For these exercises you will need to get a copy of all of the materials, which can be found on GitHub: + +https://github.com/aimeegott/RStudio-Conf-Intermediate-Shiny + +If you are familiar with GitHub you can clone the repository, or otherwise simply download (you should see a green "Clone or Download" button on the right). diff --git a/RStudio-Conf-Intermediate-Shiny.Rproj b/RStudio-Conf-Intermediate-Shiny.Rproj new file mode 100644 index 0000000..8e3c2eb --- /dev/null +++ b/RStudio-Conf-Intermediate-Shiny.Rproj @@ -0,0 +1,13 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX diff --git a/apps/add-2/add_2.R b/apps/add-2/add_2.R new file mode 100644 index 0000000..470f9a6 --- /dev/null +++ b/apps/add-2/add_2.R @@ -0,0 +1,24 @@ +library(shiny) + +# Define UI for application that adds 2 to a selected value +ui <- fluidPage( + # Application title + titlePanel("Add 2"), + # Sidebar with a slider input for x + sidebarLayout( + sidebarPanel( sliderInput("x", "Select x", min = 1, max = 50, value = 30) ), + mainPanel( textOutput("x_updated") ) + ) +) + +# Define server logic +server <- function(input, output) { + add_2 <- function(x) { x + 2 } + #current_x <- add_2(input$x) + #output$x_updated <- renderText({ current_x }) + current_x <- reactive({ add_2(input$x) }) + output$x_updated <- renderText({ current_x() }) +} + +# Run the application +shinyApp(ui = ui, server = server) diff --git a/apps/adv-reactivity/counter-solution.R b/apps/adv-reactivity/counter-solution.R new file mode 100644 index 0000000..9b86c71 --- /dev/null +++ b/apps/adv-reactivity/counter-solution.R @@ -0,0 +1,34 @@ +library(shiny) + +# Define UI for counter --------------------------------------------- +ui <- fluidPage( + actionButton("increment", "Increment"), + actionButton("decrement", "Decrement"), + actionButton("reset", "Reset"), + + p( + textOutput("value") + ) +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + rv <- reactiveValues(count = 0) + + observeEvent(input$increment, { + rv$count <- rv$count + 1 + }) + observeEvent(input$decrement, { + rv$count <- rv$count - 1 + }) + observeEvent(input$reset, { + rv$count <- 0 + }) + + output$value <- renderText({ + rv$count + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/counter.R b/apps/adv-reactivity/counter.R new file mode 100644 index 0000000..07add38 --- /dev/null +++ b/apps/adv-reactivity/counter.R @@ -0,0 +1,22 @@ +library(shiny) + +# Define UI for counter --------------------------------------------- +ui <- fluidPage( + actionButton("increment", "Increment"), + actionButton("decrement", "Decrement"), + actionButton("reset", "Reset"), + + p( + textOutput("value") + ) +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + output$value <- renderText({ + 0 + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/cranlogs-solution.R b/apps/adv-reactivity/cranlogs-solution.R new file mode 100644 index 0000000..38574e8 --- /dev/null +++ b/apps/adv-reactivity/cranlogs-solution.R @@ -0,0 +1,52 @@ +library(cranlogs) +library(dplyr) +library(lubridate) +library(ggplot2) +library(shiny) + +# Define UI for specifying package and plotting cranlogs ------------ +ui <- fluidPage( + sidebarLayout( + sidebarPanel( + textInput("packages", "Package names (comma separated)"), + actionButton("update", "Update") + ), + mainPanel( + plotOutput("plot") + ) + ) +) + +# Define server logic for downloading and parsing cranlogs ---------- +server <- function(input, output, session) { + + # Parses comma-separated string into a proper vector + packages <- eventReactive(input$update, { + strsplit(input$packages, " *, *")[[1]] + }) + + # Daily downloads + daily_downloads <- reactive({ + cranlogs::cran_downloads( + packages = packages(), + from = "2016-01-01", to = "2016-12-31" + ) + }) + + # Weekly downloads + weekly_downloads <- reactive({ + daily_downloads() %>% mutate(date = ceiling_date(date, "week")) %>% + group_by(date, package) %>% + summarise(count = sum(count)) + }) + + # Plot weekly downloads, plus trendline + output$plot <- renderPlot({ + ggplot(weekly_downloads(), aes(date, count, color = package)) + + geom_line() + + geom_smooth() + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/cranlogs.R b/apps/adv-reactivity/cranlogs.R new file mode 100644 index 0000000..76f869d --- /dev/null +++ b/apps/adv-reactivity/cranlogs.R @@ -0,0 +1,53 @@ +library(cranlogs) +library(dplyr) +library(lubridate) +library(ggplot2) +library(shiny) + +# Define UI for specifying package and plotting cranlogs ------------ +ui <- fluidPage( + sidebarLayout( + sidebarPanel( + textInput("packages", "Package names (comma separated)"), + actionButton("update", "Update") + ), + mainPanel( + plotOutput("plot") + ) + ) +) + +# Define server logic for downloading and parsing cranlogs ---------- +server <- function(input, output, session) { + + # Parses comma-separated string into a proper vector + packages <- reactive({ + strsplit(input$packages, " *, *")[[1]] + }) + + # Daily downloads + daily_downloads <- reactive({ + cranlogs::cran_downloads( + packages = packages(), + from = "2016-01-01", to = "2016-12-31" + ) + }) + + # Weekly downloads + weekly_downloads <- reactive({ + daily_downloads() %>% + mutate(date = ceiling_date(date, "week")) %>% + group_by(date, package) %>% + summarise(count = sum(count)) + }) + + # Plot weekly downloads, plus trendline + output$plot <- renderPlot({ + ggplot(weekly_downloads(), aes(date, count, color = package)) + + geom_line() + + geom_smooth() + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/diamonds.csv b/apps/adv-reactivity/diamonds.csv new file mode 100644 index 0000000..52e9cf0 --- /dev/null +++ b/apps/adv-reactivity/diamonds.csv @@ -0,0 +1,1001 @@ +"carat","cut","color","clarity","depth","table","price","x","y","z" +1.51,"Premium","D","SI1",61.6,57,12738,7.41,7.32,4.54 +0.41,"Ideal","F","VVS2",60.1,57,1115,4.83,4.85,2.91 +2.42,"Premium","J","SI2",62.3,58,16198,8.63,8.55,5.35 +1.57,"Premium","H","VS1",61.7,58,10880,7.47,7.56,4.64 +0.32,"Ideal","F","VS2",61.2,56,828,4.44,4.41,2.71 +0.32,"Ideal","F","VS1",61.6,57,716,4.39,4.42,2.71 +1.05,"Good","D","SI2",60,63,4560,6.59,6.64,3.97 +0.55,"Very Good","F","VS2",61.6,56.1,1777,5.29,5.31,3.27 +2.18,"Very Good","E","I1",62,60,10340,8.25,8.33,5.14 +0.43,"Premium","D","VS2",60.7,58,1056,4.84,4.88,2.95 +0.57,"Ideal","F","VVS2",61.7,56,2402,5.31,5.35,3.29 +1.59,"Ideal","I","SI1",62.1,57,8835,7.48,7.46,4.64 +1.29,"Ideal","I","VS2",62.7,57,6509,6.97,6.91,4.35 +1.21,"Ideal","H","SI1",60.7,57,7810,6.85,6.89,4.17 +1.06,"Ideal","H","SI2",59.9,58,4749,6.67,6.63,3.98 +0.34,"Very Good","D","SI1",62.8,55,626,4.45,4.5,2.81 +0.34,"Premium","D","SI2",59.2,59,507,4.54,4.58,2.7 +1.01,"Good","D","SI1",63.9,60,5055,6.29,6.32,4.03 +0.71,"Premium","F","SI1",59.8,61,2633,5.81,5.79,3.47 +1.02,"Ideal","H","SI2",60.5,57,4297,6.52,6.56,3.95 +0.68,"Ideal","D","VVS1",61.3,57,4325,5.66,5.69,3.48 +0.41,"Good","E","VVS1",63.5,57,1002,4.73,4.75,3.01 +0.5,"Premium","D","VS2",61.4,59,1752,5.11,5.15,3.15 +0.41,"Ideal","D","SI1",61.4,56,791,4.77,4.8,2.94 +1,"Very Good","E","VVS2",59.5,59,9139,6.54,6.58,3.9 +0.31,"Premium","F","VS2",61.8,59,802,4.33,4.31,2.67 +0.3,"Ideal","D","SI1",61.8,56,508,4.31,4.33,2.67 +0.44,"Very Good","E","VVS2",59.6,59,1337,4.98,4.99,2.97 +0.8,"Ideal","D","SI2",61.9,54,3210,5.95,6,3.7 +1.18,"Ideal","E","I1",61.6,56,4229,6.82,6.79,4.19 +0.31,"Ideal","H","VVS2",62.8,57,802,4.33,4.3,2.71 +0.55,"Ideal","F","SI2",61.2,56,1263,5.29,5.23,3.22 +1.02,"Ideal","H","SI2",61.9,56,4353,6.47,6.51,4.02 +1.55,"Very Good","G","SI1",59.2,59,10707,7.51,7.59,4.47 +1,"Ideal","H","SI2",61.4,60,4713,6.35,6.41,3.92 +0.36,"Premium","E","VS2",62,58,789,4.54,4.56,2.82 +1,"Ideal","E","VS2",62,55,6043,6.42,6.38,3.97 +0.31,"Very Good","F","SI1",60.7,58,516,4.35,4.38,2.65 +1.71,"Ideal","G","VS1",62.2,55,17595,7.72,7.65,4.78 +0.51,"Ideal","G","VVS2",61.1,56,1875,5.15,5.19,3.16 +0.42,"Ideal","E","VVS2",62.3,55,1216,4.76,4.81,2.98 +0.41,"Premium","E","SI1",60.4,58,930,4.79,4.75,2.88 +0.43,"Ideal","J","VVS2",61.8,55,710,4.89,4.91,3.03 +1.06,"Ideal","F","VVS2",62.1,57,9118,6.54,6.5,4.05 +1.21,"Ideal","E","IF",61.8,56,17353,6.81,6.88,4.23 +0.4,"Premium","G","VVS2",61.3,59,980,4.78,4.74,2.92 +1.01,"Premium","D","SI1",62,60,6066,6.37,6.4,3.96 +0.31,"Very Good","G","VVS2",62.7,55,627,4.32,4.35,2.72 +0.46,"Very Good","F","VVS1",61.4,57,1657,4.95,4.99,3.05 +0.7,"Fair","F","SI2",58.2,66,1920,5.77,5.74,3.35 +1.01,"Premium","G","VS1",60.5,60,6353,6.52,6.44,3.92 +0.74,"Very Good","J","VS2",60.8,58,2003,5.79,5.85,3.54 +0.31,"Ideal","F","IF",61.4,56,1061,4.38,4.41,2.7 +1.13,"Ideal","E","VVS1",61.8,57,13485,6.66,6.71,4.13 +0.54,"Very Good","E","SI1",62.1,59,1379,5.17,5.2,3.22 +0.71,"Ideal","F","VS1",61.5,57,2839,5.74,5.71,3.52 +1.7,"Premium","I","VVS2",62.1,59,11775,7.6,7.53,4.7 +0.52,"Ideal","H","VVS1",61.7,55,1847,5.2,5.17,3.2 +0.5,"Fair","D","SI1",65.7,56,1323,5.01,4.97,3.28 +1.51,"Premium","E","SI1",62.8,59,11565,7.3,7.26,4.57 +0.37,"Very Good","G","VS1",58.4,59,657,4.76,4.69,2.76 +0.52,"Ideal","G","SI2",61.6,55,1090,5.16,5.19,3.19 +1,"Premium","F","SI2",60.4,58,3858,6.47,6.44,3.9 +1,"Premium","F","SI2",62.4,61,4155,6.34,6.32,3.95 +0.66,"Ideal","H","SI1",62.4,58,1609,5.53,5.56,3.46 +1.23,"Ideal","D","VVS1",62.4,57,16253,6.88,6.83,4.28 +1.51,"Ideal","H","SI1",61.3,56,9833,7.4,7.44,4.55 +0.34,"Premium","H","VVS1",61.1,59,995,4.52,4.48,2.75 +0.31,"Very Good","H","VVS1",58.5,59,755,4.45,4.5,2.62 +0.76,"Very Good","G","VVS2",61.5,59,3394,5.83,5.91,3.61 +0.75,"Premium","G","SI2",63,58,2250,5.81,5.77,3.62 +2.11,"Ideal","H","SI2",61.5,57,12179,8.3,8.25,5.09 +1.09,"Premium","H","SI2",61.2,62,4395,6.63,6.58,4.04 +2,"Good","J","I1",63.6,62,6521,7.97,7.8,5.02 +0.4,"Good","G","SI1",63.3,58,655,4.66,4.69,2.96 +0.9,"Very Good","E","SI2",63.7,56,3482,6.08,6.13,3.89 +1.05,"Very Good","H","SI1",63.1,60,4692,6.49,6.42,4.07 +0.6,"Ideal","E","SI1",61.3,56,1890,5.49,5.44,3.35 +0.37,"Premium","F","SI1",61.6,59,616,4.62,4.67,2.86 +0.5,"Fair","E","VS2",79,73,2579,5.21,5.18,4.09 +0.5,"Good","E","VS2",63.8,54,1752,5.05,5.07,3.23 +0.51,"Ideal","H","SI2",61.7,55,1435,5.13,5.15,3.17 +0.41,"Very Good","F","VS2",62.4,56,863,4.75,4.77,2.97 +1.2,"Ideal","D","SI1",61.8,58,7508,6.76,6.83,4.2 +0.7,"Very Good","H","VS2",63.2,57,2137,5.58,5.62,3.54 +0.7,"Good","F","SI2",59,57,2100,5.8,5.83,3.43 +0.43,"Very Good","F","VS2",61.3,59,905,4.81,4.84,2.96 +1.31,"Premium","J","SI1",59.4,60,5446,7.06,7.12,4.21 +1.09,"Ideal","G","VS1",60.5,57,7078,6.69,6.73,4.06 +0.26,"Ideal","H","VS2",62.1,55,434,4.08,4.1,2.54 +1.1,"Very Good","I","VS1",60.8,58.3,5196,6.63,6.68,4.04 +0.51,"Good","H","VS2",61.8,65,1128,5.07,5.02,3.12 +0.31,"Ideal","H","IF",61.3,56,789,4.39,4.42,2.7 +0.34,"Ideal","G","IF",60.1,57,1014,4.54,4.58,2.74 +0.38,"Ideal","G","VS1",62.4,54,759,4.63,4.67,2.9 +0.57,"Ideal","E","VS2",60.8,56,1819,5.4,5.35,3.27 +0.59,"Premium","E","SI1",58.7,57,1550,5.53,5.47,3.23 +1.02,"Premium","H","I1",62.5,60,3199,6.41,6.39,4 +0.3,"Ideal","E","SI1",61.7,58,499,4.29,4.3,2.65 +0.9,"Very Good","I","VS2",62.1,61,3535,6.08,6.12,3.79 +0.53,"Ideal","F","VVS2",61,57,2269,5.23,5.26,3.22 +0.71,"Premium","E","SI2",61.4,59,2306,5.74,5.7,3.51 +0.53,"Ideal","G","SI1",61.8,58,1255,5.16,5.19,3.2 +0.34,"Premium","D","VS2",59.3,58,1033,4.55,4.52,2.69 +0.34,"Premium","E","VS2",62.6,58,956,4.45,4.43,2.78 +0.34,"Fair","F","VS2",64.7,55,816,4.52,4.41,2.89 +0.7,"Premium","G","SI2",61.9,58,2268,5.64,5.6,3.48 +1.17,"Fair","I","I1",64.5,59,2336,6.67,6.47,4.25 +0.24,"Very Good","E","VS1",61.7,60,430,3.97,4,2.46 +1.17,"Ideal","G","SI2",62.6,55,5743,6.74,6.78,4.23 +0.7,"Premium","E","VS2",62.8,61,2737,5.66,5.62,3.54 +1,"Premium","F","VVS1",61,60,9901,6.43,6.39,3.91 +0.72,"Good","D","VS1",63.3,55,3570,5.69,5.75,3.62 +1.01,"Premium","E","VS2",62.4,60,6488,6.39,6.43,4 +0.3,"Premium","D","VS2",61.9,58,911,4.32,4.28,2.66 +1.01,"Good","D","SI1",63.9,61,5147,6.31,6.28,4.02 +1.02,"Ideal","D","VVS2",61,56,11765,6.52,6.55,3.99 +0.51,"Very Good","D","VS2",62.5,58,1668,5.12,5.18,3.22 +0.24,"Ideal","F","VVS2",62.1,56,678,3.96,3.99,2.46 +0.37,"Ideal","F","VVS2",60.7,57,839,4.67,4.69,2.84 +0.51,"Premium","E","VS2",61.6,58,1567,5.18,5.15,3.18 +1.05,"Very Good","H","VS1",63.4,57,4969,6.48,6.45,4.1 +1.5,"Very Good","I","VS2",63.3,55,9533,7.3,7.26,4.61 +2.01,"Ideal","I","SI1",62.2,56,15116,8.12,8.06,5.03 +0.32,"Premium","I","VS2",61.1,57,576,4.42,4.39,2.69 +0.7,"Premium","F","SI1",61.9,58,2230,5.69,5.74,3.54 +0.72,"Very Good","E","VS2",63,58,3065,5.69,5.73,3.6 +1.13,"Ideal","H","SI1",62,57,4959,6.66,6.73,4.15 +1.18,"Premium","G","VVS2",61.6,58,9137,6.77,6.8,4.18 +0.56,"Premium","F","VS1",58.2,60,2016,5.41,5.38,3.14 +1,"Premium","H","VS1",62.7,58,4732,6.37,6.33,3.98 +0.3,"Premium","H","VS1",62.3,58,675,4.28,4.26,2.66 +0.71,"Ideal","G","SI2",62.3,56,2266,5.68,5.72,3.55 +0.35,"Very Good","H","SI1",61.3,55,504,4.55,4.58,2.8 +0.47,"Ideal","E","SI2",61.5,55,931,4.98,5.04,3.08 +0.43,"Ideal","G","IF",62.1,54,1433,4.83,4.87,3.01 +0.51,"Premium","E","SI1",60.3,56,1443,5.27,5.17,3.15 +0.55,"Ideal","E","VS2",60.3,57,1596,5.28,5.3,3.19 +1.15,"Ideal","H","SI2",62,57,4830,6.75,6.66,4.16 +1.23,"Ideal","E","SI2",62.1,55,7336,6.91,6.84,4.27 +0.32,"Ideal","E","VVS2",61.2,56,816,4.39,4.43,2.7 +0.51,"Premium","F","VS2",63,55,1574,5.1,5.06,3.2 +0.34,"Premium","D","SI1",62.4,58,803,4.46,4.42,2.77 +0.73,"Ideal","G","VVS1",61.3,56,3667,5.79,5.82,3.56 +0.9,"Ideal","E","SI2",62.7,54,4091,6.13,6.21,3.87 +2.16,"Premium","I","SI1",58.5,60,17934,8.54,8.49,4.98 +0.8,"Very Good","H","SI1",62.3,59,2670,5.95,6,3.72 +1.01,"Very Good","G","VS2",63.2,57,5701,6.35,6.3,4 +0.41,"Ideal","D","SI2",62.7,55,876,4.75,4.72,2.97 +0.32,"Ideal","D","SI1",62.6,55,589,4.36,4.39,2.74 +0.31,"Ideal","D","VS2",61.6,55,804,4.4,4.37,2.7 +0.7,"Very Good","H","SI1",62,60,2048,5.65,5.7,3.52 +0.76,"Ideal","F","VVS2",60.9,57,3716,5.89,5.96,3.61 +1.21,"Very Good","F","VS2",60.1,55,8711,6.91,7.01,4.18 +0.56,"Ideal","G","VVS2",62.5,56,1889,5.24,5.28,3.29 +0.56,"Premium","D","SI1",61.4,58,1723,5.29,5.33,3.26 +0.73,"Very Good","E","VS1",60.9,61,3370,5.79,5.81,3.53 +0.5,"Ideal","F","VVS2",59.9,58,2016,5.14,5.17,3.09 +0.75,"Fair","J","VS1",61.9,67,1869,5.8,5.7,3.56 +0.4,"Premium","E","SI2",61.4,57,855,4.74,4.68,2.89 +0.5,"Ideal","D","VS2",62.4,55,1653,5.09,5.1,3.18 +1.5,"Good","H","VS1",63.8,61,9878,7.17,7.12,4.56 +0.71,"Premium","E","SI2",62.2,57,2386,5.74,5.68,3.55 +1,"Premium","F","SI1",62.1,60,4234,6.29,6.23,3.88 +0.33,"Very Good","G","VS1",61.6,57,621,4.42,4.51,2.75 +0.8,"Very Good","F","SI2",61,60,2460,5.95,5.98,3.64 +0.41,"Ideal","E","VS1",61.9,55,1079,4.76,4.8,2.96 +0.51,"Ideal","E","SI1",61.2,57,1284,5.14,5.16,3.15 +1.15,"Premium","G","SI1",62,58,4776,6.68,6.77,4.17 +0.31,"Ideal","G","VVS2",62.7,57,907,4.34,4.31,2.71 +2.04,"Good","J","VS2",59.6,56,13550,8.26,8.31,4.94 +1,"Ideal","F","SI2",62.4,57,5798,6.37,6.42,3.99 +0.92,"Ideal","G","SI1",62.6,56,4173,6.21,6.19,3.88 +0.33,"Ideal","F","VS1",61.2,56,928,4.49,4.46,2.74 +0.5,"Ideal","D","VS2",62.4,55,1635,5.1,5.13,3.19 +0.52,"Ideal","D","VS1",60.4,56,2146,5.24,5.26,3.17 +1.01,"Premium","G","VS2",58.1,59,5538,6.61,6.53,3.82 +1.09,"Ideal","G","SI1",62.4,56,5496,6.57,6.61,4.11 +1.02,"Ideal","F","SI1",60.3,60,5195,6.55,6.51,3.94 +2.54,"Ideal","G","SI2",62.7,56,17339,8.75,8.67,5.46 +0.33,"Premium","D","SI1",60.1,59,608,4.46,4.49,2.69 +1.16,"Ideal","D","SI2",62.1,54,5898,6.79,6.74,4.2 +0.41,"Premium","G","VS2",62.4,58,827,4.72,4.76,2.96 +0.23,"Very Good","E","VVS2",61.8,58,530,3.92,3.94,2.43 +0.3,"Premium","E","VS1",61.3,59,911,4.33,4.28,2.64 +0.71,"Fair","D","VS1",65.4,59,2747,5.62,5.58,3.66 +0.38,"Ideal","H","VS1",60.6,57,871,4.7,4.73,2.85 +0.31,"Premium","E","VS2",61.3,60,680,4.32,4.39,2.67 +0.36,"Ideal","D","VS2",61.3,55,928,4.58,4.62,2.82 +2.03,"Very Good","E","SI2",58.8,59,18115,8.23,8.28,4.85 +1.01,"Good","D","SI2",63.9,57,4672,6.36,6.29,4.04 +0.31,"Premium","F","VS2",61.4,55,802,4.34,4.32,2.66 +1.14,"Premium","F","SI1",59.6,58,5925,6.78,6.8,4.05 +1.2,"Ideal","G","VVS1",62.2,57,9009,6.77,6.81,4.22 +0.5,"Ideal","E","VVS2",62.2,54,2889,5.09,5.11,3.17 +0.31,"Ideal","F","SI1",62.3,55,490,4.34,4.39,2.72 +0.94,"Premium","G","SI2",63,59,3099,6.16,6.1,3.86 +1.5,"Very Good","I","VS2",59.4,61,9342,7.41,7.45,4.41 +0.57,"Ideal","F","VVS1",61.3,56,3343,5.4,5.37,3.3 +0.92,"Very Good","E","VS1",61.3,57,5210,6.22,6.27,3.83 +2,"Fair","E","SI1",65.7,60,15330,7.7,7.8,5.09 +0.32,"Ideal","H","IF",61.8,55,814,4.42,4.45,2.74 +0.34,"Ideal","H","VS2",60.4,57,555,4.54,4.57,2.75 +1.01,"Very Good","G","VVS2",63.4,55,6968,6.41,6.34,4.04 +0.64,"Ideal","E","VVS2",62.1,53,3157,5.51,5.54,3.43 +1.02,"Ideal","F","VS2",62.7,54,6597,6.5,6.42,4.05 +1.59,"Very Good","I","SI1",62.4,56,9925,7.46,7.48,4.66 +0.58,"Very Good","F","SI1",62.6,57,1373,5.24,5.36,3.32 +0.31,"Ideal","F","VVS1",61.4,55,1074,4.37,4.39,2.69 +0.31,"Very Good","H","SI1",61.7,59,435,4.36,4.39,2.7 +0.38,"Ideal","F","VS2",62.3,54,870,4.65,4.69,2.91 +1.25,"Ideal","G","IF",60.2,54,11511,6.99,7.03,4.22 +0.41,"Very Good","F","SI1",62.4,60,801,4.73,4.75,2.96 +0.45,"Very Good","F","SI2",61.5,61,729,4.9,4.95,3.03 +1.04,"Good","E","SI1",63.8,58,5766,6.46,6.39,4.1 +0.57,"Very Good","J","SI1",60.6,61,1037,5.36,5.4,3.26 +0.32,"Ideal","F","IF",62.2,55,1010,4.38,4.4,2.73 +0.92,"Ideal","E","SI1",61.4,55,4183,6.29,6.25,3.85 +0.56,"Ideal","D","VS1",61.1,56,2741,5.3,5.33,3.25 +0.41,"Premium","G","VS2",62.4,58,1061,4.76,4.72,2.96 +1.03,"Ideal","I","VS2",61.2,56,5378,6.5,6.51,3.98 +1.7,"Premium","I","VS2",62.4,58,10910,7.61,7.56,4.73 +0.32,"Ideal","F","VS1",61,54,716,4.42,4.44,2.7 +0.53,"Very Good","J","VS2",62.7,56,996,5.15,5.18,3.24 +1.21,"Premium","E","SI1",63,57,6261,6.75,6.7,4.24 +0.31,"Good","E","SI1",63.6,57,544,4.28,4.3,2.73 +0.3,"Very Good","D","VS1",63,56,645,4.27,4.33,2.71 +0.23,"Very Good","D","VS1",61.9,58,402,3.92,3.96,2.44 +0.91,"Premium","E","SI1",62.1,58,4256,6.18,6.15,3.83 +1.2,"Ideal","J","SI2",59.1,62,4509,6.97,6.94,4.11 +1.01,"Good","E","SI2",58.5,61,4506,6.51,6.55,3.82 +1.53,"Premium","I","VS1",62.4,59,10924,7.34,7.3,4.57 +1.03,"Ideal","J","SI1",62.3,56,3893,6.51,6.45,4.04 +0.52,"Premium","E","VS2",62.5,60,1694,5.14,5.1,3.2 +0.38,"Premium","E","VS1",60.7,59,1000,4.69,4.73,2.86 +0.55,"Ideal","E","VS2",62.5,56,2030,5.26,5.23,3.28 +1.02,"Very Good","E","VS2",60.6,61,6366,6.44,6.47,3.91 +0.42,"Ideal","I","VVS1",60.2,57,884,4.85,4.88,2.93 +1.13,"Very Good","I","SI1",61.5,60,4766,6.68,6.72,4.12 +1.61,"Ideal","F","SI1",62.6,58,12085,7.44,7.48,4.67 +0.32,"Premium","E","VS2",60.5,59,702,4.39,4.43,2.67 +0.7,"Very Good","E","SI2",61.5,56,2298,5.71,5.73,3.52 +0.92,"Good","F","SI2",64.2,58,3282,6.14,6.11,3.93 +0.39,"Fair","E","SI1",65.6,60,601,4.5,4.56,2.97 +1.57,"Premium","H","VS2",62.2,58,11415,7.45,7.4,4.62 +1.5,"Fair","G","SI1",56.1,62,7300,7.6,7.52,4.24 +1.01,"Premium","H","SI2",61.5,60,4242,6.4,6.34,3.92 +2.01,"Premium","H","VS2",62.8,58,13342,7.99,7.9,4.99 +0.24,"Very Good","E","VVS2",62.8,58,478,3.92,3.95,2.47 +0.51,"Premium","E","VS1",62.3,56,1837,5.14,5.13,3.2 +0.72,"Premium","D","SI1",62.6,54,3048,5.78,5.72,3.6 +1.05,"Ideal","H","SI1",60.8,56,5704,6.62,6.58,4.01 +0.52,"Ideal","G","VVS2",62.7,55,1906,5.12,5.15,3.22 +1.61,"Ideal","I","SI1",62.7,55,9611,7.54,7.48,4.71 +1.11,"Very Good","E","SI2",60,61,4170,6.66,6.71,4.01 +0.34,"Very Good","G","VVS2",62.3,59,740,4.45,4.48,2.78 +1.78,"Very Good","F","SI1",60.6,57,13659,7.89,7.94,4.8 +0.66,"Very Good","H","VVS1",61.9,59,2323,5.59,5.65,3.48 +1.2,"Ideal","G","VVS2",62.2,56,9373,6.76,6.81,4.22 +2,"Good","J","VS2",61.4,63,13542,8.01,8.08,4.94 +0.3,"Premium","E","VS2",62,60,844,4.26,4.23,2.63 +0.53,"Ideal","G","VS1",62.6,54,1813,5.19,5.16,3.24 +2.04,"Premium","I","SI2",60.2,59,15543,8.28,8.22,4.97 +0.32,"Ideal","I","VVS1",62.4,55,756,4.38,4.34,2.72 +1.25,"Ideal","F","VS1",62,55,9586,6.91,6.95,4.3 +0.32,"Very Good","H","VS1",63,55,561,4.4,4.42,2.78 +0.32,"Ideal","E","VS2",61.9,56,702,4.36,4.4,2.71 +0.71,"Good","I","VS1",61.5,64,2327,5.76,5.65,3.51 +0.31,"Premium","G","VVS1",59.9,62,1046,4.37,4.35,2.61 +0.3,"Ideal","H","VVS1",62.2,56,665,4.28,4.3,2.67 +0.51,"Ideal","E","SI1",61.7,55,1443,5.17,5.13,3.18 +0.84,"Ideal","J","SI1",61.8,56,2493,6.04,6.07,3.74 +1.01,"Premium","E","VS2",60.8,60,6606,6.46,6.43,3.92 +0.41,"Very Good","E","SI2",63.2,58,818,4.72,4.68,2.97 +1.7,"Ideal","I","VS2",61.7,56,11257,7.64,7.72,4.74 +0.33,"Ideal","F","IF",61.5,55,1114,4.47,4.44,2.74 +1.19,"Ideal","H","SI2",61.7,56,4798,6.83,6.78,4.2 +0.32,"Premium","G","VVS2",62.6,58,936,4.37,4.35,2.73 +0.3,"Ideal","G","VS1",60.6,57,624,4.38,4.4,2.66 +0.53,"Very Good","E","SI1",63,55,1408,5.14,5.18,3.25 +0.6,"Premium","E","SI1",61.9,58,1738,5.39,5.43,3.35 +2.03,"Ideal","I","SI2",60,57,13182,8.32,8.2,4.96 +0.55,"Ideal","G","VS1",61.6,55,1786,5.29,5.32,3.27 +0.74,"Very Good","F","VVS2",61.5,55.1,3948,5.82,5.85,3.59 +1.02,"Good","D","SI1",56.9,62,4948,6.64,6.69,3.79 +0.63,"Ideal","E","VS1",61.9,55,2565,5.46,5.5,3.4 +0.5,"Good","F","SI1",64.3,57,975,5.03,4.94,3.21 +0.9,"Very Good","F","SI2",61.6,56,3601,6.22,6.29,3.85 +0.31,"Ideal","D","SI1",61.8,56,571,4.34,4.37,2.69 +0.72,"Ideal","F","VS1",62,56,2879,5.76,5.73,3.56 +1,"Fair","F","SI1",56.5,60,4679,6.62,6.66,3.75 +1,"Ideal","F","VVS2",61.5,55,7849,6.46,6.41,3.96 +1.51,"Ideal","J","VS1",61.3,61,8298,7.34,7.4,4.52 +2.02,"Premium","H","VS2",62.7,53,18207,8.02,7.95,0 +0.3,"Ideal","E","VS2",61.4,56,621,4.33,4.36,2.67 +1.5,"Very Good","E","SI1",61.9,59,11717,7.26,7.32,4.51 +0.25,"Very Good","G","VVS1",63.7,54,451,3.98,4.03,2.55 +0.91,"Very Good","I","VS2",63,58,3340,6.07,6.15,3.85 +0.41,"Very Good","D","SI1",63,57,717,4.64,4.7,2.94 +0.31,"Very Good","F","VS2",63.4,56,802,4.32,4.29,2.73 +0.31,"Ideal","D","VS1",61.8,55,877,4.36,4.34,2.69 +1.5,"Premium","G","VS1",61.2,59,14105,7.32,7.36,4.49 +0.5,"Ideal","E","VVS2",61.5,57,2236,5.09,5.12,3.14 +1.56,"Very Good","I","VS1",62.7,58,9857,7.42,7.37,4.64 +0.34,"Ideal","E","SI1",62.1,55,765,4.51,4.47,2.79 +0.23,"Ideal","G","VVS1",61.9,58,536,3.93,3.96,2.44 +0.55,"Ideal","F","VS2",61.7,56,1709,5.25,5.31,3.26 +1.63,"Premium","I","SI1",62,54,9256,7.67,7.6,4.73 +0.3,"Premium","F","VS2",61.5,60,776,4.29,4.26,2.63 +2.02,"Good","F","SI2",57.1,60,12615,8.31,8.25,4.73 +1,"Fair","D","SI1",65.9,54,4704,6.24,6.2,4.1 +0.41,"Ideal","F","VVS1",61.8,57,1356,4.79,4.75,2.95 +0.59,"Very Good","D","SI1",62.8,57,1743,5.32,5.38,3.36 +0.31,"Good","D","SI2",63.9,57,462,4.28,4.33,2.75 +1.62,"Premium","F","VS2",61.1,60,14961,7.57,7.56,4.62 +0.61,"Very Good","G","VS2",62,57,1861,5.44,5.47,3.38 +1.02,"Very Good","F","SI1",63.1,55,5058,6.45,6.38,4.05 +0.41,"Ideal","D","VVS2",62.3,55,1356,4.77,4.76,2.97 +1.02,"Good","H","SI2",63.7,58,3884,6.28,6.24,3.99 +0.73,"Very Good","J","VS2",62.7,57,2101,5.71,5.74,3.59 +1.01,"Very Good","F","SI1",61,57,5174,6.44,6.54,3.96 +0.51,"Good","E","VVS2",62,60.5,1980,5.05,5.08,3.15 +0.76,"Very Good","F","VVS2",62.9,58,3640,5.76,5.85,3.65 +0.41,"Very Good","E","SI2",62.8,58,638,4.69,4.73,2.96 +0.53,"Premium","F","I1",61.3,58,886,5.22,5.18,3.19 +2.02,"Premium","F","SI2",61.3,59,18274,8.15,8.11,4.98 +1.53,"Premium","G","VS1",61,60,14344,7.43,7.4,4.52 +0.35,"Very Good","E","VS1",62.3,60,829,4.5,4.52,2.81 +0.51,"Ideal","G","VVS2",61.6,56,1842,5.14,5.12,3.16 +0.57,"Premium","E","SI1",62.2,55,1590,5.36,5.31,3.32 +0.7,"Very Good","D","SI1",63.5,58,2686,5.61,5.64,3.57 +0.3,"Ideal","E","VS2",61.5,55,844,4.4,4.32,2.68 +0.53,"Ideal","F","VS1",62,55,1812,5.15,5.2,3.21 +0.42,"Ideal","F","VS1",61.3,57,1103,4.85,4.8,2.96 +0.5,"Premium","D","SI1",62.3,58,1610,5.08,5.07,3.16 +0.41,"Premium","G","VS1",61.9,60,961,4.76,4.7,2.93 +0.3,"Premium","H","VVS1",62.3,58,684,4.29,4.32,2.68 +0.3,"Ideal","H","SI1",62.9,57,554,4.27,4.22,2.67 +0.57,"Premium","G","VS2",62.6,55,1728,5.31,5.26,3.31 +0.42,"Very Good","F","SI1",63.1,56,717,4.77,4.8,3.02 +0.51,"Ideal","E","VS2",61.4,57,1656,5.13,5.16,3.16 +0.5,"Ideal","E","VS2",62.2,55,1624,5.07,5.09,3.16 +1.02,"Ideal","F","I1",61,56,3599,6.53,6.51,3.98 +0.54,"Ideal","G","SI1",62.5,56,1314,5.2,5.24,3.26 +1.05,"Premium","E","SI1",61.2,58,5433,6.57,6.53,4.01 +0.9,"Good","E","VS2",64,58,4203,6.07,6.02,3.87 +0.51,"Ideal","D","VS2",61.6,56,1787,5.15,5.17,3.18 +1.35,"Ideal","D","VS2",61.3,57,10602,7.09,7.13,4.36 +0.3,"Fair","F","SI1",64.6,56,599,4.27,4.25,2.75 +0.31,"Premium","J","SI1",60.9,60,363,4.36,4.38,2.66 +1.02,"Very Good","G","VVS2",63.1,59,7942,6.45,6.38,4.05 +1.2,"Good","I","VS1",64.8,58,5600,6.6,6.65,4.29 +0.7,"Good","E","SI1",63.3,60,2569,5.56,5.59,3.53 +1.21,"Ideal","G","VVS1",61.4,58,10483,6.85,6.89,4.22 +1.02,"Very Good","F","VS1",61.3,58,7740,6.46,6.52,3.98 +0.41,"Ideal","G","SI1",61.6,57,1110,4.77,4.81,2.95 +0.56,"Ideal","D","VS2",61.2,56,2066,5.35,5.3,3.26 +0.52,"Ideal","E","SI1",63,54,1429,5.15,5.11,3.23 +0.39,"Premium","E","VVS2",61.1,59,1129,4.68,4.74,2.88 +0.5,"Ideal","D","SI1",62.9,57,1654,5.08,5.06,3.19 +0.71,"Premium","F","VS1",61.1,58,2942,5.76,5.72,3.51 +0.96,"Fair","E","SI2",65.6,58,3533,6.11,6.15,4.02 +0.41,"Ideal","F","VVS1",61.8,57,1295,4.75,4.79,2.95 +1.57,"Ideal","G","VS2",62.7,55,12506,7.42,7.49,4.68 +0.5,"Ideal","G","VVS2",62.2,56,1842,5.08,5.11,3.17 +1.09,"Premium","H","SI1",61.8,58,4871,6.63,6.58,4.08 +0.7,"Ideal","E","VS2",62.1,55,2952,5.71,5.75,3.56 +0.39,"Very Good","J","VS1",63.1,56,790,4.7,4.62,2.94 +0.93,"Premium","E","SI2",62.9,57,3984,6.25,6.19,3.91 +1.53,"Premium","I","SI1",62.6,57,9022,7.38,7.29,4.59 +1.53,"Very Good","H","SI1",61.1,57,10468,7.44,7.45,4.55 +0.79,"Premium","E","VS2",60.6,53,2876,6.04,5.98,3.64 +1.01,"Very Good","G","VS1",63.1,57,6936,6.32,6.39,4.01 +0.5,"Ideal","F","VS2",62.9,55,1736,5.12,5.08,3.21 +0.38,"Premium","G","VS2",59.2,60,983,4.73,4.7,2.79 +0.31,"Ideal","J","VS2",62.3,54,396,4.35,4.38,2.72 +1.71,"Ideal","G","VS1",63,56,17009,7.65,7.58,4.8 +0.33,"Very Good","F","IF",58.7,55,897,4.56,4.6,2.69 +0.7,"Good","H","SI1",64.2,60,2048,5.52,5.6,3.57 +0.64,"Ideal","H","SI2",60.8,56,1125,5.57,5.61,3.4 +0.36,"Ideal","I","VS2",61.8,55,648,4.61,4.58,2.84 +1.51,"Ideal","G","VS2",62,56,13234,7.32,7.35,4.55 +0.32,"Premium","H","VVS1",62.7,57,936,4.41,4.36,2.75 +0.7,"Good","E","SI2",60.7,61,2405,5.69,5.71,3.46 +1.35,"Very Good","I","VS2",62.1,62,6961,6.97,7.05,4.35 +1.62,"Ideal","F","VS2",61.2,57,18281,7.52,7.58,4.62 +0.41,"Ideal","E","VS1",61.8,57,1153,4.79,4.76,2.95 +1,"Premium","G","SI1",60.1,61,3634,6.44,6.4,3.86 +0.35,"Very Good","H","VS1",60,57,603,4.57,4.6,2.75 +0.32,"Ideal","I","SI1",60.5,58,450,4.43,4.49,2.7 +0.56,"Ideal","E","SI1",62.8,58,1784,5.31,5.26,3.32 +0.3,"Ideal","G","SI1",60.9,57,422,4.34,4.39,2.66 +0.75,"Premium","G","VVS2",62.5,56,3486,5.84,5.78,3.63 +0.41,"Ideal","H","VVS1",62.7,54,1043,4.78,4.79,3 +0.31,"Very Good","E","VVS1",62.3,59,878,4.32,4.38,2.71 +0.31,"Ideal","D","VS1",61.8,55,683,4.34,4.36,2.69 +1.58,"Ideal","I","SI1",61.7,56,9335,7.55,7.48,4.64 +1.57,"Ideal","J","SI1",62,55.6,8035,7.43,7.47,4.62 +1.53,"Very Good","F","SI1",58.5,59,11713,7.55,7.62,4.44 +1.22,"Ideal","H","SI2",61,57,5502,6.88,6.93,4.2 +0.31,"Ideal","J","VVS1",62.4,54,461,4.32,4.35,2.7 +1.52,"Very Good","G","VS2",63.3,57,11338,7.32,7.27,4.62 +0.57,"Very Good","E","VS2",63,59,1654,5.25,5.29,3.32 +1.52,"Ideal","I","IF",62.2,57,10609,7.33,7.27,4.54 +0.41,"Premium","G","VS2",61.4,59,1061,4.79,4.75,2.93 +0.62,"Ideal","G","VS2",61.6,55,2321,5.51,5.53,3.4 +1.19,"Good","J","SI1",59.8,64,4498,6.94,6.9,4.14 +0.7,"Good","E","SI2",59.9,57,2026,5.75,5.8,3.46 +0.41,"Very Good","E","VS1",63.2,59,954,4.71,4.75,2.99 +0.3,"Very Good","E","VVS2",61.1,62,622,4.28,4.33,2.63 +1.24,"Ideal","I","SI1",62.1,56,5797,6.84,6.88,4.26 +0.8,"Good","F","VS1",59,60.9,3477,6.03,6.04,3.56 +0.7,"Ideal","H","SI1",61.4,56,2815,5.7,5.76,3.52 +0.37,"Very Good","G","VVS2",59.9,55,774,4.71,4.75,2.83 +1.51,"Ideal","H","VS1",62.6,56,11580,7.28,7.32,4.57 +0.33,"Premium","D","SI2",60.7,56,631,4.46,4.43,2.7 +0.34,"Ideal","G","SI1",61.8,54,540,4.48,4.51,2.78 +1.26,"Premium","H","SI1",62.1,57,6435,6.94,6.88,4.29 +0.61,"Premium","I","VS2",58.8,58,1308,5.59,5.53,3.27 +1,"Very Good","G","VS2",62.4,58,6449,6.31,6.38,3.96 +1.52,"Premium","I","SI1",61.9,58,8631,7.42,7.37,4.58 +0.75,"Ideal","G","VVS2",62.2,56,3879,5.78,5.82,3.61 +0.31,"Very Good","D","SI1",63.5,56,732,4.31,4.29,2.73 +0.51,"Ideal","G","VVS2",61.3,56,1902,5.16,5.19,3.17 +1.06,"Ideal","H","VS2",60.5,57,5669,6.63,6.6,4 +0.31,"Ideal","G","VS2",61.5,56,652,4.34,4.36,2.68 +0.31,"Premium","D","VVS1",62.7,58,882,4.3,4.31,2.7 +0.38,"Premium","G","IF",62.5,60,1227,4.64,4.61,2.89 +0.63,"Very Good","G","VS1",61.5,56,1960,5.53,5.49,3.39 +1,"Premium","H","VS1",62.4,58,4950,6.43,6.4,4 +0.32,"Premium","E","SI2",61.7,60,449,4.38,4.41,2.71 +0.51,"Premium","E","VS2",60.6,60,1614,5.2,5.19,3.15 +0.3,"Very Good","H","VVS2",63.1,60,776,4.28,4.24,2.69 +0.4,"Very Good","F","SI1",59.6,61,927,4.79,4.84,2.87 +0.32,"Very Good","F","VS2",61.5,59.7,624,4.32,4.39,2.68 +1,"Premium","J","I1",58.3,58,1681,6.61,6.51,3.82 +0.31,"Ideal","I","SI1",62.1,53,498,4.34,4.36,2.7 +0.72,"Premium","D","VS2",61,59,2721,5.77,5.74,3.51 +1.51,"Very Good","E","VS2",62.4,59,14709,7.26,7.36,4.56 +1.52,"Premium","H","VS2",60.6,61,9704,7.46,7.42,4.51 +0.33,"Premium","E","VS2",60.6,60,928,4.48,4.43,2.7 +1.1,"Premium","G","VS2",62.8,58,6387,6.6,6.58,4.14 +0.91,"Ideal","F","SI2",62,57,4642,6.15,6.23,3.84 +0.35,"Fair","D","VVS2",53.2,62,1011,4.87,4.8,2.57 +0.33,"Ideal","F","VVS1",61.9,55,880,4.44,4.48,2.76 +0.82,"Ideal","F","SI1",61.3,55,3439,6.06,6.08,3.72 +1.21,"Very Good","E","SI1",62.9,58,6324,6.78,6.79,4.27 +0.31,"Good","F","SI1",63.1,55,516,4.28,4.34,2.72 +0.31,"Ideal","E","IF",61,57,1319,4.36,4.39,2.67 +0.41,"Good","E","SI1",63.6,56,705,4.7,4.73,3 +0.71,"Very Good","H","VS1",63.9,60,2562,5.54,5.6,3.56 +1.54,"Ideal","G","VVS2",62,54,15415,7.36,7.43,4.59 +2.01,"Premium","F","SI2",61.3,61,16881,8.11,8.01,4.94 +0.26,"Ideal","H","VVS1",61.2,56,468,4.11,4.16,2.53 +1.2,"Premium","G","SI1",62.3,59,6586,6.84,6.75,4.23 +0.34,"Ideal","E","VVS2",60.8,58,838,4.51,4.53,2.75 +0.3,"Very Good","E","VS2",62.9,58,544,4.27,4.31,2.7 +0.34,"Ideal","G","VS2",62.7,55,596,4.48,4.49,2.81 +1.01,"Premium","H","VS1",62.7,58,5199,6.37,6.39,4 +0.31,"Fair","F","VVS1",63.1,61,740,4.32,4.37,2.74 +0.32,"Very Good","G","VVS2",61.5,54,672,4.4,4.42,2.71 +1.01,"Premium","D","SI1",61.8,60,5543,6.37,6.35,3.93 +1.02,"Good","F","SI1",63.7,61,4678,6.27,6.23,3.98 +2,"Premium","I","VS1",61.1,58,17436,8.11,8.08,4.95 +0.71,"Very Good","G","SI1",63.3,56,2274,5.66,5.69,3.59 +0.25,"Ideal","G","VVS1",62.6,56,582,4.01,4.05,2.52 +0.36,"Premium","E","VS1",61.5,59,933,4.6,4.57,2.82 +2.02,"Ideal","I","SI1",61.9,58,15942,8.07,8.18,5.03 +1,"Very Good","H","SI1",60.9,58,5287,6.43,6.46,3.93 +1.16,"Premium","H","SI2",61.8,58,4872,6.81,6.75,4.19 +1.03,"Premium","H","VS1",62.5,59,5624,6.47,6.43,4.03 +0.36,"Ideal","G","SI2",60.7,58,505,4.62,4.64,2.81 +0.3,"Very Good","G","VVS1",62.8,55,635,4.28,4.31,2.7 +0.58,"Good","E","SI1",59.3,64,1287,5.48,5.42,3.23 +0.31,"Premium","E","VS2",61,59,680,4.35,4.37,2.66 +1.62,"Ideal","I","VS1",60.8,56,11152,7.56,7.61,4.62 +0.54,"Ideal","F","VVS2",61.2,55,2333,5.27,5.25,3.22 +0.32,"Ideal","G","VVS1",62.4,56,842,4.36,4.39,2.73 +1.15,"Premium","H","SI2",59.6,59,3735,6.82,6.78,4.05 +1.2,"Very Good","H","SI1",62.9,56,6019,6.74,6.8,4.26 +0.44,"Very Good","J","VS1",63.2,57,891,4.86,4.82,3.06 +2.01,"Premium","I","SI2",62.1,60,9658,8.1,8.03,5.01 +1.52,"Premium","D","SI2",61.4,54,10308,7.51,7.43,4.59 +0.41,"Very Good","G","SI2",59.6,60,621,4.82,4.85,2.88 +0.35,"Fair","G","VS2",65.9,54,1415,5.57,5.53,3.66 +0.61,"Ideal","F","SI1",61.4,56,1681,5.46,5.42,3.34 +0.4,"Very Good","E","SI2",63.2,57,855,4.68,4.66,2.95 +2.22,"Fair","J","I1",66.7,56,5607,8.04,8.02,5.36 +0.23,"Very Good","F","VVS2",61.6,57,583,3.96,3.99,2.45 +1.54,"Premium","G","VS2",61.6,59,12308,7.46,7.4,4.58 +1.12,"Very Good","G","VS1",62.2,59,7687,6.58,6.61,4.1 +1,"Premium","E","VVS2",61.6,59,8888,6.42,6.46,3.97 +1,"Fair","E","SI1",65.1,61,4435,6.15,6.08,3.98 +1.01,"Very Good","F","SI2",60,59,4416,6.48,6.61,3.93 +0.38,"Ideal","F","SI1",60.4,57,844,4.7,4.74,2.85 +0.33,"Ideal","F","VS2",62.1,55,854,4.47,4.45,2.77 +1.1,"Very Good","D","VVS2",61.7,56,11132,6.64,6.65,4.1 +0.3,"Good","H","SI1",63.1,56,432,4.27,4.29,2.7 +0.32,"Ideal","G","IF",60.5,57,954,4.42,4.44,2.68 +0.7,"Good","D","SI1",64.2,60,2298,5.59,5.62,3.6 +0.32,"Good","D","SI1",63.1,56,589,4.34,4.38,2.75 +0.43,"Ideal","E","VS2",61.6,54,1053,4.9,4.88,3.01 +0.33,"Very Good","G","VS2",61.5,59.4,623,4.45,4.49,2.75 +1,"Very Good","G","VS1",59.1,61,6435,6.48,6.54,3.85 +0.3,"Good","G","VS1",63.1,58,605,4.24,4.28,2.69 +0.9,"Good","G","VS1",63.7,56,4460,6.15,6.07,3.89 +0.33,"Ideal","E","VVS1",60.7,57,906,4.46,4.5,2.72 +0.9,"Good","E","SI2",63.4,62,3139,6,6.02,3.81 +1.14,"Very Good","H","SI2",63.3,57,4615,6.6,6.63,4.19 +0.3,"Ideal","F","VVS1",61.5,56,1041,4.32,4.36,2.67 +0.31,"Ideal","H","VS1",61.7,57,698,4.34,4.32,2.67 +0.92,"Ideal","H","IF",62.5,55,5758,6.25,6.3,3.92 +0.44,"Premium","F","VVS2",61.6,58,1253,4.89,4.85,3 +0.71,"Fair","F","SI2",65.2,55.5,2103,5.52,5.58,3.62 +1.5,"Very Good","E","SI2",62.8,57,8538,7.17,7.23,4.52 +1.2,"Ideal","E","VVS2",61.5,57,11883,6.79,6.89,4.21 +0.23,"Very Good","E","VVS1",63.3,57,485,3.88,3.95,2.48 +0.93,"Premium","G","VS1",62.1,59,4793,6.21,6.16,3.84 +1.03,"Very Good","D","SI2",61.8,60,4478,6.42,6.45,3.98 +0.7,"Premium","I","VS1",62.9,61,2234,5.64,5.62,3.54 +1.59,"Ideal","J","SI1",62.4,55,8325,7.48,7.45,4.66 +1.21,"Very Good","H","VS1",62.6,58,7445,6.71,6.75,4.21 +0.7,"Premium","G","VS2",59.4,59,2657,5.79,5.76,3.43 +0.32,"Ideal","G","VS2",61.5,57,720,4.41,4.4,2.71 +1.52,"Premium","H","SI1",62,60,7559,7.36,7.28,4.54 +0.31,"Very Good","G","SI1",61.9,56,462,4.34,4.38,2.7 +0.9,"Very Good","F","SI2",62,61,3770,6.14,6.16,3.81 +0.24,"Premium","H","VVS2",60.7,58,554,4.07,4.04,2.46 +0.31,"Ideal","H","VS2",61.4,56,507,4.38,4.42,2.7 +0.4,"Ideal","F","VVS2",62.8,57,1163,4.73,4.66,2.95 +0.36,"Premium","E","VVS1",62.4,56,1035,4.57,4.53,2.84 +0.7,"Very Good","E","SI1",62.3,58,2476,5.6,5.67,3.51 +0.29,"Good","F","VS1",62.1,56,415,4.24,4.26,2.64 +0.7,"Premium","J","VS2",61.2,60,1940,5.73,5.7,3.5 +1,"Premium","D","SI1",62.3,60,4469,6.23,6.19,3.87 +0.4,"Premium","D","VS1",62.1,58,1123,4.7,4.73,2.93 +0.33,"Ideal","H","VS1",62,55,579,4.44,4.46,2.76 +0.35,"Ideal","F","VS2",60.8,57,706,4.52,4.56,2.76 +0.31,"Ideal","D","IF",61.1,56,1251,4.39,4.42,2.69 +1.26,"Very Good","G","SI1",63.3,58,7910,6.88,6.84,4.34 +0.41,"Ideal","D","VS2",61.7,55,1177,4.8,4.76,2.95 +0.71,"Ideal","F","SI1",59.8,53,2838,5.86,5.82,3.49 +0.32,"Ideal","E","VS2",62.1,56,702,4.4,4.43,2.74 +0.5,"Very Good","D","VS1",62,56,1750,5.09,5.11,3.16 +0.35,"Ideal","D","VS2",62.3,55,829,4.52,4.54,2.82 +0.36,"Ideal","G","SI1",61.4,55,571,4.61,4.64,2.84 +0.24,"Very Good","F","VS1",62.9,59,393,3.95,3.97,2.49 +1.56,"Ideal","J","SI2",62.1,55,5766,7.45,7.41,4.62 +1.01,"Premium","F","SI2",58.8,61,4468,6.53,6.46,3.82 +1.03,"Premium","E","VS1",61.5,58,7614,6.55,6.43,3.99 +0.85,"Premium","F","VVS2",61.2,60,4451,6.13,6.1,3.74 +0.32,"Ideal","I","VVS1",61.4,56,575,4.42,4.44,2.72 +0.51,"Good","H","SI1",63.7,56,1119,5.07,5.1,3.24 +0.42,"Premium","E","SI1",61.5,58,722,4.78,4.84,2.96 +0.71,"Ideal","F","VS1",62.1,57,3066,5.73,5.76,3.57 +0.56,"Ideal","H","VS1",61.8,55,1616,5.3,5.34,3.29 +0.53,"Very Good","E","VS1",58.5,61,1852,5.28,5.39,3.12 +0.38,"Ideal","G","VVS2",60,56,879,4.72,4.76,2.84 +1.01,"Premium","G","VS2",58.5,61,6108,6.57,6.52,3.83 +0.36,"Premium","E","SI2",61.5,58,648,4.61,4.56,2.82 +0.35,"Ideal","H","VVS2",59.2,56,906,4.65,4.6,2.74 +0.53,"Very Good","D","SI1",61.4,57,1631,5.2,5.26,3.21 +0.3,"Premium","I","VS1",61.7,59,608,4.3,4.26,2.64 +0.91,"Good","E","I1",57.7,63,2342,6.35,6.3,3.65 +0.33,"Ideal","G","VVS1",61.8,55,1114,4.45,4.42,2.74 +0.58,"Ideal","H","VS2",62.4,58,1600,5.3,5.34,3.32 +0.9,"Premium","J","SI1",60.9,61,2873,6.26,6.22,3.8 +1.05,"Ideal","F","VS1",62.3,55,8100,6.53,6.5,4.06 +1.18,"Premium","G","VVS2",59.7,58,9366,6.9,6.94,4.13 +0.52,"Ideal","G","VS1",61.6,56,1722,5.18,5.22,3.2 +1.1,"Very Good","E","SI2",60,58,4539,6.72,6.75,4.04 +0.49,"Premium","E","VS2",58.8,59,1351,5.2,5.14,3.04 +0.53,"Very Good","G","SI1",63.4,54,1161,5.09,5.13,3.24 +0.52,"Ideal","G","VVS1",61.9,54.4,1936,5.15,5.18,3.2 +0.41,"Very Good","H","SI1",62.9,58,683,4.72,4.73,2.97 +0.42,"Premium","F","VVS2",60.3,59,1142,4.83,4.86,2.92 +0.72,"Ideal","F","VS2",60.3,56,2724,5.84,5.81,3.51 +0.92,"Ideal","F","SI2",61.5,56,3763,6.27,6.32,3.87 +0.7,"Premium","G","SI1",62.6,60,2415,5.61,5.57,3.5 +0.39,"Ideal","G","VS1",62,55,1077,4.71,4.66,2.9 +0.73,"Ideal","H","VVS2",61.6,56,2846,5.79,5.84,3.58 +0.74,"Very Good","F","VS1",61.7,57,3226,5.79,5.85,3.59 +0.53,"Good","D","VS1",60.2,56,1775,5.22,5.28,3.16 +0.88,"Ideal","D","SI2",62.2,56,3962,6.12,6.16,3.82 +0.9,"Premium","G","VS2",62.1,59,4259,6.2,6.14,3.83 +0.51,"Very Good","H","VS2",60.8,58,1414,5.12,5.17,3.13 +1.01,"Fair","E","SI1",64.7,59,4181,6.23,6.11,3.99 +0.7,"Very Good","D","SI1",63.4,58,2734,5.63,5.66,3.58 +0.41,"Premium","G","VS1",60.2,59,961,4.84,4.79,2.9 +1.2,"Premium","H","SI2",62.8,61,4973,6.7,6.62,4.18 +0.4,"Ideal","F","VS2",61,62,867,4.71,4.74,2.88 +0.9,"Very Good","E","VS2",63,57,4643,6.07,6.15,3.85 +1,"Very Good","F","SI2",61.7,58,3789,6.32,6.36,3.91 +1.58,"Ideal","I","SI2",60.9,59,9973,7.48,7.55,4.58 +0.73,"Ideal","D","SI1",61.5,56,2858,5.84,5.8,3.58 +0.27,"Very Good","H","VVS1",61.2,57,504,4.15,4.18,2.55 +1.31,"Very Good","J","VS1",63.7,55,6101,6.94,7.01,4.44 +0.73,"Premium","D","SI1",61.7,55,2821,5.84,5.82,3.6 +0.53,"Ideal","G","VS1",62.4,54,1659,5.18,5.21,3.24 +0.3,"Premium","G","SI2",62.3,59,394,4.25,4.29,2.66 +0.74,"Ideal","G","VS2",62.9,54,2723,5.81,5.78,3.64 +0.61,"Premium","F","VVS2",59.7,58,2392,5.56,5.53,3.31 +0.7,"Fair","G","VS1",68.5,58,2250,5.47,5.34,3.7 +0.47,"Premium","G","VS2",61,59,1116,5.03,5,3.06 +0.44,"Ideal","G","IF",61.3,55,1378,4.91,4.95,3.02 +1.55,"Ideal","I","VS1",61.9,55,10869,7.43,7.46,4.61 +0.42,"Ideal","D","SI1",62.4,57,1040,4.84,4.77,3 +0.5,"Ideal","D","VVS2",60.7,57,2376,5.2,5.15,3.14 +0.91,"Premium","D","SI2",62.2,59,4051,6.23,6.19,3.86 +1.61,"Very Good","E","SI2",63,59.9,10891,7.42,7.45,4.68 +1.5,"Very Good","H","SI2",62.3,60,7775,7.28,7.22,4.52 +0.31,"Ideal","G","VVS2",61.3,56,687,4.37,4.41,2.69 +0.44,"Premium","H","VS2",61.3,58,810,4.88,4.91,3 +1.01,"Ideal","G","SI1",62.9,57,4004,6.37,6.3,3.98 +1.04,"Ideal","E","SI2",62.3,55,5531,6.46,6.49,4.03 +0.34,"Very Good","I","SI1",61.7,56,459,4.51,4.54,2.79 +1.08,"Ideal","G","VS2",62.5,56,6530,6.57,6.54,4.1 +1.51,"Premium","J","SI2",59.7,62,5327,7.46,7.42,4.44 +1.01,"Ideal","E","SI2",61.5,55,5437,6.44,6.51,3.98 +1.72,"Good","J","SI2",63.2,57,7741,7.56,7.6,4.79 +0.92,"Premium","G","VS2",61.6,62,4287,6.3,6.24,3.86 +1.07,"Ideal","F","VS2",61.7,57,8640,6.52,6.54,4.03 +1.03,"Good","D","SI2",59.3,58,4671,6.57,6.61,3.91 +0.35,"Ideal","F","IF",60.9,55,1312,4.58,4.61,2.8 +0.95,"Fair","F","SI2",56,60,2815,6.62,6.53,3.68 +2.07,"Premium","H","SI1",61.2,60,14476,8.2,8.12,4.99 +0.38,"Premium","G","VS1",60.6,58,1069,4.67,4.64,2.82 +0.9,"Good","D","SI1",63.2,62,4068,6.06,6.13,3.85 +0.52,"Ideal","H","VS2",61.8,56,1573,5.19,5.16,3.2 +1.5,"Premium","H","SI1",61.4,58,10080,7.41,7.28,4.51 +1.53,"Premium","G","VS2",61.8,59,12717,7.45,7.31,4.56 +0.41,"Very Good","H","SI1",62.8,56,683,4.72,4.77,2.98 +1.96,"Very Good","H","SI2",62.7,58,13099,7.86,7.93,4.95 +0.26,"Very Good","F","VVS1",61.7,57,657,4.09,4.13,2.53 +0.33,"Ideal","G","VS1",61.6,57,699,4.46,4.49,2.75 +0.79,"Very Good","F","SI1",61.5,58,3047,5.94,5.97,3.66 +0.71,"Premium","G","SI2",58.2,60,1902,5.91,5.88,3.43 +0.31,"Ideal","D","SI1",62.9,56,732,4.34,4.31,2.72 +0.56,"Very Good","D","SI1",63.1,57,1777,5.22,5.19,3.29 +1.56,"Ideal","H","SI1",60.4,59,10642,7.5,7.53,4.54 +0.52,"Ideal","E","VVS2",62.3,57,2116,5.12,5.15,3.2 +0.52,"Ideal","E","VS2",60.9,57,1815,5.23,5.21,3.18 +0.92,"Ideal","D","SI1",62.2,56,4561,6.23,6.27,3.89 +0.34,"Ideal","F","VVS2",61.8,56,914,4.49,4.47,2.77 +0.32,"Ideal","H","VVS2",61.9,53,619,4.42,4.44,2.74 +1.01,"Premium","H","SI2",61.1,59,4242,6.54,6.46,3.97 +0.31,"Ideal","I","VS1",62.8,55,628,4.35,4.31,2.72 +1.1,"Ideal","H","SI1",61.5,56,6844,6.61,6.65,4.08 +0.3,"Ideal","D","SI1",62.2,56,552,4.25,4.3,2.66 +2.01,"Ideal","G","SI1",61.6,57,12829,8.08,8,4.95 +0.54,"Ideal","G","VVS1",61.8,55,2236,5.27,5.24,3.25 +1.27,"Ideal","I","SI1",62.4,56,5690,6.95,6.9,4.32 +1.06,"Premium","G","VVS2",59.6,58,8003,6.61,6.65,3.95 +0.27,"Premium","H","VVS2",60.7,59,623,4.21,4.19,2.55 +0.74,"Ideal","G","VVS1",61.9,54,3402,5.8,5.84,3.6 +1.13,"Very Good","F","SI2",59.1,59,5014,6.81,6.87,4.04 +0.46,"Premium","E","VS2",58.5,61,1173,5.1,5.05,2.97 +0.3,"Ideal","G","VVS2",62.7,57,684,4.26,4.29,2.68 +1.35,"Premium","I","SI1",59.2,59,6577,7.24,7.18,4.27 +0.42,"Ideal","D","SI1",62,55,810,4.83,4.84,3 +1.52,"Good","J","SI1",63.6,60,7022,7.25,7.21,4.6 +0.96,"Premium","G","SI1",62,57,3355,6.34,6.31,3.92 +1.2,"Very Good","H","SI2",61.5,58,5884,6.78,6.84,4.19 +0.77,"Ideal","F","SI1",61.5,55,3321,5.88,5.92,3.63 +0.94,"Good","D","SI2",57.9,61,3125,6.48,6.43,3.74 +0.43,"Premium","F","SI1",62.9,60,1016,4.8,4.77,3.01 +0.33,"Ideal","D","VS1",61.1,57,727,4.46,4.48,2.73 +1.03,"Fair","G","SI2",65.6,58,3765,6.3,6.26,4.12 +0.33,"Good","D","VS2",63.5,56,625,4.36,4.4,2.78 +0.31,"Ideal","D","VS2",60.4,56,942,4.42,4.39,2.66 +0.71,"Ideal","E","VS1",62.4,54,2923,5.71,5.74,3.57 +0.32,"Ideal","F","VS1",62,54,876,4.44,4.43,2.75 +1.05,"Very Good","H","SI2",63,59,4158,6.44,6.48,4.07 +0.33,"Very Good","F","VVS1",61.1,58,912,4.42,4.46,2.71 +1.55,"Ideal","J","VS2",61.4,55,8498,7.41,7.49,4.58 +1.01,"Ideal","E","SI2",62,56,4694,6.46,6.42,3.99 +0.51,"Ideal","F","VVS1",60.9,57,2208,5.16,5.21,3.16 +0.34,"Ideal","H","VS2",61.5,54,689,4.54,4.5,2.78 +0.59,"Ideal","I","VVS1",61,55,1742,5.43,5.48,3.33 +0.7,"Good","E","VS2",61.5,61,2473,5.64,5.74,3.5 +1.21,"Ideal","I","VS1",61.8,56,7037,6.83,6.87,4.23 +0.31,"Ideal","H","VVS1",61.8,57,907,4.35,4.32,2.68 +0.32,"Premium","G","VS1",62.1,58,828,4.39,4.37,2.72 +0.71,"Ideal","I","VS2",61.5,55,2878,5.76,5.78,3.55 +1.5,"Premium","H","SI1",62.4,58,9697,7.33,7.28,4.56 +0.36,"Good","E","VVS1",58.2,56,923,4.68,4.74,2.74 +2.3,"Premium","I","SI2",61.3,58,11051,8.53,8.46,5.21 +0.41,"Good","E","SI2",63.5,55,638,4.69,4.73,2.99 +0.91,"Premium","J","SI1",62.8,59,2905,6.19,6.14,3.87 +0.32,"Ideal","H","VS2",62,55,505,4.39,4.42,2.73 +0.3,"Ideal","E","VS1",61.9,56,670,4.28,4.31,2.66 +1.02,"Premium","D","SI2",59.5,62,4912,6.56,6.52,3.89 +1.01,"Good","F","SI2",65.7,58,4049,6.12,6.2,4.05 +0.74,"Good","E","SI1",62.8,61,2906,5.74,5.76,3.61 +0.77,"Ideal","H","VS1",61.3,56,3468,5.91,5.97,3.64 +0.53,"Ideal","J","VS1",61.4,55.2,1218,5.2,5.22,3.2 +0.32,"Ideal","D","VS2",62.7,57,972,4.44,4.4,2.77 +2,"Premium","H","SI2",61.4,59,11108,8.07,8,4.93 +0.98,"Premium","F","SI2",62.3,56,3485,6.44,6.35,3.98 +0.9,"Premium","G","SI1",62.7,59,3774,6.14,6.1,3.84 +0.32,"Ideal","D","VVS1",61.8,56,1067,4.39,4.41,2.72 +0.53,"Ideal","D","VS2",61,56,1783,5.29,5.26,3.22 +0.34,"Ideal","E","SI1",61.7,56,596,4.49,4.52,2.78 +1.13,"Ideal","D","VVS2",60.1,57,12261,6.83,6.78,4.09 +0.55,"Premium","G","VS1",62,57,1881,5.3,5.25,3.27 +0.3,"Very Good","D","VS2",62.8,59,710,4.26,4.28,2.68 +0.45,"Ideal","J","VVS1",61.9,56,978,4.93,4.95,3.06 +1.06,"Ideal","G","VVS1",61.6,57,8643,6.55,6.53,4.03 +1.2,"Premium","H","SI1",61.2,57,6129,6.91,6.78,4.19 +0.31,"Ideal","G","VVS1",62.5,55,816,4.33,4.34,2.71 +0.41,"Good","G","SI2",63.6,54,784,4.74,4.7,3 +0.91,"Ideal","E","SI1",61.9,55,5458,6.21,6.23,3.85 +0.6,"Very Good","G","SI1",63.5,59.9,1565,5.28,5.3,3.36 +0.25,"Very Good","E","VVS1",60.2,59,575,4.11,4.13,2.48 +0.61,"Very Good","I","VVS2",62,54.4,1773,5.47,5.51,3.4 +1,"Fair","I","I1",66.9,57,1997,6.15,6.03,4.09 +1,"Premium","F","SI1",62.1,59,5152,6.39,6.36,3.96 +2.1,"Ideal","I","SI1",61.6,57,12168,8.24,8.15,5.05 +0.51,"Premium","D","SI1",61.9,60,1642,5.15,5.12,3.18 +1.03,"Premium","E","VS2",60,59,6344,6.54,6.6,3.94 +0.75,"Premium","E","VS2",59.9,61,3108,5.97,5.91,3.56 +0.31,"Very Good","E","SI1",63.4,55,698,4.33,4.32,2.74 +0.7,"Very Good","F","VVS1",63,60,3261,5.59,5.62,3.53 +0.25,"Premium","E","VS1",61.5,60,558,4.04,4.02,2.48 +0.36,"Premium","G","VS1",59.7,56,932,4.67,4.64,2.78 +0.47,"Premium","H","VS1",61.8,58,1143,4.94,4.99,3.07 +0.39,"Very Good","I","VS2",59.6,57,712,4.77,4.82,2.86 +1.13,"Very Good","H","SI1",60.1,60,4959,6.73,6.77,4.06 +2.05,"Very Good","J","VS1",61.4,58.5,16641,8.13,8.16,5 +2.12,"Premium","G","I1",60,58,7508,8.39,8.28,4.99 +0.7,"Premium","G","VVS2",60.2,61,2999,5.74,5.66,3.43 +1.04,"Ideal","F","I1",61.6,57,3718,6.51,6.46,4 +0.54,"Ideal","D","VVS1",61.2,57,3494,5.25,5.27,3.22 +0.8,"Ideal","D","SI1",62.6,55,3597,5.91,5.94,3.71 +2.22,"Good","I","SI2",63.2,57,16398,8.23,8.28,5.22 +0.7,"Very Good","E","SI1",61.9,60,2496,5.6,5.67,3.49 +1.09,"Ideal","H","VS2",61.3,56,6288,6.57,6.63,4.05 +0.91,"Very Good","H","SI1",62.8,58,3734,6.13,6.16,3.86 +1.41,"Premium","E","VS2",62.7,56,11644,7.18,7.1,4.48 +1.02,"Premium","F","SI2",61,58,4043,6.49,6.52,3.97 +0.31,"Ideal","D","SI1",61.9,57,548,4.36,4.39,2.71 +1.22,"Very Good","F","VVS2",60.7,62,10719,6.81,6.84,4.14 +0.38,"Ideal","E","VVS1",61.9,56,1267,4.64,4.67,2.88 +0.3,"Ideal","E","SI1",61.6,54,499,4.32,4.35,2.67 +0.31,"Premium","D","VS2",60.7,59,942,4.38,4.35,2.65 +2.02,"Ideal","J","SI1",59.8,60,12713,8.21,8.16,4.9 +0.5,"Premium","I","VVS1",62.8,61,1556,5.05,4.98,3.15 +0.72,"Premium","G","VS2",62.3,57,2550,5.74,5.69,3.56 +0.31,"Very Good","G","VVS2",62.9,58,707,4.27,4.31,2.7 +0.38,"Ideal","G","VVS1",61.2,54,949,4.69,4.72,2.88 +1.51,"Good","G","IF",62.8,60,14654,7.18,7.24,4.53 +0.5,"Very Good","D","SI2",63.1,56,1015,5.05,4.96,3.16 +1.02,"Premium","H","SI1",61.9,61,4558,6.42,6.34,3.95 +0.32,"Premium","H","VVS2",62.3,58,828,4.37,4.33,2.71 +0.72,"Premium","H","VS2",61.7,56,2316,5.77,5.73,3.55 +1.06,"Premium","I","SI2",60.9,58,4096,6.6,6.56,4.01 +0.84,"Good","F","I1",60.8,64,1749,6.05,6.03,3.67 +0.58,"Very Good","H","SI1",61.8,56,1219,5.34,5.38,3.31 +0.54,"Very Good","F","SI1",63.3,56,1389,5.24,5.21,3.31 +1.09,"Premium","G","VS2",62.1,57,5098,6.6,6.55,4.08 +0.23,"Very Good","E","VVS1",63.5,54,530,3.92,3.95,2.5 +2.43,"Fair","G","SI2",64.5,57,14975,8.41,8.36,5.41 +0.3,"Ideal","H","SI1",62.4,53.7,442,4.29,4.31,2.68 +0.31,"Very Good","G","VS2",62.9,57,544,4.31,4.34,2.72 +0.48,"Very Good","E","SI1",62.7,58.5,1349,4.99,5.01,3.14 +0.9,"Very Good","G","VS2",63.5,62,4081,6.07,6.11,3.87 +0.36,"Ideal","F","SI1",61.5,57,770,4.59,4.55,2.81 +0.29,"Premium","E","SI1",58.4,60,548,4.34,4.32,2.53 +2.01,"Good","I","SI2",64.6,57,12681,7.82,7.88,5.07 +0.4,"Premium","G","SI1",59.6,61,840,4.76,4.74,2.83 +0.32,"Premium","G","SI1",62.6,58,612,4.37,4.35,2.73 +0.52,"Premium","E","VS2",60.6,58,1622,5.23,5.2,3.16 +0.4,"Ideal","J","IF",62.6,56,1063,4.75,4.71,2.96 +1.54,"Premium","G","SI2",61.6,58,7287,7.45,7.3,4.57 +1.13,"Ideal","I","VS2",62.3,56,5031,6.73,6.63,4.16 +0.3,"Premium","I","VVS1",62.2,58,709,4.31,4.28,2.67 +0.7,"Premium","D","SI2",62.1,60,2319,5.73,5.71,3.55 +0.31,"Ideal","F","VS1",62.1,56,680,4.32,4.35,2.69 +0.31,"Ideal","F","IF",62.1,56,979,4.33,4.36,2.7 +0.34,"Ideal","G","VS2",61.7,56,596,4.48,4.53,2.78 +0.81,"Premium","J","VS2",60.6,60,2129,6.04,6,3.65 +0.34,"Ideal","F","VS1",60.9,57,723,4.53,4.56,2.77 +0.31,"Premium","E","VVS1",61.8,59,1012,4.33,4.31,2.67 +0.9,"Good","E","SI2",59.9,61,3660,6.16,6.2,3.7 +0.55,"Ideal","D","VS2",62.8,57,1894,5.27,5.24,3.3 +0.42,"Ideal","E","SI2",62.7,55.2,687,4.78,4.79,3 +0.81,"Very Good","G","VS2",63.1,58,2994,5.88,5.84,3.7 +0.51,"Premium","G","VVS1",60.2,58,1925,5.2,5.24,3.14 +0.4,"Good","J","VS1",64,56,734,4.69,4.66,2.99 +0.77,"Very Good","I","VS1",62.6,55,2501,5.85,5.9,3.68 +0.4,"Fair","E","VVS2",57.3,60,1069,4.84,4.89,2.79 +0.53,"Ideal","I","SI2",61.8,54,947,5.22,5.24,3.23 +1.21,"Premium","G","VVS1",60.1,61,9003,6.92,6.85,4.14 +1.02,"Premium","H","I1",62.5,60,3141,6.39,6.41,4 +2.14,"Premium","I","VS2",59.3,59,15559,8.43,8.39,5 +1.31,"Very Good","F","VS1",59.1,60,9797,7.13,7.18,4.23 +0.41,"Premium","D","SI2",62.3,58,876,4.77,4.74,2.96 +0.57,"Good","D","VS2",58.3,61,2015,5.42,5.45,3.17 +1.3,"Premium","D","SI2",61.5,58,7044,6.98,6.91,4.27 +0.41,"Premium","H","SI1",60,61,876,4.83,4.77,2.88 +0.31,"Good","G","VS1",63.2,57,625,4.28,4.33,2.72 +0.54,"Very Good","F","VS2",60.9,55,1639,5.25,5.31,3.21 +0.43,"Good","G","SI2",58.8,61,661,4.92,4.94,2.9 +0.58,"Ideal","D","SI2",61.7,54,1356,5.4,5.43,3.34 +1.03,"Premium","E","VS2",62.5,59,6072,6.42,6.44,4.02 +0.31,"Ideal","F","VVS1",61.8,56,897,4.34,4.36,2.69 +0.35,"Premium","G","VS1",62.6,56,845,4.52,4.49,2.82 +0.31,"Ideal","G","IF",61.9,54,891,4.35,4.38,2.7 +0.71,"Ideal","I","SI1",62.6,54,2111,5.68,5.73,3.57 +1.09,"Premium","I","VS2",61.3,58,4659,6.63,6.58,4.05 +1.08,"Premium","H","VS1",62.5,60,5111,6.55,6.51,4.08 +0.32,"Very Good","G","VS2",59.9,57,561,4.47,4.51,2.69 +0.98,"Fair","G","SI2",66.6,56,3332,6.12,6.02,4.04 +0.41,"Ideal","F","IF",62.3,55,1439,4.78,4.82,2.99 +0.33,"Ideal","D","VVS2",60.9,57,955,4.46,4.48,2.72 +1.01,"Ideal","E","VVS1",62,57,10954,6.39,6.45,3.98 +0.46,"Good","I","VVS1",63.5,57,1089,4.85,4.91,3.1 +1.02,"Ideal","G","VS2",62.6,57,5816,6.41,6.43,4.02 +1.26,"Premium","I","SI2",60.1,59,5151,7,6.91,4.18 +1.07,"Good","J","VS2",61.7,57.7,4602,6.55,6.58,4.05 +1.51,"Premium","E","SI1",62.9,62,9647,7.31,7.21,4.57 +0.61,"Ideal","F","VVS2",62.2,55,2634,5.42,5.45,3.38 +1.23,"Ideal","H","SI2",62.1,55.9,6088,6.82,6.85,4.24 +1.47,"Premium","G","SI2",61.8,58,7557,7.28,7.22,4.48 +1.71,"Premium","H","SI1",58.1,59,9193,7.88,7.81,4.56 +2.01,"Premium","H","SI1",61.3,59,17849,8.16,8.08,4.98 +0.9,"Very Good","F","SI1",62.3,55,3950,6.14,6.18,3.84 +1.06,"Ideal","H","SI1",62.7,57,4196,6.53,6.48,4.08 +0.37,"Ideal","H","VVS1",61.4,55,815,4.64,4.67,2.86 +0.33,"Ideal","F","VVS2",61.4,57,824,4.43,4.46,2.73 +3.01,"Good","I","SI2",63.9,60,18242,9.06,9.01,5.77 +0.41,"Ideal","J","VS1",62.2,54.5,674,4.75,4.76,2.96 +0.58,"Ideal","H","VVS1",61.6,56,2006,5.35,5.39,3.31 +1.23,"Ideal","I","VS1",61.5,56,6435,6.86,6.89,4.23 +1.51,"Premium","F","SI1",62.2,58,11374,7.32,7.27,4.54 +1.01,"Fair","I","VS2",68.7,58,3597,6.14,6,4.19 +0.39,"Premium","J","VS1",61.6,59,616,4.67,4.71,2.89 +0.34,"Ideal","G","VVS1",62.5,53,956,4.49,4.47,2.8 +0.5,"Ideal","G","SI1",60.2,57,1857,5.16,5.2,3.12 +0.24,"Ideal","F","VS2",61.8,57,417,3.97,4.02,2.47 +1.5,"Fair","H","SI2",59.3,58,7098,7.31,7.37,4.35 +0.62,"Very Good","D","VS2",59.2,59.1,2311,5.55,5.6,3.3 +0.39,"Ideal","E","IF",62.5,57,1248,4.7,4.74,2.95 +0.53,"Ideal","F","VVS2",62.3,56,2045,5.24,5.2,3.25 +1.66,"Ideal","I","VS2",62.3,54,11156,7.58,7.61,4.73 +0.52,"Ideal","E","VVS2",61.8,56,2430,5.15,5.18,3.19 +0.38,"Ideal","E","VVS2",59.9,61,1008,4.71,4.74,2.83 +1.06,"Good","I","SI2",58.7,60,3842,6.65,6.71,3.92 +1,"Good","E","SI2",61,61,4394,6.37,6.44,3.91 +1.01,"Ideal","E","SI2",59.2,56,4751,6.63,6.59,3.91 +0.41,"Ideal","G","SI2",61.7,56,648,4.79,4.81,2.96 +0.91,"Premium","F","SI1",61.7,59,4036,6.21,6.17,3.82 +1.09,"Premium","G","IF",61.3,58,10065,6.64,6.6,4.06 +0.32,"Ideal","F","IF",61.2,56,1204,4.41,4.45,2.71 +1.13,"Premium","H","SI2",59.4,58,4350,6.74,6.8,4.02 +1.11,"Premium","D","SI1",62,58,6962,6.68,6.64,4.13 +0.5,"Good","J","VS2",63.2,60,965,5.01,5.06,3.18 +0.36,"Premium","E","VS2",61.3,60,1013,4.59,4.54,2.8 +0.41,"Premium","H","SI1",62.6,59,876,4.77,4.72,2.97 +1,"Premium","G","VS1",60.9,60,6000,6.51,6.41,3.91 +0.26,"Good","H","VVS2",63.3,58,468,4.04,4.08,2.57 +0.23,"Very Good","D","VVS2",62.5,58,492,3.89,3.92,2.44 +0.7,"Good","I","VS2",59.4,57,2234,5.77,5.82,3.44 +0.72,"Ideal","G","SI2",62.6,52,2295,5.74,5.77,3.6 +1.04,"Ideal","D","VS1",59.1,56,8341,6.65,6.59,3.91 +2.22,"Very Good","I","SI1",62.4,55,17160,8.29,8.35,5.19 +1.5,"Fair","G","SI1",64.5,57,10352,7.15,7.09,4.59 +0.32,"Good","D","SI2",63.9,58,612,4.33,4.31,2.76 +1.14,"Ideal","G","VS1",61.8,55,8121,6.71,6.76,4.16 +1.41,"Very Good","J","VS1",59.4,59,7636,7.34,7.38,4.37 +0.3,"Ideal","F","VVS1",61.9,57,814,4.3,4.32,2.67 +2.11,"Premium","J","SI2",62,60,11663,8.19,8.24,5.09 +0.74,"Very Good","G","SI1",63.5,60,2468,5.73,5.68,3.62 +1.01,"Very Good","F","VVS2",59.8,58,8212,6.47,6.55,3.89 +1,"Good","F","VVS2",56.5,63,7016,6.65,6.62,3.75 +0.53,"Very Good","F","VS1",61.5,59,1821,5.19,5.22,3.2 +0.42,"Premium","G","SI1",61.7,58,945,4.8,4.76,2.95 +0.67,"Premium","D","SI2",62.9,56,1819,5.65,5.6,3.54 +1.18,"Good","D","SI2",60.7,63,5168,6.77,6.81,4.12 +0.88,"Very Good","E","SI2",59.1,58,3150,6.22,6.3,3.7 +1.08,"Premium","F","SI2",60.2,59,4488,6.65,6.6,3.99 +0.67,"Very Good","I","IF",61.4,56,2066,5.59,5.65,3.45 +0.52,"Ideal","G","VS1",62.7,56,1689,5.14,5.16,3.23 +0.51,"Ideal","D","VS1",60.7,57,1826,5.18,5.23,3.16 +1.5,"Ideal","H","VS1",61,56.8,11557,7.36,7.4,4.5 +0.29,"Ideal","H","VVS2",61.6,55,607,4.27,4.29,2.64 +0.57,"Ideal","D","SI1",61.4,55,1810,5.35,5.34,3.28 +0.4,"Premium","H","VVS2",60.9,58,1125,4.79,4.74,2.9 +2.01,"Ideal","I","VS2",64.8,55,15729,7.91,7.87,5.12 +0.4,"Ideal","D","VVS2",62.2,55,1263,4.72,4.74,2.94 +0.3,"Ideal","D","SI2",63,55,574,4.26,4.25,2.68 +1.01,"Premium","H","VS2",61.5,59,5303,6.48,6.49,3.99 +1.01,"Very Good","F","VS2",59.9,61,5988,6.46,6.5,3.88 +0.34,"Very Good","G","VS1",61.7,60,686,4.45,4.49,2.76 +0.7,"Very Good","F","SI1",60.3,57,2343,5.73,5.77,3.47 +1.25,"Premium","D","SI1",62.4,58,7924,6.89,6.83,4.28 +1.52,"Premium","G","I1",61.7,58,3820,7.43,7.34,4.56 +0.54,"Premium","D","SI1",62.6,57,1650,5.21,5.12,3.23 +0.52,"Ideal","G","VVS1",60.6,57,2387,5.21,5.26,3.17 +1,"Premium","E","VS2",61.8,59,6600,6.38,6.41,3.95 +1.23,"Ideal","H","SI2",60.6,57,5951,6.98,6.94,4.22 +0.38,"Ideal","D","VVS2",61.3,56,1257,4.73,4.63,2.87 +0.42,"Premium","G","VVS1",60.2,59,1235,4.84,4.82,2.91 +0.77,"Ideal","D","VS2",61.1,57,3837,5.93,5.96,3.63 +0.3,"Premium","F","VS2",61.1,59,605,4.29,4.32,2.63 +0.32,"Ideal","I","VVS2",61.5,56,561,4.4,4.42,2.71 +0.32,"Ideal","G","VVS2",62.4,56,936,4.42,4.4,2.75 +0.9,"Good","F","SI1",64,59,3696,5.97,5.99,3.83 +2.01,"Premium","J","VS1",60.2,61,12963,8.23,8.16,4.93 +0.44,"Premium","D","VS1",60.2,59,1232,4.93,4.91,2.96 +1.21,"Fair","H","SI1",69.6,55,3862,6.49,6.42,4.49 +0.36,"Premium","I","VS1",60.3,60,729,4.64,4.58,2.78 +1.53,"Very Good","F","VS1",60.3,58,15079,7.48,7.51,4.52 +0.3,"Ideal","E","VS2",61.8,56,844,4.34,4.3,2.67 +1.63,"Premium","I","VS2",61,60,10479,7.62,7.59,4.64 +1.27,"Premium","H","VS2",62.1,60,7219,6.94,6.88,4.29 +0.48,"Very Good","D","IF",60.6,55,2677,5.08,5.12,3.09 +0.4,"Ideal","F","IF",61.9,54,1406,4.75,4.81,2.96 +0.32,"Ideal","H","VVS1",61.9,54,708,4.4,4.42,2.73 +1.02,"Ideal","G","VVS2",62.1,54,8847,6.54,6.51,4.05 +0.9,"Good","H","SI2",64.3,58,3114,5.97,6.03,3.86 +0.32,"Fair","D","VVS1",62.4,61,875,4.38,4.44,2.75 +1.52,"Premium","D","SI2",62.8,58,8631,7.37,7.28,4.6 +0.35,"Very Good","D","SI1",63.3,57,827,4.53,4.51,2.86 +0.26,"Very Good","F","SI1",61.4,56,401,4.13,4.16,2.54 +0.32,"Ideal","G","IF",61.9,55,918,4.38,4.44,2.73 +1.5,"Premium","F","VS1",59.6,60,15478,7.49,7.41,4.44 +0.3,"Good","G","VS1",63.6,55,776,4.29,4.26,2.72 +0.57,"Ideal","E","VS1",60.5,57,1884,5.33,5.38,3.24 +0.56,"Very Good","F","SI1",60,57,1679,5.41,5.38,3.24 +0.8,"Ideal","D","SI1",62.7,57,3564,5.88,5.92,3.7 +0.34,"Ideal","G","IF",61.9,54,1014,4.46,4.49,2.77 +0.38,"Premium","E","VVS1",61.9,58,1267,4.62,4.66,2.87 +1.04,"Premium","D","VS1",60.8,58,7041,6.53,6.5,3.96 +1.3,"Very Good","H","SI2",62.8,58,6140,6.93,7.01,4.38 +0.71,"Ideal","D","VS2",60.1,56,4029,5.77,5.83,3.48 +0.72,"Ideal","F","VS1",61.7,57,2829,5.77,5.74,3.55 +1.31,"Premium","I","SI1",62,58,5282,7.01,6.98,4.34 +0.27,"Ideal","E","VS2",60.8,56,537,4.25,4.23,2.58 +0.31,"Ideal","D","VVS2",61.2,59,805,4.37,4.39,2.68 +0.29,"Very Good","F","VVS1",59.8,61,609,4.31,4.35,2.59 +0.31,"Good","H","VVS2",63.6,56,625,4.28,4.33,2.74 +1.11,"Ideal","I","SI1",61.7,57,6090,6.61,6.64,4.09 +1.51,"Premium","E","SI1",60.6,59,12738,7.45,7.41,4.5 +0.7,"Ideal","F","SI2",60.6,57.2,2237,5.75,5.77,3.49 +0.77,"Ideal","E","SI2",62,54,2563,5.89,5.92,3.66 +0.4,"Ideal","F","VVS2",62.9,55,1039,4.75,4.72,2.98 +0.46,"Very Good","G","VS2",61.3,56,1172,4.98,5,3.06 +1.01,"Premium","E","VS1",60.8,59,7964,6.46,6.42,3.92 +0.29,"Very Good","G","VVS1",62,58,522,4.19,4.23,2.61 +0.54,"Ideal","E","VS2",62.8,55,1713,5.21,5.24,3.28 +0.54,"Ideal","G","SI1",61.5,55.1,1395,5.25,5.27,3.23 +1,"Good","G","VS2",63.1,61,5702,6.33,6.38,4.01 +1.01,"Good","H","SI1",63.4,59,4749,6.28,6.34,4 +0.32,"Very Good","G","VS1",62.9,57,645,4.37,4.4,2.76 +0.64,"Ideal","D","VS1",61.5,56,2787,5.54,5.55,3.41 +0.5,"Very Good","F","VS2",60.6,58,1436,5.07,5.12,3.09 +1.2,"Good","D","SI2",62.2,65,6344,6.75,6.7,4.18 +0.71,"Ideal","E","VS1",61.4,59,3198,5.71,5.75,3.52 +0.56,"Ideal","F","VVS1",62.1,56,2510,5.29,5.3,3.29 +0.74,"Premium","E","SI1",61.4,57,2042,5.83,5.79,3.57 +0.52,"Premium","G","SI2",58.8,62,1196,5.31,5.3,3.12 +1.55,"Ideal","F","SI2",61.9,55,10937,7.44,7.4,4.6 +0.9,"Very Good","H","SI2",61.1,63,3105,6.19,6.12,3.76 +1.2,"Premium","F","VS2",61.4,58,6182,6.8,6.75,4.16 +0.31,"Good","G","VVS2",63.1,57,707,4.3,4.32,2.72 +0.7,"Good","D","SI1",63.6,60,2512,5.59,5.51,3.51 +0.5,"Very Good","D","SI1",58.8,60,1436,5.17,5.23,3.06 +1.5,"Ideal","F","SI1",61.8,56,12389,7.27,7.34,4.52 +0.75,"Very Good","D","SI1",63.9,56,3085,5.73,5.75,3.67 +0.33,"Very Good","G","VS2",59.3,61,579,4.49,4.51,2.67 +1.5,"Premium","H","I1",60.1,57,3457,7.4,7.28,4.42 +1.32,"Ideal","G","VS1",61.4,54,9715,7.09,7.13,4.37 +1.2,"Good","F","SI2",59,60,5514,6.9,6.97,4.09 +0.7,"Good","F","SI1",61.1,61,2445,5.68,5.71,3.48 +0.33,"Premium","I","VS2",60.6,58,463,4.44,4.47,2.7 +1.2,"Premium","G","SI2",59.9,59,5250,6.92,6.98,4.16 +0.41,"Very Good","H","SI1",62.9,55,683,4.75,4.82,3.01 +0.71,"Ideal","I","VS1",61.3,57,2965,5.73,5.76,3.52 +0.71,"Very Good","G","SI2",63.4,56,2086,5.68,5.62,3.58 +0.32,"Good","F","SI2",63.5,56,421,4.35,4.37,2.77 +1.01,"Premium","J","SI2",59.3,56,2683,6.51,6.45,3.84 +0.91,"Good","G","SI2",63.6,59,3282,6.15,6.11,3.9 +1.5,"Fair","H","SI2",66,64,5000,7.1,6.97,4.64 +1.61,"Premium","J","SI2",62.2,59,7245,7.52,7.47,4.66 +0.9,"Premium","F","SI2",60.6,59,3951,6.27,6.21,3.78 +0.43,"Ideal","E","VS2",62.8,56,1048,4.86,4.79,3.03 +1.05,"Very Good","G","SI2",62.6,62,4516,6.45,6.49,4.05 +0.33,"Very Good","F","SI1",60.9,54,588,4.47,4.52,2.73 +1.01,"Premium","G","SI1",59.2,59,4260,6.52,6.58,3.88 +0.41,"Ideal","F","VS2",62.1,56,863,4.74,4.79,2.96 +0.75,"Good","E","SI2",59.7,62,2497,5.85,5.88,3.5 +0.72,"Very Good","D","SI1",60.5,57,3102,5.85,5.89,3.55 +0.42,"Ideal","D","VVS2",61.7,57,1132,4.8,4.82,2.97 +0.31,"Premium","G","VS1",62.9,58,802,4.35,4.3,2.72 +1,"Very Good","F","SI2",63.3,58,4269,6.26,6.29,3.97 +1.56,"Very Good","I","VS2",59.7,60,9231,7.53,7.58,4.51 +0.3,"Premium","D","SI1",62.1,59,662,4.31,4.29,2.67 +0.42,"Premium","G","VS1",60.8,59,984,4.85,4.79,2.93 +0.55,"Ideal","E","SI1",61.7,56,1668,5.29,5.24,3.25 diff --git a/apps/adv-reactivity/dynamic-antisolution.R b/apps/adv-reactivity/dynamic-antisolution.R new file mode 100644 index 0000000..0e89dee --- /dev/null +++ b/apps/adv-reactivity/dynamic-antisolution.R @@ -0,0 +1,68 @@ +library(shiny) +library(ggplot2) + +# Define UI for dynamic UI ------------------------------------------ +ui <- fluidPage( + sidebarLayout( + sidebarPanel( + fileInput("file", "CSV file"), + uiOutput("field_chooser_ui") + ), + mainPanel( + plotOutput("plot"), + verbatimTextOutput("summary") + ) + ) +) + +# Define server logic for summarizing selected file ------------------ +server <- function(input, output, session) { + + # Load data + full_data <- reactive({ + if (is.null(input$file)) + return(NULL) # Works, but not best practice + + read.csv(input$file$datapath, stringsAsFactors = FALSE) + }) + + # Subset for specified columns + subset_data <- reactive({ + if (is.null(full_data()) || is.null(input$xvar) || is.null(input$yvar)) + return(NULL) # Works, but not best practice + + full_data()[, c(input$xvar, input$yvar)] + }) + + # Dynamic UI for variable names based on selected file + output$field_chooser_ui <- renderUI({ + if (is.null(full_data())) + return(NULL) # Works, but not best practice + + col_names <- names(full_data()) + tagList( + selectInput("xvar", "X variable", col_names), + selectInput("yvar", "Y variable", col_names, selected = col_names[[2]]) + ) + }) + + # Scatterplot of selected variables + output$plot <- renderPlot({ + if (is.null(subset_data())) + return(NULL) # Works, but not best practice + + ggplot(subset_data(), aes_string(x = input$xvar, y = input$yvar)) + + geom_point() + }) + + # Summary of selected variables + output$summary <- renderPrint({ + if (is.null(subset_data())) + return(invisible()) # Works, but not best practice + + summary(subset_data()) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/dynamic-solution.R b/apps/adv-reactivity/dynamic-solution.R new file mode 100644 index 0000000..83383fe --- /dev/null +++ b/apps/adv-reactivity/dynamic-solution.R @@ -0,0 +1,57 @@ +library(shiny) +library(ggplot2) + +# Define UI for dynamic UI ------------------------------------------ +ui <- fluidPage( + sidebarLayout( + sidebarPanel( + fileInput("file", "CSV file"), + uiOutput("field_chooser_ui") + ), + mainPanel( + plotOutput("plot"), + verbatimTextOutput("summary") + ) + ) +) + +# Define server logic for summarizing selected file ------------------ +server <- function(input, output, session) { + + # Load data + full_data <- reactive({ + req(input$file) + + read.csv(input$file$datapath, stringsAsFactors = FALSE) + }) + + # Subset for specified columns + subset_data <- reactive({ + req(input$xvar, input$yvar) + + full_data()[, c(input$xvar, input$yvar)] + }) + + # Dynamic UI for variable names based on selected file + output$field_chooser_ui <- renderUI({ + col_names <- names(full_data()) + tagList( + selectInput("xvar", "X variable", col_names), + selectInput("yvar", "Y variable", col_names, selected = col_names[[2]]) + ) + }) + + # Scatterplot of selected variables + output$plot <- renderPlot({ + ggplot(subset_data(), aes_string(x = input$xvar, y = input$yvar)) + + geom_point() + }) + + # Summary of selected variables + output$summary <- renderPrint({ + summary(subset_data()) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/dynamic.R b/apps/adv-reactivity/dynamic.R new file mode 100644 index 0000000..541900f --- /dev/null +++ b/apps/adv-reactivity/dynamic.R @@ -0,0 +1,53 @@ +library(shiny) +library(ggplot2) + +# Define UI for dynamic UI ------------------------------------------ +ui <- fluidPage( + sidebarLayout( + sidebarPanel( + fileInput("file", "CSV file"), + uiOutput("field_chooser_ui") + ), + mainPanel( + plotOutput("plot"), + verbatimTextOutput("summary") + ) + ) +) + +# Define server logic for summarizing selected file ------------------ +server <- function(input, output, session) { + + # Load data + full_data <- reactive({ + read.csv(input$file$datapath, stringsAsFactors = FALSE) + }) + + # Subset for specified columns + subset_data <- reactive({ + full_data()[, c(input$xvar, input$yvar)] + }) + + # Dynamic UI for variable names based on selected file + output$field_chooser_ui <- renderUI({ + col_names <- names(full_data()) + tagList( + selectInput("xvar", "X variable", col_names), + selectInput("yvar", "Y variable", col_names, selected = col_names[[2]]) + ) + }) + + # Scatterplot of selected variables + output$plot <- renderPlot({ + ggplot(subset_data(), aes_string(x = input$xvar, y = input$yvar)) + + geom_point() + }) + + # Summary of selected variables + output$summary <- renderPrint({ + summary(subset_data()) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/points-solution.R b/apps/adv-reactivity/points-solution.R new file mode 100644 index 0000000..450f41f --- /dev/null +++ b/apps/adv-reactivity/points-solution.R @@ -0,0 +1,48 @@ +library(shiny) + +# Define UI for specifying points on a plot ------------------------- +ui <- fluidPage( + plotOutput("plot", click = "click", width = 400), + verbatimTextOutput("summary") +) + +# Define server logic for summarizing selected file ------------------ +server <- function(input, output, session) { + + # Use rv$data to track the points clicked so far + rv <- reactiveValues(data = data.frame(x=numeric(), y=numeric())) + + # Handle click events by adding a new row to the rv$data data frame + observeEvent(input$click, { + rv$data <- rbind( + rv$data, + data.frame(x=input$click$x, y=input$click$y) + ) + }) + + # Plot specified points + output$plot <- renderPlot({ + ggplot(rv$data, aes(x=x, y=y)) + geom_point() + + xlim(0, 1) + ylim(0, 1) + }) + + # Wrap rv$data and ensure that it's not empty + data <- reactive({ + req(nrow(rv$data) > 0) + rv$data + }) + + # Debounce + debounced_data <- debounce(data, 1000) + + # Summarize data + output$summary <- renderPrint({ + # Insert artificial slowness + on.exit(Sys.sleep(1)) + + print(summary(debounced_data())) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/adv-reactivity/points.R b/apps/adv-reactivity/points.R new file mode 100644 index 0000000..a68f7e0 --- /dev/null +++ b/apps/adv-reactivity/points.R @@ -0,0 +1,45 @@ +library(shiny) + +# Define UI for specifying points on a plot ------------------------- +ui <- fluidPage( + plotOutput("plot", click = "click", width = 400), + verbatimTextOutput("summary") +) + +# Define server logic for summarizing selected file ------------------ +server <- function(input, output, session) { + + # Use rv$data to track the points clicked so far + rv <- reactiveValues(data = data.frame(x = numeric(), y = numeric())) + + # Handle click events by adding a new row to the rv$data data frame + observeEvent(input$click, { + rv$data <- rbind( + rv$data, + data.frame(x=input$click$x, y=input$click$y) + ) + }) + + # Plot specified points + output$plot <- renderPlot({ + ggplot(rv$data, aes(x=x, y=y)) + geom_point() + + xlim(0, 1) + ylim(0, 1) + }) + + # Wrap rv$data and ensure that it's not empty + data <- reactive({ + req(nrow(rv$data) > 0) + rv$data + }) + + # Summarize data + output$summary <- renderPrint({ + # Insert artificial slowness + on.exit(Sys.sleep(1)) + + summary(data()) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/bookmark/bookmark_01.R b/apps/bookmark/bookmark_01.R new file mode 100644 index 0000000..8435d5c --- /dev/null +++ b/apps/bookmark/bookmark_01.R @@ -0,0 +1,21 @@ +library(shiny) + +# Define UI for bookmarking demo app -------------------------------- +ui <- function(request) { + fluidPage( + textInput("txt", "Enter text"), + checkboxInput("caps", "Capitalize"), + verbatimTextOutput("out"), + bookmarkButton() + ) +} + +# Define server logic for capitalizing text ------------------------- +server <- function(input, output, session) { + output$out <- renderText({ + ifelse(input$caps, toupper(input$txt), input$txt) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server, enableBookmarking = "url") diff --git a/apps/bookmark/bookmark_02.R b/apps/bookmark/bookmark_02.R new file mode 100644 index 0000000..0181b1e --- /dev/null +++ b/apps/bookmark/bookmark_02.R @@ -0,0 +1,35 @@ +library(shiny) + +# Define UI for app with multiple tabs ------------------------------ +ui <- function(request) { + fluidPage( + tabsetPanel(id = "tabs", + tabPanel("Tab one", + checkboxInput("chk1", "Checkbox 1"), + bookmarkButton(id = "bookmark1") + ), + tabPanel("Tab two", + checkboxInput("chk2", "Checkbox 2"), + bookmarkButton(id = "bookmark2") + ) + ) + ) +} + +# Define server logic for app with multiple tabs and bookmarking ---- +server <- function(input, output, session) { + + # Need to exclude the buttons from themselves being bookmarked + setBookmarkExclude(c("bookmark1", "bookmark2")) + + # Trigger bookmarking with either button + observeEvent(input$bookmark1, { + session$doBookmark() + }) + observeEvent(input$bookmark2, { + session$doBookmark() + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server, enableBookmarking = "url") diff --git a/apps/bookmark/bookmark_03.R b/apps/bookmark/bookmark_03.R new file mode 100644 index 0000000..deb561a --- /dev/null +++ b/apps/bookmark/bookmark_03.R @@ -0,0 +1,28 @@ +library(shiny) + +# Define UI for bookmarking demo app -------------------------------- +ui <- fluidPage( + sidebarPanel( + sliderInput("n", "Value to add", min = 0, max = 100, value = 50), + actionButton("add", "Add"), + br(), br() + ), + mainPanel( + h4("Sum:", textOutput("sum")) + ) + ) + +# Define server logic for bookmarking demo app ---------------------- +server <- function(input, output, session) { + vals <- reactiveValues(sum = 0) + + observeEvent(input$add, { + vals$sum <- vals$sum + input$n + }) + output$sum <- renderText({ + vals$sum + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server, enableBookmarking = "url") diff --git a/apps/bookmark/bookmark_04.R b/apps/bookmark/bookmark_04.R new file mode 100644 index 0000000..59b8287 --- /dev/null +++ b/apps/bookmark/bookmark_04.R @@ -0,0 +1,37 @@ +library(shiny) + +# Define UI for accumulator app ------------------------------------- +ui <- function(request) { + fluidPage( + sidebarPanel( + sliderInput("n", "Value to add", min = 0, max = 100, value = 50), + actionButton("add", "Add"), br(), br(), + bookmarkButton() + ), + mainPanel( + h4("Sum:", textOutput("sum")) + ) + ) +} + +# Define server accumulator app with bookmarking -------------------- +server <- function(input, output, session) { + vals <- reactiveValues(sum = 0) + + onBookmark(function(state) { + state$values$currentSum <- vals$sum + }) + onRestore(function(state) { + vals$sum <- state$values$currentSum + }) + + observeEvent(input$add, { + vals$sum <- vals$sum + input$n + }) + output$sum <- renderText({ + vals$sum + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server, enableBookmarking = "url") diff --git a/apps/bookmark/bookmark_05.R b/apps/bookmark/bookmark_05.R new file mode 100644 index 0000000..c2dad42 --- /dev/null +++ b/apps/bookmark/bookmark_05.R @@ -0,0 +1,38 @@ +library(shiny) + +# Define UI for accumulator app ------------------------------------- +ui <- function(request) { + fluidPage( + sidebarPanel( + sliderInput("n", "Value to add", min = 0, max = 100, value = 50), + actionButton("add", "Add"), br(), br(), + bookmarkButton() + ), + mainPanel( + h4("Sum:", textOutput("sum")) + ) + ) +} + +# Define server accumulator app with bookmarking -------------------- +server <- function(input, output, session) { + vals <- reactiveValues(sum = 0) + + onBookmark(function(state) { + state$values$currentSum <- vals$sum + }) + onRestore(function(state) { + vals$sum <- state$values$currentSum + }) + setBookmarkExclude("add") + + observeEvent(input$add, { + vals$sum <- vals$sum + input$n + }) + output$sum <- renderText({ + vals$sum + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server, enableBookmarking = "url") diff --git a/apps/dashboard/flexdashboard_01.Rmd b/apps/dashboard/flexdashboard_01.Rmd new file mode 100644 index 0000000..93cede4 --- /dev/null +++ b/apps/dashboard/flexdashboard_01.Rmd @@ -0,0 +1,61 @@ +--- +title: "flexdashboard + shiny" +output: + flexdashboard::flex_dashboard: + orientation: columns + source_code: embed +runtime: shiny +--- + +```{r global, include=FALSE} +# load data in 'global' chunk so it can be shared by all users of the dashboard +library(shiny) +library(ggplot2) +library(dplyr) +``` + +Inputs {.sidebar} +----------------------------------------------------------------------- + +```{r} +checkboxGroupInput("cyl", "Cylinders", choices = c("4", "6", "8"), + selected = c("4", "6", "8"), inline = TRUE + ) + +sliderInput("hp", "Horsepower", + min = min(mtcars$hp), max = max(mtcars$hp), + value = range(mtcars$hp) + ) +``` + +Outputs +----------------------------------------------------------------------- + +### Scatterplot of weight and miles per gallon + +```{r} +mpg_subset <- reactive({ + mtcars %>% + filter( + hp >= input$hp[1], + hp <= input$hp[2], + cyl %in% input$cyl + ) +}) + +renderPlot({ + ggplot(mpg_subset(), aes(x = wt, y = mpg, color = factor(cyl))) + + geom_point() +}) +``` + +### Histogram of weight + +```{r} +renderPlot({ + + ggplot(mpg_subset(), aes(x = wt)) + + geom_histogram(binwidth = 0.25) + +}) +``` \ No newline at end of file diff --git a/apps/dashboard/flexdashboard_02.Rmd b/apps/dashboard/flexdashboard_02.Rmd new file mode 100644 index 0000000..f76a266 --- /dev/null +++ b/apps/dashboard/flexdashboard_02.Rmd @@ -0,0 +1,71 @@ +--- +title: "flexdashboard + shiny" +output: + flexdashboard::flex_dashboard: + orientation: columns + source_code: embed +runtime: shiny +--- + +```{r global, include=FALSE} +# load data in 'global' chunk so it can be shared by all users of the dashboard +library(shiny) +library(ggplot2) +library(dplyr) +``` + +Inputs {.sidebar} +----------------------------------------------------------------------- + +```{r} +checkboxGroupInput("cyl", "Cylinders", choices = c("4", "6", "8"), + selected = c("4", "6", "8"), inline = TRUE + ) + +sliderInput("hp", "Horsepower", + min = min(mtcars$hp), max = max(mtcars$hp), + value = range(mtcars$hp) + ) + +radioButtons("plot_type", "Weight plot type", + choices = c("Histogram", "Violin plot"), selected = c("Histogram")) +``` + +Outputs +----------------------------------------------------------------------- + +### Scatterplot of weight and miles per gallon + +```{r} +mpg_subset <- reactive({ + mtcars %>% + filter( + hp >= input$hp[1], + hp <= input$hp[2], + cyl %in% input$cyl + ) +}) + +renderPlot({ + ggplot(mpg_subset(), aes(x = wt, y = mpg, color = factor(cyl))) + + geom_point() +}) +``` + +### Histogram of weight + +```{r} +renderPlot({ + + if(input$plot_type == "Histogram"){ + ggplot(mpg_subset(), aes(x = wt)) + + geom_histogram(binwidth = 0.25) + + coord_cartesian(xlim = range(mtcars$wt)) + } + else { + ggplot(mpg_subset(), aes(y = wt, x = factor(1))) + + geom_violin() + } + +}) +``` \ No newline at end of file diff --git a/apps/dashboard/flexdashboard_03.Rmd b/apps/dashboard/flexdashboard_03.Rmd new file mode 100644 index 0000000..b81e318 --- /dev/null +++ b/apps/dashboard/flexdashboard_03.Rmd @@ -0,0 +1,78 @@ +--- +title: "flexdashboard + shiny_prerendered" +output: + flexdashboard::flex_dashboard: + orientation: columns + source_code: embed +runtime: shiny +--- + +```{r context="setup", include=FALSE} +library(shiny) +library(ggplot2) +library(dplyr) +``` + +Inputs {.sidebar} +----------------------------------------------------------------------- + +```{r context="render"} +checkboxGroupInput("cyl", "Cylinders", choices = c("4", "6", "8"), + selected = c("4", "6", "8"), inline = TRUE + ) + +sliderInput("hp", "Horsepower", + min = min(mtcars$hp), max = max(mtcars$hp), + value = range(mtcars$hp) + ) + +radioButtons("plot_type", "Weight plot type", + choices = c("Histogram", "Violin plot"), selected = c("Histogram")) +``` + +Outputs +----------------------------------------------------------------------- + +### Scatterplot of weight and miles per gallon + +```{r context="server"} +mpg_subset <- reactive({ + mtcars %>% + filter( + hp >= input$hp[1], + hp <= input$hp[2], + cyl %in% input$cyl + ) +}) + +output$scatter <- renderPlot({ + ggplot(mpg_subset(), aes(x = wt, y = mpg, color = factor(cyl))) + + geom_point() +}) +``` + +```{r context="render"} +plotOutput("scatter") +``` + +### Histogram or violin plot of weight + +```{r context="server"} +output$weight_plot <- renderPlot({ + + if(input$plot_type == "Histogram"){ + ggplot(mpg_subset(), aes(x = wt)) + + geom_histogram(binwidth = 0.25) + + coord_cartesian(xlim = range(mtcars$wt)) + } + else { + ggplot(mpg_subset(), aes(y = wt, x = factor(1))) + + geom_violin() + } + +}) +``` + +```{r context="render"} +plotOutput("weight_plot") +``` diff --git a/apps/gapminder/data.R b/apps/gapminder/data.R new file mode 100644 index 0000000..9f4ec59 --- /dev/null +++ b/apps/gapminder/data.R @@ -0,0 +1,11 @@ +library(gapminder) + +# Note: This code creates data sets to use in each tab. +# It removes Kuwait since Kuwait distorts the gdp scale + +all_data <- filter(gapminder, country != "Kuwait") +africa_data <- filter(gapminder, continent == "Africa") +americas_data <- filter(gapminder, continent == "Americas") +asia_data <- filter(gapminder, continent == "Asia", country != "Kuwait") +europe_data <- filter(gapminder, continent == "Europe") +oceania_data <- filter(gapminder, continent == "Oceania") \ No newline at end of file diff --git a/apps/gapminder/gapminder.R b/apps/gapminder/gapminder.R new file mode 100644 index 0000000..a8515a9 --- /dev/null +++ b/apps/gapminder/gapminder.R @@ -0,0 +1,31 @@ +library(shiny) +library(dplyr) +source("data.R") +source("gapModule.R") + +# UI -------------------------------------------------------------------------- +ui <- fluidPage( + tags$style(type="text/css", ".recalculating { opacity: 1.0; }"), + titlePanel("Gapminder"), + tabsetPanel(id = "continent", + tabPanel("All", gapModuleUI("all")), + tabPanel("Africa", gapModuleUI("africa")), + tabPanel("Americas", gapModuleUI("americas")), + tabPanel("Asia", gapModuleUI("asia")), + tabPanel("Europe", gapModuleUI("europe")), + tabPanel("Oceania", gapModuleUI("oceania")) + ) +) + +# Server ---------------------------------------------------------------------- +server <- function(input, output) { + callModule(gapModule, "all", all_data) + callModule(gapModule, "africa", africa_data) + callModule(gapModule, "americas", americas_data) + callModule(gapModule, "asia", asia_data) + callModule(gapModule, "europe", europe_data) + callModule(gapModule, "oceania", oceania_data) +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) \ No newline at end of file diff --git a/apps/gapminder/gapmodule.R b/apps/gapminder/gapmodule.R new file mode 100644 index 0000000..21016b4 --- /dev/null +++ b/apps/gapminder/gapmodule.R @@ -0,0 +1,51 @@ +# Module UI ------------------------------------------------------------------- +gapModuleUI <- function(id) { + ns <- NS(id) + + tagList( + plotOutput(ns("plot")), + sliderInput(ns("year"), "Select Year", value = 1952, + min = 1952, max = 2007, step = 5, + animate = animationOptions(interval = 500)) + ) +} + +# Module server --------------------------------------------------------------- +gapModule <- function(input, output, session, data) { + + # Collect one year of data -------------------------------------------------- + ydata <- reactive({ + filter(data, year == input$year) + }) + + xrange <- range(data$gdpPercap) + yrange <- range(data$lifeExp) + + output$plot <- renderPlot({ + + # Draw background plot with legend ---------------------------------------- + plot(data$gdpPercap, data$lifeExp, type = "n", + xlab = "GDP per capita", ylab = "Life Expectancy", + panel.first = { + grid() + text(mean(xrange), mean(yrange), input$year, + col = "grey90", cex = 5) + }) + + legend("bottomright", legend = levels(data$continent), + cex = 1.3, inset = 0.01, text.width = diff(xrange)/5, + fill = c("#E41A1C99", "#377EB899", "#4DAF4A99", + "#984EA399", "#FF7F0099")) + + # Determine bubble colors ------------------------------------------------- + cols <- c("Africa" = "#E41A1C99", + "Americas" = "#377EB899", + "Asia" = "#4DAF4A99", + "Europe" = "#984EA399", + "Oceania" = "#FF7F0099")[ydata()$continent] + + # Add bubbles ------------------------------------------------------------- + symbols(ydata()$gdpPercap, ydata()$lifeExp, circles = sqrt(ydata()$pop), + bg = cols, inches = 0.5, fg = "white", add = TRUE) + }) +} \ No newline at end of file diff --git a/apps/hist-med/hist_med.R b/apps/hist-med/hist_med.R new file mode 100644 index 0000000..ee9361c --- /dev/null +++ b/apps/hist-med/hist_med.R @@ -0,0 +1,33 @@ +library(shiny) + +# Define UI for app that draws a histogram and overlays median ------ +ui <- fluidPage( + # Application title + titlePanel("Histogram and median"), + # Sidebar with a slider input for n + sidebarLayout( + sidebarPanel( sliderInput("n", "Select n", min = 1, max = 50, value = 30) ), + mainPanel( + plotOutput("hist"), + textOutput("med") + ) + ) +) + +# Define server logic ----------------------------------------------- +server <- function(input, output) { + dist <- reactive({ rnorm(input$n) }) + med <- reactive({ median(dist()) }) + output$hist <- renderPlot({ + hist(dist()) + #med <- reactive({ median(dist()) }) + abline(v = med(), col = "red") + }) + output$med <- renderText({ + paste("The median is", round(med(), 3)) + }) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/left-right/left_right_01.R b/apps/left-right/left_right_01.R new file mode 100644 index 0000000..04adcbc --- /dev/null +++ b/apps/left-right/left_right_01.R @@ -0,0 +1,69 @@ +library(shiny) + +# Module 1: Dataset chooser --------------------------------------------------- + +# Module 1 UI +dataset_chooser_UI <- function(id) { + ns <- NS(id) + + tagList( + selectInput(ns("dataset"), "Choose a dataset", c("pressure", "cars")), + numericInput(ns("count"), "Number of records to return", 10) + ) +} + +# Module 1 Server +dataset_chooser <- function(input, output, session) { + dataset <- reactive({ + req(input$dataset) + get(input$dataset, pos = "package:datasets") + }) + + return(list( + dataset = dataset, + count = reactive(input$count) + )) +} + +# Module 2: Dataset summarizer ------------------------------------------------ + +# Module 2 UI +dataset_summarizer_UI <- function(id) { + ns <- NS(id) + + verbatimTextOutput(ns("summary")) +} + +# Module 2 Server +dataset_summarizer <- function(input, output, session, dataset, count) { + output$summary <- renderPrint({ + summary(head(dataset(), count())) + }) +} + +# App combining Module 1 and Module 2 ----------------------------------------- + +# App UI +ui <- fluidPage( + fluidRow( + column(6, + dataset_chooser_UI("left_input"), + dataset_summarizer_UI("left_output") + ), + column(6, + dataset_chooser_UI("right_input"), + dataset_summarizer_UI("right_output") + ) + ) +) + +# App server +server <- function(input, output, session) { + left_result <- callModule(dataset_chooser, "left_input") + right_result <- callModule(dataset_chooser, "right_input") + + callModule(dataset_summarizer, "left_output", dataset = left_result$dataset, count = left_result$count) + callModule(dataset_summarizer, "right_output", dataset = right_result$dataset, count = right_result$count) +} + +shinyApp(ui, server) \ No newline at end of file diff --git a/apps/left-right/left_right_02.R b/apps/left-right/left_right_02.R new file mode 100644 index 0000000..12ab330 --- /dev/null +++ b/apps/left-right/left_right_02.R @@ -0,0 +1,102 @@ +library(shiny) + +# Module 1: Dataset chooser --------------------------------------------------- + +# Module 1 UI +dataset_chooser_UI <- function(id) { + ns <- NS(id) + + tagList( + selectInput(ns("dataset"), "Choose a dataset", c("pressure", "cars")), + numericInput(ns("count"), "Number of records to return", 10) + ) +} + +# Module 1 Server +dataset_chooser <- function(input, output, session) { + dataset <- reactive({ + req(input$dataset) + get(input$dataset, pos = "package:datasets") + }) + + return(list( + dataset = dataset, + count = reactive(input$count) + )) +} + +# Module 2: Dataset summarizer ------------------------------------------------ + +# Module 2 UI +dataset_summarizer_UI <- function(id) { + ns <- NS(id) + + verbatimTextOutput(ns("summary")) +} + +# Module 2 Server +dataset_summarizer <- function(input, output, session, dataset, count) { + selected_data <- reactive({ head(dataset(), count()) }) + + output$summary <- renderPrint({ + summary( selected_data() ) + }) + + mean_x <- reactive({ mean(selected_data()[,1]) }) + mean_y <- reactive({ mean(selected_data()[,2]) }) + + return(list( + mean_x = mean_x, + mean_y = mean_y + )) + +} + +# Module 3: Dataset plotter --------------------------------------------------- + +# Module 3 UI +dataset_plotter_UI <- function(id) { + ns <- NS(id) + + plotOutput(ns("scatterplot")) +} + +# Module 3 Server +dataset_plotter <- function(input, output, session, dataset, count, mean_x, mean_y) { + output$scatterplot <- renderPlot({ + plot(head(dataset(), count())) + points(x = mean_x(), y = mean_y(), pch = 19, col = "red") + }) +} + +# App combining Module 1 and Module 2 ----------------------------------------- + +# App UI +ui <- fluidPage( + fluidRow( + column(6, + dataset_chooser_UI("left_input"), + dataset_summarizer_UI("left_output"), + dataset_plotter_UI("left_plot") + ), + column(6, + dataset_chooser_UI("right_input"), + dataset_summarizer_UI("right_output"), + dataset_plotter_UI("right_plot") + ) + ) +) + +# App server +server <- function(input, output, session) { + left_result <- callModule(dataset_chooser, "left_input") + right_result <- callModule(dataset_chooser, "right_input") + + left_means <- callModule(dataset_summarizer, "left_output", dataset = left_result$dataset, count = left_result$count) + right_means <- callModule(dataset_summarizer, "right_output", dataset = right_result$dataset, count = right_result$count) + + callModule(dataset_plotter, "left_plot", dataset = left_result$dataset, count = left_result$count, mean_x = left_means$mean_x, mean_y = left_means$mean_y) + callModule(dataset_plotter, "right_plot", dataset = right_result$dataset, count = right_result$count, mean_x = right_means$mean_x, mean_y = right_means$mean_y) +} + +shinyApp(ui, server) \ No newline at end of file diff --git a/apps/movies/movies.Rdata b/apps/movies/movies.Rdata new file mode 100644 index 0000000000000000000000000000000000000000..0add3b16f3eefe672cf7bc5fc1327ede52842b2d GIT binary patch literal 64990 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 H`6Ob~=G@tb?HF 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 literal 0 HcmV?d00001 diff --git a/apps/movies/movies_01.R b/apps/movies/movies_01.R new file mode 100644 index 0000000..fe54ecf --- /dev/null +++ b/apps/movies/movies_01.R @@ -0,0 +1,46 @@ +library(shiny) +library(ggplot2) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "critics_score") + ), + + # Output: Show scatterplot -------------------------------------- + mainPanel( + plotOutput(outputId = "scatterplot") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y)) + + geom_point() + }) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_02.R b/apps/movies/movies_02.R new file mode 100644 index 0000000..302e4c8 --- /dev/null +++ b/apps/movies/movies_02.R @@ -0,0 +1,53 @@ +library(shiny) +library(ggplot2) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("title_type", "genre", "mpaa_rating", "critics_rating", "audience_rating"), + selected = "mpaa_rating") + ), + + # Output: Show scatterplot -------------------------------------- + mainPanel( + plotOutput(outputId = "scatterplot") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point() + }) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_03.R b/apps/movies/movies_03.R new file mode 100644 index 0000000..f3868fc --- /dev/null +++ b/apps/movies/movies_03.R @@ -0,0 +1,59 @@ +library(shiny) +library(ggplot2) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("title_type", "genre", "mpaa_rating", "critics_rating", "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5) + ), + + # Output: Show scatterplot -------------------------------------- + mainPanel( + plotOutput(outputId = "scatterplot") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha) + }) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_04.R b/apps/movies/movies_04.R new file mode 100644 index 0000000..7bc2942 --- /dev/null +++ b/apps/movies/movies_04.R @@ -0,0 +1,79 @@ +library(shiny) +library(ggplot2) +library(DT) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("title_type", "genre", "mpaa_rating", "critics_rating", "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + ), + + # Output -------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_05.R b/apps/movies/movies_05.R new file mode 100644 index 0000000..689f190 --- /dev/null +++ b/apps/movies/movies_05.R @@ -0,0 +1,99 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + ), + + # Output -------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " "))) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_06.R b/apps/movies/movies_06.R new file mode 100644 index 0000000..46ee373 --- /dev/null +++ b/apps/movies/movies_06.R @@ -0,0 +1,104 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + ), + + # Output -------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies, aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " "))) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_07.R b/apps/movies/movies_07.R new file mode 100644 index 0000000..70eb089 --- /dev/null +++ b/apps/movies/movies_07.R @@ -0,0 +1,134 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film") + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_subset(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " "))) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_subset()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_08.R b/apps/movies/movies_08.R new file mode 100644 index 0000000..57209eb --- /dev/null +++ b/apps/movies/movies_08.R @@ -0,0 +1,134 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film") + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_subset(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " "))) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_subset()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_subset()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_09.R b/apps/movies/movies_09.R new file mode 100644 index 0000000..03f8021 --- /dev/null +++ b/apps/movies/movies_09.R @@ -0,0 +1,145 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " "))) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_10.R b/apps/movies/movies_10.R new file mode 100644 index 0000000..02b9920 --- /dev/null +++ b/apps/movies/movies_10.R @@ -0,0 +1,159 @@ +# Note: This app is intentionally broken, +# it is used as part of an exercise + +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + output$pretty_plot_title <- toTitleCase(input$plot_title) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = output$pretty_plot_title + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_11.R b/apps/movies/movies_11.R new file mode 100644 index 0000000..97c4a2b --- /dev/null +++ b/apps/movies/movies_11.R @@ -0,0 +1,156 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = pretty_plot_title() + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_12.R b/apps/movies/movies_12.R new file mode 100644 index 0000000..15c7b8e --- /dev/null +++ b/apps/movies/movies_12.R @@ -0,0 +1,165 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = pretty_plot_title() + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_13.R b/apps/movies/movies_13.R new file mode 100644 index 0000000..30b02b8 --- /dev/null +++ b/apps/movies/movies_13.R @@ -0,0 +1,169 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Theme selector -------------------------------------------------- + shinythemes::themeSelector(), + theme = shinythemes::shinytheme("united"), + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = pretty_plot_title() + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_14.R b/apps/movies/movies_14.R new file mode 100644 index 0000000..5c71372 --- /dev/null +++ b/apps/movies/movies_14.R @@ -0,0 +1,165 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50) + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_15.R b/apps/movies/movies_15.R new file mode 100644 index 0000000..d51954f --- /dev/null +++ b/apps/movies/movies_15.R @@ -0,0 +1,179 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50), + + # Write sampled data as csv ------------------------------------------ + actionButton(inputId = "write_csv", + label = "Write CSV") + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Create new df that is n_samp obs from selected type movies ------ + movies_sample <- reactive({ + req(input$n_samp) # ensure availablity of value before proceeding + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Write sampled data as csv --------------------------------------- + observeEvent(eventExpr = input$write_csv, + handlerExpr = { + filename <- paste0("movies_", str_replace_all(Sys.time(), ":|\ ", "_"), ".csv") + write.csv(movies_sample(), file = filename, row.names = FALSE) + } + ) + +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_16.R b/apps/movies/movies_16.R new file mode 100644 index 0000000..465c3e1 --- /dev/null +++ b/apps/movies/movies_16.R @@ -0,0 +1,189 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50), + + # Get a new sample ------------------------------------------------------ + actionButton(inputId = "get_new_sample", + label = "Get new sample"), + + # A little bit of visual separation ------------------------------------- + br(), br(), + + # Write sampled data as csv ------------------------------------------ + actionButton(inputId = "write_csv", + label = "Write CSV") + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Get new sample -------------------------------------------------- + movies_sample <- eventReactive(eventExpr = input$get_new_sample, + valueExpr = { + req(input$n_samp) + sample_n(movies_subset(), input$n_samp) + }, + ignoreNULL = FALSE + ) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Write sampled data as csv --------------------------------------- + observeEvent(eventExpr = input$write_csv, + handlerExpr = { + filename <- paste0("movies_", str_replace_all(Sys.time(), ":|\ ", "_"), ".csv") + write.csv(movies_sample(), file = filename, row.names = FALSE) + } + ) + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_17.R b/apps/movies/movies_17.R new file mode 100644 index 0000000..c6bece8 --- /dev/null +++ b/apps/movies/movies_17.R @@ -0,0 +1,203 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50), + + # Get a new sample ------------------------------------------------------ + actionButton(inputId = "get_new_sample", + label = "Get new sample"), + + # A little bit of visual separation ------------------------------------- + br(), br(), + + # Write sampled data as csv ------------------------------------------ + actionButton(inputId = "write_csv", + label = "Write CSV") + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Print how long app is being viewed for ---------------------- + textOutput(outputId = "time_elapsed"), + br(), + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Get new sample -------------------------------------------------- + movies_sample <- eventReactive(eventExpr = input$get_new_sample, + valueExpr = { + req(input$n_samp) + sample_n(movies_subset(), input$n_samp) + }, + ignoreNULL = FALSE + ) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Write sampled data as csv --------------------------------------- + observeEvent(eventExpr = input$write_csv, + handlerExpr = { + filename <- paste0("movies_", str_replace_all(Sys.time(), ":|\ ", "_"), ".csv") + write.csv(movies_sample(), file = filename, row.names = FALSE) + } + ) + + # Calculate time diff bet when app is first launched and now ------ + beg <- Sys.time() + now <- reactive({ invalidateLater(millis = 1000); Sys.time() }) + diff <- reactive({ round(difftime(now(), beg, units = "secs")) }) + + # Print time viewing app ------------------------------------------ + output$time_elapsed <- renderText({ + paste("You have been viewing this app for", diff(), "seconds.") + }) + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_18.R b/apps/movies/movies_18.R new file mode 100644 index 0000000..2d01d4c --- /dev/null +++ b/apps/movies/movies_18.R @@ -0,0 +1,196 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50), + + # A little bit of visual separation ------------------------------------- + br(), br(), + + # Write sampled data as csv ------------------------------------------ + actionButton(inputId = "write_csv", + label = "Write CSV") + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Print how long app is being viewed for ---------------------- + textOutput(outputId = "time_elapsed"), + br(), + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Show data table --------------------------------------------- + DT::dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Get new sample every 5 seconds ---------------------------------- + movies_sample <- reactive({ invalidateLater(millis = 5000) + req(input$n_samp) + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Write sampled data as csv --------------------------------------- + observeEvent(eventExpr = input$write_csv, + handlerExpr = { + filename <- paste0("movies_", str_replace_all(Sys.time(), ":|\ ", "_"), ".csv") + write.csv(movies_sample(), file = filename, row.names = FALSE) + } + ) + + # Calculate time diff bet when app is first launched and now ------ + beg <- Sys.time() + now <- reactive({ invalidateLater(millis = 1000); Sys.time() }) + diff <- reactive({ round(difftime(now(), beg, units = "secs")) }) + + # Print time viewing app ------------------------------------------ + output$time_elapsed <- renderText({ + paste("You have been viewing this app for", diff(), "seconds.") + }) + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_19.R b/apps/movies/movies_19.R new file mode 100644 index 0000000..34bd49c --- /dev/null +++ b/apps/movies/movies_19.R @@ -0,0 +1,232 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Enter text for plot title --------------------------------------------- + textInput(inputId = "plot_title", + label = "Plot title", + placeholder = "Enter text to be used as plot title"), + + # Horizontal line for visual separation ----------------------- + hr(), + + # Select which types of movies to plot ------------------------ + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 50), + + # A little bit of visual separation ------------------------------------- + br(), br(), + + # Write sampled data as csv ------------------------------------------ + actionButton(inputId = "write_csv", + label = "Write CSV") + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Print how long app is being viewed for ---------------------- + textOutput(outputId = "time_elapsed"), + br(), + + # Show scatterplot -------------------------------------------- + plotOutput(outputId = "scatterplot"), + br(), # a little bit of visual separation + + # Print number of obs plotted --------------------------------- + uiOutput(outputId = "n"), + br(), br(), # a little bit of visual separation + + # Use tabs for the data tables to reduce clutter ------------------------ + tabsetPanel( + # Show data table ----------------------------------------------------- + tabPanel("Plotted data", DT::dataTableOutput(outputId = "moviestable")), + + # Show CSV files in directory ----------------------------------------- + tabPanel("Files in directory", DT::dataTableOutput(outputId = "csv_files")) + ) + + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ------ + movies_subset <- reactive({ + req(input$selected_type) # ensure availablity of value before proceeding + filter(movies, title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ------ + observe({ + updateNumericInput(session, + inputId = "n_samp", + value = min(50, nrow(movies_subset())), + max = nrow(movies_subset()) + ) + }) + + # Get new sample every 5 seconds ---------------------------------- + movies_sample <- reactive({ invalidateLater(millis = 5000) + req(input$n_samp) + sample_n(movies_subset(), input$n_samp) + }) + + # Convert plot_title toTitleCase ---------------------------------- + pretty_plot_title <- reactive({ toTitleCase(input$plot_title) }) + + # Create scatterplot object the plotOutput function is expecting -- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y, + color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")), + title = isolate({ pretty_plot_title() }) + ) + }) + + # Print number of movies plotted ---------------------------------- + output$n <- renderUI({ + types <- movies_sample()$title_type %>% + factor(levels = input$selected_type) + counts <- table(types) + + HTML(paste("There are", counts, input$selected_type, "movies in this dataset.
")) + }) + + # Print data table if checked ------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Write sampled data as csv --------------------------------------- + observeEvent(eventExpr = input$write_csv, + handlerExpr = { + filename <- paste0("movies_", str_replace_all(Sys.time(), ":|\ ", "_"), ".csv") + write.csv(movies_sample(), file = filename, row.names = FALSE) + } + ) + + # Calculate time diff bet when app is first launched and now ------ + beg <- Sys.time() + now <- reactive({ invalidateLater(millis = 1000); Sys.time() }) + diff <- reactive({ round(difftime(now(), beg, units = "secs")) }) + + # Print time viewing app ------------------------------------------ + output$time_elapsed <- renderText({ + paste("You have been viewing this app for", diff(), "seconds.") + }) + + # Helper funs to count and list CSV files in the directory ------------------ + + # Check function + count_files <- function(){ length(dir(pattern = "*.csv")) } + + # Value retrieval function + list_files <- function(){ + files <- dir(pattern = "*.csv") + if(length(files) == 0){ return( data.frame() ) } + sapply(files, function(file) dim(read.csv(file))) %>% + unlist() %>% + t() %>% + as.data.frame() %>% + setNames(c("rows", "cols")) + } + + # Count and list CSV files in the directory every 5 seconds ----------------- + csv_files <- reactivePoll(intervalMillis = 5000, + session, + checkFunc = count_files, + valueFunc = list_files) + + # Print CSV files in the directory ------------------------------------------ + output$csv_files <- DT::renderDataTable( + DT::datatable(data = csv_files(), + options = list(pageLength = 10), + rownames = TRUE) + ) + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_20.R b/apps/movies/movies_20.R new file mode 100644 index 0000000..03093d3 --- /dev/null +++ b/apps/movies/movies_20.R @@ -0,0 +1,169 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + tabsetPanel(id = "movies", + tabPanel("Documentaries", + plotOutput("scatterplot_doc"), + DT::dataTableOutput("moviestable_doc")), + tabPanel("Feature Films", + plotOutput("scatterplot_feature"), + DT::dataTableOutput("moviestable_feature")), + tabPanel("TV Movies", + plotOutput("scatterplot_tv"), + DT::dataTableOutput("moviestable_tv")) + ) + + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create subsets for various title types -------------------------- + docs <- reactive({ + filter(movies, title_type == "Documentary") + }) + + features <- reactive({ + filter(movies, title_type == "Feature Film") + }) + + tvs <- reactive({ + filter(movies, title_type == "TV Movie") + }) + + + # Scatterplot for docs -------------------------------------------- + output$scatterplot_doc <- renderPlot({ + ggplot(data = docs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for features ---------------------------------------- + output$scatterplot_feature <- renderPlot({ + ggplot(data = features(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for tvs --------------------------------------------- + output$scatterplot_tv <- renderPlot({ + ggplot(data = tvs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Table for docs -------------------------------------------------- + output$moviestable_doc <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = docs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for features ---------------------------------------------- + output$moviestable_feature <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = features()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for tvs --------------------------------------------------- + output$moviestable_tv <- DT::renderDataTable( + if(input$show_data) + DT::datatable(data = tvs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE + + ) + ) + +} + + +# Run the app ------------------------------------------------------ +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_21.R b/apps/movies/movies_21.R new file mode 100644 index 0000000..5fad433 --- /dev/null +++ b/apps/movies/movies_21.R @@ -0,0 +1,104 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") +source("moviesmodule.R") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Title Type" = "title_type", + "Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot ------------------------------------------------------ + tabsetPanel(id = "movies", + tabPanel("Documentaries", movies_module_UI("doc")), + tabPanel("Feature Films", movies_module_UI("feature")), + tabPanel("TV Movies", movies_module_UI("tv")) + ) + + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + x <- reactive(input$x) + y <- reactive(input$y) + z <- reactive(input$z) + alpha <- reactive(input$alpha) + size <- reactive(input$size) + show_data <- reactive(input$show_data) + + # Create the scatterplot object the plotOutput function is expecting -------- + callModule(movies_module, "doc", data = movies, mov_title_type = "Documentary", x, y, z, alpha, size, show_data) + callModule(movies_module, "feature", data = movies, mov_title_type = "Feature Film", x, y, z, alpha, size, show_data) + callModule(movies_module, "tv", data = movies, mov_title_type = "TV Movie", x, y, z, alpha, size, show_data) + +} + + +# Run the app ------------------------------------------------------ +shinyApp(ui = ui, server = server) diff --git a/apps/movies/movies_broken_01.R b/apps/movies/movies_broken_01.R new file mode 100644 index 0000000..59f9c53 --- /dev/null +++ b/apps/movies/movies_broken_01.R @@ -0,0 +1,164 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score") + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score") + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating") + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5) + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2) + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + tabsetPanel(id = "movies", + tabPanel("Documentaries", + plotOutput("scatterplot_doc"), + DT::dataTableOutput("moviestable_doc")), + tabPanel("Feature Films", + plotOutput("scatterplot_feature"), + DT::dataTableOutput("moviestable_feature")), + tabPanel("TV Movies", + plotOutput("scatterplot_tv"), + DT::dataTableOutput("moviestable_tv")) + ) + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create subsets for various title types -------------------------- + docs <- reactive({ + filter(movies, title_type == "Documentary") + }) + + features <- reactive({ + filter(movies, title_type == "Feature Film") + }) + + tvs <- reactive({ + filter(movies, title_type == "TV Movie") + }) + + # Scatterplot for docs -------------------------------------------- + output$scatterplot_doc <- renderPlot({ + ggplot(data = docs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for features ---------------------------------------- + output$scatterplot_feature <- renderPlot({ + ggplot(data = features(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for tvs --------------------------------------------- + output$scatterplot_tv <- renderPlot({ + ggplot(data = tvs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Table for docs -------------------------------------------------- + output$moviestable_doc <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = docs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for features ---------------------------------------------- + output$moviestable_feature <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = features()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for tvs --------------------------------------------------- + output$moviestable_tv <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = tvs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_broken_02.R b/apps/movies/movies_broken_02.R new file mode 100644 index 0000000..82ae89b --- /dev/null +++ b/apps/movies/movies_broken_02.R @@ -0,0 +1,164 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + tabsetPanel(id = "movies", + tabPanel("Documentaries", + plotOutput("scatterplot_doc"), + DT::dataTableOutput("moviestable_doc")), + tabPanel("Feature Films", + plotOutput("scatterplot_feature"), + DT::dataTableOutput("moviestable_feature")), + tabPanel("TV Movies", + plotOutput("scatterplot_tv"), + DT::dataTableOutput("moviestable_tv")) + ) + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create subsets for various title types -------------------------- + docs <- reactive({ + filter(movies, title_type == "Documentary") + }) + + features <- reactive({ + filter(movies, title_type == "Feature Film") + }) + + tvs <- reactive({ + filter(movies, title_type == "TV Movie") + }) + + # Scatterplot for docs -------------------------------------------- + output$scatterplot_doc <- renderPlot({ + ggplot(data = docs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for features ---------------------------------------- + output$scatterplot_feature <- renderPlot({ + ggplot(data = features(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for tvs --------------------------------------------- + output$scatterplot_tv <- renderPlot({ + ggplot(data = tvs(), aes_string(x = input$x, y = input$y, color = input$z)) + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Table for docs -------------------------------------------------- + output$moviestable_doc <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = docs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for features ---------------------------------------------- + output$moviestable_feature <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = features()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for tvs --------------------------------------------------- + output$moviestable_tv <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = tvs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_broken_03.R b/apps/movies/movies_broken_03.R new file mode 100644 index 0000000..b218c67 --- /dev/null +++ b/apps/movies/movies_broken_03.R @@ -0,0 +1,164 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + tabsetPanel(id = "movies", + tabPanel("Documentaries", + plotOutput("scatterplot_doc"), + DT::dataTableOutput("moviestable_doc")), + tabPanel("Feature Films", + plotOutput("scatterplot_feature"), + DT::dataTableOutput("moviestable_feature")), + tabPanel("TV Movies", + plotOutput("scatterplot_tv"), + DT::dataTableOutput("moviestable_tv")) + ) + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create subsets for various title types -------------------------- + docs <- reactive({ + filter(movies, title_type == "Documentary") + }) + + features <- reactive({ + filter(movies, title_type == "Feature Film") + }) + + tvs <- reactive({ + filter(movies, title_type == "TV Movie") + }) + + # Scatterplot for docs -------------------------------------------- + output$scatterplot_doc <- renderPlot({ + ggplot(data = docs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for features ---------------------------------------- + output$scatterplot_feature <- renderPlot({ + ggplot(data = features(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for tvs --------------------------------------------- + output$scatterplot_tv <- renderPlot({ + ggplot(data = tvs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Table for docs -------------------------------------------------- + output$moviestable_doc <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = docs[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for features ---------------------------------------------- + output$moviestable_feature <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = features[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for tvs --------------------------------------------------- + output$moviestable_tv <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = tvs[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_broken_04.R b/apps/movies/movies_broken_04.R new file mode 100644 index 0000000..f6f678a --- /dev/null +++ b/apps/movies/movies_broken_04.R @@ -0,0 +1,164 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +load("movies.Rdata") + +# Define UI for application that plots features of movies ----------- +ui <- fluidPage( + + # Application title ----------------------------------------------- + titlePanel("Movie browser - without modules"), + + # Sidebar layout with a input and output definitions -------------- + sidebarLayout( + + # Inputs: Select variables to plot ------------------------------ + sidebarPanel( + + # Select variable for y-axis ---------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis ---------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Select variable for color ----------------------------------- + selectInput(inputId = "z", + label = "Color by:", + choices = c("Genre" = "genre", + "MPAA Rating" = "mpaa_rating", + "Critics Rating" = "critics_rating", + "Audience Rating" = "audience_rating"), + selected = "mpaa_rating"), + + # Set alpha level --------------------------------------------- + sliderInput(inputId = "alpha", + label = "Alpha:", + min = 0, max = 1, + value = 0.5), + + # Set point size ---------------------------------------------- + sliderInput(inputId = "size", + label = "Size:", + min = 0, max = 5, + value = 2), + + # Show data table --------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE) + + ), + + # Output: ------------------------------------------------------- + mainPanel( + + # Show scatterplot -------------------------------------------- + tabsetPanel(id = "movies", + tabPanel("Documentaries", + plotOutput("scatterplot_doc"), + DT::dataTableOutput("moviestable_doc")), + tabPanel("Feature Films", + plotOutput("scatterplot_features"), + DT::dataTableOutput("moviestable_features")), + tabPanel("TV Movies", + plotOutput("scatterplot_tv"), + DT::dataTableOutput("moviestable_tv")) + ) + ) + ) +) + +# Define server function required to create the scatterplot --------- +server <- function(input, output, session) { + + # Create subsets for various title types -------------------------- + docs <- reactive({ + filter(movies, title_type == "Documentary") + }) + + features <- reactive({ + filter(movies, title_type == "Feature Film") + }) + + tvs <- reactive({ + filter(movies, title_type == "TV Movie") + }) + + # Scatterplot for docs -------------------------------------------- + output$scatterplot_doc <- renderPlot({ + ggplot(data = docs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for features ---------------------------------------- + output$scatterplot_feature <- renderPlot({ + ggplot(data = features(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Scatterplot for tvs --------------------------------------------- + output$scatterplot_tv <- renderPlot({ + ggplot(data = tvs(), aes_string(x = input$x, y = input$y, color = input$z)) + + geom_point(alpha = input$alpha, size = input$size) + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Table for docs -------------------------------------------------- + output$moviestable_doc <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = docs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for features ---------------------------------------------- + output$moviestable_feature <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = features()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + + # Table for tvs --------------------------------------------------- + output$moviestable_tv <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = tvs()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} + +# Run the application ----------------------------------------------- +shinyApp(ui = ui, server = server) + diff --git a/apps/movies/movies_broken_05.R b/apps/movies/movies_broken_05.R new file mode 100644 index 0000000..6744bcf --- /dev/null +++ b/apps/movies/movies_broken_05.R @@ -0,0 +1,143 @@ +library(shiny) +library(ggplot2) +library(DT) +library(stringr) +library(dplyr) +library(tools) +load("movies.Rdata") + +# Define UI for application that plots features of movies --------------------- +ui <- fluidPage( + + # Application title --------------------------------------------------------- + titlePanel("Movie browser"), + + # Sidebar layout with a input and output definitions ------------------------ + sidebarLayout( + + # Inputs: Select variables to plot ---------------------------------------- + sidebarPanel( + + # Select variable for y-axis -------------------------------------------- + selectInput(inputId = "y", + label = "Y-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "audience_score"), + + # Select variable for x-axis -------------------------------------------- + selectInput(inputId = "x", + label = "X-axis:", + choices = c("IMDB rating" = "imdb_rating", + "IMDB number of votes" = "imdb_num_votes", + "Critics Score" = "critics_score", + "Audience Score" = "audience_score", + "Runtime" = "runtime"), + selected = "critics_score"), + + # Show data table ------------------------------------------------------- + checkboxInput(inputId = "show_data", + label = "Show data table", + value = TRUE), + + # Horizontal line for visual separation --------------------------------- + hr(), + + # Select which types of movies to plot ---------------------------------- + checkboxGroupInput(inputId = "selected_type", + label = "Select movie type(s):", + choices = c("Documentary", "Feature Film", "TV Movie"), + selected = "Feature Film"), + + # Select sample size ---------------------------------------------------- + numericInput(inputId = "n_samp", + label = "Sample size:", + min = 1, max = nrow(movies), + value = 10), + + # Get a new sample ------------------------------------------------------ + actionButton(inputId = "get_new_sample", + label = "Get new sample") + + ), + + # Output: ----------------------------------------------------------------- + mainPanel( + + # Show scatterplot ------------------------------------------------------ + plotOutput(outputId = "scatterplot"), + HTML("
"), # a little bit of visual separation + + # Print number of obs plotted ------------------------------------------- + textOutput(outputId = "n"), + HTML("

"), # a little bit of visual separation + + # Show data table ------------------------------------------------------- + dataTableOutput(outputId = "moviestable") + ) + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output, session) { + + # Create a subset of data filtering for selected title types ---------------- + movies_subset <- reactive({ + movies %>% + filter(title_type %in% input$selected_type) + }) + + # Update the maximum allowed n_samp for selected type movies ---------------- + observe({ + updateNumericInput(session, + inputId = "n_samp", + max = nrow(movies_subset()), + value = input$n_samp + ) + }) + + # Get new sample ------------------------------------------------------------ + movies_sample <- eventReactive(eventExpr = input$get_new_sample, + valueExpr = { + movies_subset() %>% + sample_n(input$n_samp) + }, + ignoreNULL = FALSE + ) + + # Create the scatterplot object the plotOutput function is expecting -------- + output$scatterplot <- renderPlot({ + ggplot(data = movies_sample(), aes_string(x = input$x, y = input$y)) + + geom_point() + + labs(x = toTitleCase(str_replace_all(input$x, "_", " ")), + y = toTitleCase(str_replace_all(input$y, "_", " ")), + color = toTitleCase(str_replace_all(input$z, "_", " ")) + ) + }) + + # Print number of movies plotted -------------------------------------------- + output$n <- renderText({ + counts <- movies_sample() %>% + group_by(title_type) %>% + summarise(count = n()) %>% + select(count) %>% + unlist() + paste("There are", counts, input$selected_type, "movies in this dataset.") + }) + + # Print data table if checked ----------------------------------------------- + output$moviestable <- DT::renderDataTable( + if(input$show_data){ + DT::datatable(data = movies_sample()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/movies/moviesmodule.R b/apps/movies/moviesmodule.R new file mode 100644 index 0000000..ddf55a6 --- /dev/null +++ b/apps/movies/moviesmodule.R @@ -0,0 +1,39 @@ +# Module UI ------------------------------------------------------------------- +movies_module_UI <- function(id) { + ns <- NS(id) + + tagList( + plotOutput(ns("scatterplot")), + DT::dataTableOutput(ns("moviestable")) + ) + +} + +# Module server --------------------------------------------------------------- +movies_module <- function(input, output, session, data, mov_title_type, x, y, z, alpha, size, show_data) { + + # Select movies with given title type ---------------------------------------- + movies_with_type <- reactive({ + filter(data, title_type == as.character(mov_title_type)) + }) + + # Create the scatterplot object the plotOutput function is expecting -------- + output$scatterplot <- renderPlot({ + ggplot(data = movies_with_type(), aes_string(x = x(), y = y(), color = z())) + + geom_point(alpha = alpha(), size = size()) + + labs(x = toTitleCase(str_replace_all(x(), "_", " ")), + y = toTitleCase(str_replace_all(y(), "_", " ")), + color = toTitleCase(str_replace_all(z(), "_", " ")) + ) + }) + + # Print data table if checked ----------------------------------------------- + output$moviestable <- DT::renderDataTable( + if(show_data()){ + DT::datatable(data = movies_with_type()[, 1:7], + options = list(pageLength = 10), + rownames = FALSE) + } + ) + +} \ No newline at end of file diff --git a/apps/movies/moviesmodule_template.R b/apps/movies/moviesmodule_template.R new file mode 100644 index 0000000..8582b8d --- /dev/null +++ b/apps/movies/moviesmodule_template.R @@ -0,0 +1,25 @@ +# Module UI --------------------------------------------------------- +movies_module_UI <- function(id) { + ns <- NS(id) + + tagList( + ### add UI elements ### + ) + +} + +# Module server ----------------------------------------------------- +movies_module <- function(input, output, session, [add other necessary inputs] ) { + + # Select movies with given title type ----------------------------- + ### add UI elements ### + + + # Create scatterplot object the plotOutput function is expecting -- + ### add plotting code ### + + + # Print data table if checked ------------------------------------- + ### add data table code ### + +} \ No newline at end of file diff --git a/apps/nytimes/app.R b/apps/nytimes/app.R new file mode 100644 index 0000000..ce8ea5b --- /dev/null +++ b/apps/nytimes/app.R @@ -0,0 +1,15 @@ +library(shiny) +library(jsonlite) +library(dplyr) +library(lubridate) +library(stringi) + +source("get_nyt_archive.R") + +ui <- + + +server <- + + +runApp(ui, server) \ No newline at end of file diff --git a/apps/nytimes/get_nyt_archive.R b/apps/nytimes/get_nyt_archive.R new file mode 100644 index 0000000..1045bbb --- /dev/null +++ b/apps/nytimes/get_nyt_archive.R @@ -0,0 +1,29 @@ +get_nyt_archive <- function(year, month, day, api_key ="75f29a4d07eb423096785401b763c22d") +{ + year = as.integer(year) + month = as.integer(month) + day = as.integer(day) + + stopifnot(!any(is.na(c(year,month,day)))) + stopifnot(year >= 1851) + stopifnot(month >= 1 & month <= 12) + stopifnot(day >= 1 & day <= 31) + + url = sprintf( + "https://api.nytimes.com/svc/archive/v1/%d/%d.json?api-key=%s", + year,month, api_key + ) + + date = paste(year, month, day, sep="/") %>% ymd() + + d = fromJSON(url,flatten = TRUE)$response$docs + res = d %>% + select(web_url,lead_paragraph, print_page, multimedia, + pub_date, headline = headline.main) %>% + filter(ymd_hms(pub_date) == date, print_page == 1L) %>% + mutate(headline = stri_trans_totitle(headline)) + + stopifnot(is.data.frame(res)) + + res +} \ No newline at end of file diff --git a/apps/soi/soi.Rdata b/apps/soi/soi.Rdata new file mode 100644 index 0000000000000000000000000000000000000000..7e1986130ec56a97a2fdebc0fd3e24c3e83b9600 GIT binary patch literal 3147 zcmaKpe>~Is9>+tP5l(b-{9GzII_H>^)H2zXx^7V`Kbnpon^P1zOd2Np&TprCW8u`w zk5)$|M@&~DvKd8Ae&k1+$bKNhY{oMC@g4Wx?s;(UdE7^zKVE-4-_O_M@p-)8u)piA z`}A}OMUb18FU_;51Ll#Kpt_G-+uTfUU*Bct9dXH4PEefF&`0j&*;stI9m}9De;Kw8gH){#^1vkeSw;@Fj#_Di#o+_$0nALA$NopXo(90}tjq%ki zQW&biK$3l#AKG9n$${`alJsn{z4(21q5&<#ufm{#CO6XWhnWX%xsmZ9P1S|c&ξ z4@4N{<(TphA)v>z{rLVmhBn zPMeIf+HfXTMqVvvZ)$tBj!W0OLD8%M=|-Q7bAtUzHle9z8P!=Lma0bUf}SO-y#{(g zznC>yqk92r#(If|2J2HuW-Z0p}Q|i!_p_H0`lbXfCZ`<|a?ry96!z+Zg zCB9m!qp-c217j`Y*ZHLC2s)&u3RBR0S(}{2Wbp(rDf&E%$>&J}Pn^E+``QhphZQC% z<_v97D@G8Fw<$3;Ysr%ODa=7DK#Q4)Wzhxuq_!#RVQoG)byw2RxV@m+WXlRJ=EU?c zq`j3<152@HXz?=Rq~9v`ra%}5#;i7}o}0d(pk9hp900YJ^_t(9`R{t&da=gs(Ymi& zkJjvdq+Qt>Rpa_d%bwMV*Duj8XHDZblt9n1-rvLmR%SQhO zomo93tEc9FE|0f-Z`$vIaC(1vC>xL~ky9T#r>dkziqpT>P?fQ4j zc;KC^v`qyk5F2;01b<$YRR}jNbgQ3qkDJZ_|J@zm?I@Q8zfTcl%+4{yc@F9A%|3?n z+q%k|^c=Ij`MwPs9do|sA6?^?>F6+0DGsGFJh6m~D+4#1Il@4sPv!GZ$X&)~fYdppz`TC+Y^ z%%@!i&raBHN0|eiQtxc+Zm>W=-N-zvuxo>xD?4AI{{rk@C|pCU*6&4o)PA6I-a8L_ z5iA&|S}`XSb{+8j%Fa&oap2-Y;Tl@C3TY+a#Dx9-E$S*AUZFhz{RKZhRhzk4alZww z3phx<)3ExW?=@OFxOt*{D{2j`S)VEPZ$%j{419_fxFOj8hxqK&w}4gv{yb5>17!y| z%zIzK9tC~Js3y#x7587j?UW9k=p(?<1-~`4YW-eJq1e}4QY3oC$J9){EtwyZisrc$ zR70lYTMm7+Z{b$-_Vu*I^tVNIC4kOy)0AqAK<-Odne)V<}! zy#dUV?n|-(w0Y$g#NTZtI ze>=d;da0Q35B2kKNqO8*%5-zMJZ+N0<5GCkD0*Du;yiFkqaqB#gBY|`Y zRaZ;!Qxhjg-+t=^$C|y3-h+*99t@>b0ufeR=LA>P~zBz^Ik*C2hejI_Js3C8-tt?`p7qsX%} zKQO4^BS1lbc4PiDgWX&#uIm_+V}d*!YnW-{)8iBXg@M+&XuQ`k9AuMo<6si5@qKLNh55ajKXkfPobYJ!I7yrlAx15I#+L zqzE~k?3jiVRtx>bj%6IB_sK@eeB-Bmt^J?u|L^ov5twHsI;v$8lIcH zd~ck1O3li{_8u$pdi^n0CDRO*-0CGA`1p+NDRQYLSy`(O6aA1ObL}G-f~JAEq$?I{ zNRVM3QqCNO>xeZfSrJWMsKSsIW9S3R{qE;)oe847n@oP|DI}2VjZ;?kLNt@^7PRU5 zapFOdn5!dOc;-xyB)PvKHlf8!x7vS?V2s%vgKXT!`3m?%aoy z;~X~^3c8Ef9n{ens$>%n2&ZH>Dhel~Imb97%K=`*Hut3p+9`F@Vit_qjyx}krcvM0 z+AB4cvSBYtpt>D}tsvJ8EW13DiXtUK(jC&9SoeC(G{d4?#d$2h%MOcDBS6MJ_4C9h z$-U>Xi73jnSaa!W2fKsB#l&lF%_j_=l$EmGZC1c2P8+B$#geY;Iqf`^tzan&gkQ?u|srp9P=>M&>vI)8^>sDsH`U4@c=bBofC@T|=^$ zXcxzZ)jabVwCu!zCwV%PL$kGcypZpWbAyB~%p2@lF}c|yen{bI?<0T{oj?>ew`A5G z2j-g&@~7raDMdK?FnLVj(0J5-d$k2ql2$nVW{% + mutate( + date = ymd(paste0(date, "01")), + year = year(date), + month = month(date), + date_for_plot = year + (month / 12) + ) + +# Define UI for application that plots features of movies --------------------- +ui <- fluidPage( + fluidRow( + plotOutput("plot", + click = clickOpts(id = "plot_click"), + brush = brushOpts(id = "plot_brush") + ) + ), + fluidRow( + column(width = 6, + h4("Points near click"), + verbatimTextOutput("click_info") + ), + column(width = 6, + h4("Brushed points"), + verbatimTextOutput("brush_info") + ) + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output) { + output$plot <- renderPlot({ + ggplot(data = soi, aes(x = date_for_plot, y = value)) + + geom_point(size = 0.8) + + geom_line(lwd = 0.3) + + theme_bw() + + geom_hline(yintercept = 0, color = "orange", lty = 2) + + labs(title = "Southern Oscillation Index (SOI)", + y = "SOI", x = "Date") + }) + + output$click_info <- renderPrint({ + nearPoints(soi, input$plot_click) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + + output$brush_info <- renderPrint({ + brushedPoints(soi, input$plot_brush) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/soi/soi_02.R b/apps/soi/soi_02.R new file mode 100644 index 0000000..fd9f2c6 --- /dev/null +++ b/apps/soi/soi_02.R @@ -0,0 +1,68 @@ +library(shiny) +library(ggplot2) +library(lubridate) +library(dplyr) +load("soi.Rdata") + +soi <- soi %>% + mutate( + date = ymd(paste0(date, "01")), + year = year(date), + month = month(date), + date_for_plot = year + (month / 12) + ) + +# Define UI for application that plots features of movies --------------------- +ui <- fluidPage( + fluidRow( + plotOutput("plot", + click = clickOpts(id = "plot_click"), + brush = brushOpts(id = "plot_brush") + ) + ), + fluidRow( + column(width = 6, + h4("Points near click"), + verbatimTextOutput("click_info") + ), + column(width = 6, + h4("Brushed points"), + verbatimTextOutput("brush_info") + ) + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output) { + output$plot <- renderPlot({ + ggplot(data = soi, aes(x = date_for_plot, y = value)) + + geom_point(size = 0.8) + + geom_line(lwd = 0.3) + + theme_bw() + + geom_hline(yintercept = 0, color = "orange", lty = 2) + + labs(title = "Southern Oscillation Index (SOI)", + y = "SOI", x = "Date") + }) + + observeEvent(input$plot_click, + output$click_info <- renderPrint({ + nearPoints(soi, input$plot_click) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + + observeEvent(input$plot_brush, + output$brush_info <- renderPrint({ + brushedPoints(soi, input$plot_brush) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/soi/soi_03.R b/apps/soi/soi_03.R new file mode 100644 index 0000000..9c45b66 --- /dev/null +++ b/apps/soi/soi_03.R @@ -0,0 +1,96 @@ +library(shiny) +library(ggplot2) +library(lubridate) +library(dplyr) +load("soi.Rdata") + +soi <- soi %>% + mutate( + date = ymd(paste0(date, "01")), + year = year(date), + month = month(date), + date_for_plot = year + (month / 12) + ) + +# Define UI for application that plots features of movies --------------------- +ui <- fluidPage( + fluidRow( + plotOutput("plot", + click = clickOpts(id = "plot_click"), + brush = brushOpts(id = "plot_brush"), + dblclick = dblclickOpts(id = "plot_dblclick"), + hover = hoverOpts("plot_hover") + ) + ), + fluidRow( + column(width = 3, + h4("Points near click"), + verbatimTextOutput("click_info") + ), + column(width = 3, + h4("Brushed points"), + verbatimTextOutput("brush_info") + ), + column(width = 3, + h4("Double-clicked points"), + verbatimTextOutput("dblclick_info") + ), + column(width = 3, + h4("Hovered points"), + verbatimTextOutput("hover_info") + ) + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output) { + output$plot <- renderPlot({ + ggplot(data = soi, aes(x = date_for_plot, y = value)) + + geom_point(size = 0.8) + + geom_line(lwd = 0.3) + + theme_bw() + + geom_hline(yintercept = 0, color = "orange", lty = 2) + + labs(title = "Southern Oscillation Index (SOI)", + y = "SOI", x = "Date") + }) + + observeEvent(input$plot_click, + output$click_info <- renderPrint({ + nearPoints(soi, input$plot_click) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + + observeEvent(input$plot_brush, + output$brush_info <- renderPrint({ + brushedPoints(soi, input$plot_brush) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + + observeEvent(input$plot_dblclick, + output$dblclick_info <- renderPrint({ + nearPoints(soi, input$plot_dblclick) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + + observeEvent(input$plot_hover, + output$hover_info <- renderPrint({ + nearPoints(soi, input$plot_hover) %>% + mutate(month = month(month, label = TRUE)) %>% + rename(SOI = value) %>% + select(month, year, SOI) + }) + ) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/soi/soi_04.R b/apps/soi/soi_04.R new file mode 100644 index 0000000..bb89cc1 --- /dev/null +++ b/apps/soi/soi_04.R @@ -0,0 +1,47 @@ +library(shiny) +library(ggplot2) +library(lubridate) +library(dplyr) +load("soi.Rdata") + +soi <- soi %>% + mutate( + date = ymd(paste0(date, "01")), + year = year(date), + month = month(date), + date_for_plot = year + (month / 12) + ) + +# Define UI for application that plots features of movies --------------------- +ui <- basicPage( + plotOutput("zoom", height = "350px"), + plotOutput("overall", height = "150px", + brush = brushOpts(id = "brush", direction = "x") + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output) { + + p <- ggplot(data = soi, aes(x = date_for_plot, y = value)) + + geom_point(size = 0.8) + + geom_line(lwd = 0.3) + + theme_bw() + + geom_hline(yintercept = 0, color = "orange", lty = 2) + + labs(y = "SOI", x = "Date") + + output$zoom <- renderPlot({ + if (!is.null(input$brush)) { + p <- p + + xlim(input$brush$xmin, input$brush$xmax) + + labs(title = "Southern Oscillation Index (SOI)") + } + p + }) + + output$overall <- renderPlot(p) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/soi/soi_05.R b/apps/soi/soi_05.R new file mode 100644 index 0000000..697b9f7 --- /dev/null +++ b/apps/soi/soi_05.R @@ -0,0 +1,54 @@ +library(shiny) +library(ggplot2) +library(lubridate) +library(dplyr) +load("soi.Rdata") + +soi <- soi %>% + mutate( + date = ymd(paste0(date, "01")), + year = year(date), + month = month(date), + date_for_plot = year + (month / 12) + ) + +# Define UI for application that plots features of movies --------------------- +ui <- basicPage( + fluidRow( + column(width = 6, + plotOutput("scatterplot", + brush = brushOpts(id = "brush") + ) + ), + column(width = 6, + plotOutput("histgram") + ) + ) +) + +# Define server function required to create the scatterplot ------------------- +server <- function(input, output) { + + output$scatterplot <- renderPlot({ + ggplot(data = soi, aes(x = date_for_plot, y = value)) + + geom_point(size = 0.8) + + geom_line(lwd = 0.3) + + theme_bw() + + geom_hline(yintercept = 0, color = "orange", lty = 2) + + labs(title = "Southern Oscillation Index (SOI)", + y = "SOI", x = "Date") + }) + + output$histgram <- renderPlot({ + brushed <- brushedPoints(soi, input$brush) + ggplot(soi, aes(x = value)) + + geom_histogram(border = "white") + + geom_histogram(data = brushed, fill = "orange") + + theme_bw() + + labs(x = "SOI", title = "Histogram of SOI") + }) + +} + +# Run the application --------------------------------------------------------- +shinyApp(ui = ui, server = server) diff --git a/apps/ui/ui_01.R b/apps/ui/ui_01.R new file mode 100644 index 0000000..acab81d --- /dev/null +++ b/apps/ui/ui_01.R @@ -0,0 +1,25 @@ +library(shiny) +library(ggplot2) + +# Define UI for application demoing UI construction ----------------- +ui <- fluidPage( + plotOutput("plot", brush = "brush"), + tableOutput("detail") +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + output$plot <- renderPlot({ + ggplot(mtcars, aes(x = hp, y = mpg)) + + geom_point() + }) + + output$detail <- renderTable({ + brushed <- brushedPoints(mtcars, input$brush) + validate(need(nrow(brushed) > 0, "Click and drag to select data points")) + brushed[, c("mpg", "cyl", "disp", "hp", "wt")] + }, rownames = TRUE) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) \ No newline at end of file diff --git a/apps/ui/ui_02.R b/apps/ui/ui_02.R new file mode 100644 index 0000000..50bd1a2 --- /dev/null +++ b/apps/ui/ui_02.R @@ -0,0 +1,31 @@ +library(shiny) +library(ggplot2) + +# Define UI for application demoing UI construction ----------------- +ui <- fluidPage( + fluidRow( + column(5, + plotOutput("plot", brush = "brush") + ), + column(7, + tableOutput("detail") + ) + ) +) + +# Define server logic for application demoing UI construction ------- +server <- function(input, output, session) { + output$plot <- renderPlot({ + ggplot(mtcars, aes(x = hp, y = mpg)) + + geom_point() + }) + + output$detail <- renderTable({ + brushed <- brushedPoints(mtcars, input$brush) + validate(need(nrow(brushed) > 0, "Click and drag to select data points")) + brushed[, c("mpg", "cyl", "disp", "hp", "wt")] + }, rownames = TRUE) +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) \ No newline at end of file diff --git a/apps/ui/ui_03.R b/apps/ui/ui_03.R new file mode 100644 index 0000000..b79bc1d --- /dev/null +++ b/apps/ui/ui_03.R @@ -0,0 +1,14 @@ +library(shiny) + +# Define UI for YouTube player -------------------------------------- +ui <- fluidPage( + includeHTML("youtube_thumbnail.html") +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/ui/ui_04.R b/apps/ui/ui_04.R new file mode 100644 index 0000000..3f86eaa --- /dev/null +++ b/apps/ui/ui_04.R @@ -0,0 +1,22 @@ +library(shiny) + +# Define UI for YouTube player -------------------------------------- +ui <- fluidPage( + div(class = "thumbnail", + div(class = "embed-responsive embed-responsive-16by9", + tags$iframe(class = "embed-responsive-item", src = "https://www.youtube.com/embed/hou0lU8WMgo", allowfullscreen = NA) + ), + div(class = "caption", + h3("You are technically correct"), + div("The best kind of correct!") + ) + ) +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/ui/ui_05.R b/apps/ui/ui_05.R new file mode 100644 index 0000000..6dfe572 --- /dev/null +++ b/apps/ui/ui_05.R @@ -0,0 +1,42 @@ +library(shiny) + +# Define function that takes a YouTube URL,title, and description --- +# and returns a thumbnail frame +videoThumbnail <- function(videoUrl, title, description) { + div(class = "thumbnail", + div(class = "embed-responsive embed-responsive-16by9", + tags$iframe(class = "embed-responsive-item", src = videoUrl, allowfullscreen = NA) + ), + div(class = "caption", + h3(title), + div(description) + ) + ) +} + +# Define UI for YouTube player -------------------------------------- +ui <- fluidPage( + h1("Random videos"), + fluidRow( + column(6, + videoThumbnail("https://www.youtube.com/embed/hou0lU8WMgo", + "You are technically correct", + "The best kind of correct!" + ) + ), + column(6, + videoThumbnail("https://www.youtube.com/embed/4F4qzPbcFiA", + "Admiral Ackbar", + "It's a trap!" + ) + ) + ) +) + +# Define server logic ----------------------------------------------- +server <- function(input, output, session) { + +} + +# Run the app ------------------------------------------------------- +shinyApp(ui, server) diff --git a/apps/ui/youtube_thumbnail.html b/apps/ui/youtube_thumbnail.html new file mode 100644 index 0000000..46703b5 --- /dev/null +++ b/apps/ui/youtube_thumbnail.html @@ -0,0 +1,9 @@ +
+
+ +
+
+

You are technically correct

+
The best kind of correct!
+
+
\ No newline at end of file diff --git a/slides/01-fast-intro.pdf b/slides/01-fast-intro.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a33ecfc7299ba20f66a2d2f9adf7248d3716821f GIT binary patch literal 4238742 zcmeGDRajg>(>4k-KwxkSPGIoh?(Xg|xVyW%OK^9W;7)>T&=A}`1cxxV!zR!3zW@II zqkXau_qFC)-CZqJ)phskuI?U6WpPOc7DhHi%Avi>y_1To!s(%5M0OA}$kD_Gk)I#L zBya9u>1GAucqgfXm?W+3+{|6xLpx(Pb8&N1M>BJfpdg~Fn~S-zJ)##NPIbazjTyb` zgl_-yC$e+ZQsNPQ9d&_a`$^E}7$WHYU^Ojgd+Nw%|HxFGYUdzz=poXU+z}Vg`q49UxIF84EqSFFrm!YesK+{YbO4Al<`2YlEzje@Re97 zF@M)IqL@OLcqv46JwXTX0U8xQ-x%zshV|HI7c-cIHq zCS_yG|GZty9o#@{|24U)xvQhQi>bLQi1WV$F-Hft_k35-KbX8@Lc!e3+E~=l3#7~Z zPGI3-eSa}?GwUP11LJ=<{j2%EfKqmGG*vTq1L?lA6PE-rshfMbftY0M-&u?PPbl_3 zp$teL#3bfu=jfv5WNc~<`iDm`SC;qY|8ahA{~d_$!u*G>Zu(AV`L9Ik>hJM?+PzDs zuFeW#`5#r()!9HS|CRb*T`eUO8*|ft)e+zMvw*n&TSLbFy~cm>{;!mpm9d$%gXMpi zs9CXqxc*b>J?H;c?;q)Z)%!oh{jZq+zZU+}#ccl+a&$3seb@h=7XN)%n3?~nD(+}+ zZ0+zb2a)ApTEgqSqs`vaZZ7WT|9!nvCEXoN-K-rQKrH_i`2UvUU;2OL_@8mh^G^EL z3;!|i|0>L+=5FHlAIg8a9mJ$*ZT3FKS=hMQK}^!-)|OUoATA!(cPqSG+QrH7-(W}l zj|~5(HU3w2qG^zjb$-u|m()Dkx?!p3_z;Q}m z9yUHceirqw?z=xiE<97d1{jD)A8|g@D{B=t2pb0vK!<<${|NtIfBe4#hix9~-~&e) zug$B13~`o$tAcNovgfJEy_#VI(4MoWdK-!0|myLZ}wdg%{K+l2?JsxxeOF~iu6ZtC; zg{^CadV0}@zUny$+AQRZ(Qm}_{TBhrMmNZaI7bXtUEX@E-5Rer-D3*maR?g-c49&i zh_Pj$cf!@)p0F%T@5Y3CNHYOz@$`krYE)gG7xU@3YSJRxA>Ha52iM|_;qd00;uwAQ z$_UF4%owCId{m9r806XvhS(cQ0>Y9}f-+D(M8?o2zcoZ8ihiwqdrJ6Q4oP6!={z@6 z7S2}a_3VZO+A}}TRqYhmN!$l=626}EVFi2+rhm+24wt=*}3eVi9T3%x@}+F=rlX^ zKj<+2vY0P1z);^=J+?Lkztw=P7FDum`60 z!aX&BZ&Xarq6?678(^=NtC#2GPWMUp-8|9e+w0w13{r1;#9Ly-)_vU8eIb$=%|jo& zpfJ+g?bhp>XU|pMcbR*Ab4cHBj4pT#DEcN1`k?loTtS}eaP_AI-YQh;+JqWNv>mSK z+l=#Flxip*eEG)3i1N#bunoqah*{07BT4^qKU8UU%c{T_^%VwVs(@!g5QONqciN-y zs?aWNiPD!C+lnd+_!#u~c)zO5G7sL_aUSYT`lL{wWMq(sX1i<^L@0ougj}0mgL;~V z&X8}gNtU7b@(|iLdXZlh4$`sYN7j!ZSVE5_gaaQ=5VueXOccjMHf?8R`yAxx2faAB z)H{B<7b(FmRuvKra=ekDEtw^acLw}DK&}*@9x{T5ZViG9MIy$TkChvTML~O+l?-w8 z)PMBf>*qBL_nPwUV_6ueuftXSP9FH?9}acf2syzX2$T;Ul;`>5m=?M9Jh}A~W4z&Y z4qnJ=#s^yDW>sueuMI+o^qNu147oO8T<_~my(Lhg3f2!8E}hQWq@jZVlE>kl`D#gP7NquxZ(Xs{ zAjBc5al#u6MAmw88|+BdCNfSe@)&UN6!+Vb6lDziia@Q7T_p%elE5M6{;ZErq)s=} zs+uFcrAKP#u?eaiNsUDNh9o+EvNpPc#i?K2*ka>$4er=8o+dLW1Z!gi!gb2uH?&GK3g##=gQaCg%;jxA_-5$0u6Pr#48 z!Pr4{0^W@3YvP{e>Lmg zrt{&oVd1h}-cyKt zI``}({1czYDdJ8ex_a(wahReBodemo%=6DeAD=CLUzynRLK`|&@Q_ttd}wu~R2Hl{+`${q@z#aOOxk1`fG)$nI%Ow` zF}y##X`lfXYh!Z^e9EC4=IVVoBbDS<%1TZ@-v1n5*XXmD!?<=POC*7B^QK$iP*&KNcIYs*i+nyG=$J>qMSsON|Y#jQc+60u*45c`io|rs(vf-*m{^t zI~$Z*TOuaqmE*GH(U=~e^mtyJ1xnord}z@cXreABMyH@kWpX6K*pwe=Z-zh`6Y1CN z%t$mz&FnkoC=3Pv(q^2pUSKL~{N=8<(utAa7i7F2QoDXaK9Oz4J%roTW*%PkgI;hC zoDFwjs0$@K-4^zvd7lp1h$dq%!gnHTrptFsNxn$d@MsH>aqxP|(}n8b%HL;E>oGM^ zl$_Zm5Z}-Ha}I4n8GAr*IM4Erj%1BKH}%w;w6x;ABQ%?nh4M669z-@TPgM>Zx>NIj zY^aq)vR0v0;y3y_N)Gg8DYIYyOIR$O1G>?W=aw6a6S$132ij{iCAT`M=iJchQrg7V zAV|5#kzi>G-Fli#;baLZ&e{q{N{70ZNt?2m z*gMXX2uD$(I?36-{UKXyT69WtHMMh9!CDQTAFHFROrq6VHr3zl zA*vjl>Z#hCnk(q9qXsOS%H@HHOoft)Znm7FEh5?#%jNToS4EK}q#h@86-4=HEsbB+ zi(3`(We>2DpHEC{>v#j*h?0JAHRZ^$3oFUnheCy##kXGrqX(a+d?oN}#JcYl1~tX3 z=PAz7k6aq(GklA2`}FzCtz$D}e~{!6{fn94&$qYdC*Gj>RA(yI>C*jMi|wiwl!-CX zlc09?wz}X;(^I!<*&`;SaaKt>V{NQuS~A@AvgNYhTc@qr&ip&|xIQI8&=XIzGd4_U zp9@`C!Z*al&}GF30vOU|2%?k+1gS9=L0^J`zeE+X<2s0=4>s|pZG$94L#UqVLuYt9 zcN*c`!e~Yb;-i3}gh7ZU*q&aeiDlTfeVQQ`LdqdEv}jI(4`c9uI}<*J-vwT#sC={tV6J@_dbtZ^jWfTwDuco0 z2~?5HIf@-+k&P%DZlTqN2AI!&N2Dtf2!m0nlw0HqhcVa8{G~0P7+jOJ2?Z_A{(XTg zCG0DO9V;g?r$zu#T^T1ugt8(#hDch}ZuRHMWv_0YurtowTiBA{ZqqN{Q8O8kiintY zvmp3(Cx@#QdnKpcM~C0zgIhifPZ|6)OD&vFC@XRompy(c?;jq^Pt+;%QBP~Et#@EI z?`uB5|QS)m7fhG10hByxRHZ7#V=^Ol>$*aE?uM)@%^(L8v2?qSqck z)d&~1Dn4mO!r4l$-O0CZX!X({a%iuy4b!2r4Fl*)vWs!Pc7)>ngy<@buSuA$5~3a) zYn%mTg-R2}Tv`a(`MClsRXX_g$1#NDS3aeq8#Y;$!*(#OBw-Phh}zUOcc?11GMTIb zCd9afno++)Jzj3yB~|A;=D^-%p}azUyVK3FhD$c@Z7U&{gPv#6w{Kj3j50pluM}dA zpDT$O8j=vXpogVyYza*ZF*7TVgUb^2G_`JQZN^(nZaSz+!WJee{pbv87vg}E7HS&# zd%8DYZ~EEApQXiU)1J%RzVhQqQPw2Z%*d+$Mn*%cr?ZBp&8-a)2KO#phTYDos_(&J zLEK%fQ^H2El`Y~-3_`&>a2LS`olbkl*gZL~zLQF@Lguj{%gs=NCIKm-ddq))dibJ7 zc8=)7wr3=0L#i9*Nk}H9UQef32g4(w=m)>1RZu7i_@r|=-v>J27)3>CB z13pPtv-6kLsdQ}Tm)b*g09UaE`_yD@v{ zx7pFfhXec{G+PlPR2D>(v1l0BGqNjqypx%k@y{Gc_NJpz!opGsE9xWZobxq`h428| zji&LI;+7oNz#Z$!>?1N0rrjNVqc50EeIOsY=TGdb4lUHD<%A-YaZ@kUBZ4ZA{kyKf z9ig)6*TI?sOTiAD>yttf-%Q$i0_AXi-fq!M75Kx_TNKfHQK8~#zvEOGz}%Xw5VO;@ zq>(YObN4Z6n%+~q*<%Zv4+w@frL^$^nI(t$sY zT|kH(9!owpS_2B*E?#i%q6=w-FBXxPd=#?!8SjDKpn{UjTZKgx$-dh}!bI5QOEKwMvh zIk~JV%e4Xbeo)1#P13Y;F@9j{mp@+>xy^21aAc~q80WIf*>$<9zG|D=pfzj4j>u(q zod+RUm6Q&%48+7X6h|=w$o+IZtid|bQS-?Xvzci&D|ft_Alfpv@@e2%tvP8|W<|Gr zI#__#v4y%O#!|9nY+m$`QZwm#ygEukLR(G}TJQ_A_7>KjSC-zYW;AS_tCv`zPuX#pi5isx5so_|rN<;AY_~aGE zhH2E-hZlMgfhtt!4(x|StngZpWN}#*ar<`jES^{Q99O#pUv>W+vhJHnvQsh=;;x?5 z226x8m7A_ti>XCqAk#RjomkCLf$ZjOruzT|FVp$;ruwR%pxE%*g1b@j?SZw22{TO? zykTu_Yqw_su&>i?_ScIMhrA{UiIwKfhke6uXo1ISLy>=b4NF8#(Q?TN01_zZpJ!4R zv9;g9wO0y3aGNbb;1vS{!VP-L^gv6t;7cc&B>HsrY64?Ucy6DB}Yx{Eq2isG3;t%p1uvxhY*vqP$L=`XFb^eR*btR6fow8LW_Q#RfMe@OX-rpMs( zF~20mg1-@(iBnjtxPOpu;!RpwJLX7Mt+s;w;DfC~P}!`y_w z=(LVnXccQWhH}{79u(dAdc3L*1x&jKiyaE(-)cEpG+@W^)2~jAD9|LKoS9DmxyG&7 z0O;>UqtNR^O=e(Q*K#bTjz2X*n;(_GqjsghRsbfLxfg@PZkMlqx%i|PHa}t70fS6R znFRzUTVN_Nr&-0(O5Dn6p1+GmtdA}0gCsI*5<6%Zkbe-!YaViwyj=R>fBJw>1{0|= zBZh8QQu0z-{45iS11ciG)4lk9sWR*roh<%^^Gr>{q_P!WiU6&jfYstqk4B^_)mfdg zC+4e*f_|CK*jKWpV@9rCp|4<;0v+G{u}{H{2?EZK>l- z#btPvhc!jz$jhg6+^4QvteMA-VGZXgTv{b9f%c+8o6(}Jr;BB`7iwvONcP%gbY=V` zblClOWi6P_?A1zI8YY+dl@e6jU--{{6izB)2#xD}!6>Mqox+~B9RsVxucXw>`oP!9 zQ5ltiOEsh`P2_U7 zAnPQnazdf+`tJO)x3_J}Y5JPLEYn%nHhW z-$ghxZ-Jq0XrJd&DJzn0zbQgA)~Fi2C)?^c&@8Ha_fZQOW#-BXQ z8(H)<%H|TZUbm_=%)@)Y3@GM%bj~jJIp#X`7EYYst5;&>qptNCx@v6CdCJIb0#^vN#g}~y%x7S_8a@>NnPWA zYQB3um0LmXX;23HTv@GVHcg$KIU7Ut?FZ8AzX%WH0}Kf6JzsxqUGzN=S6mcB%3Ta7 zA;VlfNv0Glwo|1%;JqGdC2a|a@iJ8YAC;f*X_jt=Z%_$##LxWgV#uAPc+jKNl08`b z(Dxf4i3EN$Rp@dX^aCZsHGi`iazaVym&<Fy7hq4caU` zEi1AyQNNQoIKx26g5nTW$LiNxNI1sFPbr6?2e#J9<)SVcS&2AxS6o$^GQ5~`^aB=v z?pwPXSw9Mu(f@>W&`C7^N~3cd;0ytcqE) zw{V_$m5y&T+MS{Vmjh|58jZAN<~piz#(mURhaiU)7yOVy z>mRew72W|d6r;PU`N;&(Cg6Dm5llC~)D&579zwVTdxAgSS$3lkW`lyAYc@UA2VDD9 zrr05tXi`WNMg>4HbOM(tcQ=z>``P>QJ3WCZi0WxWDUY9${xuI27_nen^W3y&;05?j z%SbafIqSZg@ZIlWHXKQy3GFr4E>dV~@HfkC{#V?PW9!7oUOh)V5el?kn{WGV6Q`!g zNtF3tx6Ux|HyUb()2p z3S{Ot5>&51BzTq=Ah_4~lN65*^>&$NtKQ{wq&g)*2J2I&*MV7%X(gG99yPHo;S5Xj zu>@ZQ(?`@dqh7Dq>j=?(2ITYZLG=McdE%KXf^m4sg?{Yxg9Tx$I4W>4Wh}FtT*TB_ zxa1^uEz`7;Fb%kMQ)~b7l=riR+EWBqRx;hRq{X-$%PRx+tg;t&A7pi>x?gGC9Hx@E z1Ta)2(r~i;>Ppjm$TV3^vi*jpEEHy=YUGC+nL?;*d?*Kyd^?i;hQ854;_Af3-K)*p zJxN{Suz!eCpaPoJYeYo!b`Zb{rY4!h|dT{l?7&4Q^8G{#Vv#FH9@onkDY?G=V>rfd+AgUQ zPEw_E1hPx$!%)~lp}OFp=r(c9QtHNM@Y~K``_}P$w)_As&Z|4dezlyxaG;vu4#cH_ za}h;sw0&BdYu44e@~SymI*o+;cK5iWaMvu_!Z;rto_3n;_(Wax@XFSf;+ZKP=sx$z z$C_-{o56Lr#EMyac<%-Q@?cAZDU5uiQ@wrXP+h1BfD#oyT!#o@Z!rH?UcMDE1sVWq zMTx5{|H#YHQIz2ohv8M4;X@i+?zuBG?zo)c#^b%eJ~nrtXvOb(JD+uB`RgXv5^8v?TNA#jRtp~SRpI%TIP zSi}!ED)+qI>sTJmpWEa3=S)hmltv!E|EqlFTwkw9!QKNNKYWo8hBPUmbLoVj)m*mZ zKo79v*4aYc*>&YB&xC_wPQ7^*r-GNgtfP)bSfbCW4)GX#K>&h~>BR zUmVi&L*>52M;9yW9&uxL^M{@34Jrb}^3mS?W`Bu`hj#=%)u}W|vNQ`bTvDAz>(C0C zvR;BdqiHL8w{I6lH5bt@e9)fwB?~75y`i57m^3Ha5IEqemOu^vNHl5Y<0APbcbY7+ zIc#v<_g4X*Z$xOWBGJ-9>XArN2Q{0*OiHdET4aWabr^npjnc=+<`Zvg90uZpApBx_ z7~uIdq6-mAG(61dr*-&if!G%wQvo9ABe+=BRZ6;mgfFBNk zQO6Valg`X6`ZUmVA;ft?ZHESBH*rxWnWI%I^^l(3g+W`d zjl~u+6*PmMK8a~igQ-w^-0%M^Yu1Knu1%Gznr9jPTQevfo4I!F12&jNNea6RSPO`z zDQanJa-ii%`7W3~Va?mHXurq#;o7pf1M_Y!JJCQ;SBIS1OVu`Y?;E;bb5`Pa*>8^t z4+*Z=x<{^2)21Uf@>$d11b`A}IzADP3+x-zU)y-+X0C}u^N!pR^fG!LZlCMV?9?+C zvfMa3Z_{Wm=;!!;V{!%qNcc!g!MySiLZif`?!WHmeg}Ns;Ut1Mr^Au?BwEB;$cY0$ zC)nfyW8wkOBUZ&PVqTxFvTol%*OUB+ef_5#k0q{!Pgd6a%QKt)e;_QxZ=hQ_{sxWc zI8v1;%zZWp;{>FL`9mM%L08Dd@DL)g;8qifR4q%VLDf$P8!ZMpJHDi|xRDNR~%mJKD@E$E#ym zn#1BXoBgI{>U&)ZTMM#V!DQYVwv`JS8rhN>F3m|@H0%RQtU7WGIg~XWn9o%}4An5X zGMW%z_}KD_Y>MB#sXRGm9zgH@SZ9J;R*ON&>!pg}w^?(!!k&gM_$Rl4@X2G$uuA#j z< z(u`Qor&k$!&__?}$-VuAePpk@QV9^mn88Tl{t?(wEKvfSTbLv7g`w!(k$AE>1)~mq z#dHA|imvaX+_AnL9nzE$H7?M)+{j_GyhX%59UXjpotZDxtl?V={?g%Qw1yU!N(IJT z!9^l5eY#g1HOSQXcx)nSDt|PskG)=e?*6Wr-xvV|C)z^!_{HiCqCk} zc3UpT+@y@M)BS~u%V9ik9+0Dfqus|yQBzYGvG0rEO$$XKv@up_f5LXX?Bze`bjZA` zy1LnD?3}0dyD#)E-!C_L4Nhm#_0VhW?e9tcxNY8|gNAaPU>yf&aL8fdqv#8P+me5! zZVDSd)0z5FN+->v)}{^1b6Y1(y}RJ8*kuBJ7cC2yKP~fy^GT^l;?`f4+rmk4Z}?$; z9w6rrOja~@jc^Q9Gody9i9D)%fH7H6E|aPpb-i(H`gv0K96I%BiSMtaBExp{_+V*m zZJaq=mx1gS`Qq}jbov1tnr!};Aj2UDA!JBA2p9Hwy#5(c?Re`(f9objvnyl{qxUym z&u?Nw>%xqLw?99a0vhYM?r#j=+&9gqcC$%{iDCKY@!VKU%#fq_uz(3jZ=)A#llJ=D zh;8TA%Z=xKzar8%;_N#KbxGKf&Fw?Hi5u4|06UcO?$tM)67{ z;dAe3Eg|&mH}xeXUh_249PAfRIP=Zn^B}SE_Y1r-b%&qcT3_@IuvD;W$S6P~kCjKaBu+-B0R~Tk9j{J9UpL<^y zjJt{`gt;FQei3IHhGX6g{s9XrHfrTBV$Dw}>n3L4P)rR+8&(Z7RhLZR-;M^Bk@T61!FG5Mg_X%0=J=5I2{T2dKZk3zR!h9a{SlM(b7AR5M4`| zUpT8P$k+-!5Q6506yRWsl*6({(b7h2XKih<8a9*g^Ke3r%iY7UDHukrILOWW6Q(Hz ziUNE#Dm(O$n4Nfds*E#IWB516wh8gq#%=z@AAzJ%QzZxdOG&WWxTJDqKHoXPazq02 z8>{Q;-z@LqrAYiC0D}p+OUPitw&?cRw=OyMI6lv_fs6**rN4Q6p67mkcXfGQ(1$!P zNo~5Q#K;&iJ?wKw!!UZ#Oz;Ee4Oj|%ZRg9ROluqMDY$KaYpVy5NSAPn^*p}MThtYG zr^xlaIfKE(qr(ya^&H{sn8BK2i{78Jbe>XQq3df7+hgjhZlCJJ^$Gu`*2HymhQ8|g z^OW5_Hgv{7RXLI!QbN>M#5dMy`M+v;j9~h>579ke6r%mj|B0*UpAg{+Rh!8d+M#JWl`Nu?cvTn&#aHv-3wnXUKrNy zVvwMh01WvjJFp)vObb6yHjV7en(vG9qJ7#}T5huUe2MQ?;3L%W!w~HivN%^p#q4Bg&GN~iJ=oJdKl!;sS49U)5(FL zc*`8xO?L=tu=)IAlhHjv7Zmr0NKAvP+|(ay%=SWCDjV8k=ErNlKI^FR+M1}0#GNAu z{t@hKZP7F+z9J}94?Tw>irBK2`O(`t`UhOsSS%7$lkCpn1t_VeYf+7gBg0MMD#oFt zLN;yztE1BNLL_y;omGBiu4;yji1w?+ZL}Kg{w(!?RZFgoug4cORrJ+P!%cgz;TZ$b zutsNd#@$e;P?DeJt0z{Wi!%4lF$?nyHZO#5rWO&0=IfPUfiFe3n9Ga zmn%wr?DDq0)N;3q5Rm1JP_P2bsc#|-Dt@@k_Pp4}dXP|9HQ)Ni7*)7`r)T3lR7U?x zfzP&Dm*4%4{aV``n=`>Q?jp%(PWXq%iR#pEj=pXqxAtymT+sT}%>k#?Dc^u|EFC{} zKKLQK_|I>r{pk93pCt87pd;^#KhZas6TDl{U@HX^IqK423|wsFNsv3doo=E&l1uFG z4Pt)viL+{4uf;=47{X1SnhLAE6$Mw7sSJEJcP_!4z_~NMZ%=phguS9&`VzY8hK9;pbWlh-SoZII-Z*%XHuiN6`|6HA>% z<`h&)Bx4SmH!$>$WJTi+!l(zYuy#k{*Hz?y5d13-o|o9xY7M+}IhsEl>3O!*Q_)j* zw7p|Woq4!qpNtH`FTI?%fQ9busl?8T^jsuYVmK}~)>J$AHGF$^15dKC_B{GGLdtXD zd^51Hw;MlQ5Nk8{dH;^U^W#j z<*{^LWBMk3cac(o$K!O3)q})1-Vj?Mpauwcrp0JqQ1IGNwJ(#^HGm>~q;KK;$YMKn z{I#c}izAz|IEJdwuU^ku!TtI#k2V3mspMsL>--SNg|fS^gPnj(z`#=6*Iq}3hqfFd za#Sm8J0HE=!B9t6VsHKfN)-GjnqFw);!=_v{Kbrc^^l!~yoIzN{1=K!hKo5_IqGS% z{FKPBWwRSN8hnARF{}y+nb97|@ZqJycUE7n!YeZQw;f8^q@5)FRM}!dUQVNlFF`Ra ztA#d}9h62pQUTUCZ;?K+QK=(lD#RvdncIDs#*y!?z5k6vl9pU!sC^OEkM(M zGLiu>hH@%m*g2Ri1Za8He}UFQoBr&2*n}$Vaf#(b$xdRFi&eh#u%_HAB;U^l(`&z0 zlED8A5knKa-iDz_OyDP)l?p2i3KX`7@Cp+qG8)6bjh&jT2Hw>PG(`(T@uK_PDKhiJ zV{P*p%@|586_KB6Z;wJDoTer&VD#_yZ^sCH_$|=qA4Ipatbz)%vKMR!JkKBTw5vcv zlWjJ7K3gkW(WggSrl|`Z8HJAoo9vQ+ILYI!QSZ|?R8O7x3p4d+1zb&n{=$H#8n zfI1iOF~EyP6lyEP;Wc!>Jr=$o4I%K>GVnGS&2O7J@RGXs{Hfbk#X?zljoUGpWX*s*sQOK{kwY;6d=$1E&a%Zzm<+YZg;Pd zo(n>;S4DMc9iLa`T&y%*m*OLC?Vog8`tlgrNnW17l_ z5yB~R_nN6p?X9gj%@6a5FnNwckVme-s^!&ckIoF|DE3lcW&6+g>g1X8aBpmNLR?AuA~eubML zNZPAb#BP|SHztTpj0yTAdC@c@tB+dGlOq7arv;;3Da7Ygy9E&B5Z-@EWJ9~|OSa|BT*ioR{}!QuT-`@9W$Uf`M_ zkMqvwUubn9yC3hToPjO`!KVm6a-76b8SQMX9oBmbP=I_MQGrICHH^Sbgw>r=@&23N zyouQGsSZedsN%m_5X}xke2|^+q?srM9SDg+PC)u)4Jgn8R)eNN&0^%QA%*1kD7Q_) zMU9o=5?J~>H827X80=}GLK7^D5iaWnB(}9Va|jQm>d3i{+Ks2ba7(8bplTxhb;XuY zr=Wj9JM7fDG~Pb$C7Yw0%dz1%r1TZg#{JP46Ol@S)07J@xg6K_3lN0sSI=oBEaKdC zi~tH@KkHCbG&W`FnZ${NH*0XtC4E=qmZP%J5j?Xz^!9mzIR>&u{;^P#pwkSF(SD$8K zf^vQvzn=4NH43SdC^5ZU_>RpWOUCz2C8_6a_`oaubDyQ0&1&WI??l4@5{II z3pG>-q2Jk3z*)7yO%+$qMO-fgskg5R84m5a=~B=1`bS?X3v-}1JIk33@eQOH>JN{0?kLpJd-gdfj{}D9Sf}kQtroHK7`4R{@K*_v3g#&O^K-?NTG7po zWXBAKlg4h%73yJxaQVpTYuy>p=U4~r+~L@#rpNxNXW!nJU>SX8c9Eu&UMbHa@iUC| zW=Vf#Cbd$Nb7N6^+6~;=ExSX#t;Nb`!C5*oIXkY}}lynmXn+>do3L)n#D|<9j)n^&@gV z0phk`k>J)30K?E31Gv?b$aq=T=J9KZsv&N4gW3!7@`afD(NOCau(<7FMz&VEa7}V4 zljyI;mchP? zrK8V1hU^D|!NkZXFAV|_X)ifO=^BvZ`N1Cx8ckz9!x^^*Gcp6LgBB$F}cU!HpZmi^&c_uh+Kn)Lvz#xh4aT(74*-EZmnjMREBP`RHQAl&1qMN34Wz}Eh z(`0k=W^z$fPP73#UfTt9D!0M(8A~1Btu5Aoqmyu#5fvwnJ--yL(aYB=ck2ax1$vzn zqt}LA>OWk73W3eg!N>~_R}=Iv&rTq8Qf?t2m4pjUJvY91GBrU0XAETdN_~bBUg$3OC!uoC<%rhL5S3gn%98=|Ud%+WrVz3b-6x*e?N$k*cM$ugs8}tGi z2@h2yegqZ<&$^MP=~GYo--z21c-{o8leGjVVE{GpVI{PC979)`wkEf#zVg6IbF4rD zvCyXXp_7;zoge^JOgKLU<#;Wg=#bx|@Wjh>WTqo@BRA=L^D9UYkWSeW#*jX;V(P6E z1oejB`#av~hT`et@@Rvp5_tvaul@1zmJg6pLEmj(%l~Ajn<#C%&l@SuuExsY%xIjH z9xPus3i-&3fXI}3yTZTh+{thM!!~;LMnYCMqe+6wNH%s9r+-G3CRvwEg$I$b#(@D= zqsb&Kv&vA;)m$0dOq#NMMHS0>LmULul>dk;{)0KL1X@Mbn!@xFqX_%`IKK+&dw+J6 ztbbC4LJwkaSN-oJyG|#0;i`7V2eL8^VYN>o1So(Jq(3en`Sx(KL>E%3Co^eJn|rKx z3DtOXCNfu1=w@qJG?puQtp`QoZ^HxS zkp4J{qtxycicjqD_9cN-CtdssPwkDE#QZ<4y=4tqLIM9$?n_Dr82_0 z{<*FinrR z@Y}RO<2|m^@98je0$M2*_oR1ZjAshB0TlzL9bJ>Dq#0N}Eeu#gd}(^<-ugdt9HdHR zFHM1k`-vCINs3uBa}jIiL?2b0GeAK0j=n?&eI@*~8uG6JSTr|Uc47lEKdv)`?D_9- z=-9Bwo+rEOqO!oWO9i*RCR5%f9iNpBbNj^jnc%jV$@68CNJY|=E5YmOM^k5F1M`Xp z?yTLpmlHpwb?AbD8;h-CZ6jskhj^@|#+2A4zc0UvU2~%x#$Nc;vcz7AxQn;-Wk_*j zwtoBxuKuMbGeeF$Fp5ieQ8J_{qX+8;|Db*`(;v~)PTlWd}JXQ{G{Ngu{b8EYjs6ALB>(O7*x+J3v zVrX|!-{hS~Sw^tWgr=LS>#Q}!CSF7J;aAbVxqY%d65L$(u4z0&ua{WX-inGWv3(AvDKyavvf5;Uq&!GlePj+G(5I}_vmaI?gt15GyO>{ z>HV;vf;?U$rlk^&Zj#a_sWImE3UvfMi&cT@BZ3kSn37C>^Im60bBSy>aY1K=c6^FK zLMu?8e}}S2p$L<m=*m*W2Hl>LK|Z_kN6_jGU#)Tis^{Z} zUO)ypJa;J{%b)uQ^bpY*nrbS)#JW^??-XcM4DU*@-$V$$?CPJ@74(RvnRRbuO99cd zXVWpnK+-uGZj^y9G-|k!9$SKHEXJO)NY^mCVMe2ty425zMMd zOVP$ZzTQh|5a)?TxRjz7;rUKyU||=*h9;|~vLp;&uFCw9jbmo182Y$x{l!O@#@2@p z!K(++S24N{Zbj8MeJpARU*3)}qBC8h#G)>h8B2poSPXN*Sf7^<(?ZK7X?~Fv1}av? zZ1Shw0lA`#Yq$g3d4^(08V3DX>L}vWN32ZUS4p9#zKr@iWq!H#k$BWMShlkT)HodsIeXDZ z;S+oCiY_Wux$(~3cz>S5k?ax=>_~`7?=}M80`JjCU_s4)f_^;wNQPObI$iR5m@s@5 z*t!zxM`D>u6&hP;iwxG{Iyf;Cy`8mq`kjAJq1X@mAqCj&P<93OpZL%ctb! zRgJA#Kyyz!3gvfP=-(L}6tgMlpwW^XDrHeig6y?hu2!xVH}*DDF-?0S?66f9;xGHf(JWI8qOixs{j?wn+2vObjFe=XyE{-PR_YAQ~VIH{ux zo>^K@rBfA^%mgSe#RvAban1veHM_ zu!h+IQ!4nXTe6HOb765&nK~D@vrP%XZ_=rRLUj8%3UVoYcw4Qpt2IH^Y8vS`;%Pbt zHR7h`^xX#RCvYLO1ajCDAFB4R4La4QO$a{u`p?=dh^wEe>uIr0^QLZo(XohCyUtL& zy&zZ9ZSZbP{?4x>d#D<~P@3a_4c)*ezwN3&Gx;Hd1W=(?qhj3o+pVyB+yBP|bf&it z{D^4K89)l2sw=42Jx^HprI-^oJ4HC%H~aGec%V3PXVv`w0;oV&zZjsgG{b1um=JPx z;g`)+g-?ilCb%woOUjgl;&?73Foll~!f3rhI;l~ll2W<&z?8KP$yJ2Q@E^J$uSw|w z?B3p(66Cy~y>=u-N))U9ISfOi6|)*($|!wQx#+P8up*S1y{1F&zk}9L-r) zV4cQ%aF++8YQtYwd68Lp+&pkgT8zM^gOCa&qtx}&_2lZ+%l@FTs~oy6kyEY9<8|KH zZjocfIaoZz8`rMKkweB^?7e=YhS=MCJw#s6m5o{yr(SJZJ(1BO&-B8cHW|-!)kA0c zc>i2k>n7+M&7MHFgUd7*grVbKQPocFnFVX@Ot0C)xLqt zz5N$&^k2B%*AwD}>yo|PD@E7)2X71v_6-b4Ep2pYXn?rE4unR_uVrwsUt&6d=#V;}n%o_t0b`fS!An2cKv9p>-|FgVlqY*-+2Oya?gLoE`! ziDX+lg%6@vsE*$t8G3|)w+>6X*g4YG-QLlKSX(DPghOpzhugZ25L<;f9GHoc84hD_mPf6M>`H3BSMQF=}9L7vV(=*OGt1{7_W&gy*gE^v=*5_ zROI<8ZvskGO?5OVBH9xbHl3<4%6f(2667kvz|xmgq*XeM-(neSC@v_=+X&XU!ns2s zT-WCH)31s#9*Wy_l@ne=QpGM@iITh-A!)SKL{z2Ltb9SjXG8B-UYdRc?$F=T06rbb zZ>*t8S6VWf-Qt8WBgTXb_1$Q{H14lT1!(3m!1{Cye+)8|u#$l$@h67pITh#<(pZPm zDaCb!qT>9%X-`tfQ@Rj1p~x#qORE{k;aqhdmXI$VRx4E+g$XDVLV|cUmz$DCjkaF+n41N^Oa$Dh!4a zdzL1b18o*A`pBJ|^01vQM(fWFIFqYh>2X9oC!x zD8Wz~^N^GPs1kN?=;0=;51}@%&BG0mlL5%Hr_wpo>GpBRO$oWO!sWH;#;strN$_M#jdg$I-Fz zyEKlEkB(17acq1di4zlJNt_&;kT~w+8dHH6d}DIC*;!4Ky)2IW;^n zIWRVHV|3!`@c5;{v7Uj^^ZgQg`o}H~j9nQTzdkb2H##{uJ~c8iH8wdtUf#NPrnaX(dLnEWT1A{%6Ewt+2@%5(xk_7}naAxnp?3|Xw z0S26X$P1D=rLgl58xW3g79tA+!Ra!=uazB=2$)Fb7bpyRP}0q|1r96VT}ebvA%KPx z^mAsjOg=~ta+J`ML!mkv4pBur!^;}F4;>9kv{V`jeF>N0^xO`a;5$WmIY2Kp*&Y6? zrpZH>(OjMw(A%)`wI{ec#&Eg$0P8l6>;j^wkmx+T6^3TXl@JPp;v}k&WsMMVO0_`;FkkYG7((gl+OHZ&v)K+g)e3V>_fx_-%}R!P!SgJct& zB|5!)t+emI(P{=s%aCATq?}+n1X5gvVI|mY#3exq?`V?(i zONq2;Dj8q;Ah$_VyR+d|l^Hy}SPZDPDzk9;qEOfyNVj(Zrvj*Q$h@Jxne{FDIlnv1o(? z$ffDU(p7W$@r9Qz*-tno=(vRYfT-@;lZm_v(|IWd3^RI6>Xpyy1@yNb08|)QKEWpd ztsG4G?C|hVDP~YrE~FYA9hO)XQVE`tI4W@?xM_TROkxUNwwe%>RAYYxRi&}UDqAI1 zj^@g&5fGf>6rYwbor7|Q=^#p&&gcMz3`tePchl38Npzse&{M61DN*8fRIO8YYI;WE z%xv{IJu{oc*}3VwI5Rt!#JTyI+l=$`GxPJa5*P0BI5)pIx3IA|zqmNRxKt@FEG}i@ z^1{;k5ruP$OEU|LQ}YXBv-3mKbG?(ZSI1^9j7*;$nmRQwd7^*v)WFo)!Kn))GgrrE zdnf0Hrsv0I7bfQyXBMQcLd*NAfI;R0!EI z!el0tB?L^`bJjr`k8%6}ky8lR2_R87JTmv1E)Fb#5rKutd6krgillIkacZG(jtC7W zVI~>^x;ZXqS)`aTIoCoeT111KcX2{gi8h76A`tM8&V4Dq(YdM=>s0<*5#ptYkE$vY zbcCZj0|&13^|+fyOYxYtCYK@t3f!bj`JrM;ODSyWtr4bK`H~_NCX)bVA|291Tlz;= zW0tCv@LRIvvcyQCoZ`1?DR@AGKnTGbAy-0tWdNicj|eDmK@keoWhT+b06=1RqN>v7 zv=<(mRHVa2qOGinOmn_E)(o)sWJ)CSwjm2M6S*Cs3Ps!#3{EOUB3b%`gqxodo?BkQykpj>(O+i_*RI)V3mrV0r1Fz)5pAvY{b&@G;QM3X&DNUKBw1X!es#KtD z-U?h3ElTX`>(54$PYE{SR4EyOOGxcds%}$_C87k} z$`)bD^{%%F6Udf}+6I`jTX)(nOs);)&WN$rktsHcl6kR_!C_(w^xR}wBA}p8_zvZb zj11++>^xc`Ih+d#b>3}sv^2|BGZY#thj=!P74a>r0+v-mkXp?xR+SXQ>aN1W*z%$j z|5nwuUa!_gyAw8f2a%b)^AmZVPBCB(=ri<}&V`j`#B74E0^Cbbm0~M_R~BQOC8%oF zVhLN7@RR{7h;m>xJ2zh;F3cuF@q7Tq2tSS+L^1iO2Q*X-JKVK^ZgF-amp{L-l*Dq3 zQwh_}FD}p5fZ%FDd3UAE%EHph!t%=ErsC4_>e9-y8`qXr?o3==TMBX65zrfqHEG!SrE!~)2xHLY0W@Pr*z)W}Vbmt9;hx=wu49=b# zoxd`%*gvy0I=?ctxH`AIy0EgkNL=PKz?Xur|6=5^!6zWG{AYpRvFX`T41NQg2Dk{8 z<%5)d9v0ERv?5<0iA!jnnZtE3H8?VYw z-{3_r<)Fy7yyY$U4gSaf_)`v0;>02LDF7k@h!q5+s7rAWDK9lRb|S!{6e0;YN`aDK zr4&N}(~{~^nxG^_w5CmjDNP}guD6tIkk?Yl5P}Q>As!Q$lhDdZ(*T`P??DQPQlwLc zr<9p4P#0`vQCFT@c3mP}sUB8H@Zt}d_fOVihkc_m@2@9HsUIe!;*$w-VHrSDD{zF4 z*L9~&b}z1YO6spZ`*2=_?ttlpr2*>j+}%przQ<_QoSC_&~1!#u4{%AO6& zJ`>O5Q8Jd-_u(LpYywVh%2Up4fn zlWw}avutx*0t3U&xYBMoo3v6wr>?F`(0RK2nW=QTO|g%no{d4j9C)QTOHq|eZAQ$d z`BDz^Xw|xxSDKxA^PGHb$uyjGDfBZ%bAsR!pxQssuTim>rLsjXiD8#n*lU*Hwd$MK zQvBto*iw3EXjo!0-R4kOipW4}rDcsHqXNy+A|r-}S>>oPi_sh>nWU4cx)Pj8F-yX! zX@;(}urR`0Ta%rb7@bgPBS>dl=!x-iNVt)P#>4EPq~J15S=Ff+Z46FWGE@EG&=$5=a^1hPOjJIyrq~P!Ff8Mx!R$e&FDeoOzKU?b7y6+uIiLo zX}(M+&PosuthXM@GsNfNUYKObz`b>Vo({%htd~W9F-Hb+A!cx5EV(g(XmGf>?8Yz0 zcXFNCItH=p#fp=6Spb-s%Uh}u!7VN=ySM>twY0n*%35B$d21z&t2b|L zMSNoQ=55DYPpnpnUVjy_J5#iF>xnIjPp;j%ohU|LzIkhL?bhtd+Qj1O;QY$9>7}0W zg%iW`oqe;-*QOgTPZ680Ot;^dJu)zNW_0n&G?2 z6?$Q6W`1OBf&pz?d*_FK|M%bh?sxz5fBvR_@DINIMK5~MSAEr2-J4q#xN3YRtT*`1 zfB2oOH((jYpZv+6)HgJ8h!PMKOemZCWCLTsbUi(1&nNK=bWhJY;)M(6FI*%h;4aMT zaZsh~&MTkAlZBee;>={#rOe{#l1tf$2Wq=^g_s_4l1|%|FRDzI7nWfefiUT8T`xgq zpaj9(2r=GL7nTk(6&28o?h(tR26ht2Gr;sy3V%d6fjkfzKtK{C4V%uYrlvdy>)J)D z#o;7M+bJbvh3TRdNbTgenE#;84q6$QLALwBk6|`#BAT3#=s}m+!(on*` zVQMd|R`vZ1omUgZ6M2g7fUCOja$;gqqMuyL(o<78a4d__O0#dQlML$^tEG8UZ?>#4 zA{<5oujyo*5(?i+({pnPnhQSdl-8*_T^A=QGj|qsrCg<%yTF&FkD29m)d^e&ORFG###)RI8FPXT z^bEtk{y}1I-vEahhB(j*htm}00LGzEGuOf4EvQ&~;IgC6yFf!6NGTb{dd}Ek6L<$Y3e|Tg-1QJO(jU+n( zS7BS6OjnIhjD#2grGP{n1__f^Zla1=Dw)R839OLnWY-uW;HL!O2(lX=8x9j*Va`iu z-(&)=w1aGYy0kmb5KyJ+>rI4}RGB2xe?hHJGu<1Hr`Y^VoTp8#U1J$cQ{X1ptpwjD z1*r*GQwN>Ug60sI2=kMp6XPQjidFz|gp$DX?s$K4i` z+rT`XA-)9DF>SYE(WbrDAsnDvU0&6=^`I$>lC}zqJu`Z;{m*d9rzxLtWVgC@Ge6$E zxfPRQ5xBdxc9Uoj?Aaw^L=%C*FiTa|!<)CB$V7#Z5r17=De@kFd9|LebSPa{XAJ_G zG5p;#IKRU^dFtj9Iq}vLPeswh%J@${b!)4lYcXvr23B|26dP?WvRkF2=UBQNCbiG^Ts()&`Ag@{ zUq07!<@|-K7cO1De68jz2cATA>nw_4U zotc=O8K0e5dX}Ib5RgrZ0|TyoN=;u znh%D+ZICPrljf!bzaz}Opp(-1coq+iw51R-5ZW2r5EqbL8CWZujPnz7La%5nt*DFz zMAho*io|5q>!Zi(L%_X&NqBf2< zHQc&+QzO}1P-%dcY=}zNk^+&~6UQF3aEldIv;0+7lgh=W$nFkfx?s#(t7{eF)+}y} zah%77cN3;7LseNM!GSOcu9WfJpVfqppyxiTmh@Rx@M+0r}6*(wxy zkLdyNc>sQgvUg6c*X(I7s`f0BURbk9S}Xp|`F8m4!m~qX;d~WN_DZV=uUnMWcJFcw zFMDDOKQLbHmp`qmBUqfXeDjIwbLJlB?{VH2N8X({a`fbpqo1Y(DmMaTm&pvV6GgG0dQk-dUkAbs()yhHTECB|NdY7)n9$bkNw!| zU;p}7yy6uvc)<%;v45|*4%Bb(_y7Li=Y0xqfBW0t|Ni%X^8WjIb0y1|@w5ntTU?x3 zT%2537@eQ%pPRWpJ9%Yh;^NGB&-57a;`G>+>51zzlLNEUBXhG8Y<=iZ1(H!T8XFl|RIzaSGaO2Hjr^P1Ak=q)d;ETtF}NIJK)M9Xpt=KSImr*FWk49-sv&P@;D zRbag~-Uv`U$}vR=A*yAeEksI*m_#nk-yVf+~$68zi49Nq+k2PnQMBT4`BH zl0l$U1w|;N{WLyBqrNj~rKh8yN~9s_c@m{tD1Ta-@F56myTaB|$INy!2qU>(bgg{m z>8C^d%x9jy{rL1}X!@zAp61rbjSHUy#qZp&YLk8U3W%#dJjj~>3L`zi2yTAuw&-%i zv6Y&)s)yC}Wcy!mf(1N=+7SM_)55-Ep4N6f2fFrb)a|HlwiJ$!+K^A5)204Gl-{z- zao?prV(0Kv&J;SYxa^6-{g%j;b#ZwKl|Xi`jh3$xzv{HE8!QJ zL`6k*>n%`e3rPk3>dhzd8!W8enpwFyzO=>$gsaobXU3Mg`sW+3&OUyA3XcJqP_|W0D*7oM6gN=)j;>>!UB|n+PjnwXdF1$+lV>jUT)uv-Z)jk6 zd}wrHV0aXF!L{qXS2?try$!=7taF~8mFd^XsaaOtU%kZe?Y5Wd&!z)Z)^_!s7Vs!syh( z$i)1}$o%Nw{8-=o_>KATYx9%W7pD6_zsn1gE6a0KzIl_wRaS4^lIgQBy(=v`_$(c> zc}d}~1w;&6dt!5QGWivh$gV&Ra#>pC$k3aMAywLrvI(b&N~s8}NE$376PJ}%oa%us zs9jza&D2_4StHIbug)#4%r5%4Om-%T%QN^5M3OU6=v1r!_49DPM>X2#WCrZDx z!P=`B2iL*!GWTpY&m@ehZL@>A#Cax7qZh0s zUc+g?F(yR(40vWj4XyCm&y|PIe)e-H30OD*(Lx8c6d_$+;q#ySoW_zCl@Z}G(URC_ zC4jZjZy|x|3cb06G-z{4-JnxSxK8?%f_J&<5WFx|BxpAz)qEK@Tlu7KAc2~!kt*3GUfP^CHQ)>vJ|BH^gFx!QciO4Yqg_1^kYYrT5)&6VC!<-SWw z`|Db_6akZos%w!kjZpoXHKq~I(Ng;FugJ2|<#-vhbHvna?WNk5rBX2k^@`{dTn~&@ zXrEUqGNIzuLTq|st@~an(~7pX(F)oGCIgX51Dgt)-&HIZOqqr%r5i2MF6Gv$UR0^d z-N^TV(VN}#3;JHQ0Dgm&n@?~wVri?w?22qv7+z@YovXV%!!mz4d#OxPQ+ciDc{cH#Qt-Zf@b2 z|Bg2C8yxNIKHhcc1QEZ%;bW(dpFV%?;?*lR2Kt7^21h3bN5=XFhi`;K5|}+_t3on+ zE>qES>;%WFaO%w2|M{_xzweiS`E751`#*Z!>t6PO2R{0- zkF&Xho%`Z90F$q-POL8XFU?<^pE@}^)-u_*bM(qXLp`4yJa^yV*@p*v_6%Qc8}B_a zHGFYqqJMsNVrg-X33u?IK*bOPVc0=|q+mvwdQP1QW$^qaegoh}fV6^VL5>=kUIvT? z1i!epI=8wqv$`_5x;(M6Jifd%wzN1hKi@wycVm3^>hSdCzNyPsrmpl%-#9aUdzV{+cT-t&53eWLxq~MSfWNSEa~`O>EH4}pq_2*GfcoLUpIaib3;M;6goEGUCe`r|Omj$x=vkXxTGcqSxXQ^P8YdT4rxup!N$?v;6S~P%uZ3BAnc&Y{ zi##jE8q5^4CSh@rSDMU@&rMukn(bR%=v!OtyP3wd#om?q8%wjjGvk*hMz3?|0f!l| zPhpX@Ai?dUcTk(tr3E+jsHMa;A)f(yfmPu%`3`m#O#FGktUzXvK7Ipw$YKe61=BMN z14C>+nwXfHo5Q7rE9BNwPd`l+pz0UD_{F~t5&R1fmg-<GDxmyk$83AC3eMQLdeNtod}!}Vp7GCxDmP?ktDYPi4t>o0xjOaJRj|7!~ZYQFR( zZUnlyo~J(j8U30kegplGr{5YK`r4N$%F1^tGdMTlRII*Y8_#VxlLQC64s@NzXjO<4=X^Y5{RoJ@a0#ei1m(LmqJl&TZT!~<|3xg zW~=zpnrMZV+O(&$oGmQ%syw}gjhb3dKx@|0sMOyAD}o6v@m|Gc#f5K)1sKfhahE!d z^{GDwvl1VfDn(wybDs9Eil~7G%gF5N+O7H3o72l{V~eW;b1PS5$-&~`!TE!|v-MYJ z_FS6Ub#aQc?&@^&jhU`N{08&tHyE0j9vB|s9cR3@jr9fxTUs0H57g~z*tf5NG!XT; z5$ft1>KmGxnp<1j@GcxVbols@W2cWDKYQ%NIpXn?=T4kDfBM`-TW`QV1>*21XDyE6 zGJxQ?16CS@W%Kf$1(qDZzkKC-eZzs@`mNvoS3mo+-~avJ|Eh2KmaqG|ue;Zl9N;(L zk~!Xi_e%WmTi)`X_rCWp{^Fw?LCMhu>Nl8KT^(LoxUw*Pd}egl*pH;25 zIvPyIgik!hj}_ktoCW~-=>>p1PJ>&EvPeL_BUoU0?Fr)2>J#wimv2oiu1(LgBmf_a zEK~>&zOvjAvj9JI^mq%q@-2E=|lWPotK&v^Ku5IzGRI z4}nz*cr&=t@N=4YNH8*&jD`7e^VcGeUB1`2I9P46Fh9%rf|JA3qgUo9uP)78U7oqR zGMB`qnJbG^m**z0Obqu74O|=^>g7O6&gH{&sOFbJS5R=ru_68zjyRC!bRB}YCc>}B z@){=P{sNo>E*2~c>iq2IJ`d`IkG=WMj!(`Fk4|0f9lms}|61?x$QXMfXyJ)Z<2U&H z7yeq1Z$Q0Y`qE$HKM1%UR1YA3LV`g1fXqE`R@|&!11eEX>v1Z#^(fPGJiR5Q zrZ7vOAExrFms(Fu%-6jaO3hHWd$IakO&X&7bZ;msV-3dPOURuowWK%;^}% z6IDv96rmvt_Y5aiDMF@7=~fkG^*o~-4<7yXdVWDa8x|1E?qUkc!f0Ihr59XgX_*0Z zb+ZENa0Esr5i|rU0sG7@uT3ni4lk_q&Mse?S~@efaAat{qkp#L#!S<7b|_4@^v;ky zIy`r7d?D;pSQwd_WkEb=@Ljre>D0-S-CfQ~ueXe}wl|uulPCHoFWsU+!C)J3TkHd+h3;_MiB}8;5`I zM)#i%p4>Km>Cv%^AG+50yO-NPbh-U6uN|!)xzaN?F|@oeySBD0Pk8|EQ-Ek(2h6rZ z1mMiNbl$(Y!pR97qL-YY$jOGBq!&QCPV{q+WDZ(>=WV?KP6GfIPJ_9X<%#9R!R7fI zi&H1($2#XmTjxgG=Egf_r%z5ypB5-#t1D(5WG=Jj4V}E|7@xNbf`S6w2 z|8lM4BYnpnAH8&bexh$#mmJ(&z9ruj+GYM--tNI6kQ4IaZw|zuhw425U+X>#Im&Ml zAAl^sm*;W{b7Zv7a(WgU2)e&Hy|6MdzcRhZ%SLapiwDTRyoO6bA_Q5ObIUg;7j6Rc zaWA+f2PMBj0y<3X%B?9mO>}i;acyo{+zu$8V^u>)(KfTRHnFfaJi9zRvpBi9isZ<` z%E;W})Z)s5EdRI#IG1M!U;MCZAfS6Lz2r9tSD|hSF$hNv@(KdpXE-`CFgkc~a`fWt z_@&v2OLLP+oE_(Uiwlz@7e@Ne_21~ZapM{kkU zUV}eD+%?>K`~zUjfaGPJe3-5N9JBCvk2t7eV0hwM-|(fY13i~|&tK}jaJf%i2W+$e zZX=A_0I$LS{@)}x4g}VJ?z2xnDR4eP@QSGwnLFH_I4Vls0Gt7z=DY$~GZ0n`Br6sK zfrHp-$rc>QY6C=r+u(^OZiVoKoN&NrL%cChvW!5M5=azfsr!JxZ2lKN0m~Ael0J&` z6XMoj?Sb@@-2`|XWMc(?WJNj^NLE`m>+qd%-Q% zCysob8GNQ|SyTM=9EG}aA^ghe_}rys_|fARCsT$Kjh_|Ha!gnWFW~8HDV*v8xuu@z z>8$>2Y1Cp?z;lc?LaSR=2~y9oY_>G2ZXLGjSpm~lyYSX(({?L$?3rxKdg42y_EF5` zksTbLjp*v7CR|;tQmOK{suVrhXg!3;mS&q)j!IUk>x(LB&TVd^%u0A!^;9WU)Lf~# zO_x5y6+JR4=x4+NGRD&GI^_`SFEQBlAax<_-_e9vYZEGB|sDc<$_2SZpx8I6TWn z^!f2AfXQfYZ|}tm7f+u$ee~$DLx+wM4<9}jVnQE1&bf)_&h=cnc=_7Z>wVXG4`X-< zV{iWugwO-S1H-({{Qqa~y@M=E>U&T9@q!?vkqE>hi9q7<5E6lgB?x&!fTV{2IrbqT zgh2R3L9p-b%09#sAecdJK)}p&Pn+s8UEX`|z4y1Ot}kE|YzyX|c za03b<;8Z!r+5k+X;fgMA9s|nIG!U`u(b3VaFbxv^z3qkVP}AOK-(h_8AU;Cai;cuK zha>9)E0LZde@pdJ)ibljPfQg)Hd*)&lh;2tS@z$jYrZhw{Ljlh7yP4Tk@>~F81@&t z$2azmaWWv#73LC{7grb&Top8Zs)H7_sXHo!!580f~tfiM}O zJ4X}?i(q>nP91y$2}Jk_n}Py^@dN)>LbwOp@+Ai2cznPC#0|I^l%vbINdHkMfN#LJ z;Izd>b5wvlKz9IvVTssHpx{6dJp`$YY!Jdn+JkR^#ewJ>C@%khKET^OoZaj%XxcnbwL9fGPl}7Q}67udo$FPeC*m#7skUYYe`}_<;#8 z%!KEJu|O7bP$`!oaT|7p@Ft{&@*i&ycMms}A%MdU+*U}GzCOA^#YL$>?S7;=@)>D4 zyaL|AcfSjtM%XS!-QfQ_`=7&KaJdQQLDg7b9AHJzQz$*qaK31>{V}zum`rjF28MWl z+V}|>GM^&F``}qJoHxJs6=x~`)cmJrur)NVyWjck>xh^)+LW}P-VDjQnXOL6DoY_-4il!>xFjLRLRsTt#0lu80>V2 zBNvt}QiGA$-tV8^o41_YIxCw_Hr5yzIvaOVVlL$2JCgYJER!jbrFcO1eSxA3Q569-4TVrMN5*)|hE zoBiPS{%UM*X)`guu{#~znT%{tM7FukM0XZ8c2~9%!FVFNvxhA-q(7$g9F_>{V19mK zdU^)#07o%SPR&eB$yEbPg@yS=-|~uo%@1CPh9VoV2%JD%e{y63ItHlM<2eoO0&hTm z4UjQ`xFWf zjD2;n=ZiD#msdtdwnF}c-Cdy5bI;#=?)l@}&!Zj>-ynf5I?(k1roka-l*2c%6Y;IA zEi5fBF8Od=iKj|f2Ph#J)&UVvEyxJe#l{3e0w$rwaEPnFL})KIzq>iQwQ_wo+_1Oa zxf^XGY)9KRBdwuO^WE4;X(E_ zh&M~F8~Pjq1|0@?5#)((?}y?C>pPe#z@w9rg=3(61AcDpA4hj@ti=viaUK$rBTLq{ z_XF`gKD2FmUaTRM%`5&DS%+~mxGy}Al(s0bB-$4@IE#UnGceKh%|+kp-2B4)0vEbu zW?^C4g!%cYx%sJ?ISxmio|>7RnOj^7gyHE$H#muda~Savfr5yzDR>>=k*>qHBweRL zj1 zbnT729Jp%u2Eh7nKPUVqHBSJ1^Cv=n#PC3DP_x|NPmLIEQ-b{y#sT~Wf#k3Xfb76+ z%?iXvsE-E*I0x#aKPlvw?I{m7K2FqdB73> zi=Bd79aseXDKh|;lysCFEOASoHk=Cq|Ki9J#sH-<^Q0A0QRN%R%Z0lkmF9IkLY3%a zVY_i5QTPvhMmV9A4$$@;-$s!FUX3bj(0%v7P=P{3-@xG;e3xePed#pNuSO@i%ySJk zVt(4IO}7!7pA-{FNxN%OYzCXn7MnFgTK&yC-Bg`7ZA|Im5|!@A7eP z;l#ZS*IP*-nG4*J&KH;UuDQislfgvn&$PSWo1dm8cla*Dg?3>hONt4sW+pf(rZ?QX zHk(A;jD>3HFG(jEHmWxH)`0`_-c0ToC}y*+Z^Ea;NJ- zdw_8bU@pQocpR^TJ9`^Dd(rJgD4qz!c2_rdd>cDU8{3QP+e_=)#Md@=g0bC5Jh8!1 zdE2{)CIO7m=teLYUR(2nAvpwL35^1u2`kG!!s^PZpF5OG_*N>wo<}|I7Q{_e;O@OF#XZ*ZkOz z{n!tV%7K?}@EgDJ8z1`cN51@($LMo`i`zS~y**A+SWd);V&S~N)Z@ zUhd5cP2~kAKR4UZ+-&E3d4osI0E7Zx|XG(E~5kE`T!vaITk7c#e&{@C`(Q$^i%m2eCwa zX=9}}=C6&dmc~|#;;RMQYen1sqPV|k(_a``$zNW+JhgD4ck+pv;jffWJXJb*^;-X9 zrBekL<{G{>-&7fx7~JyD?rh)?Ve9B1!4V1S?GQ){H)C#Lv8AQ0x~8V8x`yL6X6F}F z>wXuld!q;eTZ6iRwFMSZF^`}V!qNhK{0sy|qvj~IeIv4aypBCW;^yYwEyBj$&1m8# ziQEdtj{>p1bxak+eWE~YA>lk_3K@*_Uv(I8dl-#V>^@Hgw{O66pb&~$mvC$f48)Jt zwhnw7yMg!tjJwr1r zFe%Rfdqv*>u#z6oxngd+%m%j zFWg65c`9-|HG`=hS8`?z-ukCyv(L(he5VM}K1&J2&;Ij%=Qou(sXhwgEWR_a#r`Cc z70B2OS?@l$iRZ&&F1z)6`Bd6?-TPOglWf|RjIcyx1X(vU*oggUR+aC^Rra+9DzHSS z;%k1IaF5`&_rPn=@JJ z%#A1=sqQ&5I0)3>P%j!anDj+(HLx`G>J@pvIO2#VB_whMh2(OYVS3ocT%E9sjR55R zdVD7u+X-*&gz!MPx$P%x$dx!Lk=V|9YzHf7U_L_T&8;|k>XGOM3hOAX2Z9>Zr6Ee= z8X|~2k$^|>U9cI0SAYCAfBVV5H{`_pmSLVB)SslCJ8~KNsw$D$sd}XHnnWdq& z@DkSV>qiIsw{N3tfF$@B73CW@*W(Ee2Sk2N;6tYWInQD(7#bQLt*NVTXl$C8nue1g z2;KM-Alq(&Afj*}t*9KpHvl~)4)!+_abGOd6${kugc}l(n!RY{ezanLy?lSYY&TL8 z3l&EES5|#b&&>VXz~~n`hQ8E3d7-xd%Z(FPnwC4-)`o`G7pLQ))kJ*#U~dP%h=4ms z-(Zh<#gsq`q6Zh9t!+!b6**Ue+39FO$nFE*fJ#ENKrle=g7}OmQ^1G|@NtR=-ypCB z-|P?|4}ZX7d|-Zb_c*+J4DjccKX&Nf+=m+gPXIFn`ier*pb9B!q;O*!;d`87_e`;2 zI1)P;CK$ef7P~D4u5RrwukVm;l@Lp;aUf+pfxm?vwoVRKz{`Xx8_*V(Xue|87W-b) z3N~3FJ|FUmKe8HJUk$AL{Nbgw;NnU^gP(&-Y?xp6OYj92R)Ri1Dgl9DWD^r1hMRrg zAvu&8&Z+|1hfp-+A6Ii%*a6c=G>$iQykX_y)oNKvoZG2bGIV9yvR}N-(#a`Y2#s1ozy2R{0f{ zZ}2RjXQgoY5q)dWG#x|C|5tDu#meRAKlNclDDA`#7lvj*n?3v-M`$`v*Q z<3hL6UGQb#8Jd|O<1R=cMIxC78|_ab2B_K;9`pvupn2$O6D+Vz%jV=veLORdd675$ zMHP1-nCW4+=HA5bd)yA+y{UTc_c>%rWTV-_ivxb5C7uI;rsK^_1WHN<+_Sjv3=#V{ktASDiHps< z390xui8Q^1q{XwBX|U=Ut_Z}zw)ZN4g6}jaxK63C6m?3)1nJul1NEl_NP18_vOofU z2BNSCHsge_8;FxAehar;yiY`Q24VntMBJc9ClGf7>B2GCh>?xV_&Kz^g3O3i$<{Di zL~6Jdr$9gL`e?g>QgU3$arOV+=n# zH;;&);~O~h!W@)o>=an~j5z@C95NW#1t5}B0r$5O+y0%+>2+Vl=IZtBKye~eln58> zh4S`7R};ZYJN~CPSN=V`_%ExoUzwl$!btyL4~_myPu~~%#xISmbWa2)<~CMVw>Kht zJMqIqlno9zMnO&NMJ-<#8k?}KaC||P^z=?bg1VI7F< zQk|EQ&RtGYh@d~Pi3-7?KgK}`@C|Ojg`n6i3B-@oNMYX>-3e|b{IR{Y7`%%_D7L%F zYP@%V7J<-suJoVd5@;NK>vXaak4lG#a|1>S9w2-JpFipgL>I9USPd_%5JH4`Us?#x z`GWH+p(QmX2!!!VnqasoN2y97?I2_5N;;4Ml{YE@FL$wtK#>G$9+^J23UUYmCop~& zCIYMjq~ZWi&@H|Sz|O)(kh3S`z)J2apFv#{$nl6KVCV3EWAA_~1B?>{iSsV`6U_mb zJV^7w)4**>K@&g>2GkWHTmS;>22=oG0wAFW>0_J#a2LM<{81P2Q6RhxJp+-;x%+5`}vp zYz!x^v1Gb)iv)R{lUW}z77COmjgd0R0QW)uOg3Ie<*9=-3bg~+2Tm|?X{M%_h+I$q z({7YAG-)GU##qDfVc2yhh}MAu+gw)*Eo~%M&Xja3ugq0=dIlFrI^VL=PI>z zbK1C>x&YBYF2DTz9)>d@)B6uX%?O_BYO(OSp8B3-&WSf!i!#IAfzTWv?rccyWE}TG zzH2dNW+m;d^F^|u&NLi)RuC#`!)H>;y?3xw)pRirlyC<0`l8E|0k^&A`*i4?4e%Ni zoCWqe0P`d%r;&bULe8vG(adbg6aj|Wao^pgr$WoDSU58=1*N9cO3_>rV4jGB9I303 zy`J-$0{YT0;NAVqS*uK-=cEXJObZ~y^MS-rL_kINaJl2=47Ja?IgY zq&K?O5?H8NnXXuxD4H3rTAFNHo$CrNk41w^@vZRQ-uBVaJ}}?K(K~yG!S&b%EUDeS zIP6fh6WPKq;^tO3vJUqEmO&T~7h7>KtmrcBBcTPf%64EOtzZH81_*EWI-!>N>kIZ~2F!>M5qo1D|`1`Tm&rghB zo?Gc%3{I_W`Xf7ATlK}ar zfxQGHpfu7*W0DP1yMBiXz*B^s#a1hx!3U6asa1`C)ctp-nxUsQ&6pSBYP#}DR z4NetF;1~o`4$%joSg%x6U^3nYj=3989KvA;Z0-iO4p2G3%YoWK2m=9k2b&4Xho5k; zwzapizP-90U)_kWiF(ftc0+MCbSSPA>HiVr7Q3E+AQ9_3@8xw6?a*?Jl=>vxnD+%I z=T|1?eB(3AV{RCoS$4wo^62#P*z~fwOHQ;7&^JI!1Ja0c=o1Pwy$20ICkx*Ij3ev| z=a!-LND*d$faq@nW{H5uf$GTOO~6V3c7X}NefS1Ie(L^Ni3NO=)NZ@wkG!>Vx_%lk(}zs zXQ+b%Y?A`Y6hY@HVoK<-EZ{dqSeYHLILJ%kl3*@{V1hC<=v@PUl8>igoGj4hyihbV zzl#%dgSeDBoH1K^RWsk4CB=5dJ&7nT%kq|cm3~qsjg|UcUfqdt(u*?k+*#|+^opeE zy)$DK{|azc)J#{qbLr&B8K+Q=Y!+glD{}fAKDo}GyD7Ya9F;t&E8IuU!WKAV9$JS2 z1O659$u~E@G&(kM{d(zVKl|U_``-8d;xGQyf3c z&A`si27H5qL!95?y`QTH@pt!^{b7H29o2Q@*T|ruquBJ}60j+lIYxxtT$u*YbpkG+ z6WEf3Zy*3u5IX+!ly88|z{XB&bt^g*S!s+c=5N6|2oxmzR}=nAdutaGD^Kn&e?7kV z&zp0PN2k9MntW_!^s)J&$EQcGOwDvI_$JoEKg;PF=m6yU3pl;N}>~T~8 zkP886@Q#xGVh0E1U>~%?O@Z4A@ZpotWK1&z;K%j@F}x!lMmX9aeyDB|1>nOsz`Y?D zKd>cs2jQ(1X$K$7DAC4Z`cOKxkum zEi|``8A51&B{;WC2$(Rt95BKBoL*R6Tn);xChIZy21egN`%RP$coT19l(G1?fxDy= z#BNRx-vs2McmR_1atREtK(!7We|ieNg`WW6btL`{=5^33z#LEvI#$#yDl2Kh1<@dJ zMe&A9KwL1m0B}(`kb@QMg95q*o@;*LDhLxpfV=_YrhMgb!H01IQ%n2Sl@}|+#O2i_ zvyorHuMu?O9>En*qJ@$U1DTLcu!6QE%ux$OI#bcQTon|g5aEX87MYie7c}!hYH5yz zBc45+;1z!Hpi{C3ad;FvEmbcBKL$$rtf?epozbE*rI>kQuDMF^=DE-DEZVlV18pQZ zE@$$IbP57B!z5#R=fR5yHSQU;OmuedQ_^AS-L%C!_lT!V@{@ns`I!* zD*1JAr~^Vzho7kkR18`PkRM5a>Cme=;m=6~e|Fe{*vp8+9HE#a2*Z81sMn?kGCPT0 zc^PQMm7N)xnkmF2icC#1NS@PB%xOTwrLj*Z`%lg3q5LzcdZ)v2VD5H)*2qcK$X@vXSriL2#3>H<&m@ub~`)L`n z4)m#sC(Q)jm|4$rrJPo0@7q(WnpNz6w~4B;&$?toidfuRnbf$=FOf4s;2(%=Ss9P# zOT-7GW7A=G4YgK?EU&ChP0zJ=_B{63KYipQAAQF=e)ILOfBh?7@xQ$Er7wNptraZa z;8m}FH4KwK`lCPkzy9(sC#PrdKfwB<(suX&N81MnTb#+5*jyyrzXc`Upc6U&s1IQTKRzBTXj`}{$iv!g{L>>zqK*{jg7e{HfH~I zefpoGlaGZb{xLZACI85mS4JLR7`rk*)wHxYL&}L5vrY0b7QZ z0B#VXYoYZ(WRpSXsTkC$Vn*#W={L$WK|!BzV@!WaqOn_~^AqrGU>TvBLP#|t%arCo znz|$|v&9AuU3JoVB*o-Sf2NjWa;Crsipq{4#D37h+Nr<|50eVRy~xFa8a2-``7N~3 zufW1U8?kfGrsRwy1Y?rlUUTKlsF=5s&c~SRS(EP6N|+3(&n7s>Q;za9=^TY3K~f}` zM0zqgM)Yb%37KV{JH>Rqz48hh&y3uo3ZzaLcO5gU8CS70&1q_CXO}bgbg~h*=@N0~ zvs>~RN;8k!-acz29grF*=YgNe44Eh|Yc@^vjQd$@a^fQ?o#XUX3OMx&f-@1T_pZc~ zy1qspdM4lr_H^MVz|#Xc9rE=Y^gny6SGCfKXJAPWy2MWNo&^j)JtcbptVi234W(MR znmckwz{&wEj#v$#1PV^Y0%<=jQaEdGp9w~JaN@~e?M$V4(W0m1R5pUAyS({x$1^Hs zyCQewJg_JgiJXk@bsZamP3}t@G_3n|81rEugas#xpi2}<|s08cD!L{-#EV$94~#;HF5Tq;nRD%H7QC96)WVBoN;8mA6<^xL)B= zNU^X8oJ7tY*p_2WK<*fZ7`GCFb`8vwS2$qPNpV}`?Rl^pBL#uY4vw-At}fsnFpi<9 zCq%YFCb)@k3^+Cs%8E^gXBB0qAWeg|1Q-gSlPZ~%Bq(rTodw;BNe%kTM0{F;DJRQS z^QV+=VVx(E3#Ia)z2%MDL~q1-OR`uO_oacsw4Z_vPXUG&PCAj4M^ceyTH*TBfow_W zmmBDv=nK~XF~&3#k*R1kYkF#;qQc}rXREDy*W&J65!-JjVtSjNG?A2UxeL&$Tq%(V z3;&9Sb9F)zb$St~iJyc+Gw9(|>}kkOAyac=B7@qpK+X)r=K+Qe-h@f6o`P@|bk74N zpBC_6bmnkQj4bwy1fI%`YMngi%dn+Sr9ru~AVIB9u6N}czKr}HXnCfWo+p1=qcVPG zn}j*=>Dk~Cu+$=^(;zBH%4SwxjU^G`NE_~r8!tKs+35 z?}(^c1JF#5+T`?14$Ih%Y@t+OR10FT1)}1}LOou_c3=@WK~uyHCR-}o{q`lP)Q#!2loH zh@^fC#*~~i>ICysugP2Hr-DH`=>+CKQ-s@tUVC zra*g5Zv{Ddif8#!^rMD#AcKojQ^JM~F*y;{8z62$Jwnleo`6~@2+l=?B)VW(UnK96 z*U1}C4Hmn3aa`7?vO_!z{X7wUJPlCis)-$`%%-XI)78$+{&p|kbSfY)Gim!Nq){%R zOd2Jb`7;SNlR_~EZlr^zT(~R+*(thooYO|}SnCb0_gd@5){Wq_BzuT%a3D_7?d?5? zd+Xym(KVHH9qL-ox|tC#cBVH}0_$9Jbxvk_N_VL^m=wu&5{gg#WW1k`#8YI-89>q* z$1LTiy)nJmlV6(tUady@oXIII%?fEVaHyS=*#N1Tx;bF!sq(%v;8t*)7pt0|NpQz1 z=b;>OlI7k!cM{M1W;3OJxl>F(oT0JamfCnKs!e%|-b(F(Q(LF|f-Y8PBGS%6$lZfH zX=~}pKhH*9-h*15_9B;p%}$5k#|mWapUm23&6Z3wC#jwLYIS}bg4{WgEwh}|{V``Y z`(RrB6Mwpm&H2geJpZ2D%|7~P1VMI^oIID#dDlX-Ty?V<9C+oH?@fQf#Lb%ay&F)| za7CT&H1iD8xw}O)KuqNo+scNeKS`Hc8caOxr{|Vg_Kjjm$`)X^iL8;dy~F;@n)$va z(qvPxODj#R*1Ax;SlzEkyY z01+^UQIjJxZ;#;BkR$zO}AKzTt-dv4ut`N32eR0BuFSfC=wXuflg{{rV))uS=mwr*@3n0QsDg}H+H^W(iKtc%^ zfe0RSq?vfTlxJN$B_K-=MsXq>y=suDLP+QFRMg2S8#zNb%CW6-aw}J|nTTE`#f=cp z4CcXXSIWs9+`92P1C2q!G}&NbQtlEIdy(v&$F;+yhttBT;$Y2?hFi_g^rFsNaw-D1oSQdXABw+K5M-ngL4<8Z~Qv4rFRz>D@up+!&V4#j9U!wy^toO#`8_ z3EtN&`&@RCHq*Wi`FZY-!t=eGl`8d% z%kqjG8NAW!SR`*^e2_zC&%@|JmpDa5`mcjTP>SeFB!ySdZ1=jy#PSIp24cV4|a+2TE|yZ4W$ zZ*a~WwlsrC=v-K&U$+o!P>e!ah@~B`G?TD4nKA-?S)$ zNdaroNHh|Oa2P`{91eu>yck{!hgO{sTn#w^=l-j~pg$N41VbTO#PJOdV06)+S3GL5 zB#Aa|fT#U=a>PNYp(si$5;qaz=4W`_iRe$aC_%^iMy^27bq9tUFmCX;rVBte!NObp z>1~4dSr^HsN@i08$8rmlYQer2v6864tMlGmxz1TiVDOuq~)IMNNGx1E{h?k%x45t1>HpuAeqN zXT)qYr(ZK_;)TiQh@U}Vs!gL^-a6mw4KBwnlSatdjYcD0(#yk_yITs=TkPra9F(4= z5>rUNwC0@irz!Ie3Ov0PDMV~eY?1^ux(A&E8BRbG->+MWVvs+q8eY1~Q74-|qUvxdh&x%7DKlq*XEMCXR+AGR^j7ko z$EC?`dp$T;d-5L5kTZ>7j(6GF<%yVeCgnTz+&v{dS7mGoxiVy?+ee7FcP&L~Q%uBQ zVVmgvnQV?0qCd^b#ww=(&AY+5a>lzrH?n!1zN_A8p45tYH%c47*E^;I`fT}k9Jx;w zJA1LYYJT<-&YUxq%rNA{Id|bZ*nj1bRMO?FKkb+0M($?MH8z`fd37sb*H0qpOQ@!3 zhOD~BX^FBFvj{LWdbA?+KZr)~7r_-r8bn4q_yRyGB)4`c-yQNS@GKk#^7sScrRCM> z+4+H?kt=!EKK&P;`Mux&!#BVA&98dZtAFG{_i})~!4LoN55Mx2uYB~;H~sGK{{F{5 z`N`V4hT)O1*|`PZ%9=kIrZXKp>%vT3UcM7K$hZbZ_Kl-7$<)8ZoC zb`WSX;>p8+QV2p`7zj2*gqdIidTP=V+Tf`BS8X;-s)o@Wfj1(g| zwE|WTGF8;+VW&9a{>&5$LQjsQK6oYtV7>@1`g1oX&)(!Dh=AF(!DnC@Lf6 zq!+8z@UjbdyZ5Izp6xBR{IrPGRLl{v8iNk|LWxzSSLs!{m$@OGEcCo*X*CO`hhHaK zPbx@}{GQ@g0hu+7{gKk3%-(ETMxq8yAL;ASn%K!aJ_trBt?rnb7xb5fr z5y|?-l*FW%G81x|^(Ql(6wlJ+#It5QZ(?S#r=@r{xHQE2V*BZ`UeB{IW~{(&A$Fy` zgVJ2J@EnV6rqystO4`!RD6kqcYDD&ZIeLJ@x;1lC=3194I~RSg75@FT~ z_y&kmIf{{6Yw!(x{@FP>kg=($^&h_Q#XtSCKl_c}c>C*K_d4U{;D`Rhe|S(84m^B= zN8uZM@{^xzZ||O+TjZDt;J@-)tQgd8C?3o!4v^D+nrz8M*x69rUBe?S&BgjVJzX~l zd9@oD*{r7#*~+-}aW@pthGjH@EJl`HM)xe25p6ay?-t-)icNZ2iudP<5=n#FEON0w zWtMvBHz77sgZHkvl{F>vsWTI_b~W}8x~X+Y7M@PfTC&*|VpBY&r9Y*&+*f36vTZ35 z)7}@(HQ5{4>gK(Brg+xQN!hke>&fgT+}%^|=-B>0Q(HVw+5C3kY>GtAQfFJ*DVfhZ z_q_Qt5Y>%A~Ii)kRH6eRx(h0gdr*GM3q8Tjay7P#|tp=znR&|i9 zd&|X`*{bB2n|a6;8e)CLct|4;M)uN022d;cDvP$A=R{Jbdg{-U?`A&e$?x4Mh-dz^ zDSFr7GJ{W*Tj*?Il43SK-F?hHXtqTcdD*>8hImhBySbWmNjM1(FgFNY83p#pSI4PN zI_p4Yi^D8(hvQ@tF>_vN{u~p=F@E&;)zK7d2x%=bH9{eV>^x6t+DymH&{Mcck=pV( z$jT;@!GU8*av~M*3Ylc78a-*k=(ahDmIgapBn!1;=^PKrc4;$6HMKBxDLQ$n`=U%# zu7sb_+I4kGHNWOGWVVatJq<~3jx^S>N;9uZ_6)O5dc$Da*@bEkE@wF3qXT96_?_05)akHILuXH5YWfSLJItX8ApX&!`s|m~~eV zyNq}v?&9ECfj#-XcfC)Y9QQtTTHIY3Qef$eBr)4+ma#C}CGo``(S7xelse>i*E#ce>E~3^&MjXn zZ|ZhxJx^%Dxo^>sw6U;F^QN0bQcQk()pT#`UO4gW{VWysPAX^9mv)^eoVA(WKKucR zX9I(0?Jjo+((<2cXiVm`5>EK(7Ve!DG8wXbO4*v`K7RWAF?F!{ZIx`wT|~TEwsS{JTkySOs+at!ya;7P&}4{DqnA#18IWj^OJ>Bfm(y<9bQ3W^%$sPec;q-p z#a5cZ!wFBth9}=upehP%0_cp9VEUDG3&#wIlTmgWs1B)=S)qx}mm&-Vh91|!<|v<} zGvotHX&cPqQUZp1AQQlOP~8qo2^qnbfa7L2o+Vr6gC@o6Y&jX{q#-BBk-_F1rIWAw zoaXEvZJZL}h-Wv*8OI!LOee^+(blD+IaNgvDgvykee1Fj7&V7iplk$Z#EpdAd~}Yq zJw;q=89UwuA>+$+m+s`UV@APA7xs}%Axf5tISAUWu})Qy)S#Ie#hy{@DAE5!nN#Ko zM59hi1K6b%GOrxlL!KA(?+e)5w;q|Q5xjx&6>F4W#94C$?S3Gx3eqd5e|9F>KcXKf?&AFNt14V*BP=Np9 zl5cKdX?A{*FsEUDVQFD;8QD21_vjvY1nA-qfd?^o$4CMFgq5{`F;y5E8LMk-`uqR! zg%5o2gKvH7TYvUvfA;0Ccm*d8fUh4&l>@79@WwX^-{4~(`(#IF&(hK=-NM4liv7X| zP}u;2rSs1cVP`biY{WigHdcO`Tjr;Yn{@NjK9W81!tciKV-4N@&)#+3yS9?v#1rEu zjgBqt#U44a2kb1hv-dtkykzRB@iWk|4h5T+d7IdT}QV!#yEL6Q>A zMUA_}v(lUynDKnH)A#go#fAzGRlcn7O2Ob+5WU5WI;(R*LX%F(=MPEwsRe+#GAMIH zYG_7KJrRiz*$v81aOB8lWM#Effu^F}U6D|WkXK~8BHpELx}U;7N$eehpbw939^JTg z<5{Bo4soplk!W507~8I7?7SE;yac5{~R62e}@} zT24wL@A8Ih@0I*Fj@+OXyKyM3OL7UMv6^yp->H|kki4syU6#kx03;VwZiCDsC9PAA5YpXHW-r0;c7&7T z2ASK`7MEh{$lam=RD9P0t7}0dO}KADgV!|*Hi`uJyxPL;5;?`)Q!ql1Z0gWh&5G5J zamXa%+==sO!0*&5iR)#y>w2Qq5WNw)QQc5W*SR&JWKlMj5C|bgMEyA3epZ}E;rfhY z!Icr=a{0{HY8EbfgP*3cFW{x-99%L_E4(LM-+kPzLmEDHms~#Q2L_NnY>4!LuvLYp zszHC=8_vTa+k}K<;VJQxnYZ??U0_)ybYoHi#$6sA;>6wKq8s9%fVE=Tw~E4mFb(Dw z9KONAlI0t4m$L<7FTjvAE3n}ksA)r(MbEb?d;=aFo0#tD8@Tw)>cg_OgOI@ZUc|(ACU+zLUTHt z2TcLU9~~aaEtzks9-#5m6iMg3HW*&S(Y`z-ah=H;Po_vc9jeu#pXKmq!}_4kw#hOv zZV2mOZ=bscOu3lLaG9hVk(lF%*x+jc*AS~fawi1Er86j-49;*E?@!J!tw-dR=dSB& zSVm0)5pU1~Ym&MF>{bvY%oc-}b=t@fGdC=|z=5A|4LSRtP8tudMhvw`*ku4dIm~5|>w&SNv-{ z8|CaP7>~}`Tb!D0YT_PxMJG$3J{*jN+is~zD73n=vaql;H@_efL&SwkzD3{4l5aI7 ztgQLgf_}IbC?1OrgS>(UnvYc0uGluSn%9v?`38wRy#8SHfQw!YhRr~-7N0(hyfAx! zSt=W@^<5wvnL0eQ-VRN~anpzI`UnaGtPiLbn1JGetVL?1fTjVe2&falH^A2cYcC70 z@nVO*fjBqthcIODtpr%LSZyX}=7vVb>*^an_qqS^{ttWrm4pBIAOF+KU;gq3RpmhV z1~2{LSG@9-Z+zn$f9Kur{@BMq-rU+De1ibJ4jm}FziSgJCZZmlQbQCuw2BBIvS|x@ z6D_**Cf>}_tIh94rfHDYd+VI>ByzM6@(v?{;4G*ik^)Q9%1p(c7HvVtnjqyk zI4iSQFI2qeaSQIGEuOPt`Dt$%4EQ3rdOFq!BAx5W;1^VDhf=|5)=o|$R%HUD{}j5; z1Q|-!aIW;BW>bCIjtF@5ZrYO(VO*y`47z@fbfOVia_vX!8H=Vc3BeyhYWs*Nhv?&s~=}6T9m4=eB z$m7$pCs)(25uVdWoET zxjbbi1|!bn;wOqDe&ifpoEVF|*ytXx2VtZDUN+Of4ijCC)P8?&f1A^k*Ehn*g##k0 zRx?t7AgE2a0rcLU1Th&9y#fR3MMdF&a<`#O;5LB%5N*VzKCaS&gDaJ#Ajc?cM6? zsO}5aPVDa;95I=h>c_X9l{wFZKRQ;v0nPEqVIAH8{x$9d2gRidn0qOpL1mQUZ2{M8jQ7(i#pnA5H zpnJM~eM77RwC9;NW}e9Wfq2l#BOu*?M?veH1icl*>-4H`Wo~A6YM?t9vU4Qo*18;nVN>%FgrClJw84;G&I~l zI65{pH@~#H8i+>LV@w{)$Dj`MHdo&6)`SQXc$XdzhhbkV&&|w?jgAfu4ssmW;K=Cc z_~hjD%=qNg@Yux2#LU>_G{>clP0dWsF3c^htOSHR0fP(TR@*C$WePENX8Cg8B3z({ z;b9Lv?12|}57@1iPnb;#n9rieN(g7tx4I@w0O14RvcS(0N;)b@T#4hyfTfjXiVSks z(N;oX$%Zh>OXB4~_y%HK1(TfeS%FpGz)uMx}+k^-kj(BzXv~$^jV!uv?7eC-BVq7J~)Oa&@$n_3hd7pYnFwYN<^25^{i6oP=D#DG=U*0sAThM_FCO(?DHEUhJUV+t1y8 z)@g#2X~26~Y^hP6Ai(o*1(uHVQ^Vh^K?m zaClu-_zl<^j(D9~nn2<@^q!D>dPQCj0|enw6#3Bxn)Y0Yhr^K|5F5A+==KZZR#?qR zQWB6hg+d%G#lg=}s3Ii$Bx3an>1c@0Rh65g(h6)xjD-RQUNrX(ZonUdZ@_#IR>_TH zK8vJ^f&fw&2-s*O;59^}Q68S1o*o^Y937h+85tiL85`&w=o=U&GCb7Z*V_-)o|&DW zn_D2v&Mv5we|8EiJTWynF$ol(n3$TLo*{j9c5Y5`O6K|bMH3v;-FdoNt#?)QzqGuD z1MENurVtzF79X3kyrk3w*& z9eqRn0|Tw?9W7nGT|Is6ogKAJE$w}D@XYMu%4!h00M3&zspMnP<&OEx#3pWE^a6)V z53BdE2OjnSJ;2h$Hw)>)e!+gkvJ5L=VQJZQT!0ONnjx^)7{>+h5LB1IY&PbAR%I5B&PC|M~;0 za^Ug}Uh#%Eyy0E%de=uk_KEt2<^|;&Ku&CKiNYA10pT9F!An#dj)5cBvwFNySgH!2s%R!1=_s^R8&5@=25;Icni#5Tl;T;b ziKfd>8w^CH6Vh6mwOf?d65)lz5Kt*?HdLEr9k_QD`@r8w9#`ZtWP}N0(1G`wo|r@1 zAq95`7<3RH_`(F6!Z({Mm`(o)!rW^HUhgph*ECM49_!%`Z3Vj+^!B$QxkNQE}bKQj{4czEh-5p5AbTs-~r^PFwNBMr?O|b0^}4=+@5q z*6w<2mvj_j`PTSq%m<|mL!*f;b3p8lHNbq(h&JIoRn>|)wH0Y*8tciKg!(RCmn>OG zS#K~6)V^~1U%z*wYat?6MkLvvPPHY`W-}SI1V^|=ej_cV4@HNWmC67#;T4<8xY#pU zF)vReSwn%SZXP;~xI%BkHvmvSfBU)TxxzXCM!_`LKf1NOcVlb!aC66mgRPx|t=)sT z2A&pga%#qIloky4z{`Jdz`KGn1^z|{Uas;}SOEgoa))G2^4z!qy8yj+bg&r<84gEe zjJ7!i!eK~Z3m8^|^CDG&Fnj}PqjC=nZ{#K*(Et!LlpgTqkvQKQ6H%u?^P=Qf*pJQ= zv2%$D!1Q3;A(oWvnVpzIL_6&b;64&3kPA=Gq09*d1!I{bv_P*5tV!Khp; z++iKC38Hl%_*pei7#9!U;CO$3pS3u+>Kp6rZEI?2sB3I!XlZHf8=pqBu5uqi;t~)) zuc2Ema9+gaDrD!mH6I6O4-9p;4USJNh~B#h+|gBE6Ywr!74f`p*|(e$mKPTh-vgW% zi7YKG%iX1A)awD*voo{PQ`1u#kb}<}gf4pT^Wbj*;&bz}#L29IpVKpQQ=sF?836mZ zNYaP!jx_`E}YFi@9II8J~BLvynb|OaCl%~2xdZWPj5$4U1eEiQ*(QF zcW+;B-$4Js;J~1Up+SW25{7wjaEJ0EC zEp6Rx9bFCejaAk4b@k2l)s;mBrIl5UO-*ghjZM`R<%Ri$g~cU#SMy7%Te}9vCTG$7 z#nqy%jDzd>FtsLD^8uZcZMZ)eJj_gvb+$B=l~q*KHZ(Q2wzPG$b#%6OcDHwS)>T(k z@ZQGes`BFeqT-^`%8HiW;i-j%6$t-LVU@6O$?_#Dm@bJaDhD!555vPAc-R9k>>glc z;49|)g_z;PhTRQ+U}kP%YGzIum@|fr$xmUu!aH5^!5DXR5703XrUBMf!ZdIsj~+7z zHa*Hj<4&NW06I}Qu%-&ER`3llv*JL;vGFOq96WX5;wL}(sdvBo-M{b)Z~BR!_^C%8 zL@x)HZ}4+(c*8s2`Oc4gbkJL31tuy7>gLF>2m~gW1DF(B3FJ}8CUQNI z^;@xB7OV=HaZ+%|U58eu*c`!TkcyovDB0}d7gK+9Yh&9?6|I<*EJUNSpe3^i<}A)q z`d`~CFV)BGUGtO9QTe8$FG1X(Dxt%@(8;_y_3EvgDa~HJx3a|3`_0=wHty{xn|Kc+ z-tukd*sk`%4JR(h&J!%HYa^zmj0pXpycB>J!WmILwRud0oZLcZbrVrnXd~*6Mpi>% zAE%@cf{~R_)E`+7;%!+O2+BQRqB7!AxCWFv4O?kxoxF;^{O<4r!e_muN=@4(3RZ6zeh@XVaa~KhfBW1c74vh15&V8eQ(2Qcq zf;kY~-1SG|Ymr!BeTNX**bQ$cqOrtAJh2&1VCx!0DMfY!wa%6mFJ+nH6|~o^Y-Y}! z+|ty~Rwfwm9Fd}EGGmpD#8YLRc;;c%aZ1)V>SQpz;Xra=g*Hw42eKI(07d%LM?|iU zAaxxXt6PqjFTofYhJdSICr!{fuSJPnIaNaT8bUigVARpYZy2bMm7G@CfpF$370^KQ z%`MaIY}qD4pPO_t7`zX7N5uT>v(FR2)HiQEcXa&h-r>!iz2o)xK{R%-v3*3?+&S9X zy|KM_yt9A2yMF{rXFUe>&X+EZm_T15{TGu5u^JFofOsmv1;O!=m)0A)n7>i;$Xebg6BX@>KKzSQAX4--8g&W5}KT$R?0MMA{n^#-4 z1OdguTaac-PE^xx+~lQnh3OxKJoi!U*_6*f=v2}5P$!j{x8AGWf=OhCARR#F0$V_s z2Iz7FfeEk+Gzbp?z5zn*>Dg&u^Ww7jJyMke%3(T53DHfp^h7NI^>~MMAP(+S>wqfl zA23$vji90N9BdXk6ypJ`PgfV``kER_^GnOhK$~r??LB>iV-q0RDFx%>Q{#k*X@L3k z)C^c2Bl;Px)MtEh42k^k=s-XCcntCOC_s30d~AGTY!tQksi{daj12Vk_aV|A9Omxm z=*aNUKrd9?V1I9SXIFR6z>qvJIy~Ih-P7IE+u7C(wrvJ*cD6TRr`m*=S^)UKKz~<9 zYb}5E4ej0i14F|DLqpx2?Jey+9qp}^RkhXiJk!(F(N7#-#_gXQHLKxV-fL5BdLd1X;aL2+$;ZBuPcLsdmZ-leOB<@Hpox}vhA zyuP))tG%_YwxXgazv$YvqN1Y8`uc{7lA=pEd9i`Paw00nfZ|i7m>h2qvUtSHX>OMG{HOKj)*=p_T zY9^Rrbg)JQR##DU=dK1zYlTG>HI-FW@F%WZ zudHqB9T=OQ#r1a>4MeY2gX}5HYO}uaQfHW6*of&NTjOC5JnR8JRX$jj2=*g(D75C} zlmuL_%*}g(XdS5Y6E*u<#VkzBxY+KE4^+J6ESyC{O4{7Z5oZM=5{ke-B1r`MnpxATkFgWELpU zjNn0_S>uMFO}pCC*esX{&{3o?{med@qDsfKx@a{`nFaf;f=0HXkE%8D;3S>XWY zlcqNWN7$fTh2&40elH@((_I<8=Z&^x;b|Cr1h+>iK)HIXJoK*Bf=;QVc@R@(9+7yq z@(pW6dsu+BbfyD>w0niVb%XYy>GrfMPuVfzYo+qKJ~(!ccBJUrI5p>c4@F@Vtj_p+ z;|t5fbIU`szTsKl=)7-Yab*U*rPaU+TCMAl3;OvxFp6RglG4s`Fr)3L^hnNG?dc-Z zEy8d!Y$&a;2o^02G#mqkfzplmXmXhtwtVlGC2^TQ&a9K4Ztpn}?P1dG8MPnaxp>zRw_}bWFuMk< zQQJ9&Q|kS2T+=59!aIeCE_4V-XW#?O>-_lW#egn=<}>MV5@f4V)oyvpEU+?FOuHC* z+Q{mp2cJuwk^dQPpNps49F3Q(-ek!Vn0ELN$YhEwirY%Gy;wY?ubK zc`hz40|<3LMPN&*>rvy<+~tPJxO+Jgu7$hSFey4WizEV@`_Z`Q9>f!e8?nUJb^@6-fmbsDkj%mXFfQ+~Bj5*E z)R?QYWLtKMd`HfDYrZD=z9eWKYDG@XEO%vUX%DmF$K$bRB!X-klXBJWUKC3`Jp62u z3)TVd4n#iz@C)?g?MB0#(Scw)02>~mdav?yMrhb*8FUZJzX zSzOK2s zxwE@x5Y_y4mp)PswFnm-`n5WTvuAw+||=7;_8~V?%w|H z&X%&$imK|G`r5jtj^4g5kTT-u>bhExYf))wO-lzd`?{jS!os403czGZVR3O~TSs?K zS9^8Q^}@Vs#USB&d&O( zl7jsFD~0716_t5cuU#vtf#pzJaXmjjzq+Y?U~Fn}HGmrYE`Al2VWJ!-F;!p#!%>4v z=gW@3{I-09k^bK5!t0kVT)uK8|LWBON`C6e3zrLMSABJ9(UmL3HFeGK1@bRledclj z6&4A5d1ZNN$+f4x`Q$e*7MGS+R#X({U3})k<&tt~W%0Gk7cX8etE#E4EV**^T3J(yE5Kn!2*`#@GgtdeB)aet}rUs3yZE_dFEPqWA`vB8_PH^WQryE27E+R zgQb9osfq9nuv1t^^I>&kuDb|Nln2OQDvyA!9Jq= zNKvx}^%Agy4OVJ6Lwq9!4Jaz{4JRVfBFB{-E4oY(wyv z?QC%wN31@y3kXE`x#YwDD&AK_*#M>i6f8TS5KDM4P})hhNDY*Ob{!ey@E1M*g{_lS zNhvYeI=Lm@5si}s-x^L`X6Kj3I9Q=~;K`>ieBu+I`kmiF<=_{7>Zcw+l>>)w@bZ_x z{^x)Gw}1P$Km6g3u;E~1CMPODKpJgB*Q*%n2Ly1U?j}Oy@2Y5?#oVmAq~r`K0{7h6 zTQ}c^*G9Q8%XqbqD=IjZ}#+iVWEDh0M9>k1P%ta*_yd&>Y z;A37&X6gpfE?clN5R`QQjzDq0;NctSgh`nLw%Z;0L_wlSG~F((hGnCC#bh2R9AGAI z*@$moq`4gMPcJPFOs@1!_&P_ITZdNKN7i~Lf@AaHndQime`U_Myug{P9IPT3ifU7= zq6s|-i=L4dnIH|v@WBS7(C)>I)JKD06El3KZ*2)YB1{z_c-+Y;pjhw=4z#5I<;ZDl zOO3qSU{Zn7TCC|ky}C>uGm(r*yRZc`NDnKu05s)vY$be0Bn^mb86)((wo%6DFMkS9AqY#>jKwSES)foP* z9)0WgBjAn(!{lW0gX8!Bl_{s(iDYdZ`8ePUE%GEpHPe8JLBq-H;y6d1i%a&M!~tJr zbZZx;!GeEtbUxBO8R!`Eca8^pXCjlnt(C}bSXl?yEMTnwjS9~hl`~+Gpl_N(Ez!eHpEDSJa6l<)0ATTOHf}5O^j&pJp1H_pR@P2t|aS}gYb4$2T z^DT*zHXhP2ujZ~?#Y!D-X+B`^=P_6l?@JWJiB{v69of0 ze{5-Ue0g)y7n@v(^-M>G<~J6DJHf4eSO<*S);5-L2^LaL0|xn`=fDKO{XYM8cVTcb zy;0tfZwJ-~ed5AfV}>sh1kBIz1!o+@`Gdhg2+j%Vu7kJ`7VYxU(KP-=BVqr_d|yLt zc`-uE>xIP?b*+74Gs|lzDaB~h5enz%nZvlCu@3V=S75#rZi57AEKCwO2BLMKnh7u& zNYu5Iq|BSjBD6o~=8+TiO1)AQ+E35z9@h>(+$q!1Mt$51>) z3PHP39s6rhq(B;BkHGwqeq$L?9tA&n#CW1c_yYbk)(WyFY`|y~9|z!PhqWU94UYHs z5=>~{{QPKNciE-9i{HvCC@d>2t!ixT?(XStZ>TQJFRrX^ZfR++DJELi-qF+5+K2$X zxU#vuy}cYkdtFO=XHRn#Oo5u_wyv(u=F*bla(D*l>i74y)t6n*FT~irrKP#CrY!&J zGlgXp4UM%$MR^4!j+(TGNH!)rDnkpE+K?08rFahy_I6gewTv?fS`Fas@`Kr3As+#M0`B$!9 zFRyN_tEwo-yIxw3`F=}%O-gWy-9L5l zdPx~jy`nh(nF~)BlvLDIS6t1zD#{RT?U+2YwltMp&3oqJwJVqNOKLj%ho@&3Sb>s! z12dzT+e}~e7=>J$>og)hm~u`qsZc@y(~GWw>T)B3=w5Z_P)x5%r z`mW(|+z&8=m|`h>16}QHO~lcqa4@#E@IAp|I5jce+tFH8T3T9;u|jiG6J`q~B^6kC zv{aUsUN5bI-_zXETv}dL(a_mTdlzXh`d`8~FsqhnEFTf=<;v?wq2c%AgMC=$!yb6p z1NX28WW7RK#A1cY0bX098<2DCee71a_*bGxuf(CX%qECc0-B$O+J^?%V7GFV4b}zV zXo_&%mC}P`Qffg+Q>8gso}f(FA`!K)>k;6b!=0F#7L|jV+WNoxo4tFx+-~7#Ye&|DgUQ$+$b4Vef!yp<}-`&Cr5>Iz= z*a)NuJ!x16g7Fv5NE3*XATS!f@0#l9Hq9ii{bVmp%!wP{U)C8vGfTQOGqH~(0f)(0-D0jQx|h#B z2W@bC>o$J9=oyZ%M0Tl4FNTL;kddH8Z1%*h6H^hm!MqiN8nLMnfhPFTU=a7*5EqgF zOf;uj-w3%Y7)>aDC%=~9%`A$?POt3So19z%8x)~1I1!b7YV1~)` zxmi+lEVSF<)u@nHj(HXG+u?Rf29P+)FsQ|@hJrK8i#?;G#f?K3%Ll(+H1My5Lr)Zq zJY6=HU$@*b9GqBKnOY1iudVvfVp^e@0%nblH>jDlf^%E2V{*i}&?DLq+TxCgv`gjA z^uGx5@Ec7h_S=t*^O?aD!(WC27xf^Kd=b=1PIb^ zlK~3(SC@zT`+zNz(+jh-bRP7NOjazfeF#{WR|PIfAOgb~-@L1f669DhINN#)`g#E! zYn+$$)K)ju)^`n!jSRH6wO3X3qAxp#`ZtDnGjmA%;fIUF79D2@T3W4K5%lNP*Sa5d zIM_AfVjbh_nW^!b%IePU!O6+l;nudE)-LpWvB4HAYzYfUka3bWF+NmYQr+)2FV;O3?wJn5I^gd5_CCT|x?&MC_Eom~AS*MACx7aJU#4pyfTHv&_UiCpW@hoq zJ~=u%Iy5qlbu7*_1Hj{)VH*@)K`}yx@;I)z|bj*w!(pNwt(E638_cp1zCQX&w`?ZVfdD?6krs% z)(YzVPh8>Mq)!+``ozxOdq^zVqIe4f!Ei7rtoHO6GZ`9&se&4bafl~ZjiXMt(_e` zEj1|ESJpRo_4f9+)zuVVgRxUuTwGmK*NG4Rt`?N}D{Gp&`ue)+>#E9Y>bkKa7#i&D zY_2IqWxf&}{g%cWWc7K4MR-uCt1d0Le!a1y3$ucTs`ApZdJGoYo9aui6;;%>v^F(V z73W{cyH?W#u&yh+o>x#>*V0^HTKLSxXD*c>v2JX{e!j7_y{)ySk}syBsiUK-wYjOR z;Ce-UTUSR%bA2VixEGd_=o@fgH6H=~F@$d>pTJEh1XVdWG^Pqdhp>OKz|rHJi!d`e z)!*4sQ3wZwig&iQ;<})&1lV8K-rgeS3B@IKt?ivSgAn_O>gwX6f@iK4lvOv>*T5mT zl9yLdiN-};EkCa1brT|f zY;*BO2+vsU6kHCi&RfURsXKw0$uR1-*EcrcPGU4N*wCQcWg!yBt=X_`Sw+E~a|FDOV&W5>#fYOma#VsN${? zyaHeak*v;y#mj-J9N^_(8Wp&2eCz2?eBu-D{GH!<^wCEjM3n=FZ}7U;zy7y=>$g7m zXMa|7y%e&O9smFu^k+E+fF__5P)lhB=|ihHE&XYNiawJ+#fV!GB8(c)fr@EZnGvEf z3T`0oh;EUgtLRh28DMbX320!0Kp2X;ugLH893tpgF)F2dG6cadG7h|KolWUAP>@cv<~o& z1c?r9te6Oc>+IEQ1ydo=}hO47tV0eV1|jOmKKKxM#iCk0*tl@aa5ize)hmx zxbcQOhg*Pmu9>N^!Tz?E0gi_fS1mHcj39HvjHVGEyMqhY6uLbS0M9BvN0?h_NJ09HssKm<=V9{a^Wi{@_L2@16W3wt4NT6$ z#>*Egf#@EG&}pZCrhD4!FJ8R(t#3W`&2K(+F(231gF|D}lQV$dCFT#a2!k@9D^m5D z*#+hpDzHop!W`3VdJb#lvC*-<&bETxTo%ERc#MmLlPqCVF6u0^n};!aSi0V%8) zc5ZlQ1&PcbrEeYCkl8-q8-Q0r>pPeyw2!XU^e&AotTzp>H4Xbm7B@kuje~25yd&|$ zSmJ0qamZ4`27!PZRV!Kgez>Qnwz$53XnbU7d~9?|?5`*1rl;nnCTH=7 zHZ}(TWNK_;dW?2W%#2Ey9>yd380r8RiIaa~WCZ2v?(WXcCWz(hd37CK-QDfYV58>l z{^5~3L{92`LN8J%xzdWZXax;ndh1|}9{j;*ZX z8*Xx9th=@L$tUy5s_Sd&8j7E~m{$slm_}(CrW&L>bpS{*cEW{VfR|U$NDzIA`9(e) zzDL$r7f>Y0dj^GIZ2w&-EzS)N4c{PsI6S}JJnToupl>GHH5u-oUFX^~5*S_FjKmIO zyGJ_-!afTHuV67@72QO#xD`Xoz&AZKGz!0JVSa9AxVx>Tv8k;S+w^KMBevccq1ShE ze|&hLtEQ?3$#P43TYXh=Rcm+u2-49W%-1`6y2TS;YxmF;yaN_blsA@Ur^b6)>IyGh zC@!x7P!>FMrK)9UW*)&O%(*>Q`~5@C(L1EQ%uHDZ%|f@d3{w|F5?Bh#H+b$@$C-od z1?V7<&eS#Y({xnk&T^M2GU1h1LtpW+uymk?f}4Wj(Fr-hPJ37THK`RCZ%x%2+^>#JYR@b)l z(JU%u&&{&R!2{sagJ#F=+r6sN1eS<>-?e(Q) zwJqT6zCI>QRbf#PwhhIlr5MN$j*RehRbv-xAFQdin%d^hfsv81@v)Ka7F_su_0RdE zF&umz-+*uS+_#^7?%QbH7;6Qj70e19bopdpvGEnbwT5xLytq6)IoZ?N-rUwN-?fCH z4lr-`Aj&`kxEXBi?dL=8>&1q@uCAf39(R&_)4e@}?k-LxXlZWg>h9&QtD{|hwD52j z&)}9}Xn1&#;h&fsmgqPwTBhyLov)?^SLj(z=u{R2ZBusA%-@emX0hH-iVpA}=` zxng1hm_Lq>M-E^Zz|G^}C~GEq02m7g@M*kdGy%Ld0oOwf3KuR}6FrRr%R|nC#X znJ`Q7ZZXazhh4})6VsE^Gpt<_ghLBcaRsi9KZFA`Iqgv;Uny&sAx^y8&0T(>4KtPX}{)Zlv zKbrHhm%aRTuY29w-u8|^{on`l3$BY~3gXg;8ug3-v}X}JqFM||zy^cp6FCC?CY?_Z zKqRWsLg=cFJy%0@I4L4Fm4lF=NdVFkceLC^gev+WatmINs-CI<9pVImHAEY4p>Q@< z1R)&Tgi8yt#^rz^D0~smVI#~P#M) zd%5@q>Tiww$k0(^I z2<+|CkpO{PaLs5`Yxl(C8kc)qJCGnihygIux~jUXOKYvOw9LxVT5GLE>ddNYF*AI+ z-}iY$WMo!V&-9?dCC0AJCnqYx!^6Yf!~OgJKj9PO5|By`5P!g8)2xH&DrYz|HZndo zMlP_JyuKu$ne2c(Ij*}QD@>DhlWU2nhK7hORa4*T9U5b+qX}7~iKaC*JR>opaP~CRfmxJk99o+$R^1j2BkD^i zBd*dHMno|k;dBsP!&tI=$L0;_J6I`(-1^Su%+gqG+gM@4bV>76cKzr(#lzpvlk`^p zOp!;-51y7!w|S=r$A_hg<1`oJ926ircZ6risFlTGZ+CG)N&m3OHWPvnXC}vIc=Mrw z;oiRCu}O)}3baE(%)KIq%n(wWkklfXa7^P*62)s`v=L9z=HA&Q#2LoB$S3;ZLK)#|?qUUht&jzuu% z!WiQR_~|LnFRf=cD*!PxgOFOpAfKEV?QX5Pe?PMfq*+&&cmH8VPK5~ggTwv4;U4c0 zLVr_pt4E;iP)}#81lR8L`i913bFrb3zOIhy@~YBObYG=U3)}hzX-I4>h&ds4O?)Rj zNndsz9!w*a^Roc7;VY&A6B45>(=uAPq+>>8KZXYh?#}QAn|oq!&^fYN+q=*=wLLVy zH#onKrn{WT@YVSu$3*d3i;71(j8vKA=WtM@xQ5U1fb!No93mVM)2Cy|aI)zpoAZ zWgMT2iwX;Jvte5*8(Z2s+nQ?gbFswk>Fw%jMY&yEhW@a=s@l`kJ~Xq4^8%JHY9oYW z2q6d-XMLW=@|uRmRt&3&>gMh5_qEnHRTb6}WgR%tSeV<`*4@|BS)Z4eQ(Ef*OLuj5 zqonQWswu84FRpF&h~;%@ZO_;gTeJy{gPNYu>OF0Bj~+aDnp=Q|@*y_H<#jy+1j$1e zFY_w;V$dIE1`Kb&CZXpTHcUagN>IeJU>rY% z>9wPd(T(28EqbI6Cx!X_rh&EAk#%^3-QzF;5YB^9CRiq8rf~o%%5kO${;_iGY%IbF zG`Dq*j)C18ON$%3I$JBUvz``LR@c;4SLEjwG!gTzqoJg#O%W2!V+BB{Pg7bU|(D5yC(%9o0o0?l*+hU>fp9cuB z2yYN(r192R8bHhvS0Bz6&nAM31eG_yvI2y7^$eVde)&>d6(Uh4E)=8MEP{8;5PgHc zW`^V`dZ%q+fqWXW-V;<4D+`^e26cV15OOvW0RO!GBuk=8^rlMw|I7K=Zh@PDu!D$Sec;B?uX}uR$q<`2q)-@i^JdbAEg!o6)+Dix zlapjt8o_*JqUXIm!S$znjCzKXNy(I8GAmzUTFeNU=RijEC(QWR__6Q-nh{sfx{i!Z zvLo%oM`?fgU;Zz)8~Ck%_wRn?SAOLeKVBOvC~xp@e&gT%+u!@W-}}ZN|7XJd08W|1 zSD^^h)DY>B1I!PQ2WT9EKk$p#hy-Ps2cVL`no%tt)ks@nb|GCj3He0KJF#p>SH8NA z+=Z1SMxw?Am8BLPIxDVf;Z-ZjDr~%QWnX6eqYogr*H>5OrX~i^)wQ*^u-i_D*EguE^+kVYmOQz0@9y0P4<4qW(#@@G?Z6tdxw`0SdRp4! z#~DvDGKyL{Ap^#T2Yg)~!ZT%JWsKivNoi?eVYR0XUF`t+0Md^8-&R$vjbMD-I zaK8u}QlR1}k*5h$UEepew6?v0+X5E#y6FbPhJk_9ZF-+yk-%5ioIY|o$SmmmNw?U% z0js>L`-C?jxWUoh+VdF#aV%hn5sJo@PEGs)L zExQ0`+E!Y)x4BJrm};o6%`dL3Xy^c&G*%WC6r$P1zjkPNaG<3IoYpZmi!vWYJ#sjd z8bS7OD#s*Xd1`E+rLHvNar&dI?5s!kGs_!Vx`-t{K#;Dg@{%V{pNey6eLLpm=wb#3 z2o%;xd~7l1tf*(RGIsoGs%RY;Mddv=In>|K&?6{n3`JE}O<`RFU74BtG$XH~2Cvv^ zoN}LL7nRkv0H)A5x7Jpc6!3}X7ZjCYS}W+j1$Wt^%Ib>RDk54HV=RlCq-mhMxX`_7*WzAUt?|J;OXNBfs9$Jvupyq>O`x1i=%duk}sgrpDkI z1fp_)_{S&A*f1ZjBjcGbmw~}o%h)jIaab_lulgzYxA#w1w~q*J;PEZ@PHy&0Yxlw>4B1Kg}%V z?q*L@eN9o?J4F3%Zg2C{<>vxk+q#+?N^+j?WwRGqIUdUSB@Khqi+D=_%^5oD8yi3r zy1A~Z9LL>mHYM-(_4f}Bcrns$E6c7xKa1IMLtbVrs>im*+^o#<+Qv@oy?Z6~c6SrX zJpWO8UQYIt+e4%t!!lnJ{nd)1gN8``@;ftg5=*E5kV~?JRt+B-e zdIUR=$(2Lz^v?Xo39Q0dFd7KQ=n={Raw7Ay7DFlX747fgbhEKMKj~|)A&h-Xb#Z+M zd(m}@Pk2oeie5HfBMiQ82(_=o#lsc7qpPE_o*4B7rA_Vat@Wh^*#&hiojqNcpV#z^ zLXZOwv7Z2MO^o)}6z0`nNZsAlP+eZz&@nu@ytNDL4fuo6P&f{Cz<2{?gH3>qtZ0~R z;Hw2@Vc$uy!@qh4lgugrb)foXiH>NdFMiFm#z1|uBCh!m3~#_nM{}{{$mo?yVl9@M z#KZz>F)b(K7zk$E*1O|x9mxlGg~4oI9di>cr*F~SfdF?yL#h6CvqeB7-c{-)BtBol z=u(0z8pJz~5F(VRj#vC?*OSE^qf@mzrB=t9j)>F3jpBr2B_?^Me0WVz{IpDisB+ww%NDz|)0l)Y#QYNoVr_c_rM3|1G#3U*GD`sgLl0u!r zM2K>d7^+!`lj2T@tYzDlAe(U#TSrJ*#5`QgfYOHCHc;IWjm*%Zwsf>JdO4}*l{$b^ zB22CTcHJUVTo>tjaZJM*$|T3zQC<9$3stF%o)soag+}VeTf?`ALJG$;V|mDflm`}} zUF3iHf}|!|0p}x1R7R8$VmfF_HUry?XNC$=8Ht4$;Y~elQ6`ELgi{U&`V`?JcnV*- zd1ZHok9>R$p?s_f1VOE`mILBjuDOHAQENeV`yR=QTQ^(?3SXbe+5P4O_?`)j8d4&!e= zC8{KKqs|OwR2wXRU}2U#6zzakBq!EEWXQpx(dxSTzx{vy?(1LwKR@@mFMRToA2*W& zi#Pa<-}v3%{oOzQ>i-ENXNXj`a-y zfY{h$tgf`aiJXS*qDfqW#q0srWUak5JeAszOi^`Pvp6|8Po&Q(<43+@|PE<2ihBQ?%qiwN>O&sxEf93;=O26DAwiF*QIpio?E$iH0|L|DWG~|DWG` z|9z|uIE7AuKv_rv6o}a~1Om%6QU@{AF%w^y9&RkoEy^iqZ13~-%7#vLrH>!J{Z3XM zp_-ek3bG&k;KzlvV(SPt@%9gTI~vRKbMHT@=)e}SySK9)OItZY7JhQ?QBiG|cMyY3 zQ92;gqxS9XY_7~t``#S_G&R&WRNcAz_MOMMHSOT~*1GbiZ>JL*siUQ_^11!_l^2U-7VQqk+y5FA+4<}zH{eEZEFwE zk}a)Boy|2x*-!31ENf_Kt}IM@>ql>W_pP@cWEWMnQrYf~4o_*@==35M^f)X?xJV30 z=pD4kXe|MTXn@dP0uT8UA>4EUOSb73(-(9NXGmNHN+flk@CIUUu(!UwIk!Aq)zbU8 z#Cxxx_pPkHx3YS^o!2Ok!D@8tG8%%7<5*qLA1$CDE~@Vx`RZU(1tT$@`+ zV5mLDeLWRvnHdiX%1ayTE6WL_onO$>(b`5Jr+40YQd;BjwDop%w1{%{X;E=)Ym=w0 zFzXQ!$ z=;$8w4U7%;c9s=4m6r7k_=eG>=0D0QDsFD?=E|gzqp~jtFNWHqC6|B7FD&U zI^*u$%zQ#!R~J8i_?U2BZ9Uyh)m8b}4*>q5d0O()^BS5vu%vG)%`GS_scHAYo#KW7 z%HZQ177can!+Upr_|}iU_ucRR_}*hY6`I@F&a0=zQ~&5OfyVl}`cQ=z=JSjefv?a{ zg-^>`I=ekJ#rGdpHZ-<*nmfpxlUrZeFfciX)hH0dQf(t}f@>HKvd{R)D7FXSpjSXt zMuh~-=WA4{k71(+5*LwxrNlfWF5;rZMcnS2SnnQPtM6NE^eyAFFut_EvF|@Ri?A&q z5K~mQ(IBegky4jQF;c<5V5+5^Ie|#u%xQCrK`KW zxuUd2hy`ryi7%dBP}|6c=D2u!@p3@Hh$2*+kIX`@?b)^Ct%Cqg z3V?KOMYa+C;rNv40w7Ej5e0fIH#@M;OS7X*RaF($?E^zFW@AHrtr)h~5=*_cwV5{b zjf{>CcC|N^6~n0(6_uCf7v>Z-5O}|4#oQ&H549j1hSvWN)&r0edxU5 z(8ZdQP8$Nh-AT6H470ta?7xXK01g50iK-M38#Z0jgCGvQC5(xPNs1|~a@e>-6JSJg z%CD3oWHsG~aG;NtDoG)UT|S-tJ!QvFMAk@*um(11@Z#O)FWzNf=#aQ%NKh0tboV>O zGOpBalRax#C55qZlEdNX8H>izC|*LI@L?DR!}Tj%3g;7-C{1lI=`6k@z%}DU2nr1C zU|@&Qli>+{l!h#gePLm zV2x=faZMG6VsRqYJQ{OMMJ$Uka5qunp>zh;8cGq{8B7NuB#0w}IK4^|8$UQ4sl3V$ zDn&?qDr^k!A+hhZRIB!%(gN~o1Y)(D;%3z828Q-=5-!%pG;K(8nU-XgNhI0t()v@l z5gup3;hVv)Dg0HHNy4Y#;@iOE>p^BeV^w(od9*%)Gp+-9ir;>gb8!39lWP@D{?jfe z<#vBi9wEO{6Z=@sgyp=s#J!Yu0~Wpk1+&DEei9(ey{`|1ft()zgfY^4BPmRPoez<2 zdKM8}uO-5|vK7upP2Brh$$ro!5#&B(N-E!7f2+<;Ia(7Z!)+CFGH_t$an(fHhk2gi z$K1lC2S8@kQ-_6hoV)Sqlqd(i{pf%H{4f8@m;d8`{H@>mxS1Tdd4q3!MR@_a1u72)suv094lQ6vrA+k3=Whx zc>n$P-+lKz{^qns#0nr-5`>B!s6oWUG{Bq!Q_H!j!3H*Ydi=DexvL9rP6&do&f1(u z_wS~m?jxY{kG}b>dztLMTwY!-Dnz0PHB}X5yz}Gx57G)sYnoaKhb&6W!tAGaGs-%9 zgj*QI?jGeV=H=o6+FY4?{~y1Tfvz|&EA4yVyK^V4sJ^YMr4`(k_JjMy;W( z-v9pFk4tMBDoP9Q|L9ImReMJtK8B-cC--p#+m-^mfWno^vtsQrlzvo z^tawAZD{N6>hX4)1l%pn|G|&a%j!L4dG{XVq1Y>U^60^xhj|qM)wcS=rh!q^m-rD7 zx{x4RY&o%a06YYG01R<#92mqebOMvtZt{Qdpr|8b|~f81&Phx;A>l-~A(4DZv@CGW`o()yv8 z#S@SH5PJg<8lzl#XJwU;5R=2+vWzFSwXGeUzTUQ$vcjtLjE45MPPPR5@sBgn_G5M5 z)$YkJsLCp6?(X-oyH`_XW@cq;n~*tO<+){Lh4o#io10onv#Nb#U_LZIkXI7S4X1^b z<)w+?UQY#7PAjpuJS{B^6;Gb9@peO7b6rVcZhBTtdq+oSYg=b~bM?dfIi=P06*)P1 zPx9G43R=hO#rgnClb#Z22TwP)4c_jK%F?>0*=>D&gWYZI`45Y*IqB}A^2EEVE-K-? zucN7nbezqN+w z-~|;e${S3HbLiCMG-J%y?Roly5m8xJSBcroz59jOGIVwOPF0d8^u9@EU>M}0pRENbh{J|#CME}L=eK{hzH_v+aWJ*C?Hya3S=pam zJ6PO2THia}JqjG3h1GRk#1CXnLj562GjlN-;SI$62?OSt$<8`V+dF)N6Sya|H8tnt zw-ZjSIy>`GA@SK-YATA@1FfW%Pr0MK!c$V+;~O3K^?Tbq6~&(3{(dh+US?iNMO95r zbp`f4#g#Rb-F+B7*ZcW+KTc^N@z0nk!$SqjZCu@84wKelUWOICQOc*Lp$ng z%Zkb>tBJKv4D>O!sBbE%@9rAF;l%5y=Bw@=7{>SU>GVzji@O+m&3(h8Bb_ZxIr%jmUS4i^Xuw-vRo68_Xb!Zy;0`=%#BdAD zh;6p&JtZ0{Mj(I`_owP~ia9_;=KzQVxe8nos0eOS>L3)ml3f)}!`p{}iG|ID^@HWj zIT1+jc!2gx|m?KHF<{uiRnQA|NS`IFZq{3DA2ugUyxlIoYSOBekzLzLD?n!9XB z;$C7t^06r#d;|m&@Tl>iU<62_VHf?lsK^b{!~j6xB-(ZblB|h}B`x~_s;a)9xZ2qX zASPH$ObbXH2sE=}$MH~3A~>Psg?3mVvdWUN6_fzEqGA>oBnccOafF3LQflReP%9W8 zi0M9pStLd?(okXDw*rQNM5~gxhcNKSmy1nrv!*Lc@%4>R70Prm|DLYN*30| z#;^il4cxXE9-bl#fg}UQ<-Od=x>rj8v^w}&Usf0ir4A4R~5U!^}cEYqDx(x1PHr1m^2`c^9Yh@@l5#WgWR8 zSy#E_%=uDIYJ=d1sBv!j%vs(Dz=U~~;n-2R1E0|sqtvLXssEe5{qJA<`hWV|=RWtz zPk!>3G|IupBfA6#qft4Yq_g*f}sx3hZ|~zr+re zi(dGF;czYuE z4fizFG!*A~yf|17^|h2BdOyxBs$$FCy2^sP_pzKNJ~0Jlq-W$*Bgx`Wj&vtcyf9*z z9v|-VRHl9B+mABy3-WW*e)!h?dzlq2gX8#L6H9*wOL&QFhMYx=YXp z1p75un#vm>0-04Zg*RYqu)wi)o5k9wQA7?>;sE9VKLrxJ!HX9!5r?9&II0Rtn_pZe zJ{9x@)CWG0BHd07HI?OOKgu8&a~H6aZKXQ8nk%y&J$iU2qp-Xv`^W$9KitX4Eh?_4 zkZqH?u)QGUQF}{Mb#d+wfAH4#zWXSDBFBph=<}iOVYV2>ZLKXyd+UBtaaD6uL-mu4hu`|n_kQrhyLaxROzrUw zj-gf_8Jiv%8fP*m4UEGEJf6AGyx zdx`q8+#kI41h4JtlJp0;MVJA5>Z{op>PKl=6}4rBjozV20#R(k8)yev+n3NIc-qoC zz!{96XXoZ`>L6MDRRS@*fykdmBrqK$SLqbOdhZ-;6Ve~=ek?1pO6&jWe*L%ZHhk+& zHr2BQ_^7X^ zyP>)+Eu*Qks}H<&?_O4UU0Y}0AZ8Rqrp_#E1t4P>(_UWy3DDZ(Ljhcmqep%n>P}3@ z%i#@1@W(}QY%A}GZb#VX(SeSdr|C~=Fo0%rdCudg(?9 z^He-d%PPcMfj!0O>&)UN4HZ7zPbj?sZ)I*?CEg)D{hq4Ir;l#-frgz5;ePug`r_*Gj2fb=jGDImK02$_qaM^WYos_B0n~d8j|$FC)Hs zHcYQ?>mMG22&k_r%&BSX?j6R}SO}?hVq8s*4fR%(lx5{s5o!*o+)!BfIIEmsbiTfh z{F2tDjv=-O9P00EVQ=-$Vd5qX4fK^}mv{8QczEk8i}G^wvU3Xw-d|W=Ropl@x4a=C z`0zBrf>Z*m?agUOPowb!uA(Fbk|5#&SQrWPxcNfOz%ZXA*vHKqXa+SoIQ8Qiv$KB! zb+Ej#hxy0y<^i4y8+*sw2WR`oes)+_nT=qlCdv&CS-S&6Y-hfJu{HL)1YaOl>Ez&O zf9D`^9;PM;n>pCn%9x!P@bs@;EqTA#K<6)LgLCjNvHwYK+ZcrEC^N{Vwi|_nDCO*#K9oL z1bHSVCdTnh9}`CdAhVctu@57z-)tU$!#5n*%rqujvc)4YF{Z%Agh0WFi_`o`;w}(2 z5i$v;ik&kWg-=^srI*SPs64i!^s&W<(WSeQd0h`}3y(J(?cJDXsRF7|1}Nn03i zsIMd99u6R7b?si+juPXRHKJZ(!Xk75Z*k1zVGtJEJF?%+F)v1-9;R;befEdYNeO9i z`OJ=PCpb|7X&f5^1-6&CBp7Z4cqr+mTfck-1g7F<=$iIne7@Nv2!-WIqa#vtxK~@% zd;0;TfvR_DWLm&t1}sIbkOL`+Vy$F!xF%wQK9t)T41A;bc)CLz;HrS-Icuc}aR4eo zNE25MNF;azLmgmvK%_(@KpTK_EJ=M^XjMtXi*S-TV^BH3{Ca|p5I+%d6_LA~{8l+P z-I81gct7zt=ebT%az>12NH;v)Ij_D6&z=+Y$Vo4$81IGD3hYws>xP8Nl?iNgBivh# z71$bB$}hJ#$2T6xU~?5~zEksw3D~C-5pQh34pL4e>p=p*l~}Nh4V=+yJx)P-3IpK$ zDUY+#jrA11f~T8w9)!r1lnl%TwkK*ODrs;unq?fC)R0?jwv$Xg)VkYNC?^bzldz`^ zFcY8>vCTed4&>4e$if9T498{t+P4eB#Zp?UhjRRkxG4V6iBJbYcu{xa43~r{?n-b^}QVQU3G~Y~<@eU=ET{aN(pCe1IbEF4(3P4r;xetJ$UqIfAN?9;Xhz<@LM0JCDhTAfFT}Z=!gaO`Wn`} zON+Ckp3>61wA_YPHaP0QB);hGo!soAy0-Sl>WUxVt8VXuYQXwn3_tMNyeADkf){%m za~_vgmJ+~wXn;7$RcSvmk*u1E9_Kv4`?(j31&OpE+r*<>nwuKK7rQ#+pT6_mAO7e& z-~PwH|KY>*k|yr}5#ZF=9Nu7Gv}2$Q^kV4gpbJpu_4@`9xk2tX!O|4oKuqS~u93l< zmC+m+4JJY|G7{SZVckiCur44#8i^6Q;KfVPG@*0i6e=iy4EnK!#bw{%2=y12vQsOwX@r=<)&gfr4#KHE9nYWR^66N?Yslv6v`n>IMOI zcC}ZRW;nJ(Yj`0V!L+P)A> z`w}r@cOP^%JUWhVCIg)W1Gc&_-B!`q($It1GVa_x?ai6FZT$nI*nC$N<0GD3$ktxn z-nJG`W>MD=QS`^BeeD$$p3Y7mP;k7fxves<-ZwfkK0H{HU*{W{CB`145ym+ZwtaaS zfH#FB^-xcJNoFQ7@*ZVnvA=dnVMQx+z%X6iT+4+g>5rde$jq zVD9{KPp@xyf-j-Aw18l6g+&dGEv-e>eS<`>92;+|>FDhp9iLp78Xx!e_BXZ;VQ&LK z^?K^yh9u(m$Y3wZ^U|`i^2*w}CW2`bLTk9EeF)9|v;^zKYG}Ya0_+9ZjuFiOgM^-u zsrlvENn#FgZedR1>5cUEQkaBZWYi53C1G@$Nn>ncc6RLjVQO+l zqh?KO3~d5m5IP&Z@Z8M8s>a{L`U8Vi44!2pIb%bMepy_JH8_be6GFx2@CJO9HaIne z5*wpBR>VdNCK(ia5}_38;COTQXnbaAc4-}s5oo-;4mrF{$WB;dGuto9CX7qWZ&>g1 zi%E=nQe#iGjUND%Kx@Ag{@2u%9T=g&h)c=GB5^g@9%6EKT%u*pO@hAXmgm@lWOrmPId#=Wp_=CjE*oOu*MR~ zQ>@CxvOTJ0O0jn0Obp)yvdFDz;UG%iD2M+!OQ#U%Y&e#IdnUXDwij zpp|4!vjJ4f;_^oR6a=RfD-RNVv{6PURMHw6+60K!3}my^(4vVp+^kHqd@}r+B%tzI zl1r+|wR$`NK^I^=K<_Z3Scypz;=mqDCPWgfAh-{a49SfKw0HxHJrF>BJ*ka~G^`{c z8RVB3M|E?m{}RU*TWdI5 zQzfQT1_Pf4-z@N-&xdX9+(}tD`Jk-9EFUa0B#ffP)4I%!l$^BqNyBgoS*nX&h|g2J zT9iYu=2#^OhM*%U49JU;s+WjPOW zo7%eBXc%-^eD7{61#k_m+07eS&wrXvBX7bwg9jso`QtxogBl9;qhBPD5xSTpQkhz+?8Hb>m8q4 zSzZ%wTq5s*J3$=4QlKc@1g6edu0kLHtC8M8B}h0T!YMJXMBYRAZqFuh1Szbx7LSH|z3`+B!re&iYAM9!> z%E+y*Xu{aNx4ydaL0UP8P!9-HuW)>X5McGvJYJ1G;|ZhWMrvZ%VX ze|UCHz{tK8fP!X0$YlJ8`-UPHET8EeNCVm*iPv_Pqgagg*og>FrOx-_u3-+U9#tb3}CZA)X3ln+xMX|o)YyjEj7so4eXepk*FmY zHMm?hje=1j>4EO2FfZ}j1y}McJd}yB4N#q#M_D{QLr8K$aIY-P6G|Fah>hhXHj@S9 zZh)6C9=5jo1g=UH5zM;4&BECu%IHgEQ3DI3S#XT!j3nnJYpPz3DD$&2qW zGceSdGr60A2K7NKHH~dT>xqRw%>ullaIP9lax0r1MV2o@-2vp6xF{OmOoM^bwh&x$ zFTvu}ui36%qMj(&(Ms|8cIz^Hw5Sbgv19%b8ZJDMEZ$JXU33|G?f;wQMI`oVfc@b!q1SQM*Yb6tN zPduOro`*LQ#WUN+k)@4=xtNRFm_^`#QT7=%0h+!bPRbJdLcF;#-Nzaq>j+p5yxK!B z4*(4j(N!{6Q}ZM%cgy(PRNl}6icf*12E8V5t^*|H?XWa3NuVNr8P5@|#V(z2H)nX~ zTbf+Q()*1c=p#%or2bmnJ&%t*kz2zd0qjp7Z=cY$#Wao>8zpmOUs3At-gE}X84{shk;PgF#2 z9(_|erZUoT(x)bWGE3mxMV=eWu}&ItBP9=hI`9Sz2^Dlj)*ZWO=b+HT7%Iqh^?p4-kl@5Ng?&$2Q8sg*g<^P+-$CDb)n6Pi|o6CK>AI$VYAOg>sGyS5is zs3rj{@Bqv8Os${}&TxppNe9kEG0u(9 z_?2ka4P%{3{tF)bs|UZLq_)$)4j^pIs8Zmt{U;G}OcJL0rei0Ab6|2hzs~uO-2o)C zG|n??I^~lwpBt_{EKhFZCBgdVHRs77;l_BTOPF3IZoE zM5QAn2XV4Phl22cYD#QVvAk0LpG6SL*O0ohzGHH5e6qQdFgZZ?L0BQ891vRl-n|EZ z{^x)3vvZvwT5cz_gr z3oNy?Eh=OltGz)Y9FrqZDF*R_K^RvkzvdQK5M`06pa_h*O6YFX1n|aKES&rC0Of%o zk)B@P!V+65Z1E4|u(q-|HSBAvuCA)6tgNW4s;q4Eu)8`u$K)ued=R^L*}J-~zNry* zq`kMxJ2E!p?PzOj_IR3_*ng}SOJ>Lrc4h>9jt&jrmflB0``9XRY;C!7q}c9pFyB!Cs|gL-#sYmco1*GcO{mE2iJExRT- z5$rjqx?`}aMA;%rp4dcVP>n)a&Y(!8O^_JTh|XglB2an>fCeI4r~Ex)SK~^l-zIJa z8b%4g!V^h6nlmJ5ffR(8OzeoFlOBGKk0XO>hZQ8Q zXdv`uL8G?HSfXU3Nyd>v@VglKFsg~6O?^PD5JqmcOK%BXPU2f4thd}~C5fxAAk-MEOC0Rv#2E&U?1=zCkeN0) z(a~mfahDhpND>2PaxyCTrog03ypmK^s&lyUvo@F17(OWwR+4KiqXK_kGce2toAlXY z@s26=$r;#19QMT_LVo2y#-U(m62O_r8{mD3jXRCm4!xmvBx?ilac}XSfJW z)RIY%ZrFuF6ul=;JM^6<$z&Hw}_Eyh@JqaZe*$&a07C!3^wYt zoD>9p^43%gO$RkcAQ5@S(qAxr-JG0P{_qE8hID@Mt&rprpUkmo(!{StAZUZDGc`@5 zgn-fl+F~vzYvW$6#^IuQQRRyo0j>%YmW2G1$+xDc*C^1D#$WN=50mE=w=)1zlJEvf9T-jV?TTZDjgHdmzaIka z+L$*9e%b{l0JU{S3sjA8;yW@5;_JxzS~l|qabx0HDR)`77!2!%w~1puM)_<-8+gO# zX+MGz_`mWfD5pTriHQYNTpT;;F}qMI@_=OK@eLZ zr>*M*vskY~IoL&umyMJuElJ_L1yc=}<@h|bb9lP7cf7fGytRwXo0z>p7vL+mvURkw zdAPnS$2*5-$HZw2F+l-vuB28r!gUUAnWJu-yWHn(DC!`}RPC@kgZsu;9GhFn;J)|v zW9J)je^58xdt**cret=qeT)v6yKb8aUt?Nx74nL^KH4R!_v%W%qW(8tGS#@T%n!UI z-=H${@c+uug~0Wo`y)Hyg-TEn(G;L2u+$2~Cc?G(1Ys9tp~n9a$(A5T>zhbi`=Sz3 z3rq|Y5%|SH9`jD5YvffVTO!sTox%^Od!y(wSTS`qj3Df=0wM>h$pKm<+vI?a6^6$u ztLy&jfBkP?{p!~~``OPD5a5@7>6d=)=YH;E!yA0z3%~QVuYLWUckaR)U~d3E!exWT zbn^zpH(;YHc!Pz-Wqe3QhYs+WpX{uy$$#*;y0*HsxRmY4TRI5yKP{fQV`E+YvRk5< z*Rs3i{LIYw(DXc;EiBH@vd=sl&I^XZS$Ad}0s-shx!IW+Q1J+U4dWON%Uyt0-T8NQ zabW>NdUg;av^RNYaPq~}8Dj%BD9yJAfDPlte;v63vLCia;2B z!7V|o`UojglA1${idlEw1m=)geg*Hy_yLOQUden`xC|R$NG}*#kIpiQKMnjrgNzJp zVH2alMA%lnr`$r6eB}+C4CYTVNSTKx?5n}9UaRQ57#mY_lBVH1U@_3FuS#vPtdLg_ zYa$u}><`Ljz)%h1Sd#E=781jtOXdn`4QT{Mk(JQo8gy)Oru@o{geGHyszZapaq<<1 zYZ)!lN;+WV*Wf{hD8-77STw~X`zZ=wEkJ7Y$ntCHj!kB*6}MQLV&O$G_=lgdlYLAh zAM1O`rejh)Cj>W@=aN8C+ke?UaJohh%vJfmOiqQm@+?V;k>yeXw;C2#qHVj96haSb zGV!j37SJ8EEo3UVMs0x-zt_IRq^_3{BGLP?Jcq&KIDvf(GSVRg3OmtgU{r=m-jvK+ zxWam?-HQx7gI;w6@}~wX^RqiU-Z5sx>cEy`#&8SAISOLC>D;JO;%>RCqz)ZP8JO9m4koz@cVkb3 zMm69h_garu@M{?OYrg_rvD8K8XMMi{Tnoy!c>^m(qEH9O*lN}*mc0num;$1eR#QVe z2sZds439+-sbF7)RhM*>B#?-BDI&cH@CGla&to)(5)-@tOb}rsRSHcJO8HaESJ6c^ z%a$J8rVgw>jqQPEP!+T59mTAI+j$l>F=)u8Ds?oW<{(8M`iB1$+@wT`SY?QXhWXR| zD{i46dg%hp;N3|aJWapY_VBhhC`BQ#Ns3*->KN((Q2}!ujiJGo%glHz0Vc%3A*?>s z1o9glAzg4=4?gFTNia^5E}oHJQvBJoSRy@-J%1ioRPHWHn;p%*1mV2Uq&VGCHCiVx zu3p47nLIKcq&`+x$}xdB6r$>Ak=iB(gIW%lJmz-&wH{#}$8U_p=1R|=M>Uz_IO9R6 z0~=)S`V|N}LDGk6g|+2PgC}~&buww*(BYvqx9Y4@lfxT4!`>hmiJt`` z`$y-(80?*>y@7<;S=&B@C|KQwE|9dodkTTDwu9snI18d1m9K-r!-&!W`Lp_KK;Lbz zz|~h=y6x%*miduye6y8#MLo@>8|!)FC6n{UOHQ55Rp(Fl!HqXMC!GW57Uzs}@QO?1 zF;|_;?t_1sOESq5O->@lNSpyg4u}Hb4Zs2+c}a;!0fL_Y$1 zfLw%}hP02655fYGEiDtCYk|@Tnttd0{XhMSzxdLZzx-)2Ir!yY_=R8iS*H$uPU0ed z0zZW>eBldU{o2>x`tjT2j=ceUAlkeEI?YA)rd(X^?H_8dv_eTqty z*h&ZihBpuZlF(?Ya#OQW0@=_uVl#}Y7m9$y2q6ht*Tk8{W%17yM{i*Ru-w=H4+7Ru ztE1Ew_JDU0&95Z&ua|wRNgCVVK5rp$3G)TU1bC7R*tC_lMs;ib8U&hvw+WmpDpbX! z&acr68%Sc>E#Va_s7e_a^9wMPW)!vTvA|)~u{!Y96e}ub%_G`XvHDQxZJiM-bYTn} z2xfqiy4lj6AU@G@s^zmllH_I=T0pTReMDxu6>a7Xy#vP4448QU`PtoDH0BIBXaN~` zGK5g0JB>htNSgq|MddB1S!!}EF_uu#(&Hq9mks2U^G;^-BBCfyax0cwEG079cDg_b z0p$lUL@`YYoX5(A=?6_QPT7(O&L+v$wmVO`>AGMV|4=Sopd3P665Fr6WpHj(4Rvnc!=*9)tvT5Yb% zi}1?AhdBCQO9jlLDarPdcKxa7+X;)U2P|`99Od{&+cAPbjz+qc`169(Q<7spY=Et0 z%rCmOM6#R+ID2dca?0(#RlBN=R)YHfKQ4W5#4Qpy`Z0+2AGgFsM+4)N)*Qevo>(&XtB z%e@RahA685!V+=LQIjOmsb%W@a0v=`lYs4VNDUFT(X(u2G<-b zN_Bn>hW)@_Cx6m`Q?k2E>1*j|A&89jO}}xWvmE`q^}V=;hpk3WKy0UQbKpF}eXpW& z8=I>F-C_^iEQH|!tY6;L@CG_O*pPye;LtUOv>}iPCyBF4v{iKc_$-BD5q~sv9zH(~ zogBa$V0D1KfyEn82jwIUAtuwE8NC|$fu41~h}#K0{kUj1Z3O8H`PdVakD0#se3(&9 z{mpD9yg@idScBbzQy7DtgHzapmCgP6)t#Bet?8w$`PIFp&7y!PX<2`W4d9 z8+gA%5vazN=y{9d<1@n}Gvnh^K6Xj#ViS3G7h^LfwnXnD`264)4#6u6E9nPZGD`t6%-2AH4OJ7`3at0T%3rH$ZCuNGIgM{Nl>&{G!+api97X790c$ zhOxmkeO7nH!bZ^wz-5P1w)LUnuxzliy}7XZk6?VONpz{n{<*4M1%} zmf^10-y&=q*;_>V>ln}=Q_++qa{|H}AiXQ<#F|oh14x5wyn%)k7U*H~5(fIYf03F< zj2r>iYW8fvDX#$FMTaPmP@^bd{eV|8*~B;5m@bR5*l4;PGjG*4nv)l zc*V9xg{nx?;LRI<4IoWy|ZB!y9GE&P72I- zcZ9a8!TvS^C4)dzYuHX}qCi3bcOZDPVKaT)R_p>m|&mO#|At0j4(< z`6~XUi;eY{{yI^@k~EZ4V%^~ILPF!4|dk=q4v z8};!A{gUl^vI{||cCKo`VQnHCduoMWjaa48EJ^#i^k~W60vV9Kon)|yLQ(M%4rA^c zGwCWE=M1a@piI%34Zc8Ol2i?iCRZS&NrLQ5$%ej27WhR^p=w{ijstw00|i8i0WG{4 zyRM!#C5Tmn0B5^*Qkf0w)eOQ)LT9SwbVDsOw5-vU04&y!)2liZZ`A_JizGeB8n-%P zG3t=e5Y*Nb;%;+J($_Ep&;?us%tv`19P6axbT37@f1qX`rQHpHWWO&Vj7 zi)i>F8jMH%@#uLxdKQnKUc}BW;^&v~;MJud@kGBXZ=j$aW`Ln$4Iv#%jGqXuF{C)Q z1-;RsakM2}Slek>XYz3mgI68f(}E00>sWf6Tg>Eu zfUWi<5_i$enG6g?&`Jc!NESeCW={FlKdpI5rx$Cqn~B1HoJ>A?ubH(3p_}lGOs%&2 zzo~}2nmrC_SRn^AaZCmtEf`#fu^A!24I7lf8(5^lMLZmj1!9rYXy_>7KM0-dhEDb) z!Sh&z^SCKsZy-;hGE@WUPL@1->BQd|l9s0kEoO12dXS(~oPg?P`jz&fG^%GR>>wbS zzWAswU_5A(ez>@C2!XJ$ zzDJ;g0Je%`>W*};I3F1<{?SI?WP&o#EZb?iRR@lBVg z>J?UJS2Ax%d_tiP0_cNSX%4X1L~|$FA6ykoEP_Z_!XXAuPmXqXwwC5+2qZo|%RW>K zL@*<~exG-2aB#f8ufM&mtF67ey|cHwufM0aucOmDFv=cQi}TBCi|p_Qw+3W$ypwK68nguQ}4$3%Z@e3EVJ-?@A5Pyh7Kzx1UqfBMs6a`5v% z|MNf7t_l`!@N2*J+0TFeD_{NUcfa?2;SF$BXD2cjZ-5M-CI{GbV1ABSH7>xwVeFrQ z$ws}ax?QomHV(oH(2VtRLR)IT~)6utWIctEtH+OWXzjy_(eyI{H00s#fju7j-@qjOrm%-O<@B!QS8cI&1u zW^Hw?TTzQ_0J|vaW877=FVy%!jL#)uijbU)V+)-qie0zvST)faEXC-Q1)Ccsaw;gc z{FL?8bOR~esRRxuUe>e~Xxi!#-AgXu4MiZF3dZ1d#!`()&7uY60c^xz5^|9JJ1$D zQ2)Rb1}7q-$K#}+{)R6uBBaa9C`roELPY+zwjvU=sDq8lXvet_w*^<70iXcZL0cl_ zy41>Q0dA0^>hBakDqb^S4IBr=1J(s1m*?Tjvyi0o@RdJ$6^vbl6az}-FD`-?@qnZl zzro9k@YQAX>IzeKqy5*?MCT~tz024@&WpNPAV0r0*0x_q&xqDoGDPNlKmhoKL`OPm~aT$Mf?P!B$;rF_Q<)`O;)?fBg9BUyHTUhLd1J`i1(3a95 z7TR)By+yHYFC4!j6Rinjn^;ZUIVV=Ui@UWAImJ1>B* zD2bTx>>Nih3J8RVx_&rR4<)dOa67_*xGHF9L|of2HH0_Nor~ec+3}AM2cR&EHxLn8 z-i0_7${5J(rQfu~xx_u?EF3wJfb`+x)9~?e!{=Mk;1L`GW8hM#1Iy|_ z5f<>D{sq(rV+@;%^GG}pz2uk_vO1Je#8|pKk6fOHxXQ>+r4G#CG0md3@dn{q4Gyw1 z)-OsfiNTDF79k~g#6=(;Kaa&uqS1p$=qMK1kA>GFfrEJDBrbGE;NpUBjR71~4Y-n) ziMc)LPuFBcO_DApah}TQ*=G!9H<>w>Z`Pg`Xi%0&@qr>8W8=m$#X{pUJ+g7M!fJLV76vj`2p$)E6(BI<0YEJ`I@E;gEg1F;SBE+e#9-jNlW&<9=N*;qkec&3!?qF5 zLwN)24bF&Z0B1yQPR8*+RiQMM}Qu(lul)XjB2Og^~3xIddHao1Es-^{eKL4QXwV>juRZ z+P&q{ZC4HWm2z%@$pW!&!on76wk{D#Sn8IPZoI@vCrSKay~R1>9K7O^M&^+loy>^? z321!NrFUPveD}o*O&nZLuefwQ^Xs3XN{kjhL*@HXAcxC5|IDro!l#5diq|nX;GwuslG#M-eP02iC?48}o}Rlb9R~ zk5*LH{NI25*Qn+{^SRIc`mg^wCI=q_-r!e%^;bXp+0TCED_{Bcx4$#W)?#x@uqB2! zkgXVZWGhBY4p1UsDsL3%fOilye!imK1uu&-7nm$ypCw6vuz|OV;svgLsHE`9!o?il zewPcf8QAOSp!H9U?_@=Pa&WQ2WRS91EL3MLnT042e8*x+A+{RSDj@-Q73UhD$_rZT zff_uEHw{UoEQd@G0z@b;HG2ln$}OURR`#1?D~2ahnE|J2nXLB7R%sS`wat|if9frA zyGbU4^QV2FKv?T(tC&SkZ5vUW13}+{%{3*|!D0^WBr*TSI$D~})vyV*lw}kx>$0O7 z7U4ltGNrF#i3tJef^RH$$)!<&0{}G>%-uXx9XXL4Hh!nwuN>YG? zpJpr+jD<0_#GKc}g*G+hxd{|WC0z|-*UEw+1~|OgU*~ZjuGnjEi59bxww^iupaygS zIybocFvpJK_{M|lC0xsfH270a2I#%w*QvlO@+4g{>SjirfKVC6nmABIWB*!;QMdvk zh@qc5H7OoGi%0wz{tA1*Eev>In{1EHWQdFnt1df*iSR7n0#9*&fTk;x#-x6sZnQ4C zDu*1nLX*pvO8t{ee>npX1Fgdt0O*eV@x9ad&PjaxB(`%J-#d>V`eR3d*l{R&5{aHf zBZtw@K_svj@$X0dhq2%(uK=ik_kcanK4qj~X>Ym`>B1!Q6o4Ku9|(L-!i0$g(g{U5 zCbs!0TdoJA{z%*(xjdsXlCI98&-}4xL7@>u#SBqcYe83nJ*F`NjPz!0^RsxH!iY6^)JJCDasW3e+x0}y{W zPN+NoY4rRca<&ybSPLGmgpQYjCkvs|mGC)`93_7E*%h%4Ff}pghLI+`!G-V!$AK7q zC!~Qg2JizWg}KTwi(VavE{=myXavq%CI>oDX(C>VAx#&{_|feniRZ~94BtXW(3U(eBz7JR>_r1Rk-%2)WG!^I9y;3!`w#G0 zh+~`rYoInO6wdd>+nt{AK}S#v@@u{(-juhaXXU_zRYz}yJv010q0z-AOpK97<&W8o_T}|QyX2d1AbljSD;hMRR<|cB{iko=$ua+ z2n0(>A3}-DE!K?|I+l2_P7vLZpaldv^@4oxOop_@2=j%S*xsij{y4QW9 zeJ?|WS%T?;`GlzhV>xCY#aWiCDW5aa3*WxXgro>NI0sITkM?)B*)nZ%Y#j1nge}F# zW=6-R2ZsqG&pzW22)>@4-d-FO*wk-&hCuY}2(Yw{$1{=ii1CiuIBOmAH)||kyi8X7 zj|qo~g1N<*9GEBvtcLhQ5T?GnyN}?3fAVL4_WQs8`=9>wr!hJBS?3LY@fSY|1PxBhXIjTq;7UHs`SWdZ9xt_n&Wz_bwWP2!D4INrCY?aU0)aJIDA)=mt;B+o32LRuDr2$J1`Er|s4Ti! z*3GdjMv^QK;#*dH72Z^S6I?7JcT!SZY&!^lI6%tcMPihiWd2M!X)R$8^up2Gzt({T zv_*h)W2hwbq_>!RU9~cZ&;9FuI*U3hW=c}|%B4`V@UN3C0f$ps#{H)h;!?(?JmUJF zPW}|dD|3sx9OoFRkDRRa1SZ1A5J88{<X>9*GCVMi)qBDr^H`Ma1q#NI90a zO7!>zT!0V<63U4vNd9o(Jme>xhR;tUNXLP*SkNC2oW;W-CnD&FE7?<& zzkpv!5q?E$8weA%`^XD2Ka7G?NJ5h8{iWSArY#g2Ed^+5^G5Q)jUEVw{0f_!LH1}tW^o(;GRzrpefHZY@C zJ4GDK$s7aFMK2D|BfF=O&7rT+>Naq#5Rv(+h>vOv*6mv$=cb;YT#%& zaIhHIU-0iO2M;&Hrw4pO)Sn%f)Nq0d$b)3w6R@o6b!jE0K7bhDmx+RtBBj50fdqoY z3+lYMdVy&H%IKYw;DJB3AGp{)kMH;|_5zoOq05u7=&5Cvph>}22Lw&kT|%(IBg_l? zgIGqJ&~}))!q_jC}$$tY18vfRBhEnjBvw`%hgcd5XA|2`Lc{(zYf(B#7Ja z2I?^({jTu|foz~0;1W=WCyKCSb=CzPN;_z4*qx&H(o-Nx9)VF7zK5*(gov&iXQ=x{x-x9s1Y_wUX6_vQiz^TDI# z@EMSNFCHdzfW;daD5tyuJU}RRbsUHug)aQj%RuZ3!Y6bgb|ayS=fMkJM=V&5f|rN> zCcb1d$+i~%+vQv(h}COU|#+(J3X*z97&pL#5J@d(`vS+YR^ zIgcYh$yAKd#WCfZLb#Vo@~lHOVW2oHQOUy@HooQ(qLC5W+4n}s1dZy$dzcTCug@f! z7g>eY27_NoYYT6n8f1Q-iEf|eH}1cPoy4Pj=uBFxq0_a{$y)G~c7-=!ILXL5UH{bR;y|inpW9xIzu}m8lp4t%k)G6%spV$<#-~kVi_8`AW2kn8%p8!b}&` zTp$C%D}# z@kcI-8?Tr4?z=Cqr5m%|aPq^{L zSqFmn9$Ao~iqoje%31T&e^rhSdGaDZ0xGG?=kI(+n%KF^m^5oRa;LvDUMfG3()nEO= zSHAL@&-^wf2S59~!7suaeC9Ks`GY_F!*71`?+GTUehQctBzOa3av(km2ZzWc%)Ks| zM2syRTx?-s8*ehH%GNmoLM_CaICwqO;~*DH;1p0S$vLm(>%1+GP;4bqqDdm&+@czm z)ykFl(=(3KLmJ$^-R>7U$nGqs*ErCQBeRuFFWH@* z0#p+t!Jq?f;YOZLbD3i)#9cTaJ9!jsAqo4##8-)(1f$1+h^FXCAj+R-LC6F&u&Ca& zg{7V;kAC%^j7$mVBq5-gzL2EWr$f7I{^LW8ru+v&6x}Tk@)qh z$)(ahiTAQ!oHHurio)(q!q1z7_P z1CU1swyL@au_anvvA%vGruA1ZNs+4;q0481i%T^1o98D>$9sV8+4JqO(~YU~ty%xh zO7LJie0oS|@-Sf=@$@;~*<)LxE!mTZXtV@w-8&%G5Ml9Q519Wg%2c2YVM!3eMMM`& zA5EXJmKIdm@ug?EvU?V3REJjZ9V{EW}7&th;*f_de*t@J6iujf< zCbuqUcQ2O?E>=#Wt7pNvaT=f8 zjSOr=<{>W5E_Ti@4g>KMKS0S(WS+I<`R>lHmX7 z_K|Hptq7>c`0n8X;6$255uXyb)(Yc87+Vbpye*M}fbs_?XHY;;2Y?G+#2T5_mJMub zAPQe_nTZj?k40ePodsGD|~Th}gzGh)j#ix`S0}hy%zc#*Wm7`~nOmfw!nu z1U+&ryng|E5Iu=uPJ&TMSfEorACN4J0pk|F2!nb#I71x+NVm{B zJC5!IS+D&%|lO)Y{nvppi2jl#}EbFOTu743~r?y*s61` zGO8&J0)q$fCzq%grE-^$14m?s<&s)~tT|)EayWtgLk2YwswEh;3DHAVij@(Fp&i;2 ziJuwbc0_BAbqqYG%T)MR^}PshSBT^~CzwlIeGakrj6fz=cq5%(#E#>Uy=ZVN;@=3J ztp-k3f~T9|z>!)@A!b@)ymX&fgT!SzLNjQzjfU8aM5zGhX(*~KJc`7#5@Q1rO-&8` zL0XRs;=fD_kW*^QIG{Ez5Jb%(HyFt({W1Y7f)D}(3YXm&FR=O8JMwQIoNXPPZSJ3~ zY@aM{9L=pA&Xd-U7B`NUHjc12V2eiLAuwq(fiujk8OimaRL$(G5hz!kdmY?o&bV)M zE;;#~GtTWP2Tq1$ta=?tzI>U4XOl9x3X$_Ek8syBIp=kNeA}5U#d< zcTcSYFK(xsU(G4`BOKgRnbenkjbd5&QWI>|^^?hGZs{`XxpKR0p^~Jif!v?`Jx4@GL7prDBo!;MxX-;kcbz99cYeS$?RR^WcRe~UA6%- zJDnYfKfVM`M^ZO}jUZn$sX|sTCpf%;OgQKxn2=@DJ^cDL!~rb&(kg%&b$oYE?~mWP z^Cy4uXaC!mzJ$ra$ACBZUz9iaKmOn=fA@FaRNjDy4s7;r@djo`cr`gdxWL-bh=o?f z7zY3fMzg`7jl>1jrXpqg%r)@)6T@ET>9-u1gFj)^N9g5lh6?lQECl2;oGt8R%-NZD93Ha9hQm1V&bI{aVHB z+uc{~8;zK43ESqRWJ`Xoea5t&T(xhP4_PcZ#dKE8EbSy{LfgR}A<{UBrgLuRz$x62 z6{dNGCNhxu1Mo80%=^-G=)w?1RAy$CPX#i_;n?4v69YLAJvgsD6JUt^*b8zq5Y)f(|wg+n2 z3urh&%tlpr#AY!E`}_M6+m=mlS!d7CkBcKbRdTEj>`xLO0a@Hxa~a9{DajX2{l!Tk zdbxEN*glRgA6!-sM;^C@a(koIW3krRm~SmQu@{;=JR3dOYg?P^*qv+K9{=8K)wgHL zi#GbYkLD-NHdjN3C?koXhk}rK2JN=%LGs!16rGnYK}4cJeEtII?&W*$z5D+AFW>v; z=P%!nKYurP@!~jqwQ&-i+3_zNM#py|tqXyU<bx&4S?Jw{=sY?R5b4`qtX&#`5AS+6|&J zv+E8!@~kW^vla2=6oHx+2{6RnbF)(;g98J@W0MQ3n`|hIUA1Burdb_J2E$?@DdGxv zhe*XdWrMwWunGjWp}t1Z!n6ab74Zo?Ez_WgI{G18V&kE_0oV!a%DMT4kGST#MKnEVI+lhJ-jk ziqPE{5gjmTAP*BV{Vu%0bMPR2fPwk(Mf4;dIf_S!1hCI9fdMe~4@dR_;oY;)&cXTW zo_}*MxVL?_wui$)=m-lLY)jZ!K_Xg+mo%=#mYFo)0>%S;0%zek79)ok6$CGjLYMUE zapak#@Ux@P)j{xbKOnrpQ81>w0S+MYd5WPmjUx>uOE&GzF|~b$`dj_4X*!ybOJ-(f zZ4n9K5_UxbZXCxVL^e2#hDlq2^ZiI@KN?;OpYO#&=T`*cAT**eZxgQpa5Uuuz`?CR zR5?cLttY|b;8u?LRVRIT19&;ussm6hQKr#_gXlGb@I@R0`1w!Mx<5!3aE$`Ym( z0Yj++1Yl6JJPVkNKZ0-$au;CVzj1vNOlEC*ZY?pl7Ef~mN-Vh)pIw|=WTMLT2k*_}EJ=PX zdFZ4}sr%=iO%vIn-R-+S5V0UvCa^AA^*O3wJ5G2aAg;ol+7e zpA3yZ^j*W$r{d)h?#>77C7W6z(Sz-$RpdZ-FlayaNI+;Y8NYpjY0g|@Jz@5UJL)-F z@qDeIN@oIY-@7Tc$(+Rk7=gKpW)ZVKd`7nH>v1~gyVSEdc~~!vdFW*2V#B&aTd35n zV`>BN#B8J70)plqd;^`TkU;y+R1QYQI;C=O=Z{f2_>JHAnVGXs_ta8OU{p&fyceB zbFd{q!S>UE-&}@JqA<9h`QynzODHo`Y+)78oWV8Qy;|@JL4+!TlEbeMWC+*`$CVH~ zerg8wOsJRgs<8C%-EdrI&jHU_mw?`jn9A=?o0{xisEzIZ$V2Y8sfEhy!(F2_3eRo=0wqCcY`9 zbEuwY8*WpQwGKJp#-`hCH6^7pBX@=98{p+WwY-&F+UcFzzuLC_YVGzbbvth~?R>pq z`&`>*&3LvWwNw@#Iy=_#>O|d(6Wlt1m_?YvzZ>ftK5=7+jzYj>^F{ zrt<5m$QTrwv#bejfx^O>)dr9V!3opgy$?Qk_x%r^zWc%6)Av?(o(|0Ibj@rv$2aOG z)~m+WA4a%tJc@2M$2KPywlQJIEUxnQ1I>+9_o`}}J3G7kv0=o|690F1G*#ZKD7$l~ zy!>`mZBy^i=-61KqxxQ3KW7fbV$sotd-a`N!z8v;)jhmlTUFEWxV>j^u(z$grt*G$ zLvu?j=SB~W4iEG++`IemQA1Np^P`#vtt0VSbS0r+c0q!UZ}1NE7_Y{f0Or9Av!=GL zs=E4NRn^0)>i&U2WW>Tt1|GExZlZD`JO$Dbm58*|f1J+&rvYk*k2e~bNF-+GvCUqA z`GaI!!upN9r|Y{)ztw-onA&{Qh2M50(F&)YkTFc58ZNJ-)n= zTv{ij@OY5j-`qOb+kJ9~vcZukZ9tqC;34dr$^jM@3)x-x0}HY-If7llmtEP>b!qzv ziQ*e<94_EyZ;w6Q_y$I7JJx~v>d6!18;H|Fj{zGE-U^o5hQ&VRc5_HpJC9PX8Ftrj zzPG!xyt6&Oxq-vJRUHGdw;|V^N4sc85VR2=n4}&)3VtCl9FVmvaqR423-HMR>{*$c zpcNo%0$2xtbgp?#)S}DiW(iu!d)4A@Dmglh~UGiyK+H#5lAN$=t=U3 zcQ3^lm6Zze5rCMNbn(hv2hyNC|*^0<0Ex zJ{>rV?Q={x{qa-F*GN#XDvaf*Rre!?;~IQSv5sK#t|#Dk2-*@sIyRcH3MDgOW>zBI z;Ft#kwL2KT4qsUSa{+SNg>a(9!;hR0XGYsPY)HY^DS~lIfLm^73VR-7SXV_wb4zC{ zh{MSO$ifPdKwwdG!BWti)K6AeXJ+WE*C|safPVuILRv#4-X)Rhcm$~mMtRcJ)Ts*7 z?1RV!@N$4ep3VJ*zkl%yU-);Q{p>G%Quqcx{p-K}KY#Iye-7UOwTf6Gq;Ft+1GFXK z8{pXh=!dx+Uy4u92(j&z9kwty;0cA}=ro8lr_sk1`WC$A;I@r1;cEkfj)sJc3QGI~4D6AvBv1C*`4U^VVhXlW|@UY)+X8t-*hFGP9ocYgTGr zXllT|P;mMKF76%qO*$E9kC9Sx#Drfp#1?orUBbL&4y7Pu88|rAi{NQZ&J`_i^gJFU ze9!G(Et>L-G-WX11#!qJ+8_xgYms#|V9J33w=1_xTMol~+1Y9~8n5yQ;Yi(#LpwYG5?_pnbSIl6crYnCyDAo}AoH3>`#TjwU;g zW=D_qb}(!Zw}GC=$AYP(vYWg|!`o%8A9pk=euQq5ZE_Z`Vf- zYa@Fv*RNmcS#6wJd_B_k-v=N3-vhV4*mv=dd(ZxH@0l+ST>O7W%f2>QbvNCe+F4uK z-x8=a$EPfzkUiR`+*V}^G7|@!#(F~4;vBs9{(J9#fWE<#ci!K7@@{tTZFCGerZyWV z*K5YIm7{A9MzXLDY9}_DV;g-ln^TMEmahS{r{eK}?za1P?_9ff<5u~D#@6nhu8ztp z=gO*Ex_kTj`+A!0U%!68zO!$j^+8#EV{^}7Br-D4_@K6?vKgOCZFM#GZ&h^mMIxi4 zgWc_QH*VIp4vdVB;^ldG7`8$4r3>e;-MM?O@?pi*>$e*F#%D6i%zy0FImsSEQEJkx za;9&9+luAoiRk2m%7^#vKj7?X1k)fyV;cykgO$K~z%?QE5Co=YSYcRRP{_nnbYy&D zjNLyDF9^Go)#Y_Oy&Q0!1snq$I}k_tpJgx&nJl(!G%VUEImD-?Cu3+_ zz&C)Yl!k1uBNcFQfaNT*XAM7q3?!z=7%pdM$4)*5uchh@2v%A|f z+gnqcn~C*oJiC!xTc6q7%gSzyWf;0u=<*%IM~HwW1*ThAG*CI%I5#ZL+ zaSYZmxY&P+odTQ$F%949Tc-G@TnE0Eg%g@zr*|Vni%Uu_O+TB~&Q@SP4ZA=26NhDSgz3N7wL&v~g2Vf0x3s_N+>u?_! zg4lTohSwh47Y^jaJInUQ9F`xO+05qpGRzg+2GIu9#hB7Z6t97z+>7(>#|145@D}`_ zMM*3U7c{W#!CZrVrUCMIYql{ptRj`8s)gV*LITzS&NEpCp&Z~3EUs>5me=PN3EBDO zb&gR$I}8>ad6+>Iz=JA8DhD4=2nMYy_B(QATAd7^wVFLwC<&jRr37PEy3zQ2S6ix1 zZX{nk80R+d7_wdvo#p~`qk`>6$6Z+;yx>3OKkgT(VOg>e*7IBl0e0pFL5RQw&$Qf! z8xD-Hu=oKA6S6ZG99Y&}K^0pHysHB;q__yzd}I+S1OncI1NFyWb0|a2@SCKnt@faz zAmXwG1+oqK0qz0oq+K0a@sNx89Cm6~W}qZ|5e__}rxer)xfiz{6W7u2Nk1Z-wa0PB zQei@u46Gavs~n8SIH<6ryZ7d;+yDEY{Mo<$*T40>&NujhANYYE{$cbDe)?B`_1FLG z&%W5*)6b!kx$_i!eFNtm5q$%vY6v$#xYA$?+jL%VsLjwi6b^JF)CGcLwnm9f1({9d zUL#rD12@jSX(ehozchaOv&KW>#x!sZFouBRIS48m%J53?$`M1rjDJn^42y}<)a+2p zgPh2`)L_$?#WNmWwF!Vq{Nv#(FL0MfBI4<#_3f3-9jOEx>%ddT4N?25$mnE7lrX-= ztv7L)o*L?!m^L_Voa?Tf59`Db6y(sJ!vC$pu=G5VUZsc!YO{a{|jktOF0W2crdAF^9`E8r?_dQ|=v58f&Z#GZBY;Zijh+ zDinp=Lq6!l%wp^CbjQT}cxG!ngE{l=Xl8dHwcRtb*%Dc(?~8Yj0)?{foMpx{=ceTRZ5N&MLqI?5ckjzW-g5;Dc#RE_l_6$+7Q6uLL@72q3~Q83Jb|Ef%iQr zgY`hk4BmsTi`>;UFWiB}DW~QPXDC^CI77+0o-c#*Vy%xJ^s0>krHfvb$jRbP;z0ae zOR=knsNw+LQGl-F@Ft(SGu7*yw`v}L_bDZZGuT~?XXA{)H$aCRWVgKiG`e^+x%4!# z`rgFS+vAH*CRU#GWws`=E4Pw8UyeNZ>mlLpKkPm8hrMt9N&mUO8ou`T;}tijTE-Wr z5_5@YVxp(z-kCSfymj{6*|V>`{??`251Tvt2m1Otn;R<1Tl&Yqx}yV4x6VIm?Hn5F zZ>_jge&=>mTX!Tf*z%~MzP@{U9_b{a(>)eyn{@VBwIoWrkLdu!aDqJ1*lxn2{Ihqo zy174{S)W}#h-MCll7}6!!}`d<)y|z)>a%72E3Gq&HzxE`}|a6WFwv0SzSBW**-)aPMmEPJ=heGTbiwQHFhEf9rEMnbyPG;a99lMuRC*4MMP^=R3Qlru;88>-JOn-IqqgwlCS1GSx*eXa;nz*aldy1C^j7Fkpvuu$?*DUpU&EKiZo++DjkqrVe+K z2RqaI+f%z+iJi^F*80>2{soce%O?Swz!Rn$yaGVnyBM3i=b<^K0}HQA6*!ng3qB)oWW#p zCY1|i3qO(02z)2fyI}FLO>u01(G{U53n#?yMhvmewu{NZy}BJ+F9@x*21D^ z)jU_1kVp^=p$IQa8feJEi3NowJos!(gWQ{jIxw85c*#n0iTV5oEB2&Uc09?@HTWXA zdRdbTf{ADaIfIVXR|wwMLt#F1Bb;s=hAuzwEz8w-M^#&HbX znn1Dc_+tm(sEA-IQjTvRLey^zw|Imq7%hU32IqtPR+mYKolkGPZSNhTl)kvRk1J+7 zF5&UxFSqP0oEb3%>vxe7>g_(GyucN81=21;;{iBAi(O7a8uUQK^)5`pu zOM z-Li{kE?&BH<;s<7*O~?pUQ_oato=&5O!Sc|IP${A`1j!9`7B&M9U8u7P zp)lmdflSXOrl&d7rMkB6)}6aIZkNAy`Bu&2&dGRUA(LKP%IsvO4rYcAx7W>1L3{(q zA!Jf~M;u}CxJ;zsBJtUD+!Y^(*K%(Zz+USR8-zl&x!^LC$mWAwhjw)hp7L+`C^&$_ zL>%%hPVo@20ba#jq!=%UGZ4>Z@JYURb@s79vE6lmngRJ!Q7z+n zeS2>n4fCBR>Fm?g`a7xhcV`vena&#_GO4QT;;XuHo)W|9SX& zS+ad-C6QQ3;i)T;j1TwJmEF8@{`#GYvMXm_d-YOPOYguy-(Y`xec8z>sJeXa`W>)uRmiBw6_G*TAEBbbBc5UA6UvHUQ>rF3p&7~fvV)vuH_mh3Mr#t>? z@cREVa`W3Q0^q7hcw>8vO*3{KEHZ?W3acK0|NKZ%OgZuaIR#w+OYHaHoo?eiXeN+bk%s%F# z_duY)Nj46egkm`XO#?VHLg=2BwcgRmksX*a2rLAoFJdYOtk`T!csZD!PNH&u+~I8cY0hO%rr1+p6wuEUPH^Q&bzxyCYJ7uOg4H|h;$RW4 zdoZ+tc;t62F`&a6(9&(Z931S-8S5Zptb^3i?(ES{@^EM7U>oki%-&XVXLELYYY9*e z)oF_#8Y9Lxc=tVc2gd)=+QKm7_#1e_E1UaxHdxt`wFNF3)^>C}1cA+c8K(!E9Quhz zTsh)k%MN;#GBw!^m(g0{rY>)2(b8$ZaD51jpx?ra2^|>0Pedsu@uxA2E*s|tX?+Ce z`t6vju(QE-`MF`7(m@0&4IsI(-Mr2>?oi629FIgFk2;?(8B zNttPtH7u8>s77rc*1fr_I>#od*BjI%*seqdisGtT{(huJM885mVl1n}BIsrfbGn6x zyhrlOcRhdXwRDI0z2sr@V6n}$*)3?U#^57*Ki#{SWSLJU)&a+T?j16Fp$4IV2}D>P z$}R1j>S8XHO#6^crQeXI>c1V5e1sCV_y zUkI<|U|Im0auK0a?-82|HX}?{=mWP9O3jC9VKgUAvRL^Bj-o zddU>&-DJe)8tUqB+;E3vqw4>U5W;0XV;npcs=crQ(9ar^QUW(_27Fl5?Csb% zNg++z2o&)}ijp((QzA$)6Et-BSfLM8sD$7#0YXX$9*@FOa-0*#LIG$9%ZCHy>!)qs zIW367QQ?g%e~dlTkO&WI|KeZ#3)46F;h+4;pZw)t{nbDCqd(%nh!gb< zmgyFV1pzmqb%#WZ9)kiASt!boTMSx8ChG}bAHTXtN{AqFMra-k63X$^+NDS-)`1>( zhd_E(^W`AMoxvkvgBo8@3 z{qpI}Ax*o7nbl3`!>srQN2oi(C6MKU7jQWCgmlPD@?_SwHgNyt^9_P}jSAIlWu;=e z$x~Hk9$P;oGz>QTGkU-@{g`EdeH>_mj{)h~>>A$2GRd*F`l`zpZ`U?7H8eKX)HL-B zjnRQ7#F?F*C8TCjDZ9>b@OD~qdB;`2-`*m6su^sMGw6uokvoOWF_~v(Qz)Zi#7ZG9 zKqXF1bN)zdd}0EBTw}4Bne^iPGS&oAJTO~{bu~r@o{oSUy1V-ahR37v=|mzCo17f# z9YH!a(Am@4*xK1U5}UyRDNGD(CppY$WnnJ*sH*IZbC=M{#r$_*aBzU^(eb{X*6Pag ztJiPdD7)LxiK26SsJpqTqqlc7o|xh!l*!SdF4UqKh(s#OuD|u#YnN``Z5fW^mJPdU zcp8v-e02Xq=b*0jzxyc|;QW-IF*$%U_=C0iqj=BJ_Qny^ z5hM`;tnKZ|SnTGlvTN6GT)A@f8Y(t~&iFX!&&*RL++`967mai*<7)zi@Tu=N)LVp z(8=W~eRayHz9y~Iq5U$w$mtmnWSg<7ca>b*p7kS=bRVBVs@Fvslt@c-OF+poFb)~s zjA!iMQHABmJXi;WwVkJ{X4Wn5@mo7H8`+7q`M$-ens|R*dg#Gy?|&UB`!B;c@1=YC zR^!q2bZUJ8#F);cVq-lGRb>}%HT3lLcDB}CK6Ca?L+9XVq_4H&YDG;`XHRcy^_^>H z%PQ{o3=a==G&J42*&zrVi$_Nv-ED?%uqNMQ3{g8-%=*nJZ2<~KE(6$s1vk2gqs49Q z-{;Wt`PJ?Dwf*GMetdp!Vs39NwKJC98q2JY&996uEDSEp)=dmFB}ZE3A}@_q-b?lL zt|TTlGO1lygxfn$4iI27HDO9H@2SY@HQ*+CUJ@t>l7*F31S@0^`Dc^>wX>m^0@5DG zK_(YBuw9C#SErV?`;(jL?Eb>W!Rq!Qhee9`hpbv#iVpU*)Ya8gS3i7M-_q6>8K0bt zMqvo_Jg%>QRNvJ6xMz4g9>?(mE9_`@XM1~F2O0%~eIwDRTn{HEfYvGe8P2m<&&{Qh zQ}M}(3D)At7$nE^^z;%jVr)7u0)fnw z?mc?K_h8u58}_*1wpIh{C7#7x9j``_$T*uql2vI2b})`Emop11^5?LyGPkgd=L-1$ z1URS=lT_ocfyTZ-OMiQZO_l~L#HVDcAkHuzs$mGjonACmDO);C6pp@t;X-T<&=7%H z%7Ga3`&+5~t=avpBmrK*-sa4%LQ)R#wiZx-gW8oEi%RgMz`P5=W|kHx7Wo5MC30WG z@sXHX!1sWSz_&YOe-8pbH}?+7W~MZ`6~ik>Yo zZa8_@5V2vnRgl>Yd-u2x0COliNb!mdl^Jjhf;@`&pIAGQIx|@6OGm6328sjy2gB@o z{P;8(iJ=7YXXG134h^Y0!l>%I>dA=cBaQp0M1MbkzoSPh0xXOYANgHh2Sd`MszM)juYZa zKIQ7wTe@n>52`M#%O44T%RS5JQ>qI!Pp~}*xn>;Ol28L&U*#Tu_DYL$=GqW6#{V38 zcT)vt%VX#=4vpZ~Rr<+xybH2Oh-Wr(B1oz{2W56V0prBxh=-%|7QJA}(&|?fg1Z)B z%~S~Hub`O=c@s96xuqlFHSqXF?1c60)LR}iHn+NJwR9+tez4vU+9d+cr2|o)W{dPy z4&);-8cU#bJuo!V($;b2?1fJZ-{6;i`Imq15B{K|yJvK40y+hcM(7wgr-)pgz5ynR z#y5}@$wy%V-4@i1V6lK{00$L92Nm=+8M^MVY)&Q9A~}|@d0$yr;z;5(;w+@LSRLxP zMizPd90m!E3xUF+)=9Wed=Y&VZM5xBnVXWMWOugLWGP>+U4wf#vO-2E+&SV5ORkM6Va&L7NH@qw3M8{ zFV>A$->7Kq8I-YX{~$wdBr-NM&|6=1=jB(v{_@vfJzrMU*fSi7C&otyx?1qP6^X$G zNKOwlR<$%X_C}`@lac<``{i|wbyb(H+D^~*Q!Rd2E5(^6FP!`TCi%%KDC;?g8GS zx4omSq3Lm3M@M5#`B%Pnt){IX>bvavovUT_17j0|13h)uzkadmac5W4`7^JcxpJeW zudl7C=GI$h+oCD#rft9&-$1jtgkajybTMeiCuM1E&bTi0G-N zmNt6FQ+0jQ9dR_1w~;NvG-!#gHjHE*c1~P-&~od>^`W6bsQPqrYGrYLb3KbqC71*9 zMoUTvID^M2nOPv=@6I0n?UQp0lT*poj;?FhZ{ECp`;E8Ge&wZ?+q$|ZVk{>~9F23l z!uDkE-e&e-d;M^4=Lj!PW;x1eF@1wI)KTs~sJwjTYI%A2WGrs-MCJkShXSVPbUv63rz`GYYzWMfDClY_A2EYR`5P{FWs>5x)2gue zJMRcFDHKOsdT20p+`?3vzae&FBjLg z7uI&u%R4iR+tUk#&FRJUnWgOX^2%5y^>}Q!Wn!>D6CYVkM%HF0VH#|&te_qRg$qn! zN($>y(Ni?044gVhW!wFer>OfQ`(|h7lzYs6Sg&wL&(FC9;bJiQ%-m9Jc7808j^Xee zCPsE=9*zBt9S&Y$yU~UPNcXJCmNGbsL}v^ZErAGJVoT9K_Qz2Z_OB8wjRPo_mN@es z1uB*&7|L0=#hm@NN)mrk8(3au7eLF411g+fJa%4KXZ*(TZ#@Ebe8RWeHurNR* znV1=jnD}7+eLjkFztXP*YRe%$qdkYyv)Lk>RY5t6W8) z$jW|db!i18(AE4V9gVDnkx5WW_=dt%Avl`}Ej3umz#?`=wNeW*0aQqf87q57hdW1y z+eZhRM+fju*ImH-!Qnmu_jd$rQ1D6Y4&77L>J57%w{~gqH}w@d3bJ{RU<`k`AqoX} z1wlG%wIgQS)}WQsrw`q$Ijrpx6?dd5I5ec$PIVR}{0#_rmuLiuJ>@^E6l5+TBwHNU zvp!RTG8IHo8~8QAuG)R%PDc=O73GL$OAl4#niOuNYi$U*2vG2WT<`_Z0a7;H>cqi; zh)@=np3$Wsb0E0f;y@FJM9fu@@JNXue@8A|1I(FEYOv*J#wQYnnPzT@q2(q4M@fi5 zb$o*)q0V44=K#u~Z{d0dstZPEN)N=C0D8gjTN4jHoQrsU<#QgqZ=^nVM5cc|=2P0^ z`f6Se`;aYPpzi^5N6;3uC+}xyTottQ)So&0n?uANlO(T-yt_Vt4PftwYCs-zRZ*wb zO9sE{Fxs{Fsc%}4A+PpuX+ag?NH~KZFDTG{`a(=7OcRo_fE0z?A`mX&*!Gm}+fcEt zt`B`JY@vFXA!j0T9fbq)N-6|4Q-D|OkFbSd7of@Pl$lY5W|o1~$iqiu0kPHF?W#Ez zr7gv7L4NjYh$z*TR64i~OIKqN7hR=qmJ4RK=8V@)x<20{@4tsDBnv7NI*q0p519^u zgRU!xPkfkN7%$jgr!ouh|JelXY=s%;AaMYd7gZ}3aM^eg|%|Mq+B z9o?gmC{B&0OY;pDoxTC1PFt8m=-$->=^Bt)9G-yiuzA-YgqGM4yA=TiBnP<9V{PH? za%WGRgyj_mFvFNB7Sb6I^maS}>avNMTY-%R@EL}t)xcL10pJ_38-5q-z*retuh=!v z@D{;h8-W@Rf#I_b#5XW~1Na7b$(vi-L$tK9cLa+7Mgb?Ga|XIQ65a6)&^MS{KS-}^ zACU{Z_Pf=tpM|3b?_MsWw?acq1XqR|;C z%%x_=`daRvfAQ~M_|oeaZ{4qJY3m;7Zm)lE>+IjXd>tQKIM8mcIQRPbtCy?0hlaXa zs;`_!Wf*0V=tM{5jp{o$T878R#|FFWufBTe@`J}+gX5Fqqdj$%WiP#Qsjho?I5HlI zpk_PT_VCt)SHJq=mHXATwGZ#S_S(7Hw!vvxD`aKwu)MUGo*KGw?$U!t$j(ME&~0yc zSoZo$w;pv4^tIo7?bX|5RqcIak)eUkriL>YyW>gtLUQB?={rB4o}P~3^sBw8^74yc z{?ZFyI(O?{V^@E7H&)Vh73Ftt-MaR|3+L`sxAqJSKYnnx?9BPHrk?JO>K9+RRMXbe z-hBVu8!x~3%Inwf+`e)9*7>V9T1FBnS|&!*AuDzOnLUazC%+cq2Tdhf3nU_M)t;`h zXg^z*xbiq70qy8tm`0 z$aZlEA_s{(IOAGg+ge=Rm|w}F0+3!>o>^Le`PDrc>54~27N(+WX+kWUNo_7K@2+of zzVR+c!eJ_fzjTb476H7BQjP(XRGcZzK>`YC?5mKF1A`al=QxOQc?D01*hL9!Ldi33 zcM%|mH0phNKr{wTg`sK)H~@W0XEHIh!3*${6UoeYEIBxy=oy~u92oBy80#7u?~6p? zT#UpMlj+&1rOeFQ;>`L|a(!_QpQG$8ETxb$QYyD%4gImex@qFjr7UsSP1p|hBpj!^ zaM&UONe)%kPz_pw=ZVJ^G^VnfD;wK5KY_1^%$j`x;Wf(zs!OcfaDVY1hi5w6-s?Cg zUY+A9_4*vMO0Wpb02l%=1{7R6SK|1-$7mhR08UxK97z^Q@FDpvg#pMj3$Ru!kjT~{ z50gQE<~U}Ic8>$#tJWLC#P|aNbHL*d&<`vaS}{U_-#||7R$_+e^TXvQxVBNRldBSO zVo-M_C;90{z`qfYPl@>J)dt!Mb{TjTOU#XI-t6AV3S&?ZHeZ`l84#CwuUk!->j9e#W z6TzGd&MugZScD&ML_p-hPY0YOWj3*_`o~FW5oDN9SOQ|S&CQ7xW68;veWdKX{`yxR zFGCRJ1%t^-aS{It(_TST6Rz`uV3^u3%Df7zeCT+zV&h&_Wy?pf4_ zydWCSLIL~?!!94Ehw<8paj&|9cB*;L6>`ul4>JlXdf+q%nVrnbUFq=r;OFzKaGBqZxZ0^I#5ZtzH{cy& zDL~VTa5&NN;r+b758i+OIl~7Zyk8VP$o+legAe@hjce&|BZDp+1o$-z0NoI{_p>RPyNsj{lriFkDvS8 zFaP`h@E_VcyCY+hF)Xo<=NqtlvZolekYhA~!a(8-a=<%%IKRkY&9Hniio`{pSjXA~ zA=1Jj%Z4Z=1jq^F8;H)N5Q_3kdmHWzgVYW3{MEH!v6a~ZJRdd8m0%)ZzZ{z;2Zu6s z7qy~|k6VGD*0PyqBPeqJ2);o&yPMgND`p%ob8HjAJNlU;oHmcqY|$is=~BybPvk3aKoL=WnZDacRsN;!CW9lpWX7*Zw(Owf8J zJv*Ig<+26~$w zokH{G)yt14G^Qm(SO9KiNqG&0c90^cAyjT{g6iJXp_U0Pb0O-{kbke9E){)W4+zk1=) zh5I$tD7wh0{Xh?*! zD;vA>+3m^nYWLV|O~+VyL*L!{o~owqdlmPtUb}Vu&97En{7Uu37h5VWPLB^RWs>Ww z%TW5pg`z4Cyd!ysZ-C|rtRx*Ep52Nh7i-%4uidV=c8vdPj7)*giir@(Yg<*sB3aT;$98I`GyBJz5-3(wY-3|-;V3wak#}pF&Qcl&UkQ~B^dXG}bmX~E-B7+CfaZCTLzZ}3poxDF4NLdT}$21vxzS5$$vHfEjn z4qat#4HMX5ZLQ&mY~Zrfuhv;*LxE==4kz;56@2jM+Maa=U`!J%pY3VmYoXisySfoCu4 zUYRcSuKe5`Z|1`IMg(#Zd*@mYXeTw?^f!^k=p zw?~cxR?HC>iZcYa!Vxc9>AF0q=pkrfmJ@@Iopbq5c*HUr$}aVq`R^ERupfW+Pxg#C z3%-JV==^4=ue^?OJrn#4Mg0Ev+gVubcQpODuJ{-md0Z9$wCSeyEcCqSOR5UT!%Z~VhEg@5>%|GxPT-z*H@45bh+{tG`+eD~xOn$KJF`g8(R zxZD2NGT1@rAZRc)CaE0Y<-qg};?wSAMz{x4(OBYppKtK}pZe6Ne*7nX;&Y$-+`sv^ z|Mqcv7kmS@drnYdqfgH*I#UJWvj~?miwqlRLXj~NUN{A51K^S(iFLp@#0J5UuWaSU zG}wXIgGC@BAsY_z;g5%Tb$hV zWN};9`Aswp4%1n}L26|SH(9%fI)@S629ym1X02Yjf*L`A(399H;Cm2XRXSoBVUnY- zjg3GYsvG2pKnlLW;?fdyI)u^!!ur?*rmhhjkoEUIIRE;&H_qOD)L3`(%`d-Jf#dCg zp`qTU+gGlfd+m11(8yqG)w!2%K6*SbGSc(t?v+>HI&-cGrT@wCftDLL>)TpKVu_iV zcw%CptNxW&zJ9m9YhZLjKG8=b{W$x+@zt+he%RVOz+vN~_q596NZ=P-H9*Ry3)!evOS>8B`P$`~>4s~3--ZwGDVOyqH0&Ty# zn2HZp*VI;3b2`}F%a<=)EU&C->ujwld-=sTE?&8M=+)6B&nTSn~M#eju9#vj_ zqwMv+eQ@@L=9{myRh*gVd%U_lzq7pwWeo_D+OV|&z5xT^;ORSCc=O&l7)z}@8csg! zojhAn|H4bJKB#%r-8Trw1|A5Ozbq+eD;xd-kge0>=m|3(U?mxMOGrVKA(9~MbUZv_ zaz0HI@j!SHU+x@$=#L&L!pNt>d;`(NY==O??svFvUl8OEM^3HfBW4KK6^a+P?U_@G zup7gGF&Pe~pRXZji5e&QcMH)U8480sO?~V0B3wMU`mHq`8#iE_nlX^pS$LV#A(?lX z{VZPJ2^+Y4-`&~R+eJptsf9c63c%gw6CeP^z(&Dpv*cyi0gyf98-m8*V*ZR53K!JD zUco@w8pzy^hihb?CD6 z74BbAKrdf%c1lq2dc)$zm!NF~yUWGm)@kax9Q@b%76dEAsr|DP=@BQ&SL6K_YWFlr zy74Hy_ceLCB+*hNpog)xmS-DTxw?SLC1j+e-VWNY+1WSZBe`Q?%oS@2X4EJbPq zhPDK(d=O!u$;V<8>w>Zc*wdh;Js40C9^?%2f1DAoUT+{BN4k(MxwGc13xS?PUIeiS zTjQjJO7N!PPAJ)=k~vT9pWvzg z-$Z~3xuKOG=hks|Kin-U$`xqyg|(421Udn}0Ys-ZGFxX@&&4jlM9w)~Uqc6PZD9#V zH?VuLzGbUKQybFbJ!2Y(1#mLTE_L@?-~8q?hi`rBoB82e-|0UZ&pUtP8~=dT1RcTt zEBe9kDLqLS!M+CG(rI}3k+lM@i|jtI0@gtsT^>1 zfeeUUXHsdA5D*ZKE^^S@SO@SEOzlwO4DE)90HmnqQ3XMSR`EEsi~h97MNXT|wbS6G zXiC82G`up1NhnN_ks{+omJ>Jjf=m@~R)ANo^x7V50XPO5dmQ)7$xUx>9k}pxZTD$< z<0viG!9jX;8@_=%Oo0+qHKln4s?A_rIxH58W9bUh0R8}AoIjAP`y=j{23+A1;C2tm z9gKvPh2%u%gG-k#oO$!j*IxPBYiBOs#XZ3|?z`a&Tzc)bufO!lD_?u_(v_;#!6@Vz z2FPtUFPwe#)vuqqe(O#}c}>~H*3lTgwG=KYI3CO`n9WP&z?Jb z?$-V4_OS$3`$O&37q4F7)Pt)xFliV|^IaJBNX=*p+P6#d$+6z{x(YlTR6MAx>K%#7 z<5hBMte=Cs#*!SSz)6wmnc?xd%o1i9PAhVc_gGmVZ=mrrKG541u!j7#xVa9IT|r8$3uy(Q!(iUfB$U^y$(Tob0qu9tUVJtK%Rxd)8HcM^U+)1%~6UgjsXWkLFg4kYQ z{Zs&VyQ@0`m#bN7nRT}tR!4%GAJnmQ};*Gn0@Ia+?g*r-$gVqPZ zaO(u?4S5f6A;)2$pKSzsS2v996Xc}_dB|@c<%#r2JeiafAZ#JxBio+q@@T(1p#A8f z;NoCB8iRF!HI_S7LEaIOKBQUXI3p7ElwCN$rf2A(cnQCtxX|-N1cpCh7UaEy?B2mz zDDZP*|8R337m7#tMwFWZA1nu`*=H1Z#p;XaLQXcF%WowFw1kVey9J5I{|v!!UzDs8 za`oog;Bg5;w|u^VxqlD5*+akw!MBf~$8tInOln4Qn04THg|)L#T3rf+7Nf{x0Am;% zI&?!y80HlJ3_tSS5D&MuR6M|90k#UKgyZhT!zn>Le9I*U*Py#d3F6;dkq_N+*9jlu zWlwnUgj-Z}!rc>Yxd%(O(>=xYgu5r)D*51XWd`X%Bq%vZ2_o)R@UtLt!d(^w77ErV zHd*!;HblWI`^g@M-(Xk=@{8!~_+TBZpuvdE!ZNEjv;^xvdk2;Wh~32&_)Y`)fBO1) zX&5GGTcCCU*~ZT6IN?E;vZvF5Fw!CQ9mjyJ5M)jG1n>=h@Kc}qu^<2OU-;bTKL0zv z+w!;_P=mff3BCc|`QaNtJU}$$fLo5DhJF@EM}Q0c_Vg**gW?{nfI)GxA*KO`Da@qi zCh?h%4}W?R7ylSM8WkbbuQDNiJttaFGL%L++;Y+oPVaKmlr$bp0L(x$zn;Yvx)I`v zY>w>YDI9-t>G7KR(U2!hEhf=}f*5Ufz zlZ*@##6ZBa!Pdc3&VZiVz)s;Hvwn!ntko?rp4>S)rh!l4i;QPxA=#m|(=!}$HH%KK zu?V>Ehn9i04P(v^cVU#kL=QF99DXc^VoPqrMe|8o?%|VVcvz$(7 zHpZOiC`)6^kY#k7;#@~8Kk$W(GwemMHcr3Ra88M?1l*^B$&@ZbPB^C;k`>&-X3v`6@45llGMJ~yO7)i+F z(T3LQ27|~`NX|hL!zPZ_)kqM462Z)%;uG*T!bApSL?N3LSOd&*@|jpU8AUirV^xH{ zg&!E@GHXAB z!EODdG|vGV@Y&&UOED34VEt{L(_DrPL+-SSIl}A6YMW)s(6p8vwEaD{hIq^LhJx`u z+=5^orL{{fUrc0TrZ##&)TKNh_MR+NY#SBpXr} z-haQOCF$u#qeUj7IipcCI1Lx;Hb>S7VE@EQ97K1ekLll^AI9K9wq~{!SjH%$-{^9cO;lj>gX8T}n z`yg$B$o$U1BJODR4zv45n|96-o@9(~FXZmA0w8@w{T2mF7gxdXwPaGuUw=@*B zl5=IclEc?Xw;<8|3>x#i zcTafmgj*$R`R++%n+qD_vkv4|h@}RoCDwt+hJ85UfCnHOT4d-LU>}SRBZPOH-G=S~ zBmuc8iVcG8!|5CR(mb@_$Edg?3fS(^eStiyi9#SnUoN z`ULO|KKMtX3T_y^EehEq>Ht%WSRQ~5 zq$$vij(#@G2!SUeKWLR2=A?mE0&-`brPYoy53;#De0L}Z_Tr`N_Wb(Z{KnDJ7UwBE z#l-<(bN}hCxkkiOBK{5LHx3sz4>Q@_6;ytqRAF)T<~F;jv*AlTU)o zLis6o+(Ppt%Ne%(Zv~Ppk>!ZJD03BK`4tste-5wX$S_w`{jxgcEN2U1*|HV8pTE-C3G+))Q27-oEBMw$X~ z z#ff3DX7OE1ag3b+UiohwD*rg_ocp+ZUwvZx%B&XtAaT0T8l{FYHAqbUp0jgj(}X!{ znACu_XALb7?fD>SQ)9mF>F$Jh5F*}cg6-q`vc@#y+~V)G!mEtUe=$c$!}_y!ih%Zzh_>H_A5 zyZwl#;V+aeWDUC43LxHsL-z*c^@xYu4ZnLO7=#bfLy3+fCsu&02CP6U(+mpW$mN)C zY%X$I&P4XyC%Q@PvF7ZS8Fg}Eg$q7Ejos5WBj>tvbqz`$Sqx-64uVmT!v_e$KWm#Y z17Q+MxyZO@^23nB2yA>IuoFhao!ww>kY0Y9|`VKeoJQ)6KP(im%pmaI z?8uNG?1OBFqAKOSSkxwQ#2KvlKpSMEC}>Zaf-ySAcnSWb@C|Mqx_&##n+7C6jd{KH>LpehAwNG46CK zO$h{OU12)Yt|TWj&fzbE|3VfLC99kuIO0}A9fBY7z>&nt-~p=~T`C&Jf`^YJ4OE#h zDVP+FE_DR3cNJ|c^#(X-5CEKk4mTjP#u?(<3-A!KJ6xBtJ4@?3i|gAQ?M=GE>ekxU zo?K@6XOyc4prEWYXe#&y%q%KJfDc5To}P(LPL7R@kBv`o!UE0`@p~{C;}3Tdcr2R- zARA^hmx);K(os+s95b|`!-mjhb?O!*dTzL!#7!{Avp)9yahch%m=7-97cWAk2pVrX z?t$<38@>g9;$uLf_!UW(2YNCLWzFCg5Z<7@%Vv!UvPp6TIF~-KH*191^$Ms@fUW#W zVQ9dh@Q)ZN0>S>AJ_cM5{h3OJFf~X@UcSXwkv~cPz}V;#xL}snyfRHP z*JMu7m%cJFD=%U&O6W-d%C3w-T4)L$+v;aEG8bT3Fy+PTKw$!Xh{XlM+VbN1+A40; zsR$yPPt3S7AaD4{AWn=eX4cmwHt);cirL~RaHM##X8LN(tl0q`B%gr4( zi?Hi(8p*5?VeV;1_~JY(SwmMNISjW$2wGFd-)o$HasZrtj*2z~(f>YhcKsm5bpcEk zIt5=sO_OZ4%G;aQPLaC`@r;4q3Q z3;;L2fwbjWF!!Fky?yj_ZT|^O1DFG&*}b0C-S(xO)}?Ji`_gvD@=o{4PXFreNOmv2 zc|bN;2U~|vrE;KC7fr;!&oRv`P&sa%TSMeK(V)6BjtKDeclfsM_hsy^~fa93WX(Wp$ua8=e+dl9@?guf4VUoirc7aZCvOGD2lp65b z;<9duP)E|Y>;flNV`z*sNhqvfxa$|?-I8Xt z7hL|lYaw_EP)vYp97?jE4(xbW(vQ1EA;;g6_N?6v%E?7^3nyIpbfbRiUHGQPI*r!S>d;^Tkq;i1Tu$^HH4Mu+U0k#0P2{w!HhLYQB3}QQ=ZPybw zs}Fm#v_Ho1rkNN2Fk3q8kz6pU1DeE`26BxE4M}eRP91H@PDz~Y07!*+6g30*25=AH z8xa3w@C|D(1dB=dX z;fHf(1|+`YQO4$qG?kyiZibHxA~_pOr&tb2Z@~$aJ@Vex97pFf$R)&A32rT7@T(<3 z$S3$+y5InFL=+EsJ&A2Vmg_Bi#3%m@B0>mn?^z&1fUt4F{lpW3sYgl=kR3`B(;+)+ zhI&A+e*|*`3=bv+aZ4qDv&!U#oG1xkVdV85LqK9?uwXg>i%X)==AqLTZRE=!SI!6KFwRBofY!>Yf^~qB zU71FgqH8UUYn8tN!6_EOA}8N1ucjAPa5Kq?@SIA|l8a#u2an?D9;f0Q7Ei!!1Kws> zmgR`X(?Ia)Nno`c+RJlzK>dmURuF7=5FSMDBWR729DFu0G&3a-HwOsX6hg$|DMZko z=sAp_L+rQ$?Cb&OVo!_`J`$V`Qt=XTLW;2YF?jqqB7!S;h^vgVvW>jSZoT>|qPQYz+c=eqkBqT!I#DZ4HXsPm3?E zu++n3$Zpz#ERMlCN`H$Bi*uRzw5$geQmHvi^Ejb0Icp)s857v+VYtWUGEZbSH9tE& z@wlbGvkwc-%uI3)@)8}y=_IzXGgx~J4|LTwKJFMC?QH94Y#o@K#r+f;#|m5+REX8i zMQr-y%8V@o)&YbXl#GvC9ZJo^Wrnp4AqIHu!=Y)xNrw>qT7sV{@Z`Jhk%BzW^)p=Q zvGI@?*GHE*!EOLWb6_w)g}#Kh)GZ-LxyEwAkRt~%zoVdZ1wk_qoRP#(iO1h{%C?!XZ|hH_4*}3 zu0x9Mdbj)sJ@6aC*Fl-Zw+gXy=&9fq?eQLzpwI#lgVjC_?DCF9n{I`K8U>`+NBGH$^5?ED0#R&C1Mhri zTXj9L6rD+zg1i7tau+Nw2OjI-d!29aec%86pZ@fxf8#S-u_>4!-Si&mjv)uOeYRMD|Jgob<=Oq@#0RDT<9J!NtvF_j+g6-Pw))e+yBG*`Gm{!wKTH6Vn`iNF zu!I!DYy@ypkTS=EI7yJ(fsA<`Fm#MUDU=MVHK>w04o-cPtt(oOpG(!<5Te& z8Z$E)n`rOs8lGg(&O~EKxTZNZ6)zA|iHW9`$3t-_vgK5AW^6n*mPluC4C{$cz#Rm1W_DqIVPbfsYbeQi?vR>%3mg7?0VAE= z7}83TgU`l>(!mOh4GknXU0#p_H}?g-@949_?1O5rXZnaD7e|f|faqM|!k*zJu~eKj z^BMk1fzyJexa4|Xkf+4YXQ=%2ETx)P)E*zQ@NYbGuyOEoe)ni{^WfrC7DmBe4lev@f98+-GJn>e`HR7YzZzcTO5$ISEL@ph zAI|PgZyzp8<=_c&FAmp$&&|$?dKkQDKsr8w%&IgwJ)6S!GF};}cYb+wg(HT|)rL3* ztE=o*sX6K2&derpCFC|5+8j#|0PNcGFtLpD6Gt>L_A(-DK*aG*GaZ{ki!y@_h1mk5 zRIr9}S~@kuX-Fd@qa#BE_PxnyG#VKl?&<2}sO!$|f!_X+5w^nqfl=G$xH~j7&^