QC
1. Number of events per sample
Blank wells are indeed blank
raw %>% filter(host == "blank") %>%
group_by(date) %>%
ggplot(aes(x = date, y = n_cells)) + geom_point(aes(shape = well)) +
stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red",
position = position_nudge(x = 0.1)) +
theme_bw(base_size = 16) + theme(axis.text.x = element_text(size = rel(0.8), angle = 90))

there are some cell like events in the blank wells, especially in one
well on 02/21 and another on 3/31. 02/08 and 02/10 also have more events
than other days. checking the pre-processing R notebook outputs, I think
there may be some carry over between wells. No wide spread contamination
though.
Below, we will remove the blank wells from further consideration
tmp <- filter(raw, host != "blank")
tmp %>%
ggplot(aes(x = n_induction)) +
#geom_histogram(bins = 30, fill = "forestgreen") + facet_grid(host~date) +
geom_density_ridges(aes(y = date)) +
facet_wrap(~host) + theme_minimal(base_size = 14) #+ panel_border()

Majority of the experimental wells (not blank) have > 5000 events,
with the exception of a few samples
tmp %>% filter(n_induction < 1000)
for now, I plan to let any sample with > 1000 events pass. This
would exclude 20 samples that have extremely low counts, likely
indicating issues. later I plan to revisit the remaining low count
samples, e.g., n_induction between 1000 and 3000.
Remove low event count and a few experiments with “fail” flag.
dat <- filter(raw, host != "blank", flag == "pass")
2. Background subtraction
Check the background fluorescence levels across different days.
dat %>% filter(host == "156") %>%
pivot_longer(BL1.H:nRFP, names_to = "parameter", values_to = "intensity") %>%
mutate(parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP"))) %>%
ggplot(aes(x = date, y = intensity)) + geom_point(aes(shape = well)) +
stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red",
position = position_nudge(x = 0.1)) +
facet_wrap(~parameter) +
theme_bw(base_size = 16) + theme(axis.text.x = element_text(size = rel(0.8), angle = 90))

02/18 and 02/21 YFP has relatively high background. I checked the
original gated data and found that indeed those samples have a higher
RFP. It is not, however, a systematic shift up, as the other samples
don’t appear to have higher RFP levels during those runs (days).
similarly, 02/10 showed higher BL1.H background, and there is no
indication that a systematic shift explains the higher background (which
can be caused by a voltage difference).
tmp <- dat %>% filter(host == "156")
lm(BL1.H ~ date, data = tmp) %>% anova()
Analysis of Variance Table
Response: BL1.H
Df Sum Sq Mean Sq F value Pr(>F)
date 12 375979 31331.6 11.525 1.512e-07 ***
Residuals 26 70680 2718.5
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
ANOVA above does reveal significant variation in GFP background
fluorescence between yH156 across days.
Is there any relationship between the background BL1.H level from
yH156 and mNeon levels from the experimental strains?
test.strain = "194"
tmp <- dat %>%
filter(grepl(paste0("NA-156|", test.strain, "-373"), name)) %>%
group_by(date, plasmid) %>%
summarize(meanGFP = mean(BL1.H), .groups = "drop") %>%
pivot_wider(id_cols = date, names_from = plasmid, names_prefix = "p", values_from = meanGFP)
lm(p194 ~ pNA, data = tmp) %>% summary()
Call:
lm(formula = p194 ~ pNA, data = tmp)
Residuals:
Min 1Q Median 3Q Max
-461.98 -75.55 61.58 162.22 210.34
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2250.0374 470.4313 4.783 0.000569 ***
pNA -0.2333 0.5651 -0.413 0.687636
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 200 on 11 degrees of freedom
Multiple R-squared: 0.01526, Adjusted R-squared: -0.07426
F-statistic: 0.1705 on 1 and 11 DF, p-value: 0.6876
p <- ggplot(tmp, aes(x = pNA, y = p194)) +
geom_point(size = 2) +
geom_text(data = filter(tmp, p194 < 1800), aes(label = date), nudge_x = -20) +
stat_smooth(method = "lm", formula = y~x) +
xlab("background BL1.H (yH156)") + ylab(paste0("Pho4-mNeon (pH", test.strain, ")")) +
theme_minimal(base_size = 16)
p

No strong correlation between the background and the mNeon levels
Given the results above, I propose to do the following:
I assume the variation in the non-fluorescent strain's reading is due to idiosynchractic behavior
of that strain and not characteristic of the days. Therefore, I plan to avearage the background
fluorescence to get a more accurate estimate, which implicitly assumes that variation in the
background is minimal between days.
Subtract the background
bg <- dat %>%
filter(host == "156") %>%
group_by(date) %>%
# average based on dates
summarize(across(BL1.H:nRFP, ~ round(mean(.x),1)), .groups = "drop") %>%
# median of day averages
summarize(across(BL1.H:nRFP, ~median(.))) %>%
unlist() # turn into a named vector storing background readings
#column_to_rownames(var = "date")
bg.rm <- dat %>%
select(date:host, events = n_induction, FSC.H:nRFP, flag) %>%
mutate(
BL1.H = BL1.H - bg["BL1.H"],
YL2.H = YL2.H - bg["YL2.H"],
nGFP = nGFP - bg["nGFP"],
nRFP = nRFP - bg["nRFP"],
)
Double check that the subtraction worked correctly
bg.rm %>% filter(host == "156") %>%
pivot_longer(BL1.H:nRFP, names_to = "parameter", values_to = "intensity") %>%
mutate(parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP"))) %>%
ggplot(aes(x = date, y = intensity)) + geom_point(aes(shape = well)) +
stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red", position = position_nudge(x = 0.1)) +
facet_wrap(~parameter, scale = "free_y") +
theme_bw(base_size = 14) + theme(axis.text.x = element_text(angle = 90))

Determine if any sample had very low mNeon levels despite having a
Pho4 chimera plasmid. I observed such samples when doing the
pre-processing, and would like to identify and remove them now.
mycolors = c(brewer.pal(name="Paired", n = 8), brewer.pal(name="Dark2", n = 6))
no.exn.th <- 250
ggplot(bg.rm, aes(x = plasmid, y = abs(BL1.H))) +
geom_hline(yintercept = no.exn.th, color = "grey50", linetype = 2, size = 0.2) +
geom_point(aes(color = date)) +
scale_y_log10(breaks = c(100, 1000, 10000)) + ylab("BL1.H") +
scale_color_manual(values = mycolors) + theme_cowplot() +
theme(axis.text.x = element_text(angle = 90, size = rel(0.7), vjust = 0.5),
legend.position = "top")
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

# assign "fail" to the non-expressing ones
bg.rm[bg.rm$plasmid != "NA" & bg.rm$BL1.H < no.exn.th, "flag"] = "fail"
filter(bg.rm, flag == "fail")
the above samples will be exported for archiving, but won’t be used
in subsequent analyses.
Lastly, pH231 assayed on 2/18 and 2/19 exhibited abnormal behaviors.
The existing one replicate from each day is
from biological replicate 2, in which the majority of the cells were not
inducing. Lindsey repeated this strain on 3/30 and 3/31, and obtained
properly behaving data. Therefore, we will remove the single replicate
for pH231 from 2/18 and 2/19
bg.rm[bg.rm$plasmid == "231" & bg.rm$host == "555" & bg.rm$date %in% c("02/18", "02/19"), "flag"] = "fail"
filter(bg.rm, flag == "fail")
Export the background-subtracted values for later use with the
shinyapp
# remove the yH156 samples
dat.export <- bg.rm %>%
filter(host != "156") %>%
mutate(
host = ordered(host, levels = c("555", "373", "529"), labels = c("PHO2", "pho2∆", "PHO84"))
)
write_tsv(dat.export, "../20231023-PHO5-bg-subtracted-data.tsv")
3. Consistency across plates.
Check the background-subtracted fluorescence values for the host
strains (yH373 and yH555) as well as the positive control strain (pH188
in yH373 or yH555 backgrounds), both of which are present on each
plate.
dat.export %>%
filter(host != "PHO84", flag == "pass", plasmid %in% c("188", "194", "NA")) %>%
pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>%
#mutate(parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP"))) %>%
ggplot(aes(x = plasmid, y = intensity, group = date)) +
geom_point(aes(color = date), position = position_dodge(0.7)) +
scale_color_manual(values = mycolors) +
facet_grid(parameter~host, scale = "free_y") +
theme_bw(base_size = 14)# +

#theme(axis.text.x = element_text(face = 3))
- The host strain fluorescence levels appear to be consistent across
the days. Additionally, their GFP levels are zero, as expected.
- The positive control strain has strong BL1.H and correspondingly has
strong YL2.H.
- 02/10 batch has strange BL1 values. Since we have three identical
sets (02/10, 11, 16), we can ignore this batch in the downstream
analysis
dat.wide.fil <- filter(dat.export, host != "PHO84", flag == "pass", date != "02/10")
Number of replicates left for each sample
expt <- dat.wide.fil %>%
filter(host %in% c("PHO2", "pho2∆"), !plasmid %in% c("188", "194")) %>%
group_by(date, plasmid, host) %>%
summarize(n = n(), .groups = "drop")
expt %>%
ggplot(aes(x = plasmid, y = n)) +
geom_col(aes(fill = host)) +
facet_grid(date ~ .) +
scale_fill_manual(values = c("PHO2" = "gray30", "pho2∆" = "gray70")) +
theme_minimal() + background_grid(major = "none") + panel_border(size = 0.5) +
scale_y_continuous(name = "Replicates", breaks = c(0, 3, 6)) + xlab(NULL) +
theme(axis.text.x = element_text(angle = 90),
legend.position = "top")

How many plasmid-host combination have < 3 replicates after
removing samples with low event counts?
dat.wide.fil %>%
count(plasmid, host) %>%
filter(n < 3)
4. Well position
Rationale
- In my original plate design, I placed a positive control strain
(envisioned CgPho4-mNeon in PHO2 background for example) in the
control columns (1, 5, 9) on every other row (A, C, E, G). The reason
for this is to use it to identify any well position effect on the
fluorescence readings.
- In Emily’s implementation, she instead put a pair
of strains, namely pH188-yH323 and pH188-yH555 in these wells. This
means I cannot use the positive control wells exactly the way as I
designed them. But I can still use them to spot any trend.
tmp <- dat.wide.fil %>%
filter(plasmid == "194", host == "PHO2") %>%
separate(well, into = c("row", "col"), sep = 1) %>%
pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity")
p0 <- list(
geom_point(aes(color = date), size = 1),
#geom_line(aes(color = date), size = 0.4),
stat_summary(aes(color = date), geom = "line", fun = mean, linewidth = 0.5),
scale_color_manual(values = mycolors),
#scale_color_brewer(type = "qual", palette = 2),
facet_wrap(~parameter, scales = "free_y"),
xlab(NULL),
guides(color = guide_legend(title.position = "left", nrow = 2, byrow = TRUE)),
theme_bw(base_size = 14),
theme(legend.text = element_text(size = rel(0.8)))
)
p1 <- ggplot(tmp, aes(x = row, y = intensity, group = date)) + p0 +
labs(subtitle = "Variation over rows")
p2 <- ggplot(tmp, aes(x = col, y = intensity, group = date)) + p0 +
labs(subtitle = "Variation over columns")
p.legend <- get_legend(p1)
plot_grid(p1 + guides(color = "none"), p2 + guides(color = "none"), p.legend,
nrow = 3, rel_heights = c(1,1,0.3))

- no obivous trend between the rows; there seems to be downward trend
for BL1 going from column 1 to 9
- a clear correlation between YL2.H and BL1.H. at least part of this
is due to the cell size differences – see size normalized data
below:
- What we care about is the ratio between Pho4-mNeon and
PHO5pr-mCherry
tmp <- dat.wide.fil %>%
filter(plasmid == "194", host == "PHO2") %>%
separate(well, into = c("row", "col"), sep = 1)
tmp %>%
ggplot(aes(x = BL1.H, y = YL2.H)) +
stat_smooth(aes(color = date, group = date),
method = "lm", formula = y ~ 0 + x,
se = FALSE, size = 0.5) +
geom_point(aes(color = date, shape = col), size = 1.5) +
#scale_color_manual(values = mycolors) +
scale_shape_manual(values = 17:19) +
facet_wrap(~ date) +
theme_minimal(base_size = 16) +
theme(axis.text = element_blank(),
legend.position = "right",
legend.box = "horizontal")

There is variation in BL1.H and correspondingly in YL2.H, but the
ratio between the two are very consistent 02/20 data is a bit of an
outlier
Let’s check both ScPho4 (pH194) and CgPho4 (pH188) to see if their
behaviors are consistent across the days.
dat.wide.fil %>%
filter(plasmid %in% c("188", "194"), host != "PHO84") %>%
mutate(`YL2.H/BL1.H` = YL2.H/BL1.H,
Pho4 = factor(plasmid, levels = c("194", "188"),
labels = c("ScPho4", "CgPho4"))) %>%
separate(well, into = c("row", "col"), sep = 1) %>%
ggplot(aes(x = date, y = `YL2.H/BL1.H`)) +
geom_bar(aes(fill = host), stat = "summary", fun = "mean",
position = position_dodge(0.9)) +
geom_point(aes(group = host), size = 1, shape = 3,
position = position_dodge(width = 0.9)) +
scale_fill_manual(values = c("PHO2" = "gray60", "pho2∆" = "orange")) +
#stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red") +
facet_grid(Pho4 ~ .) +
theme_bw(base_size = 16) + background_grid(major = "none") +
theme(axis.text.x = element_text(size = rel(.8), angle = 45, vjust = 0.5))

2/20 data is more variable (also see the figure above the one
immediately above)
5. High variance samples
Summarize the background subtracted data by calculating the means and
cv for each strain.
cv <- dat.wide.fil %>%
select(-nGFP, -nRFP) %>%
pivot_longer(FSC.H:YL2.H, names_to = "parameter", values_to = "intensity") %>%
group_by(date, plasmid, host, parameter) %>%
summarize(
n = n(),
mean = mean(intensity),
cv = sd(intensity)/mean(intensity),
.groups = "drop"
) %>%
arrange(desc(cv))
cv %>%
filter(plasmid != "NA", parameter != "FSC.H") %>%
ggplot(aes(x = cv)) + geom_histogram(aes(y = after_stat(density)/8), bins = 30) +
stat_ecdf() +
geom_hline(yintercept = 0.8, linetype = 2) +
geom_vline(xintercept = 0.2, linetype = 3, color = "red3") +
scale_y_continuous(breaks = seq(0, 1, by = 0.2)) +
ylab("cumulative density") +
facet_wrap(~parameter) +
theme_cowplot()

The histogram’s y-axis is not shown. The line graph represents the
empirical CDF, and the dotted horizontal line is at 80%. GFP is more
variable than RFP, likely because the absolute values of the former is
lower. For both, ~80% of the samples have a CV < 20%.
Do the same for the cell size-normalized values
cv.n <- dat.wide.fil %>%
select(-BL1.H, -YL2.H) %>%
pivot_longer(nGFP:nRFP, names_to = "parameter", values_to = "intensity") %>%
group_by(date, plasmid, host, parameter) %>%
summarize(
n = n(),
mean = num(mean(intensity), digits = 0),
cv = num(sd(intensity)/mean(intensity), digits = 2),
.groups = "drop"
) %>%
arrange(desc(cv))
cv.n %>%
filter(plasmid != "NA", parameter != "FSC.H") %>%
ggplot(aes(x = cv)) + geom_histogram(aes(y = after_stat(density)/10), bins = 30) +
stat_ecdf() +
geom_hline(yintercept = 0.8, linetype = 2) +
geom_vline(xintercept = 0.2, linetype = 3, color = "red3") +
scale_y_continuous(breaks = seq(0, 1, by = 0.2)) +
ylab("cumulative density") +
facet_wrap(~parameter) +
theme_cowplot()

CV is about the same for the size normalized data.
Identify the high variance samples
high.var.list <- cv %>%
mutate(CV = round(abs(cv), 3)) %>%
pivot_wider(id_cols = c(date, plasmid, host),
names_from = parameter, names_prefix = "CV_",
values_from = CV) %>%
filter(CV_BL1.H > 0.2 | CV_YL2.H > 0.2) %>%
arrange(date, plasmid, host)
dat.high.var <- left_join(high.var.list, dat.wide.fil) %>% select(-flag) %>% arrange(date, plasmid)
Joining with `by = join_by(date, plasmid, host)`
write_tsv(dat.high.var, "20231027-high-var-samples.tsv")
dat.high.var %>% filter((CV_BL1.H > 1 & plasmid != "NA") | CV_YL2.H > 1)
plasmid 233 replicates 1 & 2 repeatedly showed no RFP induction,
while replicate 3 did show induction.
LS0tCnRpdGxlOiAiRTAxMyBQaG80IGNoaW1lcmEgYWN0aXZpdHkgYW5hbHlzaXMgdXNpbmcgUEhPNSByZXBvcnRlciwgcG9vbCBhbmQgUUMiCmF1dGhvcjogIkJpbiBIZSIKZGF0ZTogIjIwMjMtMTAtMTkgdXBkYXRlZCBgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKYGBge3IgbWVzc2FnZT1GQUxTRX0KcmVxdWlyZShwbG90bHkpCnJlcXVpcmUodGlkeXZlcnNlKQpyZXF1aXJlKGdncmlkZ2VzKQpyZXF1aXJlKGNvd3Bsb3QpCnJlcXVpcmUoUkNvbG9yQnJld2VyKQpgYGAKCmBgYHtyfQpvbGQgPC0gdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE2KSkKYGBgCgoKIyBHb2FsCi0gQW5hbHl6ZSB0aGUgZnVsbCBjaGltZXJhIHNldCBmbG93IHJlc3VsdHMgZm9yIF9QSE81cHJfLW1DaGVycnkgcmVwb3J0ZXIuCi0gRGV2ZWxvcCBhbiBhbmFseXNpcyBwaXBlbGluZSB0byBwZXJmb3JtIFFDLCBjb3JyZWN0aW9uIChpZiBuZWVkZWQpIGFuZCBwbG90dGluZyB0aGUgcmVzdWx0cy4KCiMgRGF0YQpJbXBvcnQgdGhlIGRhdGEKYGBge3J9CmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICIuIiwgcGF0dGVybiA9ICIqLWdhdGVkLW1lZGlhbi1vdXQudHh0IikKbmFtZXMoZmlsZXMpIDwtIGdzdWIoIi1nYXRlZC1tZWRpYW4tb3V0LnR4dCIsICIiLCBmaWxlcykKcmF3IDwtIG1hcF9kZnIoZmlsZXMsIH5yZWFkX3RzdigueCwgY29sX3R5cGVzID0gY29scygpKSwgLmlkID0gImRhdGUiKSAlPiUgCiAgbXV0YXRlKAogICAgZmxhZyA9IGlmZWxzZShpcy5uYShmbGFnKSwgIyBpZiBubyBmbGFnIHdhcyByZWNvcmRlZCBpbiB0aGUgb3JpZ2luYWwgZ2F0ZWQgbWVkaWFuIGRhdGEgCiAgICAgICAgICAgICAgICAgIGlmZWxzZShuX2luZHVjdGlvbiA8IDEwMDAsICJmYWlsIiwgInBhc3MiKSwgIyBmYWlsIGlmIGZld2VyIHRoYW4gMTAwMCBldmVudHMKICAgICAgICAgICAgICAgICAgZmxhZyksICMgaWYgdGhlIG9yaWdpbmFsIGRhdGEgKG9uZSkgaGFzIGZsYWcsIHVzZSBpdAogICAgZGF0ZSA9IGZvcm1hdCh5bWQoZGF0ZSksICIlbS8lZCIpCiAgKSAlPiUgCiAgZmlsdGVyKCFncmVwbCgiYmVhZCIsIHNhbXBsZSkpICU+JSAKICBzZXBhcmF0ZShjb2wgPSBzYW1wbGUsIHNlcCA9ICItIiwgaW50byA9IGMoInBsYXNtaWQiLCAiaG9zdCIsICJyZXAiKSkKYGBgCgpTYW1wbGUgaW5mb3JtYXRpb24KYGBge3J9CnNhbXBsZSA8LSByZWFkX3RzdigiLi4vMjAyMzAyMDgtY2hpbWVyYS1QaG80LW1ha2V1cC50eHQiLCBjb2xfdHlwZXMgPSAiY2NjY2MiKQpgYGAKCiMgUUMKIyMgMS4gTnVtYmVyIG9mIGV2ZW50cyBwZXIgc2FtcGxlCkJsYW5rIHdlbGxzIGFyZSBpbmRlZWQgYmxhbmsKYGBge3J9CnJhdyAlPiUgZmlsdGVyKGhvc3QgPT0gImJsYW5rIikgJT4lIAogIGdyb3VwX2J5KGRhdGUpICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBuX2NlbGxzKSkgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHdlbGwpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fc2UiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQiLCAKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4xKSkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE2KSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44KSwgYW5nbGUgPSA5MCkpCmBgYAo+IHRoZXJlIGFyZSBzb21lIGNlbGwgbGlrZSBldmVudHMgaW4gdGhlIGJsYW5rIHdlbGxzLCBlc3BlY2lhbGx5IGluIG9uZSB3ZWxsIG9uIDAyLzIxIGFuZCBhbm90aGVyIG9uIDMvMzEuCj4gMDIvMDggYW5kIDAyLzEwIGFsc28gaGF2ZSBtb3JlIGV2ZW50cyB0aGFuIG90aGVyIGRheXMuIGNoZWNraW5nIHRoZSBwcmUtcHJvY2Vzc2luZyBSIG5vdGVib29rCj4gb3V0cHV0cywgSSB0aGluayB0aGVyZSBtYXkgYmUgc29tZSBjYXJyeSBvdmVyIGJldHdlZW4gd2VsbHMuIE5vIHdpZGUgc3ByZWFkIGNvbnRhbWluYXRpb24gdGhvdWdoLgoKQmVsb3csIHdlIHdpbGwgcmVtb3ZlIHRoZSBibGFuayB3ZWxscyBmcm9tIGZ1cnRoZXIgY29uc2lkZXJhdGlvbgpgYGB7cn0KdG1wIDwtIGZpbHRlcihyYXcsIGhvc3QgIT0gImJsYW5rIikKYGBgCgpgYGB7cn0KdG1wICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBuX2luZHVjdGlvbikpICsgCiAgI2dlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJmb3Jlc3RncmVlbiIpICsgZmFjZXRfZ3JpZChob3N0fmRhdGUpICsgCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhZXMoeSA9IGRhdGUpKSArCiAgZmFjZXRfd3JhcCh+aG9zdCkgKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSAjKyBwYW5lbF9ib3JkZXIoKQpgYGAKPiBNYWpvcml0eSBvZiB0aGUgZXhwZXJpbWVudGFsIHdlbGxzIChub3QgYmxhbmspIGhhdmUgPiA1MDAwIGV2ZW50cywgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIGEgZmV3IHNhbXBsZXMKCmBgYHtyfQp0bXAgJT4lIGZpbHRlcihuX2luZHVjdGlvbiA8IDEwMDApCmBgYAo+IGZvciBub3csIEkgcGxhbiB0byBsZXQgYW55IHNhbXBsZSB3aXRoID4gMTAwMCBldmVudHMgcGFzcy4gVGhpcyB3b3VsZCBleGNsdWRlIDIwIHNhbXBsZXMgdGhhdCBoYXZlIGV4dHJlbWVseSBsb3cgY291bnRzLCBsaWtlbHkgaW5kaWNhdGluZyBpc3N1ZXMuIGxhdGVyIEkgcGxhbiB0byByZXZpc2l0IHRoZSByZW1haW5pbmcgbG93IGNvdW50IHNhbXBsZXMsIGUuZy4sIG5faW5kdWN0aW9uIGJldHdlZW4gMTAwMCBhbmQgMzAwMC4KClJlbW92ZSBsb3cgZXZlbnQgY291bnQgYW5kIGEgZmV3IGV4cGVyaW1lbnRzIHdpdGggImZhaWwiIGZsYWcuCmBgYHtyfQpkYXQgPC0gZmlsdGVyKHJhdywgaG9zdCAhPSAiYmxhbmsiLCBmbGFnID09ICJwYXNzIikKYGBgCgoKIyMgMi4gQmFja2dyb3VuZCBzdWJ0cmFjdGlvbgoKQ2hlY2sgdGhlIGJhY2tncm91bmQgZmx1b3Jlc2NlbmNlIGxldmVscyBhY3Jvc3MgZGlmZmVyZW50IGRheXMuCmBgYHtyfQpkYXQgJT4lIGZpbHRlcihob3N0ID09ICIxNTYiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKEJMMS5IOm5SRlAsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKSAlPiUgCiAgbXV0YXRlKHBhcmFtZXRlciA9IG9yZGVyZWQocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJCTDEuSCIsICJZTDIuSCIsICJuR0ZQIiwgIm5SRlAiKSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gaW50ZW5zaXR5KSkgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHdlbGwpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fc2UiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQiLCAKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4xKSkgKwogIGZhY2V0X3dyYXAofnBhcmFtZXRlcikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE2KSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44KSwgYW5nbGUgPSA5MCkpCmBgYAoKPiAwMi8xOCBhbmQgMDIvMjEgWUZQIGhhcyByZWxhdGl2ZWx5IGhpZ2ggYmFja2dyb3VuZC4gSSBjaGVja2VkIHRoZSBvcmlnaW5hbCBnYXRlZCBkYXRhIGFuZCAKPiBmb3VuZCB0aGF0IGluZGVlZCB0aG9zZSBzYW1wbGVzIGhhdmUgYSBoaWdoZXIgUkZQLiBJdCBpcyBub3QsIGhvd2V2ZXIsIGEgc3lzdGVtYXRpYyBzaGlmdCB1cCwKPiBhcyB0aGUgb3RoZXIgc2FtcGxlcyBkb24ndCBhcHBlYXIgdG8gaGF2ZSBoaWdoZXIgUkZQIGxldmVscyBkdXJpbmcgdGhvc2UgcnVucyAoZGF5cykuCj4gc2ltaWxhcmx5LCAwMi8xMCBzaG93ZWQgaGlnaGVyIEJMMS5IIGJhY2tncm91bmQsIGFuZCB0aGVyZSBpcyBubyBpbmRpY2F0aW9uIHRoYXQgYSBzeXN0ZW1hdGljIAo+IHNoaWZ0IGV4cGxhaW5zIHRoZSBoaWdoZXIgYmFja2dyb3VuZCAod2hpY2ggY2FuIGJlIGNhdXNlZCBieSBhIHZvbHRhZ2UgZGlmZmVyZW5jZSkuCgpgYGB7cn0KdG1wIDwtIGRhdCAlPiUgZmlsdGVyKGhvc3QgPT0gIjE1NiIpCmxtKEJMMS5IIH4gZGF0ZSwgZGF0YSA9IHRtcCkgJT4lIGFub3ZhKCkKYGBgCgo+IEFOT1ZBIGFib3ZlIGRvZXMgcmV2ZWFsIHNpZ25pZmljYW50IHZhcmlhdGlvbiBpbiBHRlAgYmFja2dyb3VuZCBmbHVvcmVzY2VuY2UgYmV0d2VlbiB5SDE1NiBhY3Jvc3MgZGF5cy4KCklzIHRoZXJlIGFueSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgYmFja2dyb3VuZCBCTDEuSCBsZXZlbCBmcm9tIHlIMTU2IGFuZCBtTmVvbiBsZXZlbHMgZnJvbSB0aGUgZXhwZXJpbWVudGFsIHN0cmFpbnM/CmBgYHtyfQp0ZXN0LnN0cmFpbiA9ICIxOTQiCnRtcCA8LSBkYXQgJT4lIAogIGZpbHRlcihncmVwbChwYXN0ZTAoIk5BLTE1NnwiLCB0ZXN0LnN0cmFpbiwgIi0zNzMiKSwgbmFtZSkpICU+JSAKICBncm91cF9ieShkYXRlLCBwbGFzbWlkKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5HRlAgPSBtZWFuKEJMMS5IKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBkYXRlLCBuYW1lc19mcm9tID0gcGxhc21pZCwgbmFtZXNfcHJlZml4ID0gInAiLCB2YWx1ZXNfZnJvbSA9IG1lYW5HRlApCgpsbShwMTk0IH4gcE5BLCBkYXRhID0gdG1wKSAlPiUgc3VtbWFyeSgpCgpwIDwtIGdncGxvdCh0bXAsIGFlcyh4ID0gcE5BLCB5ID0gcDE5NCkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMikgKyAKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcih0bXAsIHAxOTQgPCAxODAwKSwgYWVzKGxhYmVsID0gZGF0ZSksIG51ZGdlX3ggPSAtMjApICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geX54KSArCiAgeGxhYigiYmFja2dyb3VuZCBCTDEuSCAoeUgxNTYpIikgKyB5bGFiKHBhc3RlMCgiUGhvNC1tTmVvbiAocEgiLCB0ZXN0LnN0cmFpbiwgIikiKSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpCgpwCgpgYGAKCj4gTm8gc3Ryb25nIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGJhY2tncm91bmQgYW5kIHRoZSBtTmVvbiBsZXZlbHMKCkdpdmVuIHRoZSByZXN1bHRzIGFib3ZlLCBJIHByb3Bvc2UgdG8gZG8gdGhlIGZvbGxvd2luZzoKCiAgICBJIGFzc3VtZSB0aGUgdmFyaWF0aW9uIGluIHRoZSBub24tZmx1b3Jlc2NlbnQgc3RyYWluJ3MgcmVhZGluZyBpcyBkdWUgdG8gaWRpb3N5bmNocmFjdGljIGJlaGF2aW9yCiAgICBvZiB0aGF0IHN0cmFpbiBhbmQgbm90IGNoYXJhY3RlcmlzdGljIG9mIHRoZSBkYXlzLiBUaGVyZWZvcmUsIEkgcGxhbiB0byBhdmVhcmFnZSB0aGUgYmFja2dyb3VuZAogICAgZmx1b3Jlc2NlbmNlIHRvIGdldCBhIG1vcmUgYWNjdXJhdGUgZXN0aW1hdGUsIHdoaWNoIGltcGxpY2l0bHkgYXNzdW1lcyB0aGF0IHZhcmlhdGlvbiBpbiB0aGUKICAgIGJhY2tncm91bmQgaXMgbWluaW1hbCBiZXR3ZWVuIGRheXMuCgoKU3VidHJhY3QgdGhlIGJhY2tncm91bmQKYGBge3J9CmJnIDwtIGRhdCAlPiUgCiAgZmlsdGVyKGhvc3QgPT0gIjE1NiIpICU+JSAKICBncm91cF9ieShkYXRlKSAlPiUgCiAgIyBhdmVyYWdlIGJhc2VkIG9uIGRhdGVzCiAgc3VtbWFyaXplKGFjcm9zcyhCTDEuSDpuUkZQLCB+IHJvdW5kKG1lYW4oLngpLDEpKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogICMgbWVkaWFuIG9mIGRheSBhdmVyYWdlcwogIHN1bW1hcml6ZShhY3Jvc3MoQkwxLkg6blJGUCwgfm1lZGlhbiguKSkpICU+JSAKICB1bmxpc3QoKSAjIHR1cm4gaW50byBhIG5hbWVkIHZlY3RvciBzdG9yaW5nIGJhY2tncm91bmQgcmVhZGluZ3MKICAjY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJkYXRlIikKCmJnLnJtIDwtIGRhdCAlPiUgCiAgc2VsZWN0KGRhdGU6aG9zdCwgZXZlbnRzID0gbl9pbmR1Y3Rpb24sIEZTQy5IOm5SRlAsIGZsYWcpICU+JQogIG11dGF0ZSgKICAgIEJMMS5IID0gQkwxLkggLSBiZ1siQkwxLkgiXSwKICAgIFlMMi5IID0gWUwyLkggLSBiZ1siWUwyLkgiXSwKICAgIG5HRlAgPSBuR0ZQIC0gYmdbIm5HRlAiXSwKICAgIG5SRlAgPSBuUkZQIC0gYmdbIm5SRlAiXSwKICApCmBgYAoKRG91YmxlIGNoZWNrIHRoYXQgdGhlIHN1YnRyYWN0aW9uIHdvcmtlZCBjb3JyZWN0bHkKYGBge3J9CmJnLnJtICU+JSBmaWx0ZXIoaG9zdCA9PSAiMTU2IikgJT4lIAogIHBpdm90X2xvbmdlcihCTDEuSDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIG11dGF0ZShwYXJhbWV0ZXIgPSBvcmRlcmVkKHBhcmFtZXRlciwgbGV2ZWxzID0gYygiQkwxLkgiLCAiWUwyLkgiLCAibkdGUCIsICJuUkZQIikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGludGVuc2l0eSkpICsgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSB3ZWxsKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAicmVkIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4xKSkgKwogIGZhY2V0X3dyYXAofnBhcmFtZXRlciwgc2NhbGUgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCkRldGVybWluZSBpZiBhbnkgc2FtcGxlIGhhZCB2ZXJ5IGxvdyBtTmVvbiBsZXZlbHMgZGVzcGl0ZSBoYXZpbmcgYSBQaG80IGNoaW1lcmEgcGxhc21pZC4gSSBvYnNlcnZlZCBzdWNoIHNhbXBsZXMgd2hlbiBkb2luZyB0aGUgcHJlLXByb2Nlc3NpbmcsIGFuZCB3b3VsZCBsaWtlIHRvIGlkZW50aWZ5IGFuZCByZW1vdmUgdGhlbSBub3cuCgpgYGB7cn0KbXljb2xvcnMgPSBjKGJyZXdlci5wYWwobmFtZT0iUGFpcmVkIiwgbiA9IDgpLCBicmV3ZXIucGFsKG5hbWU9IkRhcmsyIiwgbiA9IDYpKQoKbm8uZXhuLnRoIDwtIDI1MApnZ3Bsb3QoYmcucm0sIGFlcyh4ID0gcGxhc21pZCwgeSA9IGFicyhCTDEuSCkpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbm8uZXhuLnRoLCBjb2xvciA9ICJncmV5NTAiLCBsaW5ldHlwZSA9IDIsIHNpemUgPSAwLjIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRhdGUpKSArIAogIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygxMDAsIDEwMDAsIDEwMDAwKSkgKyB5bGFiKCJCTDEuSCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXljb2xvcnMpICsgdGhlbWVfY293cGxvdCgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IHJlbCgwLjcpLCB2anVzdCA9IDAuNSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKYGBge3J9CiMgYXNzaWduICJmYWlsIiB0byB0aGUgbm9uLWV4cHJlc3Npbmcgb25lcwpiZy5ybVtiZy5ybSRwbGFzbWlkICE9ICJOQSIgJiBiZy5ybSRCTDEuSCA8IG5vLmV4bi50aCwgImZsYWciXSA9ICJmYWlsIgpmaWx0ZXIoYmcucm0sIGZsYWcgPT0gImZhaWwiKQpgYGAKPiB0aGUgYWJvdmUgc2FtcGxlcyB3aWxsIGJlIGV4cG9ydGVkIGZvciBhcmNoaXZpbmcsIGJ1dCB3b24ndCBiZSB1c2VkIGluIHN1YnNlcXVlbnQgYW5hbHlzZXMuCgpMYXN0bHksIHBIMjMxIGFzc2F5ZWQgb24gMi8xOCBhbmQgMi8xOSBleGhpYml0ZWQgYWJub3JtYWwgYmVoYXZpb3JzLgohW3BIMjMxIG9uIDIvMTgsIDIvMTldKC4uLy4uL2ltZy8yMDIzMTExNi1wSDIzMS1wcm9ibGVtLnBuZykKVGhlIGV4aXN0aW5nIG9uZSByZXBsaWNhdGUgZnJvbSBlYWNoIGRheSBpcyBmcm9tIGJpb2xvZ2ljYWwgcmVwbGljYXRlIDIsIGluIHdoaWNoIHRoZSBtYWpvcml0eSBvZiB0aGUgY2VsbHMgd2VyZSBub3QgaW5kdWNpbmcuIExpbmRzZXkgcmVwZWF0ZWQgdGhpcyBzdHJhaW4gb24gMy8zMCBhbmQgMy8zMSwgYW5kIG9idGFpbmVkIHByb3Blcmx5IGJlaGF2aW5nIGRhdGEuIFRoZXJlZm9yZSwgd2Ugd2lsbCByZW1vdmUgdGhlIHNpbmdsZSByZXBsaWNhdGUgZm9yIHBIMjMxIGZyb20gMi8xOCBhbmQgMi8xOQpgYGB7cn0KYmcucm1bYmcucm0kcGxhc21pZCA9PSAiMjMxIiAmIGJnLnJtJGhvc3QgPT0gIjU1NSIgJiBiZy5ybSRkYXRlICVpbiUgYygiMDIvMTgiLCAiMDIvMTkiKSwgImZsYWciXSA9ICJmYWlsIgpmaWx0ZXIoYmcucm0sIGZsYWcgPT0gImZhaWwiKQpgYGAKCkV4cG9ydCB0aGUgYmFja2dyb3VuZC1zdWJ0cmFjdGVkIHZhbHVlcyBmb3IgbGF0ZXIgdXNlIHdpdGggdGhlIHNoaW55YXBwCmBgYHtyfQojIHJlbW92ZSB0aGUgeUgxNTYgc2FtcGxlcwpkYXQuZXhwb3J0IDwtIGJnLnJtICU+JSAKICBmaWx0ZXIoaG9zdCAhPSAiMTU2IikgJT4lIAogIG11dGF0ZSgKICAgIGhvc3QgPSBvcmRlcmVkKGhvc3QsIGxldmVscyA9IGMoIjU1NSIsICIzNzMiLCAiNTI5IiksIGxhYmVscyA9IGMoIlBITzIiLCAicGhvMuKIhiIsICJQSE84NCIpKQogICkKd3JpdGVfdHN2KGRhdC5leHBvcnQsICIuLi8yMDIzMTAyMy1QSE81LWJnLXN1YnRyYWN0ZWQtZGF0YS50c3YiKQpgYGAKCiMjIDMuIENvbnNpc3RlbmN5IGFjcm9zcyBwbGF0ZXMuCgpDaGVjayB0aGUgYmFja2dyb3VuZC1zdWJ0cmFjdGVkIGZsdW9yZXNjZW5jZSB2YWx1ZXMgZm9yIHRoZSBob3N0IHN0cmFpbnMgKHlIMzczIGFuZCB5SDU1NSkgYXMgd2VsbCBhcyB0aGUgcG9zaXRpdmUgY29udHJvbCBzdHJhaW4gKHBIMTg4IGluIHlIMzczIG9yIHlINTU1IGJhY2tncm91bmRzKSwgYm90aCBvZiB3aGljaCBhcmUgcHJlc2VudCBvbiBlYWNoIHBsYXRlLgoKYGBge3J9CmRhdC5leHBvcnQgJT4lIAogIGZpbHRlcihob3N0ICE9ICJQSE84NCIsIGZsYWcgPT0gInBhc3MiLCBwbGFzbWlkICVpbiUgYygiMTg4IiwgIjE5NCIsICJOQSIpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKEJMMS5IOllMMi5ILCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogICNtdXRhdGUocGFyYW1ldGVyID0gb3JkZXJlZChwYXJhbWV0ZXIsIGxldmVscyA9IGMoIkJMMS5IIiwgIllMMi5IIiwgIm5HRlAiLCAiblJGUCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHBsYXNtaWQsIHkgPSBpbnRlbnNpdHksIGdyb3VwID0gZGF0ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkYXRlKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjcpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycykgKwogIGZhY2V0X2dyaWQocGFyYW1ldGVyfmhvc3QsIHNjYWxlID0gImZyZWVfeSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkjICsKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9IDMpKQpgYGAKCj4gMS4gVGhlIGhvc3Qgc3RyYWluIGZsdW9yZXNjZW5jZSBsZXZlbHMgYXBwZWFyIHRvIGJlIGNvbnNpc3RlbnQgYWNyb3NzIHRoZSBkYXlzLiBBZGRpdGlvbmFsbHksIHRoZWlyIEdGUCBsZXZlbHMgYXJlIHplcm8sIGFzIGV4cGVjdGVkLgo+IDIuIFRoZSBwb3NpdGl2ZSBjb250cm9sIHN0cmFpbiBoYXMgc3Ryb25nIEJMMS5IIGFuZCBjb3JyZXNwb25kaW5nbHkgaGFzIHN0cm9uZyBZTDIuSC4KPiAzLiAwMi8xMCBiYXRjaCBoYXMgc3RyYW5nZSBCTDEgdmFsdWVzLiBTaW5jZSB3ZSBoYXZlIHRocmVlIGlkZW50aWNhbCBzZXRzICgwMi8xMCwgMTEsIDE2KSwgd2UgY2FuIGlnbm9yZSB0aGlzIGJhdGNoIGluIHRoZSBkb3duc3RyZWFtIGFuYWx5c2lzCgpgYGB7cn0KZGF0LndpZGUuZmlsIDwtIGZpbHRlcihkYXQuZXhwb3J0LCBob3N0ICE9ICJQSE84NCIsIGZsYWcgPT0gInBhc3MiLCBkYXRlICE9ICIwMi8xMCIpCmBgYAoKTnVtYmVyIG9mIHJlcGxpY2F0ZXMgbGVmdCBmb3IgZWFjaCBzYW1wbGUKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpleHB0IDwtIGRhdC53aWRlLmZpbCAlPiUgCiAgZmlsdGVyKGhvc3QgJWluJSBjKCJQSE8yIiwgInBobzLiiIYiKSwgIXBsYXNtaWQgJWluJSBjKCIxODgiLCAiMTk0IikpICU+JSAKICBncm91cF9ieShkYXRlLCBwbGFzbWlkLCBob3N0KSAlPiUgCiAgc3VtbWFyaXplKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpCgpleHB0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBwbGFzbWlkLCB5ID0gbikpICsKICBnZW9tX2NvbChhZXMoZmlsbCA9IGhvc3QpKSArIAogIGZhY2V0X2dyaWQoZGF0ZSB+IC4pICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJQSE8yIiA9ICJncmF5MzAiLCAicGhvMuKIhiIgPSAiZ3JheTcwIikpICsKICB0aGVtZV9taW5pbWFsKCkgKyBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAibm9uZSIpICsgcGFuZWxfYm9yZGVyKHNpemUgPSAwLjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJSZXBsaWNhdGVzIiwgYnJlYWtzID0gYygwLCAzLCA2KSkgKyB4bGFiKE5VTEwpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgpIb3cgbWFueSBwbGFzbWlkLWhvc3QgY29tYmluYXRpb24gaGF2ZSA8IDMgcmVwbGljYXRlcyBhZnRlciByZW1vdmluZyBzYW1wbGVzIHdpdGggbG93IGV2ZW50IGNvdW50cz8KYGBge3J9CmRhdC53aWRlLmZpbCAlPiUKICBjb3VudChwbGFzbWlkLCBob3N0KSAlPiUgCiAgZmlsdGVyKG4gPCAzKQpgYGAKCiMjIDQuIFdlbGwgcG9zaXRpb24KCioqX1JhdGlvbmFsZV8qKgoKLSBJbiBteSBvcmlnaW5hbCBwbGF0ZSBkZXNpZ24sIEkgcGxhY2VkIGEgcG9zaXRpdmUgY29udHJvbCBzdHJhaW4gKGVudmlzaW9uZWQgQ2dQaG80LW1OZW9uIGluIF9QSE8yXyBiYWNrZ3JvdW5kIGZvciBleGFtcGxlKSBpbiB0aGUgY29udHJvbCBjb2x1bW5zICgxLCA1LCA5KSBvbiBldmVyeSBvdGhlciByb3cgKEEsIEMsIEUsIEcpLiBUaGUgcmVhc29uIGZvciB0aGlzIGlzIHRvIHVzZSBpdCB0byBpZGVudGlmeSBhbnkgd2VsbCBwb3NpdGlvbiBlZmZlY3Qgb24gdGhlIGZsdW9yZXNjZW5jZSByZWFkaW5ncy4KLSBJbiBFbWlseSdzIGltcGxlbWVudGF0aW9uLCBzaGUgaW5zdGVhZCBwdXQgKiphIHBhaXIqKiBvZiBzdHJhaW5zLCBuYW1lbHkgcEgxODgteUgzMjMgYW5kIHBIMTg4LXlINTU1IGluIHRoZXNlIHdlbGxzLiBUaGlzIG1lYW5zIEkgY2Fubm90IHVzZSB0aGUgcG9zaXRpdmUgY29udHJvbCB3ZWxscyBleGFjdGx5IHRoZSB3YXkgYXMgSSBkZXNpZ25lZCB0aGVtLiBCdXQgSSBjYW4gc3RpbGwgdXNlIHRoZW0gdG8gc3BvdCBhbnkgdHJlbmQuCiAgICAKYGBge3J9CnRtcCA8LSBkYXQud2lkZS5maWwgJT4lIAogIGZpbHRlcihwbGFzbWlkID09ICIxOTQiLCBob3N0ID09ICJQSE8yIikgJT4lIAogIHNlcGFyYXRlKHdlbGwsIGludG8gPSBjKCJyb3ciLCAiY29sIiksIHNlcCA9IDEpICU+JSAKICBwaXZvdF9sb25nZXIoQkwxLkg6WUwyLkgsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKQoKcDAgPC0gbGlzdCgKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRhdGUpLCBzaXplID0gMSksIAogICNnZW9tX2xpbmUoYWVzKGNvbG9yID0gZGF0ZSksIHNpemUgPSAwLjQpLAogIHN0YXRfc3VtbWFyeShhZXMoY29sb3IgPSBkYXRlKSwgZ2VvbSA9ICJsaW5lIiwgZnVuID0gbWVhbiwgbGluZXdpZHRoID0gMC41KSwKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXljb2xvcnMpLAogICNzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9IDIpLAogIGZhY2V0X3dyYXAofnBhcmFtZXRlciwgc2NhbGVzID0gImZyZWVfeSIpLAogIHhsYWIoTlVMTCksCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gImxlZnQiLCBucm93ID0gMiwgYnlyb3cgPSBUUlVFKSksCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpLAogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC44KSkpCikKCnAxIDwtIGdncGxvdCh0bXAsIGFlcyh4ID0gcm93LCB5ID0gaW50ZW5zaXR5LCBncm91cCA9IGRhdGUpKSArIHAwICsKICBsYWJzKHN1YnRpdGxlID0gIlZhcmlhdGlvbiBvdmVyIHJvd3MiKQoKcDIgPC0gZ2dwbG90KHRtcCwgYWVzKHggPSBjb2wsIHkgPSBpbnRlbnNpdHksIGdyb3VwID0gZGF0ZSkpICsgcDAgKwogIGxhYnMoc3VidGl0bGUgPSAiVmFyaWF0aW9uIG92ZXIgY29sdW1ucyIpCgpwLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAxKQoKcGxvdF9ncmlkKHAxICsgZ3VpZGVzKGNvbG9yID0gIm5vbmUiKSwgcDIgKyBndWlkZXMoY29sb3IgPSAibm9uZSIpLCBwLmxlZ2VuZCwKICAgICAgICAgIG5yb3cgPSAzLCByZWxfaGVpZ2h0cyA9IGMoMSwxLDAuMykpCmBgYAoKPiAtIG5vIG9iaXZvdXMgdHJlbmQgYmV0d2VlbiB0aGUgcm93czsgdGhlcmUgc2VlbXMgdG8gYmUgZG93bndhcmQgdHJlbmQgZm9yIEJMMSBnb2luZyBmcm9tIGNvbHVtbiAxIHRvIDkKPiAtIGEgY2xlYXIgY29ycmVsYXRpb24gYmV0d2VlbiBZTDIuSCBhbmQgQkwxLkguIGF0IGxlYXN0IHBhcnQgb2YgdGhpcyBpcyBkdWUgdG8gdGhlIGNlbGwgc2l6ZSBkaWZmZXJlbmNlcyAtLSBzZWUgc2l6ZSBub3JtYWxpemVkIGRhdGEgYmVsb3c6CgotIFdoYXQgd2UgY2FyZSBhYm91dCBpcyB0aGUgcmF0aW8gYmV0d2VlbiBQaG80LW1OZW9uIGFuZCBfUEhPNXByXy1tQ2hlcnJ5CgpgYGB7cn0KdG1wIDwtIGRhdC53aWRlLmZpbCAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgPT0gIjE5NCIsIGhvc3QgPT0gIlBITzIiKSAlPiUgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSkKCnRtcCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gQkwxLkgsIHkgPSBZTDIuSCkpICsgCiAgc3RhdF9zbW9vdGgoYWVzKGNvbG9yID0gZGF0ZSwgZ3JvdXAgPSBkYXRlKSwgCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiAwICsgeCwgCiAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGF0ZSwgc2hhcGUgPSBjb2wpLCBzaXplID0gMS41KSArIAogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXljb2xvcnMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTc6MTkpICsKICBmYWNldF93cmFwKH4gZGF0ZSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIikKYGBgCgo+IFRoZXJlIGlzIHZhcmlhdGlvbiBpbiBCTDEuSCBhbmQgY29ycmVzcG9uZGluZ2x5IGluIFlMMi5ILCBidXQgdGhlIHJhdGlvIGJldHdlZW4gdGhlIHR3byBhcmUgdmVyeSBjb25zaXN0ZW50Cj4gMDIvMjAgZGF0YSBpcyBhIGJpdCBvZiBhbiBvdXRsaWVyCgpMZXQncyBjaGVjayBib3RoIFNjUGhvNCAocEgxOTQpIGFuZCBDZ1BobzQgKHBIMTg4KSB0byBzZWUgaWYgdGhlaXIgYmVoYXZpb3JzIGFyZSBjb25zaXN0ZW50IGFjcm9zcyB0aGUgZGF5cy4KYGBge3J9CmRhdC53aWRlLmZpbCAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgJWluJSBjKCIxODgiLCAiMTk0IiksIGhvc3QgIT0gIlBITzg0IikgJT4lIAogIG11dGF0ZShgWUwyLkgvQkwxLkhgID0gWUwyLkgvQkwxLkgsCiAgICAgICAgIFBobzQgPSBmYWN0b3IocGxhc21pZCwgbGV2ZWxzID0gYygiMTk0IiwgIjE4OCIpLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTY1BobzQiLCAiQ2dQaG80IikpKSAlPiUgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBgWUwyLkgvQkwxLkhgKSkgKyAKICBnZW9tX2JhcihhZXMoZmlsbCA9IGhvc3QpLCBzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIAogICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkgKwogIGdlb21fcG9pbnQoYWVzKGdyb3VwID0gaG9zdCksIHNpemUgPSAxLCBzaGFwZSA9IDMsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJQSE8yIiA9ICJncmF5NjAiLCAicGhvMuKIhiIgPSAib3JhbmdlIikpICsKICAjc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fc2UiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQiKSArCiAgZmFjZXRfZ3JpZChQaG80IH4gLikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE2KSArIGJhY2tncm91bmRfZ3JpZChtYWpvciA9ICJub25lIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoLjgpLCBhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNSkpCmBgYAoKPiAyLzIwIGRhdGEgaXMgbW9yZSB2YXJpYWJsZSAoYWxzbyBzZWUgdGhlIGZpZ3VyZSBhYm92ZSB0aGUgb25lIGltbWVkaWF0ZWx5IGFib3ZlKQoKIyMgNS4gSGlnaCB2YXJpYW5jZSBzYW1wbGVzCgpTdW1tYXJpemUgdGhlIGJhY2tncm91bmQgc3VidHJhY3RlZCBkYXRhIGJ5IGNhbGN1bGF0aW5nIHRoZSBtZWFucyBhbmQgY3YgZm9yIGVhY2ggc3RyYWluLgpgYGB7cn0KY3YgPC0gZGF0LndpZGUuZmlsICU+JSAKICBzZWxlY3QoLW5HRlAsIC1uUkZQKSAlPiUKICBwaXZvdF9sb25nZXIoRlNDLkg6WUwyLkgsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKSAlPiUgCiAgZ3JvdXBfYnkoZGF0ZSwgcGxhc21pZCwgaG9zdCwgcGFyYW1ldGVyKSAlPiUgCiAgc3VtbWFyaXplKAogICAgbiA9IG4oKSwKICAgIG1lYW4gPSBtZWFuKGludGVuc2l0eSksCiAgICBjdiA9IHNkKGludGVuc2l0eSkvbWVhbihpbnRlbnNpdHkpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lIAogIGFycmFuZ2UoZGVzYyhjdikpCmBgYAoKYGBge3J9CmN2ICU+JSAKICBmaWx0ZXIocGxhc21pZCAhPSAiTkEiLCBwYXJhbWV0ZXIgIT0gIkZTQy5IIikgJT4lIAogIGdncGxvdChhZXMoeCA9IGN2KSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkvOCksIGJpbnMgPSAzMCkgKyAKICBzdGF0X2VjZGYoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOCwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4yLCBsaW5ldHlwZSA9IDMsIGNvbG9yID0gInJlZDMiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMikpICsKICB5bGFiKCJjdW11bGF0aXZlIGRlbnNpdHkiKSArIAogIGZhY2V0X3dyYXAofnBhcmFtZXRlcikgKwogIHRoZW1lX2Nvd3Bsb3QoKQpgYGAKCj4gVGhlIGhpc3RvZ3JhbSdzIHktYXhpcyBpcyBub3Qgc2hvd24uIFRoZSBsaW5lIGdyYXBoIHJlcHJlc2VudHMgdGhlIGVtcGlyaWNhbCBDREYsIGFuZCB0aGUgZG90dGVkIGhvcml6b250YWwgbGluZSBpcyBhdCA4MCUuIEdGUCBpcyBtb3JlIHZhcmlhYmxlIHRoYW4gUkZQLCBsaWtlbHkgYmVjYXVzZSB0aGUgYWJzb2x1dGUgdmFsdWVzIG9mIHRoZSBmb3JtZXIgaXMgbG93ZXIuIEZvciBib3RoLCB+ODAlIG9mIHRoZSBzYW1wbGVzIGhhdmUgYSBDViA8IDIwJS4KCkRvIHRoZSBzYW1lIGZvciB0aGUgY2VsbCBzaXplLW5vcm1hbGl6ZWQgdmFsdWVzCmBgYHtyfQpjdi5uIDwtIGRhdC53aWRlLmZpbCAlPiUgCiAgc2VsZWN0KC1CTDEuSCwgLVlMMi5IKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKG5HRlA6blJGUCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBncm91cF9ieShkYXRlLCBwbGFzbWlkLCBob3N0LCBwYXJhbWV0ZXIpICU+JSAKICBzdW1tYXJpemUoCiAgICBuID0gbigpLAogICAgbWVhbiA9IG51bShtZWFuKGludGVuc2l0eSksIGRpZ2l0cyA9IDApLAogICAgY3YgPSBudW0oc2QoaW50ZW5zaXR5KS9tZWFuKGludGVuc2l0eSksIGRpZ2l0cyA9IDIpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lIAogIGFycmFuZ2UoZGVzYyhjdikpCmBgYAoKYGBge3J9CmN2Lm4gJT4lIAogIGZpbHRlcihwbGFzbWlkICE9ICJOQSIsIHBhcmFtZXRlciAhPSAiRlNDLkgiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3YpKSArIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KS8xMCksIGJpbnMgPSAzMCkgKyAKICBzdGF0X2VjZGYoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOCwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4yLCBsaW5ldHlwZSA9IDMsIGNvbG9yID0gInJlZDMiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMikpICsKICB5bGFiKCJjdW11bGF0aXZlIGRlbnNpdHkiKSArIAogIGZhY2V0X3dyYXAofnBhcmFtZXRlcikgKwogIHRoZW1lX2Nvd3Bsb3QoKQpgYGAKCj4gQ1YgaXMgYWJvdXQgdGhlIHNhbWUgZm9yIHRoZSBzaXplIG5vcm1hbGl6ZWQgZGF0YS4KCklkZW50aWZ5IHRoZSBoaWdoIHZhcmlhbmNlIHNhbXBsZXMKYGBge3J9CmhpZ2gudmFyLmxpc3QgPC0gY3YgJT4lIAogIG11dGF0ZShDViA9IHJvdW5kKGFicyhjdiksIDMpKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoZGF0ZSwgcGxhc21pZCwgaG9zdCksIAogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBwYXJhbWV0ZXIsIG5hbWVzX3ByZWZpeCA9ICJDVl8iLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gQ1YpICU+JQogIGZpbHRlcihDVl9CTDEuSCA+IDAuMiB8IENWX1lMMi5IID4gMC4yKSAlPiUgCiAgYXJyYW5nZShkYXRlLCBwbGFzbWlkLCBob3N0KQpkYXQuaGlnaC52YXIgPC0gbGVmdF9qb2luKGhpZ2gudmFyLmxpc3QsIGRhdC53aWRlLmZpbCkgJT4lIHNlbGVjdCgtZmxhZykgJT4lIGFycmFuZ2UoZGF0ZSwgcGxhc21pZCkgCgp3cml0ZV90c3YoZGF0LmhpZ2gudmFyLCAiMjAyMzEwMjctaGlnaC12YXItc2FtcGxlcy50c3YiKQoKZGF0LmhpZ2gudmFyICU+JSBmaWx0ZXIoKENWX0JMMS5IID4gMSAmIHBsYXNtaWQgIT0gIk5BIikgfCBDVl9ZTDIuSCA+IDEpCmBgYAoKPiBwbGFzbWlkIDIzMyByZXBsaWNhdGVzIDEgJiAyIHJlcGVhdGVkbHkgc2hvd2VkIG5vIFJGUCBpbmR1Y3Rpb24sIHdoaWxlIHJlcGxpY2F0ZSAzIGRpZCBzaG93IGluZHVjdGlvbi4KCg==