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
#knitr::opts_knit$set(root.dir = "/Users/marissaknoll/Desktop/MAF/")
#run in working directory
#setwd("/Users/marissaknoll/Desktop/MAF/")
#library(available)
#available("Vivaldi", browse = FALSE)
Loading Libraries
library('plyr')
library('tidyverse')
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.2 v purrr 0.3.3
v tibble 3.0.4 v dplyr 1.0.2
v tidyr 1.0.0 v stringr 1.4.0
v readr 1.3.1 v forcats 0.4.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::arrange() masks plyr::arrange()
x purrr::compact() masks plyr::compact()
x dplyr::count() masks plyr::count()
x dplyr::failwith() masks plyr::failwith()
x dplyr::filter() masks stats::filter()
x dplyr::id() masks plyr::id()
x dplyr::lag() masks stats::lag()
x dplyr::mutate() masks plyr::mutate()
x dplyr::rename() masks plyr::rename()
x dplyr::summarise() masks plyr::summarise()
x dplyr::summarize() masks plyr::summarize()
library("plotrix")
library('ggplot2')
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
library("RColorBrewer")
MyColors = c("#e41a1c", "#377eb8", "#4daf4a","#984ea3", "#ff6600", "#ffcc33", "#f781bf", "#a65628", "#999999", "#006600", "#993333", "#cc99ff", "#663300", '#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#000000')
# This is basically RColorBrewer Set1 but I darkened yellow to make it easier to see then changed orange a bit to differ more from yellow
#
SEGMENTLIST = c("H1N1_PB2","H1N1_PB1","H1N1_PA","H1N1_HA","H1N1_NP","H1N1_NA","H1N1_MP","H1N1_NS")
ggplot2::theme_set(theme_minimal())
#totalbases = 29903 # at some point should change this from being hardcoded to make this more flexible
totalbases = 13588 # hard coding for flu A, is this correct?
readsim_cov = 100000 #hardocding this for now so my code runs
Reading in Variant Data and Evaluating
AV = read.csv(af_report,header = T)
#make the segments in a specific order
AV$chrom = factor(AV$chrom, levels = SEGMENTLIST)
AV$sample_id = as.character(AV$sample_id)
AV$dp = as.numeric(AV$dp)
AV = separate(AV, sample_id, sep = "_",
into = c("strain","AF","allele_freq","frac","seq_depth","tool","parameter","parameter2")) %>%
select(allele_freq,seq_depth,tool, parameter, chrom,pos,af_golden,af_workflow,ref,alt,dp) %>%
filter(ref == "A" | ref == "C" | ref == "T" | ref == "G") %>%
filter(alt == "A" | alt == "C" | alt == "T" | alt == "G") %>% droplevels()
Warning: Expected 8 pieces. Additional pieces discarded in 2215 rows [1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
AV$seq_depth = as.numeric(AV$seq_depth)
AV$coverage = (AV$seq_depth * readsim_cov) #variable called in pipeline, corresponds to highest coverage
AV$coverage = as.character(AV$coverage)
head(AV)
variant_pos = ggplot(AV, aes(x = pos, y = tool)) +
geom_point() +
facet_grid(~chrom, scales = "free_x") + theme_minimal(base_size = 6)
print(variant_pos)

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(NA,"AF"))
viral_golden$chrom = factor(viral_golden$chrom, levels = SEGMENTLIST)
head(viral_golden)
dim(viral_golden)
[1] 122 10
viral_golden_pos = ggplot(viral_golden, aes(x = pos, y = ref, color = alt)) +
geom_point() +
facet_grid(~chrom, scales = "free_x")+ theme_minimal(base_size = 6)
print(viral_golden_pos)

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)
# SetAF Data
ggplot(AV_setAF, aes(x = tool, fill = category)) +
geom_bar() +
facet_grid(allele_freq~coverage) +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
scale_fill_brewer(palette = "Dark2")

# plot as percentage of FN as well
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)
# RandomAF Data
ggplot(AV_randomAF, aes(x = tool, fill = category)) +
geom_bar() +
facet_grid(allele_freq~coverage) +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
scale_fill_brewer(palette = "Dark2")

# plot as percentage of FN as well
SetAF - Correlation Between Golden and Workflow
#Looking at all SetAF Data
AV_Corr_setAF <-
ggplot(AV_setAF, aes(x = af_golden,y = af_workflow, color = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(coverage~tool) +
geom_smooth(method='lm', size = 1.5) +
theme(plot.title = element_text(hjust = 0.5))+ theme_minimal(base_size = 6)
print(AV_Corr_setAF)
`geom_smooth()` using formula 'y ~ x'

#ggsave(AV_Corr_setAF, file = "AllVarSet_Correlation_Filtered.png",
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
RandomAF - Correlation Between Golden and Workflow
##Looking at all RandomAF Data
AV_Corr_randomAF <-
ggplot(AV_randomAF, aes(x = af_golden,y = af_workflow, color = category)) +
geom_point(size = 3, alpha = 0.4) +
scale_color_manual(values = MyColors) +
facet_grid(coverage~tool) +
geom_smooth(method='lm', size = 1.5) +
theme(plot.title = element_text(hjust = 0.5))+ theme_minimal(base_size = 6)
print(AV_Corr_randomAF)
`geom_smooth()` using formula 'y ~ x'

#ggsave("AllVarRandom_Correlation_Filtered.png",AV_Corr_randomAF,
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
Stats for SetAF Data
detach(package:plyr, unload=TRUE)
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 = mean(af_workflow), sd = sd(af_workflow), variance = coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool', 'allele_freq' (override with `.groups` argument)
Mean_setAF = ggplot(AV_setAF_split, aes(x = coverage, y = mean, color = allele_freq)) +
geom_point() +
#facet_grid(cols = vars(allele_freq)) +
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,
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
#visulize the effect of downsampling.
CoeffVar_setAF = ggplot(AV_setAF_split, aes(x = coverage, y = variance, color = allele_freq)) +
geom_point() +
#facet_grid(cols = vars(allele_freq)) +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(CoeffVar_setAF)
Warning: Removed 1 rows containing missing values (geom_point).

#ggsave("SetAF_CoeffVar_AlleleFrequency.png",CoeffVar_setAF,
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
#variances above 10000 are simliar
Stats for RandomAF Data
AV_randomAF_split = group_by(AV_randomAF_truepos, tool, coverage) %>%
summarize(mean = mean(af_workflow), sd = sd(af_workflow), variance = coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool' (override with `.groups` argument)
Mean_randomAF = ggplot(AV_randomAF_split, aes(x = coverage, y = mean, color = tool)) +
geom_point() +
theme(text = element_text(size = 15),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(Mean_randomAF)

#ggsave("RandomAF_Mean_AlleleFrequency.png",Mean_randomAF,
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
CoeffVar_randomAF = ggplot(AV_randomAF_split, aes(x = coverage, y = variance, color = tool)) +
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,
# path = "/Users/marissaknoll/Desktop/MAF/H1N1_Images")
ggplot(AV_setAF, aes(x = log10(dp), y = af_workflow, color = tool)) +
geom_point() +
facet_grid(rows = vars(coverage), cols = vars(allele_freq)) +
xlim(0,6)

# do this with all bamfiles, not just variants
ggplot(AV_setAF, aes(x = log10(dp), fill = tool)) +
geom_histogram()+
facet_grid(rows = vars(coverage), cols = vars(allele_freq))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyNUaGlzIG5vdGVib29rIHRha2VzIHRoZSBvdXRwdXQgZm9yIHRoZSBNQUYgUGlwZWxpbmUgKG15Y3N2ZmlsZS5jc3YpIGFuZCBkb2VzOgoxLiBDYWxjdWxhdGVzIHRydWUgcG9zLCBmYWxzZSBwb3MsIGFuZCBmYWxzZSBuZWcgYW5kIG1ha2VzIGEgcHJlY2lzaW9uIHJlY2FsbCBjdXJ2ZSBmb3IgYWxsIHRvb2xzCjIuIEZpbmRzIHRvdGFsIG51bWJlcnMgb2YgdmFyaWFudHMgZm91bmQgYnkgdG9vbHMgYXQgZGlmZmVyZW50IGFsbGVsZSBmcmVxdWVuY2llcyBhbmQgc2VxdWVuY2luZyBkZXB0aHMKMy4gTG9va3MgYXQgY29ycmVsYXRpb24gYmV0d2VlbiBTTlBTIGluIHRoZSBnb2xkZW4gdmNmIGFuZCB3b3JmbG93IHZjZgoKYGBge3J9CiNrbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpCiNydW4gaW4gd29ya2luZyBkaXJlY3RvcnkKI3NldHdkKCIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpIApgYGAKCmBgYHtyfQojbGlicmFyeShhdmFpbGFibGUpCiNhdmFpbGFibGUoIlZpdmFsZGkiLCBicm93c2UgPSBGQUxTRSkKYGBgCgojI0xvYWRpbmcgTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgndGlkeXZlcnNlJykKbGlicmFyeSgicGxvdHJpeCIpIApsaWJyYXJ5KCdnZ3Bsb3QyJykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgiTUxtZXRyaWNzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKICAgICAgICAKTXlDb2xvcnMgPSBjKCIjZTQxYTFjIiwgIiMzNzdlYjgiLCAiIzRkYWY0YSIsIiM5ODRlYTMiLCAiI2ZmNjYwMCIsICIjZmZjYzMzIiwgIiNmNzgxYmYiLCAiI2E2NTYyOCIsICIjOTk5OTk5IiwgIiMwMDY2MDAiLCAiIzk5MzMzMyIsICIjY2M5OWZmIiwgIiM2NjMzMDAiLCAnI2U2MTk0YicsICcjM2NiNDRiJywgJyNmZmUxMTknLCAnIzQzNjNkOCcsICcjZjU4MjMxJywgJyM5MTFlYjQnLCAnIzQ2ZjBmMCcsICcjZjAzMmU2JywgJyNiY2Y2MGMnLCAnI2ZhYmViZScsICcjMDA4MDgwJywgJyNlNmJlZmYnLCAnIzlhNjMyNCcsICcjZmZmYWM4JywgJyM4MDAwMDAnLCAnI2FhZmZjMycsICcjODA4MDAwJywgJyNmZmQ4YjEnLCAnIzAwMDA3NScsICcjODA4MDgwJywgJyMwMDAwMDAnKQojIFRoaXMgaXMgYmFzaWNhbGx5IFJDb2xvckJyZXdlciBTZXQxIGJ1dCBJIGRhcmtlbmVkIHllbGxvdyB0byBtYWtlIGl0IGVhc2llciB0byBzZWUgdGhlbiBjaGFuZ2VkIG9yYW5nZSBhIGJpdCB0byBkaWZmZXIgbW9yZSBmcm9tIHllbGxvdwojClNFR01FTlRMSVNUID0gYygiSDFOMV9QQjIiLCJIMU4xX1BCMSIsIkgxTjFfUEEiLCJIMU4xX0hBIiwiSDFOMV9OUCIsIkgxTjFfTkEiLCJIMU4xX01QIiwiSDFOMV9OUyIpCmdncGxvdDI6OnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCgojdG90YWxiYXNlcyA9IDI5OTAzICMgYXQgc29tZSBwb2ludCBzaG91bGQgY2hhbmdlIHRoaXMgZnJvbSBiZWluZyBoYXJkY29kZWQgdG8gbWFrZSB0aGlzIG1vcmUgZmxleGlibGUKdG90YWxiYXNlcyA9IDEzNTg4ICMgaGFyZCBjb2RpbmcgZm9yIGZsdSBBLCBpcyB0aGlzIGNvcnJlY3Q/CnJlYWRzaW1fY292ID0gMTAwMDAwICNoYXJkb2NkaW5nIHRoaXMgZm9yIG5vdyBzbyBteSBjb2RlIHJ1bnMKYGBgCgojI1JlYWRpbmcgaW4gVmFyaWFudCBEYXRhIGFuZCBFdmFsdWF0aW5nCmBgYHtyfQpBViA9IHJlYWQuY3N2KGFmX3JlcG9ydCxoZWFkZXIgPSBUKQojbWFrZSB0aGUgc2VnbWVudHMgaW4gYSBzcGVjaWZpYyBvcmRlcgpBViRjaHJvbSA9IGZhY3RvcihBViRjaHJvbSwgbGV2ZWxzID0gU0VHTUVOVExJU1QpCgpBViRzYW1wbGVfaWQgPSBhcy5jaGFyYWN0ZXIoQVYkc2FtcGxlX2lkKQpBViRkcCA9IGFzLm51bWVyaWMoQVYkZHApCkFWID0gc2VwYXJhdGUoQVYsIHNhbXBsZV9pZCwgc2VwID0gIl8iLCAKICAgICAgICAgICAgICAgaW50byA9IGMoInN0cmFpbiIsIkFGIiwiYWxsZWxlX2ZyZXEiLCJmcmFjIiwic2VxX2RlcHRoIiwidG9vbCIsInBhcmFtZXRlciIsInBhcmFtZXRlcjIiKSkgJT4lCiAgc2VsZWN0KGFsbGVsZV9mcmVxLHNlcV9kZXB0aCx0b29sLCBwYXJhbWV0ZXIsIGNocm9tLHBvcyxhZl9nb2xkZW4sYWZfd29ya2Zsb3cscmVmLGFsdCxkcCkgJT4lCiAgZmlsdGVyKHJlZiA9PSAiQSIgfCByZWYgPT0gIkMiIHwgcmVmID09ICJUIiB8IHJlZiA9PSAiRyIpICU+JSAKICBmaWx0ZXIoYWx0ID09ICJBIiB8IGFsdCA9PSAiQyIgfCBhbHQgPT0gIlQiIHwgYWx0ID09ICJHIikgJT4lIGRyb3BsZXZlbHMoKQpBViRzZXFfZGVwdGggPSBhcy5udW1lcmljKEFWJHNlcV9kZXB0aCkKQVYkY292ZXJhZ2UgPSAoQVYkc2VxX2RlcHRoICogcmVhZHNpbV9jb3YpICN2YXJpYWJsZSBjYWxsZWQgaW4gcGlwZWxpbmUsIGNvcnJlc3BvbmRzIHRvIGhpZ2hlc3QgY292ZXJhZ2UKQVYkY292ZXJhZ2UgPSBhcy5jaGFyYWN0ZXIoQVYkY292ZXJhZ2UpCmhlYWQoQVYpCgp2YXJpYW50X3BvcyA9IGdncGxvdChBViwgYWVzKHggPSBwb3MsIHkgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZCh+Y2hyb20sIHNjYWxlcyA9ICJmcmVlX3giKSArIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikKcHJpbnQodmFyaWFudF9wb3MpCgpgYGAKCiMjUmVhZGluZyBpbiBHb2xkZW4gRGF0YSBhbmQgRXZhbHVhdGluZwpgYGB7cn0KdmlyYWxfZ29sZGVuID0gcmVhZC50YWJsZShnb2xkZW5fdmNmLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKY29sbmFtZXModmlyYWxfZ29sZGVuKSA9IGMoImNocm9tIiwicG9zIiwiSUQiLCJyZWYiLCJhbHQiLCJxdWFsIiwiZmlsdGVyIiwiaW5mbyIsImNvZGVzIiwiZ2Vub3R5cGUiKQp2aXJhbF9nb2xkZW4gPSBzZXBhcmF0ZSh2aXJhbF9nb2xkZW4sIGluZm8sIHNlcCA9ICI9IiwgaW50byA9IGMoTkEsIkFGIikpCnZpcmFsX2dvbGRlbiRjaHJvbSA9IGZhY3Rvcih2aXJhbF9nb2xkZW4kY2hyb20sIGxldmVscyA9IFNFR01FTlRMSVNUKQpoZWFkKHZpcmFsX2dvbGRlbikKZGltKHZpcmFsX2dvbGRlbikKCgp2aXJhbF9nb2xkZW5fcG9zID0gZ2dwbG90KHZpcmFsX2dvbGRlbiwgYWVzKHggPSBwb3MsIHkgPSByZWYsIGNvbG9yID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZCh+Y2hyb20sIHNjYWxlcyA9ICJmcmVlX3giKSsgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSA2KQpwcmludCh2aXJhbF9nb2xkZW5fcG9zKQpgYGAKCiMjU2V0QUYgLSBTZXBhcmF0aW5nIERhdGEgaW50byBUUCwgRlAsIEZOCmBgYHtyfQpBVl9zZXRBRiA9IGZpbHRlcihBViwgYWxsZWxlX2ZyZXEgIT0gInJhbmRvbSIpICU+JSBkcm9wbGV2ZWxzKCkKCkFWX3NldEFGX2ZhbHNlcG9zID0gZmlsdGVyKEFWX3NldEFGLCBhZl9nb2xkZW4gPT0gMCAmIGFmX3dvcmtmbG93ICE9IDApICU+JSBkcm9wbGV2ZWxzKCkKICBBVl9zZXRBRl9mYWxzZXBvcyRjYXRlZ29yeSA9IGMoIkZQIikKQVZfc2V0QUZfZmFsc2VuZWcgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX3dvcmtmbG93ID09IDAgJiBhZl9nb2xkZW4gIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3NldEFGX2ZhbHNlbmVnJGNhdGVnb3J5ID0gYygiRk4iKQpBVl9zZXRBRl90cnVlcG9zID0gZmlsdGVyKEFWX3NldEFGLCBhZl9nb2xkZW4gIT0gMCAmIGFmX3dvcmtmbG93ICE9IDApCiAgQVZfc2V0QUZfdHJ1ZXBvcyRjYXRlZ29yeSA9IGMoIlRQIikKICAKQVZfc2V0QUYgPSByYmluZChBVl9zZXRBRl90cnVlcG9zLCBBVl9zZXRBRl9mYWxzZW5lZywgQVZfc2V0QUZfZmFsc2Vwb3MpCgpGUF9BbGwgPSBncm91cF9ieShBVl9zZXRBRl9mYWxzZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhGUF9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJGUCIpCkZOX0FsbCA9IGdyb3VwX2J5KEFWX3NldEFGX2ZhbHNlbmVnLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKEZOX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZOIikKVFBfQWxsID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhUUF9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJUUCIpCiAgICAKQWxsVmFyID0gbWVyZ2UoRlBfQWxsLEZOX0FsbCwgYnk9YygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiKSxhbGw9VCkKQWxsVmFyID0gbWVyZ2UoQWxsVmFyLFRQX0FsbCwgYnk9YygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiKSwgYWxsPVQpCmhlYWQoQWxsVmFyKQoKQWxsVmFyW2lzLm5hKEFsbFZhcildID0gMApoZWFkKEFsbFZhcikKCkFsbFZhciRwcmVjID0gKEFsbFZhciRUUCkvKEFsbFZhciRUUCArIEFsbFZhciRGUCkKQWxsVmFyJHJlY2FsbCA9IChBbGxWYXIkVFApLyhBbGxWYXIkVFAgKyBBbGxWYXIkRk4pCkFsbFZhciRhcmVhID0gQWxsVmFyJHByZWMgKiBBbGxWYXIkcmVjYWxsCmhlYWQoQWxsVmFyKQpgYGAKYGBge3J9CiMgU2V0QUYgRGF0YQpnZ3Bsb3QoQVZfc2V0QUYsIGFlcyh4ID0gdG9vbCwgZmlsbCA9IGNhdGVnb3J5KSkgKwogIGdlb21fYmFyKCkgKwogIGZhY2V0X2dyaWQoYWxsZWxlX2ZyZXF+Y292ZXJhZ2UpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCiMgcGxvdCBhcyBwZXJjZW50YWdlIG9mIEZOIGFzIHdlbGwKYGBgCgojI1JhbmRvbUFGIC0gU2VwYXJhdGluZyBEYXRhIGludG8gVFAsIEZQLCBGTgpgYGB7cn0KQVZfcmFuZG9tQUYgPSBmaWx0ZXIoQVYsIGFsbGVsZV9mcmVxID09ICJyYW5kb20iKSAlPiUgZHJvcGxldmVscygpCgpBVl9yYW5kb21BRl9mYWxzZXBvcyA9IGZpbHRlcihBVl9yYW5kb21BRiwgYWZfZ29sZGVuID09IDAgJiBhZl93b3JrZmxvdyAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfcmFuZG9tQUZfZmFsc2Vwb3MkY2F0ZWdvcnkgPSBjKCJGUCIpCkFWX3JhbmRvbUFGX2ZhbHNlbmVnID0gZmlsdGVyKEFWX3JhbmRvbUFGLCBhZl93b3JrZmxvdyA9PSAwICYgYWZfZ29sZGVuICE9IDApICU+JSBkcm9wbGV2ZWxzKCkKICBBVl9yYW5kb21BRl9mYWxzZW5lZyRjYXRlZ29yeSA9IGMoIkZOIikKQVZfcmFuZG9tQUZfdHJ1ZXBvcyA9IGZpbHRlcihBVl9yYW5kb21BRiwgYWZfZ29sZGVuICE9IDAgJiBhZl93b3JrZmxvdyAhPSAwKQogIEFWX3JhbmRvbUFGX3RydWVwb3MkY2F0ZWdvcnkgPSBjKCJUUCIpCiAgCkFWX3JhbmRvbUFGID0gcmJpbmQoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgQVZfcmFuZG9tQUZfZmFsc2VuZWcsIEFWX3JhbmRvbUFGX2ZhbHNlcG9zKQoKckZQX0FsbCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX2ZhbHNlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKHJGUF9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJGUCIpCnJGTl9BbGwgPSBncm91cF9ieShBVl9yYW5kb21BRl9mYWxzZW5lZywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhyRk5fQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRk4iKQpyVFBfQWxsID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhyVFBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiVFAiKQoKckFsbFZhciA9IG1lcmdlKHJGUF9BbGwsckZOX0FsbCwgYnk9YygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiKSxhbGw9VCkKckFsbFZhciA9IG1lcmdlKHJBbGxWYXIsIHJUUF9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksIGFsbD1UKQpoZWFkKHJBbGxWYXIpCgpyQWxsVmFyW2lzLm5hKHJBbGxWYXIpXSA9IDAKCnJBbGxWYXIkcHJlYyA9IChyQWxsVmFyJFRQKS8ockFsbFZhciRUUCArIHJBbGxWYXIkRlApCnJBbGxWYXIkcmVjYWxsID0gKHJBbGxWYXIkVFApLyhyQWxsVmFyJFRQICsgckFsbFZhciRGTikKckFsbFZhciRhcmVhID0gckFsbFZhciRwcmVjICogckFsbFZhciRyZWNhbGwKaGVhZChyQWxsVmFyKQpgYGAKYGBge3J9CiMgUmFuZG9tQUYgRGF0YQpnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gdG9vbCwgZmlsbCA9IGNhdGVnb3J5KSkgKwogIGdlb21fYmFyKCkgKwogIGZhY2V0X2dyaWQoYWxsZWxlX2ZyZXF+Y292ZXJhZ2UpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCiMgcGxvdCBhcyBwZXJjZW50YWdlIG9mIEZOIGFzIHdlbGwKYGBgCgojI1NldEFGIC0gQ29ycmVsYXRpb24gQmV0d2VlbiBHb2xkZW4gYW5kIFdvcmtmbG93CmBgYHtyfQojTG9va2luZyBhdCBhbGwgU2V0QUYgRGF0YQpBVl9Db3JyX3NldEFGIDwtIAogIGdncGxvdChBVl9zZXRBRiwgYWVzKHggPSBhZl9nb2xkZW4seSA9IGFmX3dvcmtmbG93LCBjb2xvciA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC40KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZChjb3ZlcmFnZX50b29sKSArIAogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDYpCnByaW50KEFWX0NvcnJfc2V0QUYpCiNnZ3NhdmUoQVZfQ29ycl9zZXRBRiwgZmlsZSA9ICJBbGxWYXJTZXRfQ29ycmVsYXRpb25fRmlsdGVyZWQucG5nIiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDFOMV9JbWFnZXMiKQoKYGBgCgojI1JhbmRvbUFGIC0gQ29ycmVsYXRpb24gQmV0d2VlbiBHb2xkZW4gYW5kIFdvcmtmbG93CmBgYHtyfQojI0xvb2tpbmcgYXQgYWxsIFJhbmRvbUFGIERhdGEKICBBVl9Db3JyX3JhbmRvbUFGIDwtIAogIGdncGxvdChBVl9yYW5kb21BRiwgYWVzKHggPSBhZl9nb2xkZW4seSA9IGFmX3dvcmtmbG93LCBjb2xvciA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC40KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZChjb3ZlcmFnZX50b29sKSArIAogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDYpCnByaW50KEFWX0NvcnJfcmFuZG9tQUYpCiNnZ3NhdmUoIkFsbFZhclJhbmRvbV9Db3JyZWxhdGlvbl9GaWx0ZXJlZC5wbmciLEFWX0NvcnJfcmFuZG9tQUYsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gxTjFfSW1hZ2VzIikKYGBgCgoKCiMjIFN0YXRzIGZvciBTZXRBRiBEYXRhCmBgYHtyfQpkZXRhY2gocGFja2FnZTpwbHlyLCB1bmxvYWQ9VFJVRSkKY29lZmZfdmFyIDwtIGZ1bmN0aW9uKHgpIHsKICBDViA8LSBzZCh4KSAvIG1lYW4oeCkgKiAxMDAKICByZXR1cm4oQ1YpCn0KCkFWX3NldEFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUKICBzdW1tYXJpemUobWVhbiA9IG1lYW4oYWZfd29ya2Zsb3cpLCBzZCA9IHNkKGFmX3dvcmtmbG93KSwgdmFyaWFuY2UgPSBjb2VmZl92YXIoYWZfd29ya2Zsb3cpKSAlPiUgZHJvcGxldmVscygpCk1lYW5fc2V0QUYgPSBnZ3Bsb3QoQVZfc2V0QUZfc3BsaXQsIGFlcyh4ID0gY292ZXJhZ2UsIHkgPSBtZWFuLCBjb2xvciA9IGFsbGVsZV9mcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKwogICNmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGFsbGVsZV9mcmVxKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KE1lYW5fc2V0QUYpCiNnZ3NhdmUoIlNldEFGX01lYW5fQWxsZWxlRnJlcXVlbmN5LnBuZyIsTWVhbl9zZXRBRiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDFOMV9JbWFnZXMiKQojdmlzdWxpemUgdGhlIGVmZmVjdCBvZiBkb3duc2FtcGxpbmcuIApDb2VmZlZhcl9zZXRBRiA9IGdncGxvdChBVl9zZXRBRl9zcGxpdCwgYWVzKHggPSBjb3ZlcmFnZSwgeSA9IHZhcmlhbmNlLCBjb2xvciA9IGFsbGVsZV9mcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKwogICNmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGFsbGVsZV9mcmVxKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KENvZWZmVmFyX3NldEFGKQojZ2dzYXZlKCJTZXRBRl9Db2VmZlZhcl9BbGxlbGVGcmVxdWVuY3kucG5nIixDb2VmZlZhcl9zZXRBRiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDFOMV9JbWFnZXMiKQojdmFyaWFuY2VzIGFib3ZlIDEwMDAwIGFyZSBzaW1saWFyCgpgYGAKIyMgU3RhdHMgZm9yIFJhbmRvbUFGIERhdGEKYGBge3J9CkFWX3JhbmRvbUFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgdG9vbCwgY292ZXJhZ2UpICU+JQogIHN1bW1hcml6ZShtZWFuID0gbWVhbihhZl93b3JrZmxvdyksIHNkID0gc2QoYWZfd29ya2Zsb3cpLCB2YXJpYW5jZSA9IGNvZWZmX3ZhcihhZl93b3JrZmxvdykpICU+JSBkcm9wbGV2ZWxzKCkKCk1lYW5fcmFuZG9tQUYgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfc3BsaXQsIGFlcyh4ID0gY292ZXJhZ2UsIHkgPSBtZWFuLCBjb2xvciA9IHRvb2wpKSArIAogIGdlb21fcG9pbnQoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoTWVhbl9yYW5kb21BRikKI2dnc2F2ZSgiUmFuZG9tQUZfTWVhbl9BbGxlbGVGcmVxdWVuY3kucG5nIixNZWFuX3JhbmRvbUFGLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IMU4xX0ltYWdlcyIpCgpDb2VmZlZhcl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRl9zcGxpdCwgYWVzKHggPSBjb3ZlcmFnZSwgeSA9IHZhcmlhbmNlLCBjb2xvciA9IHRvb2wpKSArIAogIGdlb21fcG9pbnQoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoQ29lZmZWYXJfcmFuZG9tQUYpCiNnZ3NhdmUoIlJhbmRvbUFGX0NvZWZmVmFyX0FsbGVsZUZyZXF1ZW5jeS5wbmciLENvZWZmVmFyX3JhbmRvbUFGLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IMU4xX0ltYWdlcyIpCmBgYAoKYGBge3J9CmdncGxvdChBVl9zZXRBRiwgYWVzKHggPSBsb2cxMChkcCksIHkgPSBhZl93b3JrZmxvdywgY29sb3IgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhjb3ZlcmFnZSksIGNvbHMgPSB2YXJzKGFsbGVsZV9mcmVxKSkgKwogIHhsaW0oMCw2KQoKIyBkbyB0aGlzIHdpdGggYWxsIGJhbWZpbGVzLCBub3QganVzdCB2YXJpYW50cwpnZ3Bsb3QoQVZfc2V0QUYsIGFlcyh4ID0gbG9nMTAoZHApLCBmaWxsID0gdG9vbCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoY292ZXJhZ2UpLCBjb2xzID0gdmFycyhhbGxlbGVfZnJlcSkpCgpgYGAK