This notebook takes the output for the MAF Pipeline (mycsvfile.csv) and does:
- Calculates true pos, false pos, and false neg and makes a precision recall curve for all tools
- Finds total numbers of variants found by tools at different allele frequencies and sequencing depths
- Looks at correlation between SNPS in the golden vcf and worflow vcf For viral variant callers!
Loading Libraries
library('ggplot2')
library('tidyverse')
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✔ tibble 3.0.4 ✔ dplyr 1.0.2
✔ tidyr 1.0.0 ✔ stringr 1.4.0
✔ readr 1.3.1 ✔ forcats 0.4.0
✔ purrr 0.3.3
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library('plyr')
------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
------------------------------------------------------------------------------
Attaching package: 'plyr'
The following objects are masked from 'package:dplyr':
arrange, count, desc, failwith, id, mutate, rename, summarise,
summarize
The following object is masked from 'package:purrr':
compact
library('ggpubr')
Attaching package: 'ggpubr'
The following object is masked from 'package:plyr':
mutate
library("MLmetrics")
Attaching package: 'MLmetrics'
The following object is masked from 'package:base':
Recall
MyColors = c("#E76F51", "#E9C369", "#2A9D8F","#2B4FA2", "#119DAC", "#672D7B", "#262366", "#BCBCBC")
ggplot2::theme_set(theme_minimal())
detach(package:plyr, unload=TRUE)
library("plotrix")
Making Transition/Transversion Function
TsTv = function(dataframe) {
transitions = 0
for (row in 1:nrow(dataframe)) {
REF <- dataframe[row, "ref"] #requires dataframe to have column name "ref"
ALT <- dataframe[row, "alt"] # requires dataframe to have column name "alt"
if(REF == "A" & ALT == "G")
transitions = transitions + 1
if(REF == "G" & ALT == "A")
transitions = transitions + 1
if(REF == "C" & ALT == "T")
transitions = transitions + 1
if(REF == "T" & ALT == "C")
transitions = transitions + 1
}
transversions = 0
for (row in 1:nrow(dataframe)) {
REF <- dataframe[row, "ref"]
ALT <- dataframe[row, "alt"]
if(REF == "A" & ALT == "T")
transversions = transversions + 1
if(REF == "T" & ALT == "A")
transversions = transversions + 1
if(REF == "C" & ALT == "A")
transversions = transversions + 1
if(REF == "A" & ALT == "C")
transversions = transversions + 1
if(REF == "G" & ALT == "T")
transversions = transversions + 1
if(REF == "T" & ALT == "G")
transversions = transversions + 1
if(REF == "C" & ALT == "G")
transversions = transversions + 1
if(REF == "G" & ALT == "C")
transversions = transversions + 1
}
TsTv_df = data.frame(transitions,transversions)
print(TsTv_df)
TsTv_ratio = (transitions/transversions)
print(TsTv_ratio)
}
Reading in Variant Data and Evaluating
AV = read.csv(af_report,header = T)
AV$sample_id = as.character(AV$sample_id)
AV$dp = as.numeric(AV$dp)
AV = separate(AV, sample_id, sep = "_",
into = c(NA,NA,"allele_freq",NA,"seq_depth","tool","parameter"))%>%
filter(ref == "A" | ref == "C" | ref == "T" | ref == "G") %>%
filter(alt == "A" | alt == "C" | alt == "T" | alt == "G") %>% droplevels()
Warning: Expected 7 pieces. Additional pieces discarded in 9552 rows [5010,
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023,
5024, 5025, 5026, 5027, 5028, 5029, ...].
Warning: Expected 7 pieces. Missing pieces filled with `NA` in 44000 rows [458,
459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474,
475, 476, 477, ...].
AV$seq_depth = as.numeric(AV$seq_depth)
AV$coverage = (AV$seq_depth * 100000)
AV$parameter = NULL
head(AV)
Dp_Variation = ggplot(AV, aes(x = log10(coverage), y = log10(dp), color = tool)) +
geom_point() +
facet_wrap(~tool, scales = "free_y") +
scale_color_manual(values = MyColors)
Warning: namespace 'plyr' is not available and has been replaced
by .GlobalEnv when processing object ''
print(Dp_Variation)
Warning: Removed 7435 rows containing missing values (geom_point).

ggsave(Dp_Variation, file = "AV_Dp_Coverage.png")
Saving 7 x 5 in image
Warning: Removed 7435 rows containing missing values (geom_point).
Reading in Golden Data and Evaluating
viral_golden = read.table(golden_vcf, stringsAsFactors = F)
colnames(viral_golden) = c("chrom","pos","ID","ref","alt","qual","filter","info","codes","genotype")
viral_golden = separate(viral_golden, info, sep = "=", into = c("label","AF"))
viral_golden$label = NULL
head(viral_golden)
dim(viral_golden)
[1] 150 10
viral_golden_pos = ggplot(viral_golden, aes(x = pos, y = ref, color = alt)) +
geom_point()
print(viral_golden_pos)

TsTv(viral_golden)
transitions transversions
1 109 41
[1] 2.658537
SetAF - Separating Data into TP, FP, FN
AV_setAF = filter(AV, allele_freq != "random") %>% droplevels()
AV_setAF_falsepos = filter(AV_setAF, af_golden == 0 & af_workflow != 0) %>% droplevels()
AV_setAF_falsepos$category = c("FP")
AV_setAF_falseneg = filter(AV_setAF, af_workflow == 0 & af_golden != 0) %>% droplevels()
AV_setAF_falseneg$category = c("FN")
AV_setAF_truepos = filter(AV_setAF, af_golden != 0 & af_workflow != 0)
AV_setAF_truepos$category = c("TP")
AV_setAF = rbind(AV_setAF_truepos, AV_setAF_falseneg, AV_setAF_falsepos)
FP_All = group_by(AV_setAF_falsepos, allele_freq,coverage,tool) %>% tally()
colnames(FP_All) = c("allele_freq","coverage","tool","FP")
FN_All = group_by(AV_setAF_falseneg, allele_freq,coverage,tool) %>% tally()
colnames(FN_All) = c("allele_freq","coverage","tool","FN")
TP_All = group_by(AV_setAF_truepos, allele_freq,coverage,tool) %>% tally()
colnames(TP_All) = c("allele_freq","coverage","tool","TP")
AllVar = merge(FP_All,FN_All, by=c("allele_freq","coverage","tool"),all=T)
AllVar = merge(AllVar,TP_All, by=c("allele_freq","coverage","tool"), all=T)
head(AllVar)
AllVar[is.na(AllVar)] = 0
head(AllVar)
AllVar$prec = (AllVar$TP)/(AllVar$TP + AllVar$FP)
AllVar$recall = (AllVar$TP)/(AllVar$TP + AllVar$FN)
AllVar$area = AllVar$prec * AllVar$recall
head(AllVar)
RandomAF - Separating Data into TP, FP, FN
AV_randomAF = filter(AV, allele_freq == "random") %>% droplevels()
AV_randomAF_falsepos = filter(AV_randomAF, af_golden == 0 & af_workflow != 0) %>% droplevels()
AV_randomAF_falsepos$category = c("FP")
AV_randomAF_falseneg = filter(AV_randomAF, af_workflow == 0 & af_golden != 0) %>% droplevels()
AV_randomAF_falseneg$category = c("FN")
AV_randomAF_truepos = filter(AV_randomAF, af_golden != 0 & af_workflow != 0)
AV_randomAF_truepos$category = c("TP")
AV_randomAF = rbind(AV_randomAF_truepos, AV_randomAF_falseneg, AV_randomAF_falsepos)
rFP_All = group_by(AV_randomAF_falsepos, allele_freq,coverage,tool) %>% tally()
colnames(rFP_All) = c("allele_freq","coverage","tool","FP")
rFN_All = group_by(AV_randomAF_falseneg, allele_freq,coverage,tool) %>% tally()
colnames(rFN_All) = c("allele_freq","coverage","tool","FN")
rTP_All = group_by(AV_randomAF_truepos, allele_freq,coverage,tool) %>% tally()
colnames(rTP_All) = c("allele_freq","coverage","tool","TP")
rAllVar = merge(rFP_All,rFN_All, by=c("allele_freq","coverage","tool"),all=T)
rAllVar = merge(rAllVar, rTP_All, by=c("allele_freq","coverage","tool"), all=T)
head(rAllVar)
rAllVar[is.na(rAllVar)] = 0
rAllVar$prec = (rAllVar$TP)/(rAllVar$TP + rAllVar$FP)
rAllVar$recall = (rAllVar$TP)/(rAllVar$TP + rAllVar$FN)
rAllVar$area = rAllVar$prec * rAllVar$recall
head(rAllVar)
1. Precision_Recall Curves
PR_AllVarSet_freq = ggplot(AllVar,aes(x=recall, y=prec, group = tool, color = tool)) +
geom_point() +
geom_line() +
facet_wrap(~allele_freq) +
scale_color_manual(values = MyColors)
print(PR_AllVarSet_freq)
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 4 row(s) containing missing values (geom_path).

ggsave("PR_AllVarSet_byAF.png",PR_AllVarSet_freq)
Saving 7 x 5 in image
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 4 row(s) containing missing values (geom_path).
PR_AllVarSet_cover = ggplot(AllVar,aes(x=recall, y=prec, group = tool, color=tool)) +
geom_point() +
geom_line() +
facet_wrap(~coverage) +
scale_color_manual(values = MyColors)
print(PR_AllVarSet_cover)
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 2 row(s) containing missing values (geom_path).

ggsave("PR_AllVarSet_byCov.png",PR_AllVarSet_cover)
Saving 7 x 5 in image
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 2 row(s) containing missing values (geom_path).
PR_AllVarRandom = ggplot(rAllVar,aes(x=recall, y=prec, group = tool, color=tool)) +
geom_point() +
geom_line() +
scale_color_manual(values = MyColors)
print(PR_AllVarRandom)

ggsave("PR_AllVarRandom.png",PR_AllVarRandom)
Saving 7 x 5 in image
# Examining Data
AllVar_PR_zeros = filter(AllVar, prec == 0 & recall == 0)
AllVar_PR_high = filter(AllVar, prec > 0.9 & recall > 0.9)
AllVar_PR_highest = group_by(AllVar, tool, allele_freq, coverage) %>%
arrange(area, decreasing = TRUE)
write.csv(AllVar_PR_highest, file = "AllVar_PR_Thresholds.csv")
2.1 SetAF - Proportion of Variants Found
AV_setAF_counts = group_by(AV_setAF_truepos, tool, allele_freq, coverage) %>% tally()
AV_setAF_counts$proportion = (AV_setAF_counts$n / nrow(viral_golden))
AV_setAF_proportion = ggplot(AV_setAF_counts,aes(x = log10(coverage), y = proportion,
group = tool, color = tool)) +
geom_point() +
geom_line() +
facet_grid(~allele_freq) +
scale_color_manual(values = MyColors)
print(AV_setAF_proportion)

ggsave("AllVarSet_Proportion.png", AV_setAF_proportion)
Saving 7 x 5 in image
2.2 RandomAF - Proportion of Variants Found
AV_randomAF_counts = group_by(AV_randomAF_truepos, tool, allele_freq, coverage) %>% tally()
AV_randomAF_counts$proportion = (AV_randomAF_counts$n / nrow(viral_golden))
AV_randomAF_proportion = ggplot(AV_randomAF_counts, aes(x = log10(coverage), y = proportion,
group = tool, color = tool)) +
geom_point() +
geom_line() +
scale_color_manual(values = MyColors)
print(AV_randomAF_proportion)

ggsave("AllVarRandom_Proportion.png", AV_randomAF_proportion)
Saving 7 x 5 in image
## Only looking at coverage between 100-1000
AV_randomAF_truepos_f = filter(AV_randomAF_truepos, coverage > 99 & coverage < 1001)
AV_randomAF_counts_f = group_by(AV_randomAF_truepos_f, tool, allele_freq, coverage) %>% tally()
AV_randomAF_counts_f$proportion = (AV_randomAF_counts_f$n / nrow(viral_golden))
AV_randomAF_proportion_f = ggplot(AV_randomAF_counts_f, aes(x = log10(coverage), y = proportion,
group = tool, color = tool)) +
geom_point() +
geom_line() +
scale_color_manual(values = MyColors)
print(AV_randomAF_proportion_f)

ggsave("AllVarRandom_Proportion_Filtered.png", AV_randomAF_proportion_f)
Saving 7 x 5 in image
3.1 SetAF - Correlation Between Golden and Workflow
## Only looking at true positives
AV_Corr_setAF = ggplot(AV_setAF, aes(x = af_golden, y = af_workflow,
color = tool, shape = category)) +
geom_point() +
scale_color_manual(values = MyColors) +
geom_boxplot(aes(group = allele_freq)) +
facet_grid(tool~coverage) +
ylim(-0.001,1.0) + xlim(-0.001,1.0)
print(AV_Corr_setAF)

ggsave("AllVarSet_Correlation.png",AV_Corr_setAF)
Saving 7 x 5 in image
##Looking at all SetAF Data
AV_Corr_setAF = ggplot(AV_setAF, aes(x = af_golden, y = af_workflow,
color = tool, group = tool, shape = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(~coverage) +
geom_smooth(method='lm', size = 1.5) +
ylim(-0.001,1.0) + xlim(-0.001,1.0)
print(AV_Corr_setAF)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 6 rows containing missing values (geom_smooth).

ggsave("AllVarSet_Correlation_Filtered.png",AV_Corr_setAF)
Saving 7 x 5 in image
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 6 rows containing missing values (geom_smooth).
AV_Corr_setAF_Zoom = ggplot(AV_setAF, aes(x = af_golden, y = af_workflow,
color = tool, group = tool, shape = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(~coverage) +
ylim(-0.01,0.15) + xlim(-0.01,0.15)
print(AV_Corr_setAF_Zoom)
Warning: Removed 22195 rows containing missing values (geom_point).

ggsave("AllVarSet_CorrelationF_Filtered_Zoom.png", AV_Corr_setAF_Zoom)
Saving 7 x 5 in image
Warning: Removed 22195 rows containing missing values (geom_point).
3.2 RandomAF - Correlation Between Golden and Workflow
## Only looking at true positives
AV_Corr_randomAF = ggplot(AV_randomAF, aes(x = af_golden, y = af_workflow,
color = tool, shape = category)) +
geom_point() +
scale_color_manual(values = MyColors) +
facet_grid(tool~coverage) +
ylim(-0.001,1.0) + xlim(-0.001,1.0)
print(AV_Corr_randomAF)

ggsave("AllVarRandom_Correlation.png",AV_Corr_randomAF)
Saving 7 x 5 in image
##Looking at all RandomAF Data
AV_Corr_randomAF = ggplot(AV_randomAF, aes(x = af_golden, y = af_workflow,
color = tool, group = tool, shape = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(~coverage) +
geom_smooth(method='lm', size = 1.5) +
ylim(-0.01,1) + xlim(-0.01,1)
print(AV_Corr_randomAF)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 8 rows containing missing values (geom_smooth).

ggsave("AllVarRandom_Correlation_Filtered.png",AV_Corr_randomAF)
Saving 7 x 5 in image
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 8 rows containing missing values (geom_smooth).
AV_Corr_randomAF_Zoom = ggplot(AV_randomAF, aes(x = af_golden, y = af_workflow,
color = tool, group = tool, shape = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(~coverage) +
geom_smooth(method='lm', size = 1.5) +
ylim(-0.01,0.15) + xlim(-0.01,0.15)
print(AV_Corr_randomAF_Zoom)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 5942 rows containing non-finite values (stat_smooth).
Warning: Removed 5942 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_smooth).

ggsave("AllVarRandom_Correlation_Filtered_Zoom.png", AV_Corr_randomAF_Zoom)
Saving 7 x 5 in image
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 5942 rows containing non-finite values (stat_smooth).
Warning: Removed 5942 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_smooth).
Stats for SetAF Data
coeff_var <- function(x) {
CV <- sd(x) / mean(x) * 100
return(CV)
}
AV_setAF_split = group_by(AV_setAF_truepos, tool, allele_freq, coverage) %>%
summarize(mean(af_workflow), sd(af_workflow), coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool', 'allele_freq' (override with `.groups` argument)
colnames(AV_setAF_split) = c("tool","AF","cov","mean","sd","variance")
Mean_setAF = ggplot(AV_setAF_split, aes(x = tool, y = mean, color = cov)) +
geom_point() +
facet_grid(rows = vars(tool), cols = vars(AF)) +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(Mean_setAF)

ggsave("SetAF_Mean_AlleleFrequency.png",Mean_setAF)
Saving 7 x 5 in image
CoeffVar_setAF = ggplot(AV_setAF_split, aes(x = tool, y = variance, color = cov)) +
geom_point() +
facet_grid(rows = vars(tool), cols = vars(AF)) +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(CoeffVar_setAF)
Warning: Removed 3 rows containing missing values (geom_point).

ggsave("SetAF_CoeffVar_AlleleFrequency.png",CoeffVar_setAF)
Saving 7 x 5 in image
Warning: Removed 3 rows containing missing values (geom_point).
Set Up for Stats for RandomAF Data
AV_randomAF_split = group_by(AV_randomAF_truepos, tool, coverage) %>%
summarize(mean(af_workflow), sd(af_workflow), coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool' (override with `.groups` argument)
colnames(AV_randomAF_split) = c("tool","cov","mean","sd","variance")
Mean_randomAF = ggplot(AV_randomAF_split, aes(x = tool, y = mean, color = cov)) +
geom_point()
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
List of 2
$ text :List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : num 15
..$ hjust : NULL
..$ vjust : NULL
..$ angle : NULL
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
$ axis.text.x:List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : NULL
..$ hjust : num 1
..$ vjust : num 0.5
..$ angle : num 90
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
- attr(*, "class")= chr [1:2] "theme" "gg"
- attr(*, "complete")= logi FALSE
- attr(*, "validate")= logi TRUE
print(Mean_randomAF)

ggsave("RandomAF_Mean_AlleleFrequency.png",Mean_randomAF)
Saving 7 x 5 in image
CoeffVar_randomAF = ggplot(AV_randomAF_split, aes(x = tool, y = variance, color = cov)) +
geom_point() +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(CoeffVar_randomAF)

ggsave("RandomAF_CoeffVar_AlleleFrequency.png",CoeffVar_randomAF)
Saving 7 x 5 in image
5.1. Looks at where the SNPS are located throughout the genome
# Set AF Data
AV_Pos = ggplot(AV_setAF_truepos, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos)

AV_Pos_falsepos = ggplot(AV_setAF_falsepos, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos_falsepos)

AV_Pos_falseneg = ggplot(AV_setAF_falseneg, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos_falseneg)

# Random AF Data
AV_Pos_r = ggplot(AV_randomAF_truepos, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos_r)

AV_Pos_falsepos_r = ggplot(AV_randomAF_falsepos, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos_falsepos_r)

AV_Pos_falseneg_r = ggplot(AV_randomAF_falseneg, aes(x = pos, y = af_workflow)) +
geom_point()
print(AV_Pos_falseneg_r)

5.2.Transitions/Transversions
setAF_TP_pos = ggplot(AV_setAF_truepos, aes(x = pos, y = ref, color = tool, shape = alt)) +
geom_point()
print(setAF_TP_pos)

TsTv(AV_setAF_truepos)
transitions transversions
1 34795 13141
[1] 2.64782
#counts variants from all tools/seq_depth/AF trials
randomAF_TP_pos = ggplot(AV_randomAF_truepos, aes(x = pos, y = ref, color = tool, shape = alt)) +
geom_point()
print(randomAF_TP_pos)

TsTv(AV_randomAF_truepos)
transitions transversions
1 4961 1854
[1] 2.675836
LS0tCnRpdGxlOiAiVmFyaWFudHNfQWxsQ2FsbGVycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyNUaGlzIG5vdGVib29rIHRha2VzIHRoZSBvdXRwdXQgZm9yIHRoZSBNQUYgUGlwZWxpbmUgKG15Y3N2ZmlsZS5jc3YpIGFuZCBkb2VzOgoxLiBDYWxjdWxhdGVzIHRydWUgcG9zLCBmYWxzZSBwb3MsIGFuZCBmYWxzZSBuZWcgYW5kIG1ha2VzIGEgcHJlY2lzaW9uIHJlY2FsbCBjdXJ2ZSBmb3IgYWxsIHRvb2xzCjIuIEZpbmRzIHRvdGFsIG51bWJlcnMgb2YgdmFyaWFudHMgZm91bmQgYnkgdG9vbHMgYXQgZGlmZmVyZW50IGFsbGVsZSBmcmVxdWVuY2llcyBhbmQgc2VxdWVuY2luZyBkZXB0aHMKMy4gTG9va3MgYXQgY29ycmVsYXRpb24gYmV0d2VlbiBTTlBTIGluIHRoZSBnb2xkZW4gdmNmIGFuZCB3b3JmbG93IHZjZgpGb3IgdmlyYWwgdmFyaWFudCBjYWxsZXJzIQoKCiMjTG9hZGluZyBMaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoJ2dncGxvdDInKQpsaWJyYXJ5KCd0aWR5dmVyc2UnKQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgiTUxtZXRyaWNzIikKCk15Q29sb3JzID0gYygiI0U3NkY1MSIsICIjRTlDMzY5IiwgIiMyQTlEOEYiLCIjMkI0RkEyIiwgIiMxMTlEQUMiLCAiIzY3MkQ3QiIsICIjMjYyMzY2IiwgIiNCQ0JDQkMiKQpnZ3Bsb3QyOjp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQoKYGBgCgpgYGB7cn0KZGV0YWNoKHBhY2thZ2U6cGx5ciwgdW5sb2FkPVRSVUUpCmxpYnJhcnkoInBsb3RyaXgiKSAKYGBgCgojI01ha2luZyBUcmFuc2l0aW9uL1RyYW5zdmVyc2lvbiBGdW5jdGlvbgpgYGB7cn0KVHNUdiA9IGZ1bmN0aW9uKGRhdGFmcmFtZSkgewogIHRyYW5zaXRpb25zID0gMAogIGZvciAocm93IGluIDE6bnJvdyhkYXRhZnJhbWUpKSB7CiAgCiAgIFJFRiA8LSBkYXRhZnJhbWVbcm93LCAicmVmIl0gI3JlcXVpcmVzIGRhdGFmcmFtZSB0byBoYXZlIGNvbHVtbiBuYW1lICJyZWYiCiAgIEFMVCA8LSBkYXRhZnJhbWVbcm93LCAiYWx0Il0gIyByZXF1aXJlcyBkYXRhZnJhbWUgdG8gaGF2ZSBjb2x1bW4gbmFtZSAiYWx0IgoKICAgIGlmKFJFRiA9PSAiQSIgJiBBTFQgPT0gIkciKQogICAgICB0cmFuc2l0aW9ucyA9IHRyYW5zaXRpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zaXRpb25zID0gdHJhbnNpdGlvbnMgKyAxCiAgICBpZihSRUYgPT0gIkMiICYgQUxUID09ICJUIikKICAgICAgdHJhbnNpdGlvbnMgPSB0cmFuc2l0aW9ucyArIDEKICAgIGlmKFJFRiA9PSAiVCIgJiBBTFQgPT0gIkMiKQogICAgICB0cmFuc2l0aW9ucyA9IHRyYW5zaXRpb25zICsgMQogIH0KCiAgdHJhbnN2ZXJzaW9ucyA9IDAKICBmb3IgKHJvdyBpbiAxOm5yb3coZGF0YWZyYW1lKSkgewogIAogICAgUkVGIDwtIGRhdGFmcmFtZVtyb3csICJyZWYiXQogICAgQUxUIDwtIGRhdGFmcmFtZVtyb3csICJhbHQiXQogIAogICAgaWYoUkVGID09ICJBIiAmIEFMVCA9PSAiVCIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJUIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJDIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJBIiAmIEFMVCA9PSAiQyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiVCIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJUIiAmIEFMVCA9PSAiRyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJDIiAmIEFMVCA9PSAiRyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiQyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogIH0KCiAgVHNUdl9kZiA9IGRhdGEuZnJhbWUodHJhbnNpdGlvbnMsdHJhbnN2ZXJzaW9ucykKICBwcmludChUc1R2X2RmKQogIFRzVHZfcmF0aW8gPSAodHJhbnNpdGlvbnMvdHJhbnN2ZXJzaW9ucykKICBwcmludChUc1R2X3JhdGlvKQogIAp9CmBgYAoKIyNSZWFkaW5nIGluIFZhcmlhbnQgRGF0YSBhbmQgRXZhbHVhdGluZwpgYGB7cn0KQVYgPSByZWFkLmNzdihhZl9yZXBvcnQsaGVhZGVyID0gVCkKQVYkc2FtcGxlX2lkID0gYXMuY2hhcmFjdGVyKEFWJHNhbXBsZV9pZCkKQVYkZHAgPSBhcy5udW1lcmljKEFWJGRwKQpBViA9IHNlcGFyYXRlKEFWLCBzYW1wbGVfaWQsIHNlcCA9ICJfIiwgCiAgICAgICAgICAgICAgIGludG8gPSBjKE5BLE5BLCJhbGxlbGVfZnJlcSIsTkEsInNlcV9kZXB0aCIsInRvb2wiLCJwYXJhbWV0ZXIiKSklPiUgCiAgZmlsdGVyKHJlZiA9PSAiQSIgfCByZWYgPT0gIkMiIHwgcmVmID09ICJUIiB8IHJlZiA9PSAiRyIpICU+JSAKICBmaWx0ZXIoYWx0ID09ICJBIiB8IGFsdCA9PSAiQyIgfCBhbHQgPT0gIlQiIHwgYWx0ID09ICJHIikgJT4lIGRyb3BsZXZlbHMoKQpBViRzZXFfZGVwdGggPSBhcy5udW1lcmljKEFWJHNlcV9kZXB0aCkKQVYkY292ZXJhZ2UgPSAoQVYkc2VxX2RlcHRoICogMTAwMDAwKQoKQVYkcGFyYW1ldGVyID0gTlVMTApoZWFkKEFWKQoKRHBfVmFyaWF0aW9uID0gZ2dwbG90KEFWLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IGxvZzEwKGRwKSwgY29sb3IgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X3dyYXAofnRvb2wsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChEcF9WYXJpYXRpb24pCmdnc2F2ZShEcF9WYXJpYXRpb24sIGZpbGUgPSAiQVZfRHBfQ292ZXJhZ2UucG5nIikKYGBgCgojI1JlYWRpbmcgaW4gR29sZGVuIERhdGEgYW5kIEV2YWx1YXRpbmcKYGBge3J9CnZpcmFsX2dvbGRlbiA9IHJlYWQudGFibGUoZ29sZGVuX3ZjZiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHZpcmFsX2dvbGRlbikgPSBjKCJjaHJvbSIsInBvcyIsIklEIiwicmVmIiwiYWx0IiwicXVhbCIsImZpbHRlciIsImluZm8iLCJjb2RlcyIsImdlbm90eXBlIikKdmlyYWxfZ29sZGVuID0gc2VwYXJhdGUodmlyYWxfZ29sZGVuLCBpbmZvLCBzZXAgPSAiPSIsIGludG8gPSBjKCJsYWJlbCIsIkFGIikpCnZpcmFsX2dvbGRlbiRsYWJlbCA9IE5VTEwKaGVhZCh2aXJhbF9nb2xkZW4pCmRpbSh2aXJhbF9nb2xkZW4pCgp2aXJhbF9nb2xkZW5fcG9zID0gZ2dwbG90KHZpcmFsX2dvbGRlbiwgYWVzKHggPSBwb3MsIHkgPSByZWYsIGNvbG9yID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludCh2aXJhbF9nb2xkZW5fcG9zKQoKVHNUdih2aXJhbF9nb2xkZW4pCmBgYAoKIyNTZXRBRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3NldEFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSAhPSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfc2V0QUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3NldEFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9zZXRBRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9zZXRBRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfc2V0QUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3NldEFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9zZXRBRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9zZXRBRiA9IHJiaW5kKEFWX3NldEFGX3RydWVwb3MsIEFWX3NldEFGX2ZhbHNlbmVnLCBBVl9zZXRBRl9mYWxzZXBvcykKCkZQX0FsbCA9IGdyb3VwX2J5KEFWX3NldEFGX2ZhbHNlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKEZQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZQIikKRk5fQWxsID0gZ3JvdXBfYnkoQVZfc2V0QUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoRk5fQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRk4iKQpUUF9BbGwgPSBncm91cF9ieShBVl9zZXRBRl90cnVlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKFRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKICAgIApBbGxWYXIgPSBtZXJnZShGUF9BbGwsRk5fQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLGFsbD1UKQpBbGxWYXIgPSBtZXJnZShBbGxWYXIsVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChBbGxWYXIpCgpBbGxWYXJbaXMubmEoQWxsVmFyKV0gPSAwCmhlYWQoQWxsVmFyKQoKQWxsVmFyJHByZWMgPSAoQWxsVmFyJFRQKS8oQWxsVmFyJFRQICsgQWxsVmFyJEZQKQpBbGxWYXIkcmVjYWxsID0gKEFsbFZhciRUUCkvKEFsbFZhciRUUCArIEFsbFZhciRGTikKQWxsVmFyJGFyZWEgPSBBbGxWYXIkcHJlYyAqIEFsbFZhciRyZWNhbGwKaGVhZChBbGxWYXIpCmBgYAoKIyNSYW5kb21BRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3JhbmRvbUFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSA9PSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfcmFuZG9tQUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3JhbmRvbUFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9yYW5kb21BRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9yYW5kb21BRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfcmFuZG9tQUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3JhbmRvbUFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9yYW5kb21BRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9yYW5kb21BRiA9IHJiaW5kKEFWX3JhbmRvbUFGX3RydWVwb3MsIEFWX3JhbmRvbUFGX2ZhbHNlbmVnLCBBVl9yYW5kb21BRl9mYWxzZXBvcykKCnJGUF9BbGwgPSBncm91cF9ieShBVl9yYW5kb21BRl9mYWxzZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhyRlBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRlAiKQpyRk5fQWxsID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMockZOX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZOIikKclRQX0FsbCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoclRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKCnJBbGxWYXIgPSBtZXJnZShyRlBfQWxsLHJGTl9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksYWxsPVQpCnJBbGxWYXIgPSBtZXJnZShyQWxsVmFyLCByVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChyQWxsVmFyKQoKckFsbFZhcltpcy5uYShyQWxsVmFyKV0gPSAwCgpyQWxsVmFyJHByZWMgPSAockFsbFZhciRUUCkvKHJBbGxWYXIkVFAgKyByQWxsVmFyJEZQKQpyQWxsVmFyJHJlY2FsbCA9IChyQWxsVmFyJFRQKS8ockFsbFZhciRUUCArIHJBbGxWYXIkRk4pCnJBbGxWYXIkYXJlYSA9IHJBbGxWYXIkcHJlYyAqIHJBbGxWYXIkcmVjYWxsCmhlYWQockFsbFZhcikKYGBgCgojMS4gUHJlY2lzaW9uX1JlY2FsbCBDdXJ2ZXMKYGBge3J9ClBSX0FsbFZhclNldF9mcmVxID0gZ2dwbG90KEFsbFZhcixhZXMoeD1yZWNhbGwsIHk9cHJlYywgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmFsbGVsZV9mcmVxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChQUl9BbGxWYXJTZXRfZnJlcSkKZ2dzYXZlKCJQUl9BbGxWYXJTZXRfYnlBRi5wbmciLFBSX0FsbFZhclNldF9mcmVxKQoKUFJfQWxsVmFyU2V0X2NvdmVyID0gZ2dwbG90KEFsbFZhcixhZXMoeD1yZWNhbGwsIHk9cHJlYywgZ3JvdXAgPSB0b29sLCBjb2xvcj10b29sKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5jb3ZlcmFnZSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoUFJfQWxsVmFyU2V0X2NvdmVyKQpnZ3NhdmUoIlBSX0FsbFZhclNldF9ieUNvdi5wbmciLFBSX0FsbFZhclNldF9jb3ZlcikKClBSX0FsbFZhclJhbmRvbSA9IGdncGxvdChyQWxsVmFyLGFlcyh4PXJlY2FsbCwgeT1wcmVjLCBncm91cCA9IHRvb2wsIGNvbG9yPXRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoUFJfQWxsVmFyUmFuZG9tKQpnZ3NhdmUoIlBSX0FsbFZhclJhbmRvbS5wbmciLFBSX0FsbFZhclJhbmRvbSkKCiMgRXhhbWluaW5nIERhdGEKCkFsbFZhcl9QUl96ZXJvcyA9IGZpbHRlcihBbGxWYXIsIHByZWMgPT0gMCAmIHJlY2FsbCA9PSAwKQpBbGxWYXJfUFJfaGlnaCA9IGZpbHRlcihBbGxWYXIsIHByZWMgPiAwLjkgJiByZWNhbGwgPiAwLjkpCgpBbGxWYXJfUFJfaGlnaGVzdCA9IGdyb3VwX2J5KEFsbFZhciwgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUKICBhcnJhbmdlKGFyZWEsIGRlY3JlYXNpbmcgPSBUUlVFKQp3cml0ZS5jc3YoQWxsVmFyX1BSX2hpZ2hlc3QsIGZpbGUgPSAiQWxsVmFyX1BSX1RocmVzaG9sZHMuY3N2IikKYGBgCgojMi4xIFNldEFGIC0gUHJvcG9ydGlvbiBvZiBWYXJpYW50cyBGb3VuZApgYGB7cn0KQVZfc2V0QUZfY291bnRzID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9zZXRBRl9jb3VudHMkcHJvcG9ydGlvbiA9IChBVl9zZXRBRl9jb3VudHMkbiAvIG5yb3codmlyYWxfZ29sZGVuKSkKCkFWX3NldEFGX3Byb3BvcnRpb24gPSBnZ3Bsb3QoQVZfc2V0QUZfY291bnRzLGFlcyh4ID0gbG9nMTAoY292ZXJhZ2UpLCB5ID0gcHJvcG9ydGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfZ3JpZCh+YWxsZWxlX2ZyZXEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpCnByaW50KEFWX3NldEFGX3Byb3BvcnRpb24pCmdnc2F2ZSgiQWxsVmFyU2V0X1Byb3BvcnRpb24ucG5nIiwgQVZfc2V0QUZfcHJvcG9ydGlvbikKYGBgCgojMi4yIFJhbmRvbUFGIC0gUHJvcG9ydGlvbiBvZiBWYXJpYW50cyBGb3VuZApgYGB7cn0KQVZfcmFuZG9tQUZfY291bnRzID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9yYW5kb21BRl9jb3VudHMkcHJvcG9ydGlvbiA9IChBVl9yYW5kb21BRl9jb3VudHMkbiAvIG5yb3codmlyYWxfZ29sZGVuKSkKCkFWX3JhbmRvbUFGX3Byb3BvcnRpb24gPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfY291bnRzLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IHByb3BvcnRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gdG9vbCwgY29sb3IgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoQVZfcmFuZG9tQUZfcHJvcG9ydGlvbikKZ2dzYXZlKCJBbGxWYXJSYW5kb21fUHJvcG9ydGlvbi5wbmciLCBBVl9yYW5kb21BRl9wcm9wb3J0aW9uKQogCiMjIE9ubHkgbG9va2luZyBhdCBjb3ZlcmFnZSBiZXR3ZWVuIDEwMC0xMDAwCkFWX3JhbmRvbUFGX3RydWVwb3NfZiA9IGZpbHRlcihBVl9yYW5kb21BRl90cnVlcG9zLCBjb3ZlcmFnZSA+IDk5ICYgY292ZXJhZ2UgPCAxMDAxKQpBVl9yYW5kb21BRl9jb3VudHNfZiA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3NfZiwgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9yYW5kb21BRl9jb3VudHNfZiRwcm9wb3J0aW9uID0gKEFWX3JhbmRvbUFGX2NvdW50c19mJG4gLyBucm93KHZpcmFsX2dvbGRlbikpCiAKQVZfcmFuZG9tQUZfcHJvcG9ydGlvbl9mID0gZ2dwbG90KEFWX3JhbmRvbUFGX2NvdW50c19mLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IHByb3BvcnRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChBVl9yYW5kb21BRl9wcm9wb3J0aW9uX2YpCmdnc2F2ZSgiQWxsVmFyUmFuZG9tX1Byb3BvcnRpb25fRmlsdGVyZWQucG5nIiwgQVZfcmFuZG9tQUZfcHJvcG9ydGlvbl9mKQpgYGAKCiMzLjEgU2V0QUYgLSBDb3JyZWxhdGlvbiBCZXR3ZWVuIEdvbGRlbiBhbmQgV29ya2Zsb3cKYGBge3J9CiMjIE9ubHkgbG9va2luZyBhdCB0cnVlIHBvc2l0aXZlcwpBVl9Db3JyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBnZW9tX2JveHBsb3QoYWVzKGdyb3VwID0gYWxsZWxlX2ZyZXEpKSArIAogIGZhY2V0X2dyaWQodG9vbH5jb3ZlcmFnZSkgKwogIHlsaW0oLTAuMDAxLDEuMCkgKyB4bGltKC0wLjAwMSwxLjApCnByaW50KEFWX0NvcnJfc2V0QUYpCmdnc2F2ZSgiQWxsVmFyU2V0X0NvcnJlbGF0aW9uLnBuZyIsQVZfQ29ycl9zZXRBRikKCiMjTG9va2luZyBhdCBhbGwgU2V0QUYgRGF0YQpBVl9Db3JyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBncm91cCA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKH5jb3ZlcmFnZSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgeWxpbSgtMC4wMDEsMS4wKSArIHhsaW0oLTAuMDAxLDEuMCkKcHJpbnQoQVZfQ29ycl9zZXRBRikKZ2dzYXZlKCJBbGxWYXJTZXRfQ29ycmVsYXRpb25fRmlsdGVyZWQucG5nIixBVl9Db3JyX3NldEFGKQoKQVZfQ29ycl9zZXRBRl9ab29tID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gdG9vbCwgZ3JvdXAgPSB0b29sLCBzaGFwZSA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC40KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZCh+Y292ZXJhZ2UpICsKICB5bGltKC0wLjAxLDAuMTUpICsgeGxpbSgtMC4wMSwwLjE1KQpwcmludChBVl9Db3JyX3NldEFGX1pvb20pCmdnc2F2ZSgiQWxsVmFyU2V0X0NvcnJlbGF0aW9uRl9GaWx0ZXJlZF9ab29tLnBuZyIsIEFWX0NvcnJfc2V0QUZfWm9vbSkKYGBgCgojMy4yIFJhbmRvbUFGIC0gQ29ycmVsYXRpb24gQmV0d2VlbiBHb2xkZW4gYW5kIFdvcmtmbG93CmBgYHtyfQojIyBPbmx5IGxvb2tpbmcgYXQgdHJ1ZSBwb3NpdGl2ZXMKQVZfQ29ycl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRiwgYWVzKHggPSBhZl9nb2xkZW4sIHkgPSBhZl93b3JrZmxvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBzaGFwZSA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZCh0b29sfmNvdmVyYWdlKSArCiAgeWxpbSgtMC4wMDEsMS4wKSArIHhsaW0oLTAuMDAxLDEuMCkKcHJpbnQoQVZfQ29ycl9yYW5kb21BRikKZ2dzYXZlKCJBbGxWYXJSYW5kb21fQ29ycmVsYXRpb24ucG5nIixBVl9Db3JyX3JhbmRvbUFGKQoKIyNMb29raW5nIGF0IGFsbCBSYW5kb21BRiBEYXRhCkFWX0NvcnJfcmFuZG9tQUYgPSBnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gYWZfZ29sZGVuLCB5ID0gYWZfd29ya2Zsb3csIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHRvb2wsIGdyb3VwID0gdG9vbCwgc2hhcGUgPSBjYXRlZ29yeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IDAuNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykgKwogIGZhY2V0X2dyaWQofmNvdmVyYWdlKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIHNpemUgPSAxLjUpICsKICB5bGltKC0wLjAxLDEpICsgeGxpbSgtMC4wMSwxKQpwcmludChBVl9Db3JyX3JhbmRvbUFGKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Db3JyZWxhdGlvbl9GaWx0ZXJlZC5wbmciLEFWX0NvcnJfcmFuZG9tQUYpCgpBVl9Db3JyX3JhbmRvbUFGX1pvb20gPSBnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gYWZfZ29sZGVuLCB5ID0gYWZfd29ya2Zsb3csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBncm91cCA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKH5jb3ZlcmFnZSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgeWxpbSgtMC4wMSwwLjE1KSArIHhsaW0oLTAuMDEsMC4xNSkKcHJpbnQoQVZfQ29ycl9yYW5kb21BRl9ab29tKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Db3JyZWxhdGlvbl9GaWx0ZXJlZF9ab29tLnBuZyIsIEFWX0NvcnJfcmFuZG9tQUZfWm9vbSkKYGBgCgojIyBTdGF0cyBmb3IgU2V0QUYgRGF0YQpgYGB7cn0KY29lZmZfdmFyIDwtIGZ1bmN0aW9uKHgpIHsKICBDViA8LSBzZCh4KSAvIG1lYW4oeCkgKiAxMDAKICByZXR1cm4oQ1YpCn0KCkFWX3NldEFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUKICBzdW1tYXJpemUobWVhbihhZl93b3JrZmxvdyksIHNkKGFmX3dvcmtmbG93KSwgY29lZmZfdmFyKGFmX3dvcmtmbG93KSkgJT4lIGRyb3BsZXZlbHMoKQpjb2xuYW1lcyhBVl9zZXRBRl9zcGxpdCkgPSBjKCJ0b29sIiwiQUYiLCJjb3YiLCJtZWFuIiwic2QiLCJ2YXJpYW5jZSIpCgpNZWFuX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSBtZWFuLCBjb2xvciA9IGNvdikpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHRvb2wpLCBjb2xzID0gdmFycyhBRikpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChNZWFuX3NldEFGKQpnZ3NhdmUoIlNldEFGX01lYW5fQWxsZWxlRnJlcXVlbmN5LnBuZyIsTWVhbl9zZXRBRikKCkNvZWZmVmFyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSB2YXJpYW5jZSwgY29sb3IgPSBjb3YpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh0b29sKSwgY29scyA9IHZhcnMoQUYpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoQ29lZmZWYXJfc2V0QUYpCmdnc2F2ZSgiU2V0QUZfQ29lZmZWYXJfQWxsZWxlRnJlcXVlbmN5LnBuZyIsQ29lZmZWYXJfc2V0QUYpCmBgYAoKCiMjIFNldCBVcCBmb3IgU3RhdHMgZm9yIFJhbmRvbUFGIERhdGEKYGBge3J9CkFWX3JhbmRvbUFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgdG9vbCwgY292ZXJhZ2UpICU+JQogIHN1bW1hcml6ZShtZWFuKGFmX3dvcmtmbG93KSwgc2QoYWZfd29ya2Zsb3cpLCBjb2VmZl92YXIoYWZfd29ya2Zsb3cpKSAlPiUgZHJvcGxldmVscygpCmNvbG5hbWVzKEFWX3JhbmRvbUFGX3NwbGl0KSA9IGMoInRvb2wiLCJjb3YiLCJtZWFuIiwic2QiLCJ2YXJpYW5jZSIpCgpNZWFuX3JhbmRvbUFGID0gZ2dwbG90KEFWX3JhbmRvbUFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSBtZWFuLCBjb2xvciA9IGNvdikpICsgCiAgZ2VvbV9wb2ludCgpCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoTWVhbl9yYW5kb21BRikKZ2dzYXZlKCJSYW5kb21BRl9NZWFuX0FsbGVsZUZyZXF1ZW5jeS5wbmciLE1lYW5fcmFuZG9tQUYpCgpDb2VmZlZhcl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRl9zcGxpdCwgYWVzKHggPSB0b29sLCB5ID0gdmFyaWFuY2UsIGNvbG9yID0gY292KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KENvZWZmVmFyX3JhbmRvbUFGKQpnZ3NhdmUoIlJhbmRvbUFGX0NvZWZmVmFyX0FsbGVsZUZyZXF1ZW5jeS5wbmciLENvZWZmVmFyX3JhbmRvbUFGKQpgYGAKCiM0LiBMb29rIGF0IGhvdyBlYWNoIHRvb2wgY29tcGFyZXMgYXQgZWFjaCBBRiBhbmQgc2VxLWRlcHRoCmBgYHtyfQpBVlNldF9Db3JyID0gZ2dwbG90KEFWX3NldEFGX3RydWVwb3MsIGFlcyh4ID0gdG9vbCwgeSA9IGFmX3dvcmtmbG93KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fYm94cGxvdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIGZhY2V0X2dyaWQoYWxsZWxlX2ZyZXF+Y292ZXJhZ2UsIHNjYWxlcyA9ICJmcmVlX3kiKQpwcmludChBVlNldF9Db3JyKQpnZ3NhdmUoIkFsbFZhclNldF9Ub29sX0NvbXBhcmlzb24ucGRmIiwgQVZTZXRfQ29yciwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMjApCiMgeSBheGVzIGFyZSBzZXQgcGVyIHJvdyBhdCB0aGUgbW9tZW50IChzY2FsZXMgPSAiZnJlZV95IikKCkFWUmFuZG9tX0NvcnIgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgYWVzKHggPSB0b29sLCB5ID0gYWZfd29ya2Zsb3cpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV92aW9saW4oKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsKICBmYWNldF9ncmlkKGFsbGVsZV9mcmVxfmNvdmVyYWdlKQpwcmludChBVlJhbmRvbV9Db3JyKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Ub29sX0NvbXBhcmlzb24ucGRmIiwgQVZSYW5kb21fQ29yciwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMjApCmBgYAoKIzUuMS4gTG9va3MgYXQgd2hlcmUgdGhlIFNOUFMgYXJlIGxvY2F0ZWQgdGhyb3VnaG91dCB0aGUgZ2Vub21lCmBgYHtyfQojIFNldCBBRiBEYXRhCkFWX1BvcyA9IGdncGxvdChBVl9zZXRBRl90cnVlcG9zLCBhZXMoeCA9IHBvcywgeSA9IGFmX3dvcmtmbG93KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChBVl9Qb3MpCkFWX1Bvc19mYWxzZXBvcyA9IGdncGxvdChBVl9zZXRBRl9mYWxzZXBvcywgYWVzKHggPSBwb3MsIHkgPSBhZl93b3JrZmxvdykpICsKICBnZW9tX3BvaW50KCkKcHJpbnQoQVZfUG9zX2ZhbHNlcG9zKQpBVl9Qb3NfZmFsc2VuZWcgPSBnZ3Bsb3QoQVZfc2V0QUZfZmFsc2VuZWcsIGFlcyh4ID0gcG9zLCB5ID0gYWZfd29ya2Zsb3cpKSArCiAgZ2VvbV9wb2ludCgpCnByaW50KEFWX1Bvc19mYWxzZW5lZykKCiMgUmFuZG9tIEFGIERhdGEKQVZfUG9zX3IgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgYWVzKHggPSBwb3MsIHkgPSBhZl93b3JrZmxvdykpICsKICBnZW9tX3BvaW50KCkKcHJpbnQoQVZfUG9zX3IpCkFWX1Bvc19mYWxzZXBvc19yID0gZ2dwbG90KEFWX3JhbmRvbUFGX2ZhbHNlcG9zLCBhZXMoeCA9IHBvcywgeSA9IGFmX3dvcmtmbG93KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChBVl9Qb3NfZmFsc2Vwb3NfcikKQVZfUG9zX2ZhbHNlbmVnX3IgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfZmFsc2VuZWcsIGFlcyh4ID0gcG9zLCB5ID0gYWZfd29ya2Zsb3cpKSArCiAgZ2VvbV9wb2ludCgpCnByaW50KEFWX1Bvc19mYWxzZW5lZ19yKQpgYGAKCiM1LjIuVHJhbnNpdGlvbnMvVHJhbnN2ZXJzaW9ucwpgYGB7cn0Kc2V0QUZfVFBfcG9zID0gZ2dwbG90KEFWX3NldEFGX3RydWVwb3MsIGFlcyh4ID0gcG9zLCB5ID0gcmVmLCBjb2xvciA9IHRvb2wsIHNoYXBlID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChzZXRBRl9UUF9wb3MpCgpUc1R2KEFWX3NldEFGX3RydWVwb3MpCiNjb3VudHMgdmFyaWFudHMgZnJvbSBhbGwgdG9vbHMvc2VxX2RlcHRoL0FGIHRyaWFscwoKcmFuZG9tQUZfVFBfcG9zID0gZ2dwbG90KEFWX3JhbmRvbUFGX3RydWVwb3MsIGFlcyh4ID0gcG9zLCB5ID0gcmVmLCBjb2xvciA9IHRvb2wsIHNoYXBlID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChyYW5kb21BRl9UUF9wb3MpCgpUc1R2KEFWX3JhbmRvbUFGX3RydWVwb3MpCmBgYAo=