Load and clean data

library(tidyverse)
library(janitor)
library(here)

set.seed(1234)
# Constraints -------------------------------------------------------------

constraint_levels <- function(x) {
  filter(constraints, constraint == x) %>% 
    pull(levels_clean) %>%
    .[[1]]
}

constraints <- tribble(
  ~constraint, ~constraint_clean, ~levels_clean,
  "create_network", "Network creation", list("Network creation" = "T", "No network creation" = "F"),
  "select", "Selection", list("Selection" = "T", "No selection" = "F"),
  "disperse", "Dispersal", list("Dispersal" = "T", "No dispersal" = "F"),
  "compete", "Competition", list("Competition" = "T", "No competition" = "F"),
  "selectfor_d", "Selection for D", list("Selection" = "T", "No selection" = "F"),
  "catastrophe", "Catastrophe", list("Catastrophe" = "T", "No catastrophe" = "F")
)

saveRDS(constraints, here("data", "derived_data", "constraints.rds"))


# High/low ----------------------------------------------------------------

BHL <- read_rds(here("data", "raw_data", "BHL.rds")) %>% 
  clean_names(case = "snake") %>%   # Get rid of invalid characters in column names
  rename_all(list(~str_remove_all(., "yn$"))) %>%  # Get rid of "yn" in column names
  # Clean up constraint values
  mutate(create_network = fct_recode(create_network, !!!constraint_levels("create_network")),
         select = fct_recode(select, !!!constraint_levels("select")),
         disperse = fct_recode(disperse, !!!constraint_levels("disperse")),
         compete = fct_recode(compete, !!!constraint_levels("compete")),
         selectfor_d = fct_recode(selectfor_d, !!!constraint_levels("selectfor_d")),
         catastrophe = fct_recode(catastrophe, !!!constraint_levels("catastrophe"))) %>% 
  mutate_at(vars(one_of(constraints$constraint)), list(~ fct_inorder(.))) %>% 
  mutate(repp = factor(repp, levels = c(1, 2), labels = c("High", "Low"), ordered = TRUE))

BHL_small <- BHL %>% 
  group_by(repp) %>% 
  sample_frac(size = 0.1) %>% 
  ungroup()

sim_hl <- BHL_small %>% 
  # Make new columns with "_constraint" suffix that show if constraint is T/F
  # instead of using the label. e.g. "Selection" becomes TRUE, "No selection"
  # becomes FALSE
  mutate_at(vars(one_of(constraints$constraint)),
            list(constraint = ~as.logical(-as.integer(.) + 2L))) %>%
  # Count how many of the constraints are TRUE in each row
  mutate(n_constraints = reduce(select(., ends_with("_constraint")), `+`)) %>%
  # Make a factor version of the constraint count for plotting
  mutate(n_constraints_f = as.factor(n_constraints)) %>% 
  mutate(turnover_diff = landscape_linked_species_mean_turnover - landscape_unlinked_species_mean_turnover)

saveRDS(BHL, here("data", "derived_data", "BHL.rds"))
saveRDS(BHL_small, here("data", "derived_data", "BHL_small.rds"))
saveRDS(sim_hl, here("data", "derived_data", "sim_hl.rds"))


# Latin squares -----------------------------------------------------------

BLS <- read_rds(here("data", "raw_data", "BLS.rds")) %>% 
  clean_names(case = "snake") %>%   # Get rid of invalid characters in column names
  rename_all(list(~str_remove_all(., "yn$"))) %>%  # Get rid of "yn" in column names
  # Clean up constraint values
  mutate(create_network = fct_recode(create_network, !!!constraint_levels("create_network")),
         select = fct_recode(select, !!!constraint_levels("select")),
         disperse = fct_recode(disperse, !!!constraint_levels("disperse")),
         compete = fct_recode(compete, !!!constraint_levels("compete")),
         selectfor_d = fct_recode(selectfor_d, !!!constraint_levels("selectfor_d")),
         catastrophe = fct_recode(catastrophe, !!!constraint_levels("catastrophe"))) %>% 
  mutate_at(vars(one_of(constraints$constraint)), list(~fct_inorder(.)))

BLS_small <- BLS %>% 
  sample_frac(size = 0.1)

sim_ls <- BLS_small %>%
  # Make new columns with "_constraint" suffix that show if constraint is T/F
  # instead of using the label. e.g. "Selection" becomes TRUE, "No selection"
  # becomes FALSE
  mutate_at(vars(one_of(constraints$constraint)),
            list(constraint = ~as.logical(-as.integer(.) + 2L))) %>%
  # Count how many of the constraints are TRUE in each row
  mutate(n_constraints = reduce(select(., ends_with("_constraint")), `+`)) %>%
  # Make a factor version of the constraint count for plotting
  mutate(n_constraints_f = as.factor(n_constraints)) %>% 
  mutate(turnover_diff = landscape_linked_species_mean_turnover - landscape_unlinked_species_mean_turnover)

saveRDS(BLS, here("data", "derived_data", "BLS.rds"))
saveRDS(BLS_small, here("data", "derived_data", "BLS_small.rds"))
saveRDS(sim_ls, here("data", "derived_data", "sim_ls.rds"))

Create columns for every combination of constraint in the data (e.g. select, select & disperse, select & disperse & create_network, etc.)

(By the inimitable Vincent Arel-Bundock)

make_combinations <- function(df, m = 5) {
  com <- colnames(df)[2:ncol(df)] %>%
    combn(m) %>%
    as_tibble()
  out <- com %>%
    map(~ df[.]) %>%
    map(~ rowSums(.) == ncol(.)) %>%
    setNames(map(com, paste, collapse = " + ")) %>%
    as_tibble()
  return(out)
}

outcomes <- c("landscape_fitness_linked", "avg_evenness_t", "var_fitness", 
              "landscape_richness_mean", "landscape_linked_species_mean_turnover",
              "turnover_diff")

# High/low ----------------------------------------------------------------

# Select just the run number and *_constraint TRUE/FALSE columns
constraint_combinations_hl <- sim_hl %>%
  select(runnum, ends_with("_constraint")) %>%
  # Shrink names by removing "_constraint"
  rename_at(vars(ends_with("constraint")),
            list(~str_replace_all(., "_constraint", "")))

# Find all combinations of variables (m = number of items in combination; m = 2
# means pairs, m = 3 means triplets, etc.)
all_constraint_combos_hl <- map(2:6, ~make_combinations(constraint_combinations_hl, m = .)) %>%
  bind_cols(constraint_combinations_hl, .)

# Select the outcome variables we care about and join the constraint combinations
constraint_combo_outcomes_hl <- sim_hl %>%
  select(runnum, repp, n_constraints, one_of(outcomes)) %>%
  right_join(all_constraint_combos_hl, by = "runnum")

# Don't double count rows. If a row has two constraints like select and
# disperse, it'll also have select + disperse set to TRUE. If that's the case,
# we don't want to include it in just select or just disperse
constraint_combo_outcomes_hl_nested <- constraint_combo_outcomes_hl %>%
  select(-n_constraints) %>%
  # Make long
  gather(constraint_combo, value, -runnum, -repp, -one_of(outcomes)) %>%
  # Count how many constraints there are within each row based on + signs
  mutate(n = str_count(constraint_combo, "\\+") + 1) %>%
  # Only keep rows where the constraint is turned on
  filter(value == TRUE) %>%
  # Nest all the constraint combinations within each row
  group_by(runnum) %>%
  nest()

# Only keep the values where n == max(n) for that row
# This takes ≈2 minutes
constraint_combo_outcomes_hl_filtered <- constraint_combo_outcomes_hl_nested %>%
  mutate(filtered = data %>% map(~filter(., n == max(.$n)))) %>%
  select(-data) %>%
  unnest(filtered)

# This omitted all the rows where n_constraints == 0, so add those back in
no_constraints_hl <- constraint_combo_outcomes_hl %>%
  filter(n_constraints == 0) %>%
  mutate(constraint_combo = "No constraints", n = 0) %>%
  select(runnum, repp, one_of(outcomes), constraint_combo, n)

constraint_combo_outcomes_hl_done <- bind_rows(constraint_combo_outcomes_hl_filtered,
                                               no_constraints_hl) %>%
  select(-value)

saveRDS(constraint_combo_outcomes_hl_done, 
        here("data", "derived_data", "constraint_combo_outcomes_hl.rds"))


# Latin squares -----------------------------------------------------------

# Select just the run number and *_constraint TRUE/FALSE columns
constraint_combinations_ls <- sim_ls %>%
  select(runnum, ends_with("_constraint")) %>% 
  # Shrink names by removing "_constraint"
  rename_at(vars(ends_with("constraint")), 
            list(~str_replace_all(., "_constraint", "")))

# Find all combinations of variables (m = number of items in combination; m = 2
# means pairs, m = 3 means triplets, etc.)
all_constraint_combos_ls <- map(2:6, ~make_combinations(constraint_combinations_ls, m = .)) %>% 
  bind_cols(constraint_combinations_ls, .)

# Select the outcome variables we care about and join the constraint combinations
constraint_combo_outcomes_ls <- sim_ls %>%
  select(runnum, n_constraints, one_of(outcomes)) %>% 
  right_join(all_constraint_combos_ls, by = "runnum")

# Don't double count rows. If a row has two constraints like select and
# disperse, it'll also have select + disperse set to TRUE. If that's the case,
# we don't want to include it in just select or just disperse
constraint_combo_outcomes_ls_nested <- constraint_combo_outcomes_ls %>% 
  select(-n_constraints) %>% 
  # Make long
  gather(constraint_combo, value, -runnum, -one_of(outcomes)) %>% 
  # Count how many constraints there are within each row based on + signs
  mutate(n = str_count(constraint_combo, "\\+") + 1) %>%
  # Only keep rows where the constraint is turned on
  filter(value == TRUE) %>%
  # Nest all the constraint combinations within each row
  group_by(runnum) %>% 
  nest()

# Only keep the values where n == max(n) for that row
# This takes ≈1 minute
constraint_combo_outcomes_ls_filtered <- constraint_combo_outcomes_ls_nested %>% 
  mutate(filtered = data %>% map(~filter(., n == max(.$n)))) %>% 
  select(-data) %>% 
  unnest(filtered)

# This omitted all the rows where n_constraints == 0, so add those back in
no_constraints_ls <- constraint_combo_outcomes_ls %>% 
  filter(n_constraints == 0) %>% 
  mutate(constraint_combo = "No constraints", n = 0) %>% 
  select(runnum, one_of(outcomes), constraint_combo, n)

constraint_combo_outcomes_ls_done <- bind_rows(constraint_combo_outcomes_ls_filtered,
                                               no_constraints_ls) %>% 
  select(-value)

saveRDS(constraint_combo_outcomes_ls_done, 
        here("data", "derived_data", "constraint_combo_outcomes_ls.rds"))

Data details:

  • High-low full: 1,280,000 rows
    • High: 640,000 rows
    • Low: 640,000 rows
  • High-low small: 128,000 rows
    • High: 64,000 rows
    • Low: 64,000 rows
  • Latin squares full: 640,000 rows
  • Latin squares small: 64,000 rows


Original computing environment

writeLines(readLines(file.path(Sys.getenv("HOME"), ".R/Makevars")))
## # http://dirk.eddelbuettel.com/blog/2017/11/27/#011_faster_package_installation_one
## # VER=
## # CCACHE=ccache
## # CC=$(CCACHE) gcc$(VER)
## # CXX=$(CCACHE) g++$(VER)
## # CXXFLAGS=-O3 #-Wno-unused-variable -Wno-unused-function -Wno-unused-local-typedefs
## # CXX11=$(CCACHE) g++$(VER)
## # CXX14=$(CCACHE) g++$(VER)
## # FC=$(CCACHE) gfortran$(VER)
## # F77=$(CCACHE) gfortran$(VER)
## 
## # clang: start
## CFLAGS=-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
## CCFLAGS=-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
## CXXFLAGS=-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
## CPPFLAGS=-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I/usr/local/include
## 
## SHLIB_CXXLDFLAGS+=-Wl,-rpath,${R_HOME}/lib ${R_HOME}/lib/libc++abi.1.dylib
## SHLIB_CXX14LDFLAGS+=-Wl,-rpath,${R_HOME}/lib ${R_HOME}/lib/libc++abi.1.dylib
## # clang: end
## 
## CXX14FLAGS=-O3 -march=native -mtune=native
## CXX14FLAGS += -arch x86_64 -ftemplate-depth-256
devtools::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.3 (2020-02-29)
##  os       macOS Catalina 10.15.4      
##  system   x86_64, darwin15.6.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       America/New_York            
##  date     2020-04-23                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version    date       lib source                            
##  assertthat    0.2.1      2019-03-21 [1] CRAN (R 3.6.0)                    
##  backports     1.1.6      2020-04-05 [1] CRAN (R 3.6.2)                    
##  base64enc     0.1-3      2015-07-28 [1] CRAN (R 3.6.0)                    
##  broom         0.5.3.9000 2020-04-01 [1] Github (tidymodels/broom@3c922d5) 
##  callr         3.4.3      2020-03-28 [1] CRAN (R 3.6.2)                    
##  cellranger    1.1.0      2016-07-27 [1] CRAN (R 3.6.0)                    
##  cli           2.0.2      2020-02-28 [1] CRAN (R 3.6.0)                    
##  colorspace    1.4-1      2019-03-18 [1] CRAN (R 3.6.0)                    
##  crayon        1.3.4      2017-09-16 [1] CRAN (R 3.6.0)                    
##  DBI           1.1.0      2019-12-15 [1] CRAN (R 3.6.0)                    
##  dbplyr        1.4.2      2019-06-17 [1] CRAN (R 3.6.0)                    
##  desc          1.2.0      2018-05-01 [1] CRAN (R 3.6.0)                    
##  devtools      2.2.2      2020-02-17 [1] CRAN (R 3.6.0)                    
##  digest        0.6.25     2020-02-23 [1] CRAN (R 3.6.0)                    
##  dplyr       * 0.8.5      2020-03-07 [1] CRAN (R 3.6.0)                    
##  ellipsis      0.3.0      2019-09-20 [1] CRAN (R 3.6.0)                    
##  evaluate      0.14       2019-05-28 [1] CRAN (R 3.6.0)                    
##  fansi         0.4.1      2020-01-08 [1] CRAN (R 3.6.0)                    
##  forcats     * 0.5.0      2020-03-01 [1] CRAN (R 3.6.0)                    
##  fs            1.3.2      2020-03-05 [1] CRAN (R 3.6.0)                    
##  generics      0.0.2      2018-11-29 [1] CRAN (R 3.6.0)                    
##  ggplot2     * 3.3.0.9000 2020-04-23 [1] Github (tidyverse/ggplot2@d3d47be)
##  glue          1.4.0      2020-04-03 [1] CRAN (R 3.6.2)                    
##  gtable        0.3.0      2019-03-25 [1] CRAN (R 3.6.0)                    
##  haven         2.2.0      2019-11-08 [1] CRAN (R 3.6.0)                    
##  here        * 0.1        2017-05-28 [1] CRAN (R 3.6.0)                    
##  hms           0.5.3      2020-01-08 [1] CRAN (R 3.6.0)                    
##  htmltools     0.4.0      2019-10-04 [1] CRAN (R 3.6.0)                    
##  httr          1.4.1      2019-08-05 [1] CRAN (R 3.6.0)                    
##  janitor     * 2.0.1      2020-04-12 [1] CRAN (R 3.6.2)                    
##  jsonlite      1.6.1      2020-02-02 [1] CRAN (R 3.6.0)                    
##  knitr         1.28       2020-02-06 [1] CRAN (R 3.6.0)                    
##  lifecycle     0.2.0      2020-03-06 [1] CRAN (R 3.6.0)                    
##  lubridate     1.7.4      2018-04-11 [1] CRAN (R 3.6.0)                    
##  magrittr      1.5        2014-11-22 [1] CRAN (R 3.6.0)                    
##  memoise       1.1.0      2017-04-21 [1] CRAN (R 3.6.0)                    
##  modelr        0.1.6      2020-02-22 [1] CRAN (R 3.6.0)                    
##  munsell       0.5.0      2018-06-12 [1] CRAN (R 3.6.0)                    
##  pillar        1.4.3      2019-12-20 [1] CRAN (R 3.6.0)                    
##  pkgbuild      1.0.6      2019-10-09 [1] CRAN (R 3.6.0)                    
##  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 3.6.0)                    
##  pkgload       1.0.2      2018-10-29 [1] CRAN (R 3.6.0)                    
##  prettyunits   1.1.1      2020-01-24 [1] CRAN (R 3.6.0)                    
##  processx      3.4.2      2020-02-09 [1] CRAN (R 3.6.0)                    
##  ps            1.3.2      2020-02-13 [1] CRAN (R 3.6.0)                    
##  purrr       * 0.3.4      2020-04-17 [1] CRAN (R 3.6.2)                    
##  R6            2.4.1      2019-11-12 [1] CRAN (R 3.6.0)                    
##  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.0)                    
##  readxl        1.3.1      2019-03-13 [1] CRAN (R 3.6.0)                    
##  remotes       2.1.1      2020-02-15 [1] CRAN (R 3.6.0)                    
##  reprex        0.3.0      2019-05-16 [1] CRAN (R 3.6.0)                    
##  rlang         0.4.5      2020-03-01 [1] CRAN (R 3.6.0)                    
##  rmarkdown     2.1        2020-01-20 [1] CRAN (R 3.6.0)                    
##  rprojroot     1.3-2      2018-01-03 [1] CRAN (R 3.6.0)                    
##  rstudioapi    0.11       2020-02-07 [1] CRAN (R 3.6.0)                    
##  rvest         0.3.5      2019-11-08 [1] CRAN (R 3.6.0)                    
##  scales        1.1.0      2019-11-18 [1] CRAN (R 3.6.0)                    
##  sessioninfo   1.1.1      2018-11-05 [1] CRAN (R 3.6.0)                    
##  snakecase     0.11.0     2019-05-25 [1] CRAN (R 3.6.0)                    
##  stringi       1.4.6      2020-02-17 [1] CRAN (R 3.6.0)                    
##  stringr     * 1.4.0      2019-02-10 [1] CRAN (R 3.6.0)                    
##  testthat      2.3.2      2020-03-02 [1] CRAN (R 3.6.0)                    
##  tibble      * 3.0.1      2020-04-20 [1] CRAN (R 3.6.2)                    
##  tidyr       * 1.0.2      2020-01-24 [1] CRAN (R 3.6.0)                    
##  tidyselect    1.0.0      2020-01-27 [1] CRAN (R 3.6.0)                    
##  tidyverse   * 1.3.0      2019-11-21 [1] CRAN (R 3.6.0)                    
##  usethis       1.5.1      2019-07-04 [1] CRAN (R 3.6.0)                    
##  vctrs         0.2.4      2020-03-10 [1] CRAN (R 3.6.0)                    
##  withr         2.2.0      2020-04-20 [1] CRAN (R 3.6.2)                    
##  xfun          0.13       2020-04-13 [1] CRAN (R 3.6.2)                    
##  xml2          1.3.1      2020-04-09 [1] CRAN (R 3.6.2)                    
##  yaml          2.2.1      2020-02-01 [1] CRAN (R 3.6.0)                    
## 
## [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library
LS0tCnRpdGxlOiAiQ2xlYW4gZGF0YSIKYXV0aG9yOiAiU3RldmVuIEwuIFBlY2sgYW5kIEFuZHJldyBIZWlzcyIKZGF0ZTogIkxhc3QgcnVuOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVlLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBoaWRlCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQotLS0KCiMgTG9hZCBhbmQgY2xlYW4gZGF0YQoKYGBge3Igc2V0dXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoaGVyZSkKCnNldC5zZWVkKDEyMzQpCmBgYAoKCmBgYHtyIGNsZWFuLWRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPVRSVUV9CiMgQ29uc3RyYWludHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKY29uc3RyYWludF9sZXZlbHMgPC0gZnVuY3Rpb24oeCkgewogIGZpbHRlcihjb25zdHJhaW50cywgY29uc3RyYWludCA9PSB4KSAlPiUgCiAgICBwdWxsKGxldmVsc19jbGVhbikgJT4lCiAgICAuW1sxXV0KfQoKY29uc3RyYWludHMgPC0gdHJpYmJsZSgKICB+Y29uc3RyYWludCwgfmNvbnN0cmFpbnRfY2xlYW4sIH5sZXZlbHNfY2xlYW4sCiAgImNyZWF0ZV9uZXR3b3JrIiwgIk5ldHdvcmsgY3JlYXRpb24iLCBsaXN0KCJOZXR3b3JrIGNyZWF0aW9uIiA9ICJUIiwgIk5vIG5ldHdvcmsgY3JlYXRpb24iID0gIkYiKSwKICAic2VsZWN0IiwgIlNlbGVjdGlvbiIsIGxpc3QoIlNlbGVjdGlvbiIgPSAiVCIsICJObyBzZWxlY3Rpb24iID0gIkYiKSwKICAiZGlzcGVyc2UiLCAiRGlzcGVyc2FsIiwgbGlzdCgiRGlzcGVyc2FsIiA9ICJUIiwgIk5vIGRpc3BlcnNhbCIgPSAiRiIpLAogICJjb21wZXRlIiwgIkNvbXBldGl0aW9uIiwgbGlzdCgiQ29tcGV0aXRpb24iID0gIlQiLCAiTm8gY29tcGV0aXRpb24iID0gIkYiKSwKICAic2VsZWN0Zm9yX2QiLCAiU2VsZWN0aW9uIGZvciBEIiwgbGlzdCgiU2VsZWN0aW9uIiA9ICJUIiwgIk5vIHNlbGVjdGlvbiIgPSAiRiIpLAogICJjYXRhc3Ryb3BoZSIsICJDYXRhc3Ryb3BoZSIsIGxpc3QoIkNhdGFzdHJvcGhlIiA9ICJUIiwgIk5vIGNhdGFzdHJvcGhlIiA9ICJGIikKKQoKc2F2ZVJEUyhjb25zdHJhaW50cywgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiY29uc3RyYWludHMucmRzIikpCgoKIyBIaWdoL2xvdyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpCSEwgPC0gcmVhZF9yZHMoaGVyZSgiZGF0YSIsICJyYXdfZGF0YSIsICJCSEwucmRzIikpICU+JSAKICBjbGVhbl9uYW1lcyhjYXNlID0gInNuYWtlIikgJT4lICAgIyBHZXQgcmlkIG9mIGludmFsaWQgY2hhcmFjdGVycyBpbiBjb2x1bW4gbmFtZXMKICByZW5hbWVfYWxsKGxpc3QofnN0cl9yZW1vdmVfYWxsKC4sICJ5biQiKSkpICU+JSAgIyBHZXQgcmlkIG9mICJ5biIgaW4gY29sdW1uIG5hbWVzCiAgIyBDbGVhbiB1cCBjb25zdHJhaW50IHZhbHVlcwogIG11dGF0ZShjcmVhdGVfbmV0d29yayA9IGZjdF9yZWNvZGUoY3JlYXRlX25ldHdvcmssICEhIWNvbnN0cmFpbnRfbGV2ZWxzKCJjcmVhdGVfbmV0d29yayIpKSwKICAgICAgICAgc2VsZWN0ID0gZmN0X3JlY29kZShzZWxlY3QsICEhIWNvbnN0cmFpbnRfbGV2ZWxzKCJzZWxlY3QiKSksCiAgICAgICAgIGRpc3BlcnNlID0gZmN0X3JlY29kZShkaXNwZXJzZSwgISEhY29uc3RyYWludF9sZXZlbHMoImRpc3BlcnNlIikpLAogICAgICAgICBjb21wZXRlID0gZmN0X3JlY29kZShjb21wZXRlLCAhISFjb25zdHJhaW50X2xldmVscygiY29tcGV0ZSIpKSwKICAgICAgICAgc2VsZWN0Zm9yX2QgPSBmY3RfcmVjb2RlKHNlbGVjdGZvcl9kLCAhISFjb25zdHJhaW50X2xldmVscygic2VsZWN0Zm9yX2QiKSksCiAgICAgICAgIGNhdGFzdHJvcGhlID0gZmN0X3JlY29kZShjYXRhc3Ryb3BoZSwgISEhY29uc3RyYWludF9sZXZlbHMoImNhdGFzdHJvcGhlIikpKSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMob25lX29mKGNvbnN0cmFpbnRzJGNvbnN0cmFpbnQpKSwgbGlzdCh+IGZjdF9pbm9yZGVyKC4pKSkgJT4lIAogIG11dGF0ZShyZXBwID0gZmFjdG9yKHJlcHAsIGxldmVscyA9IGMoMSwgMiksIGxhYmVscyA9IGMoIkhpZ2giLCAiTG93IiksIG9yZGVyZWQgPSBUUlVFKSkKCkJITF9zbWFsbCA8LSBCSEwgJT4lIAogIGdyb3VwX2J5KHJlcHApICU+JSAKICBzYW1wbGVfZnJhYyhzaXplID0gMC4xKSAlPiUgCiAgdW5ncm91cCgpCgpzaW1faGwgPC0gQkhMX3NtYWxsICU+JSAKICAjIE1ha2UgbmV3IGNvbHVtbnMgd2l0aCAiX2NvbnN0cmFpbnQiIHN1ZmZpeCB0aGF0IHNob3cgaWYgY29uc3RyYWludCBpcyBUL0YKICAjIGluc3RlYWQgb2YgdXNpbmcgdGhlIGxhYmVsLiBlLmcuICJTZWxlY3Rpb24iIGJlY29tZXMgVFJVRSwgIk5vIHNlbGVjdGlvbiIKICAjIGJlY29tZXMgRkFMU0UKICBtdXRhdGVfYXQodmFycyhvbmVfb2YoY29uc3RyYWludHMkY29uc3RyYWludCkpLAogICAgICAgICAgICBsaXN0KGNvbnN0cmFpbnQgPSB+YXMubG9naWNhbCgtYXMuaW50ZWdlciguKSArIDJMKSkpICU+JQogICMgQ291bnQgaG93IG1hbnkgb2YgdGhlIGNvbnN0cmFpbnRzIGFyZSBUUlVFIGluIGVhY2ggcm93CiAgbXV0YXRlKG5fY29uc3RyYWludHMgPSByZWR1Y2Uoc2VsZWN0KC4sIGVuZHNfd2l0aCgiX2NvbnN0cmFpbnQiKSksIGArYCkpICU+JQogICMgTWFrZSBhIGZhY3RvciB2ZXJzaW9uIG9mIHRoZSBjb25zdHJhaW50IGNvdW50IGZvciBwbG90dGluZwogIG11dGF0ZShuX2NvbnN0cmFpbnRzX2YgPSBhcy5mYWN0b3Iobl9jb25zdHJhaW50cykpICU+JSAKICBtdXRhdGUodHVybm92ZXJfZGlmZiA9IGxhbmRzY2FwZV9saW5rZWRfc3BlY2llc19tZWFuX3R1cm5vdmVyIC0gbGFuZHNjYXBlX3VubGlua2VkX3NwZWNpZXNfbWVhbl90dXJub3ZlcikKCnNhdmVSRFMoQkhMLCBoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJCSEwucmRzIikpCnNhdmVSRFMoQkhMX3NtYWxsLCBoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJCSExfc21hbGwucmRzIikpCnNhdmVSRFMoc2ltX2hsLCBoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJzaW1faGwucmRzIikpCgoKIyBMYXRpbiBzcXVhcmVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpCTFMgPC0gcmVhZF9yZHMoaGVyZSgiZGF0YSIsICJyYXdfZGF0YSIsICJCTFMucmRzIikpICU+JSAKICBjbGVhbl9uYW1lcyhjYXNlID0gInNuYWtlIikgJT4lICAgIyBHZXQgcmlkIG9mIGludmFsaWQgY2hhcmFjdGVycyBpbiBjb2x1bW4gbmFtZXMKICByZW5hbWVfYWxsKGxpc3QofnN0cl9yZW1vdmVfYWxsKC4sICJ5biQiKSkpICU+JSAgIyBHZXQgcmlkIG9mICJ5biIgaW4gY29sdW1uIG5hbWVzCiAgIyBDbGVhbiB1cCBjb25zdHJhaW50IHZhbHVlcwogIG11dGF0ZShjcmVhdGVfbmV0d29yayA9IGZjdF9yZWNvZGUoY3JlYXRlX25ldHdvcmssICEhIWNvbnN0cmFpbnRfbGV2ZWxzKCJjcmVhdGVfbmV0d29yayIpKSwKICAgICAgICAgc2VsZWN0ID0gZmN0X3JlY29kZShzZWxlY3QsICEhIWNvbnN0cmFpbnRfbGV2ZWxzKCJzZWxlY3QiKSksCiAgICAgICAgIGRpc3BlcnNlID0gZmN0X3JlY29kZShkaXNwZXJzZSwgISEhY29uc3RyYWludF9sZXZlbHMoImRpc3BlcnNlIikpLAogICAgICAgICBjb21wZXRlID0gZmN0X3JlY29kZShjb21wZXRlLCAhISFjb25zdHJhaW50X2xldmVscygiY29tcGV0ZSIpKSwKICAgICAgICAgc2VsZWN0Zm9yX2QgPSBmY3RfcmVjb2RlKHNlbGVjdGZvcl9kLCAhISFjb25zdHJhaW50X2xldmVscygic2VsZWN0Zm9yX2QiKSksCiAgICAgICAgIGNhdGFzdHJvcGhlID0gZmN0X3JlY29kZShjYXRhc3Ryb3BoZSwgISEhY29uc3RyYWludF9sZXZlbHMoImNhdGFzdHJvcGhlIikpKSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMob25lX29mKGNvbnN0cmFpbnRzJGNvbnN0cmFpbnQpKSwgbGlzdCh+ZmN0X2lub3JkZXIoLikpKQoKQkxTX3NtYWxsIDwtIEJMUyAlPiUgCiAgc2FtcGxlX2ZyYWMoc2l6ZSA9IDAuMSkKCnNpbV9scyA8LSBCTFNfc21hbGwgJT4lCiAgIyBNYWtlIG5ldyBjb2x1bW5zIHdpdGggIl9jb25zdHJhaW50IiBzdWZmaXggdGhhdCBzaG93IGlmIGNvbnN0cmFpbnQgaXMgVC9GCiAgIyBpbnN0ZWFkIG9mIHVzaW5nIHRoZSBsYWJlbC4gZS5nLiAiU2VsZWN0aW9uIiBiZWNvbWVzIFRSVUUsICJObyBzZWxlY3Rpb24iCiAgIyBiZWNvbWVzIEZBTFNFCiAgbXV0YXRlX2F0KHZhcnMob25lX29mKGNvbnN0cmFpbnRzJGNvbnN0cmFpbnQpKSwKICAgICAgICAgICAgbGlzdChjb25zdHJhaW50ID0gfmFzLmxvZ2ljYWwoLWFzLmludGVnZXIoLikgKyAyTCkpKSAlPiUKICAjIENvdW50IGhvdyBtYW55IG9mIHRoZSBjb25zdHJhaW50cyBhcmUgVFJVRSBpbiBlYWNoIHJvdwogIG11dGF0ZShuX2NvbnN0cmFpbnRzID0gcmVkdWNlKHNlbGVjdCguLCBlbmRzX3dpdGgoIl9jb25zdHJhaW50IikpLCBgK2ApKSAlPiUKICAjIE1ha2UgYSBmYWN0b3IgdmVyc2lvbiBvZiB0aGUgY29uc3RyYWludCBjb3VudCBmb3IgcGxvdHRpbmcKICBtdXRhdGUobl9jb25zdHJhaW50c19mID0gYXMuZmFjdG9yKG5fY29uc3RyYWludHMpKSAlPiUgCiAgbXV0YXRlKHR1cm5vdmVyX2RpZmYgPSBsYW5kc2NhcGVfbGlua2VkX3NwZWNpZXNfbWVhbl90dXJub3ZlciAtIGxhbmRzY2FwZV91bmxpbmtlZF9zcGVjaWVzX21lYW5fdHVybm92ZXIpCgpzYXZlUkRTKEJMUywgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiQkxTLnJkcyIpKQpzYXZlUkRTKEJMU19zbWFsbCwgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiQkxTX3NtYWxsLnJkcyIpKQpzYXZlUkRTKHNpbV9scywgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAic2ltX2xzLnJkcyIpKQpgYGAKCgpDcmVhdGUgY29sdW1ucyBmb3IgZXZlcnkgY29tYmluYXRpb24gb2YgY29uc3RyYWludCBpbiB0aGUgZGF0YSAoZS5nLiBgc2VsZWN0YCwgYHNlbGVjdGAgJiBgZGlzcGVyc2VgLCBgc2VsZWN0YCAmIGBkaXNwZXJzZWAgJiBgY3JlYXRlX25ldHdvcmtgLCBldGMuKQoKKEJ5IHRoZSBpbmltaXRhYmxlIFZpbmNlbnQgQXJlbC1CdW5kb2NrKQoKYGBge3IgY2FjaGU9VFJVRSwgd2FybmluZz1GQUxTRX0KbWFrZV9jb21iaW5hdGlvbnMgPC0gZnVuY3Rpb24oZGYsIG0gPSA1KSB7CiAgY29tIDwtIGNvbG5hbWVzKGRmKVsyOm5jb2woZGYpXSAlPiUKICAgIGNvbWJuKG0pICU+JQogICAgYXNfdGliYmxlKCkKICBvdXQgPC0gY29tICU+JQogICAgbWFwKH4gZGZbLl0pICU+JQogICAgbWFwKH4gcm93U3VtcyguKSA9PSBuY29sKC4pKSAlPiUKICAgIHNldE5hbWVzKG1hcChjb20sIHBhc3RlLCBjb2xsYXBzZSA9ICIgKyAiKSkgJT4lCiAgICBhc190aWJibGUoKQogIHJldHVybihvdXQpCn0KCm91dGNvbWVzIDwtIGMoImxhbmRzY2FwZV9maXRuZXNzX2xpbmtlZCIsICJhdmdfZXZlbm5lc3NfdCIsICJ2YXJfZml0bmVzcyIsIAogICAgICAgICAgICAgICJsYW5kc2NhcGVfcmljaG5lc3NfbWVhbiIsICJsYW5kc2NhcGVfbGlua2VkX3NwZWNpZXNfbWVhbl90dXJub3ZlciIsCiAgICAgICAgICAgICAgInR1cm5vdmVyX2RpZmYiKQoKIyBIaWdoL2xvdyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFNlbGVjdCBqdXN0IHRoZSBydW4gbnVtYmVyIGFuZCAqX2NvbnN0cmFpbnQgVFJVRS9GQUxTRSBjb2x1bW5zCmNvbnN0cmFpbnRfY29tYmluYXRpb25zX2hsIDwtIHNpbV9obCAlPiUKICBzZWxlY3QocnVubnVtLCBlbmRzX3dpdGgoIl9jb25zdHJhaW50IikpICU+JQogICMgU2hyaW5rIG5hbWVzIGJ5IHJlbW92aW5nICJfY29uc3RyYWludCIKICByZW5hbWVfYXQodmFycyhlbmRzX3dpdGgoImNvbnN0cmFpbnQiKSksCiAgICAgICAgICAgIGxpc3QofnN0cl9yZXBsYWNlX2FsbCguLCAiX2NvbnN0cmFpbnQiLCAiIikpKQoKIyBGaW5kIGFsbCBjb21iaW5hdGlvbnMgb2YgdmFyaWFibGVzIChtID0gbnVtYmVyIG9mIGl0ZW1zIGluIGNvbWJpbmF0aW9uOyBtID0gMgojIG1lYW5zIHBhaXJzLCBtID0gMyBtZWFucyB0cmlwbGV0cywgZXRjLikKYWxsX2NvbnN0cmFpbnRfY29tYm9zX2hsIDwtIG1hcCgyOjYsIH5tYWtlX2NvbWJpbmF0aW9ucyhjb25zdHJhaW50X2NvbWJpbmF0aW9uc19obCwgbSA9IC4pKSAlPiUKICBiaW5kX2NvbHMoY29uc3RyYWludF9jb21iaW5hdGlvbnNfaGwsIC4pCgojIFNlbGVjdCB0aGUgb3V0Y29tZSB2YXJpYWJsZXMgd2UgY2FyZSBhYm91dCBhbmQgam9pbiB0aGUgY29uc3RyYWludCBjb21iaW5hdGlvbnMKY29uc3RyYWludF9jb21ib19vdXRjb21lc19obCA8LSBzaW1faGwgJT4lCiAgc2VsZWN0KHJ1bm51bSwgcmVwcCwgbl9jb25zdHJhaW50cywgb25lX29mKG91dGNvbWVzKSkgJT4lCiAgcmlnaHRfam9pbihhbGxfY29uc3RyYWludF9jb21ib3NfaGwsIGJ5ID0gInJ1bm51bSIpCgojIERvbid0IGRvdWJsZSBjb3VudCByb3dzLiBJZiBhIHJvdyBoYXMgdHdvIGNvbnN0cmFpbnRzIGxpa2Ugc2VsZWN0IGFuZAojIGRpc3BlcnNlLCBpdCdsbCBhbHNvIGhhdmUgc2VsZWN0ICsgZGlzcGVyc2Ugc2V0IHRvIFRSVUUuIElmIHRoYXQncyB0aGUgY2FzZSwKIyB3ZSBkb24ndCB3YW50IHRvIGluY2x1ZGUgaXQgaW4ganVzdCBzZWxlY3Qgb3IganVzdCBkaXNwZXJzZQpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2hsX25lc3RlZCA8LSBjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2hsICU+JQogIHNlbGVjdCgtbl9jb25zdHJhaW50cykgJT4lCiAgIyBNYWtlIGxvbmcKICBnYXRoZXIoY29uc3RyYWludF9jb21ibywgdmFsdWUsIC1ydW5udW0sIC1yZXBwLCAtb25lX29mKG91dGNvbWVzKSkgJT4lCiAgIyBDb3VudCBob3cgbWFueSBjb25zdHJhaW50cyB0aGVyZSBhcmUgd2l0aGluIGVhY2ggcm93IGJhc2VkIG9uICsgc2lnbnMKICBtdXRhdGUobiA9IHN0cl9jb3VudChjb25zdHJhaW50X2NvbWJvLCAiXFwrIikgKyAxKSAlPiUKICAjIE9ubHkga2VlcCByb3dzIHdoZXJlIHRoZSBjb25zdHJhaW50IGlzIHR1cm5lZCBvbgogIGZpbHRlcih2YWx1ZSA9PSBUUlVFKSAlPiUKICAjIE5lc3QgYWxsIHRoZSBjb25zdHJhaW50IGNvbWJpbmF0aW9ucyB3aXRoaW4gZWFjaCByb3cKICBncm91cF9ieShydW5udW0pICU+JQogIG5lc3QoKQoKIyBPbmx5IGtlZXAgdGhlIHZhbHVlcyB3aGVyZSBuID09IG1heChuKSBmb3IgdGhhdCByb3cKIyBUaGlzIHRha2VzIOKJiDIgbWludXRlcwpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2hsX2ZpbHRlcmVkIDwtIGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfaGxfbmVzdGVkICU+JQogIG11dGF0ZShmaWx0ZXJlZCA9IGRhdGEgJT4lIG1hcCh+ZmlsdGVyKC4sIG4gPT0gbWF4KC4kbikpKSkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICB1bm5lc3QoZmlsdGVyZWQpCgojIFRoaXMgb21pdHRlZCBhbGwgdGhlIHJvd3Mgd2hlcmUgbl9jb25zdHJhaW50cyA9PSAwLCBzbyBhZGQgdGhvc2UgYmFjayBpbgpub19jb25zdHJhaW50c19obCA8LSBjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2hsICU+JQogIGZpbHRlcihuX2NvbnN0cmFpbnRzID09IDApICU+JQogIG11dGF0ZShjb25zdHJhaW50X2NvbWJvID0gIk5vIGNvbnN0cmFpbnRzIiwgbiA9IDApICU+JQogIHNlbGVjdChydW5udW0sIHJlcHAsIG9uZV9vZihvdXRjb21lcyksIGNvbnN0cmFpbnRfY29tYm8sIG4pCgpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2hsX2RvbmUgPC0gYmluZF9yb3dzKGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfaGxfZmlsdGVyZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9fY29uc3RyYWludHNfaGwpICU+JQogIHNlbGVjdCgtdmFsdWUpCgpzYXZlUkRTKGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfaGxfZG9uZSwgCiAgICAgICAgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiY29uc3RyYWludF9jb21ib19vdXRjb21lc19obC5yZHMiKSkKCgojIExhdGluIHNxdWFyZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgU2VsZWN0IGp1c3QgdGhlIHJ1biBudW1iZXIgYW5kICpfY29uc3RyYWludCBUUlVFL0ZBTFNFIGNvbHVtbnMKY29uc3RyYWludF9jb21iaW5hdGlvbnNfbHMgPC0gc2ltX2xzICU+JQogIHNlbGVjdChydW5udW0sIGVuZHNfd2l0aCgiX2NvbnN0cmFpbnQiKSkgJT4lIAogICMgU2hyaW5rIG5hbWVzIGJ5IHJlbW92aW5nICJfY29uc3RyYWludCIKICByZW5hbWVfYXQodmFycyhlbmRzX3dpdGgoImNvbnN0cmFpbnQiKSksIAogICAgICAgICAgICBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgIl9jb25zdHJhaW50IiwgIiIpKSkKCiMgRmluZCBhbGwgY29tYmluYXRpb25zIG9mIHZhcmlhYmxlcyAobSA9IG51bWJlciBvZiBpdGVtcyBpbiBjb21iaW5hdGlvbjsgbSA9IDIKIyBtZWFucyBwYWlycywgbSA9IDMgbWVhbnMgdHJpcGxldHMsIGV0Yy4pCmFsbF9jb25zdHJhaW50X2NvbWJvc19scyA8LSBtYXAoMjo2LCB+bWFrZV9jb21iaW5hdGlvbnMoY29uc3RyYWludF9jb21iaW5hdGlvbnNfbHMsIG0gPSAuKSkgJT4lIAogIGJpbmRfY29scyhjb25zdHJhaW50X2NvbWJpbmF0aW9uc19scywgLikKCiMgU2VsZWN0IHRoZSBvdXRjb21lIHZhcmlhYmxlcyB3ZSBjYXJlIGFib3V0IGFuZCBqb2luIHRoZSBjb25zdHJhaW50IGNvbWJpbmF0aW9ucwpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2xzIDwtIHNpbV9scyAlPiUKICBzZWxlY3QocnVubnVtLCBuX2NvbnN0cmFpbnRzLCBvbmVfb2Yob3V0Y29tZXMpKSAlPiUgCiAgcmlnaHRfam9pbihhbGxfY29uc3RyYWludF9jb21ib3NfbHMsIGJ5ID0gInJ1bm51bSIpCgojIERvbid0IGRvdWJsZSBjb3VudCByb3dzLiBJZiBhIHJvdyBoYXMgdHdvIGNvbnN0cmFpbnRzIGxpa2Ugc2VsZWN0IGFuZAojIGRpc3BlcnNlLCBpdCdsbCBhbHNvIGhhdmUgc2VsZWN0ICsgZGlzcGVyc2Ugc2V0IHRvIFRSVUUuIElmIHRoYXQncyB0aGUgY2FzZSwKIyB3ZSBkb24ndCB3YW50IHRvIGluY2x1ZGUgaXQgaW4ganVzdCBzZWxlY3Qgb3IganVzdCBkaXNwZXJzZQpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2xzX25lc3RlZCA8LSBjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2xzICU+JSAKICBzZWxlY3QoLW5fY29uc3RyYWludHMpICU+JSAKICAjIE1ha2UgbG9uZwogIGdhdGhlcihjb25zdHJhaW50X2NvbWJvLCB2YWx1ZSwgLXJ1bm51bSwgLW9uZV9vZihvdXRjb21lcykpICU+JSAKICAjIENvdW50IGhvdyBtYW55IGNvbnN0cmFpbnRzIHRoZXJlIGFyZSB3aXRoaW4gZWFjaCByb3cgYmFzZWQgb24gKyBzaWducwogIG11dGF0ZShuID0gc3RyX2NvdW50KGNvbnN0cmFpbnRfY29tYm8sICJcXCsiKSArIDEpICU+JQogICMgT25seSBrZWVwIHJvd3Mgd2hlcmUgdGhlIGNvbnN0cmFpbnQgaXMgdHVybmVkIG9uCiAgZmlsdGVyKHZhbHVlID09IFRSVUUpICU+JQogICMgTmVzdCBhbGwgdGhlIGNvbnN0cmFpbnQgY29tYmluYXRpb25zIHdpdGhpbiBlYWNoIHJvdwogIGdyb3VwX2J5KHJ1bm51bSkgJT4lIAogIG5lc3QoKQoKIyBPbmx5IGtlZXAgdGhlIHZhbHVlcyB3aGVyZSBuID09IG1heChuKSBmb3IgdGhhdCByb3cKIyBUaGlzIHRha2VzIOKJiDEgbWludXRlCmNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHNfZmlsdGVyZWQgPC0gY29uc3RyYWludF9jb21ib19vdXRjb21lc19sc19uZXN0ZWQgJT4lIAogIG11dGF0ZShmaWx0ZXJlZCA9IGRhdGEgJT4lIG1hcCh+ZmlsdGVyKC4sIG4gPT0gbWF4KC4kbikpKSkgJT4lIAogIHNlbGVjdCgtZGF0YSkgJT4lIAogIHVubmVzdChmaWx0ZXJlZCkKCiMgVGhpcyBvbWl0dGVkIGFsbCB0aGUgcm93cyB3aGVyZSBuX2NvbnN0cmFpbnRzID09IDAsIHNvIGFkZCB0aG9zZSBiYWNrIGluCm5vX2NvbnN0cmFpbnRzX2xzIDwtIGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHMgJT4lIAogIGZpbHRlcihuX2NvbnN0cmFpbnRzID09IDApICU+JSAKICBtdXRhdGUoY29uc3RyYWludF9jb21ibyA9ICJObyBjb25zdHJhaW50cyIsIG4gPSAwKSAlPiUgCiAgc2VsZWN0KHJ1bm51bSwgb25lX29mKG91dGNvbWVzKSwgY29uc3RyYWludF9jb21ibywgbikKCmNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHNfZG9uZSA8LSBiaW5kX3Jvd3MoY29uc3RyYWludF9jb21ib19vdXRjb21lc19sc19maWx0ZXJlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub19jb25zdHJhaW50c19scykgJT4lIAogIHNlbGVjdCgtdmFsdWUpCgpzYXZlUkRTKGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHNfZG9uZSwgCiAgICAgICAgaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiY29uc3RyYWludF9jb21ib19vdXRjb21lc19scy5yZHMiKSkKYGBgCgoKRGF0YSBkZXRhaWxzOgoKLSBIaWdoLWxvdyBmdWxsOiBgciBzY2FsZXM6OmNvbW1hKG5yb3coQkhMKSlgIHJvd3MKICAgIC0gSGlnaDogYHIgc2NhbGVzOjpjb21tYShucm93KGZpbHRlcihCSEwsIHJlcHAgPT0gIkhpZ2giKSkpYCByb3dzCiAgICAtIExvdzogYHIgc2NhbGVzOjpjb21tYShucm93KGZpbHRlcihCSEwsIHJlcHAgPT0gIkxvdyIpKSlgIHJvd3MKLSBIaWdoLWxvdyBzbWFsbDogYHIgc2NhbGVzOjpjb21tYShucm93KEJITF9zbWFsbCkpYCByb3dzCiAgICAtIEhpZ2g6IGByIHNjYWxlczo6Y29tbWEobnJvdyhmaWx0ZXIoQkhMX3NtYWxsLCByZXBwID09ICJIaWdoIikpKWAgcm93cwogICAgLSBMb3c6IGByIHNjYWxlczo6Y29tbWEobnJvdyhmaWx0ZXIoQkhMX3NtYWxsLCByZXBwID09ICJMb3ciKSkpYCByb3dzCi0gTGF0aW4gc3F1YXJlcyBmdWxsOiBgciBzY2FsZXM6OmNvbW1hKG5yb3coQkxTKSlgIHJvd3MKLSBMYXRpbiBzcXVhcmVzIHNtYWxsOiBgciBzY2FsZXM6OmNvbW1hKG5yb3coQkxTX3NtYWxsKSlgIHJvd3MKCgpcCgojIE9yaWdpbmFsIGNvbXB1dGluZyBlbnZpcm9ubWVudAoKPGJ1dHRvbiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjc2Vzc2lvbmluZm8iIGNsYXNzPSJidG4gYnRuLXByaW1hcnkgYnRuLW1kIGJ0bi1pbmZvIj5IZXJlJ3Mgd2hhdCB3ZSB1c2VkIHRoZSBsYXN0IHRpbWUgd2UgYnVpbHQgdGhpcyBwYWdlPC9idXR0b24+Cgo8ZGl2IGlkPSJzZXNzaW9uaW5mbyIgY2xhc3M9ImNvbGxhcHNlIj4KCmBgYHtyIHNob3ctc2Vzc2lvbi1pbmZvLCBlY2hvPVRSVUUsIHdpZHRoPTEwMH0Kd3JpdGVMaW5lcyhyZWFkTGluZXMoZmlsZS5wYXRoKFN5cy5nZXRlbnYoIkhPTUUiKSwgIi5SL01ha2V2YXJzIikpKQoKZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYAoKPC9kaXY+IAo=