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:
- Fit a model to Grampians data.
- Calculate Performance Metrics:
- Predict probability of occurrence
- Predict within Grampians training set:
- Predict for each species including species random effects.
- Predict for each species without species random effects.
- Predict to the South-east validation set:
- Predict to each IBRA subregion within the South-east:
- Predict for each species common to Grampians and South-east subregion:
- Predict including species random effects.
- Predict without species random effects.
- Predict for each species not found in the Grampians training set.
- For each prediction type (within-sample/out-of-sample, with-re/without-re, and modelled-species/unmodelled-species), bioregion, and species (and their combinations) calculate performance metrics
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==