QC
1. Number of events per sample
dat %>% ggplot(aes(x = n_induction)) + geom_histogram(bins = 30, fill = "forestgreen") + facet_grid(host~date) + theme_bw(base_size = 14) #+ panel_border()

Majority of the experimental wells (not blank) have > 10000
events, with the exception of a few samples
dat %>% filter(host != "blank", n_induction < 10000)
Given the distribution of event counts, we will label all samples
with < 7000 counts, which would exclude 2 samples. The rationale is
that even though some samples had between 7000 - 10000 events, their
mean fluorescence values appear in line with the other replicates of the
same genotype. I also removed the blank wells and add a flag to mark the
plasmids that Emily remade because the original one (used for this batch
of data) contains nonsynonymous mutations.
event.th <- 7000
list.mutations <- as.character(c(215, 209, 211, 210, 217, 218, 220, 221, 223, 224, 222, 227, 230, 229, 231, 233, 240, 241, 250:255, 257, 258, 265, 266))
expt <- dat %>%
filter(host != "blank") %>%
group_by(date, plasmid, host) %>%
summarize(n = n(), n_filter = sum(n_induction >= event.th), .groups = "drop") %>%
mutate(flag = ifelse(plasmid %in% list.mutations, "mutation", ""))
dat <- dat %>%
mutate(
low_event_count = n_induction < event.th,
mutation = ifelse(plasmid %in% list.mutations, TRUE, FALSE)
) %>%
filter(host != "blank")
How many plasmid-host combination have < 3 replicates after
removing samples with low event counts?
dat %>% filter(!low_event_count) %>%
count(plasmid, host) %>%
filter(n < 3)
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, scale = "free_y") +
theme_bw(base_size = 14)

03/29/22 D9 showed higher background fluorescence than the others.
after checking the gating result, I found that NA-156-2 sample in D9 had
a slightly wider distribution, and the 2d cluster gate is also wider
than the other two samples. The cell size normalized intensity doesn’t
show the same pattern, suggesting that at least some of the difference
could be due to cell size variation. Try just averaging the three blank
wells and perform the background removal.
Subtract the background
bg <- dat %>%
filter(host == "156") %>%
group_by(date) %>%
summarize(across(FSC.H:nRFP, ~ round(mean(.x),1))) %>%
column_to_rownames(var = "date")
dat1 <- dat %>%
select(date:host, FSC.H:nRFP, low_event_count, mutation) %>%
mutate(
BL1.H = BL1.H - bg[date, "BL1.H"],
YL2.H = YL2.H - bg[date, "YL2.H"],
nGFP = nGFP - bg[date, "nGFP"],
nRFP = nRFP - bg[date, "nRFP"],
)
Double check that the subtraction worked correctly
dat1 %>% 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)

# remove the yH156 samples
dat1 <- dat1 %>%
filter(host != "156") %>%
mutate(host = ordered(host, levels = c("555", "373"), labels = c("PHO2", "pho2∆")))
Export the background-subtracted values for later use with the
shinyapp
write_tsv(dat1, "../output/20220614-mar22-batch-bg-sub-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.
dat1 %>% filter(plasmid %in% c("188", "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, color = date)) +
geom_point(position = position_dodge(0.5)) +
scale_color_brewer(type = "qual", palette = 2) +
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 three days. Additionally, their GFP levels are zero, as
expected.
- The positive control strain has strong BL1.H and correspondingly has
strong YL2.H.
The size normalized values show slightly lower variance:
dat1 %>% filter(plasmid %in% c("188", "NA")) %>%
pivot_longer(nGFP:nRFP, names_to = "parameter", values_to = "intensity") %>%
#mutate(parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP"))) %>%
ggplot(aes(x = plasmid, y = intensity, color = date)) +
geom_point(position = position_dodge(0.5)) +
scale_color_brewer(type = "qual", palette = 2) +
facet_grid(parameter~host, scale = "free_y") +
theme_bw(base_size = 14) +
theme(axis.text.x = element_text(face = 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.
dat1 %>%
filter(plasmid == "188") %>%
separate(well, into = c("row", "col"), sep = 1) %>%
pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>%
ggplot(aes(x = row, y = intensity, group = date)) +
geom_point(aes(color = date), size = 1) +
#geom_line(aes(color = date), size = 0.4) +
stat_summary(aes(color = date), geom = "line", fun = mean) +
scale_color_brewer(type = "qual", palette = 2) +
facet_grid(parameter~host, scales = "free_y") +
theme_bw(base_size = 14)

- no obivous trend between the rows (or columns, not shown)
- 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:
dat1 %>%
filter(plasmid == "188") %>%
separate(well, into = c("row", "col"), sep = 1) %>%
pivot_longer(c(YL2.H, nRFP), names_to = "parameter", values_to = "intensity") %>%
ggplot(aes(x = row, y = intensity, group = date)) +
geom_point(aes(color = date), size = 1) +
#geom_line(aes(color = date), size = 0.4) +
stat_summary(aes(color = date), geom = "line", fun = mean) +
scale_color_brewer(type = "qual", palette = 2) +
facet_grid(parameter~host, scales = "free_y") +
theme_bw(base_size = 14)

- What we care about is the ratio between Pho4-mNeon and
PHO5pr-mCherry
dat1 %>%
filter(plasmid == "188") %>%
separate(well, into = c("row", "col"), sep = 1) %>%
ggplot(aes(x = BL1.H, y = YL2.H)) +
geom_point(aes(shape = date, color = row), size = 3) +
stat_smooth(method = "lm", se = FALSE, color = "gray50", size = 0.5) +
scale_color_viridis_d() +
scale_shape_manual(values = 15:17) +
#scale_x_log10() + scale_y_log10() +
#facet_grid(parameter~host, scales = "free_y") +
theme_bw(base_size = 14)
`geom_smooth()` using formula 'y ~ x'

- There is variation in BL1.H and correspondingly in YL2.H, but the
ratio between the two are very consistent
Let’s check both ScPho4 (pH194) and CgPho4 (pH188) to see if their
behaviors are consistent across the days.
dat1 %>%
filter(plasmid %in% c("188", "194")) %>%
mutate(`YL2.H/BL1.H` = YL2.H/BL1.H,
#mutate(`YL2.H/BL1.H` = nRFP/nGFP,
Pho4 = factor(plasmid, levels = c("194", "188"),
labels = c("ScPho4", "CgPho4"))) %>%
separate(well, into = c("row", "col"), sep = 1) %>%
ggplot(aes(x = host, y = `YL2.H/BL1.H`)) +
geom_point(color = alpha("gray50", 0.9), position = position_jitter(0.2)) +
stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red") +
facet_grid(Pho4~date) +
theme_bw(base_size = 14)

5. High variance samples
Summarize the background subtracted data by calculating the means and
cv for each strain.
dat2 <- dat1 %>%
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 = num(mean(intensity), digits = 0),
cv = num(sd(intensity)/mean(intensity), digits = 2)
) %>%
arrange(desc(cv))
`summarise()` has grouped output by 'date', 'plasmid', 'host'. You can override using the `.groups` argument.
dat2 %>%
filter(plasmid != "NA", parameter != "FSC.H") %>%
ggplot(aes(x = cv)) + geom_histogram(aes(y = ..density../20)) + stat_ecdf() +
geom_hline(yintercept = 0.8, linetype = 2) +
ylab("cumulative density") +
facet_wrap(~parameter) +
theme_cowplot()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

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
ndat2 <- dat1 %>%
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)
) %>%
arrange(desc(cv))
`summarise()` has grouped output by 'date', 'plasmid', 'host'. You can override using the `.groups` argument.
ndat2 %>%
filter(plasmid != "NA", parameter != "FSC.H") %>%
ggplot(aes(x = cv)) + geom_histogram(aes(y = ..density../20)) + stat_ecdf() +
geom_hline(yintercept = 0.8, linetype = 2) +
ylab("cumulative density") +
facet_wrap(~parameter) +
theme_cowplot()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

CV is smaller on the cell size normalized fluorescence values.
Main
Plotting functions
Here I’d like to develop a series of plotting functions that take the
names or any part of the Pho4 chimera annotation as input and plot their
results in a variety of ways Load the Pho4 plasmid information and merge
with the reshaped data
meta <- read_tsv("../data/20220330-chimera-Pho4-makeup.tsv", col_types = "cccc")
Plotting function
# extract ximera names
refs <- c("CCCCC","SSSSS")
ximeras <- setdiff(meta$symbol, refs)
# make a test set
test <- sample(ximeras, 6)
# subset data
tmp <- meta %>%
filter(symbol %in% c(refs,test)) %>%
inner_join(dat1, by = "plasmid") %>%
mutate(symbol = factor(symbol, levels = c(refs, test)))
Plot individual components
tmp %>%
pivot_longer(nGFP:nRFP, names_to = "parameter", values_to = "intensity") %>%
mutate(parameter = ordered(parameter, levels = c("nRFP", "nGFP"))) %>%
#pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>%
#mutate(parameter = ordered(parameter, levels = c("YL2.H", "BL1.H"))) %>%
ggplot(aes(x = symbol, y = intensity, group = host)) +
geom_bar(aes(fill = host), width = 0.5, alpha = 0.8,
stat = "summary", fun = "mean", position = position_dodge(0.5)) +
geom_point(aes(color = host), size = 1,
position = position_jitterdodge(dodge.width = 0.5)) +
scale_color_manual(values = c("PHO2" = "gray20", "pho2∆" = "gray40")) +
scale_fill_viridis_d(begin = 0.2, end = 0.6) +
#stat_summary(fun = "mean", geom = "crossbar", color = "red", width = 0.25,
# position = position_dodge(0.75), ) +
facet_wrap(~parameter, scale = "free_y", ncol = 1) +
xlab("Pho4 chimera") + expand_limits(y = 0) +
theme_gray(base_size = 14) +
theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"))

tmp %>%
#mutate(`YL2.H/BL1.H` = YL2.H/BL1.H,
mutate(`R/G` = nRFP/nGFP) %>%
ggplot(aes(x = symbol, y = `R/G`, group = host)) +
geom_bar(aes(fill = host), width = 0.5, alpha = 0.8,
stat = "summary", fun = "mean", position = position_dodge(0.5)) +
geom_point(aes(color = host), position = position_jitterdodge(dodge.width = 0.5)) +
scale_color_manual(values = c("PHO2" = "gray20", "pho2∆" = "gray40")) +
scale_fill_viridis_d(begin = 0.2, end = 0.6) +
#stat_summary(fun = "mean", color = "red", geom = "crossbar", width = 0.2,
# position = position_dodge(0.75), ) +
theme_gray(base_size = 14) + xlab("Pho4 chimera") +
theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"))

Next idea is to plot the ratio between the mean R/G for PHO2
and mean R/G for pho2∆, over the mean R/G for PHO2
First summarize the data.
datsum <- dat1 %>%
filter(plasmid != "NA") %>%
mutate(`R/G` = YL2.H/BL1.H, `nR/G` = nRFP/nGFP) %>%
group_by(date, plasmid, host) %>%
summarize(across(c(BL1.H, nGFP, YL2.H, nRFP, `R/G`, `nR/G`), mean), .groups = "drop") %>%
pivot_wider(names_from = host, values_from = BL1.H:`nR/G`) %>%
mutate(`pho2∆/PHO2` = `R/G_pho2∆`/`R/G_PHO2`,
`n.pho2∆/PHO2` = `nR/G_pho2∆`/`nR/G_PHO2`)
# useful to set a flag for low activity mutants
low.act.th <- datsum %>% filter(plasmid == "194") %>% summarize(across(.cols = where(is.numeric), .fns = mean)) %>% unlist()
Then extract the subset for plotting
tmpsum <- meta %>%
filter(symbol %in% c(refs,test)) %>%
inner_join(datsum, by = "plasmid") %>%
mutate(symbol = factor(symbol, levels = c(refs, test)))
Design the plot
tmpsum %>%
mutate(Activity = ifelse(`R/G_PHO2` < 2*low.act.th["R/G_pho2∆"], "low", "pass")) %>%
ggplot(aes(x = symbol, y = `pho2∆/PHO2`)) +
geom_col(aes(group = date, fill = `R/G_PHO2`), width = 0.75, color = "gray50",
position = position_dodge(0.9)) +
#geom_point(aes(color = host), position = position_jitterdodge(dodge.width = 0.5)) +
scale_fill_gradient2("Activity") +
#scale_color_manual(values = c(alpha("black",0), "red3")) +
#stat_summary(fun = "mean", color = "red", geom = "crossbar", width = 0.2,
# position = position_dodge(0.75), ) +
facet_grid(.~Activity, scales = "free_x", space = "free_x", labeller = "label_both") +
theme_bw(base_size = 14) + xlab("Pho4 chimera") +
theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"))

X-Y plot
p3 <- tmpsum %>%
mutate(`nR/G_PHO2` = signif(`nR/G_PHO2`, digits = 2),
`nR/G_pho2∆` = signif(`nR/G_pho2∆`, digits = 2)) %>%
ggplot(aes(x = `nR/G_PHO2`, y = `nR/G_pho2∆`, label = symbol)) +
geom_point(size = 2.5) + geom_abline(slope = 1) +
theme_gray(base_size = 14)
ggplotly(p3, tooltip = c("label", "x", "y"))
Warning: `gather_()` was deprecated in tidyr 1.2.0.
Please use `gather()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
LS0tCnRpdGxlOiAiRTAxMyBQaG80IGNoaW1lcmEgYWN0aXZpdHkgYW5hbHlzaXMsIG5ldyBob3N0IgphdXRob3I6IEJpbiBIZQpkYXRlOiAiMjAyMi0wMy0zMCB1cGRhdGVkIGByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhyZXF1aXJlKHBsb3RseSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhyZXF1aXJlKHRpZHl2ZXJzZSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhyZXF1aXJlKGNvd3Bsb3QpKQpgYGAKCiMgR29hbAotIEFuYWx5emUgdGhlIGxhdGVzdCBiYXRjaGVzIG9mIGZsb3cgY3l0b21ldHJ5IGRhdGEgdG8gZGV0ZXJtaW5lIHRoZSBjb250cmlidXRpb24gb2YgZGlmZmVyZW50IChtYXRjaGluZykgcGFydHMgb2YgU2NQaG80IGFuZCBDZ1BobzQgdG8gdGhlaXIgZGlmZmVyZW5jZSBpbiBQaG8yIGRlcGVuZGVuY2UuIAotIERldmVsb3AgYW4gYW5hbHlzaXMgcGlwZWxpbmUgdG8gcGVyZm9ybSBRQywgY29ycmVjdGlvbiAoaWYgbmVlZGVkKSBhbmQgcGxvdHRpbmcgdGhlIHJlc3VsdHMuCgojIERhdGEKTWVyZ2UgdGhlIHRocmVlIGJhdGNoZXMKYGBge3J9CnJhdyA8LSBsaXN0KAogICIwMy8xNS8yMiIgPSByZWFkX3RzdigiLi4vZGF0YS8yMDIyMDMxNS1FTy1jaGltZXJhLWJhdGNoLTEvMjAyMjAzMjktZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAiMDMvMjIvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjAzMjItRU8tY2hpbWVyYS1iYXRjaC0yLzIwMjIwMzI3LWdhdGVkLW1lZGlhbi1vdXQudHh0Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSksCiAgIjAzLzI5LzIyIiA9IHJlYWRfdHN2KCIuLi9kYXRhLzIwMjIwMzI5LUVPLWNoaW1lcmEtYmF0Y2gtMy8yMDIyMDMzMC1nYXRlZC1tZWRpYW4tb3V0LnR4dCIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCikKZGF0IDwtIGJpbmRfcm93cyhyYXcsIC5pZCA9ICJkYXRlIikgJT4lIAogICNzZXBhcmF0ZShjb2wgPSB3ZWxsLCBzZXAgPSAxLCBpbnRvID0gYygicm93IiwgImNvbCIpKSAlPiUgCiAgc2VwYXJhdGUoY29sID0gc2FtcGxlLCBzZXAgPSAiLSIsIGludG8gPSBjKCJwbGFzbWlkIiwgImhvc3QiLCAicmVwIikpCmBgYAoKCiMgUUMKIyMgMS4gTnVtYmVyIG9mIGV2ZW50cyBwZXIgc2FtcGxlCmBgYHtyfQpkYXQgJT4lIGdncGxvdChhZXMoeCA9IG5faW5kdWN0aW9uKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGZpbGwgPSAiZm9yZXN0Z3JlZW4iKSArIGZhY2V0X2dyaWQoaG9zdH5kYXRlKSArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSAjKyBwYW5lbF9ib3JkZXIoKQpgYGAKPiBNYWpvcml0eSBvZiB0aGUgZXhwZXJpbWVudGFsIHdlbGxzIChub3QgYmxhbmspIGhhdmUgPiAxMDAwMCBldmVudHMsIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBhIGZldyBzYW1wbGVzCgpgYGB7cn0KZGF0ICU+JSBmaWx0ZXIoaG9zdCAhPSAiYmxhbmsiLCBuX2luZHVjdGlvbiA8IDEwMDAwKQpgYGAKR2l2ZW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBldmVudCBjb3VudHMsIHdlIHdpbGwgbGFiZWwgYWxsIHNhbXBsZXMgd2l0aCA8IDcwMDAgY291bnRzLCB3aGljaCB3b3VsZCBleGNsdWRlIDIgc2FtcGxlcy4gVGhlIHJhdGlvbmFsZSBpcyB0aGF0IGV2ZW4gdGhvdWdoIHNvbWUgc2FtcGxlcyBoYWQgYmV0d2VlbiA3MDAwIC0gMTAwMDAgZXZlbnRzLCB0aGVpciBtZWFuIGZsdW9yZXNjZW5jZSB2YWx1ZXMgYXBwZWFyIGluIGxpbmUgd2l0aCB0aGUgb3RoZXIgcmVwbGljYXRlcyBvZiB0aGUgc2FtZSBnZW5vdHlwZS4gSSBhbHNvIHJlbW92ZWQgdGhlIGJsYW5rIHdlbGxzIGFuZCBhZGQgYSBmbGFnIHRvIG1hcmsgdGhlIHBsYXNtaWRzIHRoYXQgRW1pbHkgcmVtYWRlIGJlY2F1c2UgdGhlIG9yaWdpbmFsIG9uZSAodXNlZCBmb3IgdGhpcyBiYXRjaCBvZiBkYXRhKSBjb250YWlucyBub25zeW5vbnltb3VzIG11dGF0aW9ucy4KYGBge3J9CmV2ZW50LnRoIDwtIDcwMDAKCmxpc3QubXV0YXRpb25zIDwtIGFzLmNoYXJhY3RlcihjKDIxNSwgMjA5LCAyMTEsIDIxMCwgMjE3LCAyMTgsIDIyMCwgMjIxLCAyMjMsIDIyNCwgMjIyLCAyMjcsIDIzMCwgMjI5LCAyMzEsIDIzMywgMjQwLCAyNDEsIDI1MDoyNTUsIDI1NywgMjU4LCAyNjUsIDI2NikpCgpleHB0IDwtIGRhdCAlPiUgCiAgZmlsdGVyKGhvc3QgIT0gImJsYW5rIikgJT4lIAogIGdyb3VwX2J5KGRhdGUsIHBsYXNtaWQsIGhvc3QpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgbl9maWx0ZXIgPSBzdW0obl9pbmR1Y3Rpb24gPj0gZXZlbnQudGgpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgbXV0YXRlKGZsYWcgPSBpZmVsc2UocGxhc21pZCAlaW4lIGxpc3QubXV0YXRpb25zLCAibXV0YXRpb24iLCAiIikpCmBgYAoKYGBge3J9CmRhdCA8LSBkYXQgJT4lIAogIG11dGF0ZSgKICAgIGxvd19ldmVudF9jb3VudCA9IG5faW5kdWN0aW9uIDwgZXZlbnQudGgsCiAgICBtdXRhdGlvbiA9IGlmZWxzZShwbGFzbWlkICVpbiUgbGlzdC5tdXRhdGlvbnMsIFRSVUUsIEZBTFNFKQogICkgJT4lIAogIGZpbHRlcihob3N0ICE9ICJibGFuayIpCmBgYAoKSG93IG1hbnkgcGxhc21pZC1ob3N0IGNvbWJpbmF0aW9uIGhhdmUgPCAzIHJlcGxpY2F0ZXMgYWZ0ZXIgcmVtb3Zpbmcgc2FtcGxlcyB3aXRoIGxvdyBldmVudCBjb3VudHM/CmBgYHtyfQpkYXQgJT4lIGZpbHRlcighbG93X2V2ZW50X2NvdW50KSAlPiUgCiAgY291bnQocGxhc21pZCwgaG9zdCkgJT4lIAogIGZpbHRlcihuIDwgMykKYGBgCgoKIyMgMi4gQmFja2dyb3VuZCBzdWJ0cmFjdGlvbgoKQ2hlY2sgdGhlIGJhY2tncm91bmQgZmx1b3Jlc2NlbmNlIGxldmVscyBhY3Jvc3MgZGlmZmVyZW50IGRheXMuCmBgYHtyfQpkYXQgJT4lIGZpbHRlcihob3N0ID09ICIxNTYiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKEJMMS5IOm5SRlAsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKSAlPiUgCiAgbXV0YXRlKHBhcmFtZXRlciA9IG9yZGVyZWQocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJCTDEuSCIsICJZTDIuSCIsICJuR0ZQIiwgIm5SRlAiKSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gaW50ZW5zaXR5KSkgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHdlbGwpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fc2UiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAwLjEpKSArCiAgZmFjZXRfd3JhcCh+cGFyYW1ldGVyLCBzY2FsZSA9ICJmcmVlX3kiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCmBgYAoKPiAwMy8yOS8yMiBEOSBzaG93ZWQgaGlnaGVyIGJhY2tncm91bmQgZmx1b3Jlc2NlbmNlIHRoYW4gdGhlIG90aGVycy4gYWZ0ZXIgY2hlY2tpbmcgdGhlIGdhdGluZyByZXN1bHQsIEkgZm91bmQgdGhhdCBOQS0xNTYtMiBzYW1wbGUgaW4gRDkgaGFkIGEgc2xpZ2h0bHkgd2lkZXIgZGlzdHJpYnV0aW9uLCBhbmQgdGhlIDJkIGNsdXN0ZXIgZ2F0ZSBpcyBhbHNvIHdpZGVyIHRoYW4gdGhlIG90aGVyIHR3byBzYW1wbGVzLiBUaGUgY2VsbCBzaXplIG5vcm1hbGl6ZWQgaW50ZW5zaXR5IGRvZXNuJ3Qgc2hvdyB0aGUgc2FtZSBwYXR0ZXJuLCBzdWdnZXN0aW5nIHRoYXQgYXQgbGVhc3Qgc29tZSBvZiB0aGUgZGlmZmVyZW5jZSBjb3VsZCBiZSBkdWUgdG8gY2VsbCBzaXplIHZhcmlhdGlvbi4gVHJ5IGp1c3QgYXZlcmFnaW5nIHRoZSB0aHJlZSBibGFuayB3ZWxscyBhbmQgcGVyZm9ybSB0aGUgYmFja2dyb3VuZCByZW1vdmFsLgoKU3VidHJhY3QgdGhlIGJhY2tncm91bmQKYGBge3J9CmJnIDwtIGRhdCAlPiUgCiAgZmlsdGVyKGhvc3QgPT0gIjE1NiIpICU+JSAKICBncm91cF9ieShkYXRlKSAlPiUgCiAgc3VtbWFyaXplKGFjcm9zcyhGU0MuSDpuUkZQLCB+IHJvdW5kKG1lYW4oLngpLDEpKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiZGF0ZSIpCgpkYXQxIDwtIGRhdCAlPiUgCiAgc2VsZWN0KGRhdGU6aG9zdCwgRlNDLkg6blJGUCwgbG93X2V2ZW50X2NvdW50LCBtdXRhdGlvbikgJT4lCiAgbXV0YXRlKAogICAgQkwxLkggPSBCTDEuSCAtIGJnW2RhdGUsICJCTDEuSCJdLAogICAgWUwyLkggPSBZTDIuSCAtIGJnW2RhdGUsICJZTDIuSCJdLAogICAgbkdGUCA9IG5HRlAgLSBiZ1tkYXRlLCAibkdGUCJdLAogICAgblJGUCA9IG5SRlAgLSBiZ1tkYXRlLCAiblJGUCJdLAogICkKYGBgCgpEb3VibGUgY2hlY2sgdGhhdCB0aGUgc3VidHJhY3Rpb24gd29ya2VkIGNvcnJlY3RseQpgYGB7cn0KZGF0MSAlPiUgZmlsdGVyKGhvc3QgPT0gIjE1NiIpICU+JSAKICBwaXZvdF9sb25nZXIoQkwxLkg6blJGUCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBtdXRhdGUocGFyYW1ldGVyID0gb3JkZXJlZChwYXJhbWV0ZXIsIGxldmVscyA9IGMoIkJMMS5IIiwgIllMMi5IIiwgIm5HRlAiLCAiblJGUCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBpbnRlbnNpdHkpKSArIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gd2VsbCkpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZSIsIGdlb20gPSAicG9pbnRyYW5nZSIsIGNvbG9yID0gInJlZCIsIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IDAuMSkpICsKICBmYWNldF93cmFwKH5wYXJhbWV0ZXIsIHNjYWxlID0gImZyZWVfeSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkKCiMgcmVtb3ZlIHRoZSB5SDE1NiBzYW1wbGVzCmRhdDEgPC0gZGF0MSAlPiUgCiAgZmlsdGVyKGhvc3QgIT0gIjE1NiIpICU+JSAKICBtdXRhdGUoaG9zdCA9IG9yZGVyZWQoaG9zdCwgbGV2ZWxzID0gYygiNTU1IiwgIjM3MyIpLCBsYWJlbHMgPSBjKCJQSE8yIiwgInBobzLiiIYiKSkpCmBgYAoKRXhwb3J0IHRoZSBiYWNrZ3JvdW5kLXN1YnRyYWN0ZWQgdmFsdWVzIGZvciBsYXRlciB1c2Ugd2l0aCB0aGUgc2hpbnlhcHAKYGBge3J9CndyaXRlX3RzdihkYXQxLCAiLi4vb3V0cHV0LzIwMjIwNjE0LW1hcjIyLWJhdGNoLWJnLXN1Yi1kYXRhLnRzdiIpCmBgYAoKCiMjIDMuIENvbnNpc3RlbmN5IGFjcm9zcyBwbGF0ZXMuCgpDaGVjayB0aGUgYmFja2dyb3VuZC1zdWJ0cmFjdGVkIGZsdW9yZXNjZW5jZSB2YWx1ZXMgZm9yIHRoZSBob3N0IHN0cmFpbnMgKHlIMzczIGFuZCB5SDU1NSkgYXMgd2VsbCBhcyB0aGUgcG9zaXRpdmUgY29udHJvbCBzdHJhaW4gKHBIMTg4IGluIHlIMzczIG9yIHlINTU1IGJhY2tncm91bmRzKSwgYm90aCBvZiB3aGljaCBhcmUgcHJlc2VudCBvbiBlYWNoIHBsYXRlLgoKYGBge3J9CmRhdDEgJT4lIGZpbHRlcihwbGFzbWlkICVpbiUgYygiMTg4IiwgIk5BIikpICU+JSAKICBwaXZvdF9sb25nZXIoQkwxLkg6WUwyLkgsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKSAlPiUgCiAgI211dGF0ZShwYXJhbWV0ZXIgPSBvcmRlcmVkKHBhcmFtZXRlciwgbGV2ZWxzID0gYygiQkwxLkgiLCAiWUwyLkgiLCAibkdGUCIsICJuUkZQIikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcGxhc21pZCwgeSA9IGludGVuc2l0eSwgY29sb3IgPSBkYXRlKSkgKyAKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKyAKICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9IDIpICsKICBmYWNldF9ncmlkKHBhcmFtZXRlcn5ob3N0LCBzY2FsZSA9ICJmcmVlX3kiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gMykpCmBgYAoKPiAxLiBUaGUgaG9zdCBzdHJhaW4gZmx1b3Jlc2NlbmNlIGxldmVscyBhcHBlYXIgdG8gYmUgY29uc2lzdGVudCBhY3Jvc3MgdGhlIHRocmVlIGRheXMuIEFkZGl0aW9uYWxseSwgdGhlaXIgR0ZQIGxldmVscyBhcmUgemVybywgYXMgZXhwZWN0ZWQuCj4gMS4gVGhlIHBvc2l0aXZlIGNvbnRyb2wgc3RyYWluIGhhcyBzdHJvbmcgQkwxLkggYW5kIGNvcnJlc3BvbmRpbmdseSBoYXMgc3Ryb25nIFlMMi5ILgoKVGhlIHNpemUgbm9ybWFsaXplZCB2YWx1ZXMgc2hvdyBzbGlnaHRseSBsb3dlciB2YXJpYW5jZToKYGBge3J9CmRhdDEgJT4lIGZpbHRlcihwbGFzbWlkICVpbiUgYygiMTg4IiwgIk5BIikpICU+JSAKICBwaXZvdF9sb25nZXIobkdGUDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogICNtdXRhdGUocGFyYW1ldGVyID0gb3JkZXJlZChwYXJhbWV0ZXIsIGxldmVscyA9IGMoIkJMMS5IIiwgIllMMi5IIiwgIm5HRlAiLCAiblJGUCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHBsYXNtaWQsIHkgPSBpbnRlbnNpdHksIGNvbG9yID0gZGF0ZSkpICsgCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsgCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAyKSArCiAgZmFjZXRfZ3JpZChwYXJhbWV0ZXJ+aG9zdCwgc2NhbGUgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9IDMpKQpgYGAKIyMgNC4gV2VsbCBwb3NpdGlvbgoKKipfUmF0aW9uYWxlXyoqCgotIEluIG15IG9yaWdpbmFsIHBsYXRlIGRlc2lnbiwgSSBwbGFjZWQgYSBwb3NpdGl2ZSBjb250cm9sIHN0cmFpbiAoZW52aXNpb25lZCBDZ1BobzQtbU5lb24gaW4gX1BITzJfIGJhY2tncm91bmQgZm9yIGV4YW1wbGUpIGluIHRoZSBjb250cm9sIGNvbHVtbnMgKDEsIDUsIDkpIG9uIGV2ZXJ5IG90aGVyIHJvdyAoQSwgQywgRSwgRykuIFRoZSByZWFzb24gZm9yIHRoaXMgaXMgdG8gdXNlIGl0IHRvIGlkZW50aWZ5IGFueSB3ZWxsIHBvc2l0aW9uIGVmZmVjdCBvbiB0aGUgZmx1b3Jlc2NlbmNlIHJlYWRpbmdzLgotIEluIEVtaWx5J3MgaW1wbGVtZW50YXRpb24sIHNoZSBpbnN0ZWFkIHB1dCAqKmEgcGFpcioqIG9mIHN0cmFpbnMsIG5hbWVseSBwSDE4OC15SDMyMyBhbmQgcEgxODgteUg1NTUgaW4gdGhlc2Ugd2VsbHMuIFRoaXMgbWVhbnMgSSBjYW5ub3QgdXNlIHRoZSBwb3NpdGl2ZSBjb250cm9sIHdlbGxzIGV4YWN0bHkgdGhlIHdheSBhcyBJIGRlc2lnbmVkIHRoZW0uIEJ1dCBJIGNhbiBzdGlsbCB1c2UgdGhlbSB0byBzcG90IGFueSB0cmVuZC4KICAgIApgYGB7cn0KZGF0MSAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgPT0gIjE4OCIpICU+JSAKICBzZXBhcmF0ZSh3ZWxsLCBpbnRvID0gYygicm93IiwgImNvbCIpLCBzZXAgPSAxKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKEJMMS5IOllMMi5ILCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIGdncGxvdChhZXMoeCA9IHJvdywgeSA9IGludGVuc2l0eSwgZ3JvdXAgPSBkYXRlKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRhdGUpLCBzaXplID0gMSkgKyAKICAjZ2VvbV9saW5lKGFlcyhjb2xvciA9IGRhdGUpLCBzaXplID0gMC40KSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhjb2xvciA9IGRhdGUpLCBnZW9tID0gImxpbmUiLCBmdW4gPSBtZWFuKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAyKSArCiAgZmFjZXRfZ3JpZChwYXJhbWV0ZXJ+aG9zdCwgc2NhbGVzID0gImZyZWVfeSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkKYGBgCgo+IC0gbm8gb2Jpdm91cyB0cmVuZCBiZXR3ZWVuIHRoZSByb3dzIChvciBjb2x1bW5zLCBub3Qgc2hvd24pCj4gLSBhIGNsZWFyIGNvcnJlbGF0aW9uIGJldHdlZW4gWUwyLkggYW5kIEJMMS5ILiBhdCBsZWFzdCBwYXJ0IG9mIHRoaXMgaXMgZHVlIHRvIHRoZSBjZWxsIHNpemUgZGlmZmVyZW5jZXMgLS0gc2VlIHNpemUgbm9ybWFsaXplZCBkYXRhIGJlbG93OgoKYGBge3J9CmRhdDEgJT4lIAogIGZpbHRlcihwbGFzbWlkID09ICIxODgiKSAlPiUgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSkgJT4lIAogIHBpdm90X2xvbmdlcihjKFlMMi5ILCBuUkZQKSwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByb3csIHkgPSBpbnRlbnNpdHksIGdyb3VwID0gZGF0ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkYXRlKSwgc2l6ZSA9IDEpICsgCiAgI2dlb21fbGluZShhZXMoY29sb3IgPSBkYXRlKSwgc2l6ZSA9IDAuNCkgKwogIHN0YXRfc3VtbWFyeShhZXMoY29sb3IgPSBkYXRlKSwgZ2VvbSA9ICJsaW5lIiwgZnVuID0gbWVhbikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBwYWxldHRlID0gMikgKwogIGZhY2V0X2dyaWQocGFyYW1ldGVyfmhvc3QsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCmBgYAoKLSBXaGF0IHdlIGNhcmUgYWJvdXQgaXMgdGhlIHJhdGlvIGJldHdlZW4gUGhvNC1tTmVvbiBhbmQgX1BITzVwcl8tbUNoZXJyeQoKYGBge3J9CmRhdDEgJT4lIAogIGZpbHRlcihwbGFzbWlkID09ICIxODgiKSAlPiUgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSkgJT4lIAogIGdncGxvdChhZXMoeCA9IEJMMS5ILCB5ID0gWUwyLkgpKSArIAogIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gZGF0ZSwgY29sb3IgPSByb3cpLCBzaXplID0gMykgKyAKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJncmF5NTAiLCBzaXplID0gMC41KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSAxNToxNykgKwogICNzY2FsZV94X2xvZzEwKCkgKyBzY2FsZV95X2xvZzEwKCkgKwogICNmYWNldF9ncmlkKHBhcmFtZXRlcn5ob3N0LCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KQpgYGAKCj4gLSBUaGVyZSBpcyB2YXJpYXRpb24gaW4gQkwxLkggYW5kIGNvcnJlc3BvbmRpbmdseSBpbiBZTDIuSCwgYnV0IHRoZSByYXRpbyBiZXR3ZWVuIHRoZSB0d28gYXJlIHZlcnkgY29uc2lzdGVudAoKTGV0J3MgY2hlY2sgYm90aCBTY1BobzQgKHBIMTk0KSBhbmQgQ2dQaG80IChwSDE4OCkgdG8gc2VlIGlmIHRoZWlyIGJlaGF2aW9ycyBhcmUgY29uc2lzdGVudCBhY3Jvc3MgdGhlIGRheXMuCmBgYHtyfQpkYXQxICU+JSAKICBmaWx0ZXIocGxhc21pZCAlaW4lIGMoIjE4OCIsICIxOTQiKSkgJT4lIAogIG11dGF0ZShgWUwyLkgvQkwxLkhgID0gWUwyLkgvQkwxLkgsCiAgI211dGF0ZShgWUwyLkgvQkwxLkhgID0gblJGUC9uR0ZQLAogICAgICAgICBQaG80ID0gZmFjdG9yKHBsYXNtaWQsIGxldmVscyA9IGMoIjE5NCIsICIxODgiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiU2NQaG80IiwgIkNnUGhvNCIpKSkgJT4lIAogIHNlcGFyYXRlKHdlbGwsIGludG8gPSBjKCJyb3ciLCAiY29sIiksIHNlcCA9IDEpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBob3N0LCB5ID0gYFlMMi5IL0JMMS5IYCkpICsgCiAgZ2VvbV9wb2ludChjb2xvciA9IGFscGhhKCJncmF5NTAiLCAwLjkpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjIpKSArIAogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAicmVkIikgKwogIGZhY2V0X2dyaWQoUGhvNH5kYXRlKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCmBgYAoKIyMgNS4gSGlnaCB2YXJpYW5jZSBzYW1wbGVzCgpTdW1tYXJpemUgdGhlIGJhY2tncm91bmQgc3VidHJhY3RlZCBkYXRhIGJ5IGNhbGN1bGF0aW5nIHRoZSBtZWFucyBhbmQgY3YgZm9yIGVhY2ggc3RyYWluLgpgYGB7cn0KZGF0MiA8LSBkYXQxICU+JSAKICBzZWxlY3QoLW5HRlAsIC1uUkZQKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKEZTQy5IOllMMi5ILCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIGdyb3VwX2J5KGRhdGUsIHBsYXNtaWQsIGhvc3QsIHBhcmFtZXRlcikgJT4lIAogIHN1bW1hcml6ZSgKICAgIG4gPSBuKCksCiAgICBtZWFuID0gbnVtKG1lYW4oaW50ZW5zaXR5KSwgZGlnaXRzID0gMCksCiAgICBjdiA9IG51bShzZChpbnRlbnNpdHkpL21lYW4oaW50ZW5zaXR5KSwgZGlnaXRzID0gMikKICApICU+JSAKICBhcnJhbmdlKGRlc2MoY3YpKQpgYGAKCmBgYHtyfQpkYXQyICU+JSAKICBmaWx0ZXIocGxhc21pZCAhPSAiTkEiLCBwYXJhbWV0ZXIgIT0gIkZTQy5IIikgJT4lIAogIGdncGxvdChhZXMoeCA9IGN2KSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uLzIwKSkgKyBzdGF0X2VjZGYoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOCwgbGluZXR5cGUgPSAyKSArCiAgeWxhYigiY3VtdWxhdGl2ZSBkZW5zaXR5IikgKyAKICBmYWNldF93cmFwKH5wYXJhbWV0ZXIpICsKICB0aGVtZV9jb3dwbG90KCkKYGBgCgo+IFRoZSBoaXN0b2dyYW0ncyB5LWF4aXMgaXMgbm90IHNob3duLiBUaGUgbGluZSBncmFwaCByZXByZXNlbnRzIHRoZSBlbXBpcmljYWwgQ0RGLCBhbmQgdGhlIGRvdHRlZCBob3Jpem9udGFsIGxpbmUgaXMgYXQgODAlLiBHRlAgaXMgbW9yZSB2YXJpYWJsZSB0aGFuIFJGUCwgbGlrZWx5IGJlY2F1c2UgdGhlIGFic29sdXRlIHZhbHVlcyBvZiB0aGUgZm9ybWVyIGlzIGxvd2VyLiBGb3IgYm90aCwgfjgwJSBvZiB0aGUgc2FtcGxlcyBoYXZlIGEgQ1YgPCAyMCUuCgpEbyB0aGUgc2FtZSBmb3IgdGhlIGNlbGwgc2l6ZS1ub3JtYWxpemVkIHZhbHVlcwpgYGB7cn0KbmRhdDIgPC0gZGF0MSAlPiUgCiAgc2VsZWN0KC1CTDEuSCwgLVlMMi5IKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKG5HRlA6blJGUCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBncm91cF9ieShkYXRlLCBwbGFzbWlkLCBob3N0LCBwYXJhbWV0ZXIpICU+JSAKICBzdW1tYXJpemUoCiAgICBuID0gbigpLAogICAgbWVhbiA9IG51bShtZWFuKGludGVuc2l0eSksIGRpZ2l0cyA9IDApLAogICAgY3YgPSBudW0oc2QoaW50ZW5zaXR5KS9tZWFuKGludGVuc2l0eSksIGRpZ2l0cyA9IDIpCiAgKSAlPiUgCiAgYXJyYW5nZShkZXNjKGN2KSkKYGBgCgpgYGB7cn0KbmRhdDIgJT4lIAogIGZpbHRlcihwbGFzbWlkICE9ICJOQSIsIHBhcmFtZXRlciAhPSAiRlNDLkgiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3YpKSArIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4vMjApKSArIHN0YXRfZWNkZigpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC44LCBsaW5ldHlwZSA9IDIpICsKICB5bGFiKCJjdW11bGF0aXZlIGRlbnNpdHkiKSArIAogIGZhY2V0X3dyYXAofnBhcmFtZXRlcikgKwogIHRoZW1lX2Nvd3Bsb3QoKQpgYGAKCj4gQ1YgaXMgc21hbGxlciBvbiB0aGUgY2VsbCBzaXplIG5vcm1hbGl6ZWQgZmx1b3Jlc2NlbmNlIHZhbHVlcy4KCiMgTWFpbgojIyBQbG90dGluZyBmdW5jdGlvbnMKSGVyZSBJJ2QgbGlrZSB0byBkZXZlbG9wIGEgc2VyaWVzIG9mIHBsb3R0aW5nIGZ1bmN0aW9ucyB0aGF0IHRha2UgdGhlIG5hbWVzIG9yIGFueSBwYXJ0IG9mIHRoZSBQaG80IGNoaW1lcmEgYW5ub3RhdGlvbiBhcyBpbnB1dCBhbmQgcGxvdCB0aGVpciByZXN1bHRzIGluIGEgdmFyaWV0eSBvZiB3YXlzCkxvYWQgdGhlIFBobzQgcGxhc21pZCBpbmZvcm1hdGlvbiBhbmQgbWVyZ2Ugd2l0aCB0aGUgcmVzaGFwZWQgZGF0YQpgYGB7cn0KbWV0YSA8LSByZWFkX3RzdigiLi4vZGF0YS8yMDIyMDYyMS1jaGltZXJhLVBobzQtbWFrZXVwLnRzdiIsIGNvbF90eXBlcyA9ICJjY2NjYyIpCmBgYAoKUGxvdHRpbmcgZnVuY3Rpb24KYGBge3J9CiMgZXh0cmFjdCB4aW1lcmEgbmFtZXMKcmVmcyA8LSBjKCJDQ0NDQyIsIlNTU1NTIikKeGltZXJhcyA8LSBzZXRkaWZmKG1ldGEkc3ltYm9sLCByZWZzKQojIG1ha2UgYSB0ZXN0IHNldAp0ZXN0IDwtIHNhbXBsZSh4aW1lcmFzLCA2KQojIHN1YnNldCBkYXRhCnRtcCA8LSBtZXRhICU+JSAKICBmaWx0ZXIoc3ltYm9sICVpbiUgYyhyZWZzLHRlc3QpKSAlPiUgCiAgaW5uZXJfam9pbihkYXQxLCBieSA9ICJwbGFzbWlkIikgJT4lIAogIG11dGF0ZShzeW1ib2wgPSBmYWN0b3Ioc3ltYm9sLCBsZXZlbHMgPSBjKHJlZnMsIHRlc3QpKSkKYGBgCgpQbG90IGluZGl2aWR1YWwgY29tcG9uZW50cwpgYGB7cn0KdG1wICU+JSAKICBwaXZvdF9sb25nZXIobkdGUDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIG11dGF0ZShwYXJhbWV0ZXIgPSBvcmRlcmVkKHBhcmFtZXRlciwgbGV2ZWxzID0gYygiblJGUCIsICJuR0ZQIikpKSAlPiUgCiAgI3Bpdm90X2xvbmdlcihCTDEuSDpZTDIuSCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICAjbXV0YXRlKHBhcmFtZXRlciA9IG9yZGVyZWQocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJZTDIuSCIsICJCTDEuSCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN5bWJvbCwgeSA9IGludGVuc2l0eSwgZ3JvdXAgPSBob3N0KSkgKyAKICBnZW9tX2JhcihhZXMoZmlsbCA9IGhvc3QpLCB3aWR0aCA9IDAuNSwgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGhvc3QpLCBzaXplID0gMSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoZG9kZ2Uud2lkdGggPSAwLjUpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQSE8yIiA9ICJncmF5MjAiLCAicGhvMuKIhiIgPSAiZ3JheTQwIikpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChiZWdpbiA9IDAuMiwgZW5kID0gMC42KSArCiAgI3N0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGdlb20gPSAiY3Jvc3NiYXIiLCBjb2xvciA9ICJyZWQiLCB3aWR0aCA9IDAuMjUsCiAgIyAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNzUpLCApICsKICBmYWNldF93cmFwKH5wYXJhbWV0ZXIsIHNjYWxlID0gImZyZWVfeSIsIG5jb2wgPSAxKSArCiAgeGxhYigiUGhvNCBjaGltZXJhIikgKyBleHBhbmRfbGltaXRzKHkgPSAwKSArCiAgdGhlbWVfZ3JheShiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSwgZmFtaWx5ID0gIm1vbm8iKSkKYGBgCmBgYHtyfQp0bXAgJT4lIAogICNtdXRhdGUoYFlMMi5IL0JMMS5IYCA9IFlMMi5IL0JMMS5ILAogIG11dGF0ZShgUi9HYCA9IG5SRlAvbkdGUCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN5bWJvbCwgeSA9IGBSL0dgLCBncm91cCA9IGhvc3QpKSArIAogIGdlb21fYmFyKGFlcyhmaWxsID0gaG9zdCksIHdpZHRoID0gMC41LCBhbHBoYSA9IDAuOCwKICAgICAgICAgICBzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gaG9zdCksIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoZG9kZ2Uud2lkdGggPSAwLjUpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJQSE8yIiA9ICJncmF5MjAiLCAicGhvMuKIhiIgPSAiZ3JheTQwIikpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChiZWdpbiA9IDAuMiwgZW5kID0gMC42KSArCiAgI3N0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGNvbG9yID0gInJlZCIsIGdlb20gPSAiY3Jvc3NiYXIiLCB3aWR0aCA9IDAuMiwKICAjICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC43NSksICkgKwogIHRoZW1lX2dyYXkoYmFzZV9zaXplID0gMTQpICsgeGxhYigiUGhvNCBjaGltZXJhIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSwgZmFtaWx5ID0gIm1vbm8iKSkKYGBgCgpOZXh0IGlkZWEgaXMgdG8gcGxvdCB0aGUgcmF0aW8gYmV0d2VlbiB0aGUgbWVhbiBSL0cgZm9yIF9QSE8yXyBhbmQgbWVhbiBSL0cgZm9yIF9waG8y4oiGXywgb3ZlciB0aGUgbWVhbiBSL0cgZm9yIF9QSE8yXwoKRmlyc3Qgc3VtbWFyaXplIHRoZSBkYXRhLgpgYGB7cn0KZGF0c3VtIDwtIGRhdDEgJT4lCiAgZmlsdGVyKHBsYXNtaWQgIT0gIk5BIikgJT4lIAogIG11dGF0ZShgUi9HYCA9IFlMMi5IL0JMMS5ILCBgblIvR2AgPSBuUkZQL25HRlApICU+JSAKICBncm91cF9ieShkYXRlLCBwbGFzbWlkLCBob3N0KSAlPiUgCiAgc3VtbWFyaXplKGFjcm9zcyhjKEJMMS5ILCBuR0ZQLCBZTDIuSCwgblJGUCwgYFIvR2AsIGBuUi9HYCksIG1lYW4pLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGhvc3QsIHZhbHVlc19mcm9tID0gQkwxLkg6YG5SL0dgKSAlPiUgCiAgbXV0YXRlKGBwaG8y4oiGL1BITzJgID0gYFIvR19waG8y4oiGYC9gUi9HX1BITzJgLAogICAgICAgICBgbi5waG8y4oiGL1BITzJgID0gYG5SL0dfcGhvMuKIhmAvYG5SL0dfUEhPMmApCgojIHVzZWZ1bCB0byBzZXQgYSBmbGFnIGZvciBsb3cgYWN0aXZpdHkgbXV0YW50cwpsb3cuYWN0LnRoIDwtIGRhdHN1bSAlPiUgZmlsdGVyKHBsYXNtaWQgPT0gIjE5NCIpICU+JSBzdW1tYXJpemUoYWNyb3NzKC5jb2xzID0gd2hlcmUoaXMubnVtZXJpYyksIC5mbnMgPSBtZWFuKSkgJT4lIHVubGlzdCgpCmBgYAoKVGhlbiBleHRyYWN0IHRoZSBzdWJzZXQgZm9yIHBsb3R0aW5nCmBgYHtyfQp0bXBzdW0gPC0gbWV0YSAlPiUgCiAgZmlsdGVyKHN5bWJvbCAlaW4lIGMocmVmcyx0ZXN0KSkgJT4lIAogIGlubmVyX2pvaW4oZGF0c3VtLCBieSA9ICJwbGFzbWlkIikgJT4lIAogIG11dGF0ZShzeW1ib2wgPSBmYWN0b3Ioc3ltYm9sLCBsZXZlbHMgPSBjKHJlZnMsIHRlc3QpKSkKCmBgYAoKRGVzaWduIHRoZSBwbG90CmBgYHtyfQp0bXBzdW0gJT4lIAogIG11dGF0ZShBY3Rpdml0eSA9IGlmZWxzZShgUi9HX1BITzJgIDwgMipsb3cuYWN0LnRoWyJSL0dfcGhvMuKIhiJdLCAibG93IiwgInBhc3MiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN5bWJvbCwgeSA9IGBwaG8y4oiGL1BITzJgKSkgKyAKICBnZW9tX2NvbChhZXMoZ3JvdXAgPSBkYXRlLCBmaWxsID0gYFIvR19QSE8yYCksIHdpZHRoID0gMC43NSwgY29sb3IgPSAiZ3JheTUwIiwKICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpICsKICAjZ2VvbV9wb2ludChhZXMoY29sb3IgPSBob3N0KSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShkb2RnZS53aWR0aCA9IDAuNSkpICsgCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIoIkFjdGl2aXR5IikgKwogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhhbHBoYSgiYmxhY2siLDApLCAicmVkMyIpKSArCiAgI3N0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGNvbG9yID0gInJlZCIsIGdlb20gPSAiY3Jvc3NiYXIiLCB3aWR0aCA9IDAuMiwKICAjICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC43NSksICkgKwogIGZhY2V0X2dyaWQoLn5BY3Rpdml0eSwgc2NhbGVzID0gImZyZWVfeCIsIHNwYWNlID0gImZyZWVfeCIsIGxhYmVsbGVyID0gImxhYmVsX2JvdGgiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgeGxhYigiUGhvNCBjaGltZXJhIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSwgZmFtaWx5ID0gIm1vbm8iKSkKYGBgCgpYLVkgcGxvdApgYGB7cn0KcDMgPC0gdG1wc3VtICU+JSAKICBtdXRhdGUoYG5SL0dfUEhPMmAgPSBzaWduaWYoYG5SL0dfUEhPMmAsIGRpZ2l0cyA9IDIpLAogICAgICAgICBgblIvR19waG8y4oiGYCA9IHNpZ25pZihgblIvR19waG8y4oiGYCwgZGlnaXRzID0gMikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBgblIvR19QSE8yYCwgeSA9IGBuUi9HX3BobzLiiIZgLCBsYWJlbCA9IHN5bWJvbCkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMi41KSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSkgKwogIHRoZW1lX2dyYXkoYmFzZV9zaXplID0gMTQpCmdncGxvdGx5KHAzLCB0b29sdGlwID0gYygibGFiZWwiLCAieCIsICJ5IikpCmBgYAoK