This document visualises the expert assessment for accepted full papers at the GIScience conference series for the following conferences and proceedings.

The analysis is based on the assessment first published in “Reproducible research and GIScience: an evaluation using AGILE conference papers” (https://doi.org/10.7717/peerj.5072), see https://github.com/nuest/reproducible-research-and-giscience.

Reproduce paper

To create the assessment result data and figures based on this document you can run the following commands in a new R session after completing the prerequisites with the original paper corpus data. If you have problems rendering the document you can execute each chunk independently in RStudio.

# Following code is not executed when document is created
require("knitr")
require("rmarkdown")
rmarkdown::render("giscience-reproducibility-assessment.Rmd")

Software dependencies and code

This document does not install the required R packages by default. You can run the script install.R to install all required dependencies on a new R installation, or use install.packages(..) to install missing R packages. This is not required if you use the Docker container provided by the authors.

source("install.R")

The plots and tables of survey data and evaluation use the packages ggplot2, knitr::kable(), huxtable, and kableExtra. Required libraries and runtime environment description are as follows.

library("tidyverse")
library("tidyr")
library("readr")
library("ggplot2")
library("reshape2")
library("ggthemes")
library("grid")
library("gridBase")
library("gridExtra")
library("kableExtra")
library("huxtable")
library("here")
library("googlesheets4")
library("patchwork")
library("knitr")
library("kableExtra")
library("ggalluvial")
library("ggfittext")

Load data

assessment_file <- here::here("results/paper_assessment.csv")
codebook_file <- here::here("results/codebook.csv")

The data is loaded from a collaborative spreadsheet using the googlesheets4 package. After a year is completed by all assessors, a named version of the spreadsheet is created. Then the data file /home/rstudio/results/paper_assessment.csv is updated from the online spreadsheet and committed to the git history. Afterwards the individual assessments are manually merged in the online spreadsheet and the data file is updated and committed once more.

The following plots are based on the data file /home/rstudio/results/paper_assessment.csv, the result from the manual reproducibility assessment. The file /home/rstudio/results/codebook.csv contains a codebook with names, labels, and descriptions for the variables in the data file as documentation of the dataset outside of this computational notebook.

category_levels <- c("0", "1", "2", "3")
paper_evaluation <- readr::read_csv(assessment_file, 
    col_types = readr::cols(
      `conceptual paper` = readr::col_logical(),
      `computational environment` = readr::col_factor(levels = category_levels),
      `input data` = readr::col_factor(levels = category_levels),
      `method/analysis/processing` = readr::col_factor(levels = category_levels),
      preprocessing = readr::col_factor(levels = category_levels),
      results = readr::col_factor(levels = category_levels)
      ),
    na = "NA")
## Warning: Missing column names filled in: 'X1' [1]
paper_evaluation_wo_conceptual <- filter(paper_evaluation, `conceptual paper` == FALSE)

categoryColumns <- c("input data", 
                     "preprocessing",
                     "method/analysis/processing",
                     "computational environment",
                     "results")
options(knitr.kable.NA = '-')
knitr::kable(paper_evaluation %>% 
               dplyr::select(-matches("X1|reviewer|conceptual|authors")),
            format = "html",
            booktabs = TRUE,
            caption = paste0("Reproducibility levels for paper corpus; ",
                             "'-' is category not available")) %>%
  kableExtra::kable_styling("striped", full_width = FALSE)
Reproducibility levels for paper corpus; ‘-’ is category not available
paper year title input data preprocessing method/analysis/processing computational environment results
12018 2018 Early Detection of Herding Behaviour during Emergency Evacuations 1
1 0 1
22018 2018 What Makes Spatial Data Big? A Discussion on How to Partition Spatial Data 0 1 1 0 1
32018 2018 Intersections of Our World 0 1 1 0 1
42018 2018 Considerations of Graphical Proximity and Geographical Nearness 0
1 0 1
52018 2018 An Empirical Study on the Names of Points of Interest and Their Changes with Geographic Distance 0 1 1 0 1
62018 2018 Outlier Detection and Comparison of Origin-Destination Flows Using Data Depth 0 0 0 0 1
72018 2018 Is Salience Robust? A Heterogeneity Analysis of Survey Ratings 1 1 1 0 1
82018 2018 Labeling Points of Interest in Dynamic Maps using Disk Labels 1 2 2 0 1
92018 2018 Improving Discovery of Open Civic Data 0
1 0 1
102018 2018 Local Co-location Pattern Detection: A Summary of Results 0 1 1 1 1
112018 2018 Detection and Localization of Traffic Signals with GPS Floating Car Data and Random Forest 0 1 1 1 1
122018 2018 Heterogeneous Skeleton for Summarizing Continuously Distributed Demand in a Region 0
1 0 1
132018 2018 A Network Flow Model for the Analysis of Green Spaces in Urban Areas 1 1 1 1 1
142018 2018 Continuous Obstructed Detour Queries 0 0 1 1 1
152018 2018 Enhanced Multi Criteria Decision Analysis for Planning Power Transmission Lines 0 1 1 1 1
162018 2018 FUTURES-AMR: Towards an Adaptive Mesh Refinement Framework for Geosimulations 0 0 1 1 1
172018 2018 xNet+SC: Classifying Places Based on Images by Incorporating Spatial Contexts 0 1 1 1 1
12016 2016 Computing River Floods Using Massive Terrain Data 2 1 1 1 1
22016 2016 Partitioning Polygons via Graph Augmentation 0
1 0 1
32016 2016 Hierarchical Prism Trees for Scalable Time Geographic Analysis 2 2 2 0 2
42016 2016 Mining Network Hotspots with Holes: A Summary of Results 1 0 1 0 1
52016 2016 Distance-Constrained k Spatial Sub-Networks: A Summary of Results 0 0 1 1 1
62016 2016 GIScience Considerations in Spatial Social Networks
72016 2016 On Distortion of Raster-Based Least-Cost Corridors 0 0 1 0 1
82016 2016 Model-Based Clustering of Social Vulnerability to Urban Extreme Heat Events 1 1 1 0 1
92016 2016 Representing the Spatial Extent of Places Based on Flickr Photos with a Representativeness-Weighted Kernel Density Estimation 1 1 1 0 1
102016 2016 Scaling Behavior of Human Mobility Distributions 0 1 1 1 1
112016 2016 pFUTURES: A Parallel Framework for Cellular Automaton Based Urban Growth Models 0 0 1 1 1
122016 2016 From Data Streams to Fields: Extending Stream Data Models with Field Data Types
132016 2016 Point Partitions: A Qualitative Representation for Region-Based Spatial Scenes in R2
142016 2016 Fine Scale Spatio-Temporal Modelling of Urban Air Pollution 0 1 1 0 1
152016 2016 Modeling Checkpoint-Based Movement with the Earth Mover’s Distance 2 1 1 0 1
162016 2016 Exploratory Chronotopic Data Analysis 1 1 1 0 1
172016 2016 Exploring the Notion of Spatial Lenses 1 1 1 0 1
182016 2016 Moon Landing or Safari? A Study of Systematic Errors and Their Causes in Geographic Linked Data 1 0 1 0 1
192016 2016 Circles in the Water: Towards Island Group Labeling 0
1 0 1
202016 2016 An Algorithmic Framework for Labeling Road Maps 2 1 1 1 2
212016 2016 Measuring Cognitive Load for Map Tasks Through Pupil Diameter 1 1 1 1 1
12014 2014 Map Schematization with Circular Arcs 0
1 0 1
22014 2014 Travel-Time Maps: Linear Cartograms with Fixed Vertex Locations 0
1 0 1
32014 2014 3D Network Spatialization: Does It Add Depth to 2D Representations of Semantic Proximity? 1 1 1 1 1
42014 2014 Uncertainty Analysis of Step-Selection Functions: The Effect of Model Parameters on Inferences about the Relationship between Animal Movement and the Environment 2 1 1 0 1
52014 2014 Logic Scoring of Preference and Spatial Multicriteria Evaluation for Urban Residential Land Use Analysis 0 1 1 0 1
62014 2014 Spatial Weights: Constructing Weight-Compatible Exchange Matrices from Proximity Matrices 0 0 1 0 1
72014 2014 Spatial Graphs Cost and Efficiency: Exploring Edges Competition by MCMC 1 1 1 0 1
82014 2014 Geosemantic Network-of-Interest Construction Social Media Data 1 1 1 0 1
92014 2014 Data Quality Assurance for Volunteered Geographic Information 1 1 1 0 1
102014 2014 Re-Envisioning Data Description Using Peirce’ Pragmatics
112014 2014 Fields as a Generic Data Type for Big Spatial Data 1 1 1 0 1
122014 2014 Linked Data - A Paradigm Shift for Geographic Information Science
132014 2014 An Ontology Design Pattern for Surface Water Features
142014 2014 An Indoor Navigation Ontology for Production Assets in a Production Environment 0
0 0 1
152014 2014 Wayfinding Decision Situations: A Conceptual Model and Evaluation 1 1 1 0 1
162014 2014 Understanding Information Requirements in “Text Only” Pedestrian Wayfinding Systems 1
1 0 1
172014 2014 Automatic Itinerary Reconstruction from Texts 1 1 1 0 2
182014 2014 Integrating Sensing and Routing for Indoor Evacuation 0
1 0 1
192014 2014 Significant Route Discovery: A Summary of Results 2 0 1 0 1
202014 2014 Location Oblivious Privacy Protection for Group Nearest Neighbor Queries 2
1 0 1
212014 2014 Practical Approaches to Partially Guarding a Polyhedral Terrain 1
1 0 1
222014 2014 Oriented Regions for Linearly Conceptualized Features
232014 2014 RCC-9 and CBM
12012 2012 Combining Trip and Task Planning: How to Get from A to Passport
22012 2012 Automated Centerline Delineation to Enrich the National Hydrography Dataset 2 1 1 1 1
32012 2012 Evolution Strategies for Optimizing Rectangular Cartograms 1 1 1 1 1
42012 2012 Context-Aware Similarity of Trajectories 2 1 1 0 1
52012 2012 Generating Named Road Vector Data from Raster Maps 1
1 0 1
62012 2012 An Ordering of Convex Topological Relations
72012 2012 Toward Web Mapping with Vector Data 0
1 0 1
82012 2012 – Exploring the Research Field of GIScience with Linked Data 2 1 1 1 2
92012 2012 Crowdsourcing Satellite Imagery Analysis: Study of Parallel and Iterative Models 0 0 1 0 1
102012 2012 Quantifying Resolution Sensitivity of Spatial Autocorrelation: A Resolution Correlogram Approach 0 1 1 1 1
112012 2012 LocalAlert: Simulating Decentralized Ad-Hoc Collaboration in Emergency Situations
2 1 1
122012 2012 High-Level Event Detection in Spatially Distributed Time Series 0 1 1 0 1
132012 2012 Towards Vague Geographic Data Warehouses 0
2 0 2
142012 2012 Measuring the Influence of Built Environment on Walking Behavior: An Accessibility Approach 1 1 1 0 1
152012 2012 Social Welfare to Assess the Global Legibility of a Generalized Map 0
1 0 1
162012 2012 Investigations into the Cognitive Conceptualization and Similarity Assessment of Spatial Scenes 1
1 1 1
172012 2012 A Qualitative Bigraph Model for Indoor Space
182012 2012 Dynamic Refuse Collection Strategy Based on Adjacency Relationship between Euler Cycles 2
1 0 1
192012 2012 Impact of Indoor Location Information Reliability on Users’ Trust of an Indoor Positioning System 1
1 0 1
202012 2012 Ontology for the Engineering of Geospatial Systems 1
1 0 1
212012 2012 Preserving Detail in a Combined Land Use Ontology 1 1 1 0 0
222012 2012 The Maptree: A Fine-Grained Formal Representation of Space
232012 2012 Automatic Creation of Crosswalk for Geospatial Metadata Standard Interoperability 1 0 1 0 1
242012 2012 A Dartboard Network Cut Based Approach to Evacuation Route Planning: A Summary of Results 2
1 1 1
252012 2012 Hybrid Geo-spatial Query Methods on the Semantic Web with a Spatially-Enhanced Index of DBpedia 1
1 0 1
262012 2012 Extracting Dynamic Urban Mobility Patterns from Mobile Phone Data 0 1 1 0 1

Table: Statistics of reproducibility levels per criterion for non-conceptual papers

evaldata_numeric <- paper_evaluation_wo_conceptual %>%
  # must convert factors to numbers to calculate the mean and median
  dplyr::mutate_if(is.factor, list(~ as.integer(as.character(.))))

# https://stackoverflow.com/questions/32011873/force-summary-to-report-the-number-of-nas-even-if-none
summaryna <- function (v) {
  if(!any(is.na(v))){
    res <- c(summary(v),"NA's"=0)
  } else{
    res <- summary(v)
  }
  return(res)
}

# apply summary independently to format as table
summaries <- sapply(evaldata_numeric[,categoryColumns], summaryna)
exclude_values_summary <- c("1st Qu.", "3rd Qu.")

kable(subset(summaries, !(rownames(summaries) %in% exclude_values_summary)), 
      digits = 1,
      col.names = c("input data", "preproc.", "method/analysis/proc.",
                    "comp. env.", "results"),
      caption = "Statistics of reproducibility levels per criterion (rounded to one decimal place)") %>%
  kableExtra::row_spec(0, bold = TRUE) %>%
  kableExtra::kable_styling(latex_options = c("striped"),
                            font_size = 8)
Statistics of reproducibility levels per criterion (rounded to one decimal place)
input data preproc. method/analysis/proc. comp. env. results
Min. 0.0 0.0 0 0.0 0.0
Median 1.0 1.0 1 0.0 1.0
Mean 0.7 0.8 1 0.3 1.1
Max. 2.0 2.0 2 1.0 2.0
NA’s 1.0 24.0 0 0.0 0.0

The preprocessing has 51 values, with 0 and 1 around the “middle” resulting in a fraction as the median.

Data points for text

data_level_zero <- paper_evaluation_wo_conceptual %>% 
  filter(`input data` == 0) %>% 
  count() %>% .$n

data_level_two <- paper_evaluation_wo_conceptual %>% 
  filter(`input data` == 2) %>% 
  count() %>% .$n

preprocessing_included <- paper_evaluation_wo_conceptual %>% 
  filter(!is.na(preprocessing)) %>% 
  count() %>% .$n

preprocessing_level_one <- paper_evaluation_wo_conceptual %>% 
  filter(preprocessing == 1) %>% 
  count() %>% .$n

methods_and_results_eq_one <- paper_evaluation_wo_conceptual %>% 
  filter(`method/analysis/processing` == 1 & results == 1) %>% 
  count() %>% .$n
  
compenv_level_zero <- paper_evaluation_wo_conceptual %>% 
  filter(`computational environment` == 0) %>% 
  count() %>% .$n

33 papers have level 0 and 12 have level 2 in the data criterion.

51 papers include some kind of preprocessing.

65 papers have level 1 in both methods and results criterion.

Figure: Barplots of reproducibility assessment results

# match the colours to time series plot below
colours <- RColorBrewer::brewer.pal(length(categoryColumns), "Set1")
level_names <- c("0", "1", "2", "3", NA)
breaks <- seq(from = 0, to = nrow(paper_evaluation_wo_conceptual), by = 10)

criteriaBarplot = function(category, main, colour) {
  cat <- enquo(category)
  ggplot2::ggplot(data = paper_evaluation_wo_conceptual,
                aes(!!cat),
                show.legend = FALSE) +
    ggplot2::geom_bar(fill = colours[colour], color = "black") +
    ggplot2::ggtitle(main) +
    ggplot2::xlab("Level") +
    ggplot2::xlim(level_names) +
    ggplot2::ylab("") +
    ggplot2::scale_y_continuous(breaks = breaks,
                                limits = range(breaks)) +
    ggthemes::theme_tufte(base_size = 8) + theme(axis.ticks.x = element_blank())
}

fig_barplot <- patchwork::wrap_plots(
  ncol = 5,
  criteriaBarplot(`input data`,    main = "Input data",    colour = 1),
  criteriaBarplot(`preprocessing`, main = "Preprocessing", colour = 2),
  criteriaBarplot(`method/analysis/processing`,
                  main = "Methods/Analysis/\nProcessing",  colour = 3),
  criteriaBarplot(`computational environment`,
                  main = "Computational\nEnvironment", colour = 4),
  criteriaBarplot(results,         main = "Results", colour = 5)
)

fig_barplot

Figure: Alluvial diagramme of reproducibility assessment results across categories

This figure is based on package ggalluvial. It does not include the category preprocessing because it was discovered to be quite hard to assess, and subsequently has a large share of missing values. The figure also does not include any papers who have one or more categories as NA, as that means “not assessable”.

papers_wo_na_wo_prepr <- paper_evaluation_wo_conceptual %>%
  drop_na() %>%
  mutate_if(is.factor, forcats::fct_rev) %>%
  group_by(`input data`,
           `method/analysis/processing`,
           `computational environment`,
           results) %>%
  tally() %>%
  mutate(`Category levels (#)` = paste0(`input data`, " ",
                       `method/analysis/processing`, " ",
                       `computational environment`, " ",
                       results, " (", n, ")"))
fig_alluvial <- ggplot(data = papers_wo_na_wo_prepr,
       aes(axis1 = `input data`,
           axis2 = `method/analysis/processing`,
           axis3 = `computational environment`,
           axis4 = results,
           y = n)
       ) +
  ggplot2::scale_x_discrete(limits = c("Input Data",
                              "Methods/\nAnalysis/\nProcessing",
                              "Computational\nEnvironment",
                              "Results"),
                   expand = c(.1, 0)
                   ) +
  xlab("Category") +
  ylab("Number of papers") +
  ggplot2::scale_fill_manual(values = c(
    RColorBrewer::brewer.pal(9, "Set1"),            # colours from the other plots
    RColorBrewer::brewer.pal(4, "Dark2")[c(1,3,4)]) # manually chosen from another palette
    ) +
  ggalluvial::geom_alluvium(aes(fill = `Category levels (#)`), width = 1/3) +
  ggalluvial::geom_stratum(alpha = 1) +
  ggfittext::geom_fit_text(stat = "stratum", aes(label = after_stat(stratum)), min.size = 1) +
  ggthemes::theme_tufte()

fig_alluvial

Table: Mean levels per criterion for non-conceptual papers

means <- lapply(evaldata_numeric %>%
                      select(all_of(categoryColumns)),
                    summary) %>%
    lapply(`[[`, "Mean") %>%
    as.data.frame()

kable(means,
      digits = 2,
      col.names = c("input data", "preproc.", "method/analysis/proc.", "comp. env.", "results"),
      caption = "Mean levels per criterion for non-conceptual papers") %>%
  kableExtra::kable_styling("striped", full_width = FALSE)
Mean levels per criterion for non-conceptual papers
input data preproc. method/analysis/proc. comp. env. results
0.72 0.8 1.03 0.28 1.05

Table: Mean levels averaged across criteria over time for non-conceptual papers

means_years <- evaldata_numeric %>%
  filter(`conceptual paper` == FALSE) %>%
  group_by(year) %>%
  summarise(mean = mean(c(`input data`, 
                          preprocessing, 
                          `method/analysis/processing`, 
                          `computational environment`, 
                          `results`),
                        na.rm = TRUE),
            `paper count` = n())

means_years_table <- means_years %>% 
        mutate(mean = round(mean, 2), 
               `paper count` = as.character(`paper count`)) %>%
        mutate(labels = str_c(year, " (n = ", `paper count`, ")")) %>%
        column_to_rownames("labels") %>%
        select(mean) %>%
        t()

kable(means_years_table,
      caption = "Summarised mean values over all criteria over time (non-conceptual papers)") %>%
  kableExtra::kable_styling("striped", full_width = TRUE)
Summarised mean values over all criteria over time (non-conceptual papers)
2012 (n = 22) 2014 (n = 18) 2016 (n = 18) 2018 (n = 17)
mean 0.84 0.73 0.82 0.69

Figure: Mean reproducibility levels per category over time for non-conceptual papers

evaldata_years <- evaldata_numeric %>%
  filter(`conceptual paper` == FALSE) %>%
  group_by(year) %>%
  summarise(input = mean(`input data`, na.rm = TRUE),
         preprocessing = mean(preprocessing, na.rm = TRUE),
            method = mean(`method/analysis/processing`, na.rm = TRUE),
            environment = mean(`computational environment`, na.rm = TRUE),
            results = mean(results, na.rm = TRUE))
paper_count_years <- evaldata_numeric %>%
  filter(`conceptual paper` == FALSE) %>%
  group_by(year) %>%
  summarise(`paper count` = n())

evaldata_years_long <- melt(evaldata_years, id.vars = c("year"))
fig_mean_over_time <- ggplot(evaldata_years_long, aes(year, value)) +
  geom_bar(aes(fill = variable), position = "dodge", stat = "identity") +
  #geom_errorbar(stat = "summary", fun.data = "mean_sdl", 
  #                fun.args = list(mult = 1),
  #                position =  position_dodge(width = 0.9)) +
  ylab("mean value of criterion level") + 
  scale_x_continuous(breaks = evaldata_years$year,
                     labels = paste0(paper_count_years$year, 
                                     " (n=", 
                                     paper_count_years$`paper count`, 
                                     ")")) +
  scale_fill_brewer(palette = "Set1", name = "Category") +
  ggthemes::theme_tufte(base_size = 18) +
  theme(legend.position = c(0.15,0.75), 
        legend.text = element_text(size = 14)) +
  ylim(0, 3) +
  stat_summary(fun = mean, fun.min = mean, fun.max = mean, shape = "-", size = 2) +
  stat_summary(fun = mean, geom = "line", linetype = "dotted", mapping = aes(group = 1))

fig_mean_over_time

Colophon

This document is licensed under a Creative Commons Attribution 4.0 International License. All contained code is licensed under the Apache License 2.0. This document is versioned in a public git repository, https://github.com/nuest/reproducible-research-at-giscience, and archived on Zenodo at https://doi.org/10.5281/zenodo.4032875.

Runtime environment description:

## ─ Session info ───────────────────────────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.3 (2020-02-29)
##  os       Debian GNU/Linux 10 (buster)
##  system   x86_64, linux-gnu           
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       Etc/UTC                     
##  date     2021-06-01                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────────────────────────
##  package       * version date       lib source                                  
##  assertthat      0.2.1   2019-03-21 [1] CRAN (R 3.6.3)                          
##  backports       1.1.6   2020-04-05 [1] CRAN (R 3.6.3)                          
##  base          * 3.6.3   2020-05-14 [2] local                                   
##  broom           0.5.6   2020-04-20 [1] CRAN (R 3.6.3)                          
##  callr           3.4.3   2020-03-28 [1] CRAN (R 3.6.3)                          
##  cellranger      1.1.0   2016-07-27 [1] CRAN (R 3.6.3)                          
##  cli             2.0.2   2020-02-28 [1] CRAN (R 3.6.3)                          
##  colorspace      1.4-1   2019-03-18 [1] CRAN (R 3.6.3)                          
##  compiler        3.6.3   2020-05-14 [2] local                                   
##  crayon          1.3.4   2017-09-16 [1] CRAN (R 3.6.3)                          
##  datasets      * 3.6.3   2020-05-14 [2] local                                   
##  DBI             1.1.0   2019-12-15 [1] CRAN (R 3.6.3)                          
##  dbplyr          1.4.3   2020-04-19 [1] CRAN (R 3.6.3)                          
##  desc            1.2.0   2018-05-01 [1] CRAN (R 3.6.3)                          
##  devtools        2.3.0   2020-04-10 [1] CRAN (R 3.6.3)                          
##  digest          0.6.25  2020-02-23 [1] CRAN (R 3.6.3)                          
##  dplyr         * 0.8.5   2020-03-07 [1] CRAN (R 3.6.3)                          
##  ellipsis        0.3.0   2019-09-20 [1] CRAN (R 3.6.3)                          
##  evaluate        0.14    2019-05-28 [1] CRAN (R 3.6.3)                          
##  fansi           0.4.1   2020-01-08 [1] CRAN (R 3.6.3)                          
##  farver          2.0.3   2020-01-16 [1] CRAN (R 3.6.3)                          
##  forcats       * 0.5.0   2020-03-01 [1] CRAN (R 3.6.3)                          
##  fs              1.4.1   2020-04-04 [1] CRAN (R 3.6.3)                          
##  generics        0.0.2   2018-11-29 [1] CRAN (R 3.6.3)                          
##  ggalluvial    * 0.11.3  2020-04-16 [1] CRAN (R 3.6.3)                          
##  ggfittext     * 0.8.1   2019-07-18 [1] CRAN (R 3.6.3)                          
##  ggplot2       * 3.3.0   2020-03-05 [1] CRAN (R 3.6.3)                          
##  ggthemes      * 4.2.0   2019-05-13 [1] CRAN (R 3.6.3)                          
##  glue            1.4.0   2020-04-03 [1] CRAN (R 3.6.3)                          
##  googlesheets4 * 0.1.1   2021-06-01 [1] Github (tidyverse/googlesheets4@ec3946b)
##  graphics      * 3.6.3   2020-05-14 [2] local                                   
##  grDevices     * 3.6.3   2020-05-14 [2] local                                   
##  grid          * 3.6.3   2020-05-14 [2] local                                   
##  gridBase      * 0.4-7   2014-02-24 [1] CRAN (R 3.6.3)                          
##  gridExtra     * 2.3     2017-09-09 [1] CRAN (R 3.6.3)                          
##  gtable          0.3.0   2019-03-25 [1] CRAN (R 3.6.3)                          
##  haven           2.2.0   2019-11-08 [1] CRAN (R 3.6.3)                          
##  here          * 0.1     2017-05-28 [1] CRAN (R 3.6.3)                          
##  highr           0.8     2019-03-20 [1] CRAN (R 3.6.3)                          
##  hms             0.5.3   2020-01-08 [1] CRAN (R 3.6.3)                          
##  htmltools       0.4.0   2019-10-04 [1] CRAN (R 3.6.3)                          
##  httr            1.4.1   2019-08-05 [1] CRAN (R 3.6.3)                          
##  huxtable      * 4.7.1   2020-01-08 [1] CRAN (R 3.6.3)                          
##  jsonlite        1.6.1   2020-02-02 [1] CRAN (R 3.6.3)                          
##  kableExtra    * 1.1.0   2019-03-16 [1] CRAN (R 3.6.3)                          
##  knitr         * 1.28    2020-02-06 [1] CRAN (R 3.6.3)                          
##  labeling        0.3     2014-08-23 [1] CRAN (R 3.6.3)                          
##  lattice         0.20-38 2018-11-04 [2] CRAN (R 3.6.3)                          
##  lifecycle       0.2.0   2020-03-06 [1] CRAN (R 3.6.3)                          
##  lubridate       1.7.8   2020-04-06 [1] CRAN (R 3.6.3)                          
##  magrittr        1.5     2014-11-22 [1] CRAN (R 3.6.3)                          
##  memoise         1.1.0   2017-04-21 [1] CRAN (R 3.6.3)                          
##  methods       * 3.6.3   2020-05-14 [2] local                                   
##  modelr          0.1.6   2020-02-22 [1] CRAN (R 3.6.3)                          
##  munsell         0.5.0   2018-06-12 [1] CRAN (R 3.6.3)                          
##  nlme            3.1-144 2020-02-06 [2] CRAN (R 3.6.3)                          
##  patchwork     * 1.1.0   2021-06-01 [1] Github (thomasp85/patchwork@48819a9)    
##  pillar          1.4.3   2019-12-20 [1] CRAN (R 3.6.3)                          
##  pkgbuild        1.0.6   2019-10-09 [1] CRAN (R 3.6.3)                          
##  pkgconfig       2.0.3   2019-09-22 [1] CRAN (R 3.6.3)                          
##  pkgload         1.0.2   2018-10-29 [1] CRAN (R 3.6.3)                          
##  plyr            1.8.6   2020-03-03 [1] CRAN (R 3.6.3)                          
##  prettyunits     1.1.1   2020-01-24 [1] CRAN (R 3.6.3)                          
##  processx        3.4.2   2020-02-09 [1] CRAN (R 3.6.3)                          
##  ps              1.3.2   2020-02-13 [1] CRAN (R 3.6.3)                          
##  purrr         * 0.3.4   2020-04-17 [1] CRAN (R 3.6.3)                          
##  R6              2.4.1   2019-11-12 [1] CRAN (R 3.6.3)                          
##  RColorBrewer    1.1-2   2014-12-07 [1] CRAN (R 3.6.3)                          
##  Rcpp            1.0.4.6 2020-04-09 [1] CRAN (R 3.6.3)                          
##  readr         * 1.3.1   2018-12-21 [1] CRAN (R 3.6.3)                          
##  readxl          1.3.1   2019-03-13 [1] CRAN (R 3.6.3)                          
##  remotes         2.1.1   2020-02-15 [1] CRAN (R 3.6.3)                          
##  reprex          0.3.0   2019-05-16 [1] CRAN (R 3.6.3)                          
##  reshape2      * 1.4.4   2020-04-09 [1] CRAN (R 3.6.3)                          
##  rlang           0.4.5   2020-03-01 [1] CRAN (R 3.6.3)                          
##  rmarkdown       2.5     2021-06-01 [1] Github (rstudio/rmarkdown@4ff2093)      
##  rprojroot       1.3-2   2018-01-03 [1] CRAN (R 3.6.3)                          
##  rstudioapi      0.11    2020-02-07 [1] CRAN (R 3.6.3)                          
##  rvest           0.3.5   2019-11-08 [1] CRAN (R 3.6.3)                          
##  scales          1.1.0   2019-11-18 [1] CRAN (R 3.6.3)                          
##  sessioninfo     1.1.1   2018-11-05 [1] CRAN (R 3.6.3)                          
##  stats         * 3.6.3   2020-05-14 [2] local                                   
##  stringi         1.4.6   2020-02-17 [1] CRAN (R 3.6.3)                          
##  stringr       * 1.4.0   2019-02-10 [1] CRAN (R 3.6.3)                          
##  testthat        2.3.2   2020-03-02 [1] CRAN (R 3.6.3)                          
##  tibble        * 3.0.1   2020-04-20 [1] CRAN (R 3.6.3)                          
##  tidyr         * 1.0.2   2020-01-24 [1] CRAN (R 3.6.3)                          
##  tidyselect      1.0.0   2020-01-27 [1] CRAN (R 3.6.3)                          
##  tidyverse     * 1.3.0   2019-11-21 [1] CRAN (R 3.6.3)                          
##  tools           3.6.3   2020-05-14 [2] local                                   
##  usethis         1.6.0   2020-04-09 [1] CRAN (R 3.6.3)                          
##  utils         * 3.6.3   2020-05-14 [2] local                                   
##  vctrs           0.2.4   2020-03-10 [1] CRAN (R 3.6.3)                          
##  viridisLite     0.3.0   2018-02-01 [1] CRAN (R 3.6.3)                          
##  webshot         0.5.2   2019-11-22 [1] CRAN (R 3.6.3)                          
##  withr           2.2.0   2020-04-20 [1] CRAN (R 3.6.3)                          
##  xfun            0.15    2021-06-01 [1] Github (yihui/xfun@06e86a6)             
##  xml2            1.3.2   2020-04-23 [1] CRAN (R 3.6.3)                          
##  yaml            2.2.1   2020-02-01 [1] CRAN (R 3.6.3)                          
## 
## [1] /usr/local/lib/R/site-library
## [2] /usr/local/lib/R/library
LS0tCnRpdGxlOiAnUmVwcm9kdWNpYmlsaXR5IGFzc2Vzc21lbnQgZGF0YSBhbmFseXNpcyBmb3IgIlJlcHJvZHVjaWJsZSByZXNlYXJjaCBhbmQgR0lTY2llbmNlOiBhbiBldmFsdWF0aW9uIHVzaW5nIEdJU2NpZW5jZSBjb25mZXJlbmNlIHBhcGVycyInCmF1dGhvcjogIkRhbmllbCBOw7xzdCwgQ2FybG9zIEdyYW5lbGwiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHNlbGZfY29udGFpbmVkOiBmYWxzZQogICAgbGliX2RpcjogbGlicwp1cmxjb2xvcjogYmx1ZQotLS0KCmBgYHtjc3MsIGVjaG89RkFMU0V9CnByZSB7CiAgZm9udC1zaXplOiAxMnB4OwogIG92ZXJmbG93LXg6IGF1dG87Cn0KcHJlIGNvZGUgewogIHdvcmQtd3JhcDogbm9ybWFsOwogIHdoaXRlLXNwYWNlOiBwcmU7Cn0KYGBgCgpUaGlzIGRvY3VtZW50IHZpc3VhbGlzZXMgdGhlIGV4cGVydCBhc3Nlc3NtZW50IGZvciBhY2NlcHRlZCBmdWxsIHBhcGVycyBhdCB0aGUgW0dJU2NpZW5jZSBjb25mZXJlbmNlIHNlcmllc10oaHR0cHM6Ly93d3cuZ2lzY2llbmNlLm9yZy8pIGZvciB0aGUgZm9sbG93aW5nIGNvbmZlcmVuY2VzIGFuZCBwcm9jZWVkaW5ncy4KCi0gMjAxODogVGVudGggSW50ZXJuYXRpb25hbCBDb25mZXJlbmNlIG9uIEdlb2dyYXBoaWMgSW5mb3JtYXRpb24gU2NpZW5jZSwgTWVsYm91cm5lLCBBdXN0cmFsaWEKICAKICBfUHJvY2VlZGluZ3MgMTB0aCBJbnRlcm5hdGlvbmFsIENvbmZlcmVuY2Ugb24gR2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBTY2llbmNlIChHSVNjaWVuY2UgMjAxOCkuIDIwMTguIEluIFdpbnRlciwgUy4sIEdyaWZmaW4sIEEuLCBTZXN0ZXIsIE0uIChFZHMuKSwgTElQSUNTIFZvbC4gMTE0LiBJU0JOIDk3OC0zLTk1OTc3LTA4My01LiBodHRwOi8vd3d3LmRhZ3N0dWhsLmRlL2RhZ3B1Yi85NzgtMy05NTk3Ny0wODMtNSBfCgotIDIwMTY6IE5pbnRoIEludGVybmF0aW9uYWwgQ29uZmVyZW5jZSBvbiBHZW9ncmFwaGljIEluZm9ybWF0aW9uIFNjaWVuY2UsIFNlcCAyNywgMjAxNiAtIFNlcCAzMCwgMjAxNiwgCU1vbnRyZWFsLCBDYW5hZGEKICAKICBfR2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBTY2llbmNlLiAyMDE2LiBJbiBKLiBBLiBNaWxsZXIsIEQuIE/igJlTdWxsaXZhbiwgJiBOLiBXaWVnYW5kIChFZHMuKSwgTGVjdHVyZSBOb3RlcyBpbiBDb21wdXRlciBTY2llbmNlLiBTcHJpbmdlciBJbnRlcm5hdGlvbmFsIFB1Ymxpc2hpbmcuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3Lzk3OC0zLTMxOS00NTczOC0zIF8KCi0gMjAxNDogRWlnaHRoIEludGVybmF0aW9uYWwgQ29uZmVyZW5jZSBvbiBHZW9ncmFwaGljIEluZm9ybWF0aW9uIFNjaWVuY2UsIFNlcCAyNCwgMjAxNCAtIFNlcCAyNiwgMjAxNCwgCVZpZW5uYSwgQXVzdHJpYQogID4gR2VvZ3JhcGhpYyBJbmZvcm1hdGlvbiBTY2llbmNlLiAyMDE0LiBJbiBNLiBEdWNraGFtLCBFLiBQZWJlc21hLCBLLiBTdGV3YXJ0LCAmIEEuIFUuIEZyYW5rIChFZHMuKSwgTGVjdHVyZSBOb3RlcyBpbiBDb21wdXRlciBTY2llbmNlLiBTcHJpbmdlciBJbnRlcm5hdGlvbmFsIFB1Ymxpc2hpbmcuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDA3Lzk3OC0zLTMxOS0xMTU5My0xCgotIDIwMTI6IFNldmVudGggSW50ZXJuYXRpb25hbCBDb25mZXJlbmNlIG9uIEdlb2dyYXBoaWMgSW5mb3JtYXRpb24gU2NpZW5jZSwgU2VwIDE4LCAyMDEyIC0gU2VwIDIxLCAyMDEyLCBDb2x1bWJ1cywgT2hpbywgVVNBCiAgPiBHZW9ncmFwaGljIEluZm9ybWF0aW9uIFNjaWVuY2UuIDIwMTIuIEluIE4uIFhpYW8sIE0uLVAuIEt3YW4sIE0uIEYuIEdvb2RjaGlsZCwgJiBTLiBTaGVraGFyIChFZHMuKSwgTGVjdHVyZSBOb3RlcyBpbiBDb21wdXRlciBTY2llbmNlLiBTcHJpbmdlciBCZXJsaW4gSGVpZGVsYmVyZy4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvOTc4LTMtNjQyLTMzMDI0LTcKClRoZSBhbmFseXNpcyBpcyBiYXNlZCBvbiB0aGUgYXNzZXNzbWVudCBmaXJzdCBwdWJsaXNoZWQgaW4gXyJSZXByb2R1Y2libGUgcmVzZWFyY2ggYW5kIEdJU2NpZW5jZTogYW4gZXZhbHVhdGlvbiB1c2luZyBBR0lMRSBjb25mZXJlbmNlIHBhcGVycyJfIChbaHR0cHM6Ly9kb2kub3JnLzEwLjc3MTcvcGVlcmouNTA3Ml0oaHR0cHM6Ly9kb2kub3JnLzEwLjc3MTcvcGVlcmouNTA3MikpLCBzZWUgW2h0dHBzOi8vZ2l0aHViLmNvbS9udWVzdC9yZXByb2R1Y2libGUtcmVzZWFyY2gtYW5kLWdpc2NpZW5jZV0oaHR0cHM6Ly9naXRodWIuY29tL251ZXN0L3JlcHJvZHVjaWJsZS1yZXNlYXJjaC1hbmQtZ2lzY2llbmNlKS4KCiMjIFJlcHJvZHVjZSBwYXBlcgoKVG8gY3JlYXRlIHRoZSBhc3Nlc3NtZW50IHJlc3VsdCBkYXRhIGFuZCBmaWd1cmVzIGJhc2VkIG9uIHRoaXMgZG9jdW1lbnQgeW91IGNhbiBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kcyBpbiBhIG5ldyBSIHNlc3Npb24gYWZ0ZXIgY29tcGxldGluZyB0aGUgcHJlcmVxdWlzaXRlcyB3aXRoIHRoZSBvcmlnaW5hbCBwYXBlciBjb3JwdXMgZGF0YS4KSWYgeW91IGhhdmUgcHJvYmxlbXMgcmVuZGVyaW5nIHRoZSBkb2N1bWVudCB5b3UgY2FuIGV4ZWN1dGUgZWFjaCBjaHVuayBpbmRlcGVuZGVudGx5IGluIFtSU3R1ZGlvXShodHRwczovL3JzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vKS4KCmBgYHtyIHJlbmRlcl93aXRoX3JtYXJrZG93biwgZXZhbD1GQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CiMgRm9sbG93aW5nIGNvZGUgaXMgbm90IGV4ZWN1dGVkIHdoZW4gZG9jdW1lbnQgaXMgY3JlYXRlZApyZXF1aXJlKCJrbml0ciIpCnJlcXVpcmUoInJtYXJrZG93biIpCnJtYXJrZG93bjo6cmVuZGVyKCJnaXNjaWVuY2UtcmVwcm9kdWNpYmlsaXR5LWFzc2Vzc21lbnQuUm1kIikKYGBgCgojIyBTb2Z0d2FyZSBkZXBlbmRlbmNpZXMgYW5kIGNvZGUKClRoaXMgZG9jdW1lbnQgZG9lcyBub3QgaW5zdGFsbCB0aGUgcmVxdWlyZWQgUiBwYWNrYWdlcyBieSBkZWZhdWx0LgpZb3UgY2FuIHJ1biB0aGUgc2NyaXB0IGBpbnN0YWxsLlJgIHRvIGluc3RhbGwgYWxsIHJlcXVpcmVkIGRlcGVuZGVuY2llcyBvbiBhIG5ldyBSIGluc3RhbGxhdGlvbiwgb3IgdXNlIGBpbnN0YWxsLnBhY2thZ2VzKC4uKWAgdG8gaW5zdGFsbCBtaXNzaW5nIFIgcGFja2FnZXMuCl9UaGlzIGlzIG5vdCByZXF1aXJlZCBpZiB5b3UgdXNlIHRoZSBEb2NrZXIgY29udGFpbmVyIHByb3ZpZGVkIGJ5IHRoZSBhdXRob3JzLl8KCmBgYHtyIGluc3RhbGxfciwgZXZhbD1GQUxTRX0Kc291cmNlKCJpbnN0YWxsLlIiKQpgYGAKClRoZSBwbG90cyBhbmQgdGFibGVzIG9mIHN1cnZleSBkYXRhIGFuZCBldmFsdWF0aW9uIHVzZSB0aGUgcGFja2FnZXMgW2BnZ3Bsb3QyYF0oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pLCBbYGtuaXRyOjprYWJsZSgpYF0oaHR0cHM6Ly95aWh1aS5uYW1lL2tuaXRyLyksIFtgaHV4dGFibGVgXShodHRwczovL2h1Z2hqb25lc2QuZ2l0aHViLmlvL2h1eHRhYmxlLyksIGFuZCBbYGthYmxlRXh0cmFgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9wYWNrYWdlPWthYmxlRXh0cmEpLgpSZXF1aXJlZCBsaWJyYXJpZXMgYW5kIHJ1bnRpbWUgZW52aXJvbm1lbnQgZGVzY3JpcHRpb24gYXJlIGFzIGZvbGxvd3MuCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJ0aWR5ciIpCmxpYnJhcnkoInJlYWRyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInJlc2hhcGUyIikKbGlicmFyeSgiZ2d0aGVtZXMiKQpsaWJyYXJ5KCJncmlkIikKbGlicmFyeSgiZ3JpZEJhc2UiKQpsaWJyYXJ5KCJncmlkRXh0cmEiKQpsaWJyYXJ5KCJrYWJsZUV4dHJhIikKbGlicmFyeSgiaHV4dGFibGUiKQpsaWJyYXJ5KCJoZXJlIikKbGlicmFyeSgiZ29vZ2xlc2hlZXRzNCIpCmxpYnJhcnkoInBhdGNod29yayIpCmxpYnJhcnkoImtuaXRyIikKbGlicmFyeSgia2FibGVFeHRyYSIpCmxpYnJhcnkoImdnYWxsdXZpYWwiKQpsaWJyYXJ5KCJnZ2ZpdHRleHQiKQpgYGAKCiMjIExvYWQgZGF0YQoKYGBge3IgZXZhbGRhdGFfZmlsZX0KYXNzZXNzbWVudF9maWxlIDwtIGhlcmU6OmhlcmUoInJlc3VsdHMvcGFwZXJfYXNzZXNzbWVudC5jc3YiKQpjb2RlYm9va19maWxlIDwtIGhlcmU6OmhlcmUoInJlc3VsdHMvY29kZWJvb2suY3N2IikKYGBgCgpUaGUgZGF0YSBpcyBsb2FkZWQgZnJvbSBhIGNvbGxhYm9yYXRpdmUgc3ByZWFkc2hlZXQgdXNpbmcgdGhlIFtgZ29vZ2xlc2hlZXRzNGBdKGh0dHBzOi8vZ29vZ2xlc2hlZXRzNC50aWR5dmVyc2Uub3JnLykgcGFja2FnZS4KQWZ0ZXIgYSB5ZWFyIGlzIGNvbXBsZXRlZCBieSBhbGwgYXNzZXNzb3JzLCBhIFtuYW1lZCB2ZXJzaW9uXShodHRwczovL3N1cHBvcnQuZ29vZ2xlLmNvbS9hL3VzZXJzL2Fuc3dlci85MzMxMTY5P2hsPWVuIykgb2YgdGhlIHNwcmVhZHNoZWV0IGlzIGNyZWF0ZWQuClRoZW4gdGhlIGRhdGEgZmlsZSBgYCBgciBhc3Nlc3NtZW50X2ZpbGVgIGBgIGlzIHVwZGF0ZWQgZnJvbSB0aGUgb25saW5lIHNwcmVhZHNoZWV0IGFuZCBjb21taXR0ZWQgdG8gdGhlIGdpdCBoaXN0b3J5LgpBZnRlcndhcmRzIHRoZSBpbmRpdmlkdWFsIGFzc2Vzc21lbnRzIGFyZSBtYW51YWxseSBtZXJnZWQgaW4gdGhlIG9ubGluZSBzcHJlYWRzaGVldCBhbmQgdGhlIGRhdGEgZmlsZSBpcyB1cGRhdGVkIGFuZCBjb21taXR0ZWQgb25jZSBtb3JlLgoKYGBge3IgZ29vZ2xlc2hlZXRzX2F1dGgsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9CiMgcnVuIG9uY2UKZ29vZ2xlc2hlZXRzNDo6c2hlZXRzX2F1dGgodXNlX29vYiA9IFRSVUUpCmBgYAoKYGBge3IgZXZhbGRhdGFfZG93bmxvYWQsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9CmFzc2Vzc21lbnRfc2hlZXQgPC0gZ29vZ2xlc2hlZXRzNDo6cmVhZF9zaGVldCgKICBzcyA9ICJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xRGYwelg1eXFEdURTQ3pISFZhdWNOdFRoc2VITDVMMzJVMnNXVFBoeWwwSS9lZGl0I2dpZD0wIiwKICBzaGVldCA9ICJhc3Nlc3NtZW50IiwKICAjIGZpeCB0eXBlIGZvciBkb3dubG9hZGluZyBkYXRhOiB0dXJuIGFsbCBkYXRhIGludG8gY2hhcmFjdGVyIHN0cmluZ3M7IHR5cGUgc2V0IGxhdGVyIGluIGxvYWQKICBjb2xfdHlwZXMgPSAiYyIsCiAgcmFuZ2UgPSBnb29nbGVzaGVldHM0OjpjZWxsX3Jvd3MoMTo4OCkgIyAyMDE4LCAyMDE2LCAyMDE0LCAyMDEyCikKCndyaXRlLmNzdihhc3Nlc3NtZW50X3NoZWV0LCBmaWxlID0gYXNzZXNzbWVudF9maWxlKQpgYGAKClRoZSBmb2xsb3dpbmcgcGxvdHMgYXJlIGJhc2VkIG9uIHRoZSBkYXRhIGZpbGUgYGAgYHIgYXNzZXNzbWVudF9maWxlYCBgYCwgdGhlIHJlc3VsdCBmcm9tIHRoZSBtYW51YWwgcmVwcm9kdWNpYmlsaXR5IGFzc2Vzc21lbnQuClRoZSBmaWxlIGBgIGByIGNvZGVib29rX2ZpbGVgIGBgIGNvbnRhaW5zIGEgY29kZWJvb2sgd2l0aCBuYW1lcywgbGFiZWxzLCBhbmQgZGVzY3JpcHRpb25zIGZvciB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhIGZpbGUgYXMgZG9jdW1lbnRhdGlvbiBvZiB0aGUgZGF0YXNldCBvdXRzaWRlIG9mIHRoaXMgY29tcHV0YXRpb25hbCBub3RlYm9vay4KCmBgYHtyIGxvYWRfZXZhbGRhdGF9CmNhdGVnb3J5X2xldmVscyA8LSBjKCIwIiwgIjEiLCAiMiIsICIzIikKcGFwZXJfZXZhbHVhdGlvbiA8LSByZWFkcjo6cmVhZF9jc3YoYXNzZXNzbWVudF9maWxlLCAKICAgIGNvbF90eXBlcyA9IHJlYWRyOjpjb2xzKAogICAgICBgY29uY2VwdHVhbCBwYXBlcmAgPSByZWFkcjo6Y29sX2xvZ2ljYWwoKSwKICAgICAgYGNvbXB1dGF0aW9uYWwgZW52aXJvbm1lbnRgID0gcmVhZHI6OmNvbF9mYWN0b3IobGV2ZWxzID0gY2F0ZWdvcnlfbGV2ZWxzKSwKICAgICAgYGlucHV0IGRhdGFgID0gcmVhZHI6OmNvbF9mYWN0b3IobGV2ZWxzID0gY2F0ZWdvcnlfbGV2ZWxzKSwKICAgICAgYG1ldGhvZC9hbmFseXNpcy9wcm9jZXNzaW5nYCA9IHJlYWRyOjpjb2xfZmFjdG9yKGxldmVscyA9IGNhdGVnb3J5X2xldmVscyksCiAgICAgIHByZXByb2Nlc3NpbmcgPSByZWFkcjo6Y29sX2ZhY3RvcihsZXZlbHMgPSBjYXRlZ29yeV9sZXZlbHMpLAogICAgICByZXN1bHRzID0gcmVhZHI6OmNvbF9mYWN0b3IobGV2ZWxzID0gY2F0ZWdvcnlfbGV2ZWxzKQogICAgICApLAogICAgbmEgPSAiTkEiKQoKcGFwZXJfZXZhbHVhdGlvbl93b19jb25jZXB0dWFsIDwtIGZpbHRlcihwYXBlcl9ldmFsdWF0aW9uLCBgY29uY2VwdHVhbCBwYXBlcmAgPT0gRkFMU0UpCgpjYXRlZ29yeUNvbHVtbnMgPC0gYygiaW5wdXQgZGF0YSIsIAogICAgICAgICAgICAgICAgICAgICAicHJlcHJvY2Vzc2luZyIsCiAgICAgICAgICAgICAgICAgICAgICJtZXRob2QvYW5hbHlzaXMvcHJvY2Vzc2luZyIsCiAgICAgICAgICAgICAgICAgICAgICJjb21wdXRhdGlvbmFsIGVudmlyb25tZW50IiwKICAgICAgICAgICAgICAgICAgICAgInJlc3VsdHMiKQpgYGAKCmBgYHtyIGNvcnB1c190YWJsZX0Kb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICctJykKa25pdHI6OmthYmxlKHBhcGVyX2V2YWx1YXRpb24gJT4lIAogICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1tYXRjaGVzKCJYMXxyZXZpZXdlcnxjb25jZXB0dWFsfGF1dGhvcnMiKSksCiAgICAgICAgICAgIGZvcm1hdCA9ICJodG1sIiwKICAgICAgICAgICAgYm9va3RhYnMgPSBUUlVFLAogICAgICAgICAgICBjYXB0aW9uID0gcGFzdGUwKCJSZXByb2R1Y2liaWxpdHkgbGV2ZWxzIGZvciBwYXBlciBjb3JwdXM7ICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIictJyBpcyBjYXRlZ29yeSBub3QgYXZhaWxhYmxlIikpICU+JQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKIyMgVGFibGU6IFN0YXRpc3RpY3Mgb2YgcmVwcm9kdWNpYmlsaXR5IGxldmVscyBwZXIgY3JpdGVyaW9uIGZvciBub24tY29uY2VwdHVhbCBwYXBlcnMKCmBgYHtyIHN1bW1hcnlfZXZhbGRhdGF9CmV2YWxkYXRhX251bWVyaWMgPC0gcGFwZXJfZXZhbHVhdGlvbl93b19jb25jZXB0dWFsICU+JQogICMgbXVzdCBjb252ZXJ0IGZhY3RvcnMgdG8gbnVtYmVycyB0byBjYWxjdWxhdGUgdGhlIG1lYW4gYW5kIG1lZGlhbgogIGRwbHlyOjptdXRhdGVfaWYoaXMuZmFjdG9yLCBsaXN0KH4gYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoLikpKSkKCiMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzIwMTE4NzMvZm9yY2Utc3VtbWFyeS10by1yZXBvcnQtdGhlLW51bWJlci1vZi1uYXMtZXZlbi1pZi1ub25lCnN1bW1hcnluYSA8LSBmdW5jdGlvbiAodikgewogIGlmKCFhbnkoaXMubmEodikpKXsKICAgIHJlcyA8LSBjKHN1bW1hcnkodiksIk5BJ3MiPTApCiAgfSBlbHNlewogICAgcmVzIDwtIHN1bW1hcnkodikKICB9CiAgcmV0dXJuKHJlcykKfQoKIyBhcHBseSBzdW1tYXJ5IGluZGVwZW5kZW50bHkgdG8gZm9ybWF0IGFzIHRhYmxlCnN1bW1hcmllcyA8LSBzYXBwbHkoZXZhbGRhdGFfbnVtZXJpY1ssY2F0ZWdvcnlDb2x1bW5zXSwgc3VtbWFyeW5hKQpleGNsdWRlX3ZhbHVlc19zdW1tYXJ5IDwtIGMoIjFzdCBRdS4iLCAiM3JkIFF1LiIpCgprYWJsZShzdWJzZXQoc3VtbWFyaWVzLCAhKHJvd25hbWVzKHN1bW1hcmllcykgJWluJSBleGNsdWRlX3ZhbHVlc19zdW1tYXJ5KSksIAogICAgICBkaWdpdHMgPSAxLAogICAgICBjb2wubmFtZXMgPSBjKCJpbnB1dCBkYXRhIiwgInByZXByb2MuIiwgIm1ldGhvZC9hbmFseXNpcy9wcm9jLiIsCiAgICAgICAgICAgICAgICAgICAgImNvbXAuIGVudi4iLCAicmVzdWx0cyIpLAogICAgICBjYXB0aW9uID0gIlN0YXRpc3RpY3Mgb2YgcmVwcm9kdWNpYmlsaXR5IGxldmVscyBwZXIgY3JpdGVyaW9uIChyb3VuZGVkIHRvIG9uZSBkZWNpbWFsIHBsYWNlKSIpICU+JQogIGthYmxlRXh0cmE6OnJvd19zcGVjKDAsIGJvbGQgPSBUUlVFKSAlPiUKICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGxhdGV4X29wdGlvbnMgPSBjKCJzdHJpcGVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250X3NpemUgPSA4KQpgYGAKClRoZSBwcmVwcm9jZXNzaW5nIGhhcyBgciBzdW0oIWlzLm5hKGV2YWxkYXRhX251bWVyaWMkcHJlcHJvY2Vzc2luZykpYCB2YWx1ZXMsIHdpdGggYDBgIGFuZCBgMWAgYXJvdW5kIHRoZSAibWlkZGxlIiByZXN1bHRpbmcgaW4gYSBmcmFjdGlvbiBhcyB0aGUgbWVkaWFuLgoKIyMgRGF0YSBwb2ludHMgZm9yIHRleHQKCmBgYHtyIGNyaXRlcmlhX251bWJlcnN9CmRhdGFfbGV2ZWxfemVybyA8LSBwYXBlcl9ldmFsdWF0aW9uX3dvX2NvbmNlcHR1YWwgJT4lIAogIGZpbHRlcihgaW5wdXQgZGF0YWAgPT0gMCkgJT4lIAogIGNvdW50KCkgJT4lIC4kbgoKZGF0YV9sZXZlbF90d28gPC0gcGFwZXJfZXZhbHVhdGlvbl93b19jb25jZXB0dWFsICU+JSAKICBmaWx0ZXIoYGlucHV0IGRhdGFgID09IDIpICU+JSAKICBjb3VudCgpICU+JSAuJG4KCnByZXByb2Nlc3NpbmdfaW5jbHVkZWQgPC0gcGFwZXJfZXZhbHVhdGlvbl93b19jb25jZXB0dWFsICU+JSAKICBmaWx0ZXIoIWlzLm5hKHByZXByb2Nlc3NpbmcpKSAlPiUgCiAgY291bnQoKSAlPiUgLiRuCgpwcmVwcm9jZXNzaW5nX2xldmVsX29uZSA8LSBwYXBlcl9ldmFsdWF0aW9uX3dvX2NvbmNlcHR1YWwgJT4lIAogIGZpbHRlcihwcmVwcm9jZXNzaW5nID09IDEpICU+JSAKICBjb3VudCgpICU+JSAuJG4KCm1ldGhvZHNfYW5kX3Jlc3VsdHNfZXFfb25lIDwtIHBhcGVyX2V2YWx1YXRpb25fd29fY29uY2VwdHVhbCAlPiUgCiAgZmlsdGVyKGBtZXRob2QvYW5hbHlzaXMvcHJvY2Vzc2luZ2AgPT0gMSAmIHJlc3VsdHMgPT0gMSkgJT4lIAogIGNvdW50KCkgJT4lIC4kbgogIApjb21wZW52X2xldmVsX3plcm8gPC0gcGFwZXJfZXZhbHVhdGlvbl93b19jb25jZXB0dWFsICU+JSAKICBmaWx0ZXIoYGNvbXB1dGF0aW9uYWwgZW52aXJvbm1lbnRgID09IDApICU+JSAKICBjb3VudCgpICU+JSAuJG4KYGBgCgpgciBkYXRhX2xldmVsX3plcm9gIHBhcGVycyBoYXZlIGxldmVsIGAwYCBhbmQgYHIgZGF0YV9sZXZlbF90d29gIGhhdmUgbGV2ZWwgYDJgIGluIHRoZSBkYXRhIGNyaXRlcmlvbi4KCmByIHByZXByb2Nlc3NpbmdfaW5jbHVkZWRgIHBhcGVycyBpbmNsdWRlIHNvbWUga2luZCBvZiBwcmVwcm9jZXNzaW5nLgoKYHIgbWV0aG9kc19hbmRfcmVzdWx0c19lcV9vbmVgIHBhcGVycyBoYXZlIGxldmVsIGAxYCBpbiBib3RoIG1ldGhvZHMgYW5kIHJlc3VsdHMgY3JpdGVyaW9uLgoKIyMgRmlndXJlOiBCYXJwbG90cyBvZiByZXByb2R1Y2liaWxpdHkgYXNzZXNzbWVudCByZXN1bHRzCgpgYGB7ciBmaWdfYXNzZXNzbWVudF9yZXN1bHRzLCBmaWcud2lkdGg9MTJ9CiMgbWF0Y2ggdGhlIGNvbG91cnMgdG8gdGltZSBzZXJpZXMgcGxvdCBiZWxvdwpjb2xvdXJzIDwtIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChsZW5ndGgoY2F0ZWdvcnlDb2x1bW5zKSwgIlNldDEiKQpsZXZlbF9uYW1lcyA8LSBjKCIwIiwgIjEiLCAiMiIsICIzIiwgTkEpCmJyZWFrcyA8LSBzZXEoZnJvbSA9IDAsIHRvID0gbnJvdyhwYXBlcl9ldmFsdWF0aW9uX3dvX2NvbmNlcHR1YWwpLCBieSA9IDEwKQoKY3JpdGVyaWFCYXJwbG90ID0gZnVuY3Rpb24oY2F0ZWdvcnksIG1haW4sIGNvbG91cikgewogIGNhdCA8LSBlbnF1byhjYXRlZ29yeSkKICBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YSA9IHBhcGVyX2V2YWx1YXRpb25fd29fY29uY2VwdHVhbCwKICAgICAgICAgICAgICAgIGFlcyghIWNhdCksCiAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2JhcihmaWxsID0gY29sb3Vyc1tjb2xvdXJdLCBjb2xvciA9ICJibGFjayIpICsKICAgIGdncGxvdDI6OmdndGl0bGUobWFpbikgKwogICAgZ2dwbG90Mjo6eGxhYigiTGV2ZWwiKSArCiAgICBnZ3Bsb3QyOjp4bGltKGxldmVsX25hbWVzKSArCiAgICBnZ3Bsb3QyOjp5bGFiKCIiKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYnJlYWtzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IHJhbmdlKGJyZWFrcykpICsKICAgIGdndGhlbWVzOjp0aGVtZV90dWZ0ZShiYXNlX3NpemUgPSA4KSArIHRoZW1lKGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkKfQoKZmlnX2JhcnBsb3QgPC0gcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKAogIG5jb2wgPSA1LAogIGNyaXRlcmlhQmFycGxvdChgaW5wdXQgZGF0YWAsICAgIG1haW4gPSAiSW5wdXQgZGF0YSIsICAgIGNvbG91ciA9IDEpLAogIGNyaXRlcmlhQmFycGxvdChgcHJlcHJvY2Vzc2luZ2AsIG1haW4gPSAiUHJlcHJvY2Vzc2luZyIsIGNvbG91ciA9IDIpLAogIGNyaXRlcmlhQmFycGxvdChgbWV0aG9kL2FuYWx5c2lzL3Byb2Nlc3NpbmdgLAogICAgICAgICAgICAgICAgICBtYWluID0gIk1ldGhvZHMvQW5hbHlzaXMvXG5Qcm9jZXNzaW5nIiwgIGNvbG91ciA9IDMpLAogIGNyaXRlcmlhQmFycGxvdChgY29tcHV0YXRpb25hbCBlbnZpcm9ubWVudGAsCiAgICAgICAgICAgICAgICAgIG1haW4gPSAiQ29tcHV0YXRpb25hbFxuRW52aXJvbm1lbnQiLCBjb2xvdXIgPSA0KSwKICBjcml0ZXJpYUJhcnBsb3QocmVzdWx0cywgICAgICAgICBtYWluID0gIlJlc3VsdHMiLCBjb2xvdXIgPSA1KQopCgpmaWdfYmFycGxvdApgYGAKCiMjIEZpZ3VyZTogQWxsdXZpYWwgZGlhZ3JhbW1lIG9mIHJlcHJvZHVjaWJpbGl0eSBhc3Nlc3NtZW50IHJlc3VsdHMgYWNyb3NzIGNhdGVnb3JpZXMKClRoaXMgZmlndXJlIGlzIGJhc2VkIG9uIHBhY2thZ2UgW2BnZ2FsbHV2aWFsYF0oaHR0cHM6Ly9jb3J5YnJ1bnNvbi5naXRodWIuaW8vZ2dhbGx1dmlhbC8pLgpJdCBkb2VzIG5vdCBpbmNsdWRlIHRoZSBjYXRlZ29yeSBgcHJlcHJvY2Vzc2luZ2AgYmVjYXVzZSBpdCB3YXMgZGlzY292ZXJlZCB0byBiZSBxdWl0ZSBoYXJkIHRvIGFzc2VzcywgYW5kIHN1YnNlcXVlbnRseSBoYXMgYSBsYXJnZSBzaGFyZSBvZiBtaXNzaW5nIHZhbHVlcy4KVGhlIGZpZ3VyZSBhbHNvIGRvZXMgX25vdF8gaW5jbHVkZSBhbnkgcGFwZXJzIHdobyBoYXZlIG9uZSBvciBtb3JlIGNhdGVnb3JpZXMgYXMgYE5BYCwgYXMgdGhhdCBtZWFucyAibm90IGFzc2Vzc2FibGUiLgoKYGBge3IgZGF0YV9hbGx1dmlhbH0KcGFwZXJzX3dvX25hX3dvX3ByZXByIDwtIHBhcGVyX2V2YWx1YXRpb25fd29fY29uY2VwdHVhbCAlPiUKICBkcm9wX25hKCkgJT4lCiAgbXV0YXRlX2lmKGlzLmZhY3RvciwgZm9yY2F0czo6ZmN0X3JldikgJT4lCiAgZ3JvdXBfYnkoYGlucHV0IGRhdGFgLAogICAgICAgICAgIGBtZXRob2QvYW5hbHlzaXMvcHJvY2Vzc2luZ2AsCiAgICAgICAgICAgYGNvbXB1dGF0aW9uYWwgZW52aXJvbm1lbnRgLAogICAgICAgICAgIHJlc3VsdHMpICU+JQogIHRhbGx5KCkgJT4lCiAgbXV0YXRlKGBDYXRlZ29yeSBsZXZlbHMgKCMpYCA9IHBhc3RlMChgaW5wdXQgZGF0YWAsICIgIiwKICAgICAgICAgICAgICAgICAgICAgICBgbWV0aG9kL2FuYWx5c2lzL3Byb2Nlc3NpbmdgLCAiICIsCiAgICAgICAgICAgICAgICAgICAgICAgYGNvbXB1dGF0aW9uYWwgZW52aXJvbm1lbnRgLCAiICIsCiAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cywgIiAoIiwgbiwgIikiKSkKYGBgCgpgYGB7ciBmaWdfYWxsdXZpYWwsIHdhcm5pbmc9RkFMU0V9CmZpZ19hbGx1dmlhbCA8LSBnZ3Bsb3QoZGF0YSA9IHBhcGVyc193b19uYV93b19wcmVwciwKICAgICAgIGFlcyhheGlzMSA9IGBpbnB1dCBkYXRhYCwKICAgICAgICAgICBheGlzMiA9IGBtZXRob2QvYW5hbHlzaXMvcHJvY2Vzc2luZ2AsCiAgICAgICAgICAgYXhpczMgPSBgY29tcHV0YXRpb25hbCBlbnZpcm9ubWVudGAsCiAgICAgICAgICAgYXhpczQgPSByZXN1bHRzLAogICAgICAgICAgIHkgPSBuKQogICAgICAgKSArCiAgZ2dwbG90Mjo6c2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJJbnB1dCBEYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1ldGhvZHMvXG5BbmFseXNpcy9cblByb2Nlc3NpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tcHV0YXRpb25hbFxuRW52aXJvbm1lbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVzdWx0cyIpLAogICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYyguMSwgMCkKICAgICAgICAgICAgICAgICAgICkgKwogIHhsYWIoIkNhdGVnb3J5IikgKwogIHlsYWIoIk51bWJlciBvZiBwYXBlcnMiKSArCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygKICAgIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg5LCAiU2V0MSIpLCAgICAgICAgICAgICMgY29sb3VycyBmcm9tIHRoZSBvdGhlciBwbG90cwogICAgUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDQsICJEYXJrMiIpW2MoMSwzLDQpXSkgIyBtYW51YWxseSBjaG9zZW4gZnJvbSBhbm90aGVyIHBhbGV0dGUKICAgICkgKwogIGdnYWxsdXZpYWw6Omdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBgQ2F0ZWdvcnkgbGV2ZWxzICgjKWApLCB3aWR0aCA9IDEvMykgKwogIGdnYWxsdXZpYWw6Omdlb21fc3RyYXR1bShhbHBoYSA9IDEpICsKICBnZ2ZpdHRleHQ6Omdlb21fZml0X3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksIG1pbi5zaXplID0gMSkgKwogIGdndGhlbWVzOjp0aGVtZV90dWZ0ZSgpCgpmaWdfYWxsdXZpYWwKYGBgCgojIyBUYWJsZTogTWVhbiBsZXZlbHMgcGVyIGNyaXRlcmlvbiBmb3Igbm9uLWNvbmNlcHR1YWwgcGFwZXJzCgpgYGB7ciBzdW1tYXJ5X2V2YWxkYXRhX2dyb3VwZWR9Cm1lYW5zIDwtIGxhcHBseShldmFsZGF0YV9udW1lcmljICU+JQogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGFsbF9vZihjYXRlZ29yeUNvbHVtbnMpKSwKICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5KSAlPiUKICAgIGxhcHBseShgW1tgLCAiTWVhbiIpICU+JQogICAgYXMuZGF0YS5mcmFtZSgpCgprYWJsZShtZWFucywKICAgICAgZGlnaXRzID0gMiwKICAgICAgY29sLm5hbWVzID0gYygiaW5wdXQgZGF0YSIsICJwcmVwcm9jLiIsICJtZXRob2QvYW5hbHlzaXMvcHJvYy4iLCAiY29tcC4gZW52LiIsICJyZXN1bHRzIiksCiAgICAgIGNhcHRpb24gPSAiTWVhbiBsZXZlbHMgcGVyIGNyaXRlcmlvbiBmb3Igbm9uLWNvbmNlcHR1YWwgcGFwZXJzIikgJT4lCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgojIyBUYWJsZTogTWVhbiBsZXZlbHMgYXZlcmFnZWQgYWNyb3NzIGNyaXRlcmlhIG92ZXIgdGltZSBmb3Igbm9uLWNvbmNlcHR1YWwgcGFwZXJzCgpgYGB7ciBldmFsZGF0YV9zdW1tYXJ5X2J5X3llYXJfbWVhbn0KbWVhbnNfeWVhcnMgPC0gZXZhbGRhdGFfbnVtZXJpYyAlPiUKICBmaWx0ZXIoYGNvbmNlcHR1YWwgcGFwZXJgID09IEZBTFNFKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oYyhgaW5wdXQgZGF0YWAsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHByZXByb2Nlc3NpbmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGBtZXRob2QvYW5hbHlzaXMvcHJvY2Vzc2luZ2AsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGBjb21wdXRhdGlvbmFsIGVudmlyb25tZW50YCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYHJlc3VsdHNgKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgYHBhcGVyIGNvdW50YCA9IG4oKSkKCm1lYW5zX3llYXJzX3RhYmxlIDwtIG1lYW5zX3llYXJzICU+JSAKICAgICAgICBtdXRhdGUobWVhbiA9IHJvdW5kKG1lYW4sIDIpLCAKICAgICAgICAgICAgICAgYHBhcGVyIGNvdW50YCA9IGFzLmNoYXJhY3RlcihgcGFwZXIgY291bnRgKSkgJT4lCiAgICAgICAgbXV0YXRlKGxhYmVscyA9IHN0cl9jKHllYXIsICIgKG4gPSAiLCBgcGFwZXIgY291bnRgLCAiKSIpKSAlPiUKICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoImxhYmVscyIpICU+JQogICAgICAgIHNlbGVjdChtZWFuKSAlPiUKICAgICAgICB0KCkKCmthYmxlKG1lYW5zX3llYXJzX3RhYmxlLAogICAgICBjYXB0aW9uID0gIlN1bW1hcmlzZWQgbWVhbiB2YWx1ZXMgb3ZlciBhbGwgY3JpdGVyaWEgb3ZlciB0aW1lIChub24tY29uY2VwdHVhbCBwYXBlcnMpIikgJT4lCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUUlVFKQpgYGAKCiMjIEZpZ3VyZTogTWVhbiByZXByb2R1Y2liaWxpdHkgbGV2ZWxzIHBlciBjYXRlZ29yeSBvdmVyIHRpbWUgZm9yIG5vbi1jb25jZXB0dWFsIHBhcGVycwoKYGBge3IgRmlnNCxmaWcuaGVpZ2h0PTQsZHBpPTMwMH0KZXZhbGRhdGFfeWVhcnMgPC0gZXZhbGRhdGFfbnVtZXJpYyAlPiUKICBmaWx0ZXIoYGNvbmNlcHR1YWwgcGFwZXJgID09IEZBTFNFKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UoaW5wdXQgPSBtZWFuKGBpbnB1dCBkYXRhYCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgcHJlcHJvY2Vzc2luZyA9IG1lYW4ocHJlcHJvY2Vzc2luZywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWV0aG9kID0gbWVhbihgbWV0aG9kL2FuYWx5c2lzL3Byb2Nlc3NpbmdgLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBlbnZpcm9ubWVudCA9IG1lYW4oYGNvbXB1dGF0aW9uYWwgZW52aXJvbm1lbnRgLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICByZXN1bHRzID0gbWVhbihyZXN1bHRzLCBuYS5ybSA9IFRSVUUpKQpwYXBlcl9jb3VudF95ZWFycyA8LSBldmFsZGF0YV9udW1lcmljICU+JQogIGZpbHRlcihgY29uY2VwdHVhbCBwYXBlcmAgPT0gRkFMU0UpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIHN1bW1hcmlzZShgcGFwZXIgY291bnRgID0gbigpKQoKZXZhbGRhdGFfeWVhcnNfbG9uZyA8LSBtZWx0KGV2YWxkYXRhX3llYXJzLCBpZC52YXJzID0gYygieWVhciIpKQpmaWdfbWVhbl9vdmVyX3RpbWUgPC0gZ2dwbG90KGV2YWxkYXRhX3llYXJzX2xvbmcsIGFlcyh5ZWFyLCB2YWx1ZSkpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IHZhcmlhYmxlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICNnZW9tX2Vycm9yYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1bi5kYXRhID0gIm1lYW5fc2RsIiwgCiAgIyAgICAgICAgICAgICAgICBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpLAogICMgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArCiAgeWxhYigibWVhbiB2YWx1ZSBvZiBjcml0ZXJpb24gbGV2ZWwiKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBldmFsZGF0YV95ZWFycyR5ZWFyLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwYXN0ZTAocGFwZXJfY291bnRfeWVhcnMkeWVhciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIChuPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFwZXJfY291bnRfeWVhcnMkYHBhcGVyIGNvdW50YCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZSA9ICJDYXRlZ29yeSIpICsKICBnZ3RoZW1lczo6dGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMTUsMC43NSksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsKICB5bGltKDAsIDMpICsKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZnVuLm1pbiA9IG1lYW4sIGZ1bi5tYXggPSBtZWFuLCBzaGFwZSA9ICItIiwgc2l6ZSA9IDIpICsKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgbGluZXR5cGUgPSAiZG90dGVkIiwgbWFwcGluZyA9IGFlcyhncm91cCA9IDEpKQoKZmlnX21lYW5fb3Zlcl90aW1lCmBgYAoKIyMgQ29sb3Bob24KClRoaXMgZG9jdW1lbnQgaXMgbGljZW5zZWQgdW5kZXIgYSBbQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbiA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlXShodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvNC4wLykuCkFsbCBjb250YWluZWQgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgW0FwYWNoZSBMaWNlbnNlIDIuMF0oaHR0cHM6Ly9jaG9vc2VhbGljZW5zZS5jb20vbGljZW5zZXMvYXBhY2hlLTIuMC8pLgpUaGlzIGRvY3VtZW50IGlzIHZlcnNpb25lZCBpbiBhIHB1YmxpYyBbZ2l0XShodHRwczovL2dpdC1zY20uY29tLykgcmVwb3NpdG9yeSwgW2h0dHBzOi8vZ2l0aHViLmNvbS9udWVzdC9yZXByb2R1Y2libGUtcmVzZWFyY2gtYXQtZ2lzY2llbmNlXShodHRwczovL2dpdGh1Yi5jb20vbnVlc3QvcmVwcm9kdWNpYmxlLXJlc2VhcmNoLWF0LWdpc2NpZW5jZSksIGFuZCBhcmNoaXZlZCBvbiBaZW5vZG8gYXQgW2h0dHBzOi8vZG9pLm9yZy8xMC41MjgxL3plbm9kby40MDMyODc1XShodHRwczovL2RvaS5vcmcvMTAuNTI4MS96ZW5vZG8uNDAzMjg3NSkuCgoqKlJ1bnRpbWUgZW52aXJvbm1lbnQgZGVzY3JpcHRpb246KioKCmBgYHtyIHNlc3Npb25faW5mbywgZWNobz1GQUxTRX0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkKZGV2dG9vbHM6OnNlc3Npb25faW5mbyhpbmNsdWRlX2Jhc2UgPSBUUlVFKQpgYGAKCmBgYHtyIHVwbG9hZF90b19kcml2ZSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyB1cGxvYWQgdGhlIEhUTUwgZmlsZSB0byB0aGUgUmVwcm9kdWNpYmlsaXR5IENvbW1pdHRlZSBzaGFyZWQgZm9sZGVyCiMgdXBsb2FkIHRoZSBIVE1MIGZpbGUgYW5kIHNvdXJjZSBjb2RlIHRvIHRoZSBSZXByb2R1Y2liaWxpdHkgQ29tbWl0dGVlIHNoYXJlZCBmb2xkZXIKZ29vZ2xlZHJpdmU6OmRyaXZlX2F1dGgodXNlX29vYiA9IFRSVUUpCmdvb2dsZWRyaXZlOjpkcml2ZV9wdXQoImdpc2NpZW5jZS1yZXByb2R1Y2liaWxpdHktYXNzZXNzbWVudC5odG1sIiwgcGF0aCA9IGdvb2dsZWRyaXZlOjphc19kcmliYmxlKCJodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZHJpdmUvZm9sZGVycy8xN0VVdE1fekN4MWdRTWVhMU1ITl81WFNWcnNzeHY5R0EiKSkKZ29vZ2xlZHJpdmU6OmRyaXZlX3B1dCgiZ2lzY2llbmNlLXJlcHJvZHVjaWJpbGl0eS1hc3Nlc3NtZW50LlJtZCIsIHBhdGggPSBnb29nbGVkcml2ZTo6YXNfZHJpYmJsZSgiaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2RyaXZlL2ZvbGRlcnMvMTdFVXRNX3pDeDFnUU1lYTFNSE5fNVhTVnJzc3h2OUdBIikpCmBgYAo=