knitr::opts_chunk$set(cache = TRUE, dev = c("png", "pdf"))
library(here)
source(here("src", "model_linear_grampians.R"))
source(here("src", "environmental_distance_metrics.R"))
library(bossMaps)
library(dplyr)
library(ggplot2)
library(gridExtra)
#library(rstanarm)
library(tidyr)

The following is a validation of the predictions/inference from a trait-environment model of the Grampians Bioregion ~20 taxa dataset.

The following steps are undertaken:

mds <- local({
  nms1 <-   c(
    "mean_moisture_index_of_low_qtr", "topographic_wetness_index_3sec",
    "relief_1000m_radius", "total_nitrogen"
  )
  nms2 <- c("sla_mm2_per_mg", "seed_mass_mg", "max_height_m")
  vars <- lapply(nms1, function(x) log(grampians[[x]]))
  vars <- do.call(cbind, vars)
  vars <- cbind(
    vars, do.call(cbind, lapply(nms2, function(x) log(grampians[[x]])))
  )
  vars <- scale(vars)
  cntrs <- attr(vars, "scaled:center")
  scales <- attr(vars, "scaled:scale")

  vars_new_raw <- na.omit(southeast)
  vars_new <- lapply(seq_along(nms1), function(x) log(vars_new_raw[[nms1[x]]]))
  vars_new <- do.call(cbind, vars_new)
  vars_new <- cbind(
    vars_new, do.call(cbind, lapply(nms2, function(x) log(vars_new_raw[[x]])))
  )
  vars_new <- scale(vars_new, center = cntrs, scale = scales)

  setNames(
    data.frame(
      vars_new_raw[, c("occupancy", "taxon", "ibra_subregion")], vars_new
    ),
    c(
      "y", "taxon", "ibra_subregion", "mlq", "twi", "r1k", "tn", "sla", "sm",
      "mh"
    )
  )
})
perf <- local({
  perf <- mapply(
    function(f, re.form) {
      f(
        model_grampians, y, list(taxon, ibra_subregion),
        rbind(mds, mdg[names(mds)]), re.form
      )
    },
    f = rep(
      list(auroc, pred_inf, dev_explained, auprc, auprc_rel, auprc_rand),
      each = 2
    ),
    re.form = list(NULL,  NA)
  )
  taxon <- sub("(.*)\\..*", "\\1", rownames(perf))
  ibra_subregion <- sub(".*\\.", "", rownames(perf))
  dim(perf) <- dim(perf) * c(2, .5)
  colnames(perf) <- c(
    "AUC", "mean_predictive_info", "deviance_explained", "AUC-PR", "Rel-AUC-PR",
    "Rand-AUC-PR"
  )
  cbind(
    taxon = rep(taxon, 2),
    ibra_subregion = rep(ibra_subregion, 2),
    random_effect = rep(c(TRUE, FALSE), each = nrow(perf) / 2),
    as.data.frame(perf)
  )
})
taxon_region_prevalence <- summarise(
  group_by(rbind(mds, mdg[names(mds)]), taxon, ibra_subregion),
  prevalence = mean(y))

aucdist <- data.frame(
  perf[c("taxon", "ibra_subregion", "AUC", "AUC-PR")],
  `Geographic (km)`= dists[as.character(perf$ibra_subregion)],
  Environmental = kldists[as.character(perf$ibra_subregion)],
  Community = community_dist[as.character(perf$ibra_subregion)],
  "Dummy" = "Dummy",
  check.names = FALSE
)

aucdist <- aucdist[!perf$random_effect, ]

# Pete: "This retains two values for each model predciton, for random_effect =
#        TRUE or FALSE."
# Will: "Yes, effectively making predictions with knowledge of species ID or
#        with trait information only."

aucdist <- gather(
  aucdist, "distance", "value", `Geographic (km)`, Environmental, Community
)

aucdist <- left_join(aucdist, taxon_region_prevalence)

aucdistmean <- summarise(
  group_by(aucdist, ibra_subregion, distance),
  medauc = median(AUC),
  medauprc = median(`AUC-PR` / prevalence),
  value = mean(value)
)

aucdistplot <- ggplot(aucdist) +
  aes(AUC, value) +
  geom_vline(xintercept = .5, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauc), data = aucdistmean, size = 2, shape = 21, fill = "white"
  ) +
  xlim(.4, 1) +
  ylab("Distance") +
  facet_grid(. ~ distance, scales = "free_x") +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.background = element_blank()
  )

aucbw <- ggplot(aucdist) +
  aes(x = Dummy, y = AUC) +
  geom_boxplot(fill = "grey") +
  facet_grid(. ~ Dummy) +
  ylim(.4, 1) +
  scale_x_discrete(labels = "0.95") +
  xlab("Dummy") +
  theme_bw() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x  = element_blank(),
    axis.ticks.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_text(color = "transparent"),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

aucplot_gg <- ggplot(filter(aucdist, ibra_subregion == "Greater Grampians")) +
  aes(x = AUC, y = 1) +
  geom_vline(xintercept = .5, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauc),
    data = slice(filter(aucdistmean, ibra_subregion == "Greater Grampians"), 1L),
    size = 2, shape = 21, fill = "white"
  ) +
  xlim(.4, 1) +
  ylab("Distance") +
  xlab("AUROC") +
  facet_grid(. ~ Dummy) +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x  = element_blank(),
    axis.ticks.x = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_text(color = "transparent"),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

auprcdistplot <- ggplot(aucdist) +
  aes(`AUC-PR` / prevalence, value) +
  scale_x_continuous(
    trans = "log2", breaks = 2^seq(-1, 8, 2), labels = 2^seq(-1, 8, 2),
    limits = c(.5, 170)
  ) +
  geom_vline(xintercept = 1, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauprc), data = aucdistmean, size = 2, shape = 21, fill = "white"
  ) +
  ylab("Distance") +
  facet_grid(. ~ distance, scales = "free_x") +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )

auprcbw <- ggplot(aucdist) +
  aes(x = Dummy, y = `AUC-PR` / prevalence) +
  scale_y_continuous(trans = "log2", limits = c(.5, 170)) +
  geom_boxplot(fill = "grey") +
  facet_grid(. ~ Dummy) +
  scale_x_discrete(labels = "0.95") +
  xlab("Dummy") +
  theme_bw() +
  theme(
    axis.title.x = element_text(color = "transparent"),
    axis.text.x  = element_text(color = "transparent"),
    axis.ticks.x = element_line(color = "transparent"),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank(),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

auprcplot_gg <- ggplot(filter(aucdist, ibra_subregion == "Greater Grampians")) +
  aes(x = `AUC-PR` / prevalence, y = 1) +
  scale_x_continuous(
    trans = "log2", breaks = 2^seq(-1, 8, 2), labels = 2^seq(-1, 8, 2),
    limits = c(.5, 170)
  ) +
  geom_vline(xintercept = 1, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauprc),
    data =
      slice(filter(aucdistmean, ibra_subregion == "Greater Grampians"), 1L),
    size = 2, shape = 21, fill = "white"
  ) +
  ylab("Distance") +
  xlab("AUPRC / Prevalence") +
  facet_grid(. ~ Dummy) +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.x = element_text(color = "transparent"),
    axis.text.x  = element_text(color = "transparent"),
    axis.ticks.x = element_line(color = "transparent"),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank(),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

grid.arrange(
  aucplot_gg, aucbw, aucdistplot, auprcplot_gg, auprcbw, auprcdistplot,
  nrow = 2, widths = c(.12, .08, .8), heights = c(.49, .51)
)

Boxplot statistics

boxplot.stats(aucdist$AUC)
$stats
[1] 0.4215136 0.5685906 0.6539451 0.7735350 0.9946237

$n
[1] 1740

$conf
[1] 0.6461823 0.6617079

$out
numeric(0)
boxplot.stats(aucdist$`AUC-PR` / aucdist$prevalence)
$stats
[1] 0.5029651 0.8867251 1.2357457 2.1772197 3.9946279

$n
[1] 1740

$conf
[1] 1.186865 1.284627

$out
  [1]   6.264201  11.029269   5.019779   6.194359   4.447007  17.060637
  [7] 166.550516  10.339579   4.468890   5.349636   4.286554   4.177586
 [13]   4.590621   5.202100   5.562653   4.394573   8.573941   6.993234
 [19]   6.819060   5.304599   6.190532  12.412588  48.896500   4.648834
 [25]  12.633072   6.219755   6.904140  57.381477   7.504053   6.509198
 [31]  43.937150  12.936753   5.292922  40.670476   9.529626   6.535023
 [37]   8.369079   4.933171  61.103639   4.365564   4.818119   6.961859
 [43]  10.586430   4.843684  26.497484   5.904673  13.011292   5.033057
 [49]   8.044636   5.558887   4.540611  39.155428   5.168444   6.487082
 [55]  28.285509  13.719953   8.633631  12.569967  53.620160   7.464814
 [61]   5.578885  16.645197   4.539642   6.264201  11.029269   5.019779
 [67]   6.194359   4.447007  17.060637 166.550516  10.339579   4.468890
 [73]   5.349636   4.286554   4.177586   4.590621   5.202100   5.562653
 [79]   4.394573   8.573941   6.993234   6.819060   5.304599   6.190532
 [85]  12.412588  48.896500   4.648834  12.633072   6.219755   6.904140
 [91]  57.381477   7.504053   6.509198  43.937150  12.936753   5.292922
 [97]  40.670476   9.529626   6.535023   8.369079   4.933171  61.103639
[103]   4.365564   4.818119   6.961859  10.586430   4.843684  26.497484
[109]   5.904673  13.011292   5.033057   8.044636   5.558887   4.540611
[115]  39.155428   5.168444   6.487082  28.285509  13.719953   8.633631
[121]  12.569967  53.620160   7.464814   5.578885  16.645197   4.539642
[127]   6.264201  11.029269   5.019779   6.194359   4.447007  17.060637
[133] 166.550516  10.339579   4.468890   5.349636   4.286554   4.177586
[139]   4.590621   5.202100   5.562653   4.394573   8.573941   6.993234
[145]   6.819060   5.304599   6.190532  12.412588  48.896500   4.648834
[151]  12.633072   6.219755   6.904140  57.381477   7.504053   6.509198
[157]  43.937150  12.936753   5.292922  40.670476   9.529626   6.535023
[163]   8.369079   4.933171  61.103639   4.365564   4.818119   6.961859
[169]  10.586430   4.843684  26.497484   5.904673  13.011292   5.033057
[175]   8.044636   5.558887   4.540611  39.155428   5.168444   6.487082
[181]  28.285509  13.719953   8.633631  12.569967  53.620160   7.464814
[187]   5.578885  16.645197   4.539642
aucdist_so <- filter(aucdist, taxon %in% intersect(mds$taxon, mdg$taxon))

aucdistmean_so <- summarise(
  group_by(aucdist_so, ibra_subregion, distance),
  medauc = median(AUC),
  medauprc = median(`AUC-PR` / prevalence),
  value = mean(value)
)

aucdistplot_so <- ggplot(aucdist_so) +
  aes(AUC, value) +
  geom_vline(xintercept = .5, color = "grey", size = 1.5) +
  geom_point(alpha = .1) +
  geom_point(
    aes(medauc), data = aucdistmean_so, size = 2, shape = 21, fill = "white"
  ) +
  xlim(.4, 1) +
  ylab("Distance") +
  facet_grid(. ~ distance, scales = "free_x") +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.background = element_blank()
  )

aucbw_so <- ggplot(aucdist_so) +
  aes(x = Dummy, y = AUC) +
  geom_boxplot(fill = "grey") +
  facet_grid(. ~ Dummy) +
  ylim(.4, 1) +
  scale_x_discrete(labels = "0.95") +
  xlab("Dummy") +
  theme_bw() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x  = element_blank(),
    axis.ticks.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_text(color = "transparent"),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

aucplot_gg_so <- ggplot(filter(aucdist_so, ibra_subregion == "Greater Grampians")) +
  aes(x = AUC, y = 1) +
  geom_vline(xintercept = .5, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauc),
    data = slice(filter(aucdistmean_so, ibra_subregion == "Greater Grampians"), 1L),
    size = 2, shape = 21, fill = "white"
  ) +
  xlim(.4, 1) +
  ylab("Distance") +
  xlab("AUROC") +
  facet_grid(. ~ Dummy) +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x  = element_blank(),
    axis.ticks.x = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_text(color = "transparent"),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

auprcdistplot_so <- ggplot(aucdist_so) +
  aes(`AUC-PR` / prevalence, value) +
  scale_x_continuous(
    trans = "log2", breaks = 2^seq(-1, 8, 2), labels = 2^seq(-1, 8, 2),
    limits = c(.5, 170)
  ) +
  geom_vline(xintercept = 1, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauprc), data = aucdistmean_so, size = 2, shape = 21, fill = "white"
  ) +
  ylab("Distance") +
  facet_grid(. ~ distance, scales = "free_x") +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )

auprcbw_so <- ggplot(aucdist_so) +
  aes(x = Dummy, y = `AUC-PR` / prevalence) +
  scale_y_continuous(trans = "log2", limits = c(.5, 170)) +
  geom_boxplot(fill = "grey") +
  facet_grid(. ~ Dummy) +
  scale_x_discrete(labels = "0.95") +
  xlab("Dummy") +
  theme_bw() +
  theme(
    axis.title.x = element_text(color = "transparent"),
    axis.text.x  = element_text(color = "transparent"),
    axis.ticks.x = element_line(color = "transparent"),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank(),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

auprcplot_gg_so <- ggplot(filter(aucdist_so, ibra_subregion == "Greater Grampians")) +
  aes(x = `AUC-PR` / prevalence, y = 1) +
  scale_x_continuous(
    trans = "log2", breaks = 2^seq(-1, 8, 2), labels = 2^seq(-1, 8, 2),
    limits = c(.5, 170)
  ) +
  geom_vline(xintercept = 1, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(medauprc),
    data =
      slice(filter(aucdistmean_so, ibra_subregion == "Greater Grampians"), 1L),
    size = 2, shape = 21, fill = "white"
  ) +
  ylab("Distance") +
  xlab("AUPRC / Prevalence") +
  facet_grid(. ~ Dummy) +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.x = element_text(color = "transparent"),
    axis.text.x  = element_text(color = "transparent"),
    axis.ticks.x = element_line(color = "transparent"),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank(),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

grid.arrange(
  aucplot_gg_so, aucbw_so, aucdistplot_so, auprcplot_gg_so, auprcbw_so,
  auprcdistplot_so,
  nrow = 2, widths = c(.12, .08, .8), heights = c(.49, .51)
)

devdist <- data.frame(
  perf[c("taxon", "ibra_subregion", "deviance_explained")],
  `Geographic (km)`= dists[as.character(perf$ibra_subregion)],
  Environmental = kldists[as.character(perf$ibra_subregion)],
  Community = community_dist[as.character(perf$ibra_subregion)],
  "Dummy" = "Dummy",
  check.names = FALSE
)

devdist <- gather(
  devdist, "distance", "value", `Geographic (km)`, Environmental, Community
)

devdist <- na.omit(devdist)

colnames(devdist)[3] <- "Deviance explained"

devdistmean <- summarise(
  group_by(devdist, ibra_subregion, distance),
  meandev = mean(`Deviance explained`), value = mean(value)
)

devdistplot <- ggplot(devdist) +
  aes(`Deviance explained`, value) +
  geom_vline(xintercept = 0, color = "grey", size = 1.5) +
  geom_point(alpha=.1) +
  geom_point(
    aes(meandev), data = devdistmean, size = 2, shape = 21, fill = "white"
  ) +
  scale_x_continuous(trans = "asinh", limits = c(-56, 1)) +
  ylab("Distance") +
  facet_grid(. ~ distance, scales = "free_x") +
  coord_flip() +
  theme_bw() +
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    strip.background = element_blank()
  )

devbw <- ggplot(devdist) +
  aes(x = Dummy, y = `Deviance explained`) +
  geom_boxplot(fill = "grey") +
  facet_grid(. ~ Dummy) +
  scale_y_continuous(trans = "asinh", limits = c(-56, 1)) +
  scale_x_discrete(labels = "0.95") +
  xlab("Dummy") +
  theme_bw() +
  theme(
    axis.title.x = element_text(color = "transparent"),
    axis.text.x  = element_text(color = "transparent"),
    axis.ticks.x = element_line(color = "transparent"),
    strip.background = element_blank(),
    strip.text.x = element_text(color = "transparent"),
    plot.margin = margin(5.5, 0, 5.5, 5.5)
  )

grid.arrange(devbw, devdistplot, nrow = 1, widths = c(.14, .86))

ggplot(
  transform(
    subset(perf, ibra_subregion != "Greater Grampians" & !random_effect),
    ibra_subregion = factor(
      ibra_subregion, names(sort(tapply(AUC, ibra_subregion, median)))
    )
  )
) +
aes(AUC) + geom_histogram() +
facet_wrap(
  ~ibra_subregion, 6,
  labeller = as_labeller(
    function(x) {
      x <- gsub("-", "- ", x)
      x <- strwrap(x, width = 13, simplify = FALSE)
      vapply(x, paste, character(1), collapse = "\n")
    }
  )
) +
xlab("AUC") +
ylab("No. of taxa") +
theme_bw() +
theme(axis.text.x = element_text(size = 8))

ggplot(
  transform(
    subset(
      left_join(perf, taxon_region_prevalence),
      ibra_subregion != "Greater Grampians" & !random_effect
    ),
    ibra_subregion = factor(
      ibra_subregion, names(sort(tapply(AUC, ibra_subregion, median)))
    )
  )
) +
aes(prevalence, AUC) +
geom_point(alpha = .5) +
facet_wrap(
  ~ibra_subregion, 6,
  labeller = as_labeller(
    function(x) {
      x <- gsub("-", "- ", x)
      x <- strwrap(x, width = 13, simplify = FALSE)
      vapply(x, paste, character(1), collapse = "\n")
    }
  )
) +
xlab("Prevalence") +
ylab("AUC") +
theme_bw() +
theme(axis.text.x = element_text(size = 8))

ggplot(
  transform(
    subset(perf, ibra_subregion != "Greater Grampians" & !random_effect),
    ibra_subregion = factor(
      ibra_subregion,
      names(sort(tapply(mean_predictive_info, ibra_subregion, median)))
    )
  )
) +
aes(mean_predictive_info) + geom_histogram() + facet_wrap(~ibra_subregion, 3) +
xlab("Mean Predictive Information") +
ylab("No. of taxa") +
ggtitle(
  paste(
    "Mean Predictive Information for taxa within IBRA subregions of",
    "Southeast Australia"
  )
)

ggplot(
  transform(
    subset(perf, taxon %in% mdg$taxon & random_effect),
    taxon = factor(
      taxon,
      names(
        sort(
          tapply(
            AUC[ibra_subregion == "Greater Grampians"],
            taxon[ibra_subregion == "Greater Grampians"],
            median
          )
        )
      )
    )
  )
) +
aes(
  AUC,
  mean_predictive_info,
  col = ifelse(
    ibra_subregion == "Greater Grampians",
    "Grampians",
    "Other Region"
  )
) +
geom_point() +
facet_wrap(~taxon, labeller = label_wrap_gen(40)) +
labs(col = NULL) +
xlab("AUC") +
ylab("Mean Predictive Information") +
ggtitle(
  paste(
    ""
  )
) +
theme(legend.position = "bottom")

#model_auc <- stan_glmer(
#  (AUC - .001) ~ value + (1 | ibra_subregion/taxon),
#  family = mgcv::betar,
#  iter = 1000, chains = 3,
#  data = aucdist,
#  subset = ibra_subregion != "Greater Grampians" & distance == "Geographic (km)"
#)
#summary(model_auc, regex_pars = "^[^b]", probs = c(.025, .975))
IycgLS0tCiMnIHRpdGxlOiAiVmFsaWRhdGlvbiBvZiBsaW5lYXIgbW9kZWwiCiMnIGF1dGhvcjogIldpbGxpYW0gSy4gTW9ycmlzIgojJyBkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCiMnIG91dHB1dDoKIycgICBybWFya2Rvd246Omh0bWxfbm90ZWJvb2s6CiMnICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKIycgLS0tCgojKyBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgZmlnLmtlZXA9Im5vbmUiLCBmaWcuc2hvdz0iaGlkZSIKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gVFJVRSwgZGV2ID0gYygicG5nIiwgInBkZiIpKQpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlKCJzcmMiLCAibW9kZWxfbGluZWFyX2dyYW1waWFucy5SIikpCnNvdXJjZShoZXJlKCJzcmMiLCAiZW52aXJvbm1lbnRhbF9kaXN0YW5jZV9tZXRyaWNzLlIiKSkKbGlicmFyeShib3NzTWFwcykKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKI2xpYnJhcnkocnN0YW5hcm0pCmxpYnJhcnkodGlkeXIpCgojJyBUaGUgZm9sbG93aW5nIGlzIGEgdmFsaWRhdGlvbiBvZiB0aGUgcHJlZGljdGlvbnMvaW5mZXJlbmNlIGZyb20gYQojJyB0cmFpdC1lbnZpcm9ubWVudCBtb2RlbCBvZiB0aGUgR3JhbXBpYW5zIEJpb3JlZ2lvbiB+MjAgdGF4YSBkYXRhc2V0LgojJwojJyBUaGUgZm9sbG93aW5nIHN0ZXBzIGFyZSB1bmRlcnRha2VuOgojJwojJyAqIEZpdCBhIG1vZGVsIHRvIEdyYW1waWFucyBkYXRhLgojJyAqIENhbGN1bGF0ZSBQZXJmb3JtYW5jZSBNZXRyaWNzOgojJyAgICAgKiBQcmVkaWN0IHByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2UKIycgICAgICAgICAqIFByZWRpY3Qgd2l0aGluIEdyYW1waWFucyB0cmFpbmluZyBzZXQ6CiMnICAgICAgICAgICAgICogUHJlZGljdCBmb3IgZWFjaCBzcGVjaWVzIGluY2x1ZGluZyBzcGVjaWVzIHJhbmRvbSBlZmZlY3RzLgojJyAgICAgICAgICAgICAqIFByZWRpY3QgZm9yIGVhY2ggc3BlY2llcyB3aXRob3V0IHNwZWNpZXMgcmFuZG9tIGVmZmVjdHMuCiMnICAgICAgICAgKiBQcmVkaWN0IHRvIHRoZSBTb3V0aC1lYXN0IHZhbGlkYXRpb24gc2V0OgojJyAgICAgICAgICAgICAqIFByZWRpY3QgdG8gZWFjaCBJQlJBIHN1YnJlZ2lvbiB3aXRoaW4gdGhlIFNvdXRoLWVhc3Q6CiMnICAgICAgICAgICAgICAgICAqIFByZWRpY3QgZm9yIGVhY2ggc3BlY2llcyBjb21tb24gdG8gR3JhbXBpYW5zIGFuZCBTb3V0aC1lYXN0CiMnICAgICAgICAgICAgICAgICAgIHN1YnJlZ2lvbjoKIycgICAgICAgICAgICAgICAgICAgICAqIFByZWRpY3QgaW5jbHVkaW5nIHNwZWNpZXMgcmFuZG9tIGVmZmVjdHMuCiMnICAgICAgICAgICAgICAgICAgICAgKiBQcmVkaWN0IHdpdGhvdXQgc3BlY2llcyByYW5kb20gZWZmZWN0cy4KIycgICAgICAgICAgICAgICAgICogUHJlZGljdCBmb3IgZWFjaCBzcGVjaWVzIG5vdCBmb3VuZCBpbiB0aGUgR3JhbXBpYW5zCiMnICAgICAgICAgICAgICAgICAgIHRyYWluaW5nIHNldC4KIycgICAgICogRm9yIGVhY2ggcHJlZGljdGlvbiB0eXBlICh3aXRoaW4tc2FtcGxlL291dC1vZi1zYW1wbGUsCiMnICAgICAgIHdpdGgtcmUvd2l0aG91dC1yZSwgYW5kIG1vZGVsbGVkLXNwZWNpZXMvdW5tb2RlbGxlZC1zcGVjaWVzKSwKIycgICAgICAgYmlvcmVnaW9uLCBhbmQgc3BlY2llcyAoYW5kIHRoZWlyIGNvbWJpbmF0aW9ucykgY2FsY3VsYXRlIHBlcmZvcm1hbmNlCiMnICAgICAgIG1ldHJpY3MKCiMrIG1kcwptZHMgPC0gbG9jYWwoewogIG5tczEgPC0gICBjKAogICAgIm1lYW5fbW9pc3R1cmVfaW5kZXhfb2ZfbG93X3F0ciIsICJ0b3BvZ3JhcGhpY193ZXRuZXNzX2luZGV4XzNzZWMiLAogICAgInJlbGllZl8xMDAwbV9yYWRpdXMiLCAidG90YWxfbml0cm9nZW4iCiAgKQogIG5tczIgPC0gYygic2xhX21tMl9wZXJfbWciLCAic2VlZF9tYXNzX21nIiwgIm1heF9oZWlnaHRfbSIpCiAgdmFycyA8LSBsYXBwbHkobm1zMSwgZnVuY3Rpb24oeCkgbG9nKGdyYW1waWFuc1tbeF1dKSkKICB2YXJzIDwtIGRvLmNhbGwoY2JpbmQsIHZhcnMpCiAgdmFycyA8LSBjYmluZCgKICAgIHZhcnMsIGRvLmNhbGwoY2JpbmQsIGxhcHBseShubXMyLCBmdW5jdGlvbih4KSBsb2coZ3JhbXBpYW5zW1t4XV0pKSkKICApCiAgdmFycyA8LSBzY2FsZSh2YXJzKQogIGNudHJzIDwtIGF0dHIodmFycywgInNjYWxlZDpjZW50ZXIiKQogIHNjYWxlcyA8LSBhdHRyKHZhcnMsICJzY2FsZWQ6c2NhbGUiKQoKICB2YXJzX25ld19yYXcgPC0gbmEub21pdChzb3V0aGVhc3QpCiAgdmFyc19uZXcgPC0gbGFwcGx5KHNlcV9hbG9uZyhubXMxKSwgZnVuY3Rpb24oeCkgbG9nKHZhcnNfbmV3X3Jhd1tbbm1zMVt4XV1dKSkKICB2YXJzX25ldyA8LSBkby5jYWxsKGNiaW5kLCB2YXJzX25ldykKICB2YXJzX25ldyA8LSBjYmluZCgKICAgIHZhcnNfbmV3LCBkby5jYWxsKGNiaW5kLCBsYXBwbHkobm1zMiwgZnVuY3Rpb24oeCkgbG9nKHZhcnNfbmV3X3Jhd1tbeF1dKSkpCiAgKQogIHZhcnNfbmV3IDwtIHNjYWxlKHZhcnNfbmV3LCBjZW50ZXIgPSBjbnRycywgc2NhbGUgPSBzY2FsZXMpCgogIHNldE5hbWVzKAogICAgZGF0YS5mcmFtZSgKICAgICAgdmFyc19uZXdfcmF3WywgYygib2NjdXBhbmN5IiwgInRheG9uIiwgImlicmFfc3VicmVnaW9uIildLCB2YXJzX25ldwogICAgKSwKICAgIGMoCiAgICAgICJ5IiwgInRheG9uIiwgImlicmFfc3VicmVnaW9uIiwgIm1scSIsICJ0d2kiLCAicjFrIiwgInRuIiwgInNsYSIsICJzbSIsCiAgICAgICJtaCIKICAgICkKICApCn0pCgojKyBwZXJmCnBlcmYgPC0gbG9jYWwoewogIHBlcmYgPC0gbWFwcGx5KAogICAgZnVuY3Rpb24oZiwgcmUuZm9ybSkgewogICAgICBmKAogICAgICAgIG1vZGVsX2dyYW1waWFucywgeSwgbGlzdCh0YXhvbiwgaWJyYV9zdWJyZWdpb24pLAogICAgICAgIHJiaW5kKG1kcywgbWRnW25hbWVzKG1kcyldKSwgcmUuZm9ybQogICAgICApCiAgICB9LAogICAgZiA9IHJlcCgKICAgICAgbGlzdChhdXJvYywgcHJlZF9pbmYsIGRldl9leHBsYWluZWQsIGF1cHJjLCBhdXByY19yZWwsIGF1cHJjX3JhbmQpLAogICAgICBlYWNoID0gMgogICAgKSwKICAgIHJlLmZvcm0gPSBsaXN0KE5VTEwsICBOQSkKICApCiAgdGF4b24gPC0gc3ViKCIoLiopXFwuLioiLCAiXFwxIiwgcm93bmFtZXMocGVyZikpCiAgaWJyYV9zdWJyZWdpb24gPC0gc3ViKCIuKlxcLiIsICIiLCByb3duYW1lcyhwZXJmKSkKICBkaW0ocGVyZikgPC0gZGltKHBlcmYpICogYygyLCAuNSkKICBjb2xuYW1lcyhwZXJmKSA8LSBjKAogICAgIkFVQyIsICJtZWFuX3ByZWRpY3RpdmVfaW5mbyIsICJkZXZpYW5jZV9leHBsYWluZWQiLCAiQVVDLVBSIiwgIlJlbC1BVUMtUFIiLAogICAgIlJhbmQtQVVDLVBSIgogICkKICBjYmluZCgKICAgIHRheG9uID0gcmVwKHRheG9uLCAyKSwKICAgIGlicmFfc3VicmVnaW9uID0gcmVwKGlicmFfc3VicmVnaW9uLCAyKSwKICAgIHJhbmRvbV9lZmZlY3QgPSByZXAoYyhUUlVFLCBGQUxTRSksIGVhY2ggPSBucm93KHBlcmYpIC8gMiksCiAgICBhcy5kYXRhLmZyYW1lKHBlcmYpCiAgKQp9KQoKIysgcGxvdC1hdWMtZGlzdCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDcuNSwgZmlnLmhlaWdodCA9IDQuNQp0YXhvbl9yZWdpb25fcHJldmFsZW5jZSA8LSBzdW1tYXJpc2UoCiAgZ3JvdXBfYnkocmJpbmQobWRzLCBtZGdbbmFtZXMobWRzKV0pLCB0YXhvbiwgaWJyYV9zdWJyZWdpb24pLAogIHByZXZhbGVuY2UgPSBtZWFuKHkpKQoKYXVjZGlzdCA8LSBkYXRhLmZyYW1lKAogIHBlcmZbYygidGF4b24iLCAiaWJyYV9zdWJyZWdpb24iLCAiQVVDIiwgIkFVQy1QUiIpXSwKICBgR2VvZ3JhcGhpYyAoa20pYD0gZGlzdHNbYXMuY2hhcmFjdGVyKHBlcmYkaWJyYV9zdWJyZWdpb24pXSwKICBFbnZpcm9ubWVudGFsID0ga2xkaXN0c1thcy5jaGFyYWN0ZXIocGVyZiRpYnJhX3N1YnJlZ2lvbildLAogIENvbW11bml0eSA9IGNvbW11bml0eV9kaXN0W2FzLmNoYXJhY3RlcihwZXJmJGlicmFfc3VicmVnaW9uKV0sCiAgIkR1bW15IiA9ICJEdW1teSIsCiAgY2hlY2submFtZXMgPSBGQUxTRQopCgphdWNkaXN0IDwtIGF1Y2Rpc3RbIXBlcmYkcmFuZG9tX2VmZmVjdCwgXQoKIyBQZXRlOiAiVGhpcyByZXRhaW5zIHR3byB2YWx1ZXMgZm9yIGVhY2ggbW9kZWwgcHJlZGNpdG9uLCBmb3IgcmFuZG9tX2VmZmVjdCA9CiMgICAgICAgIFRSVUUgb3IgRkFMU0UuIgojIFdpbGw6ICJZZXMsIGVmZmVjdGl2ZWx5IG1ha2luZyBwcmVkaWN0aW9ucyB3aXRoIGtub3dsZWRnZSBvZiBzcGVjaWVzIElEIG9yCiMgICAgICAgIHdpdGggdHJhaXQgaW5mb3JtYXRpb24gb25seS4iCgphdWNkaXN0IDwtIGdhdGhlcigKICBhdWNkaXN0LCAiZGlzdGFuY2UiLCAidmFsdWUiLCBgR2VvZ3JhcGhpYyAoa20pYCwgRW52aXJvbm1lbnRhbCwgQ29tbXVuaXR5CikKCmF1Y2Rpc3QgPC0gbGVmdF9qb2luKGF1Y2Rpc3QsIHRheG9uX3JlZ2lvbl9wcmV2YWxlbmNlKQoKYXVjZGlzdG1lYW4gPC0gc3VtbWFyaXNlKAogIGdyb3VwX2J5KGF1Y2Rpc3QsIGlicmFfc3VicmVnaW9uLCBkaXN0YW5jZSksCiAgbWVkYXVjID0gbWVkaWFuKEFVQyksCiAgbWVkYXVwcmMgPSBtZWRpYW4oYEFVQy1QUmAgLyBwcmV2YWxlbmNlKSwKICB2YWx1ZSA9IG1lYW4odmFsdWUpCikKCmF1Y2Rpc3RwbG90IDwtIGdncGxvdChhdWNkaXN0KSArCiAgYWVzKEFVQywgdmFsdWUpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAuNSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KGFscGhhPS4xKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyhtZWRhdWMpLCBkYXRhID0gYXVjZGlzdG1lYW4sIHNpemUgPSAyLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIgogICkgKwogIHhsaW0oLjQsIDEpICsKICB5bGFiKCJEaXN0YW5jZSIpICsKICBmYWNldF9ncmlkKC4gfiBkaXN0YW5jZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkKICApCgphdWNidyA8LSBnZ3Bsb3QoYXVjZGlzdCkgKwogIGFlcyh4ID0gRHVtbXksIHkgPSBBVUMpICsKICBnZW9tX2JveHBsb3QoZmlsbCA9ICJncmV5IikgKwogIGZhY2V0X2dyaWQoLiB+IER1bW15KSArCiAgeWxpbSguNCwgMSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gIjAuOTUiKSArCiAgeGxhYigiRHVtbXkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCAgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDUuNSwgMCwgNS41LCA1LjUpCiAgKQoKYXVjcGxvdF9nZyA8LSBnZ3Bsb3QoZmlsdGVyKGF1Y2Rpc3QsIGlicmFfc3VicmVnaW9uID09ICJHcmVhdGVyIEdyYW1waWFucyIpKSArCiAgYWVzKHggPSBBVUMsIHkgPSAxKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gLjUsIGNvbG9yID0gImdyZXkiLCBzaXplID0gMS41KSArCiAgZ2VvbV9wb2ludChhbHBoYT0uMSkgKwogIGdlb21fcG9pbnQoCiAgICBhZXMobWVkYXVjKSwKICAgIGRhdGEgPSBzbGljZShmaWx0ZXIoYXVjZGlzdG1lYW4sIGlicmFfc3VicmVnaW9uID09ICJHcmVhdGVyIEdyYW1waWFucyIpLCAxTCksCiAgICBzaXplID0gMiwgc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIKICApICsKICB4bGltKC40LCAxKSArCiAgeWxhYigiRGlzdGFuY2UiKSArCiAgeGxhYigiQVVST0MiKSArCiAgZmFjZXRfZ3JpZCguIH4gRHVtbXkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oNS41LCAwLCA1LjUsIDUuNSkKICApCgphdXByY2Rpc3RwbG90IDwtIGdncGxvdChhdWNkaXN0KSArCiAgYWVzKGBBVUMtUFJgIC8gcHJldmFsZW5jZSwgdmFsdWUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICB0cmFucyA9ICJsb2cyIiwgYnJlYWtzID0gMl5zZXEoLTEsIDgsIDIpLCBsYWJlbHMgPSAyXnNlcSgtMSwgOCwgMiksCiAgICBsaW1pdHMgPSBjKC41LCAxNzApCiAgKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KGFscGhhPS4xKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyhtZWRhdXByYyksIGRhdGEgPSBhdWNkaXN0bWVhbiwgc2l6ZSA9IDIsIHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiCiAgKSArCiAgeWxhYigiRGlzdGFuY2UiKSArCiAgZmFjZXRfZ3JpZCguIH4gZGlzdGFuY2UsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmF1cHJjYncgPC0gZ2dwbG90KGF1Y2Rpc3QpICsKICBhZXMoeCA9IER1bW15LCB5ID0gYEFVQy1QUmAgLyBwcmV2YWxlbmNlKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzIiLCBsaW1pdHMgPSBjKC41LCAxNzApKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAiZ3JleSIpICsKICBmYWNldF9ncmlkKC4gfiBEdW1teSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gIjAuOTUiKSArCiAgeGxhYigiRHVtbXkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIGF4aXMudGV4dC54ICA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDAsIDUuNSwgNS41KQogICkKCmF1cHJjcGxvdF9nZyA8LSBnZ3Bsb3QoZmlsdGVyKGF1Y2Rpc3QsIGlicmFfc3VicmVnaW9uID09ICJHcmVhdGVyIEdyYW1waWFucyIpKSArCiAgYWVzKHggPSBgQVVDLVBSYCAvIHByZXZhbGVuY2UsIHkgPSAxKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgdHJhbnMgPSAibG9nMiIsIGJyZWFrcyA9IDJec2VxKC0xLCA4LCAyKSwgbGFiZWxzID0gMl5zZXEoLTEsIDgsIDIpLAogICAgbGltaXRzID0gYyguNSwgMTcwKQogICkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsIGNvbG9yID0gImdyZXkiLCBzaXplID0gMS41KSArCiAgZ2VvbV9wb2ludChhbHBoYT0uMSkgKwogIGdlb21fcG9pbnQoCiAgICBhZXMobWVkYXVwcmMpLAogICAgZGF0YSA9CiAgICAgIHNsaWNlKGZpbHRlcihhdWNkaXN0bWVhbiwgaWJyYV9zdWJyZWdpb24gPT0gIkdyZWF0ZXIgR3JhbXBpYW5zIiksIDFMKSwKICAgIHNpemUgPSAyLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIgogICkgKwogIHlsYWIoIkRpc3RhbmNlIikgKwogIHhsYWIoIkFVUFJDIC8gUHJldmFsZW5jZSIpICsKICBmYWNldF9ncmlkKC4gfiBEdW1teSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIGF4aXMudGV4dC54ICA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oNS41LCAwLCA1LjUsIDUuNSkKICApCgpncmlkLmFycmFuZ2UoCiAgYXVjcGxvdF9nZywgYXVjYncsIGF1Y2Rpc3RwbG90LCBhdXByY3Bsb3RfZ2csIGF1cHJjYncsIGF1cHJjZGlzdHBsb3QsCiAgbnJvdyA9IDIsIHdpZHRocyA9IGMoLjEyLCAuMDgsIC44KSwgaGVpZ2h0cyA9IGMoLjQ5LCAuNTEpCikKCiMnICMjIyBCb3hwbG90IHN0YXRpc3RpY3MKIysgYm94cGxvdC1zdGF0cywgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UKYm94cGxvdC5zdGF0cyhhdWNkaXN0JEFVQykKCmJveHBsb3Quc3RhdHMoYXVjZGlzdCRgQVVDLVBSYCAvIGF1Y2Rpc3QkcHJldmFsZW5jZSkKCiMrIHBsb3QtYXVjLWRpc3Qtc2hhcmVkLW9ubHksIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcud2lkdGggPSA3LjUsIGZpZy5oZWlnaHQgPSA0LjUKYXVjZGlzdF9zbyA8LSBmaWx0ZXIoYXVjZGlzdCwgdGF4b24gJWluJSBpbnRlcnNlY3QobWRzJHRheG9uLCBtZGckdGF4b24pKQoKYXVjZGlzdG1lYW5fc28gPC0gc3VtbWFyaXNlKAogIGdyb3VwX2J5KGF1Y2Rpc3Rfc28sIGlicmFfc3VicmVnaW9uLCBkaXN0YW5jZSksCiAgbWVkYXVjID0gbWVkaWFuKEFVQyksCiAgbWVkYXVwcmMgPSBtZWRpYW4oYEFVQy1QUmAgLyBwcmV2YWxlbmNlKSwKICB2YWx1ZSA9IG1lYW4odmFsdWUpCikKCmF1Y2Rpc3RwbG90X3NvIDwtIGdncGxvdChhdWNkaXN0X3NvKSArCiAgYWVzKEFVQywgdmFsdWUpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAuNSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KGFscGhhID0gLjEpICsKICBnZW9tX3BvaW50KAogICAgYWVzKG1lZGF1YyksIGRhdGEgPSBhdWNkaXN0bWVhbl9zbywgc2l6ZSA9IDIsIHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiCiAgKSArCiAgeGxpbSguNCwgMSkgKwogIHlsYWIoIkRpc3RhbmNlIikgKwogIGZhY2V0X2dyaWQoLiB+IGRpc3RhbmNlLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmF1Y2J3X3NvIDwtIGdncGxvdChhdWNkaXN0X3NvKSArCiAgYWVzKHggPSBEdW1teSwgeSA9IEFVQykgKwogIGdlb21fYm94cGxvdChmaWxsID0gImdyZXkiKSArCiAgZmFjZXRfZ3JpZCguIH4gRHVtbXkpICsKICB5bGltKC40LCAxKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSAiMC45NSIpICsKICB4bGFiKCJEdW1teSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ICA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oNS41LCAwLCA1LjUsIDUuNSkKICApCgphdWNwbG90X2dnX3NvIDwtIGdncGxvdChmaWx0ZXIoYXVjZGlzdF9zbywgaWJyYV9zdWJyZWdpb24gPT0gIkdyZWF0ZXIgR3JhbXBpYW5zIikpICsKICBhZXMoeCA9IEFVQywgeSA9IDEpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAuNSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KGFscGhhPS4xKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyhtZWRhdWMpLAogICAgZGF0YSA9IHNsaWNlKGZpbHRlcihhdWNkaXN0bWVhbl9zbywgaWJyYV9zdWJyZWdpb24gPT0gIkdyZWF0ZXIgR3JhbXBpYW5zIiksIDFMKSwKICAgIHNpemUgPSAyLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIgogICkgKwogIHhsaW0oLjQsIDEpICsKICB5bGFiKCJEaXN0YW5jZSIpICsKICB4bGFiKCJBVVJPQyIpICsKICBmYWNldF9ncmlkKC4gfiBEdW1teSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCAgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDAsIDUuNSwgNS41KQogICkKCmF1cHJjZGlzdHBsb3Rfc28gPC0gZ2dwbG90KGF1Y2Rpc3Rfc28pICsKICBhZXMoYEFVQy1QUmAgLyBwcmV2YWxlbmNlLCB2YWx1ZSkgKwogIHNjYWxlX3hfY29udGludW91cygKICAgIHRyYW5zID0gImxvZzIiLCBicmVha3MgPSAyXnNlcSgtMSwgOCwgMiksIGxhYmVscyA9IDJec2VxKC0xLCA4LCAyKSwKICAgIGxpbWl0cyA9IGMoLjUsIDE3MCkKICApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLCBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDEuNSkgKwogIGdlb21fcG9pbnQoYWxwaGE9LjEpICsKICBnZW9tX3BvaW50KAogICAgYWVzKG1lZGF1cHJjKSwgZGF0YSA9IGF1Y2Rpc3RtZWFuX3NvLCBzaXplID0gMiwgc2hhcGUgPSAyMSwgZmlsbCA9ICJ3aGl0ZSIKICApICsKICB5bGFiKCJEaXN0YW5jZSIpICsKICBmYWNldF9ncmlkKC4gfiBkaXN0YW5jZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKYXVwcmNid19zbyA8LSBnZ3Bsb3QoYXVjZGlzdF9zbykgKwogIGFlcyh4ID0gRHVtbXksIHkgPSBgQVVDLVBSYCAvIHByZXZhbGVuY2UpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIsIGxpbWl0cyA9IGMoLjUsIDE3MCkpICsKICBnZW9tX2JveHBsb3QoZmlsbCA9ICJncmV5IikgKwogIGZhY2V0X2dyaWQoLiB+IER1bW15KSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSAiMC45NSIpICsKICB4bGFiKCJEdW1teSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgYXhpcy50ZXh0LnggID0gZWxlbWVudF90ZXh0KGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDUuNSwgMCwgNS41LCA1LjUpCiAgKQoKYXVwcmNwbG90X2dnX3NvIDwtIGdncGxvdChmaWx0ZXIoYXVjZGlzdF9zbywgaWJyYV9zdWJyZWdpb24gPT0gIkdyZWF0ZXIgR3JhbXBpYW5zIikpICsKICBhZXMoeCA9IGBBVUMtUFJgIC8gcHJldmFsZW5jZSwgeSA9IDEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICB0cmFucyA9ICJsb2cyIiwgYnJlYWtzID0gMl5zZXEoLTEsIDgsIDIpLCBsYWJlbHMgPSAyXnNlcSgtMSwgOCwgMiksCiAgICBsaW1pdHMgPSBjKC41LCAxNzApCiAgKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMSwgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KGFscGhhPS4xKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyhtZWRhdXByYyksCiAgICBkYXRhID0KICAgICAgc2xpY2UoZmlsdGVyKGF1Y2Rpc3RtZWFuX3NvLCBpYnJhX3N1YnJlZ2lvbiA9PSAiR3JlYXRlciBHcmFtcGlhbnMiKSwgMUwpLAogICAgc2l6ZSA9IDIsIHNoYXBlID0gMjEsIGZpbGwgPSAid2hpdGUiCiAgKSArCiAgeWxhYigiRGlzdGFuY2UiKSArCiAgeGxhYigiQVVQUkMgLyBQcmV2YWxlbmNlIikgKwogIGZhY2V0X2dyaWQoLiB+IER1bW15KSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgYXhpcy50ZXh0LnggID0gZWxlbWVudF90ZXh0KGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDAsIDUuNSwgNS41KQogICkKCmdyaWQuYXJyYW5nZSgKICBhdWNwbG90X2dnX3NvLCBhdWNid19zbywgYXVjZGlzdHBsb3Rfc28sIGF1cHJjcGxvdF9nZ19zbywgYXVwcmNid19zbywKICBhdXByY2Rpc3RwbG90X3NvLAogIG5yb3cgPSAyLCB3aWR0aHMgPSBjKC4xMiwgLjA4LCAuOCksIGhlaWdodHMgPSBjKC40OSwgLjUxKQopCgojKyBwbG90LWRldi1kaXN0LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gNy41LCBmaWcuaGVpZ2h0ID0gMy41CmRldmRpc3QgPC0gZGF0YS5mcmFtZSgKICBwZXJmW2MoInRheG9uIiwgImlicmFfc3VicmVnaW9uIiwgImRldmlhbmNlX2V4cGxhaW5lZCIpXSwKICBgR2VvZ3JhcGhpYyAoa20pYD0gZGlzdHNbYXMuY2hhcmFjdGVyKHBlcmYkaWJyYV9zdWJyZWdpb24pXSwKICBFbnZpcm9ubWVudGFsID0ga2xkaXN0c1thcy5jaGFyYWN0ZXIocGVyZiRpYnJhX3N1YnJlZ2lvbildLAogIENvbW11bml0eSA9IGNvbW11bml0eV9kaXN0W2FzLmNoYXJhY3RlcihwZXJmJGlicmFfc3VicmVnaW9uKV0sCiAgIkR1bW15IiA9ICJEdW1teSIsCiAgY2hlY2submFtZXMgPSBGQUxTRQopCgpkZXZkaXN0IDwtIGdhdGhlcigKICBkZXZkaXN0LCAiZGlzdGFuY2UiLCAidmFsdWUiLCBgR2VvZ3JhcGhpYyAoa20pYCwgRW52aXJvbm1lbnRhbCwgQ29tbXVuaXR5CikKCmRldmRpc3QgPC0gbmEub21pdChkZXZkaXN0KQoKY29sbmFtZXMoZGV2ZGlzdClbM10gPC0gIkRldmlhbmNlIGV4cGxhaW5lZCIKCmRldmRpc3RtZWFuIDwtIHN1bW1hcmlzZSgKICBncm91cF9ieShkZXZkaXN0LCBpYnJhX3N1YnJlZ2lvbiwgZGlzdGFuY2UpLAogIG1lYW5kZXYgPSBtZWFuKGBEZXZpYW5jZSBleHBsYWluZWRgKSwgdmFsdWUgPSBtZWFuKHZhbHVlKQopCgpkZXZkaXN0cGxvdCA8LSBnZ3Bsb3QoZGV2ZGlzdCkgKwogIGFlcyhgRGV2aWFuY2UgZXhwbGFpbmVkYCwgdmFsdWUpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDEuNSkgKwogIGdlb21fcG9pbnQoYWxwaGE9LjEpICsKICBnZW9tX3BvaW50KAogICAgYWVzKG1lYW5kZXYpLCBkYXRhID0gZGV2ZGlzdG1lYW4sIHNpemUgPSAyLCBzaGFwZSA9IDIxLCBmaWxsID0gIndoaXRlIgogICkgKwogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJhc2luaCIsIGxpbWl0cyA9IGMoLTU2LCAxKSkgKwogIHlsYWIoIkRpc3RhbmNlIikgKwogIGZhY2V0X2dyaWQoLiB+IGRpc3RhbmNlLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkKICApCgpkZXZidyA8LSBnZ3Bsb3QoZGV2ZGlzdCkgKwogIGFlcyh4ID0gRHVtbXksIHkgPSBgRGV2aWFuY2UgZXhwbGFpbmVkYCkgKwogIGdlb21fYm94cGxvdChmaWxsID0gImdyZXkiKSArCiAgZmFjZXRfZ3JpZCguIH4gRHVtbXkpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAiYXNpbmgiLCBsaW1pdHMgPSBjKC01NiwgMSkpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9ICIwLjk1IikgKwogIHhsYWIoIkR1bW15IikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gInRyYW5zcGFyZW50IiksCiAgICBheGlzLnRleHQueCAgPSBlbGVtZW50X3RleHQoY29sb3IgPSAidHJhbnNwYXJlbnQiKSwKICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oNS41LCAwLCA1LjUsIDUuNSkKICApCgpncmlkLmFycmFuZ2UoZGV2YncsIGRldmRpc3RwbG90LCBucm93ID0gMSwgd2lkdGhzID0gYyguMTQsIC44NikpCgojKyBwbG90LWF1YywgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDMuNSwgZmlnLmhlaWdodCA9IDgKZ2dwbG90KAogIHRyYW5zZm9ybSgKICAgIHN1YnNldChwZXJmLCBpYnJhX3N1YnJlZ2lvbiAhPSAiR3JlYXRlciBHcmFtcGlhbnMiICYgIXJhbmRvbV9lZmZlY3QpLAogICAgaWJyYV9zdWJyZWdpb24gPSBmYWN0b3IoCiAgICAgIGlicmFfc3VicmVnaW9uLCBuYW1lcyhzb3J0KHRhcHBseShBVUMsIGlicmFfc3VicmVnaW9uLCBtZWRpYW4pKSkKICAgICkKICApCikgKwphZXMoQVVDKSArIGdlb21faGlzdG9ncmFtKCkgKwpmYWNldF93cmFwKAogIH5pYnJhX3N1YnJlZ2lvbiwgNiwKICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKAogICAgZnVuY3Rpb24oeCkgewogICAgICB4IDwtIGdzdWIoIi0iLCAiLSAiLCB4KQogICAgICB4IDwtIHN0cndyYXAoeCwgd2lkdGggPSAxMywgc2ltcGxpZnkgPSBGQUxTRSkKICAgICAgdmFwcGx5KHgsIHBhc3RlLCBjaGFyYWN0ZXIoMSksIGNvbGxhcHNlID0gIlxuIikKICAgIH0KICApCikgKwp4bGFiKCJBVUMiKSArCnlsYWIoIk5vLiBvZiB0YXhhIikgKwp0aGVtZV9idygpICsKdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQoKIysgcGxvdC1hdWMtcHJldiwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDMuNSwgZmlnLmhlaWdodCA9IDgKZ2dwbG90KAogIHRyYW5zZm9ybSgKICAgIHN1YnNldCgKICAgICAgbGVmdF9qb2luKHBlcmYsIHRheG9uX3JlZ2lvbl9wcmV2YWxlbmNlKSwKICAgICAgaWJyYV9zdWJyZWdpb24gIT0gIkdyZWF0ZXIgR3JhbXBpYW5zIiAmICFyYW5kb21fZWZmZWN0CiAgICApLAogICAgaWJyYV9zdWJyZWdpb24gPSBmYWN0b3IoCiAgICAgIGlicmFfc3VicmVnaW9uLCBuYW1lcyhzb3J0KHRhcHBseShBVUMsIGlicmFfc3VicmVnaW9uLCBtZWRpYW4pKSkKICAgICkKICApCikgKwphZXMocHJldmFsZW5jZSwgQVVDKSArCmdlb21fcG9pbnQoYWxwaGEgPSAuNSkgKwpmYWNldF93cmFwKAogIH5pYnJhX3N1YnJlZ2lvbiwgNiwKICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKAogICAgZnVuY3Rpb24oeCkgewogICAgICB4IDwtIGdzdWIoIi0iLCAiLSAiLCB4KQogICAgICB4IDwtIHN0cndyYXAoeCwgd2lkdGggPSAxMywgc2ltcGxpZnkgPSBGQUxTRSkKICAgICAgdmFwcGx5KHgsIHBhc3RlLCBjaGFyYWN0ZXIoMSksIGNvbGxhcHNlID0gIlxuIikKICAgIH0KICApCikgKwp4bGFiKCJQcmV2YWxlbmNlIikgKwp5bGFiKCJBVUMiKSArCnRoZW1lX2J3KCkgKwp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCgojKyBwbG90LXByZWQtaW5mbywgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDExCmdncGxvdCgKICB0cmFuc2Zvcm0oCiAgICBzdWJzZXQocGVyZiwgaWJyYV9zdWJyZWdpb24gIT0gIkdyZWF0ZXIgR3JhbXBpYW5zIiAmICFyYW5kb21fZWZmZWN0KSwKICAgIGlicmFfc3VicmVnaW9uID0gZmFjdG9yKAogICAgICBpYnJhX3N1YnJlZ2lvbiwKICAgICAgbmFtZXMoc29ydCh0YXBwbHkobWVhbl9wcmVkaWN0aXZlX2luZm8sIGlicmFfc3VicmVnaW9uLCBtZWRpYW4pKSkKICAgICkKICApCikgKwphZXMobWVhbl9wcmVkaWN0aXZlX2luZm8pICsgZ2VvbV9oaXN0b2dyYW0oKSArIGZhY2V0X3dyYXAofmlicmFfc3VicmVnaW9uLCAzKSArCnhsYWIoIk1lYW4gUHJlZGljdGl2ZSBJbmZvcm1hdGlvbiIpICsKeWxhYigiTm8uIG9mIHRheGEiKSArCmdndGl0bGUoCiAgcGFzdGUoCiAgICAiTWVhbiBQcmVkaWN0aXZlIEluZm9ybWF0aW9uIGZvciB0YXhhIHdpdGhpbiBJQlJBIHN1YnJlZ2lvbnMgb2YiLAogICAgIlNvdXRoZWFzdCBBdXN0cmFsaWEiCiAgKQopCgojKyBwbG90LWdyYW1waWFucy10YXhhLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gMTEKZ2dwbG90KAogIHRyYW5zZm9ybSgKICAgIHN1YnNldChwZXJmLCB0YXhvbiAlaW4lIG1kZyR0YXhvbiAmIHJhbmRvbV9lZmZlY3QpLAogICAgdGF4b24gPSBmYWN0b3IoCiAgICAgIHRheG9uLAogICAgICBuYW1lcygKICAgICAgICBzb3J0KAogICAgICAgICAgdGFwcGx5KAogICAgICAgICAgICBBVUNbaWJyYV9zdWJyZWdpb24gPT0gIkdyZWF0ZXIgR3JhbXBpYW5zIl0sCiAgICAgICAgICAgIHRheG9uW2licmFfc3VicmVnaW9uID09ICJHcmVhdGVyIEdyYW1waWFucyJdLAogICAgICAgICAgICBtZWRpYW4KICAgICAgICAgICkKICAgICAgICApCiAgICAgICkKICAgICkKICApCikgKwphZXMoCiAgQVVDLAogIG1lYW5fcHJlZGljdGl2ZV9pbmZvLAogIGNvbCA9IGlmZWxzZSgKICAgIGlicmFfc3VicmVnaW9uID09ICJHcmVhdGVyIEdyYW1waWFucyIsCiAgICAiR3JhbXBpYW5zIiwKICAgICJPdGhlciBSZWdpb24iCiAgKQopICsKZ2VvbV9wb2ludCgpICsKZmFjZXRfd3JhcCh+dGF4b24sIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4oNDApKSArCmxhYnMoY29sID0gTlVMTCkgKwp4bGFiKCJBVUMiKSArCnlsYWIoIk1lYW4gUHJlZGljdGl2ZSBJbmZvcm1hdGlvbiIpICsKZ2d0aXRsZSgKICBwYXN0ZSgKICAgICIiCiAgKQopICsKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgojKyBtb2RlbGF1YywgcmVzdWx0cyA9ICJoaWRlIiwgbWVzc2FnZSA9IEZBTFNFCiNtb2RlbF9hdWMgPC0gc3Rhbl9nbG1lcigKIyAgKEFVQyAtIC4wMDEpIH4gdmFsdWUgKyAoMSB8IGlicmFfc3VicmVnaW9uL3RheG9uKSwKIyAgZmFtaWx5ID0gbWdjdjo6YmV0YXIsCiMgIGl0ZXIgPSAxMDAwLCBjaGFpbnMgPSAzLAojICBkYXRhID0gYXVjZGlzdCwKIyAgc3Vic2V0ID0gaWJyYV9zdWJyZWdpb24gIT0gIkdyZWF0ZXIgR3JhbXBpYW5zIiAmIGRpc3RhbmNlID09ICJHZW9ncmFwaGljIChrbSkiCiMpCgojKyBzdW1tYXJ5X2F1Ywojc3VtbWFyeShtb2RlbF9hdWMsIHJlZ2V4X3BhcnMgPSAiXlteYl0iLCBwcm9icyA9IGMoLjAyNSwgLjk3NSkpCg==