Unsupervised clustering
of genes by fitness
Most genes correlate in fitness value between conditions. That means,
only some genes have a condition-specific fitness
effect, i.e. increase or decrease fitness of the respective
strain in one substrate or growth regime specifically. This section
investigates specific genes and their functions that show such
differential fitness between conditions. A simple comparison of one
condition versus another will not be helpful as there two many possible
combinations. To identify interesting sets of genes, cluster analysis
can be performed. The first step is to generate a matrix from
reformatted fitness data, and cluster genes by similarity using a
generic clustering algorithm such as
hclust(method = "ward.D")
.
# generate color palette for heatmap
heat_cols <- diverging_hcl(n = 7, h = c(255, 12), c = c(50, 80), l = c(20, 97), power = c(1, 1.3))
# create a matrix from wide fitness data for plotting heatmap
mat_heatmap <- df_fitness_comp %>% ungroup %>%
filter(if_any(.cols = matches(" - [CP]"), ~ !between(., -2, 2))) %>%
select(matches("locus_tag| - [CP]")) %>%
# filter out NA rows, and replace extreme values
drop_na %>% mutate(across(matches(" - [CP]"),
function(x) {y = replace(x, x > 6, 6); replace(y, y < -6, -6)})) %>%
column_to_rownames(var = "locus_tag") %>%
as.matrix
# create cluster for reordering
mat_cluster <- mat_heatmap %>% dist %>% hclust(method = "ward.D2")
mat_heatmap <- mat_heatmap[
order.dendrogram(as.dendrogram(mat_cluster)),
levels(df_fitness_summary$cond_short)
]
The second step is to find the optimal number of clusters for
subdividing the data set. Silhouette analysis can be used for this
purpose. However, the result is not entirely clear, but suggests a
number of 5 to 10 clusters would give good separation. A wrapper for
more or less fully automated silhouette analysis is available in my
Rtools
package (random collection of helper functions).
devtools::install_github("m-jahn/r-tools")
silhouette_result <- Rtools::silhouette_analysis(mat = mat_heatmap, n_clusters = 2:20, n_repeats = 10)
silhouette_result$plot_summary$par.settings = custom.colorblind()
silhouette_result$plot_summary
n_clusters = 7
svg(filename = "../figures/figure_silhouette.svg", width = 4, height = 4)
print(silhouette_result$plot_summary)
dev.off()
png
2

# define a custom set of colors for clusters
custom_colors <- colorRampPalette(custom.colorblind()$superpose.line$col[c(2,3,1,5)])(n_clusters)
# plot heatmap
plot_heatmap <- levelplot(mat_heatmap[ ,rev(colnames(mat_heatmap))],
par.settings = custom.colorblind(),
col.regions = colorRampPalette(heat_cols)(16),
at = seq(-6, 6, 1), aspect = "fill",
xlab = "", ylab = "", scales = list(x = list(draw = FALSE)),
panel = function(x, y, z, ...) {
panel.levelplot(x, y, z, ...)
panel.abline(h = 1:9+0.5, col = "white", lwd = 1.5)
}
)
plot_cluster_dend <- mat_cluster %>% as.dendrogram %>%
set("branches_k_col", custom_colors, k = n_clusters) %>%
set("branches_lwd", 0.5) %>%
as.ggdend %>%
ggplot(labels = FALSE)
gridExtra::grid.arrange(
plot_cluster_dend +
theme(plot.margin = unit(c(0.1, 0.05, -0.26, 0.085),"npc")),
plot_heatmap,
nrow = 2
)

null device
1
Gene similarity, by
cluster
The heat map clusters genes together that show similar expression
over different conditions. Alternatively, we can use dimensionality
reduction to identify clusters of genes that are similar, e.g. through
PCA, NMDS, or
t-SNE.
# set a seed to obtain same pattern for stochastic methods
set.seed(123)
regex_moa <- "mo[aedbg]([A-Z0-9]+)?"
regex_for <- "fd[swho][A-Z0-9]+"
regex_hyd <- "hox[A-Z0-9]+|hyp[A-Z0-9]+"
regex_etc <- "(qcr|cco|cta|cox|cyo|cyd)([A-Z0-9]+)?"
regex_nit <- "na[rsp]([A-Z0-9]+)?|nir([A-Z0-9]+)?|nor([A-Z0-9]+)?|nos([A-Z0-9]+)?"
regex_all <- paste(c(regex_moa, regex_for, regex_hyd, regex_etc, regex_nit), collapse = "|")
# run t-SNE analysis
SNE <- tsne(mat_heatmap %>% dist, max_iter = 500)
sigma summary: Min. : 0.443752156712937 |1st Qu. : 0.631509019280422 |Median : 0.707827611279302 |Mean : 0.768252158651903 |3rd Qu. : 0.880353013632023 |Max. : 1.38975561028632 |
Epoch: Iteration #100 error is: 14.0419952880744
Epoch: Iteration #200 error is: 0.473145722307766
Epoch: Iteration #300 error is: 0.411810046962138
Epoch: Iteration #400 error is: 0.391638658174712
Epoch: Iteration #500 error is: 0.390500309862624
df_tsne <- SNE %>% setNames(c("x", "y")) %>% as_tibble %>%
mutate(locus = rownames(mat_heatmap)) %>%
left_join(enframe(cutreeord(mat_cluster, k = n_clusters), "locus", "cluster")) %>%
rename(locus_tag = locus) %>%
left_join(select(df_fitness_comp, locus_tag, gene_name)) %>%
mutate(
gene_name = stri_extract_first_regex(gene_name, regex_all) %>%
str_replace("mog", "mogA")
)
Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of
tibble 2.0.0.
ℹ Using compatibility `.name_repair`.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
Joining with `by = join_by(locus)`
Joining with `by = join_by(locus_tag)`
plot_tsne <- df_tsne %>%
xyplot(V2 ~ V1, .,
groups = cluster, col = custom_colors,
xlab = "tSNE 1", ylab = "tSNE 2",
par.settings = custom.colorblind(),
labels = .[["gene_name"]], selected = {!is.na(.[["gene_name"]])},
panel = function(x, y, selected, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.repellabels(x, y, selected = selected, cex = 0.65,
draw_box = TRUE, box_fill = grey(0.95, 0.5), ...)
directlabels::panel.superpose.dl(x, y, ...)
}
)
print(plot_tsne)

Functions enriched in
different clusters
Extract cluster number for each gene and perform GO or KEGG
enrichment per cluster. The goal is to identify the most prevalent
biological functions per cluster.
df_cluster <- cutreeord(mat_cluster, k = n_clusters) %>%
enframe(name = "locus_tag", value = "cluster") %>%
arrange(cluster)
We use the functions kegga
for KEGG enrichment analysis
and goana
for GO term enrichment from the
limma
package. Both functions test for over or
under-representation of genes associated with certain pathways or GO
terms. The functions don’t take the strength of differential fitness
into account (DF; the depletion/enrichment over time).
tryCatch(
df_kegg_enrichment <- lapply(1:n_clusters, function(clust) {
filter(df_cluster, cluster == clust) %>% pull(locus_tag) %>%
kegga(species.KEGG = "reh") %>%
mutate(cluster = clust)
}) %>% bind_rows,
error = function(e) print(e)
)
Visualize the pathways that are most enriched for the different gene
clusters.
plot_keggenrich <- df_kegg_enrichment %>%
mutate(
kegg_pathway = tolower(Pathway),
kegg_pathway = str_remove_all(kegg_pathway, ".?biosynthesis| of| metabolism"),
kegg_pathway = str_sub(kegg_pathway, 1, 32)
) %>%
filter(N >= 5, N <= 200) %>%
mutate(log10_p_value = log10(P.DE), .keep = "unused") %>%
filter(log10_p_value < 0) %>%
group_by(cluster) %>%
arrange(log10_p_value) %>%
slice(1:3) %>% rowwise() %>%
mutate(
kegg_pathway = str_remove(kegg_pathway, " - Cupriavidus necator H16"),
kegg_pathway = str_glue("{kegg_pathway} ({cluster})")
) %>% ungroup %>%
xyplot(factor(kegg_pathway, rev(unique(kegg_pathway))) ~ log10_p_value, .,
groups = cluster,
par.settings = custom.colorblind(),
col = custom_colors,
xlab = expression("log"[10]*" p-value"), ylab = "",
panel = function(x, y, labels, ...) {
panel.grid(h = -1, col = grey(0.9))
panel.xyplot(x, y, ...)
}
)
print(plot_keggenrich)

null device
1
Supervised analysis of
energy metabolism
Molybdenum cofactor
biosynthesis
- modAB = molybdenum transporter
- moaACDE = molybdopterin backbone biosynthesis
- moeA = molybdopterin molybdenum transferase
- mobAB = molybdenum cofactor guanylyltransferase,
- mog = molybdopterin biosynthesis protein (role unclear?)
# plot heatmap
df_moco <- df_fitness_summary %>% filter(time == 8, grepl("mo[aedbg]", gene_name)) %>%
filter(!str_detect(gene_name, "moaA2")) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "mo[aedbg]([A-Z0-9]+)?") %>%
str_replace("mog", "mogA")) %>%
mutate(gene_name = factor(gene_name, c("moaA", "moaC", "moaD", "moaE", "moaF",
"modA", "modB", "modC", "mogA", "moeA1", "moeA2", "moeA3", "mobA", "mobB", "mobB2", "mobB3")))
plot_moco_fit <- heatmap_fitness(df_moco)
# plot genomic locations
df_moco <- df_moco %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_moco_g1 <- genome_plot(df_moco, xlim = c(2455.9, 2458.6), title = "chr 1")
plot_moco_g2 <- genome_plot(df_moco, xlim = c(2787.8, 2791.2), title = "chr 1")
print(plot_moco_fit, position = c(0,0.21,1,1.05), more = TRUE)
print(plot_moco_g1, position = c(0.17,-0.1,0.57,0.4), more = TRUE)
print(plot_moco_g2, position = c(0.53,-0.1,0.83,0.4))

Interesting results to double-check:
- Why is moaA essential for nitrate respiration but not formate? Is
there another iso-enzyme for first step of MoCo synthesis?
- mogA, moaA, moaB, moaE, modB, or modC deletion mutants are not
viable in E.coli. Except for moaA, also modA,B,C are not essential for
growth on formate.
- modABC is the 3-subunit membrane transport system; it should be
essential, however one explanation for it not being essential is that
another low-affinity transporter might exist that compensates for the
loss in medium with high Mo-concentration (Xia et al.,
2018). The authors write in the discussion: “Molybdate can be taken
up by the sulfate-transport system in the absence of a functional
high-affinity molybdate-transport system in E. coli and B. japonicum
(Rosentel et al., 1995; Delgado et al., 2006).”
- moeA (molybdenum transferase) is present with 3 isoenzymes. MoeA1
and A2 both seem to be important for fitness as a KO of each one of them
reduces fitness partially but not fully on formate/nitrate.
Formate
dehydrogenase
- fdsABCDG = primary soluble FDH
- fdwAB = secondary soluble FDH
- fdhABCD = primary membrane-bound FDH, 2 copies A1B1… and A2B2…
- fdoGHI = secondary membrane-bound FDH
# plot heatmap
df_fdh <- df_fitness_summary %>% filter(time == 8, grepl("fd[swho]", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "fd[swho][A-Z0-9]+")) %>%
mutate(gene_name = recode(gene_name, `fdhD` = "fdsC", `fdhC` = "fdhC1", `fdhE` = "fdhE1")) %>%
mutate(gene_name = factor(gene_name, c(paste0("fds", c("A", "B", "C", "D", "G", "R")),
"fdwA", "fdwB", paste0("fdh", c("A1", "B1", "C1", "D1", "E1", "A2")), "fdoG")))
plot_fdh_fit <- heatmap_fitness(df_fdh)
# plot genomic locations
df_fdh <- df_fdh %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_fdh_g1 <- genome_plot(df_fdh, xlim = c(677.7, 685.6), title = "chr 1")
plot_fdh_g2 <- genome_plot(df_fdh, xlim = c(3167.9, 3174.9), title = "chr 1")
print(plot_fdh_fit, position = c(0,0.23,1,1.05), more = TRUE)
print(plot_fdh_g1, position = c(0.17,-0.1,0.57,0.4), more = TRUE)
print(plot_fdh_g2, position = c(0.52,-0.1,0.83,0.4))

Hydrogenases
- hoxA = master regulator, 2-component system. HoxA is constantly
active in its non- phosphorylated state below a temperature of 33*C.
Originally, hoxA activity is regulated by the kinase HoxJ (together with
HoxBC, the ‘regulatory’ hydrogenase). This function is inactivated due
to a mutation in hoxJ, Friedrich
& Friedrich, J Bac, 1983, Lenz
et al., JMMB, 2004.
- hoxKGZ = membrane-bound hydrogenase
- hoxMLOQRTV = MBH accessory genes (cofactor incorporation, subunit
assembly, and twin-arginine-dependent membrane translocation - TAT), Schubert et al., Mol
Microbio, 2007, Fritsch et al., J Bac,
2011 Schwartz et
al., J Mol Bio, 2003
- hoxN1, hoxN2 = Nickel/Cobalt transporters. HoxN2 51% identical on AA
level but not functional, Schwartz et al., J Mol
Bio, 2003
- hoxBC = regulatory hydrogenase RH, oxygen-resistant non-energy
generating hydrogen sensor. HoxC is large active-site-containing
subunit, hoxB small subunit HoxB carrying Fe-S clusters
- HoxJ = RH binding signal transducer, histidine protein kinase Löscher et al., Chem
Phys Chem, 2010 Buerstel et al., PNAS,
2016
- hoxFUYH = soluble hydrogenase
- hoxW = soluble hydrogenase (HoxH-specific) C-terminal protease
(maturation)
- hoxI = optional subunit of SH (hoxFUYH); specific reaction site for
NADPH, Burgdorf et
al., J Bac, 2005
- a 4th hydrogenase exist on pHG1, made from 2 subunits
(hofK, hofG, pHG064/065), see Schäfer
et al., 2015.
- these subunits have no effect on fitness (high coverage of 9-11
mutants per gene), and are very lowly expressed (PHG064 n.d., PHG065 low
abundance)
# plot heatmap
df_hyd <- df_fitness_summary %>%
filter(time == 8, grepl("hox", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "hox[A-Z0-9]+")) %>%
ungroup %>% mutate(gene_name = factor(gene_name, paste0("hox", c("K","G","Z","M",
"L","O","Q","R","T","V","A","B","C","J","N","N2","F","U","Y","H","W","I"))))
plot_hyd_fit <- heatmap_fitness(df_hyd)
# plot genomic locations
df_hyd <- df_hyd %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_hyd_g1 <- genome_plot(df_hyd, xlim = c(0, 4.1), title = "pHG1")
plot_hyd_g2 <- genome_plot(df_hyd, xlim = c(15.1, 22.8), title = "pHG1")
plot_hyd_g3 <- genome_plot(df_hyd, xlim = c(79.2, 85.5), title = "pHG1")
print(plot_hyd_fit, position = c(0,0.23,1,1.05), more = TRUE)
print(plot_hyd_g1, position = c(0.15,-0.1,0.39,0.4), more = TRUE)
print(plot_hyd_g2, position = c(0.35,-0.1,0.65,0.4), more = TRUE)
print(plot_hyd_g3, position = c(0.61,-0.1,0.90,0.4))

Hydrogenase
pleiotropy genes (maturation)
- hypA1,B1,F1,C1,D1,E1 = Ni-Fe metallocenter formation proteins for
both MBH and SH. “HypC1, hypD1, and hypE1 are essential for SH and MBH
maturation, while only one intact copy each of hypA, hypB, and hypF is
needed”, Schwartz et
al., J Mol Bio, 2003
- hypA and B
- hypCDEF all form a complex to assemble the Ni-Fe-CO-CN cofactor
- hypX = CO cofactor formation for NiFe-hydrogenase. HypX converts
formyl-THF into water and CO in aerobic conditions, Schulz et al., JACS,
2020
- hypA2,B2,F2 = alternative genes for hypA1,B1,F1, not sufficient
alone for hydrogenase formation
- hypF3,hypC2,hypD2,hypE2,hypA3,hypB3. The physiological function of
these extra hyp genes is unclear
df_hyp <- df_fitness_summary %>% filter(time == 8, grepl("hyp", gene_name)) %>%
# correct names of several hyp genes to make it more systematic
mutate(gene_name = gsub("hypA PHG094", "hypA2 PHG094", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "hyp[A-Z0-9]+") %>%
recode(hypA = "hypA1", hypB = "hypB1", hypC = "hypC1", hypD = "hypD1", hypE = "hypE1")) %>%
ungroup %>% mutate(gene_name = factor(gene_name, paste0("hyp", c("A1","B1","C1","D1","E1",
"F1","X","A2","B2","C2","D2","E2","F2","A3","B3","F3"))))
plot_hyp_fit <- heatmap_fitness(df_hyp)
# plot genomic locations
df_hyp <- df_hyp %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_hyp_g1 <- genome_plot(df_hyp, xlim = c(8.3, 15.6), title = "pHG1")
plot_hyp_g2 <- genome_plot(df_hyp, xlim = c(66.3, 73.5), title = "pHG1")
plot_hyp_g3 <- genome_plot(df_hyp, xlim = c(85.0, 89.7), title = "pHG1")
print(plot_hyp_fit, position = c(0,0.23,1,1.05), more = TRUE)
print(plot_hyp_g1, position = c(0.26,-0.1,0.78,0.4), more = TRUE)

Electron transport
chain
Cytochrome e- transport proteins, cytochrome reductases, and terminal
oxidases.
- quinol oxidases
- cyoA1B1C1D1, … (3 copies) = cytochrome bo3 complex, quinole oxidase,
low O2 affinity
- cydA1B1, … (2 copies) = cytochrome bd complex, quinole oxidase, high
O2 affinity
- cytochrome reductases
- qcrABC (aka petABC,
H16_A3398
, H16_A3397
,
H16_A3396
) = cytochrome bc1 reductase
- cytochrome C e- carriers
- cytochrome c553 according to uniprot:
H16_A3451
,
H16_A0830
, H16_A0846
, H16_B1452
,
H16_A3576
, H16_A1121
, H16_A1120
.
According to String DB, H16_A3576
is in same operon as
thiosulphate oxidation pathway (SoxXYZABCD), where thiosulfate is used
as electron source Zhang et al.,
2020
- terminal cytochrome C oxidases
- coxMNOPQ = bb3 complex, affinity unknown, not essential for growth
or N-fixation in B. japonycum where it was discovered.
- ctaABCDEG = aa3 complex, low O2 affinity
- ccoGNOP = cbb3 complex, high affinity, high similarity to NO3
reductase
- VP2641 (
H16_A1031
) = Membrane spanning protein, RDD
family. PFAM: unknown function, potential transporter? Interacts with
cytochrome c553 and qcrC, cytochrome reductase. It’s depletion
implicates this protein in formate-specific e- transport in the
membrane.
df_etc <- df_fitness_summary %>% filter(time == 8, locus_tag %in% c("H16_A3451", "H16_A0830",
"H16_A0846", "16_B1452", "H16_A3576", "H16_A1121", "H16_A1120", "H16_A1031") |
grepl("qcr|cco|cta|cox[MNOPQ] |cyo|cyd", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "H16_[AB][0-9]+|(qcr|cco|cta|cox|cyo|cyd)([A-Z0-9]+)?") %>%
factor(c(
paste0("cyo", c("A1","A2","A3","B1","B2","B3","C1","C2","D1","D2")),
paste0("cyd", c("A1","B1","B2")), paste0("qcr", c("A","B","C")),
paste0("H16_", c("A3576","A0846","A1120","A1121","A1031","A3451")),
paste0("cox", c("M","N","O","P","Q")), paste0("cta", c("A","B","C","D","E","G")),
paste0("cco", c("G","N","O","P"))
))
)
plot_etc_fit <- heatmap_fitness(df_etc)
# plot genomic locations
df_etc <- df_etc %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_etc_g1 <- genome_plot(df_etc, xlim = c(3675.2, 3679.0), title = "chr 1")
plot_etc_g2 <- genome_plot(df_etc, xlim = c(361.2, 371.2), title = "chr 1")
plot_etc_g3 <- genome_plot(df_etc, xlim = c(2509.5, 2515.2), title = "chr 1")
print(plot_etc_fit, position = c(0,0.17,1,1.05), more = TRUE)
print(plot_etc_g1, position = c(0.1,-0.1,0.31,0.4), more = TRUE)
print(plot_etc_g2, position = c(0.28,-0.1,0.65,0.4), more = TRUE)
print(plot_etc_g3, position = c(0.62,-0.1,0.9,0.4))

Nitrate
respiration
Nitrate reductase (NAR)
Reaction: HNO3- + QH2 –> NO2- + H2O + Q.
Two copies of the nar operon, one on the megaplasmid and one
on chromosome 2. Several other enzymes catalyze similar reactions as
NAR. NAS is cytoplasmic and NADH dependent assimilatory nitrate
reductase Cramm R,
2008. NAP is periplasmic membrane protein complex accepting
QH2, involved in nitrate respiration but probably also dissipation of
excess redox power. Here we just focus on the main NAR enzyme.
df_nar <- df_fitness_summary %>%
filter(time == 8, grepl("na[rsp]", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "na[rsp]([A-Z0-9]+)?") %>%
recode(narG = "narG1", narH = "narH1", narI = "narI1", narL = "narL1", narX = "narX1"))
plot_nar_fit <- heatmap_fitness(df_nar)
# plot genomic locations
df_nar_genes <- df_nar %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_nar_g1 <- genome_plot(df_nar_genes, xlim = c(279.5, 294.5), title = "pHG1")
print(plot_nar_fit, position = c(0,0.26,1,1.05), more = TRUE)
print(plot_nar_g1, position = c(0.2,-0.1,0.85,0.4))

Nitrite reductase (NIR)
Reaction: NO2- + QH2 –> NO + H2O + Q
NIR is a cd1 type copper containing terminal oxidase, homodimer of 2
nirS subunits. The genes for nitrite reductase are assembled in a
cluster (nirS, -C, -F, -D, -G, -H, -J, -N, -E) spanning 8.6 kb on
chromosome 2. The first gene of this cluster, nirS, is the structural
gene encoding cd1 -NIR. The re-maining genes are presumed to be
accessory genes essential for maturation of active nitrite reductase
(?).
df_nir <- df_fitness_summary %>%
filter(time == 8, grepl("nir", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "nir([A-Z0-9]+)?"))
plot_nir_fit <- heatmap_fitness(df_nir)
# plot genomic locations
df_nir_genes <- df_nir %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_nir_g1 <- genome_plot(df_nir_genes, xlim = c(2576.3, 2585.9), title = "chr 2")
print(plot_nir_fit, position = c(0,0.26,1,1.05), more = TRUE)
print(plot_nir_g1, position = c(0.3,-0.1,0.75,0.4))

NO reductase (NOR)
Reaction: NO + QH2 –> N2O + H2O + Q
From Cramm R,
2008: “The catalytic sub-unit (NorB) of all NORs that have been
characterized to date contains one high-spin heme b and a binuclear
catalytic center of a low-spin heme b and a non-heme iron. The best
investigated NORs are heterodimers that contain, in addition to NorB, a
heme c-containing subunit NorC which channels lectrons from the
physiological electron donor cytochrome c to NorB.”
df_nor <- df_fitness_summary %>%
filter(time == 8, grepl("nor", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "nor([A-Z0-9]+)?"))
plot_nor_fit <- heatmap_fitness(df_nor)
# plot genomic locations
df_nor_genes <- df_nor %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_nor_g1 <- genome_plot(df_nor_genes, xlim = c(256.4, 262.1), title = "pHG1")
print(plot_nor_fit, position = c(0,0.25,1,1.05), more = TRUE)
print(plot_nor_g1, position = c(0.3,-0.1,0.75,0.4))

NOS (nitrous oxide) reductase
Reaction: N2O + QH2 –> N2 + H2O + Q
The NOS of R. eutropha H16 has not been investigated on the
biochemical level. Genes for NOS are located adjacent to the nor genes
on pHG1. NosC (PHG253) might be the cyt c that is the e- donor for NOS.
The nosC KO is enriched on formate, i.e. grows better than WT. Is nosC
taking e- away from formate-fed ETC?
df_nos <- df_fitness_summary %>%
filter(time == 8, grepl("nos", gene_name)) %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "nos([A-Z0-9]+)?"))
plot_nos_fit <- heatmap_fitness(df_nos)
# plot genomic locations
df_nos_genes <- df_nos %>% group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop")
plot_nos_g1 <- genome_plot(df_nos_genes, xlim = c(261.1, 271.9), title = "pHG1")
print(plot_nos_fit, position = c(0,0.25,1,1.05), more = TRUE)
print(plot_nos_g1, position = c(0.22,-0.1,0.85,0.4))

The following section simply plots all nitrate respiration modules on
one canvas.
plot_nitrate_all <- bind_rows(df_nar, df_nor, df_nos, df_nir) %>%
mutate(gene_name = factor(gene_name, c(
paste0("nar", c("X1", "L1", "K1", "K2", "G1", "H1", "I1", "X2", "L2", "G2", "H2", "I2", "K3", "K5")),
paste0("nap", c("A", "B", "C", "D")), paste0("nas", c("D", "E")),
paste0("nir", c("S", "C", "F", "D", "J", "N", "E")),
paste0("nor", c("A", "B", "R1", "A2", "B2", "R2")),
paste0("nos", c("L", "Y", "F", "D", "R", "Z", "C", "X"))
))) %>%
heatmap_fitness()
print(plot_nitrate_all, position = c(0,0.23,1,1.05), more = TRUE)
print(plot_nar_g1, position = c(0,-0.1,0.35,0.4), more = TRUE)
print(plot_nir_g1, position = c(0.33,-0.1,0.58,0.4), more = TRUE)
print(plot_nor_g1, position = c(0.56,-0.1,0.72,0.4), more = TRUE)
print(plot_nos_g1, position = c(0.70,-0.1,0.96,0.4), more = TRUE)

Comparison of nitrate
respiration conditions
- we have two different nitrate respiration conditions, continuous and
pulsed
- low depletion of nitrate/nitrite/nitrous respiration mutants
probably due to constant NO3 supply
df_fitness_summary %>%
filter(substrate == "nitrate", time == 8, !is.na(gene_name)) %>%
select(gene_name, condition, norm_gene_fitness_median) %>%
pivot_wider(names_from = condition, values_from = norm_gene_fitness_median) %>%
mutate(
dfit = pulse - continuous,
significant = !between(dfit, quantile(dfit, probs = c(0.003), na.rm = TRUE),
quantile(dfit, probs = c(0.997), na.rm = TRUE))) %>%
# plot
xyplot(continuous ~ pulse, data = ., groups = significant,
labels = .[["gene_name"]],
par.settings = custom.colorblind(), col = custom_colors,
xlim = c(-9, 3), ylim = c(-9, 3),
xlab = "Nitrate respiration (P)", ylab = "Nitrate respiration (C)",
panel = function(x, y, labels, ...) {
panel.grid(h = -1, col = grey(0.9))
panel.abline(a = 0, b = 1, col = grey(0.5), lty = 2, size = 0.8)
panel.abline(a = 4, b = 1, col = grey(0.5), lty = 2, size = 0.8)
panel.abline(a = -4, b = 1, col = grey(0.5), lty = 2, size = 0.8)
panel.xyplot(x, y, ...)
panel.repellabels(x, y, labels, cex = 0.6,
selected = .[["significant"]],
draw_box = TRUE, box_fill = "white", box_line = TRUE, ...)
}
)

Non-hydrogenase genes
important for H2 fitness
Different gene clusters appear based on the fitness pattern in
different conditions. Clusters specific for lithoautotrophic metabolism
are particularly interesting. We can add the cluster IDs to the main
data frame, and investigate fitness. Or simply select genes that show
depletion only for the hydrogen metabolizing condition.
df_fitness_summary <- df_fitness_summary %>%
left_join(by = "locus_tag",
enframe(cutreeord(mat_cluster, k = n_clusters), "locus_tag", "cluster")
)
df_fitness_summary %>%
filter(time == 8, !str_detect(gene_name, "hox|hyp")) %>%
mutate(hyd_essential = case_when(
substrate == "hydrogen" & norm_gene_fitness_median <= -2 ~ TRUE,
substrate != "hydrogen" & norm_gene_fitness_median >= -2 ~ TRUE,
TRUE ~ FALSE
)) %>%
group_by(locus_tag) %>%
filter(sum(hyd_essential) == 9 |
locus_tag %in% c("H16_A0325", "H16_A0326")) %>%
ungroup %>% arrange(locus_tag) %>%
mutate(gene_name = factor(gene_name, unique(gene_name))) %>%
mutate(norm_gene_fitness_median = norm_gene_fitness_median %>%
replace(., . < -6, -6) %>% replace(., . > 6, 6)) %>%
heatmap_fitness

- ptsI + ptsH - according to databases, a clear hit
for a PEP-dependent sugar PTS system. This can’t be true for C.
necator otherwise it would not show the familiar pattern of
depletion on hydrogen and growth benefit on other substrates. This PTS
system must be implicated in hydrogen metabolism, probably a
transporter? The genes downstream of ptsIH do not seem to be affected
(H16_A0327 to H16_A0329).
- hldD (H16_A0804) -
ADP-L-glycero-beta-D-manno-heptose-6-epimerase, involved in LPS sugar
phosphate synthesis. No obvious connection to hydrogen metabolism.
- glnE (H16_A1127) - Bifunctional glutamine
synthetase adenylyltransferase. Involved in the regulation of glutamine
synthetase GlnA. Transfers or removes adenylyl-residues to and from
GlnA, thereby regulating N uptake through GlnA. No obvious connection to
hydrogen metabolism. Only 1 mutant in library.
- H16_A2692 - uncharacterized membrane protein. Is
neutral in all other conditions, just as are all surrounding genes
(H16_A269[0-9]). Small, 141 AA, potential carbonic anhydrase or
transporter?
- bolA (H16_A3419) - Predicted transcriptional
regulator, no known domains or published functions. Only 1 mutant in
library.
- yadG (H16_A3421) Separated by only 1 gene (yadH,
H16_A3420) from the previous hit, shows very specific depletion for
hydrogen. 7-8 mutants quantified, annotated as ABC transporter, ATPase
function. YadH is the permease partner of the 2 subunits, however does
not show depletion. COG process ‘defense’ because it supposedly is
active as anti-drug efflux pump.
- H16_B1603 - ABC-type transporter, ATPase coupled
transmembrane transporter. Strong depletion on hydrogen only. All
surrounding genes are neutral to fitness. Only 1 mutant in library. A
candidate for a CO2/HCO3- transporter? Aligns best with a lot of
different ABC transporters, with spermidine/putrescine transporters best
hits.
CO2
transporter/carbonic anhydrase homologs
All CAs with quantified fitness are neutral during lithoautotrophic
growth (H16_A1192 - cag, H16_B2403 - caa, H16_B2270 -
can2). Only H16_A0169 (can) is strictly essential, no
mutants are available. This is different to the results from Gai et
al., AMB Express, 2014 that found two essential CAs, can
and caa:
“All four purified CAs were capable of performing the interconversion
of CO2 and HCO3– […] Deletion of can affected the growth of R.
eutropha; however the growth defect could be compensated by adding CO2
to the culture. Deletion of caa, encoding an alpha-CA, had the
strongest deleterious influence on cell growth.”.
Also Kusian et
al., J Bac, 2002 report the essentiality of can for
lithoautotrophic growth. Caa fitness was quantified in the
library with 11 mutants, yet does not show any phenotype on any
substrate. The results in Gai et al. are somewhat contradictory, as the
caa completion test in a quadruple-CA mutant had no beneficial
effect on growth.
Altogether, no specific bicarbonate transporters are annotated in
C. necator. However, important bicarbonate (HCO3+) or CO2
transporters known from e.g. cyanobacteria (Synechocystis sp.
PCC 6803) could be used to search for homologous genes in C.
necator. The following CO2/HCO3+ transporters are known in
Synechocystis:
- BicA (sll0834): constitutive high-flux,
low-affinity Na+/HCO3+ symport
- SbtA (slr1512): inducible low-flux, high-affinity
Na+/HCO3+ symport
- BCT1 (cmpABCD operon/slr0040-44): inducible
high-affinity, ATP-dependent uniport
- NDH (nuo operon/): all genes of this operon are
essential in C. necator, no cond. fitness
The first three of these genes were blasted against the genome of
C. necator. The figure shows alignment scores for the top 20
hits.
df_co2_transport_align <- read_tsv("../data/alignments/CO2_transporters.tsv", col_types = cols()) %>%
group_by(target_name) %>%
mutate(rank = seq_along(uniprot))
xyplot(score + -log10(e_value) ~ rank | target_name, df_co2_transport_align,
par.settings = custom.colorblind(), xlim = c(-1, 21),
xlab = "rank", ylab = expression("-log"[10]*" e value, score"),
between = list(x = 0.5, y = 0.5), lwd = 0,
scales = list(alternating = FALSE),
panel = function(x, y, z, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.barplot(x, y, ewidth = 0.5, fill_alpha = 0.7, ...)
panel.key(..., points = FALSE, corner = c(0.97, 0.97))
}
)

BicA and cmpB seem to have some very similar homologs in the C.
necator genome. However, none of these homologs has a clear
phenotype related to hydrogen metabolism.
df_co2_transport_align %>%
filter(rank <= 20) %>%
select(uniprot, target_name, rank) %>%
inner_join(df_fitness_summary, by = "uniprot") %>% ungroup %>%
mutate(norm_gene_fitness_median = norm_gene_fitness_median %>%
replace(., . < -6, -6) %>% replace(., . > 6, 6)) %>%
heatmap_fitness
Warning in inner_join(., df_fitness_summary, by = "uniprot") :
Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 1 of `x` matches multiple rows in `y`.
ℹ Row 100034 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
warning.

Main
conclusions
- MoCo cofactor is important for growth on formate and
nitrate respiration, but not for growth on hydrogen
- Main FDH is S-FDH both in terms of protein abundance, inducibility,
and essentiality
- Alternative S-FDH operon fdw does not play a roll
- Both hydrogenases, S-H and m_H have similar fitness penalty on
hydrogen when KOed
- Hydrogenase genes, but even more so master regulator hoxA and
Hydrogenase pleiotropy (hyp) genes confer fitness advantage when KOed on
all non-loithoautotrophic substrates
- Cytochrome reductase bc1 complex (qcrABC) is particularly important
for growth on formate
- Bc1 complex plays no role on nitrate, therefore no cross talk (while
a bc1 KO mutant was growth-deficient in oxygen-limited growth on nitrate
(Garg et al., 2018).
- Bc1 complex accepts reduced quinols as e- donor, pumps 4 H+ /2 e−
via proton-motive Q cycle (quinol:cyt c oxidoreduction), and releases
reduced cytochrome C e- carriers. Main cytochrome complex for most
substrates including hydrogen
- Cbb3-type cytochrome oxidase (cco operon) also important
for growth on formate, while cta operon (aa3 complex) more
important on fructose and succinate
Growth advantage of
Hydrogenase mutants
Determine mutant
growth rate from competition experiments
The main measurement that was obtained from transposon library
competition experiments is the fold change, and the fitness score as a
summary statistic thereof. The fold change of a mutant sub-population
over time can also be used to calculate the relative growth advantage
over other strains. For such a growth model, the only required input
parameters are the FC, the average population growth rate, and the time
in hours.
\[ FC = (1 - (\mu_{pop} - \mu_{mut}))^{t}
\] Re-arranged to obtain the mutant growth rate.
\[ \mu_{mut} = -(1 - FC^{1/t}) +
\mu_{pop}\]
All input variables are available:
- µ_pop = 0.1 h^-1, known from chemostats
- FC for each mutant/gene from library competition experiments
(‘fitness’ is the normalized log2 FC)
- t = n_gen x (ln 2)/0.1 - number of generations (0, 8, 16) multiplied
with generation time of 6.93 h
We make a generalized function that calculates growth rate (dis-)
advantage.
mutant_mu <- function(fold_change, pop_mu, time, log2_fc = FALSE) {
if (log2_fc) {fold_change = 2^fold_change}
result = -(1 - (fold_change^(1/time))) + pop_mu
return(result)
}
Then select the hydrogenase mutants where an enrichment was observed
in heterotrophic conditions.
df_increased_mu <- df_fitness_summary %>%
filter(
grepl("hox[KGZMLOQRTVABCJNFUYHWI]|hyp[BCDEFX]1? |hypA PHG012", gene_name), condition == "continuous",
substrate %in% c("formate", "fructose", "succinate")) %>%
filter(locus_tag != "PHG063") %>%
mutate(gene_name = stri_extract_first_regex(gene_name, "hox[KGZMLOQRTVABCJNFUYHWI]|hyp[ABCDEFX]")) %>%
mutate(gene_name = fct_inorder(gene_name))
plot_increased_mu <- xyplot(norm_gene_fitness_median ~ time | gene_name, df_increased_mu,
groups = substrate, as.table = TRUE, layout = c(6, 5),
col = stdcol[2:4], xlab = "generations", ylab = "fitness",
par.settings = custom.colorblind(), type = c("l"),
auto.key = list(columns = 3),
between = list(x = 0.5, y = 0.5),
scales = list(alternating = FALSE), lwd = 2,
panel = function(x, y, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.abline(h = 0, col = grey(0.5), lty = 3, lwd = 2)
panel.xyplot(x, y, ...)
}
)
df_mutant_mu <- df_increased_mu %>%
filter(time != 0) %>%
group_by(gene_name, substrate) %>%
mutate(mutant_mu = mutant_mu(
fold_change = norm_gene_fitness_median,
pop_mu = 0.1, time = time*(log(2)/0.1),
log2_fc = TRUE)) %>%
select(locus_tag, time, condition, substrate,
norm_gene_fitness_median, gene_name, cond_short, mutant_mu)
print(plot_increased_mu)

Growth advantage
versus protein cost
The main question is if the observed growth advantage can be purely
explained by the saving of gene expression cost. Hydrogenase and some
accessory proteins are highly abundant and therefore cause a significant
cost to the cell. It was shown in many other studies that reducing
excess/unused proteins can increase growth rate. This is based on the
observation that the protein pool is limited and cells can optimize the
utilization of this limited resource by tuning gene expression towards
highly utilized genes/proteins.
In the next section, global protein abundance data is imported that
was obtained from quantitative MS experiments. MS data is available for
the three conditions used in the previous section, continuous growth on
fructose, succinate, and formate in chemostats at defined growth
rates.
Note: The data is imported directly from the respective
github repository, requiring internet connection.
load(url("https://github.com/m-jahn/R-notebook-ralstonia-proteome/blob/main/data/input/Ralstonia_eutropha.Rdata?raw=true"))
head(Ralstonia_eutropha[1:10])
To assess real protein cost of a knock-out, it is important to
consider that KO by transposon integration will have an effect on the
downstream gene expression too, effectively disrupting
transcription/translation of the entire operon downstream of the
integration site.
If we assume that each KO knocks out the gene expression of all
consecutive genes of the operon, we need to sum up protein cost for
these affected gene sets; we generate a binary matrix
of associations for each KO with a number of affected genes (0 = FALSE,
1 = TRUE), and multiply with protein mass. Here, we need to test
different assumptions. The canonical regulation of the hox/hyp operon
happens via hoxA
transcriptional regulator,
hoxBC
H2 sensing ‘regulatory hydrogenase’ (RH), and
hoxJ
, the defect kinase that transmits the output from
hoxBC
to hoxA?
. This regulation controls two
promoters:
- the P_MBH promoter that starts transcription of the huge
hoxKGZMLOQRTV
+ hypABFCDEX
+
hoxABCJ operon
- the P_SH promoter that starts transcription of the smaller
hoxFUYHWI
+ hypA2B2F2
operon
Accordingly, hoxA
controls its own transcription in a
feed-forward autoregulatory fashion. Increased hoxA
protein
abundance leads to stronger hoxA
expression, etc. However,
if a transposon integrates into any given site of one of the operons,
transcription of following genes should be terminated or otherwise
negatively affected. Surprisingly, this effect is visible for
hyp
mutants that might negatively affect hoxA
expression, but not for any preceding genes
(hoxKHZMLOQRTV
). This suggests that:
- there is another, secondary promoter that controls
hyp
+ hoxABCJN
gene expression
- in fact this has been shown in …
gene_list_mh <- c("hoxK", "hoxG", "hoxZ", "hoxM", "hoxL", "hoxO", "hoxQ", "hoxR", "hoxT", "hoxV")
gene_list_sh <- c("hoxA", "hoxB", "hoxC", "hoxJ", "hoxN", "hoxF", "hoxU", "hoxY", "hoxH", "hoxW", "hoxI")
gene_list_hyp <- c("hypA", "hypB", "hypF", "hypC", "hypD", "hypE", "hypX")
list_mutant_genomic <- list(
hoxK = gene_list_mh,
hoxG = gene_list_mh[2:10],
hoxZ = gene_list_mh[3:10],
hoxM = gene_list_mh[4:10],
hoxL = gene_list_mh[5:10],
hoxO = gene_list_mh[6:10],
hoxQ = gene_list_mh[7:10],
hoxR = gene_list_mh[8:10],
hoxT = gene_list_mh[9:10],
hoxV = gene_list_mh[10],
hypA = c(gene_list_mh, gene_list_hyp, gene_list_sh),
hypB = c(gene_list_mh, gene_list_hyp[2:7], gene_list_sh),
hypF = c(gene_list_mh, gene_list_hyp[3:7], gene_list_sh),
hypC = c(gene_list_mh, gene_list_hyp[4:7], gene_list_sh),
hypD = c(gene_list_mh, gene_list_hyp[5:7], gene_list_sh),
hypE = c(gene_list_mh, gene_list_hyp[6:7], gene_list_sh),
hypX = c(gene_list_mh, gene_list_hyp[7], gene_list_sh),
hoxA = c(gene_list_mh, gene_list_hyp, gene_list_sh),
hoxB = gene_list_sh[2:5],
hoxC = gene_list_sh[3:5],
hoxJ = gene_list_sh[4:5],
hoxN = gene_list_sh[5],
hoxF = gene_list_sh[c(6:11)],
hoxU = gene_list_sh[c(7:11)],
hoxY = gene_list_sh[c(8:11)],
hoxH = gene_list_sh[c(9:11)],
hoxW = gene_list_sh[c(10:11)],
hoxI = gene_list_sh[c(11)]
)
mat_mutant_genomic <- lapply(list_mutant_genomic, function(x) {
as.numeric(names(list_mutant_genomic) %in% x)
}) %>% unlist %>% matrix(ncol = length(list_mutant_genomic), byrow = TRUE) %>% t
rownames(mat_mutant_genomic) <- names(list_mutant_genomic)
colnames(mat_mutant_genomic) <- names(list_mutant_genomic)
- Add individual and accumulated protein cost for each KO mutant.
# add individual protein cost from MS data
df_mutant_cost <- df_mutant_mu %>%
group_by(locus_tag, gene_name, substrate) %>%
summarize(.groups = "drop",
mean_mutant_mu = mean(mutant_mu),
sd_mutant_mu = sd(mutant_mu)) %>%
left_join(by = c("locus_tag", "substrate"),
Ralstonia_eutropha %>% ungroup %>%
filter(growthrate == 0.1) %>%
select(locus_tag, substrate, mean_mass_fraction_norm, sd_massfraction)) %>%
arrange(locus_tag) %>%
tidyr::complete(substrate, nesting(locus_tag, gene_name)) %>%
# add estimated total cost for each knockout
group_by(substrate) %>%
mutate(
corrected_cost = mean_mass_fraction_norm %>% {colSums(na.rm = TRUE, .*100*mat_mutant_genomic)},
corrected_sd = sd_massfraction %>% {colSums(na.rm = TRUE, .*100*mat_mutant_genomic)}
)
- Plot mutant growth rate, individual cost, and total protein cost
that is saved in KO mutants.
plot_mutant_mu <- xyplot(mutant_mu ~ gene_name, df_mutant_mu,
groups = substrate, as.table = TRUE,
col = stdcol[2:4], xlab = "", ylab = expression("estimated µ [h"^-1*"]"),
par.settings = custom.colorblind(), lwd = 2,
scales = list(x = list(rot = 90)),
panel = function(x, y, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.abline(h = 0.1, col = grey(0.5), lty = 3, lwd = 2)
panel.errbars(x, y, beside = TRUE, ...)
}
)
plot_mutant_cost <- xyplot(mean_mass_fraction_norm*100 ~ gene_name, df_mutant_cost,
groups = substrate, par.settings = custom.colorblind(),
error_margin = df_mutant_cost[["sd_massfraction"]]*100,
lwd = 2, col = stdcol[2:4], ylim = c(-0.2, 6.5), pch = 1,
xlab = "", ylab = "reduction protein cost [%]",
scales = list(x = list(rot = 90)),
panel = function(x, y, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.errbars(x, y, beside = TRUE, ...)
panel.key(corner = c(0.98, 0.95), ...)
panel.key(corner = c(0.98, 0.60),
labels = c("individual cost", "total cost (est.)"),
col = grey(0.5), pch = c(1, 19))
}
) + as.layer(
xyplot(corrected_cost ~ gene_name, df_mutant_cost,
groups = substrate,
error_margin = df_mutant_cost[["corrected_sd"]],
lwd = 2, col = stdcol[2:4],
panel = function(x, y, ...) {
panel.errbars(x, y, beside = TRUE, ...)
}
)
)
plot_mbh_operon <- df_increased_mu %>%
filter(time == 8) %>%
group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop") %>%
genome_plot(xlim = c(0.015, 22.490), title = "pHG1", rot_labels = 45)
plot_sh_operon <- df_increased_mu %>%
filter(time == 8) %>%
group_by(locus_tag, gene_name, scaffold, strand, start, end) %>%
summarize(strains_per_gene = min(unique(strains_per_gene)), .groups = "drop") %>%
genome_plot(xlim = c(79.612, 85.438), title = "pHG1", rot_labels = 45)
print(plot_mutant_mu, position = c(-0.017, 0.60, 1, 1), more = TRUE)
print(plot_mutant_cost, position = c(0.02, 0.30, 1, 0.70), more = TRUE)
print(plot_mbh_operon, position = c(0.075, 0.14, 0.97, 0.39), more = TRUE)
print(plot_sh_operon, position = c(0.075, 0, 0.4, 0.25))
grid::grid.text(c("A","B","C"), x = c(0.02, 0.02, 0.02),
y = c(0.98, 0.66, 0.34), gp = grid::gpar(cex = 1.2))

- plot correlation of estimated protein cost and growth rate, per
mutant
- correlation is visible when plotting both parameters separately, but
will it also hold in direct comparison?
plot_cost_vs_mu <- xyplot(mean_mutant_mu ~ corrected_cost | substrate,
df_mutant_cost, groups = substrate,
pointlabels = as.character(df_mutant_cost$gene_name),
par.settings = custom.colorblind(), col = stdcol[2:4],
xlab = "reduction protein cost [%]",
ylab = expression("estimated µ [h"^-1*"]"),
aspect = 1, scales = list(alternating = FALSE),
between = list(x = 0.5, y = 0.5),
panel = function(x, y, pointlabels, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.superpose(x, y, ...)},
panel.groups = function(x, y, ...) {
panel.xyplot(x, y, ...)
panel.lmlineq(x, y, r.squared = TRUE, label = "", ...)
}
)
plot_cost_vs_mu
svg("../figures/figure_mutant_cost_vs_growth.svg", width = 6.5, height = 3.5)
print(plot_cost_vs_mu)
dev.off()
png
2

Prediction of growth
advantage using cell economy model
The constrained Resource Balance Analysis (RBA) model described in Jahn et al., 2021
can be used to make predictions on the effect of hydrogenase knockout on
cell growth rate. The RBA model is a genome scale metabolic model of
R. eutropha that takes protein costs and global protein pool
limitations into account. In constrast to simple FBA (flux balance
analysis), growth rate is ultimately capped by rate limitation of
enzymes and space limitation for enzyme mass within the cell, or the
cytoplasmic membrane. The model was constrained using experimentally
determined steady-state growth rates and protein abundances.
Here, we can ask the question if, and to which degree, growth rate
would increase by expanding the total protein pool size (shrinking
protein cost) by the fraction indicated above (e.g. hoxA KO
freeing up to 4% protein mass). The first step is to import RBA
simulation results.
source(url("https://github.com/m-jahn/R-notebook-ralstonia-proteome/raw/main/pipeline/read_rba_result.R"))
dir_sim <- "../../../Models/Bacterial-RBA-models/Ralstonia-eutropha-H16/simulation/hydrogenase/"
df_flux <- read_rba_result(list.files(dir_sim, pattern = "fluxes_.*.tsv$", full.names = TRUE))
df_prot <- read_rba_result(list.files(dir_sim, pattern = "proteins_.*.tsv", full.names = TRUE))
df_macr <- read_rba_result(list.files(dir_sim, pattern = "macroprocesses_.*.tsv", full.names = TRUE))
The next step is to plot the increase in growth rate as a function of
protein resources that have been saved. The prediction shows smaller
increases than the growth rates estimated from the library data.
- roughly 8% increase in µ for 10% reduction of protein cost
- library data suggest roughly 40% increase for 4-5% reduction of
protein cost
- this is not realistic, most likely an artifact of calculation from
NGS data
plot_cost_predict <- df_macr %>%
mutate(carbon_source = recode(carbon_source,
`for` = "formate", `succ` = "succinate", `fru` = "fructose")) %>%
mutate(sim_run = as.numeric(sim_run)) %>%
arrange(carbon_source, sim_run) %>%
group_by(carbon_source, key) %>%
mutate(reduced_protein_cost = 0:10) %>%
filter(key == "mu") %>%
xyplot(value ~ reduced_protein_cost, .,
groups = carbon_source, aspect = 1,
par.settings = custom.colorblind(),
type = "b", lwd = 2, lty = 2, pch = 1,
ylim = c(0.095, 0.125), col = stdcol[2:4],
xlab = "freed up protein resources [% total]",
ylab = expression("µ [h"^-1*"]"),
panel = function(x, y, z, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.xyplot(x, y, ...)
panel.key(..., cex = 0.7, corner = c(0.96, 0.96))
panel.key(c("data", "model"), lines = TRUE, lty = c(1,2),
pch = c(19, 1), col = grey(0.4),
cex = 0.7, corner = c(0.96, 0.72))
}
)
print(plot_cost_predict)

Growth advantage of
clean, in-frame hydrogenase deletion mutants
- a selection of hydrogenase mutants was grown in bioreactors, batch
mode
- total volume was 50 mL minimal medium supplemented with 2 g/L
fructose + 1 g/L NH4Cl
- aeration: 100 mL/min for all tubes
- temperature 30*C
- OD 720nm was constantly measured every 15 min
- biomass yield was determined by collecting all biomass at the end of
the experiment and determining DCW
df_growth_assay <- read_csv("../data/growth_assays/df_mu_hox.csv", show_col_types = FALSE)
df_dcw_assay <- read_csv("../data/growth_assays/df_dcw_hox.csv", show_col_types = FALSE)
plot_order <- c("WT", "hoxG", "hypB", "hypX", "hoxA", "hoxH")
plot_growth_dcw <- df_dcw_assay %>%
mutate(sample = factor(sample, plot_order)) %>%
xyplot(yield_gDCW_gFRC ~ sample, .,
par.settings = custom.colorblind(),
col = stdcol[3], lwd = 2, ylim = c(-0.0, 0.6),
xlab = "", ylab = expression("yield [g DCW g Frc"^-1*"]"),
scales = list(x = list(rot = 45)),
panel = function(x, y, z, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.xyplot(x, y, pch = 19, cex = 0.5, col = grey(0.6))
panel.barplot(x, y, ...)
panel.pvalue(x, y, offset = 0.12, ...)
}
)
plot_growth_mu <- df_growth_assay %>%
mutate(sample = factor(sample, plot_order)) %>%
xyplot(mu_max ~ sample, .,
par.settings = custom.colorblind(),
col = stdcol[3], lwd = 2, ylim = c(-0.0, 0.39),
xlab = "", ylab = expression("µ [h"^-1*"]"),
scales = list(x = list(rot = 45)),
panel = function(x, y, z, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.xyplot(x, y, pch = 19, cex = 0.5, col = grey(0.6))
panel.barplot(x, y, ...)
panel.pvalue(x, y, offset = 0.08, ...)
}
)
print(plot_growth_dcw, position = c(0, 0, 0.5, 1), more = TRUE)
print(plot_growth_mu, position = c(0.5, 0, 1, 1), more = TRUE)
grid::grid.text(c("A","B"), x = c(0.03, 0.5), y = c(0.94, 0.94), gp = grid::gpar(cex = 1.2))

Hydrogen evolution of
WT and hydrogenase mutant
- an alternative hypothesis to protein cost by hydrogenases is energy
cost
- this hypothesis basically states that the enzymatic action of
hydrogenases “running reverse” catalyzes the formation of H2 from NADH
and protons (as known from cyanobacteria)
- this reaction would drain the reductant pool (NADH(P)H) and lead to
reduced growth
- this reaction plays a role when the terminal electron acceptor,
oxygen or one of the nitrogen oxides, are limiting
- in order to determine if C. necator spills reductant in
heterotrophic conditions through the action of hydrogenases, WT and a
mutant defective in all hydrogenases were cultivated with fructose and
glycerol to induce hydrogenase expression
- without strong limitation of oxygen (which was not present in our
bioreactor experiments), no hydrogen evolution was detectable
- this result strengthens the protein cost hypothesis
df_h2_evolution <- read_csv("../data/growth_assays/h2_evolution.csv", show_col_types = FALSE) %>%
mutate(time = ifelse(time == 20.5, 12.5, time))
plot_h2_evolution <- xyplot(mean ~ time,
filter(df_h2_evolution, gas == "O2"),
groups = strain,
par.settings = custom.colorblind(),
error_margin = filter(df_h2_evolution, gas == "O2")$sd,
lwd = 2, pch = 1,
xlab = "time [h]", ylab = expression("O"[2]*" [%]"),
ylim = c(-2, 22),
scales = list(x = list(at = seq(0, 10, 2))),
panel = function(x, y, ...) {
panel.grid(h = -1, v = 0, col = grey(0.9))
panel.abline(v = seq(0, 10, 2), col = grey(0.9))
panel.xyplot(x, y, type = "l", lty = 2, ...)
panel.errbars(x, y, ewidth = 0, lty = 1, ...)
panel.key(
corner = c(0.9, 0.9),
labels = c("∆hoxGHC,∆hofG", "WT", "O2", "H2"),
col = c("#E7298A", "#66A61E", grey(0.5), grey(0.5)),
pch = c(19, 19, 19, 1)
)
}
) + as.layer(
xyplot(mean/100 ~ time,
filter(df_h2_evolution, gas == "H2"),
groups = strain, pch = 19, lty = 1,
error_margin = filter(df_h2_evolution, gas == "H2")$sd/100,
panel = function(x, y, ...) {
panel.xyplot(x, y, type = "l", ...)
panel.errbars(x, y, ewidth = 0, ...)
}
)
)
print(plot_h2_evolution)

svg("../figures/figure_mutant_mu.svg", width = 7.5, height = 2.85)
print(plot_growth_dcw, position = c(-0.02, -0.034, 0.38, 1), more = TRUE)
print(plot_growth_mu, position = c(0.29, -0.034, 0.69, 1), more = TRUE)
print(plot_h2_evolution, position = c(0.61, 0, 1, 1), more = TRUE)
grid::grid.text(c("D","E", "F"), x = c(0.03, 0.35, 0.65),
y = c(0.94, 0.94, 0.94), gp = grid::gpar(cex = 1.2))
dev.off()
null device
1
Protein cost of
secondary hydrogenases
This figure shows protein cost of the hox/hof genes that were not
included in the protein cost analysis:
- the 4th ‘actinobacterial’ hydrogenase, 1 subunit (hofG, PHG065)
Ralstonia_eutropha %>% ungroup %>%
filter(grepl("PHG065", protein), substrate != "ammonium") %>%
xyplot(mean_mass_fraction_norm*100 ~ factor(growthrate) | protein, .,
groups = substrate, par.settings = custom.colorblind(),
error_margin = .[["sd_massfraction"]]*100,
lwd = 2, col = stdcol[2:4], ylim = c(-0.0005, 0.0045), pch = 19,
xlab = "", ylab = "protein mass fraction [%]",
panel = function(x, y, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.errbars(x, y, beside = TRUE, ...)
panel.key(corner = c(0.02, 0.95), ...)
}
)

Protein cost of ETC
complexes
- as a complimentary information, we can determine the mass fraction
of ETC complexes using MS data
- these are membrane proteins and hence likely underestimated in
comparison to soluble/cytoplasmic proteins
- the reason is the lower efficiency when extracting membrane
proteins
- a relative comparison is nevertheless possible
- should allow us to see the rough order of magnitude of ETC
complexes
plots_etc_mass <- Ralstonia_eutropha %>%
ungroup %>%
select(locus_tag, mean_mass_fraction_norm, growthrate, protein, substrate, sd_massfraction) %>%
inner_join(
select(df_etc, locus_tag, gene_name) %>%
distinct %>%
mutate(gene_name = as.character(gene_name)),
by = join_by(locus_tag)) %>%
filter(substrate != "ammonium", growthrate == 0.1, !is.na(gene_name), !str_detect(gene_name, "H16_")) %>%
mutate(operon = str_sub(gene_name, 1, 3)) %>%
group_by(operon) %>%
group_split() %>%
lapply(function(df) {
xyplot(mean_mass_fraction_norm*100 ~ factor(gene_name) | operon, df,
groups = substrate, par.settings = custom.colorblind(),
error_margin = df$sd_massfraction * 100,
lwd = 2, col = stdcol[2:4], ylim = c(-0.005, 0.085), pch = 19,
between = list(x = 0.5, y = 0.5), as.table = TRUE,
scales = list(alternating = FALSE, x = list(rot = 90)),
xlab = "", ylab = "protein mass fraction [%]",
panel = function(x, y, ...) {
panel.grid(h = -1, v = -1, col = grey(0.9))
panel.errbars(x, y, beside = TRUE, ...)
panel.key(corner = c(0.02, 0.95), ...)
}
)
})
gridExtra::grid.arrange(
ncol = 3, nrow = 2,
plots_etc_mass[[5]],
plots_etc_mass[[4]],
plots_etc_mass[[6]],
plots_etc_mass[[2]],
plots_etc_mass[[3]],
plots_etc_mass[[1]]
)

null device
1
LS0tCnRpdGxlOiBJbnZlc3RpZ2F0aW5nIGVuZXJneSBtZXRhYm9saXNtIGluICpDLiBuZWNhdG9yKiB1c2luZyBhIGJhcmNvZGVkIHRyYW5zcG9zb24KICBsaWJyYXJ5CmF1dGhvcjogIk1pY2hhZWwgSmFobiIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKLS0tCgojIERlc2NyaXB0aW9uCgpUaGlzIFIgbm90ZWJvb2sgaXMgYSBiaW9pbmZvcm1hdGljcyBwaXBlbGluZSB0byBhbmFseXplIGZpdG5lc3MgZGF0YSBvYnRhaW5lZCBmcm9tIGEgYmFyY29kZWQgdHJhbnNwb3NvbiBsaWJyYXJ5IGluICpSYWxzdG9uaWEgZXV0cm9waGEqIGEuay5hLiAqQ3VwcmlhdmlkdXMgbmVjYXRvciouIEZvciBiYWNrZ3JvdW5kIGFuZCBkZXRhaWxzIHJlZ2FyZGluZyB0aGUgbWV0aG9kLCBzZWUgW1dldG1vcmUgYXQgYWwuLCBtQmlvLCAyMDE1XShodHRwczovL21iaW8uYXNtLm9yZy9jb250ZW50LzYvMy9lMDAzMDYtMTUpIGFuZCBbUHJpY2UgZXQgYWwuLCBOYXR1cmUsIDIwMThdKGh0dHA6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDE4LTAxMjQtMCkpLgoKT25lIHBhcnQgb2YgdGhlIGRhdGEgdXNlZCBoZXJlIChncm93dGggb24gKipmcnVjdG9zZSoqLCAqKnN1Y2NpbmF0ZSoqLCAqKmZvcm1hdGUqKikgd2FzIGFscmVhZHkgcHVibGlzaGVkIGluIGEgcHJldmlvdXMgcmVzZWFyY2ggYXJ0aWNsZSB3aXRoIGZvY3VzIG9uICpDLiBuZWNhdG9yKidzIGNlbnRyYWwgY2FyYm9uIG1ldGFib2xpc20uIFRoZSBbcHJlcHJpbnQgaXMgYXZhaWxhYmxlIG9uIEJpb1J4aXZdKGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIxLjAzLjIxLjQzNjMwNHYyKS4gVGhlIHNlY29uZCBwYXJ0IChhdXRvdHJvcGhpYyBncm93dGggb24gKipoeWRyb2dlbioqLCBhbm94aWMgZ3Jvd3RoIHdpdGggKipuaXRyYXRlIHJlc3BpcmF0aW9uKiopIGlzIG5ldyBkYXRhIHRoYXQgY29tcGxlbWVudHMgcHJldmlvdXMgcmVzdWx0cy4gVGhlIGZvY3VzIG9mIHRoaXMgcGlwZWxpbmUgaXMgdG8gc3R1ZHkgdGhlIGVuZXJneSBtZXRhYm9saXNtIG9mICpDLiBuZWNhdG9yKiBpbiBkaXZlcnNlIGNvbmRpdGlvbnMsIGVhY2ggb2YgaXQgY2hhbGxlbmdpbmcgYSBkaWZmZXJlbnQgYXNwZWN0L21hY2hpbmVyeSBvZiBtZXRhYm9saXNtLiBUaGlzIGludmVzdGlnYXRpb24gdHJpZXMgdG8gYW5zd2VyIHRoZSBmb2xsb3dpbmcga2V5IHF1ZXN0aW9uczoKCjEuICBXaGljaCBnZW5lcyBhcmUgY29uc3RpdHV0aW5nIHRoZSBlc3NlbnRpYWwgcGFydHMgb2YgdGhlICoqaHlkcm9nZW5hc2VzIGFuZCBmb3JtYXRlIGRlaHlkcm9nZW5hc2VzKiosIGVuYWJsaW5nIGF1dG90cm9waGljIGxpZmVzdHlsZT8gTWFueSB0aGluZ3MgYWJvdXQgdGhlIHN0cnVjdHVyZSBhbmQgZnVuY3Rpb24gb2YgdGhlc2UgZW56eW1lcyBpcyBhbHJlYWR5IGtub3duLCB3aGVyZSBkbyB0aGVzZSByZXN1bHRzIHNob3cgZGlmZmVyZW5jZXM/CjIuICBXaGljaCBnZW5lcyBhcmUgKiptYW5kYXRvcnkgYXMgYWNjZXNzb3J5IHByb3RlaW5zKiosIGZvciBleGFtcGxlIGNvZmFjdG9yIHN5bnRoZXNpcywgaW5zZXJ0aW9uLCBhbmQgZW56eW1lIG1hdHVyYXRpb24/CjMuICBXaHkgZG9lcyAqKktPIG9mIGh5ZHJvZ2VuYXNlcyBwcm92aWRlcyBhIGdyb3d0aCBiZW5lZml0KiogaW4gbm9uLWF1dG90cm9waGljIGNvbmRpdGlvbnM/CjQuICBXaGF0IGFyZSB0aGUgZXNzZW50aWFsIHBhcnRzIG9mIHRoZSAqKmVsZWN0cm9uIHRyYW5zcG9ydCBjaGFpbioqPyBXaGF0IGNvbXBsZXhlcyBhcmUgdXNlZCBzcGVjaWZpY2FsbHkgZm9yIHNvbWUgZ3Jvd3RoIGNvbmRpdGlvbnM/CjUuICBJcyBlc3NlbnRpYWxpdHkvZml0bmVzcyBjb3JyZWxhdGVkIHdpdGggcHJvdGVpbiBhYnVuZGFuY2U/IElzIHRoZXJlIGEgZG9zYWdlIGVmZmVjdCwgc3VjaCB0aGF0IEtPIG9mIGEgaGlnaCBhYnVuZGFudCBpc28tZW56eW1lIGhhcyBzdHJvbmdlciBmaXRuZXNzIGVmZmVjdCBjb21wYXJlZCB0byBhIGxvdy1hYnVuZGFudD8KCiMgTGlicmFyaWVzCgpPcHRpb25hbGx5IGluc3RhbGwgcmVxdWlyZWQgbGlicmFyaWVzLCBwYXJ0aWN1bGFybHkgY3VzdG9tIHBhY2thZ2VzIGZyb20gZ2l0aHViLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtLWphaG4vbGF0dGljZS10b29scyIpCmBgYAoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeShsYXR0aWNlKQogIGxpYnJhcnkobGF0dGljZUV4dHJhKQogIGxpYnJhcnkobGF0dGljZXRvb2xzKQogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoZm9yY2F0cykKICBsaWJyYXJ5KGRlbmRleHRlbmQpCiAgbGlicmFyeShjb2xvcnNwYWNlKQogIGxpYnJhcnkoc3RyaW5naSkKICBsaWJyYXJ5KHZlZ2FuKQogIGxpYnJhcnkodHNuZSkKICBsaWJyYXJ5KGRpcmVjdGxhYmVscykKICBsaWJyYXJ5KGxpbW1hKQp9KQpgYGAKCiMgRGF0YSBpbXBvcnQgYW5kIHByb2Nlc3NpbmcKCkltcG9ydCB0aGUgbWFpbiBkYXRhIHRhYmxlcyB3aXRoIGdlbmUgZml0bmVzcyBkYXRhIGZvciBhbGwgY29uZGl0aW9ucy4gVGFibGVzIHdlcmUgb2J0YWluZWQgYnkgcHJvY2Vzc2luZyBzZXF1ZW5jaW5nIGRhdGEgd2l0aCBhIGN1c3RvbSBbQmFyU2VxIHBpcGVsaW5lXShodHRwczovL2dpdGh1Yi5jb20vbS1qYWhuL3JlYmFyKS4gVGhlIDMyIGdlbmVyYXRpb24gc2VxdWVuY2luZyBzYW1wbGVzIGFyZSByZW1vdmVkIGR1ZSB0byBsb3cgZGl2ZXJzaXR5LCBsZWFkaW5nIHRvIG92ZXJhbGwgbG93ZXIgYXZlcmFnZSByZWFkIGNvdW50IHBlciBnZW5lLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KbG9hZCgiLi4vZGF0YS9iYXJzZXEvMjAyMDEyMjJfZnJ1X2ZpdG5lc3MuUmRhdGEiKQpkZl9maXRuZXNzX2ZyYyA8LSBmaXRuZXNzX2dlbmUgJT4lIHVuZ3JvdXAgJT4lCiAgZmlsdGVyKGNvbmRpdGlvbiAhPSAibG9uZyBwdWxzZSIsIHRpbWUgIT0gMzIpICU+JQogIG11dGF0ZShJRCA9IGFzLm51bWVyaWMoSUQpLCBzdWJzdHJhdGUgPSAiZnJ1Y3Rvc2UiLAogICAgY29uZGl0aW9uID0gc3RyX3JlbW92ZShjb25kaXRpb24sICJzaG9ydCAiKSkKCmxvYWQoIi4uL2RhdGEvYmFyc2VxLzIwMjEwNDA3X3N1Y19mb3JfZml0bmVzcy5SZGF0YSIpCmRmX2ZpdG5lc3Nfc3VjIDwtIGZpdG5lc3NfZ2VuZSAlPiUgdW5ncm91cCAlPiUKICBzZXBhcmF0ZShjb25kaXRpb24sIHNlcCA9ICJfIiwgaW50byA9IGMoInN1YnN0cmF0ZSIsICJjb25kaXRpb24iKSkKCmxvYWQoIi4uL2RhdGEvYmFyc2VxLzIwMjEwNjI0X0gyX05PM19maXRuZXNzLlJkYXRhIikKZGZfZml0bmVzc19ubzMgPC0gZml0bmVzc19nZW5lICU+JSB1bmdyb3VwICU+JQogIGZpbHRlcihjb25kaXRpb24gJWluJSBjKCJOTzMiKSkgJT4lCiAgbXV0YXRlKHN1YnN0cmF0ZSA9ICJuaXRyYXRlIiwgY29uZGl0aW9uID0gImNvbnRpbnVvdXMiKQoKbG9hZCgiLi4vZGF0YS9iYXJzZXEvMjAyMTA5MjhfSDJfZml0bmVzcy5SZGF0YSIpCmRmX2ZpdG5lc3NfaDIgPC0gZml0bmVzc19nZW5lICU+JSB1bmdyb3VwICU+JQogIG11dGF0ZShzdWJzdHJhdGUgPSAiaHlkcm9nZW4iLCBjb25kaXRpb24gPSAicHVsc2UiKQoKbG9hZCgiLi4vZGF0YS9iYXJzZXEvMjAyMjA0MjBfbG93Q08yX05PMy5SZGF0YSIpCmRmX2ZpdG5lc3NfbG93Y28yIDwtIGZpdG5lc3NfZ2VuZSAlPiUgdW5ncm91cCAlPiUKICBmaWx0ZXIoY29uZGl0aW9uID09ICJOTzNfYmF0Y2giKSAlPiUKICBtdXRhdGUoc3Vic3RyYXRlID0gIm5pdHJhdGUiLCBjb25kaXRpb24gPSAicHVsc2UiKQoKIyBtZXJnZSBmaXRuZXNzIHRhYmxlcwpkZl9maXRuZXNzIDwtIGJpbmRfcm93cyhkZl9maXRuZXNzX2ZyYywgZGZfZml0bmVzc19zdWMsIGRmX2ZpdG5lc3Nfbm8zLAogIGRmX2ZpdG5lc3NfaDIsIGRmX2ZpdG5lc3NfbG93Y28yKSAlPiUKICByZW5hbWUobG9jdXNfdGFnID0gbG9jdXNJZCkKcm0oImRmX2ZpdG5lc3NfZnJjIiwgImRmX2ZpdG5lc3Nfc3VjIiwgImRmX2ZpdG5lc3NfaDIiLCAiZGZfZml0bmVzc19ubzMiLAogICAiZGZfZml0bmVzc19sb3djbzIiLCAiZml0bmVzc19nZW5lIikKCiMgaW1wb3J0IGdlbm9tZSBhbm5vdGF0aW9uCmRmX3JlZiA8LSByZWFkX2NzdigiLi4vZGF0YS9yZWYvUmFsc3RvbmlhX0gxNl9nZW5vbWVfYW5ub3RhdGlvbi5jc3YiLAogIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lCiAgZmlsdGVyKCFkdXBsaWNhdGVkKGxvY3VzX3RhZykpICU+JQogIG11dGF0ZShlZ2dOT0dfbmFtZSA9IGlmX2Vsc2UoaXMubmEoZWdnTk9HX25hbWUpLCBnZW5lX25hbWUsIGVnZ05PR19uYW1lKSkKCiMgZGVmaW5lIHN0YW5kYXJkIGNvbG9ycwpzdGRjb2wgPC0gY3VzdG9tLmNvbG9yYmxpbmQoKSRzdXBlcnBvc2UubGluZSRjb2wKYGBgCgojIEdlbmUgZml0bmVzcyBhbmFseXNpcwoKIyMgRGVwbGV0aW9uIG92ZXIgdGltZSAoZ2VuZXJhdGlvbnMpCgpXZSBjYW4gcGxvdCBsb2cyIEZDIG9yIG5vcm1hbGl6ZWQgZ2VuZSBmaXRuZXNzIG92ZXIgZ2VuZXJhdGlvbnMuIEZvciB0aGlzIHR5cGUgb2Ygb3ZlcnZpZXcgaXQgaXMgYmVzdCB0byBzdW1tYXJpemUgaW5kaXZpZHVhbCByZXBsaWNhdGVzICg0eCkgdG8gdGhlIG1lYW4gb3IgbWVkaWFuLCBwZXIgdGltZSBwb2ludCBhbmQgY29uZGl0aW9uLiBXZSBhbHNvIGFkZCBnZW5vbWUgYW5ub3RhdGlvbiB0byB0aGUgc3VtbWFyeSB0YWJsZS4gVGhlIHBsb3RzIHNob3dzIHRoYXQgZGVwbGV0aW9uIG9mIHNvbWUgc3RyYWlucyBpcyBzbyBzdHJvbmcgYWxyZWFkeSBhdCA4IGdlbmVyYXRpb25zIHRoYXQgZml0bmVzcy9sb2cyIEZDIGNvdWxkIG5vdCBiZSBxdWFudGlmaWVkIGZvciAxNiBnZW5lcmF0aW9ucyBkdWUgdG8gbWlzc2luZyByZWFkIGNvdW50cy4gSXQgaXMgYmVzdCB0byBmb2N1cyBvbiA4IGdlbmVyYXRpb25zIGFzIGJlY2F1c2UgaXQgcHJvdmlkZXMgYSBtb3JlIGNvbXBsZXRlIHBpY3R1cmUuCgpgYGB7ciwgbWVzc2FnZXMgPSBGQUxTRX0KbmVzdF9jb2xzID0gYygidGltZSIsICJjb25kaXRpb24iLCAic3Vic3RyYXRlIikKZGZfcmVmX2xvbmcgPC0gYmluZF9yb3dzKGRmX3JlZiwgZGlzdGluY3QoZGZfZml0bmVzcyAlPiUgc2VsZWN0KCEhIW5lc3RfY29scykpKSAlPiUKICBjb21wbGV0ZShsb2N1c190YWcsIG5lc3RpbmcoISEhbGFwcGx5KG5lc3RfY29scywgc3ltKSkpICU+JQogIGZpbHRlcighaXMubmEodGltZSkpICU+JSBzZWxlY3QobG9jdXNfdGFnLCAhISFuZXN0X2NvbHMpICU+JQogIGxlZnRfam9pbihkZl9yZWYsIGJ5ID0gImxvY3VzX3RhZyIpCgpkZl9maXRuZXNzX3N1bW1hcnkgPC0gZGZfZml0bmVzcyAlPiUKICBncm91cF9ieShsb2N1c190YWcsIHNjYWZmb2xkLCB0aW1lLCBjb25kaXRpb24sIHN1YnN0cmF0ZSwgc3RyYWluc19wZXJfZ2VuZSkgJT4lCiAgc3VtbWFyaXplKAogICAgLmdyb3VwcyA9ICJkcm9wIiwKICAgIG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiA9IG1lZGlhbihub3JtX2dlbmVfZml0bmVzcywgbmEucm0gPSBUUlVFKSwKICAgIGxvZzJGQ19tZWRpYW4gPSBtZWRpYW4obG9nMkZDLCBuYS5ybSA9IFRSVUUpLAogICAgdHN0YXRfbWVkaWFuID0gbWVkaWFuKHQsIG5hLnJtID0gVFJVRSkKICApICU+JQogIGZ1bGxfam9pbihkZl9yZWZfbG9uZykgJT4lCiAgbXV0YXRlKGNvbmRfc2hvcnQgPSBpZl9lbHNlKGNvbmRpdGlvbiA9PSAicHVsc2UiLCAiUCIsICJDIikpICU+JQogIG11dGF0ZShjb25kX3Nob3J0ID0gcGFzdGUwKHN1YnN0cmF0ZSwgIiAtICIsIGNvbmRfc2hvcnQpICU+JQogICAgZmFjdG9yKGxldmVscyA9IHBhc3RlMCgKICAgICAgcmVwKGMoImZydWN0b3NlIiwgInN1Y2NpbmF0ZSIsICJmb3JtYXRlIiwgImh5ZHJvZ2VuIiwgIm5pdHJhdGUiKSwgZWFjaCA9IDIpLAogICAgICByZXAoYygiIC0gUCIsICIgLSBDIiksIDUpCiAgICApWy04XSkKICApCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDYuNSwgZmlnLmhlaWdodCA9IDh9CnBsb3RfaGlzdF9sb2cyRkMgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbiwgc3Vic3RyYXRlKSAlPiUKICBzbGljZSgxOjEwMDApICU+JQogIAogIHh5cGxvdChsb2cyRkNfbWVkaWFuIH4gdGltZSB8IHN1YnN0cmF0ZSAqIGNvbmRpdGlvbiwgLiwKICAgIGdyb3VwcyA9IGxvY3VzX3RhZywgYXMudGFibGUgPSBUUlVFLAogICAgY29sID0gc3RkY29sWzFdLCBhbHBoYSA9IDAuMiwgbGF5b3V0ID0gYyg1LCAyKSwKICAgIHhsYWIgPSAiIiwgeWxhYiA9IGV4cHJlc3Npb24oImxvZyJbMl0qIiBGQyIpLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgdHlwZSA9IGMoImwiKSwKICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLAogICAgc2NhbGVzID0gbGlzdChhbHRlcm5hdGluZyA9IEZBTFNFKSwgbHdkID0gMiwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIC4uLikKICAgIH0KICApCgpwbG90X2hpc3Rfbm9ybWZnIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBncm91cF9ieShjb25kaXRpb24sIHN1YnN0cmF0ZSkgJT4lCiAgc2xpY2UoMToxMDAwKSAlPiUKICAKICB4eXBsb3Qobm9ybV9nZW5lX2ZpdG5lc3NfbWVkaWFuIH4gdGltZSB8IHN1YnN0cmF0ZSAqIGNvbmRpdGlvbiwgLiwKICAgIGdyb3VwcyA9IGxvY3VzX3RhZywgYXMudGFibGUgPSBUUlVFLAogICAgY29sID0gc3RkY29sWzJdLCBhbHBoYSA9IDAuMiwgbGF5b3V0ID0gYyg1LCAyKSwKICAgIHhsYWIgPSAiZ2VuZXJhdGlvbnMiLCB5bGFiID0gImZpdG5lc3MiLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgdHlwZSA9IGMoImwiKSwKICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLAogICAgc2NhbGVzID0gbGlzdChhbHRlcm5hdGluZyA9IEZBTFNFKSwgbHdkID0gMiwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIC4uLikKICAgIH0KICApCgpwcmludChwbG90X2hpc3RfbG9nMkZDLCBwb3NpdGlvbiA9IGMoMCwwLjQ3LDEsMSksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2hpc3Rfbm9ybWZnLCBwb3NpdGlvbiA9IGMoMCwwLDEsMC41MykpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KcG5nKCIuLi9maWd1cmVzL2ZpZ3VyZV9kZXBsZXRpb25fb3Zlcl90aW1lLnBuZyIsIHdpZHRoID0gOTAwLCBoZWlnaHQgPSAxMjAwLCByZXMgPSAxNTApCnByaW50KHBsb3RfaGlzdF9sb2cyRkMsIHBvc2l0aW9uID0gYygwLDAuNDcsMSwxKSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfaGlzdF9ub3JtZmcsIHBvc2l0aW9uID0gYygwLDAsMSwwLjUzKSkKZGV2Lm9mZigpCmBgYAoKIyMgQ29tcGFyaW5nIGdlbmUgZml0bmVzcyBiZXR3ZWVuIGNvbmRpdGlvbnMKClNpbWlsYXJseSB0byBGaWd1cmUgMiBpbiBbV2V0bW9yZSBldCBhbCwgbUJJTywgMjAxNV0oaHR0cHM6Ly9tYmlvLmFzbS5vcmcvY29udGVudC82LzMvZTAwMzA2LTE1KSwgd2UgY2FuIGludmVzdGlnYXRlIGNvbmRpdGlvbi1kZXBlbmRlbnQgZ2VuZSBmaXRuZXNzIGJ5IGNvbXBhcmluZyBjb25kaXRpb25zIGFuZCBzdWJzdHJhdGVzIG9uZS1vbi1vbmUuIFRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHN1YnN0cmF0ZXMgYW5kIGdyb3d0aCByZWdpbWVzIChjb250aW51b3VzLCBwdWxzZWQpIGlzIHF1aXRlIGRpZmZlcmVudC4gVGhlIHN0cm9uZ2VzdCBjb3JyZWxhdGlvbiBpcyBwcmVzZW50IGluIHRoZSBwdWxzZWQgdnMgY29udGludW91cyByZWdpbWUgZm9yIGVhY2ggc3Vic3RyYXRlIChSID0gMC42NCB0byAwLjg3KSwgYW5kIHdpdGhpbiB0aGUgcHVsc2VkIGNvbmRpdGlvbnMgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBzdWJzdHJhdGVzIChSID0gMC42MiB0byAwLjcyKS4KCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgbWVzc2FnZSA9IEZBTFNFfQpkZl9maXRuZXNzX2NvbXAgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JSBmaWx0ZXIodGltZSA9PSA4KSAlPiUKICBncm91cF9ieShsb2N1c190YWcpICU+JSBtdXRhdGUodHN0YXRfbWVkaWFuID0gbWluKHRzdGF0X21lZGlhbikpICU+JQogIHNlbGVjdChsb2N1c190YWcsIGNvbmRfc2hvcnQsIG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiwgZ2VuZV9uYW1lLCBDT0dfUHJvY2VzcywgdHN0YXRfbWVkaWFuKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY29uZF9zaG9ydCwgdmFsdWVzX2Zyb20gPSBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4pICU+JQogIGZpbHRlcighaXMubmEobG9jdXNfdGFnKSkgJT4lIHVuZ3JvdXAKCmN1c3RvbV9zcGxvbShkZl9maXRuZXNzX2NvbXAgJT4lCiAgc2VsZWN0KG1hdGNoZXMoIiAtIFtDUF0iKSksIHBjaCA9IDE5LCBjZXggPSAwLjMsIGNvbCA9IGdyZXkoMC40LCAwLjQpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnBuZygiLi4vZmlndXJlcy9maWd1cmVfc3Bsb21fYWxsX2NvbmRpdGlvbnMucG5nIiwgd2lkdGggPSAxMjAwLCBoZWlnaHQgPSAxMjAwLCByZXMgPSAxNTApCmN1c3RvbV9zcGxvbShkZl9maXRuZXNzX2NvbXAgJT4lCiAgc2VsZWN0KG1hdGNoZXMoIiAtIFtDUF0iKSksIHBjaCA9IDE5LCBjZXggPSAwLjMsIGNvbCA9IGdyZXkoMC40LCAwLjQpKSAlPiUgcHJpbnQKZGV2Lm9mZigpCmBgYAoKIyBVbnN1cGVydmlzZWQgY2x1c3RlcmluZyBvZiBnZW5lcyBieSBmaXRuZXNzCgpNb3N0IGdlbmVzIGNvcnJlbGF0ZSBpbiBmaXRuZXNzIHZhbHVlIGJldHdlZW4gY29uZGl0aW9ucy4gVGhhdCBtZWFucywgb25seSBzb21lIGdlbmVzIGhhdmUgYSAqKmNvbmRpdGlvbi1zcGVjaWZpYyBmaXRuZXNzIGVmZmVjdCoqLCBpLmUuIGluY3JlYXNlIG9yIGRlY3JlYXNlIGZpdG5lc3Mgb2YgdGhlIHJlc3BlY3RpdmUgc3RyYWluIGluIG9uZSBzdWJzdHJhdGUgb3IgZ3Jvd3RoIHJlZ2ltZSBzcGVjaWZpY2FsbHkuIFRoaXMgc2VjdGlvbiBpbnZlc3RpZ2F0ZXMgc3BlY2lmaWMgZ2VuZXMgYW5kIHRoZWlyIGZ1bmN0aW9ucyB0aGF0IHNob3cgc3VjaCBkaWZmZXJlbnRpYWwgZml0bmVzcyBiZXR3ZWVuIGNvbmRpdGlvbnMuIEEgc2ltcGxlIGNvbXBhcmlzb24gb2Ygb25lIGNvbmRpdGlvbiB2ZXJzdXMgYW5vdGhlciB3aWxsIG5vdCBiZSBoZWxwZnVsIGFzIHRoZXJlIHR3byBtYW55IHBvc3NpYmxlIGNvbWJpbmF0aW9ucy4gVG8gaWRlbnRpZnkgaW50ZXJlc3Rpbmcgc2V0cyBvZiBnZW5lcywgY2x1c3RlciBhbmFseXNpcyBjYW4gYmUgcGVyZm9ybWVkLiBUaGUgZmlyc3Qgc3RlcCBpcyB0byBnZW5lcmF0ZSBhIG1hdHJpeCBmcm9tIHJlZm9ybWF0dGVkIGZpdG5lc3MgZGF0YSwgYW5kIGNsdXN0ZXIgZ2VuZXMgYnkgc2ltaWxhcml0eSB1c2luZyBhIGdlbmVyaWMgY2x1c3RlcmluZyBhbGdvcml0aG0gc3VjaCBhcyBgaGNsdXN0KG1ldGhvZCA9ICJ3YXJkLkQiKWAuCgpgYGB7cn0KIyBnZW5lcmF0ZSBjb2xvciBwYWxldHRlIGZvciBoZWF0bWFwCmhlYXRfY29scyA8LSBkaXZlcmdpbmdfaGNsKG4gPSA3LCBoID0gYygyNTUsIDEyKSwgYyA9IGMoNTAsIDgwKSwgbCA9IGMoMjAsIDk3KSwgcG93ZXIgPSBjKDEsIDEuMykpCgojIGNyZWF0ZSBhIG1hdHJpeCBmcm9tIHdpZGUgZml0bmVzcyBkYXRhIGZvciBwbG90dGluZyBoZWF0bWFwCm1hdF9oZWF0bWFwIDwtIGRmX2ZpdG5lc3NfY29tcCAlPiUgdW5ncm91cCAlPiUKICBmaWx0ZXIoaWZfYW55KC5jb2xzID0gbWF0Y2hlcygiIC0gW0NQXSIpLCB+ICFiZXR3ZWVuKC4sIC0yLCAyKSkpICU+JQogIHNlbGVjdChtYXRjaGVzKCJsb2N1c190YWd8IC0gW0NQXSIpKSAlPiUKICAjIGZpbHRlciBvdXQgTkEgcm93cywgYW5kIHJlcGxhY2UgZXh0cmVtZSB2YWx1ZXMKICBkcm9wX25hICU+JSBtdXRhdGUoYWNyb3NzKG1hdGNoZXMoIiAtIFtDUF0iKSwgCiAgICBmdW5jdGlvbih4KSB7eSA9IHJlcGxhY2UoeCwgeCA+IDYsIDYpOyByZXBsYWNlKHksIHkgPCAtNiwgLTYpfSkpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAibG9jdXNfdGFnIikgJT4lCiAgYXMubWF0cml4CgojIGNyZWF0ZSBjbHVzdGVyIGZvciByZW9yZGVyaW5nCm1hdF9jbHVzdGVyIDwtIG1hdF9oZWF0bWFwICU+JSBkaXN0ICU+JSBoY2x1c3QobWV0aG9kID0gIndhcmQuRDIiKQptYXRfaGVhdG1hcCA8LSBtYXRfaGVhdG1hcFsKICBvcmRlci5kZW5kcm9ncmFtKGFzLmRlbmRyb2dyYW0obWF0X2NsdXN0ZXIpKSwKICBsZXZlbHMoZGZfZml0bmVzc19zdW1tYXJ5JGNvbmRfc2hvcnQpCl0KYGBgCgpUaGUgc2Vjb25kIHN0ZXAgaXMgdG8gZmluZCB0aGUgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMgZm9yIHN1YmRpdmlkaW5nIHRoZSBkYXRhIHNldC4gU2lsaG91ZXR0ZSBhbmFseXNpcyBjYW4gYmUgdXNlZCBmb3IgdGhpcyBwdXJwb3NlLiBIb3dldmVyLCB0aGUgcmVzdWx0IGlzIG5vdCBlbnRpcmVseSBjbGVhciwgYnV0IHN1Z2dlc3RzIGEgbnVtYmVyIG9mIDUgdG8gMTAgY2x1c3RlcnMgd291bGQgZ2l2ZSBnb29kIHNlcGFyYXRpb24uIEEgd3JhcHBlciBmb3IgbW9yZSBvciBsZXNzIGZ1bGx5IGF1dG9tYXRlZCBzaWxob3VldHRlIGFuYWx5c2lzIGlzIGF2YWlsYWJsZSBpbiBteSBgUnRvb2xzYCBwYWNrYWdlIChyYW5kb20gY29sbGVjdGlvbiBvZiBoZWxwZXIgZnVuY3Rpb25zKS4KCmBgYHtyLCBldmFsID0gRkFMU0V9CmRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibS1qYWhuL3ItdG9vbHMiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0Kc2lsaG91ZXR0ZV9yZXN1bHQgPC0gUnRvb2xzOjpzaWxob3VldHRlX2FuYWx5c2lzKG1hdCA9IG1hdF9oZWF0bWFwLCBuX2NsdXN0ZXJzID0gMjoyMCwgbl9yZXBlYXRzID0gMTApCnNpbGhvdWV0dGVfcmVzdWx0JHBsb3Rfc3VtbWFyeSRwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpCnNpbGhvdWV0dGVfcmVzdWx0JHBsb3Rfc3VtbWFyeQpuX2NsdXN0ZXJzID0gNwoKc3ZnKGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvZmlndXJlX3NpbGhvdWV0dGUuc3ZnIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwcmludChzaWxob3VldHRlX3Jlc3VsdCRwbG90X3N1bW1hcnkpCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDQuMCwgd2FybmluZyA9IEZBTFNFfQojIGRlZmluZSBhIGN1c3RvbSBzZXQgb2YgY29sb3JzIGZvciBjbHVzdGVycwpjdXN0b21fY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoY3VzdG9tLmNvbG9yYmxpbmQoKSRzdXBlcnBvc2UubGluZSRjb2xbYygyLDMsMSw1KV0pKG5fY2x1c3RlcnMpCgojIHBsb3QgaGVhdG1hcApwbG90X2hlYXRtYXAgPC0gbGV2ZWxwbG90KG1hdF9oZWF0bWFwWyAscmV2KGNvbG5hbWVzKG1hdF9oZWF0bWFwKSldLAogIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgY29sLnJlZ2lvbnMgPSBjb2xvclJhbXBQYWxldHRlKGhlYXRfY29scykoMTYpLAogIGF0ID0gc2VxKC02LCA2LCAxKSwgYXNwZWN0ID0gImZpbGwiLAogIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCBzY2FsZXMgPSBsaXN0KHggPSBsaXN0KGRyYXcgPSBGQUxTRSkpLAogIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgeiwgLi4uKSB7CiAgICBwYW5lbC5sZXZlbHBsb3QoeCwgeSwgeiwgLi4uKQogICAgcGFuZWwuYWJsaW5lKGggPSAxOjkrMC41LCBjb2wgPSAid2hpdGUiLCBsd2QgPSAxLjUpCiAgfQopCgpwbG90X2NsdXN0ZXJfZGVuZCA8LSBtYXRfY2x1c3RlciAlPiUgYXMuZGVuZHJvZ3JhbSAlPiUKICBzZXQoImJyYW5jaGVzX2tfY29sIiwgY3VzdG9tX2NvbG9ycywgayA9IG5fY2x1c3RlcnMpICU+JQogIHNldCgiYnJhbmNoZXNfbHdkIiwgMC41KSAlPiUKICBhcy5nZ2RlbmQgJT4lCiAgZ2dwbG90KGxhYmVscyA9IEZBTFNFKQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoCiAgcGxvdF9jbHVzdGVyX2RlbmQgKyAKICAgIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAuMSwgMC4wNSwgLTAuMjYsIDAuMDg1KSwibnBjIikpLAogIHBsb3RfaGVhdG1hcCwKICBucm93ID0gMgopCmBgYAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gMy41fQpzdmcoIi4uL2ZpZ3VyZXMvZmlndXJlX2hlYXRtYXAuc3ZnIiwgd2lkdGggPSA4LCBoZWlnaHQgPSAzLjUpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKAogIHBsb3RfY2x1c3Rlcl9kZW5kICsgCiAgICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjEyLCAwLjA3NSwgLTAuMjksIDAuMTE3KSwibnBjIikpLAogIHBsb3RfaGVhdG1hcCwKICBucm93ID0gMgopCmRldi5vZmYoKQpgYGAKCiMjIEdlbmUgc2ltaWxhcml0eSwgYnkgY2x1c3RlcgoKVGhlIGhlYXQgbWFwIGNsdXN0ZXJzIGdlbmVzIHRvZ2V0aGVyIHRoYXQgc2hvdyBzaW1pbGFyIGV4cHJlc3Npb24gb3ZlciBkaWZmZXJlbnQgY29uZGl0aW9ucy4gQWx0ZXJuYXRpdmVseSwgd2UgY2FuIHVzZSBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gdG8gaWRlbnRpZnkgY2x1c3RlcnMgb2YgZ2VuZXMgdGhhdCBhcmUgc2ltaWxhciwgZS5nLiB0aHJvdWdoICoqUENBKiosICoqTk1EUyoqLCBvciAqKnQtU05FKiouCgpgYGB7ciwgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDV9CiMgc2V0IGEgc2VlZCB0byBvYnRhaW4gc2FtZSBwYXR0ZXJuIGZvciBzdG9jaGFzdGljIG1ldGhvZHMKc2V0LnNlZWQoMTIzKQpyZWdleF9tb2EgPC0gIm1vW2FlZGJnXShbQS1aMC05XSspPyIKcmVnZXhfZm9yIDwtICJmZFtzd2hvXVtBLVowLTldKyIKcmVnZXhfaHlkIDwtICJob3hbQS1aMC05XSt8aHlwW0EtWjAtOV0rIgpyZWdleF9ldGMgPC0gIihxY3J8Y2NvfGN0YXxjb3h8Y3lvfGN5ZCkoW0EtWjAtOV0rKT8iCnJlZ2V4X25pdCA8LSAibmFbcnNwXShbQS1aMC05XSspP3xuaXIoW0EtWjAtOV0rKT98bm9yKFtBLVowLTldKyk/fG5vcyhbQS1aMC05XSspPyIKcmVnZXhfYWxsIDwtIHBhc3RlKGMocmVnZXhfbW9hLCByZWdleF9mb3IsIHJlZ2V4X2h5ZCwgcmVnZXhfZXRjLCByZWdleF9uaXQpLCBjb2xsYXBzZSA9ICJ8IikKCiMgcnVuIHQtU05FIGFuYWx5c2lzClNORSA8LSB0c25lKG1hdF9oZWF0bWFwICU+JSBkaXN0LCBtYXhfaXRlciA9IDUwMCkKZGZfdHNuZSA8LSBTTkUgJT4lIHNldE5hbWVzKGMoIngiLCAieSIpKSAlPiUgYXNfdGliYmxlICU+JQogIG11dGF0ZShsb2N1cyA9IHJvd25hbWVzKG1hdF9oZWF0bWFwKSkgJT4lCiAgbGVmdF9qb2luKGVuZnJhbWUoY3V0cmVlb3JkKG1hdF9jbHVzdGVyLCBrID0gbl9jbHVzdGVycyksICJsb2N1cyIsICJjbHVzdGVyIikpICU+JQogIHJlbmFtZShsb2N1c190YWcgPSBsb2N1cykgJT4lCiAgbGVmdF9qb2luKHNlbGVjdChkZl9maXRuZXNzX2NvbXAsIGxvY3VzX3RhZywgZ2VuZV9uYW1lKSkgJT4lCiAgbXV0YXRlKAogICAgZ2VuZV9uYW1lID0gc3RyaV9leHRyYWN0X2ZpcnN0X3JlZ2V4KGdlbmVfbmFtZSwgcmVnZXhfYWxsKSAlPiUKICAgIHN0cl9yZXBsYWNlKCJtb2ciLCAibW9nQSIpCiAgKQoKcGxvdF90c25lIDwtIGRmX3RzbmUgJT4lCiAgeHlwbG90KFYyIH4gVjEsIC4sCiAgICBncm91cHMgPSBjbHVzdGVyLCBjb2wgPSBjdXN0b21fY29sb3JzLAogICAgeGxhYiA9ICJ0U05FIDEiLCB5bGFiID0gInRTTkUgMiIsCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogICAgbGFiZWxzID0gLltbImdlbmVfbmFtZSJdXSwgc2VsZWN0ZWQgPSB7IWlzLm5hKC5bWyJnZW5lX25hbWUiXV0pfSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgc2VsZWN0ZWQsIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLnJlcGVsbGFiZWxzKHgsIHksIHNlbGVjdGVkID0gc2VsZWN0ZWQsIGNleCA9IDAuNjUsCiAgICAgICAgZHJhd19ib3ggPSBUUlVFLCBib3hfZmlsbCA9IGdyZXkoMC45NSwgMC41KSwgLi4uKQogICAgICBkaXJlY3RsYWJlbHM6OnBhbmVsLnN1cGVycG9zZS5kbCh4LCB5LCAuLi4pCiAgICB9CiAgKQoKcHJpbnQocGxvdF90c25lKQpgYGAKCiMjIEZ1bmN0aW9ucyBlbnJpY2hlZCBpbiBkaWZmZXJlbnQgY2x1c3RlcnMKCkV4dHJhY3QgY2x1c3RlciBudW1iZXIgZm9yIGVhY2ggZ2VuZSBhbmQgcGVyZm9ybSBHTyBvciBLRUdHIGVucmljaG1lbnQgcGVyIGNsdXN0ZXIuIFRoZSBnb2FsIGlzIHRvIGlkZW50aWZ5IHRoZSBtb3N0IHByZXZhbGVudCBiaW9sb2dpY2FsIGZ1bmN0aW9ucyBwZXIgY2x1c3Rlci4KCmBgYHtyfQpkZl9jbHVzdGVyIDwtIGN1dHJlZW9yZChtYXRfY2x1c3RlciwgayA9IG5fY2x1c3RlcnMpICU+JQogIGVuZnJhbWUobmFtZSA9ICJsb2N1c190YWciLCB2YWx1ZSA9ICJjbHVzdGVyIikgJT4lCiAgYXJyYW5nZShjbHVzdGVyKQpgYGAKCldlIHVzZSB0aGUgZnVuY3Rpb25zIGBrZWdnYWAgZm9yIEtFR0cgZW5yaWNobWVudCBhbmFseXNpcyBhbmQgYGdvYW5hYCBmb3IgR08gdGVybSBlbnJpY2htZW50IGZyb20gdGhlIGBsaW1tYWAgcGFja2FnZS4gQm90aCBmdW5jdGlvbnMgdGVzdCBmb3Igb3ZlciBvciB1bmRlci1yZXByZXNlbnRhdGlvbiBvZiBnZW5lcyBhc3NvY2lhdGVkIHdpdGggY2VydGFpbiBwYXRod2F5cyBvciBHTyB0ZXJtcy4gVGhlIGZ1bmN0aW9ucyBkb24ndCB0YWtlIHRoZSBzdHJlbmd0aCBvZiBkaWZmZXJlbnRpYWwgZml0bmVzcyBpbnRvIGFjY291bnQgKERGOyB0aGUgZGVwbGV0aW9uL2VucmljaG1lbnQgb3ZlciB0aW1lKS4KCmBgYHtyfQp0cnlDYXRjaCgKICBkZl9rZWdnX2VucmljaG1lbnQgPC0gbGFwcGx5KDE6bl9jbHVzdGVycywgZnVuY3Rpb24oY2x1c3QpIHsKICAgIGZpbHRlcihkZl9jbHVzdGVyLCBjbHVzdGVyID09IGNsdXN0KSAlPiUgcHVsbChsb2N1c190YWcpICU+JQogICAga2VnZ2Eoc3BlY2llcy5LRUdHID0gInJlaCIpICU+JQogICAgbXV0YXRlKGNsdXN0ZXIgPSBjbHVzdCkKICB9KSAlPiUgYmluZF9yb3dzLAogIGVycm9yID0gZnVuY3Rpb24oZSkgcHJpbnQoZSkKKQpgYGAKClZpc3VhbGl6ZSB0aGUgcGF0aHdheXMgdGhhdCBhcmUgbW9zdCBlbnJpY2hlZCBmb3IgdGhlIGRpZmZlcmVudCBnZW5lIGNsdXN0ZXJzLgoKYGBge3IsIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSA1fQpwbG90X2tlZ2dlbnJpY2ggPC0gZGZfa2VnZ19lbnJpY2htZW50ICU+JQogIG11dGF0ZSgKICAgIGtlZ2dfcGF0aHdheSA9IHRvbG93ZXIoUGF0aHdheSksCiAgICBrZWdnX3BhdGh3YXkgPSBzdHJfcmVtb3ZlX2FsbChrZWdnX3BhdGh3YXksICIuP2Jpb3N5bnRoZXNpc3wgb2Z8IG1ldGFib2xpc20iKSwKICAgIGtlZ2dfcGF0aHdheSA9IHN0cl9zdWIoa2VnZ19wYXRod2F5LCAxLCAzMikKICApICU+JQogIGZpbHRlcihOID49IDUsIE4gPD0gMjAwKSAlPiUKICBtdXRhdGUobG9nMTBfcF92YWx1ZSA9IGxvZzEwKFAuREUpLCAua2VlcCA9ICJ1bnVzZWQiKSAlPiUKICBmaWx0ZXIobG9nMTBfcF92YWx1ZSA8IDApICU+JQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQogIGFycmFuZ2UobG9nMTBfcF92YWx1ZSkgJT4lCiAgc2xpY2UoMTozKSAlPiUgcm93d2lzZSgpICU+JQogIG11dGF0ZSgKICAgIGtlZ2dfcGF0aHdheSA9IHN0cl9yZW1vdmUoa2VnZ19wYXRod2F5LCAiIC0gQ3VwcmlhdmlkdXMgbmVjYXRvciBIMTYiKSwKICAgIGtlZ2dfcGF0aHdheSA9IHN0cl9nbHVlKCJ7a2VnZ19wYXRod2F5fSAoe2NsdXN0ZXJ9KSIpCiAgKSAlPiUgdW5ncm91cCAlPiUKICAKICB4eXBsb3QoZmFjdG9yKGtlZ2dfcGF0aHdheSwgcmV2KHVuaXF1ZShrZWdnX3BhdGh3YXkpKSkgfiBsb2cxMF9wX3ZhbHVlLCAuLAogICAgZ3JvdXBzID0gY2x1c3RlciwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgICBjb2wgPSBjdXN0b21fY29sb3JzLAogICAgeGxhYiA9IGV4cHJlc3Npb24oImxvZyJbMTBdKiIgcC12YWx1ZSIpLCB5bGFiID0gIiIsCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIGxhYmVscywgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pCiAgICB9CiAgKQoKcHJpbnQocGxvdF9rZWdnZW5yaWNoKQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNC41LCBlY2hvID0gRkFMU0V9CnN2ZyhmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2ZpZ3VyZV90c25lLnN2ZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNC41KQpwcmludChwbG90X3RzbmUsIHBvc2l0aW9uID0gYygtMC4wMiwgMCAsIDAuNTIsIDEpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9rZWdnZW5yaWNoLCBwb3NpdGlvbiA9IGMoMC40NiwgMCAsIDEsIDEpLCBtb3JlID0gVFJVRSkKZGV2Lm9mZigpCmBgYAojIEdlbmVzIGVzc2VudGlhbCBpbiBhbGwgY29uZGl0aW9ucwoKIyMgQ2x1c3RlciAxCgotIGJlZm9yZSBsb29raW5nIGF0IGNvbmRpdGlvbi1zcGVjaWZpYyBlc3NlbnRpYWxpdHksIGNhbiBhbHNvIGxvb2sgYXQgZ2VuZXMgZXNzZW50aWFsIGluIGFsbCBjb25kaXRpb25zCi0gdGhlc2UgZ2VuZXMgYXJlIG1vc3RseSBwcmVzZW50IGluIGNsdXN0ZXIgMQotIHdlIGFzc3VtZSB0aGF0IHRoZXNlIGFyZSBhbWlubyBhY2lkIGJpb3N5bnRoZXNpcyBnZW5lcwotIHRoZXkgYmVjb21lIGVzc2VudGlhbCB3aGVuIHRyYW5zZmVycmluZyAqQy4gbmVjYXRvciogZnJvbSByaWNoIHRvIG1pbmltYWwvZGVmaW5lZCBtZWRpdW0KLSBpbiB0b3RhbCAzMyBnZW5lcyB3aXRoIGRlcGxldGlvbiAKCkdlbmVyYWxpemVkIGZ1bmN0aW9uIHRvIHBsb3QgKHNtYWxsKSBoZWF0bWFwcy4KCmBgYHtyfQpoZWF0bWFwX2ZpdG5lc3MgPC0gZnVuY3Rpb24oZGF0YSwga2V5ID0gVFJVRSkgewogIAogICMgbWFrZSBzb21lIHNtYWxsIGFkanVzdG1lbnRzIHRvIG9wdGljYWwgYXBwZWFyYW5jZQogIGRhdGEgJT4lCiAgbXV0YXRlKG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiA9IG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiAlPiUKICAgIHJlcGxhY2UoLiwgLiA8IC02LCAtNikgJT4lIHJlcGxhY2UoLiwgLiA+IDYsIDYpKSAlPiUKCiAgIyBwbG90IGhlYXRtYXAKICBsZXZlbHBsb3Qobm9ybV9nZW5lX2ZpdG5lc3NfbWVkaWFuIH4gZmFjdG9yKGdlbmVfbmFtZSkgKiBmY3RfcmV2KGNvbmRfc2hvcnQpLCAuLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgY29sb3JrZXkgPSBrZXksCiAgICBjb2wucmVnaW9ucyA9IGNvbG9yUmFtcFBhbGV0dGUoaGVhdF9jb2xzKSgyNSksCiAgICBhdCA9IHNlcSgtNiwgNiwgMC41KSwgYXNwZWN0ID0gImlzbyIsCiAgICB4bGFiID0gIiIsIHlsYWIgPSAiIiwgc2NhbGVzID0gbGlzdChjZXggPSAwLjcsIHggPSBsaXN0KHJvdCA9IDkwKSksCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIHosIC4uLikgewogICAgICBwYW5lbC5sZXZlbHBsb3QoeCwgeSwgeiwgLi4uKQogICAgICBwYW5lbC5hYmxpbmUodiA9IHNlcV9hbG9uZyh1bmlxdWUoeCkpKzAuNSwgCiAgICAgICAgaCA9IHNlcV9hbG9uZyh1bmlxdWUoeSkpKzAuNSwgY29sID0gIndoaXRlIiwgbHdkID0gMikKICAgIH0KICApCn0KYGBgCgpHZW5lcmFsaXplZCBmdW5jdGlvbiB0byBwbG90IGdlbmVzIGZvciBkaWZmZXJlbnQgcmVnaW9ucyBvZiB0aGUgZ2Vub21lLgoKYGBge3J9Cmdlbm9tZV9wbG90IDwtIGZ1bmN0aW9uKGRmLCB4bGltID0gTlVMTCwgdGl0bGUgPSAiIiwgcm90X2xhYmVscyA9IDApIHsKICBkZiA8LSAgcmVwbGFjZV9uYShkZiwgbGlzdChzdHJhaW5zX3Blcl9nZW5lID0gMCkpCiAgdGhlbWUgPSBjdXN0b20uY29sb3JibGluZChjb2wgPSBjKGdyZXkoMC43KSwgZ3JleSgwLjg1KSkpCiAgdGhlbWUkYXhpcy5saW5lJGNvbCA9IGdyZXkoMC4zKQogIHRoZW1lJGF4aXMudGV4dCRjb2wgPSBncmV5KDAuMykKICB0aGVtZSRheGlzLnRleHQkY2V4ID0gMC43CiAgCiAgaWYgKCFpcy5udWxsKHhsaW0pKQogICAgeHNjYWxlID0gbGlzdChsaW1pdHMgPSB4bGltKQogIGVsc2UgCiAgICB4c2NhbGUgPSBsaXN0KCkKICB4eXBsb3QoZW5kLzEwMDAgfiBzdGFydC8xMDAwLCBkZiwKICAgIGdyb3VwcyA9IHN0cmFuZCwgY2V4ID0gMC43LCBsd2QgPSAxLAogICAgcGFyLnNldHRpbmdzID0gdGhlbWUsIHN0cmFpbnMgPSBkZiRzdHJhaW5zX3Blcl9nZW5lLAogICAgc2NhbGVzID0gbGlzdCh5ID0gbGlzdChkcmF3ID0gRkFMU0UpLCB4ID0geHNjYWxlKSwKICAgIHlsaW0gPSBjKC0zLDIpLCB4bGFiID0gIiIsIHlsYWIgPSAiIiwKICAgIGdlbmVfc3RyYW5kID0gZGZbWyJzdHJhbmQiXV0sCiAgICBnZW5lX25hbWUgPSBkZltbImdlbmVfbmFtZSJdXSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgc3RyYWlucywgLi4uKSB7CiAgICAgIHBhbmVsLmdlbmVwbG90KHgsIHksIGFycm93cyA9IFRSVUUsIAogICAgICAgIHRpcCA9IDAuMSwgcm90X2xhYmVscyA9IHJvdF9sYWJlbHMsIC4uLikKICAgICAgcGFuZWwudGV4dCgoeCt5KS8yLCByZXAoMCwgbGVuZ3RoKHgpKSwgbGFiZWxzID0gc3RyYWlucywgY2V4ID0gMC43KQogICAgICBwYW5lbC50ZXh0KG1lYW4oeGxpbSksIDEuNSwgbGFiZWxzID0gdGl0bGUsIGNvbCA9IDEpCiAgICB9CiAgKQp9CmBgYAoKUGxvdCBoZWF0IG1hcCBvZiBjbHVzdGVyIDEgZ2VuZSBmaXRuZXNzLgoKYGBge3IsIGZpZy53aWR0aCA9IDcuMCwgZmlnLmhlaWdodCA9IDQuMH0KcGxvdF9jbDEgPC0gZGZfY2x1c3RlciAlPiUKICBmaWx0ZXIoY2x1c3RlciA9PSAxKSAlPiUKICBsZWZ0X2pvaW4oZGZfZml0bmVzc19zdW1tYXJ5LCBieSA9ICJsb2N1c190YWciKSAlPiUKICBmaWx0ZXIodGltZSA9PSA4KSAlPiUKICBncm91cF9ieShDT0dfUHJvY2VzcykgJT4lCiAgbXV0YXRlKENPR19uID0gbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShkZXNjKENPR19uKSwgQ09HX1Byb2Nlc3MsIGdlbmVfbmFtZSkgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IGZjdF9pbm9yZGVyKGdlbmVfbmFtZSkpICU+JQogIGhlYXRtYXBfZml0bmVzcygpCgpwcmludChwbG90X2NsMSkKYGBgCi0gV2hpY2ggZnVuY3Rpb25hbCBjYXRlZ29yaWVzIChDT0cpIGRvIGdlbmVzIGJlbG9uZyB0bz8KCmBgYHtyLCBmaWcud2lkdGggPSA3LjAsIGZpZy5oZWlnaHQgPSAyLjV9CnBsb3RfY2wxX2Z1bmN0aW9uIDwtIGRmX2NsdXN0ZXIgJT4lCiAgZmlsdGVyKGNsdXN0ZXIgPT0gMSkgJT4lCiAgbGVmdF9qb2luKGRmX2ZpdG5lc3NfY29tcCwgYnkgPSAibG9jdXNfdGFnIikgJT4lCiAgY291bnQoQ09HX1Byb2Nlc3MpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgbXV0YXRlKENPR19Qcm9jZXNzID0gZmN0X2lub3JkZXIoQ09HX1Byb2Nlc3MpKSAlPiUKICBtdXRhdGUodmFycyA9IGZhY3RvcigiQ09HIHByb2Nlc3MiKSkgJT4lCiAgeHlwbG90KHZhcnMgfiBuLCAuLAogICAgc3RhY2sgPSBUUlVFLCBob3Jpem9udGFsID0gVFJVRSwKICAgIGF1dG8ua2V5ID0gbGlzdChjb2x1bW5zID0gMiksCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogICAgeGxhYiA9ICJjb3VudCIsIHlsYWIgPSAiIiwgbHR5ID0gMCwKICAgIHhsaW0gPSBjKDAsIDMzKSwKICAgIGdyb3VwcyA9IENPR19Qcm9jZXNzLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC5iYXJjaGFydCh4LCB5LCAuLi4pCiAgICB9CiAgKQoKcHJpbnQocGxvdF9jbDFfZnVuY3Rpb24pCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDZ9CnN2ZyhmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2ZpZ3VyZV9jbDEuc3ZnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQpwcmludChwbG90X2NsMSwgcG9zaXRpb24gPSBjKDAsIDAsIDEsIDAuNzUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9jbDFfZnVuY3Rpb24sIHBvc2l0aW9uID0gYygtMC4wMTgsIDAuNjIsIDAuOTMsIDEpKQpkZXYub2ZmKCkKYGBgCgoKCiMgU3VwZXJ2aXNlZCBhbmFseXNpcyBvZiBlbmVyZ3kgbWV0YWJvbGlzbQoKIyMgTW9seWJkZW51bSBjb2ZhY3RvciBiaW9zeW50aGVzaXMKCi0gICBtb2RBQiA9IG1vbHliZGVudW0gdHJhbnNwb3J0ZXIKLSAgIG1vYUFDREUgPSBtb2x5YmRvcHRlcmluIGJhY2tib25lIGJpb3N5bnRoZXNpcwotICAgbW9lQSA9IG1vbHliZG9wdGVyaW4gbW9seWJkZW51bSB0cmFuc2ZlcmFzZQotICAgbW9iQUIgPSBtb2x5YmRlbnVtIGNvZmFjdG9yIGd1YW55bHlsdHJhbnNmZXJhc2UsCi0gICBtb2cgPSBtb2x5YmRvcHRlcmluIGJpb3N5bnRoZXNpcyBwcm90ZWluIChyb2xlIHVuY2xlYXI/KQoKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA0fQojIHBsb3QgaGVhdG1hcApkZl9tb2NvIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUgZmlsdGVyKHRpbWUgPT0gOCwgZ3JlcGwoIm1vW2FlZGJnXSIsIGdlbmVfbmFtZSkpICU+JQogIGZpbHRlcighc3RyX2RldGVjdChnZW5lX25hbWUsICJtb2FBMiIpKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gc3RyaV9leHRyYWN0X2ZpcnN0X3JlZ2V4KGdlbmVfbmFtZSwgIm1vW2FlZGJnXShbQS1aMC05XSspPyIpICU+JQogICAgc3RyX3JlcGxhY2UoIm1vZyIsICJtb2dBIikpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBmYWN0b3IoZ2VuZV9uYW1lLCBjKCJtb2FBIiwgIm1vYUMiLCAibW9hRCIsICJtb2FFIiwgIm1vYUYiLAogICAgIm1vZEEiLCAibW9kQiIsICJtb2RDIiwgIm1vZ0EiLCAibW9lQTEiLCAibW9lQTIiLCAibW9lQTMiLCAibW9iQSIsICJtb2JCIiwgIm1vYkIyIiwgIm1vYkIzIikpKQpwbG90X21vY29fZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9tb2NvKQoKIyBwbG90IGdlbm9taWMgbG9jYXRpb25zCmRmX21vY28gPC0gZGZfbW9jbyAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3RfbW9jb19nMSA8LSBnZW5vbWVfcGxvdChkZl9tb2NvLCB4bGltID0gYygyNDU1LjksIDI0NTguNiksIHRpdGxlID0gImNociAxIikKcGxvdF9tb2NvX2cyIDwtIGdlbm9tZV9wbG90KGRmX21vY28sIHhsaW0gPSBjKDI3ODcuOCwgMjc5MS4yKSwgdGl0bGUgPSAiY2hyIDEiKQoKcHJpbnQocGxvdF9tb2NvX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4yMSwxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9tb2NvX2cxLCBwb3NpdGlvbiA9IGMoMC4xNywtMC4xLDAuNTcsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbW9jb19nMiwgcG9zaXRpb24gPSBjKDAuNTMsLTAuMSwwLjgzLDAuNCkpCmBgYAoKSW50ZXJlc3RpbmcgcmVzdWx0cyB0byBkb3VibGUtY2hlY2s6CgotICAgV2h5IGlzIG1vYUEgZXNzZW50aWFsIGZvciBuaXRyYXRlIHJlc3BpcmF0aW9uIGJ1dCBub3QgZm9ybWF0ZT8gSXMgdGhlcmUgYW5vdGhlciBpc28tZW56eW1lIGZvciBmaXJzdCBzdGVwIG9mIE1vQ28gc3ludGhlc2lzPwotICAgbW9nQSwgbW9hQSwgbW9hQiwgbW9hRSwgbW9kQiwgb3IgbW9kQyBkZWxldGlvbiBtdXRhbnRzIGFyZSBub3QgdmlhYmxlIGluIEUuY29saS4gRXhjZXB0IGZvciBtb2FBLCBhbHNvIG1vZEEsQixDIGFyZSBub3QgZXNzZW50aWFsIGZvciBncm93dGggb24gZm9ybWF0ZS4KLSAgIG1vZEFCQyBpcyB0aGUgMy1zdWJ1bml0IG1lbWJyYW5lIHRyYW5zcG9ydCBzeXN0ZW07IGl0IHNob3VsZCBiZSBlc3NlbnRpYWwsIGhvd2V2ZXIgb25lIGV4cGxhbmF0aW9uIGZvciBpdCBub3QgYmVpbmcgZXNzZW50aWFsIGlzIHRoYXQgYW5vdGhlciBsb3ctYWZmaW5pdHkgdHJhbnNwb3J0ZXIgbWlnaHQgZXhpc3QgdGhhdCBjb21wZW5zYXRlcyBmb3IgdGhlIGxvc3MgaW4gbWVkaXVtIHdpdGggaGlnaCBNby1jb25jZW50cmF0aW9uIChbWGlhIGV0IGFsLiwgMjAxOF0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNjI5NTQ1NS8pKS4gVGhlIGF1dGhvcnMgd3JpdGUgaW4gdGhlIGRpc2N1c3Npb246ICJNb2x5YmRhdGUgY2FuIGJlIHRha2VuIHVwIGJ5IHRoZSBzdWxmYXRlLXRyYW5zcG9ydCBzeXN0ZW0gaW4gdGhlIGFic2VuY2Ugb2YgYSBmdW5jdGlvbmFsIGhpZ2gtYWZmaW5pdHkgbW9seWJkYXRlLXRyYW5zcG9ydCBzeXN0ZW0gaW4gRS4gY29saSBhbmQgQi4gamFwb25pY3VtIChSb3NlbnRlbCBldCBhbC4sIDE5OTU7IERlbGdhZG8gZXQgYWwuLCAyMDA2KS4iCi0gICBtb2VBIChtb2x5YmRlbnVtIHRyYW5zZmVyYXNlKSBpcyBwcmVzZW50IHdpdGggMyBpc29lbnp5bWVzLiBNb2VBMSBhbmQgQTIgYm90aCBzZWVtIHRvIGJlIGltcG9ydGFudCBmb3IgZml0bmVzcyBhcyBhIEtPIG9mIGVhY2ggb25lIG9mIHRoZW0gcmVkdWNlcyBmaXRuZXNzIHBhcnRpYWxseSBidXQgbm90IGZ1bGx5IG9uIGZvcm1hdGUvbml0cmF0ZS4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnaGlkZSd9CnN2ZyhmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2ZpZ3VyZV9maXRfbW9jby5zdmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCnByaW50KHBsb3RfbW9jb19maXQsIHBvc2l0aW9uID0gYygwLDAuMjEsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbW9jb19nMSwgcG9zaXRpb24gPSBjKDAuMTcsLTAuMSwwLjU3LDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X21vY29fZzIsIHBvc2l0aW9uID0gYygwLjUzLC0wLjEsMC44MywwLjQpKQpkZXYub2ZmKCkKYGBgCgojIyBGb3JtYXRlIGRlaHlkcm9nZW5hc2UKCi0gICBmZHNBQkNERyA9IHByaW1hcnkgc29sdWJsZSBGREgKLSAgIGZkd0FCID0gc2Vjb25kYXJ5IHNvbHVibGUgRkRICi0gICBmZGhBQkNEID0gcHJpbWFyeSBtZW1icmFuZS1ib3VuZCBGREgsIDIgY29waWVzIEExQjEuLi4gYW5kIEEyQjIuLi4KLSAgIGZkb0dISSA9IHNlY29uZGFyeSBtZW1icmFuZS1ib3VuZCBGREgKCmBgYHtyLCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNH0KIyBwbG90IGhlYXRtYXAKZGZfZmRoIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUgZmlsdGVyKHRpbWUgPT0gOCwgZ3JlcGwoImZkW3N3aG9dIiwgZ2VuZV9uYW1lKSkgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IHN0cmlfZXh0cmFjdF9maXJzdF9yZWdleChnZW5lX25hbWUsICJmZFtzd2hvXVtBLVowLTldKyIpKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gcmVjb2RlKGdlbmVfbmFtZSwgYGZkaERgID0gImZkc0MiLCBgZmRoQ2AgPSAiZmRoQzEiLCBgZmRoRWAgPSAiZmRoRTEiKSkgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IGZhY3RvcihnZW5lX25hbWUsIGMocGFzdGUwKCJmZHMiLCBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkciLCAiUiIpKSwKICAgICJmZHdBIiwgImZkd0IiLCBwYXN0ZTAoImZkaCIsIGMoIkExIiwgIkIxIiwgIkMxIiwgIkQxIiwgIkUxIiwgIkEyIikpLCAiZmRvRyIpKSkKcGxvdF9mZGhfZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9mZGgpCgojIHBsb3QgZ2Vub21pYyBsb2NhdGlvbnMKZGZfZmRoIDwtIGRmX2ZkaCAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3RfZmRoX2cxIDwtIGdlbm9tZV9wbG90KGRmX2ZkaCwgeGxpbSA9IGMoNjc3LjcsIDY4NS42KSwgdGl0bGUgPSAiY2hyIDEiKQpwbG90X2ZkaF9nMiA8LSBnZW5vbWVfcGxvdChkZl9mZGgsIHhsaW0gPSBjKDMxNjcuOSwgMzE3NC45KSwgdGl0bGUgPSAiY2hyIDEiKQoKcHJpbnQocGxvdF9mZGhfZml0LCBwb3NpdGlvbiA9IGMoMCwwLjIzLDEsMS4wNSksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2ZkaF9nMSwgcG9zaXRpb24gPSBjKDAuMTcsLTAuMSwwLjU3LDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2ZkaF9nMiwgcG9zaXRpb24gPSBjKDAuNTIsLTAuMSwwLjgzLDAuNCkpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30Kc3ZnKGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvZmlndXJlX2ZpdF9mZGguc3ZnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA0KQpwcmludChwbG90X2ZkaF9maXQsIHBvc2l0aW9uID0gYygwLDAuMjMsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfZmRoX2cxLCBwb3NpdGlvbiA9IGMoMC4xNywtMC4xLDAuNTcsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfZmRoX2cyLCBwb3NpdGlvbiA9IGMoMC41MiwtMC4xLDAuODMsMC40KSkKZGV2Lm9mZigpCmBgYAoKIyMgSHlkcm9nZW5hc2VzCgotICAgaG94QSA9IG1hc3RlciByZWd1bGF0b3IsIDItY29tcG9uZW50IHN5c3RlbS4gSG94QSBpcyBjb25zdGFudGx5IGFjdGl2ZSBpbiBpdHMgbm9uLSBwaG9zcGhvcnlsYXRlZCBzdGF0ZSBiZWxvdyBhIHRlbXBlcmF0dXJlIG9mIDMzXCpDLiBPcmlnaW5hbGx5LCBob3hBIGFjdGl2aXR5IGlzIHJlZ3VsYXRlZCBieSB0aGUga2luYXNlIEhveEogKHRvZ2V0aGVyIHdpdGggSG94QkMsIHRoZSAncmVndWxhdG9yeScgaHlkcm9nZW5hc2UpLiBUaGlzIGZ1bmN0aW9uIGlzIGluYWN0aXZhdGVkIGR1ZSB0byBhIG11dGF0aW9uIGluIGhveEosIFtGcmllZHJpY2ggJiBGcmllZHJpY2gsIEogQmFjLCAxOTgzXShodHRwczovL2pvdXJuYWxzLmFzbS5vcmcvZG9pLzEwLjExMjgvamIuMTUzLjEuMTc2LTE4MS4xOTgzKSwgW0xlbnogZXQgYWwuLCBKTU1CLCAyMDA0XShodHRwczovL2NpdGVzZWVyeC5pc3QucHN1LmVkdS92aWV3ZG9jL2Rvd25sb2FkP2RvaT0xMC4xLjEuMzM0LjUzMzAmcmVwPXJlcDEmdHlwZT1wZGYpLgotICAgaG94S0daID0gbWVtYnJhbmUtYm91bmQgaHlkcm9nZW5hc2UKLSAgIGhveE1MT1FSVFYgPSBNQkggYWNjZXNzb3J5IGdlbmVzIChjb2ZhY3RvciBpbmNvcnBvcmF0aW9uLCBzdWJ1bml0IGFzc2VtYmx5LCBhbmQgdHdpbi1hcmdpbmluZS1kZXBlbmRlbnQgbWVtYnJhbmUgdHJhbnNsb2NhdGlvbiAtIFRBVCksIFtTY2h1YmVydCBldCBhbC4sIE1vbCBNaWNyb2JpbywgMjAwN10oaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8xNzg1MDI1OS8pLCBbRnJpdHNjaCBldCBhbC4sIEogQmFjLCAyMDExXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzIxNDQxNTE0LykgW1NjaHdhcnR6IGV0IGFsLiwgSiBNb2wgQmlvLCAyMDAzXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzEyOTQ4NDg4KQotICAgaG94TjEsIGhveE4yID0gTmlja2VsL0NvYmFsdCB0cmFuc3BvcnRlcnMuIEhveE4yIDUxJSBpZGVudGljYWwgb24gQUEgbGV2ZWwgYnV0IG5vdCBmdW5jdGlvbmFsLCBbU2Nod2FydHogZXQgYWwuLCBKIE1vbCBCaW8sIDIwMDNdKGh0dHBzOi8vcHVibWVkLm5jYmkubmxtLm5paC5nb3YvMTI5NDg0ODgpCi0gICBob3hCQyA9IHJlZ3VsYXRvcnkgaHlkcm9nZW5hc2UgUkgsIG94eWdlbi1yZXNpc3RhbnQgbm9uLWVuZXJneSBnZW5lcmF0aW5nIGh5ZHJvZ2VuIHNlbnNvci4gSG94QyBpcyBsYXJnZSBhY3RpdmUtc2l0ZS1jb250YWluaW5nIHN1YnVuaXQsIGhveEIgc21hbGwgc3VidW5pdCBIb3hCIGNhcnJ5aW5nIEZlLVMgY2x1c3RlcnMKLSAgIEhveEogPSBSSCBiaW5kaW5nIHNpZ25hbCB0cmFuc2R1Y2VyLCBoaXN0aWRpbmUgcHJvdGVpbiBraW5hc2UgW0zDtnNjaGVyIGV0IGFsLiwgQ2hlbSBQaHlzIENoZW0sIDIwMTBdKGh0dHBzOi8vcHVibWVkLm5jYmkubmxtLm5paC5nb3YvMjAzNDAxMjQvKSBbQnVlcnN0ZWwgZXQgYWwuLCBQTkFTLCAyMDE2XShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI3OTMwMzE5LykKLSAgIGhveEZVWUggPSBzb2x1YmxlIGh5ZHJvZ2VuYXNlCi0gICBob3hXID0gc29sdWJsZSBoeWRyb2dlbmFzZSAoSG94SC1zcGVjaWZpYykgQy10ZXJtaW5hbCBwcm90ZWFzZSAobWF0dXJhdGlvbikKLSAgIGhveEkgPSBvcHRpb25hbCBzdWJ1bml0IG9mIFNIIChob3hGVVlIKTsgc3BlY2lmaWMgcmVhY3Rpb24gc2l0ZSBmb3IgTkFEUEgsIFtCdXJnZG9yZiBldCBhbC4sIEogQmFjLCAyMDA1XShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzE1ODM4MDM5LykKLSAgIGEgNHRoIGh5ZHJvZ2VuYXNlIGV4aXN0IG9uIHBIRzEsIG1hZGUgZnJvbSAyIHN1YnVuaXRzICgqaG9mSyosICpob2ZHKiwgcEhHMDY0LzA2NSksIHNlZSBbU2Now6RmZXIgZXQgYWwuLCAyMDE1XShodHRwczovL3d3dy5jZWxsLmNvbS9zdHJ1Y3R1cmUvcGRmRXh0ZW5kZWQvUzA5NjktMjEyNigxNSkwMDQ5OS0yKS4KLSAgIHRoZXNlIHN1YnVuaXRzIGhhdmUgbm8gZWZmZWN0IG9uIGZpdG5lc3MgKGhpZ2ggY292ZXJhZ2Ugb2YgOS0xMSBtdXRhbnRzIHBlciBnZW5lKSwgYW5kIGFyZSB2ZXJ5IGxvd2x5IGV4cHJlc3NlZCAoUEhHMDY0IG4uZC4sIFBIRzA2NSBsb3cgYWJ1bmRhbmNlKQoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA0fQojIHBsb3QgaGVhdG1hcApkZl9oeWQgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcih0aW1lID09IDgsIGdyZXBsKCJob3giLCBnZW5lX25hbWUpKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gc3RyaV9leHRyYWN0X2ZpcnN0X3JlZ2V4KGdlbmVfbmFtZSwgImhveFtBLVowLTldKyIpKSAlPiUKICB1bmdyb3VwICU+JSBtdXRhdGUoZ2VuZV9uYW1lID0gZmFjdG9yKGdlbmVfbmFtZSwgcGFzdGUwKCJob3giLCBjKCJLIiwiRyIsIloiLCJNIiwKICAgIkwiLCJPIiwiUSIsIlIiLCJUIiwiViIsIkEiLCJCIiwiQyIsIkoiLCJOIiwiTjIiLCJGIiwiVSIsIlkiLCJIIiwiVyIsIkkiKSkpKQpwbG90X2h5ZF9maXQgPC0gaGVhdG1hcF9maXRuZXNzKGRmX2h5ZCkKCiMgcGxvdCBnZW5vbWljIGxvY2F0aW9ucwpkZl9oeWQgPC0gZGZfaHlkICU+JSBncm91cF9ieShsb2N1c190YWcsIGdlbmVfbmFtZSwgc2NhZmZvbGQsIHN0cmFuZCwgc3RhcnQsIGVuZCkgJT4lCiAgc3VtbWFyaXplKHN0cmFpbnNfcGVyX2dlbmUgPSBtaW4odW5pcXVlKHN0cmFpbnNfcGVyX2dlbmUpKSwgLmdyb3VwcyA9ICJkcm9wIikKcGxvdF9oeWRfZzEgPC0gZ2Vub21lX3Bsb3QoZGZfaHlkLCB4bGltID0gYygwLCA0LjEpLCB0aXRsZSA9ICJwSEcxIikKcGxvdF9oeWRfZzIgPC0gZ2Vub21lX3Bsb3QoZGZfaHlkLCB4bGltID0gYygxNS4xLCAyMi44KSwgdGl0bGUgPSAicEhHMSIpCnBsb3RfaHlkX2czIDwtIGdlbm9tZV9wbG90KGRmX2h5ZCwgeGxpbSA9IGMoNzkuMiwgODUuNSksIHRpdGxlID0gInBIRzEiKQoKcHJpbnQocGxvdF9oeWRfZml0LCBwb3NpdGlvbiA9IGMoMCwwLjIzLDEsMS4wNSksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2h5ZF9nMSwgcG9zaXRpb24gPSBjKDAuMTUsLTAuMSwwLjM5LDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2h5ZF9nMiwgcG9zaXRpb24gPSBjKDAuMzUsLTAuMSwwLjY1LDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2h5ZF9nMywgcG9zaXRpb24gPSBjKDAuNjEsLTAuMSwwLjkwLDAuNCkpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30Kc3ZnKGZpbGVuYW1lID0gIi4uL2ZpZ3VyZXMvZmlndXJlX2ZpdF9oeWQuc3ZnIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQpwcmludChwbG90X2h5ZF9maXQsIHBvc2l0aW9uID0gYygwLDAuMjMsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfaHlkX2cxLCBwb3NpdGlvbiA9IGMoMC4xNSwtMC4xLDAuMzksMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfaHlkX2cyLCBwb3NpdGlvbiA9IGMoMC4zNSwtMC4xLDAuNjUsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfaHlkX2czLCBwb3NpdGlvbiA9IGMoMC42MSwtMC4xLDAuOTAsMC40KSkKZGV2Lm9mZigpCmBgYAoKIyMgSHlkcm9nZW5hc2UgcGxlaW90cm9weSBnZW5lcyAobWF0dXJhdGlvbikKCi0gICBoeXBBMSxCMSxGMSxDMSxEMSxFMSA9IE5pLUZlIG1ldGFsbG9jZW50ZXIgZm9ybWF0aW9uIHByb3RlaW5zIGZvciBib3RoIE1CSCBhbmQgU0guICJIeXBDMSwgaHlwRDEsIGFuZCBoeXBFMSBhcmUgZXNzZW50aWFsIGZvciBTSCBhbmQgTUJIIG1hdHVyYXRpb24sIHdoaWxlIG9ubHkgb25lIGludGFjdCBjb3B5IGVhY2ggb2YgaHlwQSwgaHlwQiwgYW5kIGh5cEYgaXMgbmVlZGVkIiwgW1NjaHdhcnR6IGV0IGFsLiwgSiBNb2wgQmlvLCAyMDAzXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzEyOTQ4NDg4KQotICAgaHlwQSBhbmQgQgotICAgaHlwQ0RFRiBhbGwgZm9ybSBhIGNvbXBsZXggdG8gYXNzZW1ibGUgdGhlIE5pLUZlLUNPLUNOIGNvZmFjdG9yCi0gICBoeXBYID0gQ08gY29mYWN0b3IgZm9ybWF0aW9uIGZvciBOaUZlLWh5ZHJvZ2VuYXNlLiBIeXBYIGNvbnZlcnRzIGZvcm15bC1USEYgaW50byB3YXRlciBhbmQgQ08gaW4gYWVyb2JpYyBjb25kaXRpb25zLCBbU2NodWx6IGV0IGFsLiwgSkFDUywgMjAyMF0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMjEvamFjcy45YjExNTA2KQotICAgaHlwQTIsQjIsRjIgPSBhbHRlcm5hdGl2ZSBnZW5lcyBmb3IgaHlwQTEsQjEsRjEsIG5vdCBzdWZmaWNpZW50IGFsb25lIGZvciBoeWRyb2dlbmFzZSBmb3JtYXRpb24KLSAgIGh5cEYzLGh5cEMyLGh5cEQyLGh5cEUyLGh5cEEzLGh5cEIzLiBUaGUgcGh5c2lvbG9naWNhbCBmdW5jdGlvbiBvZiB0aGVzZSBleHRyYSBoeXAgZ2VuZXMgaXMgdW5jbGVhcgoKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA0fQpkZl9oeXAgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JSBmaWx0ZXIodGltZSA9PSA4LCBncmVwbCgiaHlwIiwgZ2VuZV9uYW1lKSkgJT4lCiAgIyBjb3JyZWN0IG5hbWVzIG9mIHNldmVyYWwgaHlwIGdlbmVzIHRvIG1ha2UgaXQgbW9yZSBzeXN0ZW1hdGljCiAgbXV0YXRlKGdlbmVfbmFtZSA9IGdzdWIoImh5cEEgUEhHMDk0IiwgImh5cEEyIFBIRzA5NCIsIGdlbmVfbmFtZSkpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBzdHJpX2V4dHJhY3RfZmlyc3RfcmVnZXgoZ2VuZV9uYW1lLCAiaHlwW0EtWjAtOV0rIikgJT4lCiAgICByZWNvZGUoaHlwQSA9ICJoeXBBMSIsIGh5cEIgPSAiaHlwQjEiLCBoeXBDID0gImh5cEMxIiwgaHlwRCA9ICJoeXBEMSIsIGh5cEUgPSAiaHlwRTEiKSkgJT4lCiAgdW5ncm91cCAlPiUgbXV0YXRlKGdlbmVfbmFtZSA9IGZhY3RvcihnZW5lX25hbWUsIHBhc3RlMCgiaHlwIiwgYygiQTEiLCJCMSIsIkMxIiwiRDEiLCJFMSIsCiAgICAiRjEiLCJYIiwiQTIiLCJCMiIsIkMyIiwiRDIiLCJFMiIsIkYyIiwiQTMiLCJCMyIsIkYzIikpKSkKcGxvdF9oeXBfZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9oeXApCgojIHBsb3QgZ2Vub21pYyBsb2NhdGlvbnMKZGZfaHlwIDwtIGRmX2h5cCAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3RfaHlwX2cxIDwtIGdlbm9tZV9wbG90KGRmX2h5cCwgeGxpbSA9IGMoOC4zLCAxNS42KSwgdGl0bGUgPSAicEhHMSIpCnBsb3RfaHlwX2cyIDwtIGdlbm9tZV9wbG90KGRmX2h5cCwgeGxpbSA9IGMoNjYuMywgNzMuNSksIHRpdGxlID0gInBIRzEiKQpwbG90X2h5cF9nMyA8LSBnZW5vbWVfcGxvdChkZl9oeXAsIHhsaW0gPSBjKDg1LjAsIDg5LjcpLCB0aXRsZSA9ICJwSEcxIikKCnByaW50KHBsb3RfaHlwX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4yMywxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9oeXBfZzEsIHBvc2l0aW9uID0gYygwLjI2LC0wLjEsMC43OCwwLjQpLCBtb3JlID0gVFJVRSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ2hpZGUnfQpzdmcoZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9maWd1cmVfZml0X2h5cC5zdmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCnByaW50KHBsb3RfaHlwX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4yMywxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9oeXBfZzEsIHBvc2l0aW9uID0gYygwLjI2LC0wLjEsMC43OCwwLjQpLCBtb3JlID0gVFJVRSkKZGV2Lm9mZigpCmBgYAoKIyMgT3RoZXIgY29tcGxleGVzIGltcG9ydGFudCBpbiBlbmVyZ3kgbWV0YWJvbGlzbQoKLSAgICoqc3VjY2luYXRlIGRlaHlkcm9nZW5hc2UqKgogICAgLSAgIHNkaEFCQ0QgPSBtZW1icmFuZSBpbnRlZ3JhbCBzdWNjaW5hdGUgZGVoeWRyb2dlbmFzZSwgcmVkdWNpbmcgVVEgdG8gVVFIMjogKiphbGwgb2YgaXRzIGdlbmVzIGFyZSBzdHJpY3RseSBlc3NlbnRpYWwqKiwgbm8gS08gbXV0YW50cyBhdmFpbGFibGUKLSAgICoqTkFESCBkZWh5ZHJvZ2VuYXNlKioKICAgIC0gICBudW9BQkNERUZHSElKS0xNTiA9IG1lbWJyYW5lIGludGVncmFsIE5BREggZGVoeWRyb2dlbmFzZSwgb3hpZGl6ZXMgTkFESCwgcHVtcHMgNCBIKywgcmVkdWNlcyBVUSB0byBVUUgyOiAqKmFsbCBvZiBpdHMgZ2VuZXMgYXJlIHN0cmljdGx5IGVzc2VudGlhbCoqLCBubyBLTyBtdXRhbnRzIGF2YWlsYWJsZQoKIyMgRWxlY3Ryb24gdHJhbnNwb3J0IGNoYWluCgpDeXRvY2hyb21lIGUtIHRyYW5zcG9ydCBwcm90ZWlucywgY3l0b2Nocm9tZSByZWR1Y3Rhc2VzLCBhbmQgdGVybWluYWwgb3hpZGFzZXMuCgotICAgKipxdWlub2wgb3hpZGFzZXMqKgogICAgLSAgIGN5b0ExQjFDMUQxLCAuLi4gKDMgY29waWVzKSA9IGN5dG9jaHJvbWUgYm8zIGNvbXBsZXgsIHF1aW5vbGUgb3hpZGFzZSwgbG93IE8yIGFmZmluaXR5CiAgICAtICAgY3lkQTFCMSwgLi4uICgyIGNvcGllcykgPSBjeXRvY2hyb21lIGJkIGNvbXBsZXgsIHF1aW5vbGUgb3hpZGFzZSwgaGlnaCBPMiBhZmZpbml0eQotICAgKipjeXRvY2hyb21lIHJlZHVjdGFzZXMqKgogICAgLSAgIHFjckFCQyAoYWthIHBldEFCQywgYEgxNl9BMzM5OGAsIGBIMTZfQTMzOTdgLCBgSDE2X0EzMzk2YCkgPSBjeXRvY2hyb21lIGJjMSByZWR1Y3Rhc2UKLSAgICoqY3l0b2Nocm9tZSBDIGUtIGNhcnJpZXJzKioKICAgIC0gICBjeXRvY2hyb21lIGM1NTMgYWNjb3JkaW5nIHRvIHVuaXByb3Q6IGBIMTZfQTM0NTFgLCBgSDE2X0EwODMwYCwgYEgxNl9BMDg0NmAsIGBIMTZfQjE0NTJgLCBgSDE2X0EzNTc2YCwgYEgxNl9BMTEyMWAsIGBIMTZfQTExMjBgLiBBY2NvcmRpbmcgdG8gU3RyaW5nIERCLCBgSDE2X0EzNTc2YCBpcyBpbiBzYW1lIG9wZXJvbiBhcyB0aGlvc3VscGhhdGUgb3hpZGF0aW9uIHBhdGh3YXkgKFNveFhZWkFCQ0QpLCB3aGVyZSB0aGlvc3VsZmF0ZSBpcyB1c2VkIGFzIGVsZWN0cm9uIHNvdXJjZSBbWmhhbmcgZXQgYWwuLCAyMDIwXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTM5Ni0wMjAtMDY4NC01KQotICAgKip0ZXJtaW5hbCBjeXRvY2hyb21lIEMgb3hpZGFzZXMqKgogICAgLSAgIGNveE1OT1BRID0gYmIzIGNvbXBsZXgsIGFmZmluaXR5IHVua25vd24sIG5vdCBlc3NlbnRpYWwgZm9yIGdyb3d0aCBvciBOLWZpeGF0aW9uIGluIEIuIGphcG9ueWN1bSB3aGVyZSBpdCB3YXMgZGlzY292ZXJlZC4KICAgIC0gICBjdGFBQkNERUcgPSBhYTMgY29tcGxleCwgbG93IE8yIGFmZmluaXR5CiAgICAtICAgY2NvR05PUCA9IGNiYjMgY29tcGxleCwgaGlnaCBhZmZpbml0eSwgaGlnaCBzaW1pbGFyaXR5IHRvIE5PMyByZWR1Y3Rhc2UKICAgIC0gICBWUDI2NDEgKGBIMTZfQTEwMzFgKSA9IE1lbWJyYW5lIHNwYW5uaW5nIHByb3RlaW4sIFJERCBmYW1pbHkuIFBGQU06IHVua25vd24gZnVuY3Rpb24sIHBvdGVudGlhbCB0cmFuc3BvcnRlcj8gSW50ZXJhY3RzIHdpdGggY3l0b2Nocm9tZSBjNTUzIGFuZCBxY3JDLCBjeXRvY2hyb21lIHJlZHVjdGFzZS4gSXQncyBkZXBsZXRpb24gaW1wbGljYXRlcyB0aGlzIHByb3RlaW4gaW4gZm9ybWF0ZS1zcGVjaWZpYyBlLSB0cmFuc3BvcnQgaW4gdGhlIG1lbWJyYW5lLgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNH0KZGZfZXRjIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUgZmlsdGVyKHRpbWUgPT0gOCwgbG9jdXNfdGFnICVpbiUgYygiSDE2X0EzNDUxIiwgIkgxNl9BMDgzMCIsCiAgICAiSDE2X0EwODQ2IiwgIjE2X0IxNDUyIiwgIkgxNl9BMzU3NiIsICJIMTZfQTExMjEiLCAiSDE2X0ExMTIwIiwgIkgxNl9BMTAzMSIpIHwgCiAgICBncmVwbCgicWNyfGNjb3xjdGF8Y294W01OT1BRXSB8Y3lvfGN5ZCIsIGdlbmVfbmFtZSkpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBzdHJpX2V4dHJhY3RfZmlyc3RfcmVnZXgoZ2VuZV9uYW1lLCAiSDE2X1tBQl1bMC05XSt8KHFjcnxjY298Y3RhfGNveHxjeW98Y3lkKShbQS1aMC05XSspPyIpICU+JQogICAgZmFjdG9yKGMoCiAgICAgIHBhc3RlMCgiY3lvIiwgYygiQTEiLCJBMiIsIkEzIiwiQjEiLCJCMiIsIkIzIiwiQzEiLCJDMiIsIkQxIiwiRDIiKSksCiAgICAgIHBhc3RlMCgiY3lkIiwgYygiQTEiLCJCMSIsIkIyIikpLCBwYXN0ZTAoInFjciIsIGMoIkEiLCJCIiwiQyIpKSwKICAgICAgcGFzdGUwKCJIMTZfIiwgYygiQTM1NzYiLCJBMDg0NiIsIkExMTIwIiwiQTExMjEiLCJBMTAzMSIsIkEzNDUxIikpLAogICAgICBwYXN0ZTAoImNveCIsIGMoIk0iLCJOIiwiTyIsIlAiLCJRIikpLCBwYXN0ZTAoImN0YSIsIGMoIkEiLCJCIiwiQyIsIkQiLCJFIiwiRyIpKSwKICAgICAgcGFzdGUwKCJjY28iLCBjKCJHIiwiTiIsIk8iLCJQIikpCiAgICApKQogICkKcGxvdF9ldGNfZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9ldGMpCgojIHBsb3QgZ2Vub21pYyBsb2NhdGlvbnMKZGZfZXRjIDwtIGRmX2V0YyAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3RfZXRjX2cxIDwtIGdlbm9tZV9wbG90KGRmX2V0YywgeGxpbSA9IGMoMzY3NS4yLCAzNjc5LjApLCB0aXRsZSA9ICJjaHIgMSIpCnBsb3RfZXRjX2cyIDwtIGdlbm9tZV9wbG90KGRmX2V0YywgeGxpbSA9IGMoMzYxLjIsIDM3MS4yKSwgdGl0bGUgPSAiY2hyIDEiKQpwbG90X2V0Y19nMyA8LSBnZW5vbWVfcGxvdChkZl9ldGMsIHhsaW0gPSBjKDI1MDkuNSwgMjUxNS4yKSwgdGl0bGUgPSAiY2hyIDEiKQoKcHJpbnQocGxvdF9ldGNfZml0LCBwb3NpdGlvbiA9IGMoMCwwLjE3LDEsMS4wNSksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2V0Y19nMSwgcG9zaXRpb24gPSBjKDAuMSwtMC4xLDAuMzEsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfZXRjX2cyLCBwb3NpdGlvbiA9IGMoMC4yOCwtMC4xLDAuNjUsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfZXRjX2czLCBwb3NpdGlvbiA9IGMoMC42MiwtMC4xLDAuOSwwLjQpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnaGlkZSd9CnN2ZyhmaWxlbmFtZSA9ICIuLi9maWd1cmVzL2ZpZ3VyZV9maXRfZXRjLnN2ZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDQpCnByaW50KHBsb3RfZXRjX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4xNywxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9ldGNfZzEsIHBvc2l0aW9uID0gYygwLjEsLTAuMSwwLjMxLDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2V0Y19nMiwgcG9zaXRpb24gPSBjKDAuMjgsLTAuMSwwLjY1LDAuNCksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X2V0Y19nMywgcG9zaXRpb24gPSBjKDAuNjIsLTAuMSwwLjksMC40KSkKZGV2Lm9mZigpCmBgYAoKIyMgTml0cmF0ZSByZXNwaXJhdGlvbgoKKipOaXRyYXRlIHJlZHVjdGFzZSAoTkFSKSoqCgpSZWFjdGlvbjogSE5PMy0gKyBRSDIgLS1cPiBOTzItICsgSDJPICsgUS4KClR3byBjb3BpZXMgb2YgdGhlICpuYXIqIG9wZXJvbiwgb25lIG9uIHRoZSBtZWdhcGxhc21pZCBhbmQgb25lIG9uIGNocm9tb3NvbWUgMi4gU2V2ZXJhbCBvdGhlciBlbnp5bWVzIGNhdGFseXplIHNpbWlsYXIgcmVhY3Rpb25zIGFzIE5BUi4gTkFTIGlzIGN5dG9wbGFzbWljIGFuZCBOQURIIGRlcGVuZGVudCAqYXNzaW1pbGF0b3J5KiBuaXRyYXRlIHJlZHVjdGFzZSBbQ3JhbW0gUiwgMjAwOF0oaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8xODk1Nzg2MS8pLiBOQVAgaXMgKnBlcmlwbGFzbWljKiBtZW1icmFuZSBwcm90ZWluIGNvbXBsZXggYWNjZXB0aW5nIFFIMiwgaW52b2x2ZWQgaW4gbml0cmF0ZSByZXNwaXJhdGlvbiBidXQgcHJvYmFibHkgYWxzbyBkaXNzaXBhdGlvbiBvZiBleGNlc3MgcmVkb3ggcG93ZXIuIEhlcmUgd2UganVzdCBmb2N1cyBvbiB0aGUgbWFpbiBOQVIgZW56eW1lLgoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA0fQpkZl9uYXIgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcih0aW1lID09IDgsIGdyZXBsKCJuYVtyc3BdIiwgZ2VuZV9uYW1lKSkgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IHN0cmlfZXh0cmFjdF9maXJzdF9yZWdleChnZW5lX25hbWUsICJuYVtyc3BdKFtBLVowLTldKyk/IikgJT4lCiAgICByZWNvZGUobmFyRyA9ICJuYXJHMSIsIG5hckggPSAibmFySDEiLCBuYXJJID0gIm5hckkxIiwgbmFyTCA9ICJuYXJMMSIsIG5hclggPSAibmFyWDEiKSkKcGxvdF9uYXJfZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9uYXIpCgojIHBsb3QgZ2Vub21pYyBsb2NhdGlvbnMKZGZfbmFyX2dlbmVzIDwtIGRmX25hciAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3RfbmFyX2cxIDwtIGdlbm9tZV9wbG90KGRmX25hcl9nZW5lcywgeGxpbSA9IGMoMjc5LjUsIDI5NC41KSwgdGl0bGUgPSAicEhHMSIpCgpwcmludChwbG90X25hcl9maXQsIHBvc2l0aW9uID0gYygwLDAuMjYsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbmFyX2cxLCBwb3NpdGlvbiA9IGMoMC4yLC0wLjEsMC44NSwwLjQpKQpgYGAKCioqTml0cml0ZSByZWR1Y3Rhc2UgKE5JUikqKgoKUmVhY3Rpb246IE5PMi0gKyBRSDIgLS1cPiBOTyArIEgyTyArIFEKCk5JUiBpcyBhIGNkMSB0eXBlIGNvcHBlciBjb250YWluaW5nIHRlcm1pbmFsIG94aWRhc2UsIGhvbW9kaW1lciBvZiAyIG5pclMgc3VidW5pdHMuIFRoZSBnZW5lcyBmb3Igbml0cml0ZSByZWR1Y3Rhc2UgYXJlIGFzc2VtYmxlZCBpbiBhIGNsdXN0ZXIgKG5pclMsIC1DLCAtRiwgLUQsIC1HLCAtSCwgLUosIC1OLCAtRSkgc3Bhbm5pbmcgOC42IGtiIG9uIGNocm9tb3NvbWUgMi4gVGhlIGZpcnN0IGdlbmUgb2YgdGhpcyBjbHVzdGVyLCBuaXJTLCBpcyB0aGUgc3RydWN0dXJhbCBnZW5lIGVuY29kaW5nIGNkMSAtTklSLiBUaGUgcmUtbWFpbmluZyBnZW5lcyBhcmUgcHJlc3VtZWQgdG8gYmUgYWNjZXNzb3J5IGdlbmVzIGVzc2VudGlhbCBmb3IgbWF0dXJhdGlvbiBvZiBhY3RpdmUgbml0cml0ZSByZWR1Y3Rhc2UgKD8pLgoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA0fQpkZl9uaXIgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcih0aW1lID09IDgsIGdyZXBsKCJuaXIiLCBnZW5lX25hbWUpKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gc3RyaV9leHRyYWN0X2ZpcnN0X3JlZ2V4KGdlbmVfbmFtZSwgIm5pcihbQS1aMC05XSspPyIpKQpwbG90X25pcl9maXQgPC0gaGVhdG1hcF9maXRuZXNzKGRmX25pcikKCiMgcGxvdCBnZW5vbWljIGxvY2F0aW9ucwpkZl9uaXJfZ2VuZXMgPC0gZGZfbmlyICU+JSBncm91cF9ieShsb2N1c190YWcsIGdlbmVfbmFtZSwgc2NhZmZvbGQsIHN0cmFuZCwgc3RhcnQsIGVuZCkgJT4lCiAgc3VtbWFyaXplKHN0cmFpbnNfcGVyX2dlbmUgPSBtaW4odW5pcXVlKHN0cmFpbnNfcGVyX2dlbmUpKSwgLmdyb3VwcyA9ICJkcm9wIikKcGxvdF9uaXJfZzEgPC0gZ2Vub21lX3Bsb3QoZGZfbmlyX2dlbmVzLCB4bGltID0gYygyNTc2LjMsIDI1ODUuOSksIHRpdGxlID0gImNociAyIikKCnByaW50KHBsb3RfbmlyX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4yNiwxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9uaXJfZzEsIHBvc2l0aW9uID0gYygwLjMsLTAuMSwwLjc1LDAuNCkpCmBgYAoKKipOTyByZWR1Y3Rhc2UgKE5PUikqKgoKUmVhY3Rpb246IE5PICsgUUgyIC0tXD4gTjJPICsgSDJPICsgUQoKRnJvbSBbQ3JhbW0gUiwgMjAwOF0oaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8xODk1Nzg2MS8pOiAiVGhlIGNhdGFseXRpYyBzdWItdW5pdCAoTm9yQikgb2YgYWxsIE5PUnMgdGhhdCBoYXZlIGJlZW4gY2hhcmFjdGVyaXplZCB0byBkYXRlIGNvbnRhaW5zIG9uZSBoaWdoLXNwaW4gaGVtZSBiIGFuZCBhIGJpbnVjbGVhciBjYXRhbHl0aWMgY2VudGVyIG9mIGEgbG93LXNwaW4gaGVtZSBiIGFuZCBhIG5vbi1oZW1lIGlyb24uIFRoZSBiZXN0IGludmVzdGlnYXRlZCBOT1JzIGFyZSBoZXRlcm9kaW1lcnMgdGhhdCBjb250YWluLCBpbiBhZGRpdGlvbiB0byBOb3JCLCBhIGhlbWUgYy1jb250YWluaW5nIHN1YnVuaXQgTm9yQyB3aGljaCBjaGFubmVscyBsZWN0cm9ucyBmcm9tIHRoZSBwaHlzaW9sb2dpY2FsIGVsZWN0cm9uIGRvbm9yIGN5dG9jaHJvbWUgYyB0byBOb3JCLiIKCmBgYHtyLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KZGZfbm9yIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIodGltZSA9PSA4LCBncmVwbCgibm9yIiwgZ2VuZV9uYW1lKSkgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IHN0cmlfZXh0cmFjdF9maXJzdF9yZWdleChnZW5lX25hbWUsICJub3IoW0EtWjAtOV0rKT8iKSkKcGxvdF9ub3JfZml0IDwtIGhlYXRtYXBfZml0bmVzcyhkZl9ub3IpCgojIHBsb3QgZ2Vub21pYyBsb2NhdGlvbnMKZGZfbm9yX2dlbmVzIDwtIGRmX25vciAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpCnBsb3Rfbm9yX2cxIDwtIGdlbm9tZV9wbG90KGRmX25vcl9nZW5lcywgeGxpbSA9IGMoMjU2LjQsIDI2Mi4xKSwgdGl0bGUgPSAicEhHMSIpCgpwcmludChwbG90X25vcl9maXQsIHBvc2l0aW9uID0gYygwLDAuMjUsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3Rfbm9yX2cxLCBwb3NpdGlvbiA9IGMoMC4zLC0wLjEsMC43NSwwLjQpKQpgYGAKCioqTk9TIChuaXRyb3VzIG94aWRlKSByZWR1Y3Rhc2UqKgoKUmVhY3Rpb246IE4yTyArIFFIMiAtLVw+IE4yICsgSDJPICsgUQoKVGhlIE5PUyBvZiBSLiBldXRyb3BoYSBIMTYgaGFzIG5vdCBiZWVuIGludmVzdGlnYXRlZCBvbiB0aGUgYmlvY2hlbWljYWwgbGV2ZWwuIEdlbmVzIGZvciBOT1MgYXJlIGxvY2F0ZWQgYWRqYWNlbnQgdG8gdGhlIG5vciBnZW5lcyBvbiBwSEcxLiBOb3NDIChQSEcyNTMpIG1pZ2h0IGJlIHRoZSBjeXQgYyB0aGF0IGlzIHRoZSBlLSBkb25vciBmb3IgTk9TLiBUaGUgbm9zQyBLTyBpcyBlbnJpY2hlZCBvbiBmb3JtYXRlLCBpLmUuIGdyb3dzIGJldHRlciB0aGFuIFdULiBJcyBub3NDIHRha2luZyBlLSBhd2F5IGZyb20gZm9ybWF0ZS1mZWQgRVRDPwoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA0fQpkZl9ub3MgPC0gZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcih0aW1lID09IDgsIGdyZXBsKCJub3MiLCBnZW5lX25hbWUpKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gc3RyaV9leHRyYWN0X2ZpcnN0X3JlZ2V4KGdlbmVfbmFtZSwgIm5vcyhbQS1aMC05XSspPyIpKQpwbG90X25vc19maXQgPC0gaGVhdG1hcF9maXRuZXNzKGRmX25vcykKCiMgcGxvdCBnZW5vbWljIGxvY2F0aW9ucwpkZl9ub3NfZ2VuZXMgPC0gZGZfbm9zICU+JSBncm91cF9ieShsb2N1c190YWcsIGdlbmVfbmFtZSwgc2NhZmZvbGQsIHN0cmFuZCwgc3RhcnQsIGVuZCkgJT4lCiAgc3VtbWFyaXplKHN0cmFpbnNfcGVyX2dlbmUgPSBtaW4odW5pcXVlKHN0cmFpbnNfcGVyX2dlbmUpKSwgLmdyb3VwcyA9ICJkcm9wIikKcGxvdF9ub3NfZzEgPC0gZ2Vub21lX3Bsb3QoZGZfbm9zX2dlbmVzLCB4bGltID0gYygyNjEuMSwgMjcxLjkpLCB0aXRsZSA9ICJwSEcxIikKCnByaW50KHBsb3Rfbm9zX2ZpdCwgcG9zaXRpb24gPSBjKDAsMC4yNSwxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9ub3NfZzEsIHBvc2l0aW9uID0gYygwLjIyLC0wLjEsMC44NSwwLjQpKQpgYGAKClRoZSBmb2xsb3dpbmcgc2VjdGlvbiBzaW1wbHkgcGxvdHMgYWxsIG5pdHJhdGUgcmVzcGlyYXRpb24gbW9kdWxlcyBvbiBvbmUgY2FudmFzLgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNH0KcGxvdF9uaXRyYXRlX2FsbCA8LSBiaW5kX3Jvd3MoZGZfbmFyLCBkZl9ub3IsIGRmX25vcywgZGZfbmlyKSAlPiUKICBtdXRhdGUoZ2VuZV9uYW1lID0gZmFjdG9yKGdlbmVfbmFtZSwgYygKICAgIHBhc3RlMCgibmFyIiwgYygiWDEiLCAiTDEiLCAiSzEiLCAiSzIiLCAiRzEiLCAiSDEiLCAiSTEiLCAiWDIiLCAiTDIiLCAiRzIiLCAiSDIiLCAiSTIiLCAiSzMiLCAiSzUiKSksCiAgICBwYXN0ZTAoIm5hcCIsIGMoIkEiLCAiQiIsICJDIiwgIkQiKSksIHBhc3RlMCgibmFzIiwgYygiRCIsICJFIikpLAogICAgcGFzdGUwKCJuaXIiLCBjKCJTIiwgIkMiLCAiRiIsICJEIiwgIkoiLCAiTiIsICJFIikpLAogICAgcGFzdGUwKCJub3IiLCBjKCJBIiwgIkIiLCAiUjEiLCAiQTIiLCAiQjIiLCAiUjIiKSksCiAgICBwYXN0ZTAoIm5vcyIsIGMoIkwiLCAiWSIsICJGIiwgIkQiLCAiUiIsICJaIiwgIkMiLCAiWCIpKQogICkpKSAlPiUKICBoZWF0bWFwX2ZpdG5lc3MoKQoKcHJpbnQocGxvdF9uaXRyYXRlX2FsbCwgcG9zaXRpb24gPSBjKDAsMC4yMywxLDEuMDUpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9uYXJfZzEsIHBvc2l0aW9uID0gYygwLC0wLjEsMC4zNSwwLjQpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9uaXJfZzEsIHBvc2l0aW9uID0gYygwLjMzLC0wLjEsMC41OCwwLjQpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9ub3JfZzEsIHBvc2l0aW9uID0gYygwLjU2LC0wLjEsMC43MiwwLjQpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9ub3NfZzEsIHBvc2l0aW9uID0gYygwLjcwLC0wLjEsMC45NiwwLjQpLCBtb3JlID0gVFJVRSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ2hpZGUnfQpzdmcoZmlsZW5hbWUgPSAiLi4vZmlndXJlcy9maWd1cmVfbml0cmF0ZV9yZXNwLnN2ZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDQpCnByaW50KHBsb3Rfbml0cmF0ZV9hbGwsIHBvc2l0aW9uID0gYygwLDAuMjMsMSwxLjA1KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbmFyX2cxLCBwb3NpdGlvbiA9IGMoMCwtMC4xLDAuMzUsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbmlyX2cxLCBwb3NpdGlvbiA9IGMoMC4zMywtMC4xLDAuNTgsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3Rfbm9yX2cxLCBwb3NpdGlvbiA9IGMoMC41NiwtMC4xLDAuNzIsMC40KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3Rfbm9zX2cxLCBwb3NpdGlvbiA9IGMoMC43MCwtMC4xLDAuOTYsMC40KSwgbW9yZSA9IFRSVUUpCmRldi5vZmYoKQpgYGAKCiMjIENvbXBhcmlzb24gb2Ygbml0cmF0ZSByZXNwaXJhdGlvbiBjb25kaXRpb25zCgotICAgd2UgaGF2ZSB0d28gZGlmZmVyZW50IG5pdHJhdGUgcmVzcGlyYXRpb24gY29uZGl0aW9ucywgY29udGludW91cyBhbmQgcHVsc2VkCi0gICBsb3cgZGVwbGV0aW9uIG9mIG5pdHJhdGUvbml0cml0ZS9uaXRyb3VzIHJlc3BpcmF0aW9uIG11dGFudHMgcHJvYmFibHkgZHVlIHRvIGNvbnN0YW50IE5PMyBzdXBwbHkKCmBgYHtyLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNn0KZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihzdWJzdHJhdGUgPT0gIm5pdHJhdGUiLCB0aW1lID09IDgsICFpcy5uYShnZW5lX25hbWUpKSAlPiUKICBzZWxlY3QoZ2VuZV9uYW1lLCBjb25kaXRpb24sIG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNvbmRpdGlvbiwgdmFsdWVzX2Zyb20gPSBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4pICU+JQogIG11dGF0ZSgKICAgIGRmaXQgPSBwdWxzZSAtIGNvbnRpbnVvdXMsCiAgICBzaWduaWZpY2FudCA9ICFiZXR3ZWVuKGRmaXQsIHF1YW50aWxlKGRmaXQsIHByb2JzID0gYygwLjAwMyksIG5hLnJtID0gVFJVRSksCiAgICAgIHF1YW50aWxlKGRmaXQsIHByb2JzID0gYygwLjk5NyksIG5hLnJtID0gVFJVRSkpKSAlPiUKICAKICAjIHBsb3QKICB4eXBsb3QoY29udGludW91cyB+IHB1bHNlLCBkYXRhID0gLiwgZ3JvdXBzID0gc2lnbmlmaWNhbnQsCiAgICBsYWJlbHMgPSAuW1siZ2VuZV9uYW1lIl1dLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgY29sID0gY3VzdG9tX2NvbG9ycywKICAgIHhsaW0gPSBjKC05LCAzKSwgeWxpbSA9IGMoLTksIDMpLAogICAgeGxhYiA9ICJOaXRyYXRlIHJlc3BpcmF0aW9uIChQKSIsIHlsYWIgPSAiTml0cmF0ZSByZXNwaXJhdGlvbiAoQykiLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCBsYWJlbHMsIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC5hYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSBncmV5KDAuNSksIGx0eSA9IDIsIHNpemUgPSAwLjgpCiAgICAgIHBhbmVsLmFibGluZShhID0gNCwgYiA9IDEsIGNvbCA9IGdyZXkoMC41KSwgbHR5ID0gMiwgc2l6ZSA9IDAuOCkKICAgICAgcGFuZWwuYWJsaW5lKGEgPSAtNCwgYiA9IDEsIGNvbCA9IGdyZXkoMC41KSwgbHR5ID0gMiwgc2l6ZSA9IDAuOCkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIC4uLikKICAgICAgcGFuZWwucmVwZWxsYWJlbHMoeCwgeSwgbGFiZWxzLCBjZXggPSAwLjYsCiAgICAgICAgc2VsZWN0ZWQgPSAuW1sic2lnbmlmaWNhbnQiXV0sCiAgICAgICAgZHJhd19ib3ggPSBUUlVFLCBib3hfZmlsbCA9ICJ3aGl0ZSIsIGJveF9saW5lID0gVFJVRSwgLi4uKQogICAgfQogICkKYGBgCgojIyBOb24taHlkcm9nZW5hc2UgZ2VuZXMgaW1wb3J0YW50IGZvciBIMiBmaXRuZXNzCgpEaWZmZXJlbnQgZ2VuZSBjbHVzdGVycyBhcHBlYXIgYmFzZWQgb24gdGhlIGZpdG5lc3MgcGF0dGVybiBpbiBkaWZmZXJlbnQgY29uZGl0aW9ucy4gQ2x1c3RlcnMgc3BlY2lmaWMgZm9yIGxpdGhvYXV0b3Ryb3BoaWMgbWV0YWJvbGlzbSBhcmUgcGFydGljdWxhcmx5IGludGVyZXN0aW5nLiBXZSBjYW4gYWRkIHRoZSBjbHVzdGVyIElEcyB0byB0aGUgbWFpbiBkYXRhIGZyYW1lLCBhbmQgaW52ZXN0aWdhdGUgZml0bmVzcy4gT3Igc2ltcGx5IHNlbGVjdCBnZW5lcyB0aGF0IHNob3cgZGVwbGV0aW9uIG9ubHkgZm9yIHRoZSBoeWRyb2dlbiBtZXRhYm9saXppbmcgY29uZGl0aW9uLgoKYGBge3J9CmRmX2ZpdG5lc3Nfc3VtbWFyeSA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgbGVmdF9qb2luKGJ5ID0gImxvY3VzX3RhZyIsCiAgICBlbmZyYW1lKGN1dHJlZW9yZChtYXRfY2x1c3RlciwgayA9IG5fY2x1c3RlcnMpLCAibG9jdXNfdGFnIiwgImNsdXN0ZXIiKQogICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDQuNX0KZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcih0aW1lID09IDgsICFzdHJfZGV0ZWN0KGdlbmVfbmFtZSwgImhveHxoeXAiKSkgJT4lCiAgbXV0YXRlKGh5ZF9lc3NlbnRpYWwgPSBjYXNlX3doZW4oCiAgICBzdWJzdHJhdGUgPT0gImh5ZHJvZ2VuIiAmIG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiA8PSAtMiB+IFRSVUUsCiAgICBzdWJzdHJhdGUgIT0gImh5ZHJvZ2VuIiAmIG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiA+PSAtMiB+IFRSVUUsCiAgICBUUlVFIH4gRkFMU0UKICApKSAlPiUgCiAgZ3JvdXBfYnkobG9jdXNfdGFnKSAlPiUKICBmaWx0ZXIoc3VtKGh5ZF9lc3NlbnRpYWwpID09IDkgfAogICAgbG9jdXNfdGFnICVpbiUgYygiSDE2X0EwMzI1IiwgIkgxNl9BMDMyNiIpKSAlPiUKICB1bmdyb3VwICU+JSBhcnJhbmdlKGxvY3VzX3RhZykgJT4lCiAgbXV0YXRlKGdlbmVfbmFtZSA9IGZhY3RvcihnZW5lX25hbWUsIHVuaXF1ZShnZW5lX25hbWUpKSkgJT4lCiAgbXV0YXRlKG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiA9IG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiAlPiUKICAgIHJlcGxhY2UoLiwgLiA8IC02LCAtNikgJT4lIHJlcGxhY2UoLiwgLiA+IDYsIDYpKSAlPiUKICBoZWF0bWFwX2ZpdG5lc3MKYGBgCgotICAgKipwdHNJICsgcHRzSCoqIC0gYWNjb3JkaW5nIHRvIGRhdGFiYXNlcywgYSBjbGVhciBoaXQgZm9yIGEgUEVQLWRlcGVuZGVudCBzdWdhciBQVFMgc3lzdGVtLiBUaGlzIGNhbid0IGJlIHRydWUgZm9yICpDLiBuZWNhdG9yKiBvdGhlcndpc2UgaXQgd291bGQgbm90IHNob3cgdGhlIGZhbWlsaWFyIHBhdHRlcm4gb2YgZGVwbGV0aW9uIG9uIGh5ZHJvZ2VuIGFuZCBncm93dGggYmVuZWZpdCBvbiBvdGhlciBzdWJzdHJhdGVzLiBUaGlzIFBUUyBzeXN0ZW0gbXVzdCBiZSBpbXBsaWNhdGVkIGluIGh5ZHJvZ2VuIG1ldGFib2xpc20sIHByb2JhYmx5IGEgdHJhbnNwb3J0ZXI/IFRoZSBnZW5lcyBkb3duc3RyZWFtIG9mIHB0c0lIIGRvIG5vdCBzZWVtIHRvIGJlIGFmZmVjdGVkIChIMTZfQTAzMjcgdG8gSDE2X0EwMzI5KS4KLSAgICoqaGxkRCoqIChIMTZfQTA4MDQpIC0gQURQLUwtZ2x5Y2Vyby1iZXRhLUQtbWFubm8taGVwdG9zZS02LWVwaW1lcmFzZSwgaW52b2x2ZWQgaW4gTFBTIHN1Z2FyIHBob3NwaGF0ZSBzeW50aGVzaXMuIE5vIG9idmlvdXMgY29ubmVjdGlvbiB0byBoeWRyb2dlbiBtZXRhYm9saXNtLgotICAgKipnbG5FKiogKEgxNl9BMTEyNykgLSBCaWZ1bmN0aW9uYWwgZ2x1dGFtaW5lIHN5bnRoZXRhc2UgYWRlbnlseWx0cmFuc2ZlcmFzZS4gSW52b2x2ZWQgaW4gdGhlIHJlZ3VsYXRpb24gb2YgZ2x1dGFtaW5lIHN5bnRoZXRhc2UgR2xuQS4gVHJhbnNmZXJzIG9yIHJlbW92ZXMgYWRlbnlseWwtcmVzaWR1ZXMgdG8gYW5kIGZyb20gR2xuQSwgdGhlcmVieSByZWd1bGF0aW5nIE4gdXB0YWtlIHRocm91Z2ggR2xuQS4gTm8gb2J2aW91cyBjb25uZWN0aW9uIHRvIGh5ZHJvZ2VuIG1ldGFib2xpc20uIE9ubHkgMSBtdXRhbnQgaW4gbGlicmFyeS4KLSAgICoqSDE2X0EyNjkyKiogLSB1bmNoYXJhY3Rlcml6ZWQgbWVtYnJhbmUgcHJvdGVpbi4gSXMgbmV1dHJhbCBpbiBhbGwgb3RoZXIgY29uZGl0aW9ucywganVzdCBhcyBhcmUgYWxsIHN1cnJvdW5kaW5nIGdlbmVzIChIMTZfQTI2OVswLTldKS4gU21hbGwsIDE0MSBBQSwgcG90ZW50aWFsIGNhcmJvbmljIGFuaHlkcmFzZSBvciB0cmFuc3BvcnRlcj8KLSAgICoqYm9sQSoqIChIMTZfQTM0MTkpIC0gUHJlZGljdGVkIHRyYW5zY3JpcHRpb25hbCByZWd1bGF0b3IsIG5vIGtub3duIGRvbWFpbnMgb3IgcHVibGlzaGVkIGZ1bmN0aW9ucy4gT25seSAxIG11dGFudCBpbiBsaWJyYXJ5LgotICAgKip5YWRHKiogKEgxNl9BMzQyMSkgU2VwYXJhdGVkIGJ5IG9ubHkgMSBnZW5lICh5YWRILCBIMTZfQTM0MjApIGZyb20gdGhlIHByZXZpb3VzIGhpdCwgc2hvd3MgdmVyeSBzcGVjaWZpYyBkZXBsZXRpb24gZm9yIGh5ZHJvZ2VuLiA3LTggbXV0YW50cyBxdWFudGlmaWVkLCBhbm5vdGF0ZWQgYXMgQUJDIHRyYW5zcG9ydGVyLCBBVFBhc2UgZnVuY3Rpb24uIFlhZEggaXMgdGhlIHBlcm1lYXNlIHBhcnRuZXIgb2YgdGhlIDIgc3VidW5pdHMsIGhvd2V2ZXIgZG9lcyBub3Qgc2hvdyBkZXBsZXRpb24uIENPRyBwcm9jZXNzICdkZWZlbnNlJyBiZWNhdXNlIGl0IHN1cHBvc2VkbHkgaXMgYWN0aXZlIGFzIGFudGktZHJ1ZyBlZmZsdXggcHVtcC4KLSAgICoqSDE2X0IxNjAzKiogLSBBQkMtdHlwZSB0cmFuc3BvcnRlciwgQVRQYXNlIGNvdXBsZWQgdHJhbnNtZW1icmFuZSB0cmFuc3BvcnRlci4gU3Ryb25nIGRlcGxldGlvbiBvbiBoeWRyb2dlbiBvbmx5LiBBbGwgc3Vycm91bmRpbmcgZ2VuZXMgYXJlIG5ldXRyYWwgdG8gZml0bmVzcy4gT25seSAxIG11dGFudCBpbiBsaWJyYXJ5LiBBIGNhbmRpZGF0ZSBmb3IgYSBDTzIvSENPMy0gdHJhbnNwb3J0ZXI/IEFsaWducyBiZXN0IHdpdGggYSBsb3Qgb2YgZGlmZmVyZW50IEFCQyB0cmFuc3BvcnRlcnMsIHdpdGggc3Blcm1pZGluZS9wdXRyZXNjaW5lIHRyYW5zcG9ydGVycyBiZXN0IGhpdHMuCgojIyBDTzIgdHJhbnNwb3J0ZXIvY2FyYm9uaWMgYW5oeWRyYXNlIGhvbW9sb2dzCgpBbGwgQ0FzIHdpdGggcXVhbnRpZmllZCBmaXRuZXNzIGFyZSBuZXV0cmFsIGR1cmluZyBsaXRob2F1dG90cm9waGljIGdyb3d0aCAoSDE2X0ExMTkyIC0gKmNhZyosIEgxNl9CMjQwMyAtICpjYWEqLCBIMTZfQjIyNzAgLSAqY2FuMiopLiBPbmx5IEgxNl9BMDE2OSAoKmNhbiopIGlzIHN0cmljdGx5IGVzc2VudGlhbCwgbm8gbXV0YW50cyBhcmUgYXZhaWxhYmxlLiBUaGlzIGlzIGRpZmZlcmVudCB0byB0aGUgcmVzdWx0cyBmcm9tIFtHYWkgZXQgYWwuLCBBTUIgRXhwcmVzcywgMjAxNF0oaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9hcnRpY2xlLzEwLjExODYvMjE5MS0wODU1LTQtMikgdGhhdCBmb3VuZCB0d28gZXNzZW50aWFsIENBcywgKmNhbiogYW5kICpjYWEqOgoKIkFsbCBmb3VyIHB1cmlmaWVkIENBcyB3ZXJlIGNhcGFibGUgb2YgcGVyZm9ybWluZyB0aGUgaW50ZXJjb252ZXJzaW9uIG9mIENPMiBhbmQgSENPMy0tIFsuLi5dIERlbGV0aW9uIG9mICpjYW4qIGFmZmVjdGVkIHRoZSBncm93dGggb2YgUi4gZXV0cm9waGE7IGhvd2V2ZXIgdGhlIGdyb3d0aCBkZWZlY3QgY291bGQgYmUgY29tcGVuc2F0ZWQgYnkgYWRkaW5nIENPMiB0byB0aGUgY3VsdHVyZS4gRGVsZXRpb24gb2YgKmNhYSosIGVuY29kaW5nIGFuIGFscGhhLUNBLCBoYWQgdGhlIHN0cm9uZ2VzdCBkZWxldGVyaW91cyBpbmZsdWVuY2Ugb24gY2VsbCBncm93dGguIi4KCkFsc28gW0t1c2lhbiBldCBhbC4sIEogQmFjLCAyMDAyXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMxMzUzMTQvKSByZXBvcnQgdGhlIGVzc2VudGlhbGl0eSBvZiAqY2FuKiBmb3IgbGl0aG9hdXRvdHJvcGhpYyBncm93dGguICpDYWEqIGZpdG5lc3Mgd2FzIHF1YW50aWZpZWQgaW4gdGhlIGxpYnJhcnkgd2l0aCAxMSBtdXRhbnRzLCB5ZXQgZG9lcyBub3Qgc2hvdyBhbnkgcGhlbm90eXBlIG9uIGFueSBzdWJzdHJhdGUuIFRoZSByZXN1bHRzIGluIEdhaSBldCBhbC4gYXJlIHNvbWV3aGF0IGNvbnRyYWRpY3RvcnksIGFzIHRoZSAqY2FhKiBjb21wbGV0aW9uIHRlc3QgaW4gYSBxdWFkcnVwbGUtQ0EgbXV0YW50IGhhZCBubyBiZW5lZmljaWFsIGVmZmVjdCBvbiBncm93dGguCgpBbHRvZ2V0aGVyLCBubyBzcGVjaWZpYyBiaWNhcmJvbmF0ZSB0cmFuc3BvcnRlcnMgYXJlIGFubm90YXRlZCBpbiAqQy4gbmVjYXRvciouIEhvd2V2ZXIsIGltcG9ydGFudCBiaWNhcmJvbmF0ZSAoSENPMyspIG9yIENPMiB0cmFuc3BvcnRlcnMga25vd24gZnJvbSBlLmcuIGN5YW5vYmFjdGVyaWEgKCpTeW5lY2hvY3lzdGlzKiBzcC4gUENDIDY4MDMpIGNvdWxkIGJlIHVzZWQgdG8gc2VhcmNoIGZvciBob21vbG9nb3VzIGdlbmVzIGluICpDLiBuZWNhdG9yKi4gVGhlIGZvbGxvd2luZyBDTzIvSENPMysgdHJhbnNwb3J0ZXJzIGFyZSBrbm93biBpbiAqU3luZWNob2N5c3Rpcyo6CgotICAgKipCaWNBKiogKHNsbDA4MzQpOiBjb25zdGl0dXRpdmUgaGlnaC1mbHV4LCBsb3ctYWZmaW5pdHkgTmErL0hDTzMrIHN5bXBvcnQKLSAgICoqU2J0QSoqIChzbHIxNTEyKTogaW5kdWNpYmxlIGxvdy1mbHV4LCBoaWdoLWFmZmluaXR5IE5hKy9IQ08zKyBzeW1wb3J0Ci0gICAqKkJDVDEqKiAoY21wQUJDRCBvcGVyb24vc2xyMDA0MC00NCk6IGluZHVjaWJsZSBoaWdoLWFmZmluaXR5LCBBVFAtZGVwZW5kZW50IHVuaXBvcnQKLSAgICoqTkRIKiogKG51byBvcGVyb24vKTogYWxsIGdlbmVzIG9mIHRoaXMgb3Blcm9uIGFyZSBlc3NlbnRpYWwgaW4gKkMuIG5lY2F0b3IqLCBubyBjb25kLiBmaXRuZXNzCgpUaGUgZmlyc3QgdGhyZWUgb2YgdGhlc2UgZ2VuZXMgd2VyZSBibGFzdGVkIGFnYWluc3QgdGhlIGdlbm9tZSBvZiAqQy4gbmVjYXRvciouIFRoZSBmaWd1cmUgc2hvd3MgYWxpZ25tZW50IHNjb3JlcyBmb3IgdGhlIHRvcCAyMCBoaXRzLgoKYGBge3IsIGZpZy53aWR0aCA9IDYuNSwgZmlnLmhlaWdodCA9IDN9CmRmX2NvMl90cmFuc3BvcnRfYWxpZ24gPC0gcmVhZF90c3YoIi4uL2RhdGEvYWxpZ25tZW50cy9DTzJfdHJhbnNwb3J0ZXJzLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lCiAgZ3JvdXBfYnkodGFyZ2V0X25hbWUpICU+JQogIG11dGF0ZShyYW5rID0gc2VxX2Fsb25nKHVuaXByb3QpKQogIAogIHh5cGxvdChzY29yZSArIC1sb2cxMChlX3ZhbHVlKSB+IHJhbmsgfCB0YXJnZXRfbmFtZSwgZGZfY28yX3RyYW5zcG9ydF9hbGlnbiwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIHhsaW0gPSBjKC0xLCAyMSksCiAgICB4bGFiID0gInJhbmsiLCB5bGFiID0gZXhwcmVzc2lvbigiLWxvZyJbMTBdKiIgZSB2YWx1ZSwgc2NvcmUiKSwKICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLCBsd2QgPSAwLAogICAgc2NhbGVzID0gbGlzdChhbHRlcm5hdGluZyA9IEZBTFNFKSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgeiwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwuYmFycGxvdCh4LCB5LCBld2lkdGggPSAwLjUsIGZpbGxfYWxwaGEgPSAwLjcsIC4uLikKICAgICAgcGFuZWwua2V5KC4uLiwgcG9pbnRzID0gRkFMU0UsIGNvcm5lciA9IGMoMC45NywgMC45NykpCiAgICB9CiAgKQpgYGAKCkJpY0EgYW5kIGNtcEIgc2VlbSB0byBoYXZlIHNvbWUgdmVyeSBzaW1pbGFyIGhvbW9sb2dzIGluIHRoZSAqQy4gbmVjYXRvciogZ2Vub21lLiBIb3dldmVyLCBub25lIG9mIHRoZXNlIGhvbW9sb2dzIGhhcyBhIGNsZWFyIHBoZW5vdHlwZSByZWxhdGVkIHRvIGh5ZHJvZ2VuIG1ldGFib2xpc20uCgpgYGB7ciwgZmlnLndpZHRoID0gOS41LCBmaWcuaGVpZ2h0ID0gMy41fQpkZl9jbzJfdHJhbnNwb3J0X2FsaWduICU+JQogIGZpbHRlcihyYW5rIDw9IDIwKSAlPiUgCiAgc2VsZWN0KHVuaXByb3QsIHRhcmdldF9uYW1lLCByYW5rKSAlPiUKICBpbm5lcl9qb2luKGRmX2ZpdG5lc3Nfc3VtbWFyeSwgYnkgPSAidW5pcHJvdCIpICU+JSB1bmdyb3VwICU+JQogIG11dGF0ZShub3JtX2dlbmVfZml0bmVzc19tZWRpYW4gPSBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4gJT4lCiAgICByZXBsYWNlKC4sIC4gPCAtNiwgLTYpICU+JSByZXBsYWNlKC4sIC4gPiA2LCA2KSkgJT4lCiAgaGVhdG1hcF9maXRuZXNzCmBgYAoKIyMgTWFpbiBjb25jbHVzaW9ucwoKLSAgIE1vQ28gY29mYWN0b3IgaXMgaW1wb3J0YW50IGZvciBncm93dGggb24gZm9ybWF0ZSAqYW5kKiBuaXRyYXRlIHJlc3BpcmF0aW9uLCBidXQgbm90IGZvciBncm93dGggb24gaHlkcm9nZW4KLSAgIE1haW4gRkRIIGlzIFMtRkRIIGJvdGggaW4gdGVybXMgb2YgcHJvdGVpbiBhYnVuZGFuY2UsIGluZHVjaWJpbGl0eSwgYW5kIGVzc2VudGlhbGl0eQotICAgQWx0ZXJuYXRpdmUgUy1GREggb3Blcm9uICpmZHcqIGRvZXMgbm90IHBsYXkgYSByb2xsCi0gICBCb3RoIGh5ZHJvZ2VuYXNlcywgUy1IIGFuZCBtX0ggaGF2ZSBzaW1pbGFyIGZpdG5lc3MgcGVuYWx0eSBvbiBoeWRyb2dlbiB3aGVuIEtPZWQKLSAgIEh5ZHJvZ2VuYXNlIGdlbmVzLCBidXQgZXZlbiBtb3JlIHNvIG1hc3RlciByZWd1bGF0b3IgaG94QSBhbmQgSHlkcm9nZW5hc2UgcGxlaW90cm9weSAoaHlwKSBnZW5lcyBjb25mZXIgZml0bmVzcyBhZHZhbnRhZ2Ugd2hlbiBLT2VkIG9uIGFsbCBub24tbG9pdGhvYXV0b3Ryb3BoaWMgc3Vic3RyYXRlcwotICAgQ3l0b2Nocm9tZSByZWR1Y3Rhc2UgYmMxIGNvbXBsZXggKHFjckFCQykgaXMgcGFydGljdWxhcmx5IGltcG9ydGFudCBmb3IgZ3Jvd3RoIG9uIGZvcm1hdGUKLSAgIEJjMSBjb21wbGV4IHBsYXlzIG5vIHJvbGUgb24gbml0cmF0ZSwgdGhlcmVmb3JlIG5vIGNyb3NzIHRhbGsgKHdoaWxlIGEgYmMxIEtPIG11dGFudCB3YXMgZ3Jvd3RoLWRlZmljaWVudCBpbiBveHlnZW4tbGltaXRlZCBncm93dGggb24gbml0cmF0ZSAoR2FyZyBldCBhbC4sIDIwMTgpLgotICAgQmMxIGNvbXBsZXggYWNjZXB0cyByZWR1Y2VkIHF1aW5vbHMgYXMgZS0gZG9ub3IsIHB1bXBzIDQgSCsgLzIgZeKIkiB2aWEgcHJvdG9uLW1vdGl2ZSBRIGN5Y2xlIChxdWlub2w6Y3l0IGMgb3hpZG9yZWR1Y3Rpb24pLCBhbmQgcmVsZWFzZXMgcmVkdWNlZCBjeXRvY2hyb21lIEMgZS0gY2FycmllcnMuIE1haW4gY3l0b2Nocm9tZSBjb21wbGV4IGZvciBtb3N0IHN1YnN0cmF0ZXMgaW5jbHVkaW5nIGh5ZHJvZ2VuCi0gICBDYmIzLXR5cGUgY3l0b2Nocm9tZSBveGlkYXNlICgqY2NvKiBvcGVyb24pIGFsc28gaW1wb3J0YW50IGZvciBncm93dGggb24gZm9ybWF0ZSwgd2hpbGUgKmN0YSogb3Blcm9uIChhYTMgY29tcGxleCkgbW9yZSBpbXBvcnRhbnQgb24gZnJ1Y3Rvc2UgYW5kIHN1Y2NpbmF0ZQoKIyBDZW50cmFsIGNhcmJvbiBtZXRhYm9saXNtCgojIyBnZW5lLXJlYWN0aW9uIHJlbGF0aW9uc2hpcAoKVG8gc2hvdyAoY29uZGl0aW9uYWwpIGVzc2VudGlhbGl0eSBvZiBnZW5lcyB3aGljaCBhcmUgcmVsYXRlZCB0byBjZW50cmFsIG1ldGFib2xpYyByZWFjdGlvbnMsIHdlIG5lZWQgdG8gb2J0YWluIGEgdGFibGUgb2YgZ2VuZS1yZWFjdGlvbiByZWxhdGlvbnNoaXBzLgpTdWNoIGEgdGFibGUgd2FzIHVzZWQgaW4gb3VyIGVMaWZlIHBhcGVyLCBbSmFobiBldCBhbC4sIDIwMjFdKGh0dHBzOi8vZWxpZmVzY2llbmNlcy5vcmcvYXJ0aWNsZXMvNjkwMTkpLCBhbmQgd2FzIGV4cG9ydGVkIGZyb20gdGhlIGN1cmF0ZWQgZ2Vub21lIHNjYWxlIG1vZGVsIG9mICpDLiBuZWNhdG9yKi4KCi0gZG93bmxvYWQgZ2VuZS1yZWFjdGlvbiB0YWJsZQotIGFkZCBzb21lIGdlbmVzIG1hbnVhbGx5IHRoYXQgYXJlIG5vdCBtZXRhYm9saWMgcmVhY3Rpb25zIGJ1dCBpbnRlcmVzdGluZyByZWd1bGF0b3JzCi0gd2UgYWRkOiAKICAtIGBjYmJSYCAoYEgxNl9CMTM5NmApIGNiYiBvcGVyb24gdHJhbnNjcmlwdGlvbmFsIGFjdGl2YXRvcgogIC0gYHJlZ0FgIChgSDE2X0EwMjAyYCkgcmVzcG9uc2UgcmVndWxhdG9yLCAyLWNvbXAuIHN5c3RlbQogIC0gYHJlZ0JgIChgSDE2X0EwMjAzYCkga2luYXNlLCAyLWNvbXAuIHN5c3RlbQogIC0gYHJwb05gIChgSDE2X0EwMzg3YCkgU2lnbWEgNTQgUk5BLXBvbHltZXJhc2Ugc2lnbWEgZmFjdG9yCiAgLSBgaG94QWAgKGBQSEcwMTlgKSBob3hBIG1hc3RlciByZWd1bGF0b3IKCmBgYHtyfQp1cmxfcmVhY3Rpb25zIDwtIHVybCgiaHR0cHM6Ly9naXRodWIuY29tL20tamFobi9SLW5vdGVib29rLXJhbHN0b25pYS1wcm90ZW9tZS9yYXcvbWFpbi9kYXRhL2lucHV0L21vZGVsX3JlYWN0aW9ucy5jc3YiKQpkZl9yZWFjdGlvbnMgPC0gcmVhZF9jc3YodXJsX3JlYWN0aW9ucywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgcmVuYW1lKGxvY3VzX3RhZyA9IGdlbmVzKSAlPiUKICBhZGRfcm93KHJlYWN0aW9uX2lkID0gIlJlZ3VsYXRvcnMiLCBsb2N1c190YWcgPSAiSDE2X0IxMzk2LCBIMTZfQTAyMDIsIEgxNl9BMDIwMywgSDE2X0EwMzg3LCBQSEcwMTkiKQoKZGZfcmVhY3Rpb25zICU+JQogIGZpbHRlcighc3RyX2RldGVjdChyZWFjdGlvbl9pZCwgIl5FWF8iKSkgJT4lCiAgaGVhZCgpCmBgYAoKIyMgUGxvdCBjb25kaXRpb25hbCBmaXRuZXNzIGJyb2tlbiBkb3duIGJ5IENDTSBwYXRod2F5CgotIHVzZSB0aGUgc2FtZSBzZXQgb2YgZW56eW1lcyBhcyBpbiBbSmFobiBldCBhbC4sIDIwMjFdKGh0dHBzOi8vZWxpZmVzY2llbmNlcy5vcmcvYXJ0aWNsZXMvNjkwMTkpCi0gdXNpbmcgdGhlc2Ugc2V0cywgZXh0cmFjdCBmaXRuZXNzIGZyb20gcmVzdWx0cyB0YWJsZSBhbmQgcGxvdCBtaW5pZmlndXJlcwotIHRoZXNlIGNhbiBiZSBhcnJhbmdlZCBpbi9hcm91bmQgYSBtYXAgb2YgdGhlIGNlbnRyYWwgY2FyYm9uIG1ldGFib2xpc20gKENDTSkKLSByZWFjdGlvbnMgd2l0aCBzbGlnaHRseSBkaWZmZXJlbnQgc3Vic3RyYXRlcy9wcm9kdWN0cyBidXQgdGhhdCBhcmUgZ2VuZS13aXNlIGlkZW50aWNhbCBoYXZlIGJlZW4gcmVtb3ZlZAotIHRoZXNlIGFyZSBTVUNEaSwgQUNPTlQyLCBUS1QyLCBhbmQgUERIMyB3aGljaCBpcyBpZGVudGljYWwgdG8gQUtHREgKCmBgYHtyfQpsaXN0X2NjbV9lbnp5bWVzIDwtIGxpc3QoCiAgQ0JCID0gYygiUEdLIiwgIlRQSSIsICJHQVBEIiwgIkZCQSIsICJGQlAiLCAiVEtUMSIsICJUQWgiLCAiUlBFIiwgIlJQSSIsICJQUlVLIiwgIlJCUEMiKSwKICBFRCA9IGMoIlBHSSIsICJHNlBESDJyIiwgIlBHTCIsICJFREQiLCAiRURBIiksCiAgUFlSID0gYygiUEdNIiwgIkVOTyIsICJQWUsiLCAiUERIMSIsICJQREgyIiwgIlBDIiwgIlBQQyIsICJNRTEiLCAiTUUyIiwgIkNTIiksCiAgVENBID0gYygiQUNPTlQxIiwgIklDREh4IiwgIklDREh5ciIsICJBS0dESCIsICJTVUNPQVMiLCAiU1VDRDEiLCAiRlVNIiwgIk1ESCIsICJNQUxTIiksCiAgUkVHID0gYygiUmVndWxhdG9ycyIpCikKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMiwgZmlnLndpZHRoID0gMTQsIHdhcm5pbmcgPSBGQUxTRX0KIyBmaW5kIGdlbmVzIGZvciBtZXRhYm9saWMgcmVhY3Rpb25zCmxpc3RfcmVhY3Rpb24gPC0gbGlzdF9jY21fZW56eW1lcyAlPiUKICBlbmZyYW1lKG5hbWUgPSAicGF0aHdheSIsIHZhbHVlID0gInJlYWN0aW9uX2lkIikgJT4lCiAgdGlkeXI6OnVubmVzdChyZWFjdGlvbl9pZCkKCmxpc3RfZ2VuZXMgPC0gZGZfcmVhY3Rpb25zICU+JQogIHJpZ2h0X2pvaW4obGlzdF9yZWFjdGlvbiwgYnkgPSAicmVhY3Rpb25faWQiKSAlPiUKICBzZXBhcmF0ZV9sb25nZXJfZGVsaW0obG9jdXNfdGFnLCAiLCAiKSAlPiUKICBzZWxlY3QocGF0aHdheSwgcmVhY3Rpb25faWQsIGxvY3VzX3RhZykKCiMgZ2V0IGZpdG5lc3MgZm9yIHRoZXNlIGdlbmVzCmRmX2ZpdG5lc3NfY2NtIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIodGltZSA9PSA4KSAlPiUKICBpbm5lcl9qb2luKGxpc3RfZ2VuZXMsIGJ5ID0gImxvY3VzX3RhZyIpCgojIHBsb3QgaGVhdG1hcHMKcGxvdHNfY2NtIDwtIGRmX2ZpdG5lc3NfY2NtICU+JQogIGFycmFuZ2UocGF0aHdheSwgcmVhY3Rpb25faWQsIGxvY3VzX3RhZykgJT4lCiAgbXV0YXRlKAogICAgZ2VuZV9uYW1lID0gbG9jdXNfdGFnLAogICAgIyBnZW5lX25hbWUgPSBlZ2dOT0dfbmFtZSAlPiUKICAgICMgc3RyX2V4dHJhY3QoIlthLXpBLVowLTlfXSsiKSAlPiUKICAgICMgZmN0X2lub3JkZXIoKSwKICAgIGNvbmRfc2hvcnQgPSBjYXNlX21hdGNoKGNvbmRfc2hvcnQsCiAgICAgICJmb3JtYXRlIC0gQyIJfiAiRm9DIiwKICAgICAgImZydWN0b3NlIC0gQyIgfiAiRnJDIiwKICAgICAgIm5pdHJhdGUgLSBDIiB+ICJOaUMiLAogICAgICAic3VjY2luYXRlIC0gQyIJfiAiU3VDIiwKICAgICAgImZvcm1hdGUgLSBQIiB+ICJGb1AiLAogICAgICAiZnJ1Y3Rvc2UgLSBQIiB+ICJGclAiLAogICAgICAiaHlkcm9nZW4gLSBQIiB+ICJIeVAiLAogICAgICAibml0cmF0ZSAtIFAiCX4gIk5pUCIsCiAgICAgICJzdWNjaW5hdGUgLSBQIn4gIlN1UCIpICU+JQogICAgICBmYWN0b3IoLiwgdW5pcXVlKC4pW2MoMyw4LDcsMSw1LDQsOSwyLDYpXSksCiAgICBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4gPSBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4gJT4lCiAgICAgICAgICAgcmVwbGFjZSguLCAuIDwgLTYsIC02KSAlPiUgcmVwbGFjZSguLCAuID4gNiwgNikKICApICU+JQogIGdyb3VwX2J5KHBhdGh3YXksIHJlYWN0aW9uX2lkKSAlPiUKICBkcGx5cjo6Z3JvdXBfc3BsaXQoKSAlPiUKICBsYXBwbHkoZnVuY3Rpb24oZGYpIHsKICAgIGxldmVscGxvdCgKICAgICAgbm9ybV9nZW5lX2ZpdG5lc3NfbWVkaWFuIH4gZmN0X3Jldihjb25kX3Nob3J0KSAqIGZjdF9yZXYoZ2VuZV9uYW1lKSB8CiAgICAgICAgcmVhY3Rpb25faWQsIGRmLAogICAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLCBjb2xvcmtleSA9IEZBTFNFLAogICAgICBjb2wucmVnaW9ucyA9IGNvbG9yUmFtcFBhbGV0dGUoaGVhdF9jb2xzKSgyNSksCiAgICAgIGF0ID0gc2VxKC02LCA2LCAwLjUpLCBhc3BlY3QgPSAiaXNvIiwgeGxhYiA9ICIiLCB5bGFiID0gIiIsCiAgICAgIHNjYWxlcyA9IGxpc3QoYWx0ZXJuYXRpbmcgPSBGQUxTRSwgY2V4ID0gMC43LCB0Y2sgPSAwLAogICAgICAgIHggPSBsaXN0KHJvdCA9IDkwKSksCiAgICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLCBsd2QgPSAwLAogICAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIHosIC4uLikgewogICAgICAgIHBhbmVsLmxldmVscGxvdCh4LCB5LCB6LCAuLi4pCiAgICAgICAgcGFuZWwuYWJsaW5lKAogICAgICAgICAgdiA9IHNlcV9hbG9uZyh1bmlxdWUoeCkpICsgMC41LAogICAgICAgICAgaCA9IHNlcV9hbG9uZyh1bmlxdWUoeSkpICsgMC41LAogICAgICAgICAgY29sID0gIndoaXRlIiwKICAgICAgICAgIGx3ZCA9IDIKICAgICAgICApCiAgICAgIH0KICAgICkKICB9KQoKY293cGxvdDo6cGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxvdHNfY2NtLCBuY29sID0gNikKYGBgCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CnN2ZygiLi4vZmlndXJlcy9maWd1cmVfY2VudHJhbG1ldC5zdmciLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMikKY293cGxvdDo6cGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxvdHNfY2NtLCBuY29sID0gNikKZGV2Lm9mZigpCmBgYAoKIyBHcm93dGggYWR2YW50YWdlIG9mIEh5ZHJvZ2VuYXNlIG11dGFudHMKCiMjIERldGVybWluZSBtdXRhbnQgZ3Jvd3RoIHJhdGUgZnJvbSBjb21wZXRpdGlvbiBleHBlcmltZW50cwoKVGhlIG1haW4gbWVhc3VyZW1lbnQgdGhhdCB3YXMgb2J0YWluZWQgZnJvbSB0cmFuc3Bvc29uIGxpYnJhcnkgY29tcGV0aXRpb24gZXhwZXJpbWVudHMgaXMgdGhlIGZvbGQgY2hhbmdlLCBhbmQgdGhlIGZpdG5lc3Mgc2NvcmUgYXMgYSBzdW1tYXJ5IHN0YXRpc3RpYyB0aGVyZW9mLiBUaGUgZm9sZCBjaGFuZ2Ugb2YgYSBtdXRhbnQgc3ViLXBvcHVsYXRpb24gb3ZlciB0aW1lIGNhbiBhbHNvIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSByZWxhdGl2ZSBncm93dGggYWR2YW50YWdlIG92ZXIgb3RoZXIgc3RyYWlucy4gRm9yIHN1Y2ggYSBncm93dGggbW9kZWwsIHRoZSBvbmx5IHJlcXVpcmVkIGlucHV0IHBhcmFtZXRlcnMgYXJlIHRoZSBGQywgdGhlIGF2ZXJhZ2UgcG9wdWxhdGlvbiBncm93dGggcmF0ZSwgYW5kIHRoZSB0aW1lIGluIGhvdXJzLgoKJCQgRkMgPSAoMSAtIChcbXVfe3BvcH0gLSBcbXVfe211dH0pKV57dH0gJCQgUmUtYXJyYW5nZWQgdG8gb2J0YWluIHRoZSBtdXRhbnQgZ3Jvd3RoIHJhdGUuCgokJCBcbXVfe211dH0gPSAtKDEgLSBGQ157MS90fSkgKyBcbXVfe3BvcH0kJAoKQWxsIGlucHV0IHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlOgoKLSAgIMK1X3BvcCA9IDAuMSBoXF4tMSwga25vd24gZnJvbSBjaGVtb3N0YXRzCi0gICBGQyBmb3IgZWFjaCBtdXRhbnQvZ2VuZSBmcm9tIGxpYnJhcnkgY29tcGV0aXRpb24gZXhwZXJpbWVudHMgKCdmaXRuZXNzJyBpcyB0aGUgbm9ybWFsaXplZCBsb2cyIEZDKQotICAgdCA9IG5fZ2VuIHggKGxuIDIpLzAuMSAtIG51bWJlciBvZiBnZW5lcmF0aW9ucyAoMCwgOCwgMTYpIG11bHRpcGxpZWQgd2l0aCBnZW5lcmF0aW9uIHRpbWUgb2YgNi45MyBoCgpXZSBtYWtlIGEgZ2VuZXJhbGl6ZWQgZnVuY3Rpb24gdGhhdCBjYWxjdWxhdGVzIGdyb3d0aCByYXRlIChkaXMtKSBhZHZhbnRhZ2UuCgpgYGB7cn0KbXV0YW50X211IDwtIGZ1bmN0aW9uKGZvbGRfY2hhbmdlLCBwb3BfbXUsIHRpbWUsIGxvZzJfZmMgPSBGQUxTRSkgewogIGlmIChsb2cyX2ZjKSB7Zm9sZF9jaGFuZ2UgPSAyXmZvbGRfY2hhbmdlfQogIHJlc3VsdCA9IC0oMSAtIChmb2xkX2NoYW5nZV4oMS90aW1lKSkpICsgcG9wX211CiAgcmV0dXJuKHJlc3VsdCkKfQpgYGAKClRoZW4gc2VsZWN0IHRoZSBoeWRyb2dlbmFzZSBtdXRhbnRzIHdoZXJlIGFuIGVucmljaG1lbnQgd2FzIG9ic2VydmVkIGluIGhldGVyb3Ryb3BoaWMgY29uZGl0aW9ucy4KCmBgYHtyLCBmaWcud2lkdGggPSA2LjUsIGZpZy5oZWlnaHQgPSA2LjB9CmRmX2luY3JlYXNlZF9tdSA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKAogICAgZ3JlcGwoImhveFtLR1pNTE9RUlRWQUJDSk5GVVlIV0ldfGh5cFtCQ0RFRlhdMT8gfGh5cEEgUEhHMDEyIiwgZ2VuZV9uYW1lKSwgY29uZGl0aW9uID09ICJjb250aW51b3VzIiwKICAgIHN1YnN0cmF0ZSAlaW4lIGMoImZvcm1hdGUiLCAiZnJ1Y3Rvc2UiLCAic3VjY2luYXRlIikpICU+JQogIGZpbHRlcihsb2N1c190YWcgIT0gIlBIRzA2MyIpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBzdHJpX2V4dHJhY3RfZmlyc3RfcmVnZXgoZ2VuZV9uYW1lLCAiaG94W0tHWk1MT1FSVFZBQkNKTkZVWUhXSV18aHlwW0FCQ0RFRlhdIikpICU+JQogIG11dGF0ZShnZW5lX25hbWUgPSBmY3RfaW5vcmRlcihnZW5lX25hbWUpKQoKcGxvdF9pbmNyZWFzZWRfbXUgPC0geHlwbG90KG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiB+IHRpbWUgfCBnZW5lX25hbWUsIGRmX2luY3JlYXNlZF9tdSwKICAgIGdyb3VwcyA9IHN1YnN0cmF0ZSwgYXMudGFibGUgPSBUUlVFLCBsYXlvdXQgPSBjKDYsIDUpLAogICAgY29sID0gc3RkY29sWzI6NF0sIHhsYWIgPSAiZ2VuZXJhdGlvbnMiLCB5bGFiID0gImZpdG5lc3MiLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgdHlwZSA9IGMoImwiKSwKICAgIGF1dG8ua2V5ID0gbGlzdChjb2x1bW5zID0gMyksCiAgICBiZXR3ZWVuID0gbGlzdCh4ID0gMC41LCB5ID0gMC41KSwKICAgIHNjYWxlcyA9IGxpc3QoYWx0ZXJuYXRpbmcgPSBGQUxTRSksIGx3ZCA9IDIsCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLmFibGluZShoID0gMCwgY29sID0gZ3JleSgwLjUpLCBsdHkgPSAzLCBsd2QgPSAyKQogICAgICBwYW5lbC54eXBsb3QoeCwgeSwgLi4uKQogICAgfQogICkKCmRmX211dGFudF9tdSA8LSBkZl9pbmNyZWFzZWRfbXUgJT4lCiAgZmlsdGVyKHRpbWUgIT0gMCkgJT4lCiAgZ3JvdXBfYnkoZ2VuZV9uYW1lLCBzdWJzdHJhdGUpICU+JQogIG11dGF0ZShtdXRhbnRfbXUgPSBtdXRhbnRfbXUoCiAgICBmb2xkX2NoYW5nZSA9IG5vcm1fZ2VuZV9maXRuZXNzX21lZGlhbiwgCiAgICBwb3BfbXUgPSAwLjEsIHRpbWUgPSB0aW1lKihsb2coMikvMC4xKSwKICAgIGxvZzJfZmMgPSBUUlVFKSkgJT4lCiAgc2VsZWN0KGxvY3VzX3RhZywgdGltZSwgY29uZGl0aW9uLCBzdWJzdHJhdGUsCiAgICBub3JtX2dlbmVfZml0bmVzc19tZWRpYW4sIGdlbmVfbmFtZSwgY29uZF9zaG9ydCwgbXV0YW50X211KQoKcHJpbnQocGxvdF9pbmNyZWFzZWRfbXUpCmBgYAoKIyMgR3Jvd3RoIGFkdmFudGFnZSAqdmVyc3VzKiBwcm90ZWluIGNvc3QKClRoZSBtYWluIHF1ZXN0aW9uIGlzIGlmIHRoZSBvYnNlcnZlZCBncm93dGggYWR2YW50YWdlIGNhbiBiZSBwdXJlbHkgZXhwbGFpbmVkIGJ5IHRoZSBzYXZpbmcgb2YgZ2VuZSBleHByZXNzaW9uIGNvc3QuIEh5ZHJvZ2VuYXNlIGFuZCBzb21lIGFjY2Vzc29yeSBwcm90ZWlucyBhcmUgaGlnaGx5IGFidW5kYW50IGFuZCB0aGVyZWZvcmUgY2F1c2UgYSBzaWduaWZpY2FudCBjb3N0IHRvIHRoZSBjZWxsLiBJdCB3YXMgc2hvd24gaW4gbWFueSBvdGhlciBzdHVkaWVzIHRoYXQgcmVkdWNpbmcgZXhjZXNzL3VudXNlZCBwcm90ZWlucyBjYW4gaW5jcmVhc2UgZ3Jvd3RoIHJhdGUuIFRoaXMgaXMgYmFzZWQgb24gdGhlIG9ic2VydmF0aW9uIHRoYXQgdGhlIHByb3RlaW4gcG9vbCBpcyBsaW1pdGVkIGFuZCBjZWxscyBjYW4gb3B0aW1pemUgdGhlIHV0aWxpemF0aW9uIG9mIHRoaXMgbGltaXRlZCByZXNvdXJjZSBieSB0dW5pbmcgZ2VuZSBleHByZXNzaW9uIHRvd2FyZHMgaGlnaGx5IHV0aWxpemVkIGdlbmVzL3Byb3RlaW5zLgoKSW4gdGhlIG5leHQgc2VjdGlvbiwgZ2xvYmFsIHByb3RlaW4gYWJ1bmRhbmNlIGRhdGEgaXMgaW1wb3J0ZWQgdGhhdCB3YXMgb2J0YWluZWQgZnJvbSBxdWFudGl0YXRpdmUgTVMgZXhwZXJpbWVudHMuIE1TIGRhdGEgaXMgYXZhaWxhYmxlIGZvciB0aGUgdGhyZWUgY29uZGl0aW9ucyB1c2VkIGluIHRoZSBwcmV2aW91cyBzZWN0aW9uLCBjb250aW51b3VzIGdyb3d0aCBvbiBmcnVjdG9zZSwgc3VjY2luYXRlLCBhbmQgZm9ybWF0ZSBpbiBjaGVtb3N0YXRzIGF0IGRlZmluZWQgZ3Jvd3RoIHJhdGVzLgoKKipOb3RlOiBUaGUgZGF0YSBpcyBpbXBvcnRlZCBkaXJlY3RseSBmcm9tIHRoZSByZXNwZWN0aXZlIGdpdGh1YiByZXBvc2l0b3J5LCByZXF1aXJpbmcgaW50ZXJuZXQgY29ubmVjdGlvbioqLgoKYGBge3J9CmxvYWQodXJsKCJodHRwczovL2dpdGh1Yi5jb20vbS1qYWhuL1Itbm90ZWJvb2stcmFsc3RvbmlhLXByb3Rlb21lL2Jsb2IvbWFpbi9kYXRhL2lucHV0L1JhbHN0b25pYV9ldXRyb3BoYS5SZGF0YT9yYXc9dHJ1ZSIpKQpoZWFkKFJhbHN0b25pYV9ldXRyb3BoYVsxOjEwXSkKYGBgCgpUbyBhc3Nlc3MgcmVhbCBwcm90ZWluIGNvc3Qgb2YgYSBrbm9jay1vdXQsIGl0IGlzIGltcG9ydGFudCB0byBjb25zaWRlciB0aGF0IEtPIGJ5IHRyYW5zcG9zb24gaW50ZWdyYXRpb24gd2lsbCBoYXZlIGFuIGVmZmVjdCBvbiB0aGUgZG93bnN0cmVhbSBnZW5lIGV4cHJlc3Npb24gdG9vLCBlZmZlY3RpdmVseSBkaXNydXB0aW5nIHRyYW5zY3JpcHRpb24vdHJhbnNsYXRpb24gb2YgdGhlIGVudGlyZSBvcGVyb24gZG93bnN0cmVhbSBvZiB0aGUgaW50ZWdyYXRpb24gc2l0ZS4KCklmIHdlIGFzc3VtZSB0aGF0IGVhY2ggS08ga25vY2tzIG91dCB0aGUgZ2VuZSBleHByZXNzaW9uIG9mIGFsbCBjb25zZWN1dGl2ZSBnZW5lcyBvZiB0aGUgb3Blcm9uLCB3ZSBuZWVkIHRvIHN1bSB1cCBwcm90ZWluIGNvc3QgZm9yIHRoZXNlIGFmZmVjdGVkIGdlbmUgc2V0czsgd2UgZ2VuZXJhdGUgYSAqKmJpbmFyeSBtYXRyaXgqKiBvZiBhc3NvY2lhdGlvbnMgZm9yIGVhY2ggS08gd2l0aCBhIG51bWJlciBvZiBhZmZlY3RlZCBnZW5lcyAoMCA9IEZBTFNFLCAxID0gVFJVRSksIGFuZCBtdWx0aXBseSB3aXRoIHByb3RlaW4gbWFzcy4gSGVyZSwgd2UgbmVlZCB0byB0ZXN0IGRpZmZlcmVudCBhc3N1bXB0aW9ucy4gVGhlIGNhbm9uaWNhbCByZWd1bGF0aW9uIG9mIHRoZSBob3gvaHlwIG9wZXJvbiBoYXBwZW5zIHZpYSBgaG94QWAgdHJhbnNjcmlwdGlvbmFsIHJlZ3VsYXRvciwgYGhveEJDYCBIMiBzZW5zaW5nICdyZWd1bGF0b3J5IGh5ZHJvZ2VuYXNlJyAoUkgpLCBhbmQgYGhveEpgLCB0aGUgZGVmZWN0IGtpbmFzZSB0aGF0IHRyYW5zbWl0cyB0aGUgb3V0cHV0IGZyb20gYGhveEJDYCB0byBgaG94QT9gLiBUaGlzIHJlZ3VsYXRpb24gY29udHJvbHMgdHdvIHByb21vdGVyczoKCi0gICB0aGUgUF9NQkggcHJvbW90ZXIgdGhhdCBzdGFydHMgdHJhbnNjcmlwdGlvbiBvZiB0aGUgaHVnZSBgaG94S0daTUxPUVJUVmAgKyBgaHlwQUJGQ0RFWGAgKyBgaG94QUJDSiBvcGVyb25gCi0gICB0aGUgUF9TSCBwcm9tb3RlciB0aGF0IHN0YXJ0cyB0cmFuc2NyaXB0aW9uIG9mIHRoZSBzbWFsbGVyIGBob3hGVVlIV0lgICsgYGh5cEEyQjJGMmAgb3Blcm9uCgpBY2NvcmRpbmdseSwgYGhveEFgIGNvbnRyb2xzIGl0cyBvd24gdHJhbnNjcmlwdGlvbiBpbiBhIGZlZWQtZm9yd2FyZCBhdXRvcmVndWxhdG9yeSBmYXNoaW9uLiBJbmNyZWFzZWQgYGhveEFgIHByb3RlaW4gYWJ1bmRhbmNlIGxlYWRzIHRvIHN0cm9uZ2VyIGBob3hBYCBleHByZXNzaW9uLCBldGMuIEhvd2V2ZXIsIGlmIGEgdHJhbnNwb3NvbiBpbnRlZ3JhdGVzIGludG8gYW55IGdpdmVuIHNpdGUgb2Ygb25lIG9mIHRoZSBvcGVyb25zLCB0cmFuc2NyaXB0aW9uIG9mIGZvbGxvd2luZyBnZW5lcyBzaG91bGQgYmUgdGVybWluYXRlZCBvciBvdGhlcndpc2UgbmVnYXRpdmVseSBhZmZlY3RlZC4gU3VycHJpc2luZ2x5LCB0aGlzIGVmZmVjdCBpcyB2aXNpYmxlIGZvciBgaHlwYCBtdXRhbnRzIHRoYXQgbWlnaHQgbmVnYXRpdmVseSBhZmZlY3QgYGhveEFgIGV4cHJlc3Npb24sIGJ1dCBub3QgZm9yIGFueSBwcmVjZWRpbmcgZ2VuZXMgKGBob3hLSFpNTE9RUlRWYCkuIFRoaXMgc3VnZ2VzdHMgdGhhdDoKCi0gICB0aGVyZSBpcyBhbm90aGVyLCBzZWNvbmRhcnkgcHJvbW90ZXIgdGhhdCBjb250cm9scyBgaHlwYCArIGBob3hBQkNKTmAgZ2VuZSBleHByZXNzaW9uCi0gICBpbiBmYWN0IHRoaXMgaGFzIGJlZW4gc2hvd24gaW4gLi4uCgpgYGB7cn0KZ2VuZV9saXN0X21oIDwtIGMoImhveEsiLCAiaG94RyIsICJob3haIiwgImhveE0iLCAiaG94TCIsICJob3hPIiwgImhveFEiLCAiaG94UiIsICJob3hUIiwgImhveFYiKQpnZW5lX2xpc3Rfc2ggPC0gYygiaG94QSIsICJob3hCIiwgImhveEMiLCAiaG94SiIsICJob3hOIiwgImhveEYiLCAiaG94VSIsICJob3hZIiwgImhveEgiLCAiaG94VyIsICJob3hJIikKZ2VuZV9saXN0X2h5cCA8LSBjKCJoeXBBIiwgImh5cEIiLCAiaHlwRiIsICJoeXBDIiwgImh5cEQiLCAiaHlwRSIsICJoeXBYIikKCmxpc3RfbXV0YW50X2dlbm9taWMgPC0gbGlzdCgKICBob3hLID0gZ2VuZV9saXN0X21oLAogIGhveEcgPSBnZW5lX2xpc3RfbWhbMjoxMF0sCiAgaG94WiA9IGdlbmVfbGlzdF9taFszOjEwXSwKICBob3hNID0gZ2VuZV9saXN0X21oWzQ6MTBdLAogIGhveEwgPSBnZW5lX2xpc3RfbWhbNToxMF0sCiAgaG94TyA9IGdlbmVfbGlzdF9taFs2OjEwXSwKICBob3hRID0gZ2VuZV9saXN0X21oWzc6MTBdLAogIGhveFIgPSBnZW5lX2xpc3RfbWhbODoxMF0sCiAgaG94VCA9IGdlbmVfbGlzdF9taFs5OjEwXSwKICBob3hWID0gZ2VuZV9saXN0X21oWzEwXSwKICBoeXBBID0gYyhnZW5lX2xpc3RfbWgsIGdlbmVfbGlzdF9oeXAsIGdlbmVfbGlzdF9zaCksCiAgaHlwQiA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzI6N10sIGdlbmVfbGlzdF9zaCksCiAgaHlwRiA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzM6N10sIGdlbmVfbGlzdF9zaCksCiAgaHlwQyA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzQ6N10sIGdlbmVfbGlzdF9zaCksCiAgaHlwRCA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzU6N10sIGdlbmVfbGlzdF9zaCksCiAgaHlwRSA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzY6N10sIGdlbmVfbGlzdF9zaCksCiAgaHlwWCA9IGMoZ2VuZV9saXN0X21oLCBnZW5lX2xpc3RfaHlwWzddLCBnZW5lX2xpc3Rfc2gpLAogIGhveEEgPSBjKGdlbmVfbGlzdF9taCwgZ2VuZV9saXN0X2h5cCwgZ2VuZV9saXN0X3NoKSwKICBob3hCID0gZ2VuZV9saXN0X3NoWzI6NV0sCiAgaG94QyA9IGdlbmVfbGlzdF9zaFszOjVdLAogIGhveEogPSBnZW5lX2xpc3Rfc2hbNDo1XSwKICBob3hOID0gZ2VuZV9saXN0X3NoWzVdLAogIGhveEYgPSBnZW5lX2xpc3Rfc2hbYyg2OjExKV0sCiAgaG94VSA9IGdlbmVfbGlzdF9zaFtjKDc6MTEpXSwKICBob3hZID0gZ2VuZV9saXN0X3NoW2MoODoxMSldLAogIGhveEggPSBnZW5lX2xpc3Rfc2hbYyg5OjExKV0sCiAgaG94VyA9IGdlbmVfbGlzdF9zaFtjKDEwOjExKV0sCiAgaG94SSA9IGdlbmVfbGlzdF9zaFtjKDExKV0KKQoKbWF0X211dGFudF9nZW5vbWljIDwtIGxhcHBseShsaXN0X211dGFudF9nZW5vbWljLCBmdW5jdGlvbih4KSB7CiAgICBhcy5udW1lcmljKG5hbWVzKGxpc3RfbXV0YW50X2dlbm9taWMpICVpbiUgeCkKICB9KSAlPiUgdW5saXN0ICU+JSBtYXRyaXgobmNvbCA9IGxlbmd0aChsaXN0X211dGFudF9nZW5vbWljKSwgYnlyb3cgPSBUUlVFKSAlPiUgdApyb3duYW1lcyhtYXRfbXV0YW50X2dlbm9taWMpIDwtIG5hbWVzKGxpc3RfbXV0YW50X2dlbm9taWMpCmNvbG5hbWVzKG1hdF9tdXRhbnRfZ2Vub21pYykgPC0gbmFtZXMobGlzdF9tdXRhbnRfZ2Vub21pYykKYGBgCgotICAgQWRkIGluZGl2aWR1YWwgYW5kIGFjY3VtdWxhdGVkIHByb3RlaW4gY29zdCBmb3IgZWFjaCBLTyBtdXRhbnQuCgpgYGB7cn0KIyBhZGQgaW5kaXZpZHVhbCBwcm90ZWluIGNvc3QgZnJvbSBNUyBkYXRhCmRmX211dGFudF9jb3N0IDwtIGRmX211dGFudF9tdSAlPiUKICBncm91cF9ieShsb2N1c190YWcsIGdlbmVfbmFtZSwgc3Vic3RyYXRlKSAlPiUKICBzdW1tYXJpemUoLmdyb3VwcyA9ICJkcm9wIiwKICAgIG1lYW5fbXV0YW50X211ID0gbWVhbihtdXRhbnRfbXUpLAogICAgc2RfbXV0YW50X211ID0gc2QobXV0YW50X211KSkgJT4lCiAgbGVmdF9qb2luKGJ5ID0gYygibG9jdXNfdGFnIiwgInN1YnN0cmF0ZSIpLAogICAgUmFsc3RvbmlhX2V1dHJvcGhhICU+JSB1bmdyb3VwICU+JQogICAgICBmaWx0ZXIoZ3Jvd3RocmF0ZSA9PSAwLjEpICU+JQogICAgICBzZWxlY3QobG9jdXNfdGFnLCBzdWJzdHJhdGUsIG1lYW5fbWFzc19mcmFjdGlvbl9ub3JtLCBzZF9tYXNzZnJhY3Rpb24pKSAlPiUKICBhcnJhbmdlKGxvY3VzX3RhZykgJT4lCiAgdGlkeXI6OmNvbXBsZXRlKHN1YnN0cmF0ZSwgbmVzdGluZyhsb2N1c190YWcsIGdlbmVfbmFtZSkpICU+JQogIAogICMgYWRkIGVzdGltYXRlZCB0b3RhbCBjb3N0IGZvciBlYWNoIGtub2Nrb3V0CiAgZ3JvdXBfYnkoc3Vic3RyYXRlKSAlPiUKICBtdXRhdGUoCiAgICBjb3JyZWN0ZWRfY29zdCA9IG1lYW5fbWFzc19mcmFjdGlvbl9ub3JtICU+JSB7Y29sU3VtcyhuYS5ybSA9IFRSVUUsIC4qMTAwKm1hdF9tdXRhbnRfZ2Vub21pYyl9LAogICAgY29ycmVjdGVkX3NkID0gc2RfbWFzc2ZyYWN0aW9uICU+JSB7Y29sU3VtcyhuYS5ybSA9IFRSVUUsIC4qMTAwKm1hdF9tdXRhbnRfZ2Vub21pYyl9CiAgKQpgYGAKCi0gICBQbG90IG11dGFudCBncm93dGggcmF0ZSwgaW5kaXZpZHVhbCBjb3N0LCBhbmQgdG90YWwgcHJvdGVpbiBjb3N0IHRoYXQgaXMgc2F2ZWQgaW4gS08gbXV0YW50cy4KCmBgYHtyLCBmaWcud2lkdGggPSA3LjUsIGZpZy5oZWlnaHQgPSA3LjV9CnBsb3RfbXV0YW50X211IDwtIHh5cGxvdChtdXRhbnRfbXUgfiBnZW5lX25hbWUsIGRmX211dGFudF9tdSwKICAgIGdyb3VwcyA9IHN1YnN0cmF0ZSwgYXMudGFibGUgPSBUUlVFLAogICAgY29sID0gc3RkY29sWzI6NF0sIHhsYWIgPSAiIiwgeWxhYiA9IGV4cHJlc3Npb24oImVzdGltYXRlZCDCtSBbaCJeLTEqIl0iKSwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIGx3ZCA9IDIsCiAgICBzY2FsZXMgPSBsaXN0KHggPSBsaXN0KHJvdCA9IDkwKSksCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLmFibGluZShoID0gMC4xLCBjb2wgPSBncmV5KDAuNSksIGx0eSA9IDMsIGx3ZCA9IDIpCiAgICAgIHBhbmVsLmVycmJhcnMoeCwgeSwgYmVzaWRlID0gVFJVRSwgLi4uKQogICAgfQogICkKCnBsb3RfbXV0YW50X2Nvc3QgPC0geHlwbG90KG1lYW5fbWFzc19mcmFjdGlvbl9ub3JtKjEwMCB+IGdlbmVfbmFtZSwgZGZfbXV0YW50X2Nvc3QsCiAgICBncm91cHMgPSBzdWJzdHJhdGUsIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgICBlcnJvcl9tYXJnaW4gPSBkZl9tdXRhbnRfY29zdFtbInNkX21hc3NmcmFjdGlvbiJdXSoxMDAsCiAgICBsd2QgPSAyLCBjb2wgPSBzdGRjb2xbMjo0XSwgeWxpbSA9IGMoLTAuMiwgNi41KSwgcGNoID0gMSwKICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJyZWR1Y3Rpb24gcHJvdGVpbiBjb3N0IFslXSIsCiAgICBzY2FsZXMgPSBsaXN0KHggPSBsaXN0KHJvdCA9IDkwKSksCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLmVycmJhcnMoeCwgeSwgYmVzaWRlID0gVFJVRSwgLi4uKQogICAgICBwYW5lbC5rZXkoY29ybmVyID0gYygwLjk4LCAwLjk1KSwgLi4uKQogICAgICBwYW5lbC5rZXkoY29ybmVyID0gYygwLjk4LCAwLjYwKSwKICAgICAgICBsYWJlbHMgPSBjKCJpbmRpdmlkdWFsIGNvc3QiLCAidG90YWwgY29zdCAoZXN0LikiKSwKICAgICAgICBjb2wgPSBncmV5KDAuNSksIHBjaCA9IGMoMSwgMTkpKQogICAgfQogICkgKyBhcy5sYXllcigKICAgIHh5cGxvdChjb3JyZWN0ZWRfY29zdCB+IGdlbmVfbmFtZSwgZGZfbXV0YW50X2Nvc3QsCiAgICAgIGdyb3VwcyA9IHN1YnN0cmF0ZSwKICAgICAgZXJyb3JfbWFyZ2luID0gZGZfbXV0YW50X2Nvc3RbWyJjb3JyZWN0ZWRfc2QiXV0sCiAgICAgIGx3ZCA9IDIsIGNvbCA9IHN0ZGNvbFsyOjRdLAogICAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICAgIHBhbmVsLmVycmJhcnMoeCwgeSwgYmVzaWRlID0gVFJVRSwgLi4uKQogICAgICB9CiAgICApCiAgKQoKcGxvdF9tYmhfb3Blcm9uIDwtIGRmX2luY3JlYXNlZF9tdSAlPiUKICBmaWx0ZXIodGltZSA9PSA4KSAlPiUKICBncm91cF9ieShsb2N1c190YWcsIGdlbmVfbmFtZSwgc2NhZmZvbGQsIHN0cmFuZCwgc3RhcnQsIGVuZCkgJT4lCiAgc3VtbWFyaXplKHN0cmFpbnNfcGVyX2dlbmUgPSBtaW4odW5pcXVlKHN0cmFpbnNfcGVyX2dlbmUpKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgZ2Vub21lX3Bsb3QoeGxpbSA9IGMoMC4wMTUsIDIyLjQ5MCksIHRpdGxlID0gInBIRzEiLCByb3RfbGFiZWxzID0gNDUpCgpwbG90X3NoX29wZXJvbiA8LSBkZl9pbmNyZWFzZWRfbXUgJT4lCiAgZmlsdGVyKHRpbWUgPT0gOCkgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnLCBnZW5lX25hbWUsIHNjYWZmb2xkLCBzdHJhbmQsIHN0YXJ0LCBlbmQpICU+JQogIHN1bW1hcml6ZShzdHJhaW5zX3Blcl9nZW5lID0gbWluKHVuaXF1ZShzdHJhaW5zX3Blcl9nZW5lKSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdlbm9tZV9wbG90KHhsaW0gPSBjKDc5LjYxMiwgODUuNDM4KSwgdGl0bGUgPSAicEhHMSIsIHJvdF9sYWJlbHMgPSA0NSkKCnByaW50KHBsb3RfbXV0YW50X211LCBwb3NpdGlvbiA9IGMoLTAuMDE3LCAwLjYwLCAxLCAxKSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbXV0YW50X2Nvc3QsIHBvc2l0aW9uID0gYygwLjAyLCAwLjMwLCAxLCAwLjcwKSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfbWJoX29wZXJvbiwgcG9zaXRpb24gPSBjKDAuMDc1LCAwLjE0LCAwLjk3LCAwLjM5KSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3Rfc2hfb3Blcm9uLCBwb3NpdGlvbiA9IGMoMC4wNzUsIDAsIDAuNCwgMC4yNSkpCmdyaWQ6OmdyaWQudGV4dChjKCJBIiwiQiIsIkMiKSwgeCA9IGMoMC4wMiwgMC4wMiwgMC4wMiksCiAgeSA9IGMoMC45OCwgMC42NiwgMC4zNCksIGdwID0gZ3JpZDo6Z3BhcihjZXggPSAxLjIpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnaGlkZSd9CnN2ZygiLi4vZmlndXJlcy9maWd1cmVfbXV0YW50X2Nvc3Quc3ZnIiwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDcuNSkKcHJpbnQocGxvdF9tdXRhbnRfbXUsIHBvc2l0aW9uID0gYygtMC4wMTcsIDAuNjAsIDEsIDEpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9tdXRhbnRfY29zdCwgcG9zaXRpb24gPSBjKDAuMDIsIDAuMzAsIDEsIDAuNzApLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9tYmhfb3Blcm9uLCBwb3NpdGlvbiA9IGMoMC4wNzUsIDAuMTQsIDAuOTcsIDAuMzkpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9zaF9vcGVyb24sIHBvc2l0aW9uID0gYygwLjA3NSwgMCwgMC40LCAwLjI1KSkKZ3JpZDo6Z3JpZC50ZXh0KGMoIkEiLCJCIiwiQyIpLCB4ID0gYygwLjAyLCAwLjAyLCAwLjAyKSwKICB5ID0gYygwLjk4LCAwLjY2LCAwLjM0KSwgZ3AgPSBncmlkOjpncGFyKGNleCA9IDEuMikpCmRldi5vZmYoKQpgYGAKCi0gcGxvdCBjb3JyZWxhdGlvbiBvZiBlc3RpbWF0ZWQgcHJvdGVpbiBjb3N0IGFuZCBncm93dGggcmF0ZSwgcGVyIG11dGFudAotIGNvcnJlbGF0aW9uIGlzIHZpc2libGUgd2hlbiBwbG90dGluZyBib3RoIHBhcmFtZXRlcnMgc2VwYXJhdGVseSwgYnV0IHdpbGwgaXQgYWxzbyBob2xkIGluIGRpcmVjdCBjb21wYXJpc29uPwoKYGBge3IsIGZpZy53aWR0aCA9IDYuNSwgZmlnLmhlaWdodCA9My41fQpwbG90X2Nvc3RfdnNfbXUgPC0geHlwbG90KG1lYW5fbXV0YW50X211IH4gY29ycmVjdGVkX2Nvc3QgfCBzdWJzdHJhdGUsCiAgICBkZl9tdXRhbnRfY29zdCwgZ3JvdXBzID0gc3Vic3RyYXRlLAogICAgcG9pbnRsYWJlbHMgPSBhcy5jaGFyYWN0ZXIoZGZfbXV0YW50X2Nvc3QkZ2VuZV9uYW1lKSwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIGNvbCA9IHN0ZGNvbFsyOjRdLAogICAgeGxhYiA9ICJyZWR1Y3Rpb24gcHJvdGVpbiBjb3N0IFslXSIsCiAgICB5bGFiID0gZXhwcmVzc2lvbigiZXN0aW1hdGVkIMK1IFtoIl4tMSoiXSIpLAogICAgYXNwZWN0ID0gMSwgc2NhbGVzID0gbGlzdChhbHRlcm5hdGluZyA9IEZBTFNFKSwKICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCBwb2ludGxhYmVscywgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwuc3VwZXJwb3NlKHgsIHksIC4uLil9LAogICAgcGFuZWwuZ3JvdXBzID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pCiAgICAgIHBhbmVsLmxtbGluZXEoeCwgeSwgci5zcXVhcmVkID0gVFJVRSwgbGFiZWwgPSAiIiwgLi4uKQogICAgfQogICkKCnBsb3RfY29zdF92c19tdQoKc3ZnKCIuLi9maWd1cmVzL2ZpZ3VyZV9tdXRhbnRfY29zdF92c19ncm93dGguc3ZnIiwgd2lkdGggPSA2LjUsIGhlaWdodCA9IDMuNSkKcHJpbnQocGxvdF9jb3N0X3ZzX211KQpkZXYub2ZmKCkKYGBgCgoKIyMgUHJlZGljdGlvbiBvZiBncm93dGggYWR2YW50YWdlIHVzaW5nIGNlbGwgZWNvbm9teSBtb2RlbAoKVGhlIGNvbnN0cmFpbmVkIFJlc291cmNlIEJhbGFuY2UgQW5hbHlzaXMgKFJCQSkgbW9kZWwgZGVzY3JpYmVkIGluIFtKYWhuIGV0IGFsLiwgMjAyMV0oaHR0cHM6Ly9lbGlmZXNjaWVuY2VzLm9yZy9hcnRpY2xlcy82OTAxOSkgY2FuIGJlIHVzZWQgdG8gbWFrZSBwcmVkaWN0aW9ucyBvbiB0aGUgZWZmZWN0IG9mIGh5ZHJvZ2VuYXNlIGtub2Nrb3V0IG9uIGNlbGwgZ3Jvd3RoIHJhdGUuIFRoZSBSQkEgbW9kZWwgaXMgYSBnZW5vbWUgc2NhbGUgbWV0YWJvbGljIG1vZGVsIG9mICpSLiBldXRyb3BoYSogdGhhdCB0YWtlcyBwcm90ZWluIGNvc3RzIGFuZCBnbG9iYWwgcHJvdGVpbiBwb29sIGxpbWl0YXRpb25zIGludG8gYWNjb3VudC4gSW4gY29uc3RyYXN0IHRvIHNpbXBsZSBGQkEgKGZsdXggYmFsYW5jZSBhbmFseXNpcyksIGdyb3d0aCByYXRlIGlzIHVsdGltYXRlbHkgY2FwcGVkIGJ5IHJhdGUgbGltaXRhdGlvbiBvZiBlbnp5bWVzIGFuZCBzcGFjZSBsaW1pdGF0aW9uIGZvciBlbnp5bWUgbWFzcyB3aXRoaW4gdGhlIGNlbGwsIG9yIHRoZSBjeXRvcGxhc21pYyBtZW1icmFuZS4gVGhlIG1vZGVsIHdhcyBjb25zdHJhaW5lZCB1c2luZyBleHBlcmltZW50YWxseSBkZXRlcm1pbmVkIHN0ZWFkeS1zdGF0ZSBncm93dGggcmF0ZXMgYW5kIHByb3RlaW4gYWJ1bmRhbmNlcy4KCkhlcmUsIHdlIGNhbiBhc2sgdGhlIHF1ZXN0aW9uIGlmLCBhbmQgdG8gd2hpY2ggZGVncmVlLCBncm93dGggcmF0ZSB3b3VsZCBpbmNyZWFzZSBieSBleHBhbmRpbmcgdGhlIHRvdGFsIHByb3RlaW4gcG9vbCBzaXplIChzaHJpbmtpbmcgcHJvdGVpbiBjb3N0KSBieSB0aGUgZnJhY3Rpb24gaW5kaWNhdGVkIGFib3ZlIChlLmcuICpob3hBKiBLTyBmcmVlaW5nIHVwIHRvIDQlIHByb3RlaW4gbWFzcykuIFRoZSBmaXJzdCBzdGVwIGlzIHRvIGltcG9ydCBSQkEgc2ltdWxhdGlvbiByZXN1bHRzLgoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30Kc291cmNlKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL20tamFobi9SLW5vdGVib29rLXJhbHN0b25pYS1wcm90ZW9tZS9yYXcvbWFpbi9waXBlbGluZS9yZWFkX3JiYV9yZXN1bHQuUiIpKQpkaXJfc2ltIDwtICIuLi8uLi8uLi9Nb2RlbHMvQmFjdGVyaWFsLVJCQS1tb2RlbHMvUmFsc3RvbmlhLWV1dHJvcGhhLUgxNi9zaW11bGF0aW9uL2h5ZHJvZ2VuYXNlLyIKCmRmX2ZsdXggPC0gcmVhZF9yYmFfcmVzdWx0KGxpc3QuZmlsZXMoZGlyX3NpbSwgcGF0dGVybiA9ICJmbHV4ZXNfLioudHN2JCIsIGZ1bGwubmFtZXMgPSBUUlVFKSkKZGZfcHJvdCA8LSByZWFkX3JiYV9yZXN1bHQobGlzdC5maWxlcyhkaXJfc2ltLCBwYXR0ZXJuID0gInByb3RlaW5zXy4qLnRzdiIsIGZ1bGwubmFtZXMgPSBUUlVFKSkKZGZfbWFjciA8LSByZWFkX3JiYV9yZXN1bHQobGlzdC5maWxlcyhkaXJfc2ltLCBwYXR0ZXJuID0gIm1hY3JvcHJvY2Vzc2VzXy4qLnRzdiIsIGZ1bGwubmFtZXMgPSBUUlVFKSkKYGBgCgpUaGUgbmV4dCBzdGVwIGlzIHRvIHBsb3QgdGhlIGluY3JlYXNlIGluIGdyb3d0aCByYXRlIGFzIGEgZnVuY3Rpb24gb2YgcHJvdGVpbiByZXNvdXJjZXMgdGhhdCBoYXZlIGJlZW4gc2F2ZWQuIFRoZSBwcmVkaWN0aW9uIHNob3dzIHNtYWxsZXIgaW5jcmVhc2VzIHRoYW4gdGhlIGdyb3d0aCByYXRlcyBlc3RpbWF0ZWQgZnJvbSB0aGUgbGlicmFyeSBkYXRhLgoKLSAgIHJvdWdobHkgOCUgaW5jcmVhc2UgaW4gwrUgZm9yIDEwJSByZWR1Y3Rpb24gb2YgcHJvdGVpbiBjb3N0Ci0gICBsaWJyYXJ5IGRhdGEgc3VnZ2VzdCByb3VnaGx5IDQwJSBpbmNyZWFzZSBmb3IgNC01JSByZWR1Y3Rpb24gb2YgcHJvdGVpbiBjb3N0Ci0gICB0aGlzIGlzIG5vdCByZWFsaXN0aWMsIG1vc3QgbGlrZWx5IGFuIGFydGlmYWN0IG9mIGNhbGN1bGF0aW9uIGZyb20gTkdTIGRhdGEKCmBgYHtyLCBmaWcud2lkdGggPSAzLjcsIGZpZy5oZWlnaHQgPSAzLjd9CnBsb3RfY29zdF9wcmVkaWN0IDwtIGRmX21hY3IgJT4lCiAgbXV0YXRlKGNhcmJvbl9zb3VyY2UgPSByZWNvZGUoY2FyYm9uX3NvdXJjZSwKICAgIGBmb3JgID0gImZvcm1hdGUiLCBgc3VjY2AgPSAic3VjY2luYXRlIiwgYGZydWAgPSAiZnJ1Y3Rvc2UiKSkgJT4lCiAgbXV0YXRlKHNpbV9ydW4gPSBhcy5udW1lcmljKHNpbV9ydW4pKSAlPiUKICBhcnJhbmdlKGNhcmJvbl9zb3VyY2UsIHNpbV9ydW4pICU+JQogIGdyb3VwX2J5KGNhcmJvbl9zb3VyY2UsIGtleSkgJT4lCiAgbXV0YXRlKHJlZHVjZWRfcHJvdGVpbl9jb3N0ID0gMDoxMCkgJT4lCiAgZmlsdGVyKGtleSA9PSAibXUiKSAlPiUKICAKICB4eXBsb3QodmFsdWUgfiByZWR1Y2VkX3Byb3RlaW5fY29zdCwgLiwKICAgIGdyb3VwcyA9IGNhcmJvbl9zb3VyY2UsIGFzcGVjdCA9IDEsCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogICAgdHlwZSA9ICJiIiwgbHdkID0gMiwgbHR5ID0gMiwgcGNoID0gMSwKICAgIHlsaW0gPSBjKDAuMDk1LCAwLjEyNSksIGNvbCA9IHN0ZGNvbFsyOjRdLAogICAgeGxhYiA9ICJmcmVlZCB1cCBwcm90ZWluIHJlc291cmNlcyBbJSB0b3RhbF0iLAogICAgeWxhYiA9IGV4cHJlc3Npb24oIsK1IFtoIl4tMSoiXSIpLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCB6LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC54eXBsb3QoeCwgeSwgLi4uKQogICAgICBwYW5lbC5rZXkoLi4uLCBjZXggPSAwLjcsIGNvcm5lciA9IGMoMC45NiwgMC45NikpCiAgICAgIHBhbmVsLmtleShjKCJkYXRhIiwgIm1vZGVsIiksIGxpbmVzID0gVFJVRSwgbHR5ID0gYygxLDIpLAogICAgICAgIHBjaCA9IGMoMTksIDEpLCBjb2wgPSBncmV5KDAuNCksCiAgICAgICAgY2V4ID0gMC43LCBjb3JuZXIgPSBjKDAuOTYsIDAuNzIpKQogICAgfQogICkKCnByaW50KHBsb3RfY29zdF9wcmVkaWN0KQpgYGAKCiMjIEdyb3d0aCBhZHZhbnRhZ2Ugb2YgY2xlYW4sIGluLWZyYW1lIGh5ZHJvZ2VuYXNlIGRlbGV0aW9uIG11dGFudHMKCi0gYSBzZWxlY3Rpb24gb2YgaHlkcm9nZW5hc2UgbXV0YW50cyB3YXMgZ3Jvd24gaW4gYmlvcmVhY3RvcnMsIGJhdGNoIG1vZGUKLSB0b3RhbCB2b2x1bWUgd2FzIDUwIG1MIG1pbmltYWwgbWVkaXVtIHN1cHBsZW1lbnRlZCB3aXRoIDIgZy9MIGZydWN0b3NlICsgMSBnL0wgTkg0Q2wKLSBhZXJhdGlvbjogMTAwIG1ML21pbiBmb3IgYWxsIHR1YmVzCi0gdGVtcGVyYXR1cmUgMzBcKkMKLSBPRCA3MjBubSB3YXMgY29uc3RhbnRseSBtZWFzdXJlZCBldmVyeSAxNSBtaW4KLSBiaW9tYXNzIHlpZWxkIHdhcyBkZXRlcm1pbmVkIGJ5IGNvbGxlY3RpbmcgYWxsIGJpb21hc3MgYXQgdGhlIGVuZCBvZiB0aGUgZXhwZXJpbWVudCBhbmQgZGV0ZXJtaW5pbmcgRENXCgpgYGB7ciwgZmlnLndpZHRoID0gNi41LCBmaWcuaGVpZ2h0ID0gMi42NX0KZGZfZ3Jvd3RoX2Fzc2F5IDwtIHJlYWRfY3N2KCIuLi9kYXRhL2dyb3d0aF9hc3NheXMvZGZfbXVfaG94LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCmRmX2Rjd19hc3NheSA8LSByZWFkX2NzdigiLi4vZGF0YS9ncm93dGhfYXNzYXlzL2RmX2Rjd19ob3guY3N2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKcGxvdF9vcmRlciA8LSBjKCJXVCIsICJob3hHIiwgImh5cEIiLCAiaHlwWCIsICJob3hBIiwgImhveEgiKQoKcGxvdF9ncm93dGhfZGN3IDwtIGRmX2Rjd19hc3NheSAlPiUKICBtdXRhdGUoc2FtcGxlID0gZmFjdG9yKHNhbXBsZSwgcGxvdF9vcmRlcikpICU+JQogIHh5cGxvdCh5aWVsZF9nRENXX2dGUkMgfiBzYW1wbGUsIC4sCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogICAgY29sID0gc3RkY29sWzNdLCBsd2QgPSAyLCB5bGltID0gYygtMC4wLCAwLjYpLAogICAgeGxhYiA9ICIiLCB5bGFiID0gZXhwcmVzc2lvbigieWllbGQgW2cgRENXIGcgRnJjIl4tMSoiXSIpLAogICAgc2NhbGVzID0gbGlzdCh4ID0gbGlzdChyb3QgPSA0NSkpLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCB6LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC54eXBsb3QoeCwgeSwgcGNoID0gMTksIGNleCA9IDAuNSwgY29sID0gZ3JleSgwLjYpKQogICAgICBwYW5lbC5iYXJwbG90KHgsIHksIC4uLikKICAgICAgcGFuZWwucHZhbHVlKHgsIHksIG9mZnNldCA9IDAuMTIsIC4uLikKICAgIH0KICApCgpwbG90X2dyb3d0aF9tdSA8LSBkZl9ncm93dGhfYXNzYXkgJT4lCiAgbXV0YXRlKHNhbXBsZSA9IGZhY3RvcihzYW1wbGUsIHBsb3Rfb3JkZXIpKSAlPiUKICB4eXBsb3QobXVfbWF4IH4gc2FtcGxlLCAuLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwKICAgIGNvbCA9IHN0ZGNvbFszXSwgbHdkID0gMiwgeWxpbSA9IGMoLTAuMCwgMC4zOSksCiAgICB4bGFiID0gIiIsIHlsYWIgPSBleHByZXNzaW9uKCLCtSBbaCJeLTEqIl0iKSwKICAgIHNjYWxlcyA9IGxpc3QoeCA9IGxpc3Qocm90ID0gNDUpKSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgeiwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIHBjaCA9IDE5LCBjZXggPSAwLjUsIGNvbCA9IGdyZXkoMC42KSkKICAgICAgcGFuZWwuYmFycGxvdCh4LCB5LCAuLi4pCiAgICAgIHBhbmVsLnB2YWx1ZSh4LCB5LCBvZmZzZXQgPSAwLjA4LCAuLi4pCiAgICB9CiAgKQoKcHJpbnQocGxvdF9ncm93dGhfZGN3LCBwb3NpdGlvbiA9IGMoMCwgMCwgMC41LCAxKSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfZ3Jvd3RoX211LCBwb3NpdGlvbiA9IGMoMC41LCAwLCAxLCAxKSwgbW9yZSA9IFRSVUUpCmdyaWQ6OmdyaWQudGV4dChjKCJBIiwiQiIpLCB4ID0gYygwLjAzLCAwLjUpLCB5ID0gYygwLjk0LCAwLjk0KSwgZ3AgPSBncmlkOjpncGFyKGNleCA9IDEuMikpCmBgYAoKIyMgSHlkcm9nZW4gZXZvbHV0aW9uIG9mIFdUIGFuZCBoeWRyb2dlbmFzZSBtdXRhbnQKCi0gYW4gYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyB0byBwcm90ZWluIGNvc3QgYnkgaHlkcm9nZW5hc2VzIGlzIGVuZXJneSBjb3N0Ci0gdGhpcyBoeXBvdGhlc2lzIGJhc2ljYWxseSBzdGF0ZXMgdGhhdCB0aGUgZW56eW1hdGljIGFjdGlvbiBvZiBoeWRyb2dlbmFzZXMgInJ1bm5pbmcgcmV2ZXJzZSIgY2F0YWx5emVzIHRoZSBmb3JtYXRpb24gb2YgSDIgZnJvbSBOQURIIGFuZCBwcm90b25zIChhcyBrbm93biBmcm9tIGN5YW5vYmFjdGVyaWEpCi0gdGhpcyByZWFjdGlvbiB3b3VsZCBkcmFpbiB0aGUgcmVkdWN0YW50IHBvb2wgKE5BREgoUClIKSBhbmQgbGVhZCB0byByZWR1Y2VkIGdyb3d0aAotIHRoaXMgcmVhY3Rpb24gcGxheXMgYSByb2xlIHdoZW4gdGhlIHRlcm1pbmFsIGVsZWN0cm9uIGFjY2VwdG9yLCBveHlnZW4gb3Igb25lIG9mIHRoZSBuaXRyb2dlbiBveGlkZXMsIGFyZSBsaW1pdGluZwotIGluIG9yZGVyIHRvIGRldGVybWluZSBpZiBDLiBuZWNhdG9yIHNwaWxscyByZWR1Y3RhbnQgaW4gaGV0ZXJvdHJvcGhpYyBjb25kaXRpb25zIHRocm91Z2ggdGhlIGFjdGlvbiBvZiBoeWRyb2dlbmFzZXMsIFdUIGFuZCBhIG11dGFudCBkZWZlY3RpdmUgaW4gYWxsIGh5ZHJvZ2VuYXNlcyB3ZXJlIGN1bHRpdmF0ZWQgd2l0aCBmcnVjdG9zZSBhbmQgZ2x5Y2Vyb2wgdG8gaW5kdWNlIGh5ZHJvZ2VuYXNlIGV4cHJlc3Npb24KLSB3aXRob3V0IHN0cm9uZyBsaW1pdGF0aW9uIG9mIG94eWdlbiAod2hpY2ggd2FzIG5vdCBwcmVzZW50IGluIG91ciBiaW9yZWFjdG9yIGV4cGVyaW1lbnRzKSwgbm8gaHlkcm9nZW4gZXZvbHV0aW9uIHdhcyBkZXRlY3RhYmxlCi0gdGhpcyByZXN1bHQgc3RyZW5ndGhlbnMgdGhlIHByb3RlaW4gY29zdCBoeXBvdGhlc2lzCgoKYGBge3IsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAzLjJ9CmRmX2gyX2V2b2x1dGlvbiA8LSByZWFkX2NzdigiLi4vZGF0YS9ncm93dGhfYXNzYXlzL2gyX2V2b2x1dGlvbi5jc3YiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBtdXRhdGUodGltZSA9IGlmZWxzZSh0aW1lID09IDIwLjUsIDEyLjUsIHRpbWUpKQoKcGxvdF9oMl9ldm9sdXRpb24gPC0geHlwbG90KG1lYW4gfiB0aW1lLAogICAgZmlsdGVyKGRmX2gyX2V2b2x1dGlvbiwgZ2FzID09ICJPMiIpLAogICAgZ3JvdXBzID0gc3RyYWluLAogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwKICAgIGVycm9yX21hcmdpbiA9IGZpbHRlcihkZl9oMl9ldm9sdXRpb24sIGdhcyA9PSAiTzIiKSRzZCwKICAgIGx3ZCA9IDIsIHBjaCA9IDEsCiAgICB4bGFiID0gInRpbWUgW2hdIiwgeWxhYiA9IGV4cHJlc3Npb24oIk8iWzJdKiIgWyVdIiksCiAgICB5bGltID0gYygtMiwgMjIpLAogICAgc2NhbGVzID0gbGlzdCh4ID0gbGlzdChhdCA9IHNlcSgwLCAxMCwgMikpKSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gMCwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC5hYmxpbmUodiA9IHNlcSgwLCAxMCwgMiksIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIHR5cGUgPSAibCIsIGx0eSA9IDIsIC4uLikKICAgICAgcGFuZWwuZXJyYmFycyh4LCB5LCBld2lkdGggPSAwLCBsdHkgPSAxLCAuLi4pCiAgICAgIHBhbmVsLmtleSgKICAgICAgICBjb3JuZXIgPSBjKDAuOSwgMC45KSwKICAgICAgICBsYWJlbHMgPSBjKCLiiIZob3hHSEMs4oiGaG9mRyIsICJXVCIsICJPMiIsICJIMiIpLAogICAgICAgIGNvbCA9IGMoIiNFNzI5OEEiLCAiIzY2QTYxRSIsIGdyZXkoMC41KSwgZ3JleSgwLjUpKSwKICAgICAgICBwY2ggPSBjKDE5LCAxOSwgMTksIDEpCiAgICAgICkKICAgIH0KICApICsgYXMubGF5ZXIoCiAgICB4eXBsb3QobWVhbi8xMDAgfiB0aW1lLAogICAgICBmaWx0ZXIoZGZfaDJfZXZvbHV0aW9uLCBnYXMgPT0gIkgyIiksCiAgICAgIGdyb3VwcyA9IHN0cmFpbiwgcGNoID0gMTksIGx0eSA9IDEsCiAgICAgIGVycm9yX21hcmdpbiA9IGZpbHRlcihkZl9oMl9ldm9sdXRpb24sIGdhcyA9PSAiSDIiKSRzZC8xMDAsCiAgICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgICAgcGFuZWwueHlwbG90KHgsIHksIHR5cGUgPSAibCIsIC4uLikKICAgICAgICBwYW5lbC5lcnJiYXJzKHgsIHksIGV3aWR0aCA9IDAsIC4uLikKICAgICAgfQogICAgKQogICkKCnByaW50KHBsb3RfaDJfZXZvbHV0aW9uKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoID0gNy41LCBmaWcuaGVpZ2h0ID0gMi44NX0Kc3ZnKCIuLi9maWd1cmVzL2ZpZ3VyZV9tdXRhbnRfbXUuc3ZnIiwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDIuODUpCnByaW50KHBsb3RfZ3Jvd3RoX2RjdywgcG9zaXRpb24gPSBjKC0wLjAyLCAtMC4wMzQsIDAuMzgsIDEpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9ncm93dGhfbXUsIHBvc2l0aW9uID0gYygwLjI5LCAtMC4wMzQsIDAuNjksIDEpLCBtb3JlID0gVFJVRSkKcHJpbnQocGxvdF9oMl9ldm9sdXRpb24sIHBvc2l0aW9uID0gYygwLjYxLCAwLCAxLCAxKSwgbW9yZSA9IFRSVUUpCmdyaWQ6OmdyaWQudGV4dChjKCJEIiwiRSIsICJGIiksIHggPSBjKDAuMDMsIDAuMzUsIDAuNjUpLAogIHkgPSBjKDAuOTQsIDAuOTQsIDAuOTQpLCBncCA9IGdyaWQ6OmdwYXIoY2V4ID0gMS4yKSkKZGV2Lm9mZigpCmBgYAoKIyMgUHJvdGVpbiBjb3N0IG9mIHNlY29uZGFyeSBoeWRyb2dlbmFzZXMKClRoaXMgZmlndXJlIHNob3dzIHByb3RlaW4gY29zdCBvZiB0aGUgaG94L2hvZiBnZW5lcyB0aGF0IHdlcmUgbm90IGluY2x1ZGVkIGluIHRoZSBwcm90ZWluIGNvc3QgYW5hbHlzaXM6CgotICAgdGhlIDR0aCAnYWN0aW5vYmFjdGVyaWFsJyBoeWRyb2dlbmFzZSwgMSBzdWJ1bml0IChob2ZHLCBQSEcwNjUpCgpgYGB7ciwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9ClJhbHN0b25pYV9ldXRyb3BoYSAlPiUgdW5ncm91cCAlPiUKICBmaWx0ZXIoZ3JlcGwoIlBIRzA2NSIsIHByb3RlaW4pLCBzdWJzdHJhdGUgIT0gImFtbW9uaXVtIikgJT4lCiAgCiAgeHlwbG90KG1lYW5fbWFzc19mcmFjdGlvbl9ub3JtKjEwMCB+IGZhY3Rvcihncm93dGhyYXRlKSB8IHByb3RlaW4sIC4sCiAgICBncm91cHMgPSBzdWJzdHJhdGUsIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgICBlcnJvcl9tYXJnaW4gPSAuW1sic2RfbWFzc2ZyYWN0aW9uIl1dKjEwMCwKICAgIGx3ZCA9IDIsIGNvbCA9IHN0ZGNvbFsyOjRdLCB5bGltID0gYygtMC4wMDA1LCAwLjAwNDUpLCBwY2ggPSAxOSwKICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJwcm90ZWluIG1hc3MgZnJhY3Rpb24gWyVdIiwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwuZXJyYmFycyh4LCB5LCBiZXNpZGUgPSBUUlVFLCAuLi4pCiAgICAgIHBhbmVsLmtleShjb3JuZXIgPSBjKDAuMDIsIDAuOTUpLCAuLi4pCiAgICB9CiAgKQpgYGAKCiMjIFByb3RlaW4gY29zdCBvZiBFVEMgY29tcGxleGVzCgotIGFzIGEgY29tcGxpbWVudGFyeSBpbmZvcm1hdGlvbiwgd2UgY2FuIGRldGVybWluZSB0aGUgbWFzcyBmcmFjdGlvbiBvZiBFVEMgY29tcGxleGVzIHVzaW5nIE1TIGRhdGEKLSB0aGVzZSBhcmUgbWVtYnJhbmUgcHJvdGVpbnMgYW5kIGhlbmNlIGxpa2VseSB1bmRlcmVzdGltYXRlZCBpbiBjb21wYXJpc29uIHRvIHNvbHVibGUvY3l0b3BsYXNtaWMgcHJvdGVpbnMKLSB0aGUgcmVhc29uIGlzIHRoZSBsb3dlciBlZmZpY2llbmN5IHdoZW4gZXh0cmFjdGluZyBtZW1icmFuZSBwcm90ZWlucwotIGEgcmVsYXRpdmUgY29tcGFyaXNvbiBpcyBuZXZlcnRoZWxlc3MgcG9zc2libGUKLSBzaG91bGQgYWxsb3cgdXMgdG8gc2VlIHRoZSByb3VnaCBvcmRlciBvZiBtYWduaXR1ZGUgb2YgRVRDIGNvbXBsZXhlcwoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQpwbG90c19ldGNfbWFzcyA8LSBSYWxzdG9uaWFfZXV0cm9waGEgJT4lCiAgdW5ncm91cCAlPiUKICBzZWxlY3QobG9jdXNfdGFnLCBtZWFuX21hc3NfZnJhY3Rpb25fbm9ybSwgZ3Jvd3RocmF0ZSwgcHJvdGVpbiwgc3Vic3RyYXRlLCBzZF9tYXNzZnJhY3Rpb24pICU+JQogIGlubmVyX2pvaW4oCiAgICBzZWxlY3QoZGZfZXRjLCBsb2N1c190YWcsIGdlbmVfbmFtZSkgJT4lCiAgICAgIGRpc3RpbmN0ICU+JQogICAgICBtdXRhdGUoZ2VuZV9uYW1lID0gYXMuY2hhcmFjdGVyKGdlbmVfbmFtZSkpLAogICAgYnkgPSBqb2luX2J5KGxvY3VzX3RhZykpICU+JQogIGZpbHRlcihzdWJzdHJhdGUgIT0gImFtbW9uaXVtIiwgZ3Jvd3RocmF0ZSA9PSAwLjEsICFpcy5uYShnZW5lX25hbWUpLCAhc3RyX2RldGVjdChnZW5lX25hbWUsICJIMTZfIikpICU+JQogIG11dGF0ZShvcGVyb24gPSBzdHJfc3ViKGdlbmVfbmFtZSwgMSwgMykpICU+JQogIGdyb3VwX2J5KG9wZXJvbikgJT4lCiAgZ3JvdXBfc3BsaXQoKSAlPiUKICBsYXBwbHkoZnVuY3Rpb24oZGYpIHsKICAgIHh5cGxvdChtZWFuX21hc3NfZnJhY3Rpb25fbm9ybSoxMDAgfiBmYWN0b3IoZ2VuZV9uYW1lKSB8IG9wZXJvbiwgZGYsCiAgICAgIGdyb3VwcyA9IHN1YnN0cmF0ZSwgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwKICAgICAgZXJyb3JfbWFyZ2luID0gZGYkc2RfbWFzc2ZyYWN0aW9uICogMTAwLAogICAgICBsd2QgPSAyLCBjb2wgPSBzdGRjb2xbMjo0XSwgeWxpbSA9IGMoLTAuMDA1LCAwLjA4NSksIHBjaCA9IDE5LAogICAgICBiZXR3ZWVuID0gbGlzdCh4ID0gMC41LCB5ID0gMC41KSwgYXMudGFibGUgPSBUUlVFLAogICAgICBzY2FsZXMgPSBsaXN0KGFsdGVybmF0aW5nID0gRkFMU0UsIHggPSBsaXN0KHJvdCA9IDkwKSksCiAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJwcm90ZWluIG1hc3MgZnJhY3Rpb24gWyVdIiwKICAgICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgICAgcGFuZWwuZXJyYmFycyh4LCB5LCBiZXNpZGUgPSBUUlVFLCAuLi4pCiAgICAgICAgcGFuZWwua2V5KGNvcm5lciA9IGMoMC4wMiwgMC45NSksIC4uLikKICAgICAgfQogICAgKQogIH0pCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgKICBuY29sID0gMywgbnJvdyA9IDIsCiAgcGxvdHNfZXRjX21hc3NbWzVdXSwKICBwbG90c19ldGNfbWFzc1tbNF1dLAogIHBsb3RzX2V0Y19tYXNzW1s2XV0sCiAgcGxvdHNfZXRjX21hc3NbWzJdXSwKICBwbG90c19ldGNfbWFzc1tbM11dLAogIHBsb3RzX2V0Y19tYXNzW1sxXV0KKQpgYGAKCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpzdmcoIi4uL2ZpZ3VyZXMvZmlndXJlX2V0Y19tYXNzLnN2ZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoCiAgbmNvbCA9IDMsIG5yb3cgPSAyLAogIHBsb3RzX2V0Y19tYXNzW1s1XV0sCiAgcGxvdHNfZXRjX21hc3NbWzRdXSwKICBwbG90c19ldGNfbWFzc1tbNl1dLAogIHBsb3RzX2V0Y19tYXNzW1syXV0sCiAgcGxvdHNfZXRjX21hc3NbWzNdXSwKICBwbG90c19ldGNfbWFzc1tbMV1dCikKZGV2Lm9mZigpCmBgYAoKIyBFeHBvcnQgcHJvY2Vzc2VkIGRhdGEKCi0gZXhwb3J0IGZpdG5lc3MgZGF0YSBpbiBhIGZvcm1hdCB0aGF0IGlzIHN1aXRhYmxlIGZvciBbU2hpbnlMaWJdKGh0dHBzOi8vbS1qYWhuLnNoaW55YXBwcy5pby9TaGlueUxpYi8pCi0gd2UgZXhwb3J0IGVudGlyZSBkYXRhIHNldCBmb3IgYmVzdCBjb21wYXJpc29uIG9wdGlvbnMsIGV2ZW4gdGhvdWdoIGZpcnN0IHBhcnQgKGNhcmJvbiBzb3VyY2VzKSB3YXMgcHVibGlzaGVkIGVhbGllciBhcyBKYWhuIGV0IGFsLiwgZUxpZmUsIDIwMjEKCmBgYHtyfQpDdXByaWF2aWR1c19CYXJTZXFfMjAyMyA8LSBkZl9maXRuZXNzICU+JQogIHJlbmFtZSh0aW1lcG9pbnQgPSB0aW1lLCBmaXRuZXNzX3Njb3JlID0gbm9ybV9nZW5lX2ZpdG5lc3MsIHRfc3RhdCA9IHQpICU+JQogIG11dGF0ZSgKICAgIGluZHVjdGlvbiA9ICJub3QgYXBwbGljYWJsZSIsCiAgICBsb2cyRkMgPSByZXBsYWNlKGxvZzJGQywgaXMuaW5maW5pdGUobG9nMkZDKSwgTkEpLAogICAgZm9sZF9jaGFuZ2UgPSAyXmxvZzJGQywKICAgIGNvbmRpdGlvbiA9IHBhc3RlMChzdWJzdHJhdGUsICIgLSAiLCBjb25kaXRpb24pCiAgKSAlPiUKICBzZWxlY3QoLUlEKSAlPiUKICBhcnJhbmdlKGxvY3VzX3RhZywgY29uZGl0aW9uLCB0aW1lcG9pbnQpICU+JQogIGxlZnRfam9pbihieSA9ICJsb2N1c190YWciLAogICAgZGZfcmVmICU+JQogICAgICBzZWxlY3QoCiAgICAgICAgbG9jdXNfdGFnLCBuZXdfbG9jdXNfdGFnLAogICAgICAgIHVuaXByb3QsIHByb3RlaW5fbmFtZSwgZ2VuZV9uYW1lLAogICAgICAgIFN5c3RlbSwgUHJvY2VzcywgUGF0aHdheQogICAgICApCiAgKQoKIyBleHBvcnQgdG8gUkRhdGEKc2F2ZShDdXByaWF2aWR1c19CYXJTZXFfMjAyMywgZmlsZSA9ICIuLi9kYXRhL2JhcnNlcS9DdXByaWF2aWR1c19CYXJTZXFfMjAyMy5SZGF0YSIpCmBgYAoKCiMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK