knitr::opts_chunk$set(warning = FALSE)

library(tidyverse)     # CRAN v1.3.0
library(broom)         # [github::tidymodels/broom] v0.5.3.9000
library(randomForest)  # CRAN v4.6-14
library(ggstance)      # CRAN v0.3.3
library(ggtext)        # [github::wilkelab/ggtext] v0.1.0
library(gghalves)      # [github::erocoar/gghalves] v0.1.0
library(ggforce)       # CRAN v0.3.1
library(patchwork)     # CRAN v1.0.0
library(pander)        # CRAN v0.6.3
library(scales)        # CRAN v1.1.0
library(pluralize)     # [github::hrbrmstr/pluralize] v0.1.0
library(glue)          # CRAN v1.4.0
library(here)          # CRAN v0.1

# Disable dplyr's automatic ungrouping message
options(dplyr.summarise.inform = FALSE)

SEED <- 1234

sim_hl <- read_rds(here("data", "derived_data", "sim_hl.rds"))
sim_ls <- read_rds(here("data", "derived_data", "sim_ls.rds"))

sim_high <- sim_hl %>% filter(repp == "High")
sim_low <- sim_hl %>% filter(repp == "Low")

constraint_combo_outcomes_hl <- read_rds(here("data", "derived_data", 
                                              "constraint_combo_outcomes_hl.rds")) %>% 
  mutate(constraint_combo = str_replace(constraint_combo, "selectfor_d", "species_drift"),
         constraint_combo = str_replace(constraint_combo, "select", "selection"),
         constraint_combo = str_replace(constraint_combo, "compete", "competition"),
         constraint_combo = str_replace(constraint_combo, "disperse", "dispersal"))

constraint_combo_outcomes_ls <- read_rds(here("data", "derived_data", 
                                              "constraint_combo_outcomes_ls.rds")) %>% 
  mutate(constraint_combo = str_replace(constraint_combo, "selectfor_d", "species_drift"),
         constraint_combo = str_replace(constraint_combo, "select", "selection"),
         constraint_combo = str_replace(constraint_combo, "compete", "competition"),
         constraint_combo = str_replace(constraint_combo, "disperse", "dispersal"))

diff_hl_outcomes_full <- sim_hl %>%
  group_by(n_constraints_f) %>%
  nest() %>%
  mutate(fitness_test = map(data, ~t.test(landscape_fitness_linked ~ repp, data = .)),
         evenness_test = map(data, ~t.test(avg_evenness_t ~ repp, data = .)),
         richness_test = map(data, ~t.test(landscape_richness_mean ~ repp, data = .)),
         turnover_test = map(data, ~t.test(turnover_diff ~ repp, data = .))) %>%
  mutate_at(vars(ends_with("test")), list(tidy = ~map(., ~tidy(.)))) %>%
  mutate_at(vars(ends_with("tidy")), list(diff = ~map_dbl(., "estimate"),
                                          p.value = ~map_dbl(., "p.value"))) %>%
  ungroup()

diff_hl_outcomes_plot <- diff_hl_outcomes_full %>%
  select(-data, -ends_with("_test"), -ends_with("_tidy")) %>%
  pivot_longer(cols = -n_constraints_f) %>%
  mutate(name = str_replace(name, "_test_tidy_", "_")) %>%
  separate(name, into = c("outcome", "statistic"), sep = "_") %>%
  pivot_wider(names_from = "statistic") %>%
  mutate(sig = ifelse(p.value < 0.05, "*", ""),
         sig = ifelse(is.nan(p.value), "", sig)) %>%
  mutate(nice_diff = glue("∆ = {round(diff, 3)}{sig}")) %>%
  mutate(nice_diff = str_replace(nice_diff, "\\-", "−"))
theme_constraint <- function(base_size = 8, base_family = "DejaVu Sans Condensed") {
  ret <- theme_bw(base_size, base_family) +
    theme(plot.title = element_text(size = rel(1.1), face = "bold",
                                    family = "DejaVu Sans Condensed"),
          plot.subtitle = element_text(size = rel(0.8), face = "plain",
                                       family = "DejaVu Sans Condensed"),
          plot.caption = element_text(size = rel(0.8), color = "grey50", face = "plain",
                                      family = "DejaVu Sans Condensed",
                                      margin = ggplot2::margin(t = 5)),
          panel.border = element_rect(color = "grey50", fill = NA, size = 0.15),
          panel.spacing = unit(1, "lines"),
          panel.grid.minor = element_blank(),
          strip.text = element_text(size = rel(0.9), hjust = 0,
                                    family = "DejaVu Sans Condensed", face = "bold"),
          strip.background = element_rect(fill = "#ffffff", colour = NA),
          axis.ticks = element_blank(),
          axis.title.x = element_text(margin = ggplot2::margin(t = 5)),
          axis.text = element_text(family = "DejaVu Sans Condensed", face = "plain"),
          legend.key = element_blank(),
          legend.text = element_text(size = rel(1), family = "DejaVu Sans Condensed", 
                                     face = "plain"),
          legend.spacing = unit(0.1, "lines"),
          legend.box.margin = ggplot2::margin(t = -0.5, unit = "lines"),
          legend.margin = ggplot2::margin(t = 0),
          legend.position = "bottom")

  ret
}

# Colors from https://medialab.github.io/iwanthue/
# 6 colors, default palette, soft (k-means)
clrs <- list(
  select = "#6295cd",  # blue
  selection = "#6295cd",  # blue
  compete = "#b3943f",  # gold
  competition = "#b3943f",  # gold
  catastrophe = "#9466c9",  # purple
  create_network = "#62a85b",  # green
  dispersal = "#c85990",  # pink
  disperse = "#c85990",  # pink
  selectfor_d = "#ca5d46",  # reddish
  species_drift = "#ca5d46",  # reddish
  grey = "#7f7f7f"  # grey50
)

color_constraints <- function(df, constraint_col) {
  df %>% 
    mutate(constraint_colored = {{constraint_col}}) %>% 
    mutate(constraint_colored =
             str_replace_all(constraint_colored,  "\\bselect\\b",
                             glue("<span style='color:{clrs$select}'>select</span>")),
           constraint_colored =
             str_replace_all(constraint_colored,  "\\bselection\\b",
                             glue("<span style='color:{clrs$selection}'>selection</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bcompete\\b",
                             glue("<span style='color:{clrs$compete}'>compete</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bcompetition\\b",
                             glue("<span style='color:{clrs$competition}'>competition</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bcatastrophe\\b",
                             glue("<span style='color:{clrs$catastrophe}'>catastrophe</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bcreate_network\\b",
                             glue("<span style='color:{clrs$create_network}'>create_network</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bdisperse\\b",
                             glue("<span style='color:{clrs$disperse}'>disperse</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bdispersal\\b",
                             glue("<span style='color:{clrs$dispersal}'>dispersal</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bselectfor_d\\b",
                             glue("<span style='color:{clrs$selectfor_d}'>selectfor_d</span>")),
           constraint_colored =
             str_replace_all(constraint_colored, "\\bspecies_drift\\b",
                             glue("<span style='color:{clrs$species_drift}'>species_drift</span>")))
}

# Function for plotting outcomes across combinations of constraints
mega_means_plot <- function(df, var_name, xlab, title, add_to_right = 0, add_to_left = 0.03, xlim = NULL) {
  constraint_combos <- df %>%
    group_by(constraint_combo, n) %>%
    summarize(avg = mean({{var_name}})) %>% 
    arrange(desc(n), desc(avg)) %>% 
    ungroup() %>% 
    mutate(constraint_combo = ifelse(n >= 4, 
                                     str_wrap(constraint_combo, width = 40, exdent = 8), 
                                     constraint_combo)) %>% 
    mutate(constraint_combo = str_replace_all(constraint_combo, " {8}", "<br>")) %>% 
    mutate(constraint_combo = recode(constraint_combo,
                                     `select` = "selection",
                                     `compete` = "competition",
                                     `disperse` = "dispersal",
                                     `selectfor_d` = "species_drift")) %>% 
    color_constraints(constraint_combo) %>% 
    mutate(constraint_colored = fct_inorder(constraint_colored),
           n_title = map_chr(n, ~paste0(., pluralize(" constraint", .))))
  
  plot_02 <- ggplot(filter(constraint_combos, n %in% c(0, 1, 2)),
                            aes(x = avg, y = constraint_colored)) +
    geom_pointrangeh(aes(xmin = 0, xmax = avg)) + 
    scale_x_continuous(expand = expansion(add = c(add_to_right, add_to_left))) +
    labs(x = xlab, y = NULL) +
    facet_col(vars(n_title), scales = "free_y", space = "free") +
    theme_constraint() +
    theme(axis.text.y = element_markdown(),
          panel.grid.major.y = element_blank(),
          strip.background = element_rect(fill = "grey80"))
  
  plot_3 <- ggplot(filter(constraint_combos, n == 3),
                           aes(x = avg, y = constraint_colored)) +
    geom_pointrangeh(aes(xmin = 0, xmax = avg)) + 
    scale_x_continuous(expand = expansion(add = c(add_to_right, add_to_left))) +
    labs(x = xlab, y = NULL) +
    facet_col(vars(n_title), scales = "free_y", space = "free") +
    theme_constraint() +
    theme(axis.text.y = element_markdown(),
          panel.grid.major.y = element_blank(),
          strip.background = element_rect(fill = "grey80"))
  
  plot_46 <- ggplot(filter(constraint_combos, n %in% c(4, 5, 6)),
                            aes(x = avg, y = constraint_colored)) +
    geom_pointrangeh(aes(xmin = 0, xmax = avg)) + 
    scale_x_continuous(expand = expansion(add = c(add_to_right, add_to_left))) +
    labs(x = xlab, y = NULL) +
    facet_col(vars(n_title), scales = "free_y", space = "free") +
    theme_constraint() +
    theme(axis.text.y = element_markdown(),
          panel.grid.major.y = element_blank(),
          strip.background = element_rect(fill = "grey80"))
  
  if (!is.null(xlim)) {
    plot_02 <- plot_02 + coord_cartesian(xlim = xlim)
    plot_3 <- plot_3 + coord_cartesian(xlim = xlim)
    plot_46 <- plot_46 + coord_cartesian(xlim = xlim)
  }
  
  plot_all <- (plot_02 | plot_3 | plot_46) +
    plot_annotation(title = title,
                    theme = theme(plot.title = element_text(size = rel(1.1), face = "bold",
                                                            family = "DejaVu Sans Condensed")))
  plot_all
}

Variable importance

To determine which constraints matter the most, we use random forests to determine variable importance. We don’t need to include all the interactions (e.g. create_network + select + create_network * select, etc.) because random forests inherently pick those up.

There are two ways to measure variable importance with random forests: (1) Gini-based node impurity, and (2) permutation-based increase in mean standard error. Gini-based node impurity is trickier to interpret. According to Liz Dinsdale:

The mean decrease in Gini coefficient is a measure of how each variable contributes to the homogeneity of the nodes and leaves in the resulting random forest. Each time a particular variable is used to split a node, the Gini coefficient for the child nodes are calculated and compared to that of the original node. The Gini coefficient is a measure of homogeneity from 0 (homogeneous) to 1 (heterogeneous). The changes in Gini are summed for each variable and normalized at the end of the calculation. Variables that result in nodes with higher purity have a higher decrease in Gini coefficient.

Or in other words, importance is the mean decrease (over all the trees) in the Gini index by splits of a predictor. Basically, the higher the decrease in impurity, the more important the variable in explaining the outcome.

However, node impurity tends to inflate or distort variable importance for continuous variables, and it uses the entire data set. A common alternative (that is also more interpretable!) is to look at the percent increase in mean standard error (see slide 15 here and this answer here). This measures how much the model’s MSE changes if you shuffle one of the variables (i.e. if you completely shuffle select, how wrong does the model become?). High values show that the variable is important for maintaining accuracy; low values show that the variable doesn’t matter all that much (since it can be random noise and result in similar accuracy). Like here, the Gini-based version finds that passenger ID is incredibly important for predicting survival on the Titanic, when really it’s just a random variable that doesn’t matter. The percent-change-in-MSE-based version of importance isn’t fooled by passenger ID, though.

Because of that, we use mean decrease in accuracy as our measure of variable importance.

library(titanic)  # CRAN v0.1.0
titanic <- titanic::titanic_train %>% 
  drop_na() %>% 
  mutate(Sex = as.factor(Sex), Survived = as.factor(Survived), Pclass = as.factor(Pclass))

set.seed(SEED)
titanic_forest <- randomForest(Survived ~ Age + Sex + Pclass + PassengerId, 
                               data = titanic, importance = TRUE)
varImpPlot(titanic_forest)

Figures

Figure 4: Landscape fitness

Fig 4. Effect of the number of constraints on landscape fitness (A) Boxplots showing landscape fitness across different numbers of constraints; (B) Percent increase in mean standard error in a random forest model when each constraint is removed; (C) Average landscape fitness across all possible combinations of constraints

plot_fitness_boxplot <- ggplot(sim_ls, aes(x = n_constraints_f, y = landscape_fitness_linked)) +
  geom_half_point(size = 0.01, alpha = 0.01, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(aes(fill = "Latin hypercube samples"),
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE, alpha = 0.5) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#0074D9"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(1, -0.02)) +
  labs(x = "Number of constraints",
       y = "Landscape fitness",
       title = "A: Landscape fitness and constraints",
       subtitle = "Values near zero indicate high fitness",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_fitness_boxplot

ggsave(plot_fitness_boxplot, filename = here("analysis", "output", "fitness_A.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_fitness_boxplot, filename = here("analysis", "output", "fitness_A.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
plot_fitness_hl_diffs <- ggplot(mapping = aes(x = n_constraints_f, y = landscape_fitness_linked, fill = repp)) +
  geom_text(data = filter(diff_hl_outcomes_plot, outcome == "fitness"),
            aes(y = 0, label = nice_diff, fill = NULL),
            family = "DejaVu Sans Condensed", fontface = "plain", size = 1.5, vjust = -0.85) +
  geom_half_boxplot(data = sim_high,
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  geom_half_boxplot(data = sim_low,
                    size = 0.25, side = "r", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  stat_summary(data = sim_high, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.22)) +
  stat_summary(data = sim_low, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = 0.22)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#2ECC40", "#FF851B"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(0.65, -0.02)) +
  labs(x = "Number of constraints",
       y = "Landscape fitness",
       title = "B: Constraints across high/low",
       subtitle = "∆ = high − low",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value; * = p < 0.05")) +
  theme_constraint() +
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_fitness_hl_diffs

combined_fitness <- plot_fitness_boxplot + plot_fitness_hl_diffs

combined_fitness

ggsave(combined_fitness, filename = here("analysis", "output", "fitness_boxplots.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(combined_fitness, filename = here("analysis", "output", "fitness_boxplots.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600)
# This takes a few minutes to run
set.seed(SEED)
forest_model_fitness <- 
  randomForest(landscape_fitness_linked ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, data = sim_ls)

forest_model_fitness_low <- 
  randomForest(landscape_fitness_linked ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, data = filter(sim_hl, repp == "Low"))

forest_model_fitness_high <- 
  randomForest(landscape_fitness_linked ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, data = filter(sim_hl, repp == "High"))
clrs <- list(
  select = "#6295cd",  # blue
  selection = "#6295cd",  # blue
  compete = "#b3943f",  # gold
  competition = "#b3943f",  # gold
  catastrophe = "#9466c9",  # purple
  create_network = "#62a85b",  # green
  dispersal = "#c85990",  # pink
  disperse = "#c85990",  # pink
  selectfor_d = "#ca5d46",  # reddish
  species_drift = "#ca5d46",  # reddish
  grey = "#7f7f7f"  # grey50
)

fitness_importance_ls <- importance(forest_model_fitness, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  arrange(desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_fitness_importance_ls <- ggplot(fitness_importance_ls, 
                                     aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
                                         color = fct_rev(constraint), 
                                         shape = "Latin hypercube samples")) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_shape_manual(values = c(19), name = NULL) +
  guides(shape = guide_legend(direction = "horizontal",
                              override.aes = list(size = 0.25))) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "B: Constraint importance for landscape fitness",
       subtitle = "Higher values indicate greater variable importance",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_fitness_importance_ls

ggsave(plot_fitness_importance_ls, filename = here("analysis", "output", "fitness_B.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_fitness_importance_ls, filename = here("analysis", "output", "fitness_B.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
fitness_importance_low <- importance(forest_model_fitness_low, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "Low")

fitness_importance_high <- importance(forest_model_fitness_high, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "High")

fitness_importance_hl <- bind_rows(fitness_importance_low,
                                   fitness_importance_high) %>% 
  mutate(repp = factor(repp, levels = c("Low", "High"), ordered = TRUE)) %>% 
  arrange(desc(repp), desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_fitness_importance_hl <- ggplot(fitness_importance_hl, 
       aes(x = X.IncMSE, y = fct_rev(constraint_colored), color = fct_rev(constraint), 
           linetype = repp, shape = repp)) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE),
                   position = position_dodgev(height = 0.5), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_linetype_manual(values = c("dashed", "solid"), name = NULL) +
  scale_shape_manual(values = c(17, 15), name = NULL) +
  guides(linetype = guide_legend(direction = "horizontal", reverse = TRUE),
         shape = guide_legend(direction = "horizontal", override.aes = list(size = 0.25),
                              reverse = TRUE)) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "D: Constraint importance across high/low",
       subtitle = "",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_fitness_importance_hl

importance_fitness <- plot_fitness_importance_ls + plot_fitness_importance_hl

importance_fitness

ggsave(importance_fitness, filename = here("analysis", "output", "fitness_importance.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(importance_fitness, filename = here("analysis", "output", "fitness_importance.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
plot_fitness_all <- mega_means_plot(constraint_combo_outcomes_ls, landscape_fitness_linked, 
                                    xlab = "Average landscape fitness", 
                                    title = "Average landscape fitness across combinations of constraints")

plot_fitness_all

ggsave(plot_fitness_all, filename = here("analysis", "output", "fitness_means_all.pdf"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", device = cairo_pdf)
ggsave(plot_fitness_all, filename = here("analysis", "output", "fitness_means_all.png"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", type = "cairo", dpi = 300)

Figure 5: Landscape fitness variance

Fig 5. Effect of the number of constraints on variance of landscape fitness Boxplots showing variance of landscape fitness across different numbers of constraints

plot_landscape_fitness_variance <- ggplot(sim_ls, 
                                          aes(x = n_constraints_f, y = landscape_fitness_var)) +
  geom_half_point(size = 0.05, alpha = 0.1, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  scale_y_reverse() +
  coord_cartesian(ylim = c(0.1, 0)) +
  labs(x = "Number of constraints",
       y = "Landscape fitness, variance",
       title = "Variance in landscape fitness and constraints",
       subtitle = "Latin hypercube samples",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown())

plot_landscape_fitness_variance

ggsave(plot_landscape_fitness_variance, filename = here("analysis", "output", "fitness_variance.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_landscape_fitness_variance, filename = here("analysis", "output", "fitness_variance.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)

Figure 6: Ecological evenness

Fig 6. Effect of the number of constraints on ecological evenness (A) Boxplots showing ecological evenness across different numbers of constraints; (B) Percent increase in mean standard error in a random forest model when each constraint is removed; (C) Average ecological evenness across all possible combinations of constraints

plot_evenness_boxplot <- ggplot(sim_ls, aes(x = n_constraints_f, y = avg_evenness_t)) +
  geom_half_point(size = 0.05, alpha = 0.1, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(aes(fill = "Latin hypercube samples"),
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE, alpha = 0.5) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#0074D9"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(1, -0.02)) +
  labs(x = "Number of constraints",
       y = "Ecological evenness",
       title = "A: Ecological evenness and constraints",
       subtitle = "Values near zero indicate high evenness",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_evenness_boxplot

ggsave(plot_evenness_boxplot, filename = here("analysis", "output", "evenness_A.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_evenness_boxplot, filename = here("analysis", "output", "evenness_A.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
plot_evenness_hl_diffs <- ggplot(mapping = aes(x = n_constraints_f, y = avg_evenness_t, fill = repp)) +
  geom_text(data = filter(diff_hl_outcomes_plot, outcome == "evenness"),
            aes(y = 0, label = nice_diff, fill = NULL),
            family = "DejaVu Sans Condensed", fontface = "plain", size = 1.5, vjust = -0.85) +
  geom_half_boxplot(data = sim_high,
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  geom_half_boxplot(data = sim_low,
                    size = 0.25, side = "r", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  stat_summary(data = sim_high, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.22)) +
  stat_summary(data = sim_low, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = 0.22)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#2ECC40", "#FF851B"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(1, -0.02)) +
  labs(x = "Number of constraints",
       y = "Ecological evenness",
       title = "B: Constraints across high/low",
       subtitle = "∆ = high − low",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value; * = p < 0.05")) +
  theme_constraint() +
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_evenness_hl_diffs

combined_evenness <- plot_evenness_boxplot + plot_evenness_hl_diffs

combined_evenness

ggsave(combined_evenness, filename = here("analysis", "output", "evenness_boxplots.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(combined_evenness, filename = here("analysis", "output", "evenness_boxplots.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_evenness, filename = here("analysis", "output", "evenness_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_evenness, filename = here("analysis", "output", "evenness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
# This takes a few minutes to run
set.seed(SEED)
forest_model_evenness <- 
  randomForest(avg_evenness_t ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = drop_na(sim_ls, avg_evenness_t))

forest_model_evenness_low <- 
  randomForest(avg_evenness_t ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, avg_evenness_t), repp == "Low"))

forest_model_evenness_high <- 
  randomForest(avg_evenness_t ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, avg_evenness_t), repp == "High"))
evenness_importance_ls <- importance(forest_model_evenness, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  arrange(desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_evenness_importance_ls <- ggplot(evenness_importance_ls, 
       aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
           color = fct_rev(constraint), shape = "Latin hypercube samples")) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_shape_manual(values = c(19), name = NULL) +
  guides(shape = guide_legend(direction = "horizontal",
                                          override.aes = list(size = 0.25))) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "B: Constraint importance for ecological evenness",
       subtitle = "Higher values indicate greater variable importance",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_evenness_importance_ls

ggsave(plot_evenness_importance_ls, filename = here("analysis", "output", "evenness_B.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_evenness_importance_ls, filename = here("analysis", "output", "evenness_B.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
evenness_importance_low <- importance(forest_model_evenness_low, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "Low")

evenness_importance_high <- importance(forest_model_evenness_high, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "High")

evenness_importance_hl <- bind_rows(evenness_importance_low,
                                    evenness_importance_high) %>% 
  mutate(repp = factor(repp, levels = c("Low", "High"), ordered = TRUE)) %>% 
  arrange(desc(repp), desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_evenness_importance_hl <- ggplot(evenness_importance_hl, 
                                      aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
                                          color = fct_rev(constraint), 
                                          linetype = repp, shape = repp)) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE),
                   position = position_dodgev(height = 0.5), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_linetype_manual(values = c("dashed", "solid"), name = NULL) +
  scale_shape_manual(values = c(17, 15), name = NULL) +
  guides(linetype = guide_legend(direction = "horizontal", reverse = TRUE),
         shape = guide_legend(direction = "horizontal", override.aes = list(size = 0.25),
                              reverse = TRUE)) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "D: Constraint importance across high/low",
       subtitle = "",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_evenness_importance_hl

importance_evenness <- plot_evenness_importance_ls + plot_evenness_importance_hl

importance_evenness

ggsave(importance_evenness, filename = here("analysis", "output", "evenness_importance.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(importance_evenness, filename = here("analysis", "output", "evenness_importance.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
plot_evenness_all <- mega_means_plot(constraint_combo_outcomes_ls, avg_evenness_t, 
                                     xlab = "Average ecological evenness", 
                                     title = "Average ecological evenness across combinations of constraints", 
                                     add_to_left = 0.08)

plot_evenness_all

ggsave(plot_evenness_all, filename = here("analysis", "output", "evenness_means_all.pdf"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", device = cairo_pdf)
ggsave(plot_evenness_all, filename = here("analysis", "output", "evenness_means_all.png"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", type = "cairo", dpi = 300)

Figure 7: Landscape richness

Fig 7. Effect of the number of constraints on species richness (A) Boxplots showing species richness across different numbers of constraints; (B) Percent increase in mean standard error in a random forest model when each constraint is removed; (C) Average species richness across all possible combinations of constraints

plot_richness_boxplot <- ggplot(sim_ls, aes(x = n_constraints_f, y = landscape_richness_mean)) +
  geom_half_point(size = 0.01, alpha = 0.01, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(aes(fill = "Latin hypercube samples"),
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE, alpha = 0.5) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#0074D9"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(35, -1)) +
  labs(x = "Number of constraints",
       y = "Landscape richness",
       title = "A: Landscape richness and constraints",
       subtitle = "Values near zero indicate low species richness",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_richness_boxplot

ggsave(plot_richness_boxplot, filename = here("analysis", "output", "richness_A.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_richness_boxplot, filename = here("analysis", "output", "richness_A.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
plot_richness_hl_diffs <- ggplot(mapping = aes(x = n_constraints_f, y = landscape_richness_mean, fill = repp)) +
  geom_text(data = filter(diff_hl_outcomes_plot, outcome == "richness"),
            aes(y = 0, label = nice_diff, fill = NULL),
            family = "DejaVu Sans Condensed", fontface = "plain", size = 1.5, vjust = -0.85) +
  geom_half_boxplot(data = sim_high,
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  geom_half_boxplot(data = sim_low,
                    size = 0.25, side = "r", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  stat_summary(data = sim_high, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.22)) +
  stat_summary(data = sim_low, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = 0.22)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#2ECC40", "#FF851B"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(35, -1)) +
  labs(x = "Number of constraints",
       y = "Landscape richness",
       title = "B: Constraints across high/low",
       subtitle = "∆ = high − low",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value; * = p < 0.05")) +
  theme_constraint() +
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_richness_hl_diffs

combined_richness <- plot_richness_boxplot + plot_richness_hl_diffs

combined_richness

ggsave(combined_richness, filename = here("analysis", "output", "richness_boxplots.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(combined_richness, filename = here("analysis", "output", "richness_boxplots.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_richness, filename = here("analysis", "output", "richness_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_richness, filename = here("analysis", "output", "richness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
# This takes a few minutes to run
set.seed(SEED)
forest_model_richness <- 
  randomForest(landscape_richness_mean ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = drop_na(sim_ls, landscape_richness_mean))

forest_model_richness_low <- 
  randomForest(landscape_richness_mean ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, landscape_richness_mean), repp == "Low"))

forest_model_richness_high <- 
  randomForest(landscape_richness_mean ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, landscape_richness_mean), repp == "High"))
richness_importance_ls <- importance(forest_model_richness, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  arrange(desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_richness_importance_ls <- ggplot(richness_importance_ls, 
       aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
           color = fct_rev(constraint), shape = "Latin hypercube samples")) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_shape_manual(values = c(19), name = NULL) +
  guides(shape = guide_legend(direction = "horizontal",
                                          override.aes = list(size = 0.25))) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "B: Constraint importance for landscape richness",
       subtitle = "Higher values indicate greater variable importance",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_richness_importance_ls

ggsave(plot_richness_importance_ls, filename = here("analysis", "output", "richness_B.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_richness_importance_ls, filename = here("analysis", "output", "richness_B.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
richness_importance_low <- importance(forest_model_richness_low, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "Low")

richness_importance_high <- importance(forest_model_richness_high, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "High")

richness_importance_hl <- bind_rows(richness_importance_low,
                                    richness_importance_high) %>% 
  mutate(repp = factor(repp, levels = c("Low", "High"), ordered = TRUE)) %>% 
  arrange(desc(repp), desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_richness_importance_hl <- ggplot(richness_importance_hl, 
                                      aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
                                          color = fct_rev(constraint), 
                                          linetype = repp, shape = repp)) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE),
                   position = position_dodgev(height = 0.5), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_linetype_manual(values = c("dashed", "solid"), name = NULL) +
  scale_shape_manual(values = c(17, 15), name = NULL) +
  guides(linetype = guide_legend(direction = "horizontal", reverse = TRUE),
         shape = guide_legend(direction = "horizontal", override.aes = list(size = 0.25),
                              reverse = TRUE)) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "D: Constraint importance across high/low",
       subtitle = "",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_richness_importance_hl

importance_richness <- plot_richness_importance_ls + plot_richness_importance_hl

importance_richness

ggsave(importance_richness, filename = here("analysis", "output", "richness_importance.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(importance_richness, filename = here("analysis", "output", "richness_importance.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
plot_richness_all <- mega_means_plot(constraint_combo_outcomes_ls, landscape_richness_mean, 
                                     xlab = "Average landscape richness", 
                                     title = "Average landscape richness across combinations of constraints", 
                                     add_to_left = 1)

plot_richness_all

ggsave(plot_richness_all, filename = here("analysis", "output", "richness_means_all.pdf"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", device = cairo_pdf)
ggsave(plot_richness_all, filename = here("analysis", "output", "richness_means_all.png"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", type = "cairo", dpi = 300)

Figure 8: Difference in turnover

Fig 8. Effect of the number of constraints on the difference between turnover in linked and unlinked species (A) Boxplots showing difference between turnover in linked and unlinked species across different numbers of constraints; (B) Percent increase in mean standard error in a random forest model when each constraint is removed; (C) Average difference across all possible combinations of constraints

plot_turnover_boxplot <- ggplot(sim_ls, aes(x = n_constraints_f, y = turnover_diff)) +
  geom_half_point(size = 0.01, alpha = 0.01, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(aes(fill = "Latin hypercube samples"),
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE, alpha = 0.5) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#0074D9"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(1, -1)) +
  labs(x = "Number of constraints",
       y = "∆ turnover",
       title = "A: ∆ turnover and constraints",
       subtitle = "Turnover in linked species − turnover in unlinked species",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_turnover_boxplot

ggsave(plot_turnover_boxplot, filename = here("analysis", "output", "turnover_A.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_turnover_boxplot, filename = here("analysis", "output", "turnover_A.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
plot_turnover_hl_diffs <- ggplot(mapping = aes(x = n_constraints_f, y = turnover_diff, fill = repp)) +
  geom_text(data = filter(diff_hl_outcomes_plot, outcome == "richness"),
            aes(y = -0.35, label = nice_diff, fill = NULL),
            family = "DejaVu Sans Condensed", fontface = "plain", size = 1.5, vjust = -0.85) +
  geom_half_boxplot(data = sim_high,
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  geom_half_boxplot(data = sim_low,
                    size = 0.25, side = "r", outlier.shape = NA, errorbar.draw = TRUE,
                    nudge = 0.05, alpha = 0.5) +
  stat_summary(data = sim_high, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.22)) +
  stat_summary(data = sim_low, geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = 0.22)) +
  scale_y_reverse() +
  scale_fill_manual(values = c("#2ECC40", "#FF851B"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(1, -1)) +
  labs(x = "Number of constraints",
       y = "∆ turnover",
       title = "B: Constraints across high/low",
       subtitle = "∆ = high − low",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value; * = p < 0.05")) +
  theme_constraint() +
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_turnover_hl_diffs

combined_turnover <- plot_turnover_boxplot + plot_turnover_hl_diffs

combined_turnover

ggsave(combined_turnover, filename = here("analysis", "output", "turnover_boxplots.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(combined_turnover, filename = here("analysis", "output", "turnover_boxplots.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_turnover, filename = here("analysis", "output", "turnover_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_turnover, filename = here("analysis", "output", "turnover_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
# This takes a few minutes to run
set.seed(SEED)
forest_model_turnover <- 
  randomForest(turnover_diff ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = drop_na(sim_ls, turnover_diff))

forest_model_turnover_low <- 
  randomForest(turnover_diff ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, turnover_diff), repp == "Low"))

forest_model_turnover_high <- 
  randomForest(turnover_diff ~
                 create_network + select + disperse + 
                 compete + selectfor_d + catastrophe,
               importance = TRUE, 
               data = filter(drop_na(sim_hl, turnover_diff), repp == "High"))
turnover_importance_ls <- importance(forest_model_turnover, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  arrange(desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_turnover_importance_ls <- ggplot(turnover_importance_ls, 
                                      aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
                                          color = fct_rev(constraint), 
                                          shape = "Latin hypercube samples")) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_shape_manual(values = c(19), name = NULL) +
  guides(shape = guide_legend(direction = "horizontal",
                              override.aes = list(size = 0.25))) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "B: Constraint importance for ∆ species turnover",
       subtitle = "Higher values indicate greater variable importance",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_turnover_importance_ls

ggsave(plot_turnover_importance_ls, filename = here("analysis", "output", "turnover_B.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_turnover_importance_ls, filename = here("analysis", "output", "turnover_B.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
turnover_importance_low <- importance(forest_model_turnover_low, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "Low")

turnover_importance_high <- importance(forest_model_turnover_high, type = 1, scale = TRUE) %>% 
  data.frame() %>% 
  rownames_to_column(var = "constraint") %>% 
  mutate(repp = "High")

turnover_importance_hl <- bind_rows(turnover_importance_low,
                                    turnover_importance_high) %>% 
  mutate(repp = factor(repp, levels = c("Low", "High"), ordered = TRUE)) %>% 
  arrange(desc(repp), desc(X.IncMSE)) %>% 
  mutate(constraint = recode(constraint,
                             `select` = "selection",
                             `compete` = "competition",
                             `disperse` = "dispersal",
                             `selectfor_d` = "species_drift")) %>% 
  color_constraints(constraint) %>% 
  mutate_at(vars(starts_with("constraint")), fct_inorder) %>% 
  mutate(X.IncMSE = X.IncMSE / 100)

plot_turnover_importance_hl <- ggplot(turnover_importance_hl, 
                                      aes(x = X.IncMSE, y = fct_rev(constraint_colored), 
                                          color = fct_rev(constraint), 
                                          linetype = repp, shape = repp)) +
  geom_pointrangeh(aes(xmin = 0, xmax = X.IncMSE),
                   position = position_dodgev(height = 0.5), size = 0.25) +
  scale_x_continuous(labels = percent, expand = expansion(add = c(0, 0.02))) +
  scale_color_manual(values = unlist(clrs), guide = FALSE) +
  scale_linetype_manual(values = c("dashed", "solid"), name = NULL) +
  scale_shape_manual(values = c(17, 15), name = NULL) +
  guides(linetype = guide_legend(direction = "horizontal", reverse = TRUE),
         shape = guide_legend(direction = "horizontal", override.aes = list(size = 0.25),
                              reverse = TRUE)) +
  labs(x = "Percent increase in MSE when excluded", y = NULL, 
       title = "D: Constraint importance across high/low",
       subtitle = "",
       caption = "") +
  theme_constraint() + 
  theme(panel.grid.major.y = element_blank(),
        axis.text.y = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_markdown(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.75, unit = "lines"),
        legend.key.width = unit(2.5, "lines"),
        legend.key.size = unit(0.95, "lines"))
plot_turnover_importance_hl

importance_turnover <- plot_turnover_importance_ls + plot_turnover_importance_hl

importance_turnover

ggsave(importance_turnover, filename = here("analysis", "output", "turnover_importance.pdf"),
       width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(importance_turnover, filename = here("analysis", "output", "turnover_importance.png"),
       width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 300)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.tiff"),
#        width = params$fig_width2, height = params$fig_height, units = "in", type = "cairo", dpi = 600)
# ggsave(combined_fitness, filename = here("analysis", "output", "fitness_combined.eps"),
#        width = params$fig_width2, height = params$fig_height, units = "in", device = cairo_ps, fallback_resolution = 600) 
plot_turnover_all <- mega_means_plot(constraint_combo_outcomes_ls, turnover_diff, 
                                     xlab = "Average ∆ turnover", 
                                     title = "Average ∆ in turnover (linked species − unlinked species) across combinations of constraints", 
                                     add_to_right = 0.02, add_to_left = 0.02, xlim = c(-0.1, 0.3))

plot_turnover_all

ggsave(plot_turnover_all, filename = here("analysis", "output", "turnover_means_all.pdf"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", device = cairo_pdf)
ggsave(plot_turnover_all, filename = here("analysis", "output", "turnover_means_all.png"),
       width = params$fig_width_big, height = params$fig_height_big, units = "in", type = "cairo", dpi = 300)

Figure 9: Landscape variation

Fig 9. Overall landscape variation in species richness

plot_variation_boxplot <- ggplot(sim_ls, aes(x = n_constraints_f, y = landscape_species_number_var)) +
  geom_half_point(size = 0.01, alpha = 0.01, side = "r", color = "grey50",
                  transformation_params = list(width = 0.25, height = 0, seed = 1234)) +
  geom_half_boxplot(aes(fill = "Latin hypercube samples"),
                    size = 0.25, side = "l", outlier.shape = NA, errorbar.draw = TRUE, alpha = 0.5) +
  stat_summary(geom = "point", fun = "mean",
               size = 1, pch = 23, fill = clrs$grey, color = "white",
               position = position_nudge(x = -0.19)) +
  # scale_y_reverse() +
  scale_fill_manual(values = c("#0074D9"), name = NULL) +
  guides(fill = guide_legend(direction = "horizontal", override.aes = list(alpha = 0.3, size = 0.25))) +
  coord_cartesian(ylim = c(0, 300)) +
  labs(x = "Number of constraints",
       y = "Landscape variation in species richness",
       title = "A: Landscape variation in species richness",
       # subtitle = "Values near zero indicate high variation",
       caption = glue("<span style='color:{clrs$grey}'>◆</span> = mean value")) +
  theme_constraint() + 
  theme(panel.grid.major.x = element_blank(),
        plot.caption = element_markdown(),
        plot.title.position = "plot",
        legend.position = c(0, 0),
        legend.justification = "left",
        legend.text = element_text(size = rel(0.7)),
        legend.box.margin = ggplot2::margin(l = -0.5, t = 4.15, unit = "lines"),
        legend.key.size = unit(0.75, "lines"))
plot_variation_boxplot

ggsave(plot_variation_boxplot, filename = here("analysis", "output", "landscape_species.pdf"),
       width = params$fig_width, height = params$fig_height, units = "in", device = cairo_pdf)
ggsave(plot_variation_boxplot, filename = here("analysis", "output", "landscape_species.png"),
       width = params$fig_width, height = params$fig_height, units = "in", type = "cairo", dpi = 300)


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)
## CXX11=$(CCACHE) g++$(VER)
## CXX14=$(CCACHE) g++$(VER)
## FC=$(CCACHE) gfortran$(VER)
## F77=$(CCACHE) gfortran$(VER)
## 
## CXX14FLAGS=-O3 -march=native -mtune=native -fPIC
devtools::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.0.2 (2020-06-22)
##  os       macOS Catalina 10.15.6      
##  system   x86_64, darwin17.0          
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       America/New_York            
##  date     2020-09-12                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version date       lib source                          
##  assertthat     0.2.1   2019-03-21 [1] CRAN (R 4.0.0)                  
##  backports      1.1.9   2020-08-24 [1] CRAN (R 4.0.2)                  
##  base64enc      0.1-3   2015-07-28 [1] CRAN (R 4.0.0)                  
##  blob           1.2.1   2020-01-20 [1] CRAN (R 4.0.0)                  
##  broom        * 0.7.0   2020-07-09 [1] CRAN (R 4.0.2)                  
##  callr          3.4.3   2020-03-28 [1] CRAN (R 4.0.0)                  
##  cellranger     1.1.0   2016-07-27 [1] CRAN (R 4.0.0)                  
##  cli            2.0.2   2020-02-28 [1] CRAN (R 4.0.0)                  
##  colorspace     1.4-1   2019-03-18 [1] CRAN (R 4.0.0)                  
##  crayon         1.3.4   2017-09-16 [1] CRAN (R 4.0.0)                  
##  curl           4.3     2019-12-02 [1] CRAN (R 4.0.0)                  
##  DBI            1.1.0   2019-12-15 [1] CRAN (R 4.0.0)                  
##  dbplyr         1.4.4   2020-05-27 [1] CRAN (R 4.0.2)                  
##  desc           1.2.0   2018-05-01 [1] CRAN (R 4.0.0)                  
##  devtools       2.3.1   2020-07-21 [1] CRAN (R 4.0.2)                  
##  digest         0.6.25  2020-02-23 [1] CRAN (R 4.0.0)                  
##  dplyr        * 1.0.2   2020-08-18 [1] CRAN (R 4.0.2)                  
##  ellipsis       0.3.1   2020-05-15 [1] CRAN (R 4.0.0)                  
##  evaluate       0.14    2019-05-28 [1] CRAN (R 4.0.0)                  
##  fansi          0.4.1   2020-01-08 [1] CRAN (R 4.0.0)                  
##  farver         2.0.3   2020-01-16 [1] CRAN (R 4.0.0)                  
##  forcats      * 0.5.0   2020-03-01 [1] CRAN (R 4.0.0)                  
##  fs             1.5.0   2020-07-31 [1] CRAN (R 4.0.2)                  
##  generics       0.0.2   2018-11-29 [1] CRAN (R 4.0.0)                  
##  ggforce      * 0.3.2   2020-06-23 [1] CRAN (R 4.0.2)                  
##  gghalves     * 0.1.0   2020-03-28 [1] CRAN (R 4.0.0)                  
##  ggplot2      * 3.3.2   2020-06-19 [1] CRAN (R 4.0.2)                  
##  ggstance     * 0.3.4   2020-04-02 [1] CRAN (R 4.0.0)                  
##  ggtext       * 0.1.0   2020-05-20 [1] Github (wilkelab/ggtext@e978034)
##  glue         * 1.4.2   2020-08-27 [1] CRAN (R 4.0.2)                  
##  gridtext       0.1.1   2020-02-24 [1] CRAN (R 4.0.0)                  
##  gtable         0.3.0   2019-03-25 [1] CRAN (R 4.0.0)                  
##  haven          2.3.1   2020-06-01 [1] CRAN (R 4.0.2)                  
##  here         * 0.1     2017-05-28 [1] CRAN (R 4.0.0)                  
##  hms            0.5.3   2020-01-08 [1] CRAN (R 4.0.0)                  
##  htmltools      0.5.0   2020-06-16 [1] CRAN (R 4.0.0)                  
##  httr           1.4.2   2020-07-20 [1] CRAN (R 4.0.2)                  
##  jsonlite       1.7.0   2020-06-25 [1] CRAN (R 4.0.2)                  
##  knitr          1.29    2020-06-23 [1] CRAN (R 4.0.2)                  
##  labeling       0.3     2014-08-23 [1] CRAN (R 4.0.0)                  
##  lifecycle      0.2.0   2020-03-06 [1] CRAN (R 4.0.0)                  
##  lubridate      1.7.9   2020-06-08 [1] CRAN (R 4.0.2)                  
##  magrittr       1.5     2014-11-22 [1] CRAN (R 4.0.0)                  
##  markdown       1.1     2019-08-07 [1] CRAN (R 4.0.0)                  
##  MASS           7.3-52  2020-08-18 [1] CRAN (R 4.0.2)                  
##  memoise        1.1.0   2017-04-21 [1] CRAN (R 4.0.0)                  
##  modelr         0.1.8   2020-05-19 [1] CRAN (R 4.0.2)                  
##  munsell        0.5.0   2018-06-12 [1] CRAN (R 4.0.0)                  
##  pander       * 0.6.3   2018-11-06 [1] CRAN (R 4.0.0)                  
##  patchwork    * 1.0.1   2020-06-22 [1] CRAN (R 4.0.2)                  
##  pillar         1.4.6   2020-07-10 [1] CRAN (R 4.0.2)                  
##  pkgbuild       1.1.0   2020-07-13 [1] CRAN (R 4.0.2)                  
##  pkgconfig      2.0.3   2019-09-22 [1] CRAN (R 4.0.0)                  
##  pkgload        1.1.0   2020-05-29 [1] CRAN (R 4.0.2)                  
##  pluralize    * 0.2.0   2020-06-09 [1] CRAN (R 4.0.2)                  
##  plyr           1.8.6   2020-03-03 [1] CRAN (R 4.0.0)                  
##  polyclip       1.10-0  2019-03-14 [1] CRAN (R 4.0.0)                  
##  prettyunits    1.1.1   2020-01-24 [1] CRAN (R 4.0.0)                  
##  processx       3.4.3   2020-07-05 [1] CRAN (R 4.0.0)                  
##  ps             1.3.4   2020-08-11 [1] CRAN (R 4.0.2)                  
##  purrr        * 0.3.4   2020-04-17 [1] CRAN (R 4.0.0)                  
##  R6             2.4.1   2019-11-12 [1] CRAN (R 4.0.0)                  
##  randomForest * 4.6-14  2018-03-25 [1] CRAN (R 4.0.2)                  
##  Rcpp           1.0.5   2020-07-06 [1] CRAN (R 4.0.2)                  
##  readr        * 1.3.1   2018-12-21 [1] CRAN (R 4.0.0)                  
##  readxl         1.3.1   2019-03-13 [1] CRAN (R 4.0.0)                  
##  remotes        2.2.0   2020-07-21 [1] CRAN (R 4.0.2)                  
##  reprex         0.3.0   2019-05-16 [1] CRAN (R 4.0.0)                  
##  rlang          0.4.7   2020-07-09 [1] CRAN (R 4.0.2)                  
##  rmarkdown      2.3     2020-06-18 [1] CRAN (R 4.0.2)                  
##  rprojroot      1.3-2   2018-01-03 [1] CRAN (R 4.0.0)                  
##  rstudioapi     0.11    2020-02-07 [1] CRAN (R 4.0.0)                  
##  rvest          0.3.6   2020-07-25 [1] CRAN (R 4.0.2)                  
##  scales       * 1.1.1   2020-05-11 [1] CRAN (R 4.0.0)                  
##  sessioninfo    1.1.1   2018-11-05 [1] CRAN (R 4.0.0)                  
##  stringi        1.4.6   2020-02-17 [1] CRAN (R 4.0.0)                  
##  stringr      * 1.4.0   2019-02-10 [1] CRAN (R 4.0.0)                  
##  testthat       2.3.2   2020-03-02 [1] CRAN (R 4.0.0)                  
##  tibble       * 3.0.3   2020-07-10 [1] CRAN (R 4.0.2)                  
##  tidyr        * 1.1.2   2020-08-27 [1] CRAN (R 4.0.2)                  
##  tidyselect     1.1.0   2020-05-11 [1] CRAN (R 4.0.0)                  
##  tidyverse    * 1.3.0   2019-11-21 [1] CRAN (R 4.0.0)                  
##  titanic      * 0.1.0   2015-08-31 [1] CRAN (R 4.0.2)                  
##  tweenr         1.0.1   2018-12-14 [1] CRAN (R 4.0.0)                  
##  usethis        1.6.1   2020-04-29 [1] CRAN (R 4.0.0)                  
##  V8             3.2.0   2020-06-19 [1] CRAN (R 4.0.2)                  
##  vctrs          0.3.4   2020-08-29 [1] CRAN (R 4.0.2)                  
##  withr          2.2.0   2020-04-20 [1] CRAN (R 4.0.0)                  
##  xfun           0.16    2020-07-24 [1] CRAN (R 4.0.2)                  
##  xml2           1.3.2   2020-04-23 [1] CRAN (R 4.0.0)                  
##  yaml           2.2.1   2020-02-01 [1] CRAN (R 4.0.0)                  
## 
## [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library
LS0tCnRpdGxlOiAiRmluYWwgYW5hbHlzaXMgZm9yIHBhcGVyIgphdXRob3I6ICJTdGV2ZW4gTC4gUGVjayBhbmQgQW5kcmV3IEhlaXNzIgpkYXRlOiAiTGFzdCBydW46IGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWUsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKcGFyYW1zOgogIGZpZ193aWR0aDogNC41CiAgZmlnX3dpZHRoMjogNi41CiAgZmlnX2hlaWdodDogMi43NQogIGZpZ193aWR0aF9odG1sOiA2CiAgZmlnX2hlaWdodF9odG1sOiAzLjUKICBmaWdfd2lkdGhfYmlnOiAxMAogIGZpZ19oZWlnaHRfYmlnOiA2Ci0tLQoKYGBge3Igc2V0dXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICMgQ1JBTiB2MS4zLjAKbGlicmFyeShicm9vbSkgICAgICAgICAjIFtnaXRodWI6OnRpZHltb2RlbHMvYnJvb21dIHYwLjUuMy45MDAwCmxpYnJhcnkocmFuZG9tRm9yZXN0KSAgIyBDUkFOIHY0LjYtMTQKbGlicmFyeShnZ3N0YW5jZSkgICAgICAjIENSQU4gdjAuMy4zCmxpYnJhcnkoZ2d0ZXh0KSAgICAgICAgIyBbZ2l0aHViOjp3aWxrZWxhYi9nZ3RleHRdIHYwLjEuMApsaWJyYXJ5KGdnaGFsdmVzKSAgICAgICMgW2dpdGh1Yjo6ZXJvY29hci9nZ2hhbHZlc10gdjAuMS4wCmxpYnJhcnkoZ2dmb3JjZSkgICAgICAgIyBDUkFOIHYwLjMuMQpsaWJyYXJ5KHBhdGNod29yaykgICAgICMgQ1JBTiB2MS4wLjAKbGlicmFyeShwYW5kZXIpICAgICAgICAjIENSQU4gdjAuNi4zCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgIyBDUkFOIHYxLjEuMApsaWJyYXJ5KHBsdXJhbGl6ZSkgICAgICMgW2dpdGh1Yjo6aHJicm1zdHIvcGx1cmFsaXplXSB2MC4xLjAKbGlicmFyeShnbHVlKSAgICAgICAgICAjIENSQU4gdjEuNC4wCmxpYnJhcnkoaGVyZSkgICAgICAgICAgIyBDUkFOIHYwLjEKCiMgRGlzYWJsZSBkcGx5cidzIGF1dG9tYXRpYyB1bmdyb3VwaW5nIG1lc3NhZ2UKb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpCgpTRUVEIDwtIDEyMzQKCnNpbV9obCA8LSByZWFkX3JkcyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJzaW1faGwucmRzIikpCnNpbV9scyA8LSByZWFkX3JkcyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJzaW1fbHMucmRzIikpCgpzaW1faGlnaCA8LSBzaW1faGwgJT4lIGZpbHRlcihyZXBwID09ICJIaWdoIikKc2ltX2xvdyA8LSBzaW1faGwgJT4lIGZpbHRlcihyZXBwID09ICJMb3ciKQoKY29uc3RyYWludF9jb21ib19vdXRjb21lc19obCA8LSByZWFkX3JkcyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfaGwucmRzIikpICU+JSAKICBtdXRhdGUoY29uc3RyYWludF9jb21ibyA9IHN0cl9yZXBsYWNlKGNvbnN0cmFpbnRfY29tYm8sICJzZWxlY3Rmb3JfZCIsICJzcGVjaWVzX2RyaWZ0IiksCiAgICAgICAgIGNvbnN0cmFpbnRfY29tYm8gPSBzdHJfcmVwbGFjZShjb25zdHJhaW50X2NvbWJvLCAic2VsZWN0IiwgInNlbGVjdGlvbiIpLAogICAgICAgICBjb25zdHJhaW50X2NvbWJvID0gc3RyX3JlcGxhY2UoY29uc3RyYWludF9jb21ibywgImNvbXBldGUiLCAiY29tcGV0aXRpb24iKSwKICAgICAgICAgY29uc3RyYWludF9jb21ibyA9IHN0cl9yZXBsYWNlKGNvbnN0cmFpbnRfY29tYm8sICJkaXNwZXJzZSIsICJkaXNwZXJzYWwiKSkKCmNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHMgPC0gcmVhZF9yZHMoaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2xzLnJkcyIpKSAlPiUgCiAgbXV0YXRlKGNvbnN0cmFpbnRfY29tYm8gPSBzdHJfcmVwbGFjZShjb25zdHJhaW50X2NvbWJvLCAic2VsZWN0Zm9yX2QiLCAic3BlY2llc19kcmlmdCIpLAogICAgICAgICBjb25zdHJhaW50X2NvbWJvID0gc3RyX3JlcGxhY2UoY29uc3RyYWludF9jb21ibywgInNlbGVjdCIsICJzZWxlY3Rpb24iKSwKICAgICAgICAgY29uc3RyYWludF9jb21ibyA9IHN0cl9yZXBsYWNlKGNvbnN0cmFpbnRfY29tYm8sICJjb21wZXRlIiwgImNvbXBldGl0aW9uIiksCiAgICAgICAgIGNvbnN0cmFpbnRfY29tYm8gPSBzdHJfcmVwbGFjZShjb25zdHJhaW50X2NvbWJvLCAiZGlzcGVyc2UiLCAiZGlzcGVyc2FsIikpCgpkaWZmX2hsX291dGNvbWVzX2Z1bGwgPC0gc2ltX2hsICU+JQogIGdyb3VwX2J5KG5fY29uc3RyYWludHNfZikgJT4lCiAgbmVzdCgpICU+JQogIG11dGF0ZShmaXRuZXNzX3Rlc3QgPSBtYXAoZGF0YSwgfnQudGVzdChsYW5kc2NhcGVfZml0bmVzc19saW5rZWQgfiByZXBwLCBkYXRhID0gLikpLAogICAgICAgICBldmVubmVzc190ZXN0ID0gbWFwKGRhdGEsIH50LnRlc3QoYXZnX2V2ZW5uZXNzX3QgfiByZXBwLCBkYXRhID0gLikpLAogICAgICAgICByaWNobmVzc190ZXN0ID0gbWFwKGRhdGEsIH50LnRlc3QobGFuZHNjYXBlX3JpY2huZXNzX21lYW4gfiByZXBwLCBkYXRhID0gLikpLAogICAgICAgICB0dXJub3Zlcl90ZXN0ID0gbWFwKGRhdGEsIH50LnRlc3QodHVybm92ZXJfZGlmZiB+IHJlcHAsIGRhdGEgPSAuKSkpICU+JQogIG11dGF0ZV9hdCh2YXJzKGVuZHNfd2l0aCgidGVzdCIpKSwgbGlzdCh0aWR5ID0gfm1hcCguLCB+dGlkeSguKSkpKSAlPiUKICBtdXRhdGVfYXQodmFycyhlbmRzX3dpdGgoInRpZHkiKSksIGxpc3QoZGlmZiA9IH5tYXBfZGJsKC4sICJlc3RpbWF0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLnZhbHVlID0gfm1hcF9kYmwoLiwgInAudmFsdWUiKSkpICU+JQogIHVuZ3JvdXAoKQoKZGlmZl9obF9vdXRjb21lc19wbG90IDwtIGRpZmZfaGxfb3V0Y29tZXNfZnVsbCAlPiUKICBzZWxlY3QoLWRhdGEsIC1lbmRzX3dpdGgoIl90ZXN0IiksIC1lbmRzX3dpdGgoIl90aWR5IikpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLW5fY29uc3RyYWludHNfZikgJT4lCiAgbXV0YXRlKG5hbWUgPSBzdHJfcmVwbGFjZShuYW1lLCAiX3Rlc3RfdGlkeV8iLCAiXyIpKSAlPiUKICBzZXBhcmF0ZShuYW1lLCBpbnRvID0gYygib3V0Y29tZSIsICJzdGF0aXN0aWMiKSwgc2VwID0gIl8iKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gInN0YXRpc3RpYyIpICU+JQogIG11dGF0ZShzaWcgPSBpZmVsc2UocC52YWx1ZSA8IDAuMDUsICIqIiwgIiIpLAogICAgICAgICBzaWcgPSBpZmVsc2UoaXMubmFuKHAudmFsdWUpLCAiIiwgc2lnKSkgJT4lCiAgbXV0YXRlKG5pY2VfZGlmZiA9IGdsdWUoIuKIhiA9IHtyb3VuZChkaWZmLCAzKX17c2lnfSIpKSAlPiUKICBtdXRhdGUobmljZV9kaWZmID0gc3RyX3JlcGxhY2UobmljZV9kaWZmLCAiXFwtIiwgIuKIkiIpKQpgYGAKCmBgYHtyIHBsb3R0aW5nLWZ1bmN0aW9uc30KdGhlbWVfY29uc3RyYWludCA8LSBmdW5jdGlvbihiYXNlX3NpemUgPSA4LCBiYXNlX2ZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiKSB7CiAgcmV0IDwtIHRoZW1lX2J3KGJhc2Vfc2l6ZSwgYmFzZV9mYW1pbHkpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjEpLCBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiRGVqYVZ1IFNhbnMgQ29uZGVuc2VkIiksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44KSwgZmFjZSA9ICJwbGFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiKSwKICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuOCksIGNvbG9yID0gImdyZXk1MCIsIGZhY2UgPSAicGxhaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbih0ID0gNSkpLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImdyZXk1MCIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuMTUpLAogICAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMSwgImxpbmVzIiksCiAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuOSksIGhqdXN0ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIkRlamFWdSBTYW5zIENvbmRlbnNlZCIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmZmZmZmYiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbih0ID0gNSkpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiLCBmYWNlID0gInBsYWluIiksCiAgICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxKSwgZmFtaWx5ID0gIkRlamFWdSBTYW5zIENvbmRlbnNlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJwbGFpbiIpLAogICAgICAgICAgbGVnZW5kLnNwYWNpbmcgPSB1bml0KDAuMSwgImxpbmVzIiksCiAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbih0ID0gLTAuNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbih0ID0gMCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCiAgcmV0Cn0KCiMgQ29sb3JzIGZyb20gaHR0cHM6Ly9tZWRpYWxhYi5naXRodWIuaW8vaXdhbnRodWUvCiMgNiBjb2xvcnMsIGRlZmF1bHQgcGFsZXR0ZSwgc29mdCAoay1tZWFucykKY2xycyA8LSBsaXN0KAogIHNlbGVjdCA9ICIjNjI5NWNkIiwgICMgYmx1ZQogIHNlbGVjdGlvbiA9ICIjNjI5NWNkIiwgICMgYmx1ZQogIGNvbXBldGUgPSAiI2IzOTQzZiIsICAjIGdvbGQKICBjb21wZXRpdGlvbiA9ICIjYjM5NDNmIiwgICMgZ29sZAogIGNhdGFzdHJvcGhlID0gIiM5NDY2YzkiLCAgIyBwdXJwbGUKICBjcmVhdGVfbmV0d29yayA9ICIjNjJhODViIiwgICMgZ3JlZW4KICBkaXNwZXJzYWwgPSAiI2M4NTk5MCIsICAjIHBpbmsKICBkaXNwZXJzZSA9ICIjYzg1OTkwIiwgICMgcGluawogIHNlbGVjdGZvcl9kID0gIiNjYTVkNDYiLCAgIyByZWRkaXNoCiAgc3BlY2llc19kcmlmdCA9ICIjY2E1ZDQ2IiwgICMgcmVkZGlzaAogIGdyZXkgPSAiIzdmN2Y3ZiIgICMgZ3JleTUwCikKCmNvbG9yX2NvbnN0cmFpbnRzIDwtIGZ1bmN0aW9uKGRmLCBjb25zdHJhaW50X2NvbCkgewogIGRmICU+JSAKICAgIG11dGF0ZShjb25zdHJhaW50X2NvbG9yZWQgPSB7e2NvbnN0cmFpbnRfY29sfX0pICU+JSAKICAgIG11dGF0ZShjb25zdHJhaW50X2NvbG9yZWQgPQogICAgICAgICAgICAgc3RyX3JlcGxhY2VfYWxsKGNvbnN0cmFpbnRfY29sb3JlZCwgICJcXGJzZWxlY3RcXGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRzZWxlY3R9Jz5zZWxlY3Q8L3NwYW4+IikpLAogICAgICAgICAgIGNvbnN0cmFpbnRfY29sb3JlZCA9CiAgICAgICAgICAgICBzdHJfcmVwbGFjZV9hbGwoY29uc3RyYWludF9jb2xvcmVkLCAgIlxcYnNlbGVjdGlvblxcYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJHNlbGVjdGlvbn0nPnNlbGVjdGlvbjwvc3Bhbj4iKSksCiAgICAgICAgICAgY29uc3RyYWludF9jb2xvcmVkID0KICAgICAgICAgICAgIHN0cl9yZXBsYWNlX2FsbChjb25zdHJhaW50X2NvbG9yZWQsICJcXGJjb21wZXRlXFxiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6e2NscnMkY29tcGV0ZX0nPmNvbXBldGU8L3NwYW4+IikpLAogICAgICAgICAgIGNvbnN0cmFpbnRfY29sb3JlZCA9CiAgICAgICAgICAgICBzdHJfcmVwbGFjZV9hbGwoY29uc3RyYWludF9jb2xvcmVkLCAiXFxiY29tcGV0aXRpb25cXGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRjb21wZXRpdGlvbn0nPmNvbXBldGl0aW9uPC9zcGFuPiIpKSwKICAgICAgICAgICBjb25zdHJhaW50X2NvbG9yZWQgPQogICAgICAgICAgICAgc3RyX3JlcGxhY2VfYWxsKGNvbnN0cmFpbnRfY29sb3JlZCwgIlxcYmNhdGFzdHJvcGhlXFxiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6e2NscnMkY2F0YXN0cm9waGV9Jz5jYXRhc3Ryb3BoZTwvc3Bhbj4iKSksCiAgICAgICAgICAgY29uc3RyYWludF9jb2xvcmVkID0KICAgICAgICAgICAgIHN0cl9yZXBsYWNlX2FsbChjb25zdHJhaW50X2NvbG9yZWQsICJcXGJjcmVhdGVfbmV0d29ya1xcYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGNyZWF0ZV9uZXR3b3JrfSc+Y3JlYXRlX25ldHdvcms8L3NwYW4+IikpLAogICAgICAgICAgIGNvbnN0cmFpbnRfY29sb3JlZCA9CiAgICAgICAgICAgICBzdHJfcmVwbGFjZV9hbGwoY29uc3RyYWludF9jb2xvcmVkLCAiXFxiZGlzcGVyc2VcXGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRkaXNwZXJzZX0nPmRpc3BlcnNlPC9zcGFuPiIpKSwKICAgICAgICAgICBjb25zdHJhaW50X2NvbG9yZWQgPQogICAgICAgICAgICAgc3RyX3JlcGxhY2VfYWxsKGNvbnN0cmFpbnRfY29sb3JlZCwgIlxcYmRpc3BlcnNhbFxcYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGRpc3BlcnNhbH0nPmRpc3BlcnNhbDwvc3Bhbj4iKSksCiAgICAgICAgICAgY29uc3RyYWludF9jb2xvcmVkID0KICAgICAgICAgICAgIHN0cl9yZXBsYWNlX2FsbChjb25zdHJhaW50X2NvbG9yZWQsICJcXGJzZWxlY3Rmb3JfZFxcYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJHNlbGVjdGZvcl9kfSc+c2VsZWN0Zm9yX2Q8L3NwYW4+IikpLAogICAgICAgICAgIGNvbnN0cmFpbnRfY29sb3JlZCA9CiAgICAgICAgICAgICBzdHJfcmVwbGFjZV9hbGwoY29uc3RyYWludF9jb2xvcmVkLCAiXFxic3BlY2llc19kcmlmdFxcYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJHNwZWNpZXNfZHJpZnR9Jz5zcGVjaWVzX2RyaWZ0PC9zcGFuPiIpKSkKfQoKIyBGdW5jdGlvbiBmb3IgcGxvdHRpbmcgb3V0Y29tZXMgYWNyb3NzIGNvbWJpbmF0aW9ucyBvZiBjb25zdHJhaW50cwptZWdhX21lYW5zX3Bsb3QgPC0gZnVuY3Rpb24oZGYsIHZhcl9uYW1lLCB4bGFiLCB0aXRsZSwgYWRkX3RvX3JpZ2h0ID0gMCwgYWRkX3RvX2xlZnQgPSAwLjAzLCB4bGltID0gTlVMTCkgewogIGNvbnN0cmFpbnRfY29tYm9zIDwtIGRmICU+JQogICAgZ3JvdXBfYnkoY29uc3RyYWludF9jb21ibywgbikgJT4lCiAgICBzdW1tYXJpemUoYXZnID0gbWVhbih7e3Zhcl9uYW1lfX0pKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MobiksIGRlc2MoYXZnKSkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIG11dGF0ZShjb25zdHJhaW50X2NvbWJvID0gaWZlbHNlKG4gPj0gNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfd3JhcChjb25zdHJhaW50X2NvbWJvLCB3aWR0aCA9IDQwLCBleGRlbnQgPSA4KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdHJhaW50X2NvbWJvKSkgJT4lIAogICAgbXV0YXRlKGNvbnN0cmFpbnRfY29tYm8gPSBzdHJfcmVwbGFjZV9hbGwoY29uc3RyYWludF9jb21ibywgIiB7OH0iLCAiPGJyPiIpKSAlPiUgCiAgICBtdXRhdGUoY29uc3RyYWludF9jb21ibyA9IHJlY29kZShjb25zdHJhaW50X2NvbWJvLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBjb21wZXRlYCA9ICJjb21wZXRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgZGlzcGVyc2VgID0gImRpc3BlcnNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogICAgY29sb3JfY29uc3RyYWludHMoY29uc3RyYWludF9jb21ibykgJT4lIAogICAgbXV0YXRlKGNvbnN0cmFpbnRfY29sb3JlZCA9IGZjdF9pbm9yZGVyKGNvbnN0cmFpbnRfY29sb3JlZCksCiAgICAgICAgICAgbl90aXRsZSA9IG1hcF9jaHIobiwgfnBhc3RlMCguLCBwbHVyYWxpemUoIiBjb25zdHJhaW50IiwgLikpKSkKICAKICBwbG90XzAyIDwtIGdncGxvdChmaWx0ZXIoY29uc3RyYWludF9jb21ib3MsIG4gJWluJSBjKDAsIDEsIDIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXZnLCB5ID0gY29uc3RyYWludF9jb2xvcmVkKSkgKwogICAgZ2VvbV9wb2ludHJhbmdlaChhZXMoeG1pbiA9IDAsIHhtYXggPSBhdmcpKSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSBjKGFkZF90b19yaWdodCwgYWRkX3RvX2xlZnQpKSkgKwogICAgbGFicyh4ID0geGxhYiwgeSA9IE5VTEwpICsKICAgIGZhY2V0X2NvbCh2YXJzKG5fdGl0bGUpLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZSIpICsKICAgIHRoZW1lX2NvbnN0cmFpbnQoKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmV5ODAiKSkKICAKICBwbG90XzMgPC0gZ2dwbG90KGZpbHRlcihjb25zdHJhaW50X2NvbWJvcywgbiA9PSAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmcsIHkgPSBjb25zdHJhaW50X2NvbG9yZWQpKSArCiAgICBnZW9tX3BvaW50cmFuZ2VoKGFlcyh4bWluID0gMCwgeG1heCA9IGF2ZykpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoYWRkX3RvX3JpZ2h0LCBhZGRfdG9fbGVmdCkpKSArCiAgICBsYWJzKHggPSB4bGFiLCB5ID0gTlVMTCkgKwogICAgZmFjZXRfY29sKHZhcnMobl90aXRsZSksIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlIikgKwogICAgdGhlbWVfY29uc3RyYWludCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyZXk4MCIpKQogIAogIHBsb3RfNDYgPC0gZ2dwbG90KGZpbHRlcihjb25zdHJhaW50X2NvbWJvcywgbiAlaW4lIGMoNCwgNSwgNikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmcsIHkgPSBjb25zdHJhaW50X2NvbG9yZWQpKSArCiAgICBnZW9tX3BvaW50cmFuZ2VoKGFlcyh4bWluID0gMCwgeG1heCA9IGF2ZykpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoYWRkX3RvX3JpZ2h0LCBhZGRfdG9fbGVmdCkpKSArCiAgICBsYWJzKHggPSB4bGFiLCB5ID0gTlVMTCkgKwogICAgZmFjZXRfY29sKHZhcnMobl90aXRsZSksIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlIikgKwogICAgdGhlbWVfY29uc3RyYWludCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyZXk4MCIpKQogIAogIGlmICghaXMubnVsbCh4bGltKSkgewogICAgcGxvdF8wMiA8LSBwbG90XzAyICsgY29vcmRfY2FydGVzaWFuKHhsaW0gPSB4bGltKQogICAgcGxvdF8zIDwtIHBsb3RfMyArIGNvb3JkX2NhcnRlc2lhbih4bGltID0geGxpbSkKICAgIHBsb3RfNDYgPC0gcGxvdF80NiArIGNvb3JkX2NhcnRlc2lhbih4bGltID0geGxpbSkKICB9CiAgCiAgcGxvdF9hbGwgPC0gKHBsb3RfMDIgfCBwbG90XzMgfCBwbG90XzQ2KSArCiAgICBwbG90X2Fubm90YXRpb24odGl0bGUgPSB0aXRsZSwKICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjEpLCBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiRGVqYVZ1IFNhbnMgQ29uZGVuc2VkIikpKQogIHBsb3RfYWxsCn0KYGBgCgoKIyBWYXJpYWJsZSBpbXBvcnRhbmNlCgpUbyBkZXRlcm1pbmUgd2hpY2ggY29uc3RyYWludHMgbWF0dGVyIHRoZSBtb3N0LCB3ZSB1c2UgcmFuZG9tIGZvcmVzdHMgdG8gZGV0ZXJtaW5lIHZhcmlhYmxlIGltcG9ydGFuY2UuIFdlIGRvbid0IG5lZWQgdG8gaW5jbHVkZSBhbGwgdGhlIGludGVyYWN0aW9ucyAoZS5nLiBgY3JlYXRlX25ldHdvcmsgKyBzZWxlY3QgKyBjcmVhdGVfbmV0d29yayAqIHNlbGVjdGAsIGV0Yy4pIGJlY2F1c2UgW3JhbmRvbSBmb3Jlc3RzIGluaGVyZW50bHkgcGljayB0aG9zZSB1cF0oaHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9hLzE1NzY3NC8zMDI1KS4KClRoZXJlIGFyZSB0d28gd2F5cyB0byBtZWFzdXJlIHZhcmlhYmxlIGltcG9ydGFuY2Ugd2l0aCByYW5kb20gZm9yZXN0czogKDEpIEdpbmktYmFzZWQgbm9kZSBpbXB1cml0eSwgYW5kICgyKSBwZXJtdXRhdGlvbi1iYXNlZCBpbmNyZWFzZSBpbiBtZWFuIHN0YW5kYXJkIGVycm9yLiBHaW5pLWJhc2VkIG5vZGUgaW1wdXJpdHkgaXMgdHJpY2tpZXIgdG8gaW50ZXJwcmV0LiBBY2NvcmRpbmcgdG8gW0xpeiBEaW5zZGFsZV0oaHR0cHM6Ly9kaW5zZGFsZWxhYi5zZHN1LmVkdS9tZXRhZy5zdGF0cy9jb2RlL3JhbmRvbWZvcmVzdC5odG1sKToKCj4gVGhlIG1lYW4gZGVjcmVhc2UgaW4gR2luaSBjb2VmZmljaWVudCBpcyBhIG1lYXN1cmUgb2YgaG93IGVhY2ggdmFyaWFibGUgY29udHJpYnV0ZXMgdG8gdGhlIGhvbW9nZW5laXR5IG9mIHRoZSBub2RlcyBhbmQgbGVhdmVzIGluIHRoZSByZXN1bHRpbmcgcmFuZG9tIGZvcmVzdC4gRWFjaCB0aW1lIGEgcGFydGljdWxhciB2YXJpYWJsZSBpcyB1c2VkIHRvIHNwbGl0IGEgbm9kZSwgdGhlIEdpbmkgY29lZmZpY2llbnQgZm9yIHRoZSBjaGlsZCBub2RlcyBhcmUgY2FsY3VsYXRlZCBhbmQgY29tcGFyZWQgdG8gdGhhdCBvZiB0aGUgb3JpZ2luYWwgbm9kZS4gVGhlIEdpbmkgY29lZmZpY2llbnQgaXMgYSBtZWFzdXJlIG9mIGhvbW9nZW5laXR5IGZyb20gMCAoaG9tb2dlbmVvdXMpIHRvIDEgKGhldGVyb2dlbmVvdXMpLiBUaGUgY2hhbmdlcyBpbiBHaW5pIGFyZSBzdW1tZWQgZm9yIGVhY2ggdmFyaWFibGUgYW5kIG5vcm1hbGl6ZWQgYXQgdGhlIGVuZCBvZiB0aGUgY2FsY3VsYXRpb24uIFZhcmlhYmxlcyB0aGF0IHJlc3VsdCBpbiBub2RlcyB3aXRoIGhpZ2hlciBwdXJpdHkgaGF2ZSBhIGhpZ2hlciBkZWNyZWFzZSBpbiBHaW5pIGNvZWZmaWNpZW50LgoKT3IgaW4gb3RoZXIgd29yZHMsIGltcG9ydGFuY2UgaXMgdGhlIG1lYW4gZGVjcmVhc2UgKG92ZXIgYWxsIHRoZSB0cmVlcykgaW4gdGhlIEdpbmkgaW5kZXggYnkgc3BsaXRzIG9mIGEgcHJlZGljdG9yLiBCYXNpY2FsbHksIHRoZSBoaWdoZXIgdGhlIGRlY3JlYXNlIGluIGltcHVyaXR5LCB0aGUgbW9yZSBpbXBvcnRhbnQgdGhlIHZhcmlhYmxlIGluIGV4cGxhaW5pbmcgdGhlIG91dGNvbWUuCgpIb3dldmVyLCBub2RlIGltcHVyaXR5IHRlbmRzIHRvIFtpbmZsYXRlIG9yIGRpc3RvcnQgdmFyaWFibGUgaW1wb3J0YW5jZV0oaHR0cHM6Ly9ibG9nLmh3ci1iZXJsaW4uZGUvY29kZWFuZHN0YXRzL3ZhcmlhYmxlLWltcG9ydGFuY2UtaW4tcmFuZG9tLWZvcmVzdHMvKSBmb3IgY29udGludW91cyB2YXJpYWJsZXMsIGFuZCBpdCB1c2VzIHRoZSBlbnRpcmUgZGF0YSBzZXQuIEEgY29tbW9uIGFsdGVybmF0aXZlICh0aGF0IGlzIGFsc28gbW9yZSBpbnRlcnByZXRhYmxlISkgaXMgdG8gbG9vayBhdCB0aGUgcGVyY2VudCBpbmNyZWFzZSBpbiBtZWFuIHN0YW5kYXJkIGVycm9yIChzZWUgW3NsaWRlIDE1IGhlcmVdKGh0dHBzOi8vd3d3LnN0YXRpc3Rpay51bmktZG9ydG11bmQuZGUvdXNlUi0yMDA4L3NsaWRlcy9TdHJvYmwrWmVpbGVpcy5wZGYpIGFuZCBbdGhpcyBhbnN3ZXIgaGVyZV0oaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzE1ODIxODgwLzEyMDg5OCkpLiBUaGlzIG1lYXN1cmVzIGhvdyBtdWNoIHRoZSBtb2RlbCdzIE1TRSBjaGFuZ2VzIGlmIHlvdSBzaHVmZmxlIG9uZSBvZiB0aGUgdmFyaWFibGVzIChpLmUuIGlmIHlvdSBjb21wbGV0ZWx5IHNodWZmbGUgYHNlbGVjdGAsIGhvdyB3cm9uZyBkb2VzIHRoZSBtb2RlbCBiZWNvbWU/KS4gSGlnaCB2YWx1ZXMgc2hvdyB0aGF0IHRoZSB2YXJpYWJsZSBpcyBpbXBvcnRhbnQgZm9yIG1haW50YWluaW5nIGFjY3VyYWN5OyBsb3cgdmFsdWVzIHNob3cgdGhhdCB0aGUgdmFyaWFibGUgZG9lc24ndCBtYXR0ZXIgYWxsIHRoYXQgbXVjaCAoc2luY2UgaXQgY2FuIGJlIHJhbmRvbSBub2lzZSBhbmQgcmVzdWx0IGluIHNpbWlsYXIgYWNjdXJhY3kpLiBMaWtlIGhlcmUsIHRoZSBHaW5pLWJhc2VkIHZlcnNpb24gZmluZHMgdGhhdCBwYXNzZW5nZXIgSUQgaXMgaW5jcmVkaWJseSBpbXBvcnRhbnQgZm9yIHByZWRpY3Rpbmcgc3Vydml2YWwgb24gdGhlIFRpdGFuaWMsIHdoZW4gcmVhbGx5IGl0J3MganVzdCBhIHJhbmRvbSB2YXJpYWJsZSB0aGF0IGRvZXNuJ3QgbWF0dGVyLiBUaGUgcGVyY2VudC1jaGFuZ2UtaW4tTVNFLWJhc2VkIHZlcnNpb24gb2YgaW1wb3J0YW5jZSBpc24ndCBmb29sZWQgYnkgcGFzc2VuZ2VyIElELCB0aG91Z2guCgpCZWNhdXNlIG9mIHRoYXQsIHdlIHVzZSBtZWFuIGRlY3JlYXNlIGluIGFjY3VyYWN5IGFzIG91ciBtZWFzdXJlIG9mIHZhcmlhYmxlIGltcG9ydGFuY2UuCgpgYGB7ciB0aXRhbmljLWltcG9ydGFuY2UtZXhhbXBsZSwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfaHRtbCwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodF9odG1sfQpsaWJyYXJ5KHRpdGFuaWMpICAjIENSQU4gdjAuMS4wCnRpdGFuaWMgPC0gdGl0YW5pYzo6dGl0YW5pY190cmFpbiAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBtdXRhdGUoU2V4ID0gYXMuZmFjdG9yKFNleCksIFN1cnZpdmVkID0gYXMuZmFjdG9yKFN1cnZpdmVkKSwgUGNsYXNzID0gYXMuZmFjdG9yKFBjbGFzcykpCgpzZXQuc2VlZChTRUVEKQp0aXRhbmljX2ZvcmVzdCA8LSByYW5kb21Gb3Jlc3QoU3Vydml2ZWQgfiBBZ2UgKyBTZXggKyBQY2xhc3MgKyBQYXNzZW5nZXJJZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdGl0YW5pYywgaW1wb3J0YW5jZSA9IFRSVUUpCnZhckltcFBsb3QodGl0YW5pY19mb3Jlc3QpCmBgYAoKCiMgRmlndXJlcwoKIyMgRmlndXJlIDQ6IExhbmRzY2FwZSBmaXRuZXNzCgoqKkZpZyA0LiBFZmZlY3Qgb2YgdGhlIG51bWJlciBvZiBjb25zdHJhaW50cyBvbiBsYW5kc2NhcGUgZml0bmVzcyoqIChBKSBCb3hwbG90cyBzaG93aW5nIGxhbmRzY2FwZSBmaXRuZXNzIGFjcm9zcyBkaWZmZXJlbnQgbnVtYmVycyBvZiBjb25zdHJhaW50czsgKEIpIFBlcmNlbnQgaW5jcmVhc2UgaW4gbWVhbiBzdGFuZGFyZCBlcnJvciBpbiBhIHJhbmRvbSBmb3Jlc3QgbW9kZWwgd2hlbiBlYWNoIGNvbnN0cmFpbnQgaXMgcmVtb3ZlZDsgKEMpIEF2ZXJhZ2UgbGFuZHNjYXBlIGZpdG5lc3MgYWNyb3NzIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgY29uc3RyYWludHMKCmBgYHtyIGxhbmRzY2FwZS1maXRuZXNzLWxzLWJveHBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcGxvdF9maXRuZXNzX2JveHBsb3QgPC0gZ2dwbG90KHNpbV9scywgYWVzKHggPSBuX2NvbnN0cmFpbnRzX2YsIHkgPSBsYW5kc2NhcGVfZml0bmVzc19saW5rZWQpKSArCiAgZ2VvbV9oYWxmX3BvaW50KHNpemUgPSAwLjAxLCBhbHBoYSA9IDAuMDEsIHNpZGUgPSAiciIsIGNvbG9yID0gImdyZXk1MCIsCiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybWF0aW9uX3BhcmFtcyA9IGxpc3Qod2lkdGggPSAwLjI1LCBoZWlnaHQgPSAwLCBzZWVkID0gMTIzNCkpICsKICBnZW9tX2hhbGZfYm94cGxvdChhZXMoZmlsbCA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gImwiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMTkpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDc0RDkiKSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjMsIHNpemUgPSAwLjI1KSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMSwgLTAuMDIpKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkxhbmRzY2FwZSBmaXRuZXNzIiwKICAgICAgIHRpdGxlID0gIkE6IExhbmRzY2FwZSBmaXRuZXNzIGFuZCBjb25zdHJhaW50cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJWYWx1ZXMgbmVhciB6ZXJvIGluZGljYXRlIGhpZ2ggZml0bmVzcyIsCiAgICAgICBjYXB0aW9uID0gZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGdyZXl9Jz7il4Y8L3NwYW4+ID0gbWVhbiB2YWx1ZSIpKSArCiAgdGhlbWVfY29uc3RyYWludCgpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjcpKSwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbihsID0gLTAuNSwgdCA9IDQuMTUsIHVuaXQgPSAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsICJsaW5lcyIpKQpwbG90X2ZpdG5lc3NfYm94cGxvdAoKZ2dzYXZlKHBsb3RfZml0bmVzc19ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX0EucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfZml0bmVzc19ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX0EucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSAzMDApCmBgYAoKYGBge3IgbGFuZHNjYXBlLWZpdG5lc3MtaGwtYm94cGxvdCwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfaHRtbCwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodF9odG1sfQpwbG90X2ZpdG5lc3NfaGxfZGlmZnMgPC0gZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IG5fY29uc3RyYWludHNfZiwgeSA9IGxhbmRzY2FwZV9maXRuZXNzX2xpbmtlZCwgZmlsbCA9IHJlcHApKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIoZGlmZl9obF9vdXRjb21lc19wbG90LCBvdXRjb21lID09ICJmaXRuZXNzIiksCiAgICAgICAgICAgIGFlcyh5ID0gMCwgbGFiZWwgPSBuaWNlX2RpZmYsIGZpbGwgPSBOVUxMKSwKICAgICAgICAgICAgZmFtaWx5ID0gIkRlamFWdSBTYW5zIENvbmRlbnNlZCIsIGZvbnRmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEuNSwgdmp1c3QgPSAtMC44NSkgKwogIGdlb21faGFsZl9ib3hwbG90KGRhdGEgPSBzaW1faGlnaCwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMC4yNSwgc2lkZSA9ICJsIiwgb3V0bGllci5zaGFwZSA9IE5BLCBlcnJvcmJhci5kcmF3ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICBudWRnZSA9IDAuMDUsIGFscGhhID0gMC41KSArCiAgZ2VvbV9oYWxmX2JveHBsb3QoZGF0YSA9IHNpbV9sb3csCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsIHNpZGUgPSAiciIsIG91dGxpZXIuc2hhcGUgPSBOQSwgZXJyb3JiYXIuZHJhdyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2UgPSAwLjA1LCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShkYXRhID0gc2ltX2hpZ2gsIGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAtMC4yMikpICsKICBzdGF0X3N1bW1hcnkoZGF0YSA9IHNpbV9sb3csIGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAwLjIyKSkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMkVDQzQwIiwgIiNGRjg1MUIiKSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjMsIHNpemUgPSAwLjI1KSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMC42NSwgLTAuMDIpKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkxhbmRzY2FwZSBmaXRuZXNzIiwKICAgICAgIHRpdGxlID0gIkI6IENvbnN0cmFpbnRzIGFjcm9zcyBoaWdoL2xvdyIsCiAgICAgICBzdWJ0aXRsZSA9ICLiiIYgPSBoaWdoIOKIkiBsb3ciLAogICAgICAgY2FwdGlvbiA9IGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRncmV5fSc+4peGPC9zcGFuPiA9IG1lYW4gdmFsdWU7ICogPSBwIDwgMC4wNSIpKSArCiAgdGhlbWVfY29uc3RyYWludCgpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC4xNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImxpbmVzIikpCnBsb3RfZml0bmVzc19obF9kaWZmcwpgYGAKCmBgYHtyIGNvbWJpbmVkLWJveHBsb3RzLWZpdG5lc3MsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoMiwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodH0KY29tYmluZWRfZml0bmVzcyA8LSBwbG90X2ZpdG5lc3NfYm94cGxvdCArIHBsb3RfZml0bmVzc19obF9kaWZmcwoKY29tYmluZWRfZml0bmVzcwpnZ3NhdmUoY29tYmluZWRfZml0bmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZml0bmVzc19ib3hwbG90cy5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKGNvbWJpbmVkX2ZpdG5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImZpdG5lc3NfYm94cGxvdHMucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF9maXRuZXNzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX2NvbWJpbmVkLmVwcyIpLAojICAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wcywgZmFsbGJhY2tfcmVzb2x1dGlvbiA9IDYwMCkKYGBgCgpgYGB7ciBsYW5kc2NhcGUtZml0bmVzcy1pbXBvcnRhbmNlLCBjYWNoZT1UUlVFfQojIFRoaXMgdGFrZXMgYSBmZXcgbWludXRlcyB0byBydW4Kc2V0LnNlZWQoU0VFRCkKZm9yZXN0X21vZGVsX2ZpdG5lc3MgPC0gCiAgcmFuZG9tRm9yZXN0KGxhbmRzY2FwZV9maXRuZXNzX2xpbmtlZCB+CiAgICAgICAgICAgICAgICAgY3JlYXRlX25ldHdvcmsgKyBzZWxlY3QgKyBkaXNwZXJzZSArIAogICAgICAgICAgICAgICAgIGNvbXBldGUgKyBzZWxlY3Rmb3JfZCArIGNhdGFzdHJvcGhlLAogICAgICAgICAgICAgICBpbXBvcnRhbmNlID0gVFJVRSwgZGF0YSA9IHNpbV9scykKCmZvcmVzdF9tb2RlbF9maXRuZXNzX2xvdyA8LSAKICByYW5kb21Gb3Jlc3QobGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkIH4KICAgICAgICAgICAgICAgICBjcmVhdGVfbmV0d29yayArIHNlbGVjdCArIGRpc3BlcnNlICsgCiAgICAgICAgICAgICAgICAgY29tcGV0ZSArIHNlbGVjdGZvcl9kICsgY2F0YXN0cm9waGUsCiAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUUlVFLCBkYXRhID0gZmlsdGVyKHNpbV9obCwgcmVwcCA9PSAiTG93IikpCgpmb3Jlc3RfbW9kZWxfZml0bmVzc19oaWdoIDwtIAogIHJhbmRvbUZvcmVzdChsYW5kc2NhcGVfZml0bmVzc19saW5rZWQgfgogICAgICAgICAgICAgICAgIGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgZGlzcGVyc2UgKyAKICAgICAgICAgICAgICAgICBjb21wZXRlICsgc2VsZWN0Zm9yX2QgKyBjYXRhc3Ryb3BoZSwKICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFRSVUUsIGRhdGEgPSBmaWx0ZXIoc2ltX2hsLCByZXBwID09ICJIaWdoIikpCmBgYAoKYGBge3IgZml0bmVzcy1pbXBvcnRhbmNlLWxzLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KY2xycyA8LSBsaXN0KAogIHNlbGVjdCA9ICIjNjI5NWNkIiwgICMgYmx1ZQogIHNlbGVjdGlvbiA9ICIjNjI5NWNkIiwgICMgYmx1ZQogIGNvbXBldGUgPSAiI2IzOTQzZiIsICAjIGdvbGQKICBjb21wZXRpdGlvbiA9ICIjYjM5NDNmIiwgICMgZ29sZAogIGNhdGFzdHJvcGhlID0gIiM5NDY2YzkiLCAgIyBwdXJwbGUKICBjcmVhdGVfbmV0d29yayA9ICIjNjJhODViIiwgICMgZ3JlZW4KICBkaXNwZXJzYWwgPSAiI2M4NTk5MCIsICAjIHBpbmsKICBkaXNwZXJzZSA9ICIjYzg1OTkwIiwgICMgcGluawogIHNlbGVjdGZvcl9kID0gIiNjYTVkNDYiLCAgIyByZWRkaXNoCiAgc3BlY2llc19kcmlmdCA9ICIjY2E1ZDQ2IiwgICMgcmVkZGlzaAogIGdyZXkgPSAiIzdmN2Y3ZiIgICMgZ3JleTUwCikKCmZpdG5lc3NfaW1wb3J0YW5jZV9scyA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF9maXRuZXNzLCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgYXJyYW5nZShkZXNjKFguSW5jTVNFKSkgJT4lIAogIG11dGF0ZShjb25zdHJhaW50ID0gcmVjb2RlKGNvbnN0cmFpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgY29tcGV0ZWAgPSAiY29tcGV0aXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBkaXNwZXJzZWAgPSAiZGlzcGVyc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogIGNvbG9yX2NvbnN0cmFpbnRzKGNvbnN0cmFpbnQpICU+JSAKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiY29uc3RyYWludCIpKSwgZmN0X2lub3JkZXIpICU+JSAKICBtdXRhdGUoWC5JbmNNU0UgPSBYLkluY01TRSAvIDEwMCkKCnBsb3RfZml0bmVzc19pbXBvcnRhbmNlX2xzIDwtIGdncGxvdChmaXRuZXNzX2ltcG9ydGFuY2VfbHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLkluY01TRSwgeSA9IGZjdF9yZXYoY29uc3RyYWludF9jb2xvcmVkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBmY3RfcmV2KGNvbnN0cmFpbnQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpKSArCiAgZ2VvbV9wb2ludHJhbmdlaChhZXMoeG1pbiA9IDAsIHhtYXggPSBYLkluY01TRSksIHNpemUgPSAwLjI1KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsIGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSBjKDAsIDAuMDIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3QoY2xycyksIGd1aWRlID0gRkFMU0UpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxOSksIG5hbWUgPSBOVUxMKSArCiAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC4yNSkpKSArCiAgbGFicyh4ID0gIlBlcmNlbnQgaW5jcmVhc2UgaW4gTVNFIHdoZW4gZXhjbHVkZWQiLCB5ID0gTlVMTCwgCiAgICAgICB0aXRsZSA9ICJCOiBDb25zdHJhaW50IGltcG9ydGFuY2UgZm9yIGxhbmRzY2FwZSBmaXRuZXNzIiwKICAgICAgIHN1YnRpdGxlID0gIkhpZ2hlciB2YWx1ZXMgaW5kaWNhdGUgZ3JlYXRlciB2YXJpYWJsZSBpbXBvcnRhbmNlIiwKICAgICAgIGNhcHRpb24gPSAiIikgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0Ljc1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMi41LCAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuOTUsICJsaW5lcyIpKQpwbG90X2ZpdG5lc3NfaW1wb3J0YW5jZV9scwoKZ2dzYXZlKHBsb3RfZml0bmVzc19pbXBvcnRhbmNlX2xzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX0IucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfZml0bmVzc19pbXBvcnRhbmNlX2xzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX0IucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSAzMDApCmBgYAoKYGBge3IgY29uc3RyYWludC1pbXBvcnRhbmNlLWhsLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KZml0bmVzc19pbXBvcnRhbmNlX2xvdyA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF9maXRuZXNzX2xvdywgdHlwZSA9IDEsIHNjYWxlID0gVFJVRSkgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJjb25zdHJhaW50IikgJT4lIAogIG11dGF0ZShyZXBwID0gIkxvdyIpCgpmaXRuZXNzX2ltcG9ydGFuY2VfaGlnaCA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF9maXRuZXNzX2hpZ2gsIHR5cGUgPSAxLCBzY2FsZSA9IFRSVUUpICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiY29uc3RyYWludCIpICU+JSAKICBtdXRhdGUocmVwcCA9ICJIaWdoIikKCmZpdG5lc3NfaW1wb3J0YW5jZV9obCA8LSBiaW5kX3Jvd3MoZml0bmVzc19pbXBvcnRhbmNlX2xvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRuZXNzX2ltcG9ydGFuY2VfaGlnaCkgJT4lIAogIG11dGF0ZShyZXBwID0gZmFjdG9yKHJlcHAsIGxldmVscyA9IGMoIkxvdyIsICJIaWdoIiksIG9yZGVyZWQgPSBUUlVFKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhyZXBwKSwgZGVzYyhYLkluY01TRSkpICU+JSAKICBtdXRhdGUoY29uc3RyYWludCA9IHJlY29kZShjb25zdHJhaW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBzZWxlY3RgID0gInNlbGVjdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYGNvbXBldGVgID0gImNvbXBldGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgZGlzcGVyc2VgID0gImRpc3BlcnNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGZvcl9kYCA9ICJzcGVjaWVzX2RyaWZ0IikpICU+JSAKICBjb2xvcl9jb25zdHJhaW50cyhjb25zdHJhaW50KSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoImNvbnN0cmFpbnQiKSksIGZjdF9pbm9yZGVyKSAlPiUgCiAgbXV0YXRlKFguSW5jTVNFID0gWC5JbmNNU0UgLyAxMDApCgpwbG90X2ZpdG5lc3NfaW1wb3J0YW5jZV9obCA8LSBnZ3Bsb3QoZml0bmVzc19pbXBvcnRhbmNlX2hsLCAKICAgICAgIGFlcyh4ID0gWC5JbmNNU0UsIHkgPSBmY3RfcmV2KGNvbnN0cmFpbnRfY29sb3JlZCksIGNvbG9yID0gZmN0X3Jldihjb25zdHJhaW50KSwgCiAgICAgICAgICAgbGluZXR5cGUgPSByZXBwLCBzaGFwZSA9IHJlcHApKSArCiAgZ2VvbV9wb2ludHJhbmdlaChhZXMoeG1pbiA9IDAsIHhtYXggPSBYLkluY01TRSksCiAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdldihoZWlnaHQgPSAwLjUpLCBzaXplID0gMC4yNSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LCBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAwLjAyKSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdW5saXN0KGNscnMpLCBndWlkZSA9IEZBTFNFKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoImRhc2hlZCIsICJzb2xpZCIpLCBuYW1lID0gTlVMTCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE3LCAxNSksIG5hbWUgPSBOVUxMKSArCiAgZ3VpZGVzKGxpbmV0eXBlID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgcmV2ZXJzZSA9IFRSVUUpLAogICAgICAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDAuMjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVFJVRSkpICsKICBsYWJzKHggPSAiUGVyY2VudCBpbmNyZWFzZSBpbiBNU0Ugd2hlbiBleGNsdWRlZCIsIHkgPSBOVUxMLCAKICAgICAgIHRpdGxlID0gIkQ6IENvbnN0cmFpbnQgaW1wb3J0YW5jZSBhY3Jvc3MgaGlnaC9sb3ciLAogICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiIikgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0Ljc1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMi41LCAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuOTUsICJsaW5lcyIpKQpwbG90X2ZpdG5lc3NfaW1wb3J0YW5jZV9obApgYGAKCmBgYHtyIGNvbWJpbmVkLWltcG9ydGFuY2UtZml0bmVzcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGgyLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0fQppbXBvcnRhbmNlX2ZpdG5lc3MgPC0gcGxvdF9maXRuZXNzX2ltcG9ydGFuY2VfbHMgKyBwbG90X2ZpdG5lc3NfaW1wb3J0YW5jZV9obAoKaW1wb3J0YW5jZV9maXRuZXNzCmdnc2F2ZShpbXBvcnRhbmNlX2ZpdG5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImZpdG5lc3NfaW1wb3J0YW5jZS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKGltcG9ydGFuY2VfZml0bmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZml0bmVzc19pbXBvcnRhbmNlLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKIyBnZ3NhdmUoY29tYmluZWRfZml0bmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZml0bmVzc19jb21iaW5lZC50aWZmIiksCiMgICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSA2MDApCiMgZ2dzYXZlKGNvbWJpbmVkX2ZpdG5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImZpdG5lc3NfY29tYmluZWQuZXBzIiksCiMgICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BzLCBmYWxsYmFja19yZXNvbHV0aW9uID0gNjAwKSAKYGBgCgpgYGB7ciBwbG90LWZpdG5lc3MtYWxsLWNvbWJvcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfYmlnLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2JpZ30KcGxvdF9maXRuZXNzX2FsbCA8LSBtZWdhX21lYW5zX3Bsb3QoY29uc3RyYWludF9jb21ib19vdXRjb21lc19scywgbGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJBdmVyYWdlIGxhbmRzY2FwZSBmaXRuZXNzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkF2ZXJhZ2UgbGFuZHNjYXBlIGZpdG5lc3MgYWNyb3NzIGNvbWJpbmF0aW9ucyBvZiBjb25zdHJhaW50cyIpCgpwbG90X2ZpdG5lc3NfYWxsCmdnc2F2ZShwbG90X2ZpdG5lc3NfYWxsLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX21lYW5zX2FsbC5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aF9iaWcsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShwbG90X2ZpdG5lc3NfYWxsLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX21lYW5zX2FsbC5wbmciKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aF9iaWcsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQpgYGAKCiMjIEZpZ3VyZSA1OiBMYW5kc2NhcGUgZml0bmVzcyB2YXJpYW5jZQoKKipGaWcgNS4gRWZmZWN0IG9mIHRoZSBudW1iZXIgb2YgY29uc3RyYWludHMgb24gdmFyaWFuY2Ugb2YgbGFuZHNjYXBlIGZpdG5lc3MqKiBCb3hwbG90cyBzaG93aW5nIHZhcmlhbmNlIG9mIGxhbmRzY2FwZSBmaXRuZXNzIGFjcm9zcyBkaWZmZXJlbnQgbnVtYmVycyBvZiBjb25zdHJhaW50cwoKYGBge3IgbGFuZHNjYXBlLWZpdG5lc3MtdmFyLWJveHBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcGxvdF9sYW5kc2NhcGVfZml0bmVzc192YXJpYW5jZSA8LSBnZ3Bsb3Qoc2ltX2xzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBuX2NvbnN0cmFpbnRzX2YsIHkgPSBsYW5kc2NhcGVfZml0bmVzc192YXIpKSArCiAgZ2VvbV9oYWxmX3BvaW50KHNpemUgPSAwLjA1LCBhbHBoYSA9IDAuMSwgc2lkZSA9ICJyIiwgY29sb3IgPSAiZ3JleTUwIiwKICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtYXRpb25fcGFyYW1zID0gbGlzdCh3aWR0aCA9IDAuMjUsIGhlaWdodCA9IDAsIHNlZWQgPSAxMjM0KSkgKwogIGdlb21faGFsZl9ib3hwbG90KHNpemUgPSAwLjI1LCBzaWRlID0gImwiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFKSArCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAtMC4xOSkpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuMSwgMCkpICsKICBsYWJzKHggPSAiTnVtYmVyIG9mIGNvbnN0cmFpbnRzIiwKICAgICAgIHkgPSAiTGFuZHNjYXBlIGZpdG5lc3MsIHZhcmlhbmNlIiwKICAgICAgIHRpdGxlID0gIlZhcmlhbmNlIGluIGxhbmRzY2FwZSBmaXRuZXNzIGFuZCBjb25zdHJhaW50cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIsCiAgICAgICBjYXB0aW9uID0gZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGdyZXl9Jz7il4Y8L3NwYW4+ID0gbWVhbiB2YWx1ZSIpKSArCiAgdGhlbWVfY29uc3RyYWludCgpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24oKSkKCnBsb3RfbGFuZHNjYXBlX2ZpdG5lc3NfdmFyaWFuY2UKCmdnc2F2ZShwbG90X2xhbmRzY2FwZV9maXRuZXNzX3ZhcmlhbmNlLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX3ZhcmlhbmNlLnBkZiIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShwbG90X2xhbmRzY2FwZV9maXRuZXNzX3ZhcmlhbmNlLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX3ZhcmlhbmNlLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQpgYGAKCgojIyBGaWd1cmUgNjogRWNvbG9naWNhbCBldmVubmVzcwoKKipGaWcgNi4gRWZmZWN0IG9mIHRoZSBudW1iZXIgb2YgY29uc3RyYWludHMgb24gZWNvbG9naWNhbCBldmVubmVzcyoqIChBKSBCb3hwbG90cyBzaG93aW5nIGVjb2xvZ2ljYWwgZXZlbm5lc3MgYWNyb3NzIGRpZmZlcmVudCBudW1iZXJzIG9mIGNvbnN0cmFpbnRzOyAoQikgUGVyY2VudCBpbmNyZWFzZSBpbiBtZWFuIHN0YW5kYXJkIGVycm9yIGluIGEgcmFuZG9tIGZvcmVzdCBtb2RlbCB3aGVuIGVhY2ggY29uc3RyYWludCBpcyByZW1vdmVkOyAoQykgQXZlcmFnZSBlY29sb2dpY2FsIGV2ZW5uZXNzIGFjcm9zcyBhbGwgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGNvbnN0cmFpbnRzCgpgYGB7ciBldmVubmVzcy1ib3hwbG90LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aF9odG1sLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2h0bWx9CnBsb3RfZXZlbm5lc3NfYm94cGxvdCA8LSBnZ3Bsb3Qoc2ltX2xzLCBhZXMoeCA9IG5fY29uc3RyYWludHNfZiwgeSA9IGF2Z19ldmVubmVzc190KSkgKwogIGdlb21faGFsZl9wb2ludChzaXplID0gMC4wNSwgYWxwaGEgPSAwLjEsIHNpZGUgPSAiciIsIGNvbG9yID0gImdyZXk1MCIsCiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybWF0aW9uX3BhcmFtcyA9IGxpc3Qod2lkdGggPSAwLjI1LCBoZWlnaHQgPSAwLCBzZWVkID0gMTIzNCkpICsKICBnZW9tX2hhbGZfYm94cGxvdChhZXMoZmlsbCA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gImwiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMTkpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDc0RDkiKSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjMsIHNpemUgPSAwLjI1KSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMSwgLTAuMDIpKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkVjb2xvZ2ljYWwgZXZlbm5lc3MiLAogICAgICAgdGl0bGUgPSAiQTogRWNvbG9naWNhbCBldmVubmVzcyBhbmQgY29uc3RyYWludHMiLAogICAgICAgc3VidGl0bGUgPSAiVmFsdWVzIG5lYXIgemVybyBpbmRpY2F0ZSBoaWdoIGV2ZW5uZXNzIiwKICAgICAgIGNhcHRpb24gPSBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6e2NscnMkZ3JleX0nPuKXhjwvc3Bhbj4gPSBtZWFuIHZhbHVlIikpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC4xNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImxpbmVzIikpCnBsb3RfZXZlbm5lc3NfYm94cGxvdAoKZ2dzYXZlKHBsb3RfZXZlbm5lc3NfYm94cGxvdCwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZXZlbm5lc3NfQS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcGRmKQpnZ3NhdmUocGxvdF9ldmVubmVzc19ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJldmVubmVzc19BLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQpgYGAKCmBgYHtyIGVjb2xvZ2ljYWwtZXZlbm5lc3MtaGwtYm94cGxvdCwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfaHRtbCwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodF9odG1sfQpwbG90X2V2ZW5uZXNzX2hsX2RpZmZzIDwtIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBuX2NvbnN0cmFpbnRzX2YsIHkgPSBhdmdfZXZlbm5lc3NfdCwgZmlsbCA9IHJlcHApKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIoZGlmZl9obF9vdXRjb21lc19wbG90LCBvdXRjb21lID09ICJldmVubmVzcyIpLAogICAgICAgICAgICBhZXMoeSA9IDAsIGxhYmVsID0gbmljZV9kaWZmLCBmaWxsID0gTlVMTCksCiAgICAgICAgICAgIGZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiLCBmb250ZmFjZSA9ICJwbGFpbiIsIHNpemUgPSAxLjUsIHZqdXN0ID0gLTAuODUpICsKICBnZW9tX2hhbGZfYm94cGxvdChkYXRhID0gc2ltX2hpZ2gsCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsIHNpZGUgPSAibCIsIG91dGxpZXIuc2hhcGUgPSBOQSwgZXJyb3JiYXIuZHJhdyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2UgPSAwLjA1LCBhbHBoYSA9IDAuNSkgKwogIGdlb21faGFsZl9ib3hwbG90KGRhdGEgPSBzaW1fbG93LAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gInIiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgIG51ZGdlID0gMC4wNSwgYWxwaGEgPSAwLjUpICsKICBzdGF0X3N1bW1hcnkoZGF0YSA9IHNpbV9oaWdoLCBnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMjIpKSArCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBzaW1fbG93LCBnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4yMikpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzJFQ0M0MCIsICIjRkY4NTFCIiksIG5hbWUgPSBOVUxMKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhID0gMC4zLCBzaXplID0gMC4yNSkpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDEsIC0wLjAyKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgY29uc3RyYWludHMiLAogICAgICAgeSA9ICJFY29sb2dpY2FsIGV2ZW5uZXNzIiwKICAgICAgIHRpdGxlID0gIkI6IENvbnN0cmFpbnRzIGFjcm9zcyBoaWdoL2xvdyIsCiAgICAgICBzdWJ0aXRsZSA9ICLiiIYgPSBoaWdoIOKIkiBsb3ciLAogICAgICAgY2FwdGlvbiA9IGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRncmV5fSc+4peGPC9zcGFuPiA9IG1lYW4gdmFsdWU7ICogPSBwIDwgMC4wNSIpKSArCiAgdGhlbWVfY29uc3RyYWludCgpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC4xNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImxpbmVzIikpCnBsb3RfZXZlbm5lc3NfaGxfZGlmZnMKYGBgCgpgYGB7ciBjb21iaW5lZC1ib3hwbG90cy1ldmVubmVzcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGgyLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpjb21iaW5lZF9ldmVubmVzcyA8LSBwbG90X2V2ZW5uZXNzX2JveHBsb3QgKyBwbG90X2V2ZW5uZXNzX2hsX2RpZmZzCgpjb21iaW5lZF9ldmVubmVzcwpnZ3NhdmUoY29tYmluZWRfZXZlbm5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX2JveHBsb3RzLnBkZiIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcGRmKQpnZ3NhdmUoY29tYmluZWRfZXZlbm5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX2JveHBsb3RzLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKIyBnZ3NhdmUoY29tYmluZWRfZXZlbm5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX2NvbWJpbmVkLnRpZmYiKSwKIyAgICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDYwMCkKIyBnZ3NhdmUoY29tYmluZWRfZXZlbm5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX2NvbWJpbmVkLmVwcyIpLAojICAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wcywgZmFsbGJhY2tfcmVzb2x1dGlvbiA9IDYwMCkgCmBgYAoKYGBge3IgZWNvbG9naWNhbC1ldmVubmVzcy1pbXBvcnRhbmNlLCBjYWNoZT1UUlVFfQojIFRoaXMgdGFrZXMgYSBmZXcgbWludXRlcyB0byBydW4Kc2V0LnNlZWQoU0VFRCkKZm9yZXN0X21vZGVsX2V2ZW5uZXNzIDwtIAogIHJhbmRvbUZvcmVzdChhdmdfZXZlbm5lc3NfdCB+CiAgICAgICAgICAgICAgICAgY3JlYXRlX25ldHdvcmsgKyBzZWxlY3QgKyBkaXNwZXJzZSArIAogICAgICAgICAgICAgICAgIGNvbXBldGUgKyBzZWxlY3Rmb3JfZCArIGNhdGFzdHJvcGhlLAogICAgICAgICAgICAgICBpbXBvcnRhbmNlID0gVFJVRSwgCiAgICAgICAgICAgICAgIGRhdGEgPSBkcm9wX25hKHNpbV9scywgYXZnX2V2ZW5uZXNzX3QpKQoKZm9yZXN0X21vZGVsX2V2ZW5uZXNzX2xvdyA8LSAKICByYW5kb21Gb3Jlc3QoYXZnX2V2ZW5uZXNzX3QgfgogICAgICAgICAgICAgICAgIGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgZGlzcGVyc2UgKyAKICAgICAgICAgICAgICAgICBjb21wZXRlICsgc2VsZWN0Zm9yX2QgKyBjYXRhc3Ryb3BoZSwKICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFRSVUUsIAogICAgICAgICAgICAgICBkYXRhID0gZmlsdGVyKGRyb3BfbmEoc2ltX2hsLCBhdmdfZXZlbm5lc3NfdCksIHJlcHAgPT0gIkxvdyIpKQoKZm9yZXN0X21vZGVsX2V2ZW5uZXNzX2hpZ2ggPC0gCiAgcmFuZG9tRm9yZXN0KGF2Z19ldmVubmVzc190IH4KICAgICAgICAgICAgICAgICBjcmVhdGVfbmV0d29yayArIHNlbGVjdCArIGRpc3BlcnNlICsgCiAgICAgICAgICAgICAgICAgY29tcGV0ZSArIHNlbGVjdGZvcl9kICsgY2F0YXN0cm9waGUsCiAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUUlVFLCAKICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihkcm9wX25hKHNpbV9obCwgYXZnX2V2ZW5uZXNzX3QpLCByZXBwID09ICJIaWdoIikpCmBgYAoKYGBge3IgZXZlbm5lc3MtaW1wb3J0YW5jZS1scy1wbG90LCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aF9odG1sLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2h0bWx9CmV2ZW5uZXNzX2ltcG9ydGFuY2VfbHMgPC0gaW1wb3J0YW5jZShmb3Jlc3RfbW9kZWxfZXZlbm5lc3MsIHR5cGUgPSAxLCBzY2FsZSA9IFRSVUUpICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiY29uc3RyYWludCIpICU+JSAKICBhcnJhbmdlKGRlc2MoWC5JbmNNU0UpKSAlPiUgCiAgbXV0YXRlKGNvbnN0cmFpbnQgPSByZWNvZGUoY29uc3RyYWludCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0YCA9ICJzZWxlY3Rpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBjb21wZXRlYCA9ICJjb21wZXRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYGRpc3BlcnNlYCA9ICJkaXNwZXJzYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBzZWxlY3Rmb3JfZGAgPSAic3BlY2llc19kcmlmdCIpKSAlPiUgCiAgY29sb3JfY29uc3RyYWludHMoY29uc3RyYWludCkgJT4lIAogIG11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJjb25zdHJhaW50IikpLCBmY3RfaW5vcmRlcikgJT4lIAogIG11dGF0ZShYLkluY01TRSA9IFguSW5jTVNFIC8gMTAwKQoKcGxvdF9ldmVubmVzc19pbXBvcnRhbmNlX2xzIDwtIGdncGxvdChldmVubmVzc19pbXBvcnRhbmNlX2xzLCAKICAgICAgIGFlcyh4ID0gWC5JbmNNU0UsIHkgPSBmY3RfcmV2KGNvbnN0cmFpbnRfY29sb3JlZCksIAogICAgICAgICAgIGNvbG9yID0gZmN0X3Jldihjb25zdHJhaW50KSwgc2hhcGUgPSAiTGF0aW4gaHlwZXJjdWJlIHNhbXBsZXMiKSkgKwogIGdlb21fcG9pbnRyYW5nZWgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gWC5JbmNNU0UpLCBzaXplID0gMC4yNSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LCBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAwLjAyKSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdW5saXN0KGNscnMpLCBndWlkZSA9IEZBTFNFKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTkpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhzaGFwZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDAuMjUpKSkgKwogIGxhYnMoeCA9ICJQZXJjZW50IGluY3JlYXNlIGluIE1TRSB3aGVuIGV4Y2x1ZGVkIiwgeSA9IE5VTEwsIAogICAgICAgdGl0bGUgPSAiQjogQ29uc3RyYWludCBpbXBvcnRhbmNlIGZvciBlY29sb2dpY2FsIGV2ZW5uZXNzIiwKICAgICAgIHN1YnRpdGxlID0gIkhpZ2hlciB2YWx1ZXMgaW5kaWNhdGUgZ3JlYXRlciB2YXJpYWJsZSBpbXBvcnRhbmNlIiwKICAgICAgIGNhcHRpb24gPSAiIikgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0Ljc1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMi41LCAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuOTUsICJsaW5lcyIpKQpwbG90X2V2ZW5uZXNzX2ltcG9ydGFuY2VfbHMKCmdnc2F2ZShwbG90X2V2ZW5uZXNzX2ltcG9ydGFuY2VfbHMsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX0IucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfZXZlbm5lc3NfaW1wb3J0YW5jZV9scywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZXZlbm5lc3NfQi5wbmciKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKYGBgCgpgYGB7ciBldmVubmVzcy1pbXBvcnRhbmNlLWhsLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KZXZlbm5lc3NfaW1wb3J0YW5jZV9sb3cgPC0gaW1wb3J0YW5jZShmb3Jlc3RfbW9kZWxfZXZlbm5lc3NfbG93LCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiTG93IikKCmV2ZW5uZXNzX2ltcG9ydGFuY2VfaGlnaCA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF9ldmVubmVzc19oaWdoLCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiSGlnaCIpCgpldmVubmVzc19pbXBvcnRhbmNlX2hsIDwtIGJpbmRfcm93cyhldmVubmVzc19pbXBvcnRhbmNlX2xvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbm5lc3NfaW1wb3J0YW5jZV9oaWdoKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSBmYWN0b3IocmVwcCwgbGV2ZWxzID0gYygiTG93IiwgIkhpZ2giKSwgb3JkZXJlZCA9IFRSVUUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHJlcHApLCBkZXNjKFguSW5jTVNFKSkgJT4lIAogIG11dGF0ZShjb25zdHJhaW50ID0gcmVjb2RlKGNvbnN0cmFpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgY29tcGV0ZWAgPSAiY29tcGV0aXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBkaXNwZXJzZWAgPSAiZGlzcGVyc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogIGNvbG9yX2NvbnN0cmFpbnRzKGNvbnN0cmFpbnQpICU+JSAKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiY29uc3RyYWludCIpKSwgZmN0X2lub3JkZXIpICU+JSAKICBtdXRhdGUoWC5JbmNNU0UgPSBYLkluY01TRSAvIDEwMCkKCnBsb3RfZXZlbm5lc3NfaW1wb3J0YW5jZV9obCA8LSBnZ3Bsb3QoZXZlbm5lc3NfaW1wb3J0YW5jZV9obCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLkluY01TRSwgeSA9IGZjdF9yZXYoY29uc3RyYWludF9jb2xvcmVkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmN0X3Jldihjb25zdHJhaW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gcmVwcCwgc2hhcGUgPSByZXBwKSkgKwogIGdlb21fcG9pbnRyYW5nZWgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gWC5JbmNNU0UpLAogICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZXYoaGVpZ2h0ID0gMC41KSwgc2l6ZSA9IDAuMjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMC4wMikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjbHJzKSwgZ3VpZGUgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXNoZWQiLCAic29saWQiKSwgbmFtZSA9IE5VTEwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNywgMTUpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhsaW5ldHlwZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHJldmVyc2UgPSBUUlVFKSwKICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJzZSA9IFRSVUUpKSArCiAgbGFicyh4ID0gIlBlcmNlbnQgaW5jcmVhc2UgaW4gTVNFIHdoZW4gZXhjbHVkZWQiLCB5ID0gTlVMTCwgCiAgICAgICB0aXRsZSA9ICJEOiBDb25zdHJhaW50IGltcG9ydGFuY2UgYWNyb3NzIGhpZ2gvbG93IiwKICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICBjYXB0aW9uID0gIiIpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC43NSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIuNSwgImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjk1LCAibGluZXMiKSkKcGxvdF9ldmVubmVzc19pbXBvcnRhbmNlX2hsCmBgYAoKYGBge3IgY29tYmluZWQtaW1wb3J0YW5jZS1ldmVubmVzcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGgyLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0fQppbXBvcnRhbmNlX2V2ZW5uZXNzIDwtIHBsb3RfZXZlbm5lc3NfaW1wb3J0YW5jZV9scyArIHBsb3RfZXZlbm5lc3NfaW1wb3J0YW5jZV9obAoKaW1wb3J0YW5jZV9ldmVubmVzcwpnZ3NhdmUoaW1wb3J0YW5jZV9ldmVubmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZXZlbm5lc3NfaW1wb3J0YW5jZS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKGltcG9ydGFuY2VfZXZlbm5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX2ltcG9ydGFuY2UucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF9maXRuZXNzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX2NvbWJpbmVkLmVwcyIpLAojICAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wcywgZmFsbGJhY2tfcmVzb2x1dGlvbiA9IDYwMCkgCmBgYAoKYGBge3IgcGxvdC1ldmVubmVzcy1hbGwtY29tYm9zLCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aF9iaWcsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfYmlnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwbG90X2V2ZW5uZXNzX2FsbCA8LSBtZWdhX21lYW5zX3Bsb3QoY29uc3RyYWludF9jb21ib19vdXRjb21lc19scywgYXZnX2V2ZW5uZXNzX3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJBdmVyYWdlIGVjb2xvZ2ljYWwgZXZlbm5lc3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkF2ZXJhZ2UgZWNvbG9naWNhbCBldmVubmVzcyBhY3Jvc3MgY29tYmluYXRpb25zIG9mIGNvbnN0cmFpbnRzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfdG9fbGVmdCA9IDAuMDgpCgpwbG90X2V2ZW5uZXNzX2FsbAoKZ2dzYXZlKHBsb3RfZXZlbm5lc3NfYWxsLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJldmVubmVzc19tZWFuc19hbGwucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGhfYmlnLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodF9iaWcsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcGRmKQpnZ3NhdmUocGxvdF9ldmVubmVzc19hbGwsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgImV2ZW5uZXNzX21lYW5zX2FsbC5wbmciKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aF9iaWcsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQpgYGAKCgojIyBGaWd1cmUgNzogTGFuZHNjYXBlIHJpY2huZXNzCgoqKkZpZyA3LiBFZmZlY3Qgb2YgdGhlIG51bWJlciBvZiBjb25zdHJhaW50cyBvbiBzcGVjaWVzIHJpY2huZXNzKiogKEEpIEJveHBsb3RzIHNob3dpbmcgc3BlY2llcyByaWNobmVzcyBhY3Jvc3MgZGlmZmVyZW50IG51bWJlcnMgb2YgY29uc3RyYWludHM7IChCKSBQZXJjZW50IGluY3JlYXNlIGluIG1lYW4gc3RhbmRhcmQgZXJyb3IgaW4gYSByYW5kb20gZm9yZXN0IG1vZGVsIHdoZW4gZWFjaCBjb25zdHJhaW50IGlzIHJlbW92ZWQ7IChDKSBBdmVyYWdlIHNwZWNpZXMgcmljaG5lc3MgYWNyb3NzIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgY29uc3RyYWludHMKCmBgYHtyIHJpY2huZXNzLWJveHBsb3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcGxvdF9yaWNobmVzc19ib3hwbG90IDwtIGdncGxvdChzaW1fbHMsIGFlcyh4ID0gbl9jb25zdHJhaW50c19mLCB5ID0gbGFuZHNjYXBlX3JpY2huZXNzX21lYW4pKSArCiAgZ2VvbV9oYWxmX3BvaW50KHNpemUgPSAwLjAxLCBhbHBoYSA9IDAuMDEsIHNpZGUgPSAiciIsIGNvbG9yID0gImdyZXk1MCIsCiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybWF0aW9uX3BhcmFtcyA9IGxpc3Qod2lkdGggPSAwLjI1LCBoZWlnaHQgPSAwLCBzZWVkID0gMTIzNCkpICsKICBnZW9tX2hhbGZfYm94cGxvdChhZXMoZmlsbCA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gImwiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMTkpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMwMDc0RDkiKSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjMsIHNpemUgPSAwLjI1KSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMzUsIC0xKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgY29uc3RyYWludHMiLAogICAgICAgeSA9ICJMYW5kc2NhcGUgcmljaG5lc3MiLAogICAgICAgdGl0bGUgPSAiQTogTGFuZHNjYXBlIHJpY2huZXNzIGFuZCBjb25zdHJhaW50cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJWYWx1ZXMgbmVhciB6ZXJvIGluZGljYXRlIGxvdyBzcGVjaWVzIHJpY2huZXNzIiwKICAgICAgIGNhcHRpb24gPSBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6e2NscnMkZ3JleX0nPuKXhjwvc3Bhbj4gPSBtZWFuIHZhbHVlIikpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC4xNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImxpbmVzIikpCnBsb3RfcmljaG5lc3NfYm94cGxvdAoKZ2dzYXZlKHBsb3RfcmljaG5lc3NfYm94cGxvdCwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfQS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcGRmKQpnZ3NhdmUocGxvdF9yaWNobmVzc19ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJyaWNobmVzc19BLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQpgYGAKCmBgYHtyIGxhbmRzY2FwZS1yaWNobmVzcy1obC1ib3hwbG90LCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aF9odG1sLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2h0bWx9CnBsb3RfcmljaG5lc3NfaGxfZGlmZnMgPC0gZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IG5fY29uc3RyYWludHNfZiwgeSA9IGxhbmRzY2FwZV9yaWNobmVzc19tZWFuLCBmaWxsID0gcmVwcCkpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihkaWZmX2hsX291dGNvbWVzX3Bsb3QsIG91dGNvbWUgPT0gInJpY2huZXNzIiksCiAgICAgICAgICAgIGFlcyh5ID0gMCwgbGFiZWwgPSBuaWNlX2RpZmYsIGZpbGwgPSBOVUxMKSwKICAgICAgICAgICAgZmFtaWx5ID0gIkRlamFWdSBTYW5zIENvbmRlbnNlZCIsIGZvbnRmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEuNSwgdmp1c3QgPSAtMC44NSkgKwogIGdlb21faGFsZl9ib3hwbG90KGRhdGEgPSBzaW1faGlnaCwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMC4yNSwgc2lkZSA9ICJsIiwgb3V0bGllci5zaGFwZSA9IE5BLCBlcnJvcmJhci5kcmF3ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICBudWRnZSA9IDAuMDUsIGFscGhhID0gMC41KSArCiAgZ2VvbV9oYWxmX2JveHBsb3QoZGF0YSA9IHNpbV9sb3csCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsIHNpZGUgPSAiciIsIG91dGxpZXIuc2hhcGUgPSBOQSwgZXJyb3JiYXIuZHJhdyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2UgPSAwLjA1LCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShkYXRhID0gc2ltX2hpZ2gsIGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAtMC4yMikpICsKICBzdGF0X3N1bW1hcnkoZGF0YSA9IHNpbV9sb3csIGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAwLjIyKSkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMkVDQzQwIiwgIiNGRjg1MUIiKSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAwLjMsIHNpemUgPSAwLjI1KSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMzUsIC0xKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgY29uc3RyYWludHMiLAogICAgICAgeSA9ICJMYW5kc2NhcGUgcmljaG5lc3MiLAogICAgICAgdGl0bGUgPSAiQjogQ29uc3RyYWludHMgYWNyb3NzIGhpZ2gvbG93IiwKICAgICAgIHN1YnRpdGxlID0gIuKIhiA9IGhpZ2gg4oiSIGxvdyIsCiAgICAgICBjYXB0aW9uID0gZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGdyZXl9Jz7il4Y8L3NwYW4+ID0gbWVhbiB2YWx1ZTsgKiA9IHAgPCAwLjA1IikpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0LjE1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCAibGluZXMiKSkKcGxvdF9yaWNobmVzc19obF9kaWZmcwpgYGAKCmBgYHtyIGNvbWJpbmVkLWJveHBsb3RzLXJpY2huZXNzLCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aDIsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHQsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmNvbWJpbmVkX3JpY2huZXNzIDwtIHBsb3RfcmljaG5lc3NfYm94cGxvdCArIHBsb3RfcmljaG5lc3NfaGxfZGlmZnMKCmNvbWJpbmVkX3JpY2huZXNzCmdnc2F2ZShjb21iaW5lZF9yaWNobmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfYm94cGxvdHMucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShjb21iaW5lZF9yaWNobmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfYm94cGxvdHMucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF9yaWNobmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfY29tYmluZWQudGlmZiIpLAojICAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gNjAwKQojIGdnc2F2ZShjb21iaW5lZF9yaWNobmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfY29tYmluZWQuZXBzIiksCiMgICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BzLCBmYWxsYmFja19yZXNvbHV0aW9uID0gNjAwKSAKYGBgCgpgYGB7ciBsYW5kc2NhcGUtcmljaG5lc3MtaW1wb3J0YW5jZSwgY2FjaGU9VFJVRX0KIyBUaGlzIHRha2VzIGEgZmV3IG1pbnV0ZXMgdG8gcnVuCnNldC5zZWVkKFNFRUQpCmZvcmVzdF9tb2RlbF9yaWNobmVzcyA8LSAKICByYW5kb21Gb3Jlc3QobGFuZHNjYXBlX3JpY2huZXNzX21lYW4gfgogICAgICAgICAgICAgICAgIGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgZGlzcGVyc2UgKyAKICAgICAgICAgICAgICAgICBjb21wZXRlICsgc2VsZWN0Zm9yX2QgKyBjYXRhc3Ryb3BoZSwKICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFRSVUUsIAogICAgICAgICAgICAgICBkYXRhID0gZHJvcF9uYShzaW1fbHMsIGxhbmRzY2FwZV9yaWNobmVzc19tZWFuKSkKCmZvcmVzdF9tb2RlbF9yaWNobmVzc19sb3cgPC0gCiAgcmFuZG9tRm9yZXN0KGxhbmRzY2FwZV9yaWNobmVzc19tZWFuIH4KICAgICAgICAgICAgICAgICBjcmVhdGVfbmV0d29yayArIHNlbGVjdCArIGRpc3BlcnNlICsgCiAgICAgICAgICAgICAgICAgY29tcGV0ZSArIHNlbGVjdGZvcl9kICsgY2F0YXN0cm9waGUsCiAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUUlVFLCAKICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihkcm9wX25hKHNpbV9obCwgbGFuZHNjYXBlX3JpY2huZXNzX21lYW4pLCByZXBwID09ICJMb3ciKSkKCmZvcmVzdF9tb2RlbF9yaWNobmVzc19oaWdoIDwtIAogIHJhbmRvbUZvcmVzdChsYW5kc2NhcGVfcmljaG5lc3NfbWVhbiB+CiAgICAgICAgICAgICAgICAgY3JlYXRlX25ldHdvcmsgKyBzZWxlY3QgKyBkaXNwZXJzZSArIAogICAgICAgICAgICAgICAgIGNvbXBldGUgKyBzZWxlY3Rmb3JfZCArIGNhdGFzdHJvcGhlLAogICAgICAgICAgICAgICBpbXBvcnRhbmNlID0gVFJVRSwgCiAgICAgICAgICAgICAgIGRhdGEgPSBmaWx0ZXIoZHJvcF9uYShzaW1faGwsIGxhbmRzY2FwZV9yaWNobmVzc19tZWFuKSwgcmVwcCA9PSAiSGlnaCIpKQpgYGAKCmBgYHtyIHJpY2huZXNzLWltcG9ydGFuY2UtbHMtcGxvdCwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfaHRtbCwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodF9odG1sfQpyaWNobmVzc19pbXBvcnRhbmNlX2xzIDwtIGltcG9ydGFuY2UoZm9yZXN0X21vZGVsX3JpY2huZXNzLCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgYXJyYW5nZShkZXNjKFguSW5jTVNFKSkgJT4lIAogIG11dGF0ZShjb25zdHJhaW50ID0gcmVjb2RlKGNvbnN0cmFpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgY29tcGV0ZWAgPSAiY29tcGV0aXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBkaXNwZXJzZWAgPSAiZGlzcGVyc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogIGNvbG9yX2NvbnN0cmFpbnRzKGNvbnN0cmFpbnQpICU+JSAKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiY29uc3RyYWludCIpKSwgZmN0X2lub3JkZXIpICU+JSAKICBtdXRhdGUoWC5JbmNNU0UgPSBYLkluY01TRSAvIDEwMCkKCnBsb3RfcmljaG5lc3NfaW1wb3J0YW5jZV9scyA8LSBnZ3Bsb3QocmljaG5lc3NfaW1wb3J0YW5jZV9scywgCiAgICAgICBhZXMoeCA9IFguSW5jTVNFLCB5ID0gZmN0X3Jldihjb25zdHJhaW50X2NvbG9yZWQpLCAKICAgICAgICAgICBjb2xvciA9IGZjdF9yZXYoY29uc3RyYWludCksIHNoYXBlID0gIkxhdGluIGh5cGVyY3ViZSBzYW1wbGVzIikpICsKICBnZW9tX3BvaW50cmFuZ2VoKGFlcyh4bWluID0gMCwgeG1heCA9IFguSW5jTVNFKSwgc2l6ZSA9IDAuMjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMC4wMikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjbHJzKSwgZ3VpZGUgPSBGQUxTRSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE5KSwgbmFtZSA9IE5VTEwpICsKICBndWlkZXMoc2hhcGUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjI1KSkpICsKICBsYWJzKHggPSAiUGVyY2VudCBpbmNyZWFzZSBpbiBNU0Ugd2hlbiBleGNsdWRlZCIsIHkgPSBOVUxMLCAKICAgICAgIHRpdGxlID0gIkI6IENvbnN0cmFpbnQgaW1wb3J0YW5jZSBmb3IgbGFuZHNjYXBlIHJpY2huZXNzIiwKICAgICAgIHN1YnRpdGxlID0gIkhpZ2hlciB2YWx1ZXMgaW5kaWNhdGUgZ3JlYXRlciB2YXJpYWJsZSBpbXBvcnRhbmNlIiwKICAgICAgIGNhcHRpb24gPSAiIikgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0Ljc1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMi41LCAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuOTUsICJsaW5lcyIpKQpwbG90X3JpY2huZXNzX2ltcG9ydGFuY2VfbHMKCmdnc2F2ZShwbG90X3JpY2huZXNzX2ltcG9ydGFuY2VfbHMsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInJpY2huZXNzX0IucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfcmljaG5lc3NfaW1wb3J0YW5jZV9scywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfQi5wbmciKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKYGBgCgpgYGB7ciByaWNobmVzcy1pbXBvcnRhbmNlLWhsLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcmljaG5lc3NfaW1wb3J0YW5jZV9sb3cgPC0gaW1wb3J0YW5jZShmb3Jlc3RfbW9kZWxfcmljaG5lc3NfbG93LCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiTG93IikKCnJpY2huZXNzX2ltcG9ydGFuY2VfaGlnaCA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF9yaWNobmVzc19oaWdoLCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiSGlnaCIpCgpyaWNobmVzc19pbXBvcnRhbmNlX2hsIDwtIGJpbmRfcm93cyhyaWNobmVzc19pbXBvcnRhbmNlX2xvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmljaG5lc3NfaW1wb3J0YW5jZV9oaWdoKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSBmYWN0b3IocmVwcCwgbGV2ZWxzID0gYygiTG93IiwgIkhpZ2giKSwgb3JkZXJlZCA9IFRSVUUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHJlcHApLCBkZXNjKFguSW5jTVNFKSkgJT4lIAogIG11dGF0ZShjb25zdHJhaW50ID0gcmVjb2RlKGNvbnN0cmFpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgY29tcGV0ZWAgPSAiY29tcGV0aXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBkaXNwZXJzZWAgPSAiZGlzcGVyc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogIGNvbG9yX2NvbnN0cmFpbnRzKGNvbnN0cmFpbnQpICU+JSAKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiY29uc3RyYWludCIpKSwgZmN0X2lub3JkZXIpICU+JSAKICBtdXRhdGUoWC5JbmNNU0UgPSBYLkluY01TRSAvIDEwMCkKCnBsb3RfcmljaG5lc3NfaW1wb3J0YW5jZV9obCA8LSBnZ3Bsb3QocmljaG5lc3NfaW1wb3J0YW5jZV9obCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLkluY01TRSwgeSA9IGZjdF9yZXYoY29uc3RyYWludF9jb2xvcmVkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmN0X3Jldihjb25zdHJhaW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gcmVwcCwgc2hhcGUgPSByZXBwKSkgKwogIGdlb21fcG9pbnRyYW5nZWgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gWC5JbmNNU0UpLAogICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZXYoaGVpZ2h0ID0gMC41KSwgc2l6ZSA9IDAuMjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMC4wMikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjbHJzKSwgZ3VpZGUgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXNoZWQiLCAic29saWQiKSwgbmFtZSA9IE5VTEwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNywgMTUpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhsaW5ldHlwZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHJldmVyc2UgPSBUUlVFKSwKICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJzZSA9IFRSVUUpKSArCiAgbGFicyh4ID0gIlBlcmNlbnQgaW5jcmVhc2UgaW4gTVNFIHdoZW4gZXhjbHVkZWQiLCB5ID0gTlVMTCwgCiAgICAgICB0aXRsZSA9ICJEOiBDb25zdHJhaW50IGltcG9ydGFuY2UgYWNyb3NzIGhpZ2gvbG93IiwKICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICBjYXB0aW9uID0gIiIpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC43NSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIuNSwgImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjk1LCAibGluZXMiKSkKcGxvdF9yaWNobmVzc19pbXBvcnRhbmNlX2hsCmBgYAoKYGBge3IgY29tYmluZWQtaW1wb3J0YW5jZS1yaWNobmVzcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGgyLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0fQppbXBvcnRhbmNlX3JpY2huZXNzIDwtIHBsb3RfcmljaG5lc3NfaW1wb3J0YW5jZV9scyArIHBsb3RfcmljaG5lc3NfaW1wb3J0YW5jZV9obAoKaW1wb3J0YW5jZV9yaWNobmVzcwpnZ3NhdmUoaW1wb3J0YW5jZV9yaWNobmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfaW1wb3J0YW5jZS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKGltcG9ydGFuY2VfcmljaG5lc3MsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInJpY2huZXNzX2ltcG9ydGFuY2UucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF9maXRuZXNzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX2NvbWJpbmVkLnRpZmYiKSwKIyAgICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDYwMCkKIyBnZ3NhdmUoY29tYmluZWRfZml0bmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZml0bmVzc19jb21iaW5lZC5lcHMiKSwKIyAgICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcHMsIGZhbGxiYWNrX3Jlc29sdXRpb24gPSA2MDApIApgYGAKCmBgYHtyIHBsb3QtcmljaG5lc3MtYWxsLWNvbWJvcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfYmlnLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KcGxvdF9yaWNobmVzc19hbGwgPC0gbWVnYV9tZWFuc19wbG90KGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHMsIGxhbmRzY2FwZV9yaWNobmVzc19tZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQXZlcmFnZSBsYW5kc2NhcGUgcmljaG5lc3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkF2ZXJhZ2UgbGFuZHNjYXBlIHJpY2huZXNzIGFjcm9zcyBjb21iaW5hdGlvbnMgb2YgY29uc3RyYWludHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF90b19sZWZ0ID0gMSkKCnBsb3RfcmljaG5lc3NfYWxsCmdnc2F2ZShwbG90X3JpY2huZXNzX2FsbCwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAicmljaG5lc3NfbWVhbnNfYWxsLnBkZiIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoX2JpZywgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHRfYmlnLCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfcmljaG5lc3NfYWxsLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJyaWNobmVzc19tZWFuc19hbGwucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGhfYmlnLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodF9iaWcsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKYGBgCgoKIyMgRmlndXJlIDg6IERpZmZlcmVuY2UgaW4gdHVybm92ZXIKCioqRmlnIDguIEVmZmVjdCBvZiB0aGUgbnVtYmVyIG9mIGNvbnN0cmFpbnRzIG9uIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdHVybm92ZXIgaW4gbGlua2VkIGFuZCB1bmxpbmtlZCBzcGVjaWVzKiogKEEpIEJveHBsb3RzIHNob3dpbmcgZGlmZmVyZW5jZSBiZXR3ZWVuIHR1cm5vdmVyIGluIGxpbmtlZCBhbmQgdW5saW5rZWQgc3BlY2llcyBhY3Jvc3MgZGlmZmVyZW50IG51bWJlcnMgb2YgY29uc3RyYWludHM7IChCKSBQZXJjZW50IGluY3JlYXNlIGluIG1lYW4gc3RhbmRhcmQgZXJyb3IgaW4gYSByYW5kb20gZm9yZXN0IG1vZGVsIHdoZW4gZWFjaCBjb25zdHJhaW50IGlzIHJlbW92ZWQ7IChDKSBBdmVyYWdlIGRpZmZlcmVuY2UgYWNyb3NzIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgY29uc3RyYWludHMKCmBgYHtyIHR1cm5vdmVyLWJveHBsb3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcGxvdF90dXJub3Zlcl9ib3hwbG90IDwtIGdncGxvdChzaW1fbHMsIGFlcyh4ID0gbl9jb25zdHJhaW50c19mLCB5ID0gdHVybm92ZXJfZGlmZikpICsKICBnZW9tX2hhbGZfcG9pbnQoc2l6ZSA9IDAuMDEsIGFscGhhID0gMC4wMSwgc2lkZSA9ICJyIiwgY29sb3IgPSAiZ3JleTUwIiwKICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtYXRpb25fcGFyYW1zID0gbGlzdCh3aWR0aCA9IDAuMjUsIGhlaWdodCA9IDAsIHNlZWQgPSAxMjM0KSkgKwogIGdlb21faGFsZl9ib3hwbG90KGFlcyhmaWxsID0gIkxhdGluIGh5cGVyY3ViZSBzYW1wbGVzIiksCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsIHNpZGUgPSAibCIsIG91dGxpZXIuc2hhcGUgPSBOQSwgZXJyb3JiYXIuZHJhdyA9IFRSVUUsIGFscGhhID0gMC41KSArCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAicG9pbnQiLCBmdW4gPSAibWVhbiIsCiAgICAgICAgICAgICAgIHNpemUgPSAxLCBwY2ggPSAyMywgZmlsbCA9IGNscnMkZ3JleSwgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAtMC4xOSkpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzAwNzREOSIpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgb3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYSA9IDAuMywgc2l6ZSA9IDAuMjUpKSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygxLCAtMSkpICsKICBsYWJzKHggPSAiTnVtYmVyIG9mIGNvbnN0cmFpbnRzIiwKICAgICAgIHkgPSAi4oiGIHR1cm5vdmVyIiwKICAgICAgIHRpdGxlID0gIkE6IOKIhiB0dXJub3ZlciBhbmQgY29uc3RyYWludHMiLAogICAgICAgc3VidGl0bGUgPSAiVHVybm92ZXIgaW4gbGlua2VkIHNwZWNpZXMg4oiSIHR1cm5vdmVyIGluIHVubGlua2VkIHNwZWNpZXMiLAogICAgICAgY2FwdGlvbiA9IGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjp7Y2xycyRncmV5fSc+4peGPC9zcGFuPiA9IG1lYW4gdmFsdWUiKSkgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0LjE1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCAibGluZXMiKSkKcGxvdF90dXJub3Zlcl9ib3hwbG90CgpnZ3NhdmUocGxvdF90dXJub3Zlcl9ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJ0dXJub3Zlcl9BLnBkZiIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShwbG90X3R1cm5vdmVyX2JveHBsb3QsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInR1cm5vdmVyX0EucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSAzMDApCmBgYAoKYGBge3IgdHVybm92ZXItaGwtYm94cGxvdCwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfaHRtbCwgZmlnLmhlaWdodD1wYXJhbXMkZmlnX2hlaWdodF9odG1sfQpwbG90X3R1cm5vdmVyX2hsX2RpZmZzIDwtIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBuX2NvbnN0cmFpbnRzX2YsIHkgPSB0dXJub3Zlcl9kaWZmLCBmaWxsID0gcmVwcCkpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihkaWZmX2hsX291dGNvbWVzX3Bsb3QsIG91dGNvbWUgPT0gInJpY2huZXNzIiksCiAgICAgICAgICAgIGFlcyh5ID0gLTAuMzUsIGxhYmVsID0gbmljZV9kaWZmLCBmaWxsID0gTlVMTCksCiAgICAgICAgICAgIGZhbWlseSA9ICJEZWphVnUgU2FucyBDb25kZW5zZWQiLCBmb250ZmFjZSA9ICJwbGFpbiIsIHNpemUgPSAxLjUsIHZqdXN0ID0gLTAuODUpICsKICBnZW9tX2hhbGZfYm94cGxvdChkYXRhID0gc2ltX2hpZ2gsCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsIHNpZGUgPSAibCIsIG91dGxpZXIuc2hhcGUgPSBOQSwgZXJyb3JiYXIuZHJhdyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgbnVkZ2UgPSAwLjA1LCBhbHBoYSA9IDAuNSkgKwogIGdlb21faGFsZl9ib3hwbG90KGRhdGEgPSBzaW1fbG93LAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gInIiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgIG51ZGdlID0gMC4wNSwgYWxwaGEgPSAwLjUpICsKICBzdGF0X3N1bW1hcnkoZGF0YSA9IHNpbV9oaWdoLCBnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMjIpKSArCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBzaW1fbG93LCBnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4yMikpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzJFQ0M0MCIsICIjRkY4NTFCIiksIG5hbWUgPSBOVUxMKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhID0gMC4zLCBzaXplID0gMC4yNSkpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDEsIC0xKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgY29uc3RyYWludHMiLAogICAgICAgeSA9ICLiiIYgdHVybm92ZXIiLAogICAgICAgdGl0bGUgPSAiQjogQ29uc3RyYWludHMgYWNyb3NzIGhpZ2gvbG93IiwKICAgICAgIHN1YnRpdGxlID0gIuKIhiA9IGhpZ2gg4oiSIGxvdyIsCiAgICAgICBjYXB0aW9uID0gZ2x1ZSgiPHNwYW4gc3R5bGU9J2NvbG9yOntjbHJzJGdyZXl9Jz7il4Y8L3NwYW4+ID0gbWVhbiB2YWx1ZTsgKiA9IHAgPCAwLjA1IikpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0LjE1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCAibGluZXMiKSkKcGxvdF90dXJub3Zlcl9obF9kaWZmcwpgYGAKCmBgYHtyIGNvbWJpbmVkLXR1cm5vdmVyLCBmaWcud2lkdGg9cGFyYW1zJGZpZ193aWR0aDIsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHQsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmNvbWJpbmVkX3R1cm5vdmVyIDwtIHBsb3RfdHVybm92ZXJfYm94cGxvdCArIHBsb3RfdHVybm92ZXJfaGxfZGlmZnMKCmNvbWJpbmVkX3R1cm5vdmVyCmdnc2F2ZShjb21iaW5lZF90dXJub3ZlciwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfYm94cGxvdHMucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShjb21iaW5lZF90dXJub3ZlciwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfYm94cGxvdHMucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF90dXJub3ZlciwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfY29tYmluZWQudGlmZiIpLAojICAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gNjAwKQojIGdnc2F2ZShjb21iaW5lZF90dXJub3ZlciwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfY29tYmluZWQuZXBzIiksCiMgICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BzLCBmYWxsYmFja19yZXNvbHV0aW9uID0gNjAwKSAKYGBgCgpgYGB7ciBkaWZmLXR1cm5vdmVyLWltcG9ydGFuY2UsIGNhY2hlPVRSVUV9CiMgVGhpcyB0YWtlcyBhIGZldyBtaW51dGVzIHRvIHJ1bgpzZXQuc2VlZChTRUVEKQpmb3Jlc3RfbW9kZWxfdHVybm92ZXIgPC0gCiAgcmFuZG9tRm9yZXN0KHR1cm5vdmVyX2RpZmYgfgogICAgICAgICAgICAgICAgIGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgZGlzcGVyc2UgKyAKICAgICAgICAgICAgICAgICBjb21wZXRlICsgc2VsZWN0Zm9yX2QgKyBjYXRhc3Ryb3BoZSwKICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFRSVUUsIAogICAgICAgICAgICAgICBkYXRhID0gZHJvcF9uYShzaW1fbHMsIHR1cm5vdmVyX2RpZmYpKQoKZm9yZXN0X21vZGVsX3R1cm5vdmVyX2xvdyA8LSAKICByYW5kb21Gb3Jlc3QodHVybm92ZXJfZGlmZiB+CiAgICAgICAgICAgICAgICAgY3JlYXRlX25ldHdvcmsgKyBzZWxlY3QgKyBkaXNwZXJzZSArIAogICAgICAgICAgICAgICAgIGNvbXBldGUgKyBzZWxlY3Rmb3JfZCArIGNhdGFzdHJvcGhlLAogICAgICAgICAgICAgICBpbXBvcnRhbmNlID0gVFJVRSwgCiAgICAgICAgICAgICAgIGRhdGEgPSBmaWx0ZXIoZHJvcF9uYShzaW1faGwsIHR1cm5vdmVyX2RpZmYpLCByZXBwID09ICJMb3ciKSkKCmZvcmVzdF9tb2RlbF90dXJub3Zlcl9oaWdoIDwtIAogIHJhbmRvbUZvcmVzdCh0dXJub3Zlcl9kaWZmIH4KICAgICAgICAgICAgICAgICBjcmVhdGVfbmV0d29yayArIHNlbGVjdCArIGRpc3BlcnNlICsgCiAgICAgICAgICAgICAgICAgY29tcGV0ZSArIHNlbGVjdGZvcl9kICsgY2F0YXN0cm9waGUsCiAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUUlVFLCAKICAgICAgICAgICAgICAgZGF0YSA9IGZpbHRlcihkcm9wX25hKHNpbV9obCwgdHVybm92ZXJfZGlmZiksIHJlcHAgPT0gIkhpZ2giKSkKYGBgCgpgYGB7ciB0dXJub3Zlci1pbXBvcnRhbmNlLWxzLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KdHVybm92ZXJfaW1wb3J0YW5jZV9scyA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF90dXJub3ZlciwgdHlwZSA9IDEsIHNjYWxlID0gVFJVRSkgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJjb25zdHJhaW50IikgJT4lIAogIGFycmFuZ2UoZGVzYyhYLkluY01TRSkpICU+JSAKICBtdXRhdGUoY29uc3RyYWludCA9IHJlY29kZShjb25zdHJhaW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBzZWxlY3RgID0gInNlbGVjdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYGNvbXBldGVgID0gImNvbXBldGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgZGlzcGVyc2VgID0gImRpc3BlcnNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGZvcl9kYCA9ICJzcGVjaWVzX2RyaWZ0IikpICU+JSAKICBjb2xvcl9jb25zdHJhaW50cyhjb25zdHJhaW50KSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoImNvbnN0cmFpbnQiKSksIGZjdF9pbm9yZGVyKSAlPiUgCiAgbXV0YXRlKFguSW5jTVNFID0gWC5JbmNNU0UgLyAxMDApCgpwbG90X3R1cm5vdmVyX2ltcG9ydGFuY2VfbHMgPC0gZ2dwbG90KHR1cm5vdmVyX2ltcG9ydGFuY2VfbHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gWC5JbmNNU0UsIHkgPSBmY3RfcmV2KGNvbnN0cmFpbnRfY29sb3JlZCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGZjdF9yZXYoY29uc3RyYWludCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpKSArCiAgZ2VvbV9wb2ludHJhbmdlaChhZXMoeG1pbiA9IDAsIHhtYXggPSBYLkluY01TRSksIHNpemUgPSAwLjI1KSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsIGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSBjKDAsIDAuMDIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3QoY2xycyksIGd1aWRlID0gRkFMU0UpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxOSksIG5hbWUgPSBOVUxMKSArCiAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC4yNSkpKSArCiAgbGFicyh4ID0gIlBlcmNlbnQgaW5jcmVhc2UgaW4gTVNFIHdoZW4gZXhjbHVkZWQiLCB5ID0gTlVMTCwgCiAgICAgICB0aXRsZSA9ICJCOiBDb25zdHJhaW50IGltcG9ydGFuY2UgZm9yIOKIhiBzcGVjaWVzIHR1cm5vdmVyIiwKICAgICAgIHN1YnRpdGxlID0gIkhpZ2hlciB2YWx1ZXMgaW5kaWNhdGUgZ3JlYXRlciB2YXJpYWJsZSBpbXBvcnRhbmNlIiwKICAgICAgIGNhcHRpb24gPSAiIikgKwogIHRoZW1lX2NvbnN0cmFpbnQoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAibGVmdCIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSByZWwoMC43KSksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4obCA9IC0wLjUsIHQgPSA0Ljc1LCB1bml0ID0gImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMi41LCAibGluZXMiKSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuOTUsICJsaW5lcyIpKQpwbG90X3R1cm5vdmVyX2ltcG9ydGFuY2VfbHMKCmdnc2F2ZShwbG90X3R1cm5vdmVyX2ltcG9ydGFuY2VfbHMsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInR1cm5vdmVyX0IucGRmIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKHBsb3RfdHVybm92ZXJfaW1wb3J0YW5jZV9scywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfQi5wbmciKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKYGBgCgpgYGB7ciB0dXJub3Zlci1pbXBvcnRhbmNlLWhsLXBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KdHVybm92ZXJfaW1wb3J0YW5jZV9sb3cgPC0gaW1wb3J0YW5jZShmb3Jlc3RfbW9kZWxfdHVybm92ZXJfbG93LCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiTG93IikKCnR1cm5vdmVyX2ltcG9ydGFuY2VfaGlnaCA8LSBpbXBvcnRhbmNlKGZvcmVzdF9tb2RlbF90dXJub3Zlcl9oaWdoLCB0eXBlID0gMSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSAiSGlnaCIpCgp0dXJub3Zlcl9pbXBvcnRhbmNlX2hsIDwtIGJpbmRfcm93cyh0dXJub3Zlcl9pbXBvcnRhbmNlX2xvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHVybm92ZXJfaW1wb3J0YW5jZV9oaWdoKSAlPiUgCiAgbXV0YXRlKHJlcHAgPSBmYWN0b3IocmVwcCwgbGV2ZWxzID0gYygiTG93IiwgIkhpZ2giKSwgb3JkZXJlZCA9IFRSVUUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHJlcHApLCBkZXNjKFguSW5jTVNFKSkgJT4lIAogIG11dGF0ZShjb25zdHJhaW50ID0gcmVjb2RlKGNvbnN0cmFpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHNlbGVjdGAgPSAic2VsZWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgY29tcGV0ZWAgPSAiY29tcGV0aXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBkaXNwZXJzZWAgPSAiZGlzcGVyc2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgc2VsZWN0Zm9yX2RgID0gInNwZWNpZXNfZHJpZnQiKSkgJT4lIAogIGNvbG9yX2NvbnN0cmFpbnRzKGNvbnN0cmFpbnQpICU+JSAKICBtdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiY29uc3RyYWludCIpKSwgZmN0X2lub3JkZXIpICU+JSAKICBtdXRhdGUoWC5JbmNNU0UgPSBYLkluY01TRSAvIDEwMCkKCnBsb3RfdHVybm92ZXJfaW1wb3J0YW5jZV9obCA8LSBnZ3Bsb3QodHVybm92ZXJfaW1wb3J0YW5jZV9obCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLkluY01TRSwgeSA9IGZjdF9yZXYoY29uc3RyYWludF9jb2xvcmVkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmN0X3Jldihjb25zdHJhaW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gcmVwcCwgc2hhcGUgPSByZXBwKSkgKwogIGdlb21fcG9pbnRyYW5nZWgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gWC5JbmNNU0UpLAogICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZXYoaGVpZ2h0ID0gMC41KSwgc2l6ZSA9IDAuMjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMC4wMikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjbHJzKSwgZ3VpZGUgPSBGQUxTRSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXNoZWQiLCAic29saWQiKSwgbmFtZSA9IE5VTEwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNywgMTUpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhsaW5ldHlwZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHJldmVyc2UgPSBUUlVFKSwKICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV2ZXJzZSA9IFRSVUUpKSArCiAgbGFicyh4ID0gIlBlcmNlbnQgaW5jcmVhc2UgaW4gTVNFIHdoZW4gZXhjbHVkZWQiLCB5ID0gTlVMTCwgCiAgICAgICB0aXRsZSA9ICJEOiBDb25zdHJhaW50IGltcG9ydGFuY2UgYWNyb3NzIGhpZ2gvbG93IiwKICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICBjYXB0aW9uID0gIiIpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X21hcmtkb3duKCksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAsIDApLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gImxlZnQiLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC43NSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIuNSwgImxpbmVzIiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjk1LCAibGluZXMiKSkKcGxvdF90dXJub3Zlcl9pbXBvcnRhbmNlX2hsCmBgYAoKYGBge3IgY29tYmluZWQtaW1wb3J0YW5jZS10dXJub3ZlciwgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGgyLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0fQppbXBvcnRhbmNlX3R1cm5vdmVyIDwtIHBsb3RfdHVybm92ZXJfaW1wb3J0YW5jZV9scyArIHBsb3RfdHVybm92ZXJfaW1wb3J0YW5jZV9obAoKaW1wb3J0YW5jZV90dXJub3ZlcgpnZ3NhdmUoaW1wb3J0YW5jZV90dXJub3ZlciwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfaW1wb3J0YW5jZS5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aDIsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikKZ2dzYXZlKGltcG9ydGFuY2VfdHVybm92ZXIsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInR1cm5vdmVyX2ltcG9ydGFuY2UucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgyLCBoZWlnaHQgPSBwYXJhbXMkZmlnX2hlaWdodCwgdW5pdHMgPSAiaW4iLCB0eXBlID0gImNhaXJvIiwgZHBpID0gMzAwKQojIGdnc2F2ZShjb21iaW5lZF9maXRuZXNzLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaXRuZXNzX2NvbWJpbmVkLnRpZmYiKSwKIyAgICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDYwMCkKIyBnZ3NhdmUoY29tYmluZWRfZml0bmVzcywgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZml0bmVzc19jb21iaW5lZC5lcHMiKSwKIyAgICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoMiwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcHMsIGZhbGxiYWNrX3Jlc29sdXRpb24gPSA2MDApIApgYGAKCmBgYHtyIHBsb3QtdHVybm92ZXItYWxsLWNvbWJvcywgZmlnLndpZHRoPXBhcmFtcyRmaWdfd2lkdGhfYmlnLCBmaWcuaGVpZ2h0PXBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KcGxvdF90dXJub3Zlcl9hbGwgPC0gbWVnYV9tZWFuc19wbG90KGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbHMsIHR1cm5vdmVyX2RpZmYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJBdmVyYWdlIOKIhiB0dXJub3ZlciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiQXZlcmFnZSDiiIYgaW4gdHVybm92ZXIgKGxpbmtlZCBzcGVjaWVzIOKIkiB1bmxpbmtlZCBzcGVjaWVzKSBhY3Jvc3MgY29tYmluYXRpb25zIG9mIGNvbnN0cmFpbnRzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfdG9fcmlnaHQgPSAwLjAyLCBhZGRfdG9fbGVmdCA9IDAuMDIsIHhsaW0gPSBjKC0wLjEsIDAuMykpCgpwbG90X3R1cm5vdmVyX2FsbApnZ3NhdmUocGxvdF90dXJub3Zlcl9hbGwsIGZpbGVuYW1lID0gaGVyZSgiYW5hbHlzaXMiLCAib3V0cHV0IiwgInR1cm5vdmVyX21lYW5zX2FsbC5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aF9iaWcsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0X2JpZywgdW5pdHMgPSAiaW4iLCBkZXZpY2UgPSBjYWlyb19wZGYpCmdnc2F2ZShwbG90X3R1cm5vdmVyX2FsbCwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidHVybm92ZXJfbWVhbnNfYWxsLnBuZyIpLAogICAgICAgd2lkdGggPSBwYXJhbXMkZmlnX3dpZHRoX2JpZywgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHRfYmlnLCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSAzMDApCmBgYAoKIyMgRmlndXJlIDk6IExhbmRzY2FwZSB2YXJpYXRpb24KCioqRmlnIDkuIE92ZXJhbGwgbGFuZHNjYXBlIHZhcmlhdGlvbiBpbiBzcGVjaWVzIHJpY2huZXNzKioKCmBgYHtyIGxhbmRzY2FwZS1zcGVjaWVzLWxzLWJveHBsb3QsIGZpZy53aWR0aD1wYXJhbXMkZmlnX3dpZHRoX2h0bWwsIGZpZy5oZWlnaHQ9cGFyYW1zJGZpZ19oZWlnaHRfaHRtbH0KcGxvdF92YXJpYXRpb25fYm94cGxvdCA8LSBnZ3Bsb3Qoc2ltX2xzLCBhZXMoeCA9IG5fY29uc3RyYWludHNfZiwgeSA9IGxhbmRzY2FwZV9zcGVjaWVzX251bWJlcl92YXIpKSArCiAgZ2VvbV9oYWxmX3BvaW50KHNpemUgPSAwLjAxLCBhbHBoYSA9IDAuMDEsIHNpZGUgPSAiciIsIGNvbG9yID0gImdyZXk1MCIsCiAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybWF0aW9uX3BhcmFtcyA9IGxpc3Qod2lkdGggPSAwLjI1LCBoZWlnaHQgPSAwLCBzZWVkID0gMTIzNCkpICsKICBnZW9tX2hhbGZfYm94cGxvdChhZXMoZmlsbCA9ICJMYXRpbiBoeXBlcmN1YmUgc2FtcGxlcyIpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LCBzaWRlID0gImwiLCBvdXRsaWVyLnNoYXBlID0gTkEsIGVycm9yYmFyLmRyYXcgPSBUUlVFLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShnZW9tID0gInBvaW50IiwgZnVuID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMSwgcGNoID0gMjMsIGZpbGwgPSBjbHJzJGdyZXksIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuMTkpKSArCiAgIyBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzAwNzREOSIpLCBuYW1lID0gTlVMTCkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgb3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYSA9IDAuMywgc2l6ZSA9IDAuMjUpKSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAzMDApKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkxhbmRzY2FwZSB2YXJpYXRpb24gaW4gc3BlY2llcyByaWNobmVzcyIsCiAgICAgICB0aXRsZSA9ICJBOiBMYW5kc2NhcGUgdmFyaWF0aW9uIGluIHNwZWNpZXMgcmljaG5lc3MiLAogICAgICAgIyBzdWJ0aXRsZSA9ICJWYWx1ZXMgbmVhciB6ZXJvIGluZGljYXRlIGhpZ2ggdmFyaWF0aW9uIiwKICAgICAgIGNhcHRpb24gPSBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6e2NscnMkZ3JleX0nPuKXhjwvc3Bhbj4gPSBtZWFuIHZhbHVlIikpICsKICB0aGVtZV9jb25zdHJhaW50KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bigpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLCAwKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKGwgPSAtMC41LCB0ID0gNC4xNSwgdW5pdCA9ICJsaW5lcyIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwgImxpbmVzIikpCnBsb3RfdmFyaWF0aW9uX2JveHBsb3QKCmdnc2F2ZShwbG90X3ZhcmlhdGlvbl9ib3hwbG90LCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJsYW5kc2NhcGVfc3BlY2llcy5wZGYiKSwKICAgICAgIHdpZHRoID0gcGFyYW1zJGZpZ193aWR0aCwgaGVpZ2h0ID0gcGFyYW1zJGZpZ19oZWlnaHQsIHVuaXRzID0gImluIiwgZGV2aWNlID0gY2Fpcm9fcGRmKQpnZ3NhdmUocGxvdF92YXJpYXRpb25fYm94cGxvdCwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAibGFuZHNjYXBlX3NwZWNpZXMucG5nIiksCiAgICAgICB3aWR0aCA9IHBhcmFtcyRmaWdfd2lkdGgsIGhlaWdodCA9IHBhcmFtcyRmaWdfaGVpZ2h0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iLCBkcGkgPSAzMDApCmBgYAoKXAoKIyBPcmlnaW5hbCBjb21wdXRpbmcgZW52aXJvbm1lbnQKCjxidXR0b24gZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBkYXRhLXRhcmdldD0iI3Nlc3Npb25pbmZvIiBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IGJ0bi1tZCBidG4taW5mbyI+SGVyZSdzIHdoYXQgd2UgdXNlZCB0aGUgbGFzdCB0aW1lIHdlIGJ1aWx0IHRoaXMgcGFnZTwvYnV0dG9uPgoKPGRpdiBpZD0ic2Vzc2lvbmluZm8iIGNsYXNzPSJjb2xsYXBzZSI+CgpgYGB7ciBzaG93LXNlc3Npb24taW5mbywgZWNobz1UUlVFLCB3aWR0aD0xMDB9CndyaXRlTGluZXMocmVhZExpbmVzKGZpbGUucGF0aChTeXMuZ2V0ZW52KCJIT01FIiksICIuUi9NYWtldmFycyIpKSkKCmRldnRvb2xzOjpzZXNzaW9uX2luZm8oKQpgYGAKCjwvZGl2PiAK