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")
# 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
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. Missing pieces filled with `NA` in 128704 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] 143 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'
Warning in qt((1 - level)/2, df): NaNs produced
Warning in qt((1 - level)/2, df): NaNs produced
Warning in qt((1 - level)/2, df): NaNs produced
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning -
Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning -
Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning -
Inf

#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 24 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)
Warning: Removed 4 rows containing missing values (geom_point).

#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)
Warning: Removed 6147 rows containing missing values (geom_point).

# 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`.
Warning: Removed 6147 rows containing non-finite values (stat_bin).

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyNUaGlzIG5vdGVib29rIHRha2VzIHRoZSBvdXRwdXQgZm9yIHRoZSBNQUYgUGlwZWxpbmUgKG15Y3N2ZmlsZS5jc3YpIGFuZCBkb2VzOgoxLiBDYWxjdWxhdGVzIHRydWUgcG9zLCBmYWxzZSBwb3MsIGFuZCBmYWxzZSBuZWcgYW5kIG1ha2VzIGEgcHJlY2lzaW9uIHJlY2FsbCBjdXJ2ZSBmb3IgYWxsIHRvb2xzCjIuIEZpbmRzIHRvdGFsIG51bWJlcnMgb2YgdmFyaWFudHMgZm91bmQgYnkgdG9vbHMgYXQgZGlmZmVyZW50IGFsbGVsZSBmcmVxdWVuY2llcyBhbmQgc2VxdWVuY2luZyBkZXB0aHMKMy4gTG9va3MgYXQgY29ycmVsYXRpb24gYmV0d2VlbiBTTlBTIGluIHRoZSBnb2xkZW4gdmNmIGFuZCB3b3JmbG93IHZjZgoKYGBge3J9CiNrbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpCiNydW4gaW4gd29ya2luZyBkaXJlY3RvcnkKI3NldHdkKCIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpIApgYGAKCmBgYHtyfQojbGlicmFyeShhdmFpbGFibGUpCiNhdmFpbGFibGUoIlZpdmFsZGkiLCBicm93c2UgPSBGQUxTRSkKYGBgCgojI0xvYWRpbmcgTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgndGlkeXZlcnNlJykKbGlicmFyeSgicGxvdHJpeCIpIApsaWJyYXJ5KCdnZ3Bsb3QyJykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgiTUxtZXRyaWNzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKICAgICAgICAKTXlDb2xvcnMgPSBjKCIjZTQxYTFjIiwgIiMzNzdlYjgiLCAiIzRkYWY0YSIsIiM5ODRlYTMiLCAiI2ZmNjYwMCIsICIjZmZjYzMzIiwgIiNmNzgxYmYiLCAiI2E2NTYyOCIsICIjOTk5OTk5IiwgIiMwMDY2MDAiLCAiIzk5MzMzMyIsICIjY2M5OWZmIiwgIiM2NjMzMDAiKQojIFRoaXMgaXMgYmFzaWNhbGx5IFJDb2xvckJyZXdlciBTZXQxIGJ1dCBJIGRhcmtlbmVkIHllbGxvdyB0byBtYWtlIGl0IGVhc2llciB0byBzZWUgdGhlbiBjaGFuZ2VkIG9yYW5nZSBhIGJpdCB0byBkaWZmZXIgbW9yZSBmcm9tIHllbGxvdwojClNFR01FTlRMSVNUID0gYygiSDFOMV9QQjIiLCJIMU4xX1BCMSIsIkgxTjFfUEEiLCJIMU4xX0hBIiwiSDFOMV9OUCIsIkgxTjFfTkEiLCJIMU4xX01QIiwiSDFOMV9OUyIpCmdncGxvdDI6OnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCgp0b3RhbGJhc2VzID0gMjk5MDMgIyBhdCBzb21lIHBvaW50IHNob3VsZCBjaGFuZ2UgdGhpcyBmcm9tIGJlaW5nIGhhcmRjb2RlZCB0byBtYWtlIHRoaXMgbW9yZSBmbGV4aWJsZQpyZWFkc2ltX2NvdiA9IDEwMDAwMCAjaGFyZG9jZGluZyB0aGlzIGZvciBub3cgc28gbXkgY29kZSBydW5zCmBgYAoKIyNSZWFkaW5nIGluIFZhcmlhbnQgRGF0YSBhbmQgRXZhbHVhdGluZwpgYGB7cn0KQVYgPSByZWFkLmNzdihhZl9yZXBvcnQsaGVhZGVyID0gVCkKI21ha2UgdGhlIHNlZ21lbnRzIGluIGEgc3BlY2lmaWMgb3JkZXIKQVYkY2hyb20gPSBmYWN0b3IoQVYkY2hyb20sIGxldmVscyA9IFNFR01FTlRMSVNUKQoKQVYkc2FtcGxlX2lkID0gYXMuY2hhcmFjdGVyKEFWJHNhbXBsZV9pZCkKQVYkZHAgPSBhcy5udW1lcmljKEFWJGRwKQpBViA9IHNlcGFyYXRlKEFWLCBzYW1wbGVfaWQsIHNlcCA9ICJfIiwgCiAgICAgICAgICAgICAgIGludG8gPSBjKCJzdHJhaW4iLCJBRiIsImFsbGVsZV9mcmVxIiwiZnJhYyIsInNlcV9kZXB0aCIsInRvb2wiLCJwYXJhbWV0ZXIiLCJwYXJhbWV0ZXIyIikpICU+JQogIHNlbGVjdChhbGxlbGVfZnJlcSxzZXFfZGVwdGgsdG9vbCwgcGFyYW1ldGVyLCBjaHJvbSxwb3MsYWZfZ29sZGVuLGFmX3dvcmtmbG93LHJlZixhbHQsZHApICU+JQogIGZpbHRlcihyZWYgPT0gIkEiIHwgcmVmID09ICJDIiB8IHJlZiA9PSAiVCIgfCByZWYgPT0gIkciKSAlPiUgCiAgZmlsdGVyKGFsdCA9PSAiQSIgfCBhbHQgPT0gIkMiIHwgYWx0ID09ICJUIiB8IGFsdCA9PSAiRyIpICU+JSBkcm9wbGV2ZWxzKCkKQVYkc2VxX2RlcHRoID0gYXMubnVtZXJpYyhBViRzZXFfZGVwdGgpCkFWJGNvdmVyYWdlID0gKEFWJHNlcV9kZXB0aCAqIHJlYWRzaW1fY292KSAjdmFyaWFibGUgY2FsbGVkIGluIHBpcGVsaW5lLCBjb3JyZXNwb25kcyB0byBoaWdoZXN0IGNvdmVyYWdlCkFWJGNvdmVyYWdlID0gYXMuY2hhcmFjdGVyKEFWJGNvdmVyYWdlKQpoZWFkKEFWKQoKdmFyaWFudF9wb3MgPSBnZ3Bsb3QoQVYsIGFlcyh4ID0gcG9zLCB5ID0gdG9vbCkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQofmNocm9tLCBzY2FsZXMgPSAiZnJlZV94IikgKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDYpCnByaW50KHZhcmlhbnRfcG9zKQoKYGBgCgojI1JlYWRpbmcgaW4gR29sZGVuIERhdGEgYW5kIEV2YWx1YXRpbmcKYGBge3J9CnZpcmFsX2dvbGRlbiA9IHJlYWQudGFibGUoZ29sZGVuX3ZjZiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHZpcmFsX2dvbGRlbikgPSBjKCJjaHJvbSIsInBvcyIsIklEIiwicmVmIiwiYWx0IiwicXVhbCIsImZpbHRlciIsImluZm8iLCJjb2RlcyIsImdlbm90eXBlIikKdmlyYWxfZ29sZGVuID0gc2VwYXJhdGUodmlyYWxfZ29sZGVuLCBpbmZvLCBzZXAgPSAiPSIsIGludG8gPSBjKE5BLCJBRiIpKQp2aXJhbF9nb2xkZW4kY2hyb20gPSBmYWN0b3IodmlyYWxfZ29sZGVuJGNocm9tLCBsZXZlbHMgPSBTRUdNRU5UTElTVCkKaGVhZCh2aXJhbF9nb2xkZW4pCmRpbSh2aXJhbF9nb2xkZW4pCgoKdmlyYWxfZ29sZGVuX3BvcyA9IGdncGxvdCh2aXJhbF9nb2xkZW4sIGFlcyh4ID0gcG9zLCB5ID0gcmVmLCBjb2xvciA9IGFsdCkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQofmNocm9tLCBzY2FsZXMgPSAiZnJlZV94IikrIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikKcHJpbnQodmlyYWxfZ29sZGVuX3BvcykKYGBgCgojI1NldEFGIC0gU2VwYXJhdGluZyBEYXRhIGludG8gVFAsIEZQLCBGTgpgYGB7cn0KQVZfc2V0QUYgPSBmaWx0ZXIoQVYsIGFsbGVsZV9mcmVxICE9ICJyYW5kb20iKSAlPiUgZHJvcGxldmVscygpCgpBVl9zZXRBRl9mYWxzZXBvcyA9IGZpbHRlcihBVl9zZXRBRiwgYWZfZ29sZGVuID09IDAgJiBhZl93b3JrZmxvdyAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfc2V0QUZfZmFsc2Vwb3MkY2F0ZWdvcnkgPSBjKCJGUCIpCkFWX3NldEFGX2ZhbHNlbmVnID0gZmlsdGVyKEFWX3NldEFGLCBhZl93b3JrZmxvdyA9PSAwICYgYWZfZ29sZGVuICE9IDApICU+JSBkcm9wbGV2ZWxzKCkKICBBVl9zZXRBRl9mYWxzZW5lZyRjYXRlZ29yeSA9IGMoIkZOIikKQVZfc2V0QUZfdHJ1ZXBvcyA9IGZpbHRlcihBVl9zZXRBRiwgYWZfZ29sZGVuICE9IDAgJiBhZl93b3JrZmxvdyAhPSAwKQogIEFWX3NldEFGX3RydWVwb3MkY2F0ZWdvcnkgPSBjKCJUUCIpCiAgCkFWX3NldEFGID0gcmJpbmQoQVZfc2V0QUZfdHJ1ZXBvcywgQVZfc2V0QUZfZmFsc2VuZWcsIEFWX3NldEFGX2ZhbHNlcG9zKQoKRlBfQWxsID0gZ3JvdXBfYnkoQVZfc2V0QUZfZmFsc2Vwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoRlBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRlAiKQpGTl9BbGwgPSBncm91cF9ieShBVl9zZXRBRl9mYWxzZW5lZywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhGTl9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJGTiIpClRQX0FsbCA9IGdyb3VwX2J5KEFWX3NldEFGX3RydWVwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoVFBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiVFAiKQogICAgCkFsbFZhciA9IG1lcmdlKEZQX0FsbCxGTl9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksYWxsPVQpCkFsbFZhciA9IG1lcmdlKEFsbFZhcixUUF9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksIGFsbD1UKQpoZWFkKEFsbFZhcikKCkFsbFZhcltpcy5uYShBbGxWYXIpXSA9IDAKaGVhZChBbGxWYXIpCgpBbGxWYXIkcHJlYyA9IChBbGxWYXIkVFApLyhBbGxWYXIkVFAgKyBBbGxWYXIkRlApCkFsbFZhciRyZWNhbGwgPSAoQWxsVmFyJFRQKS8oQWxsVmFyJFRQICsgQWxsVmFyJEZOKQpBbGxWYXIkYXJlYSA9IEFsbFZhciRwcmVjICogQWxsVmFyJHJlY2FsbApoZWFkKEFsbFZhcikKYGBgCmBgYHtyfQojIFNldEFGIERhdGEKZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IHRvb2wsIGZpbGwgPSBjYXRlZ29yeSkpICsKICBnZW9tX2JhcigpICsKICBmYWNldF9ncmlkKGFsbGVsZV9mcmVxfmNvdmVyYWdlKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKQojIHBsb3QgYXMgcGVyY2VudGFnZSBvZiBGTiBhcyB3ZWxsCmBgYAoKIyNSYW5kb21BRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3JhbmRvbUFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSA9PSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfcmFuZG9tQUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3JhbmRvbUFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9yYW5kb21BRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9yYW5kb21BRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfcmFuZG9tQUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3JhbmRvbUFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9yYW5kb21BRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9yYW5kb21BRiA9IHJiaW5kKEFWX3JhbmRvbUFGX3RydWVwb3MsIEFWX3JhbmRvbUFGX2ZhbHNlbmVnLCBBVl9yYW5kb21BRl9mYWxzZXBvcykKCnJGUF9BbGwgPSBncm91cF9ieShBVl9yYW5kb21BRl9mYWxzZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhyRlBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRlAiKQpyRk5fQWxsID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMockZOX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZOIikKclRQX0FsbCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoclRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKCnJBbGxWYXIgPSBtZXJnZShyRlBfQWxsLHJGTl9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksYWxsPVQpCnJBbGxWYXIgPSBtZXJnZShyQWxsVmFyLCByVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChyQWxsVmFyKQoKckFsbFZhcltpcy5uYShyQWxsVmFyKV0gPSAwCgpyQWxsVmFyJHByZWMgPSAockFsbFZhciRUUCkvKHJBbGxWYXIkVFAgKyByQWxsVmFyJEZQKQpyQWxsVmFyJHJlY2FsbCA9IChyQWxsVmFyJFRQKS8ockFsbFZhciRUUCArIHJBbGxWYXIkRk4pCnJBbGxWYXIkYXJlYSA9IHJBbGxWYXIkcHJlYyAqIHJBbGxWYXIkcmVjYWxsCmhlYWQockFsbFZhcikKYGBgCmBgYHtyfQojIFJhbmRvbUFGIERhdGEKZ2dwbG90KEFWX3JhbmRvbUFGLCBhZXMoeCA9IHRvb2wsIGZpbGwgPSBjYXRlZ29yeSkpICsKICBnZW9tX2JhcigpICsKICBmYWNldF9ncmlkKGFsbGVsZV9mcmVxfmNvdmVyYWdlKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKQojIHBsb3QgYXMgcGVyY2VudGFnZSBvZiBGTiBhcyB3ZWxsCmBgYAoKIyNTZXRBRiAtIENvcnJlbGF0aW9uIEJldHdlZW4gR29sZGVuIGFuZCBXb3JrZmxvdwpgYGB7cn0KI0xvb2tpbmcgYXQgYWxsIFNldEFGIERhdGEKQVZfQ29ycl9zZXRBRiA8LSAKICBnZ3Bsb3QoQVZfc2V0QUYsIGFlcyh4ID0gYWZfZ29sZGVuLHkgPSBhZl93b3JrZmxvdywgY29sb3IgPSBjYXRlZ29yeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IDAuNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykgKwogIGZhY2V0X2dyaWQoY292ZXJhZ2V+dG9vbCkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgc2l6ZSA9IDEuNSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSA2KQpwcmludChBVl9Db3JyX3NldEFGKQojZ2dzYXZlKEFWX0NvcnJfc2V0QUYsIGZpbGUgPSAiQWxsVmFyU2V0X0NvcnJlbGF0aW9uX0ZpbHRlcmVkLnBuZyIsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gxTjFfSW1hZ2VzIikKCmBgYAoKIyNSYW5kb21BRiAtIENvcnJlbGF0aW9uIEJldHdlZW4gR29sZGVuIGFuZCBXb3JrZmxvdwpgYGB7cn0KIyNMb29raW5nIGF0IGFsbCBSYW5kb21BRiBEYXRhCiAgQVZfQ29ycl9yYW5kb21BRiA8LSAKICBnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gYWZfZ29sZGVuLHkgPSBhZl93b3JrZmxvdywgY29sb3IgPSBjYXRlZ29yeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IDAuNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykgKwogIGZhY2V0X2dyaWQoY292ZXJhZ2V+dG9vbCkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgc2l6ZSA9IDEuNSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSA2KQpwcmludChBVl9Db3JyX3JhbmRvbUFGKQojZ2dzYXZlKCJBbGxWYXJSYW5kb21fQ29ycmVsYXRpb25fRmlsdGVyZWQucG5nIixBVl9Db3JyX3JhbmRvbUFGLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IMU4xX0ltYWdlcyIpCmBgYAoKCgojIyBTdGF0cyBmb3IgU2V0QUYgRGF0YQpgYGB7cn0KZGV0YWNoKHBhY2thZ2U6cGx5ciwgdW5sb2FkPVRSVUUpCmNvZWZmX3ZhciA8LSBmdW5jdGlvbih4KSB7CiAgQ1YgPC0gc2QoeCkgLyBtZWFuKHgpICogMTAwCiAgcmV0dXJuKENWKQp9CgpBVl9zZXRBRl9zcGxpdCA9IGdyb3VwX2J5KEFWX3NldEFGX3RydWVwb3MsIHRvb2wsIGFsbGVsZV9mcmVxLCBjb3ZlcmFnZSkgJT4lCiAgc3VtbWFyaXplKG1lYW4gPSBtZWFuKGFmX3dvcmtmbG93KSwgc2QgPSBzZChhZl93b3JrZmxvdyksIHZhcmlhbmNlID0gY29lZmZfdmFyKGFmX3dvcmtmbG93KSkgJT4lIGRyb3BsZXZlbHMoKQpNZWFuX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IGNvdmVyYWdlLCB5ID0gbWVhbiwgY29sb3IgPSBhbGxlbGVfZnJlcSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICAjZmFjZXRfZ3JpZChjb2xzID0gdmFycyhhbGxlbGVfZnJlcSkpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChNZWFuX3NldEFGKQojZ2dzYXZlKCJTZXRBRl9NZWFuX0FsbGVsZUZyZXF1ZW5jeS5wbmciLE1lYW5fc2V0QUYsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gxTjFfSW1hZ2VzIikKI3Zpc3VsaXplIHRoZSBlZmZlY3Qgb2YgZG93bnNhbXBsaW5nLiAKQ29lZmZWYXJfc2V0QUYgPSBnZ3Bsb3QoQVZfc2V0QUZfc3BsaXQsIGFlcyh4ID0gY292ZXJhZ2UsIHkgPSB2YXJpYW5jZSwgY29sb3IgPSBhbGxlbGVfZnJlcSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICAjZmFjZXRfZ3JpZChjb2xzID0gdmFycyhhbGxlbGVfZnJlcSkpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChDb2VmZlZhcl9zZXRBRikKI2dnc2F2ZSgiU2V0QUZfQ29lZmZWYXJfQWxsZWxlRnJlcXVlbmN5LnBuZyIsQ29lZmZWYXJfc2V0QUYsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gxTjFfSW1hZ2VzIikKI3ZhcmlhbmNlcyBhYm92ZSAxMDAwMCBhcmUgc2ltbGlhcgoKYGBgCiMjIFN0YXRzIGZvciBSYW5kb21BRiBEYXRhCmBgYHtyfQpBVl9yYW5kb21BRl9zcGxpdCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3MsIHRvb2wsIGNvdmVyYWdlKSAlPiUKICBzdW1tYXJpemUobWVhbiA9IG1lYW4oYWZfd29ya2Zsb3cpLCBzZCA9IHNkKGFmX3dvcmtmbG93KSwgdmFyaWFuY2UgPSBjb2VmZl92YXIoYWZfd29ya2Zsb3cpKSAlPiUgZHJvcGxldmVscygpCgpNZWFuX3JhbmRvbUFGID0gZ2dwbG90KEFWX3JhbmRvbUFGX3NwbGl0LCBhZXMoeCA9IGNvdmVyYWdlLCB5ID0gbWVhbiwgY29sb3IgPSB0b29sKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KE1lYW5fcmFuZG9tQUYpCiNnZ3NhdmUoIlJhbmRvbUFGX01lYW5fQWxsZWxlRnJlcXVlbmN5LnBuZyIsTWVhbl9yYW5kb21BRiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDFOMV9JbWFnZXMiKQoKQ29lZmZWYXJfcmFuZG9tQUYgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfc3BsaXQsIGFlcyh4ID0gY292ZXJhZ2UsIHkgPSB2YXJpYW5jZSwgY29sb3IgPSB0b29sKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KENvZWZmVmFyX3JhbmRvbUFGKQojZ2dzYXZlKCJSYW5kb21BRl9Db2VmZlZhcl9BbGxlbGVGcmVxdWVuY3kucG5nIixDb2VmZlZhcl9yYW5kb21BRiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDFOMV9JbWFnZXMiKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoQVZfc2V0QUYsIGFlcyh4ID0gbG9nMTAoZHApLCB5ID0gYWZfd29ya2Zsb3csIGNvbG9yID0gdG9vbCkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoY292ZXJhZ2UpLCBjb2xzID0gdmFycyhhbGxlbGVfZnJlcSkpICsKICB4bGltKDAsNikKCiMgZG8gdGhpcyB3aXRoIGFsbCBiYW1maWxlcywgbm90IGp1c3QgdmFyaWFudHMKZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGxvZzEwKGRwKSwgZmlsbCA9IHRvb2wpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGNvdmVyYWdlKSwgY29scyA9IHZhcnMoYWxsZWxlX2ZyZXEpKQoKYGBgCg==