This notebook takes the output for the MAF Pipeline (mycsvfile.csv) and does:

  1. Calculates true pos, false pos, and false neg and makes a precision recall curve for all tools
  2. Finds total numbers of variants found by tools at different allele frequencies and sequencing depths
  3. 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("H3N2_PB2","H3N2_PB1","H3N2_PA","H3N2_HA","H3N2_NP","H3N2_NA","H3N2_MP","H3N2_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","mv","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,mv) %>%
  filter(ref == "A" | ref == "C" | ref == "T" | ref == "G") %>% 
  filter(alt == "A" | alt == "C" | alt == "T" | alt == "G") %>% droplevels()
Warning: Expected 9 pieces. Missing pieces filled with `NA` in 353561 rows [131,
132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
148, 149, 150, ...].
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] 124  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/H3N2_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/H3N2_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/H3N2_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)

#ggsave("SetAF_CoeffVar_AlleleFrequency.png",CoeffVar_setAF,
#       path = "/Users/marissaknoll/Desktop/MAF/H3N2_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/H3N2_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/H3N2_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 102436 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 102436 rows containing non-finite values (stat_bin).

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyNUaGlzIG5vdGVib29rIHRha2VzIHRoZSBvdXRwdXQgZm9yIHRoZSBNQUYgUGlwZWxpbmUgKG15Y3N2ZmlsZS5jc3YpIGFuZCBkb2VzOgoxLiBDYWxjdWxhdGVzIHRydWUgcG9zLCBmYWxzZSBwb3MsIGFuZCBmYWxzZSBuZWcgYW5kIG1ha2VzIGEgcHJlY2lzaW9uIHJlY2FsbCBjdXJ2ZSBmb3IgYWxsIHRvb2xzCjIuIEZpbmRzIHRvdGFsIG51bWJlcnMgb2YgdmFyaWFudHMgZm91bmQgYnkgdG9vbHMgYXQgZGlmZmVyZW50IGFsbGVsZSBmcmVxdWVuY2llcyBhbmQgc2VxdWVuY2luZyBkZXB0aHMKMy4gTG9va3MgYXQgY29ycmVsYXRpb24gYmV0d2VlbiBTTlBTIGluIHRoZSBnb2xkZW4gdmNmIGFuZCB3b3JmbG93IHZjZgoKYGBge3J9CiNrbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpCiNydW4gaW4gd29ya2luZyBkaXJlY3RvcnkKI3NldHdkKCIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGLyIpIApgYGAKCmBgYHtyfQojbGlicmFyeShhdmFpbGFibGUpCiNhdmFpbGFibGUoIlZpdmFsZGkiLCBicm93c2UgPSBGQUxTRSkKYGBgCgojI0xvYWRpbmcgTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgndGlkeXZlcnNlJykKbGlicmFyeSgicGxvdHJpeCIpIApsaWJyYXJ5KCdnZ3Bsb3QyJykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgiTUxtZXRyaWNzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKICAgICAgICAKTXlDb2xvcnMgPSBjKCIjZTQxYTFjIiwgIiMzNzdlYjgiLCAiIzRkYWY0YSIsIiM5ODRlYTMiLCAiI2ZmNjYwMCIsICIjZmZjYzMzIiwgIiNmNzgxYmYiLCAiI2E2NTYyOCIsICIjOTk5OTk5IiwgIiMwMDY2MDAiLCAiIzk5MzMzMyIsICIjY2M5OWZmIiwgIiM2NjMzMDAiLCAnI2U2MTk0YicsICcjM2NiNDRiJywgJyNmZmUxMTknLCAnIzQzNjNkOCcsICcjZjU4MjMxJywgJyM5MTFlYjQnLCAnIzQ2ZjBmMCcsICcjZjAzMmU2JywgJyNiY2Y2MGMnLCAnI2ZhYmViZScsICcjMDA4MDgwJywgJyNlNmJlZmYnLCAnIzlhNjMyNCcsICcjZmZmYWM4JywgJyM4MDAwMDAnLCAnI2FhZmZjMycsICcjODA4MDAwJywgJyNmZmQ4YjEnLCAnIzAwMDA3NScsICcjODA4MDgwJywgJyMwMDAwMDAnKQojIFRoaXMgaXMgYmFzaWNhbGx5IFJDb2xvckJyZXdlciBTZXQxIGJ1dCBJIGRhcmtlbmVkIHllbGxvdyB0byBtYWtlIGl0IGVhc2llciB0byBzZWUgdGhlbiBjaGFuZ2VkIG9yYW5nZSBhIGJpdCB0byBkaWZmZXIgbW9yZSBmcm9tIHllbGxvdwojClNFR01FTlRMSVNUID0gYygiSDNOMl9QQjIiLCJIM04yX1BCMSIsIkgzTjJfUEEiLCJIM04yX0hBIiwiSDNOMl9OUCIsIkgzTjJfTkEiLCJIM04yX01QIiwiSDNOMl9OUyIpCmdncGxvdDI6OnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCgojdG90YWxiYXNlcyA9IDI5OTAzICMgYXQgc29tZSBwb2ludCBzaG91bGQgY2hhbmdlIHRoaXMgZnJvbSBiZWluZyBoYXJkY29kZWQgdG8gbWFrZSB0aGlzIG1vcmUgZmxleGlibGUKdG90YWxiYXNlcyA9IDEzNTg4ICMgaGFyZCBjb2RpbmcgZm9yIGZsdSBBLCBpcyB0aGlzIGNvcnJlY3Q/CnJlYWRzaW1fY292ID0gMTAwMDAwICNoYXJkb2NkaW5nIHRoaXMgZm9yIG5vdyBzbyBteSBjb2RlIHJ1bnMKYGBgCgojI1JlYWRpbmcgaW4gVmFyaWFudCBEYXRhIGFuZCBFdmFsdWF0aW5nCmBgYHtyfQpBViA9IHJlYWQuY3N2KGFmX3JlcG9ydCxoZWFkZXIgPSBUKQojbWFrZSB0aGUgc2VnbWVudHMgaW4gYSBzcGVjaWZpYyBvcmRlcgpBViRjaHJvbSA9IGZhY3RvcihBViRjaHJvbSwgbGV2ZWxzID0gU0VHTUVOVExJU1QpCgpBViRzYW1wbGVfaWQgPSBhcy5jaGFyYWN0ZXIoQVYkc2FtcGxlX2lkKQpBViRkcCA9IGFzLm51bWVyaWMoQVYkZHApCkFWID0gc2VwYXJhdGUoQVYsIHNhbXBsZV9pZCwgc2VwID0gIl8iLCAKICAgICAgICAgICAgICAgaW50byA9IGMoInN0cmFpbiIsIm12IiwiQUYiLCJhbGxlbGVfZnJlcSIsImZyYWMiLCJzZXFfZGVwdGgiLCJ0b29sIiwicGFyYW1ldGVyIiwicGFyYW1ldGVyMiIpKSAlPiUKICBzZWxlY3QoYWxsZWxlX2ZyZXEsc2VxX2RlcHRoLHRvb2wsIHBhcmFtZXRlciwgY2hyb20scG9zLGFmX2dvbGRlbixhZl93b3JrZmxvdyxyZWYsYWx0LGRwLG12KSAlPiUKICBmaWx0ZXIocmVmID09ICJBIiB8IHJlZiA9PSAiQyIgfCByZWYgPT0gIlQiIHwgcmVmID09ICJHIikgJT4lIAogIGZpbHRlcihhbHQgPT0gIkEiIHwgYWx0ID09ICJDIiB8IGFsdCA9PSAiVCIgfCBhbHQgPT0gIkciKSAlPiUgZHJvcGxldmVscygpCkFWJHNlcV9kZXB0aCA9IGFzLm51bWVyaWMoQVYkc2VxX2RlcHRoKQpBViRjb3ZlcmFnZSA9IChBViRzZXFfZGVwdGggKiByZWFkc2ltX2NvdikgI3ZhcmlhYmxlIGNhbGxlZCBpbiBwaXBlbGluZSwgY29ycmVzcG9uZHMgdG8gaGlnaGVzdCBjb3ZlcmFnZQpBViRjb3ZlcmFnZSA9IGFzLmNoYXJhY3RlcihBViRjb3ZlcmFnZSkKaGVhZChBVikKCnZhcmlhbnRfcG9zID0gZ2dwbG90KEFWLCBhZXMoeCA9IHBvcywgeSA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKH5jaHJvbSwgc2NhbGVzID0gImZyZWVfeCIpICsgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSA2KQpwcmludCh2YXJpYW50X3BvcykKCmBgYAoKIyNSZWFkaW5nIGluIEdvbGRlbiBEYXRhIGFuZCBFdmFsdWF0aW5nCmBgYHtyfQp2aXJhbF9nb2xkZW4gPSByZWFkLnRhYmxlKGdvbGRlbl92Y2YsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyh2aXJhbF9nb2xkZW4pID0gYygiY2hyb20iLCJwb3MiLCJJRCIsInJlZiIsImFsdCIsInF1YWwiLCJmaWx0ZXIiLCJpbmZvIiwiY29kZXMiLCJnZW5vdHlwZSIpCnZpcmFsX2dvbGRlbiA9IHNlcGFyYXRlKHZpcmFsX2dvbGRlbiwgaW5mbywgc2VwID0gIj0iLCBpbnRvID0gYyhOQSwiQUYiKSkKdmlyYWxfZ29sZGVuJGNocm9tID0gZmFjdG9yKHZpcmFsX2dvbGRlbiRjaHJvbSwgbGV2ZWxzID0gU0VHTUVOVExJU1QpCmhlYWQodmlyYWxfZ29sZGVuKQpkaW0odmlyYWxfZ29sZGVuKQoKCnZpcmFsX2dvbGRlbl9wb3MgPSBnZ3Bsb3QodmlyYWxfZ29sZGVuLCBhZXMoeCA9IHBvcywgeSA9IHJlZiwgY29sb3IgPSBhbHQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKH5jaHJvbSwgc2NhbGVzID0gImZyZWVfeCIpKyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDYpCnByaW50KHZpcmFsX2dvbGRlbl9wb3MpCmBgYAoKIyNTZXRBRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3NldEFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSAhPSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfc2V0QUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3NldEFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9zZXRBRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9zZXRBRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfc2V0QUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3NldEFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9zZXRBRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9zZXRBRiA9IHJiaW5kKEFWX3NldEFGX3RydWVwb3MsIEFWX3NldEFGX2ZhbHNlbmVnLCBBVl9zZXRBRl9mYWxzZXBvcykKCkZQX0FsbCA9IGdyb3VwX2J5KEFWX3NldEFGX2ZhbHNlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKEZQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZQIikKRk5fQWxsID0gZ3JvdXBfYnkoQVZfc2V0QUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoRk5fQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRk4iKQpUUF9BbGwgPSBncm91cF9ieShBVl9zZXRBRl90cnVlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKFRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKICAgIApBbGxWYXIgPSBtZXJnZShGUF9BbGwsRk5fQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLGFsbD1UKQpBbGxWYXIgPSBtZXJnZShBbGxWYXIsVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChBbGxWYXIpCgpBbGxWYXJbaXMubmEoQWxsVmFyKV0gPSAwCmhlYWQoQWxsVmFyKQoKQWxsVmFyJHByZWMgPSAoQWxsVmFyJFRQKS8oQWxsVmFyJFRQICsgQWxsVmFyJEZQKQpBbGxWYXIkcmVjYWxsID0gKEFsbFZhciRUUCkvKEFsbFZhciRUUCArIEFsbFZhciRGTikKQWxsVmFyJGFyZWEgPSBBbGxWYXIkcHJlYyAqIEFsbFZhciRyZWNhbGwKaGVhZChBbGxWYXIpCmBgYApgYGB7cn0KIyBTZXRBRiBEYXRhCmdncGxvdChBVl9zZXRBRiwgYWVzKHggPSB0b29sLCBmaWxsID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoKSArCiAgZmFjZXRfZ3JpZChhbGxlbGVfZnJlcX5jb3ZlcmFnZSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKIyBwbG90IGFzIHBlcmNlbnRhZ2Ugb2YgRk4gYXMgd2VsbApgYGAKCiMjUmFuZG9tQUYgLSBTZXBhcmF0aW5nIERhdGEgaW50byBUUCwgRlAsIEZOCmBgYHtyfQpBVl9yYW5kb21BRiA9IGZpbHRlcihBViwgYWxsZWxlX2ZyZXEgPT0gInJhbmRvbSIpICU+JSBkcm9wbGV2ZWxzKCkKCkFWX3JhbmRvbUFGX2ZhbHNlcG9zID0gZmlsdGVyKEFWX3JhbmRvbUFGLCBhZl9nb2xkZW4gPT0gMCAmIGFmX3dvcmtmbG93ICE9IDApICU+JSBkcm9wbGV2ZWxzKCkKICBBVl9yYW5kb21BRl9mYWxzZXBvcyRjYXRlZ29yeSA9IGMoIkZQIikKQVZfcmFuZG9tQUZfZmFsc2VuZWcgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX3dvcmtmbG93ID09IDAgJiBhZl9nb2xkZW4gIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3JhbmRvbUFGX2ZhbHNlbmVnJGNhdGVnb3J5ID0gYygiRk4iKQpBVl9yYW5kb21BRl90cnVlcG9zID0gZmlsdGVyKEFWX3JhbmRvbUFGLCBhZl9nb2xkZW4gIT0gMCAmIGFmX3dvcmtmbG93ICE9IDApCiAgQVZfcmFuZG9tQUZfdHJ1ZXBvcyRjYXRlZ29yeSA9IGMoIlRQIikKICAKQVZfcmFuZG9tQUYgPSByYmluZChBVl9yYW5kb21BRl90cnVlcG9zLCBBVl9yYW5kb21BRl9mYWxzZW5lZywgQVZfcmFuZG9tQUZfZmFsc2Vwb3MpCgpyRlBfQWxsID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfZmFsc2Vwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMockZQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZQIikKckZOX0FsbCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX2ZhbHNlbmVnLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKHJGTl9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJGTiIpCnJUUF9BbGwgPSBncm91cF9ieShBVl9yYW5kb21BRl90cnVlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKHJUUF9BbGwpID0gYygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiLCJUUCIpCgpyQWxsVmFyID0gbWVyZ2UockZQX0FsbCxyRk5fQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLGFsbD1UKQpyQWxsVmFyID0gbWVyZ2UockFsbFZhciwgclRQX0FsbCwgYnk9YygiYWxsZWxlX2ZyZXEiLCJjb3ZlcmFnZSIsInRvb2wiKSwgYWxsPVQpCmhlYWQockFsbFZhcikKCnJBbGxWYXJbaXMubmEockFsbFZhcildID0gMAoKckFsbFZhciRwcmVjID0gKHJBbGxWYXIkVFApLyhyQWxsVmFyJFRQICsgckFsbFZhciRGUCkKckFsbFZhciRyZWNhbGwgPSAockFsbFZhciRUUCkvKHJBbGxWYXIkVFAgKyByQWxsVmFyJEZOKQpyQWxsVmFyJGFyZWEgPSByQWxsVmFyJHByZWMgKiByQWxsVmFyJHJlY2FsbApoZWFkKHJBbGxWYXIpCmBgYApgYGB7cn0KIyBSYW5kb21BRiBEYXRhCmdncGxvdChBVl9yYW5kb21BRiwgYWVzKHggPSB0b29sLCBmaWxsID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9iYXIoKSArCiAgZmFjZXRfZ3JpZChhbGxlbGVfZnJlcX5jb3ZlcmFnZSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKIyBwbG90IGFzIHBlcmNlbnRhZ2Ugb2YgRk4gYXMgd2VsbApgYGAKCiMjU2V0QUYgLSBDb3JyZWxhdGlvbiBCZXR3ZWVuIEdvbGRlbiBhbmQgV29ya2Zsb3cKYGBge3J9CiNMb29raW5nIGF0IGFsbCBTZXRBRiBEYXRhCkFWX0NvcnJfc2V0QUYgPC0gCiAgZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbix5ID0gYWZfd29ya2Zsb3csIGNvbG9yID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKGNvdmVyYWdlfnRvb2wpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIHNpemUgPSAxLjUpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkrIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikKcHJpbnQoQVZfQ29ycl9zZXRBRikKI2dnc2F2ZShBVl9Db3JyX3NldEFGLCBmaWxlID0gIkFsbFZhclNldF9Db3JyZWxhdGlvbl9GaWx0ZXJlZC5wbmciLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IM04yX0ltYWdlcyIpCgpgYGAKCiMjUmFuZG9tQUYgLSBDb3JyZWxhdGlvbiBCZXR3ZWVuIEdvbGRlbiBhbmQgV29ya2Zsb3cKYGBge3J9CiMjTG9va2luZyBhdCBhbGwgUmFuZG9tQUYgRGF0YQogIEFWX0NvcnJfcmFuZG9tQUYgPC0gCiAgZ2dwbG90KEFWX3JhbmRvbUFGLCBhZXMoeCA9IGFmX2dvbGRlbix5ID0gYWZfd29ya2Zsb3csIGNvbG9yID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKGNvdmVyYWdlfnRvb2wpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIHNpemUgPSAxLjUpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkrIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gNikKcHJpbnQoQVZfQ29ycl9yYW5kb21BRikKI2dnc2F2ZSgiQWxsVmFyUmFuZG9tX0NvcnJlbGF0aW9uX0ZpbHRlcmVkLnBuZyIsQVZfQ29ycl9yYW5kb21BRiwKIyAgICAgICBwYXRoID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9NQUYvSDNOMl9JbWFnZXMiKQpgYGAKCgoKIyMgU3RhdHMgZm9yIFNldEFGIERhdGEKYGBge3J9CmRldGFjaChwYWNrYWdlOnBseXIsIHVubG9hZD1UUlVFKQpjb2VmZl92YXIgPC0gZnVuY3Rpb24oeCkgewogIENWIDwtIHNkKHgpIC8gbWVhbih4KSAqIDEwMAogIHJldHVybihDVikKfQoKQVZfc2V0QUZfc3BsaXQgPSBncm91cF9ieShBVl9zZXRBRl90cnVlcG9zLCB0b29sLCBhbGxlbGVfZnJlcSwgY292ZXJhZ2UpICU+JQogIHN1bW1hcml6ZShtZWFuID0gbWVhbihhZl93b3JrZmxvdyksIHNkID0gc2QoYWZfd29ya2Zsb3cpLCB2YXJpYW5jZSA9IGNvZWZmX3ZhcihhZl93b3JrZmxvdykpICU+JSBkcm9wbGV2ZWxzKCkKTWVhbl9zZXRBRiA9IGdncGxvdChBVl9zZXRBRl9zcGxpdCwgYWVzKHggPSBjb3ZlcmFnZSwgeSA9IG1lYW4sIGNvbG9yID0gYWxsZWxlX2ZyZXEpKSArIAogIGdlb21fcG9pbnQoKSArCiAgI2ZhY2V0X2dyaWQoY29scyA9IHZhcnMoYWxsZWxlX2ZyZXEpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoTWVhbl9zZXRBRikKI2dnc2F2ZSgiU2V0QUZfTWVhbl9BbGxlbGVGcmVxdWVuY3kucG5nIixNZWFuX3NldEFGLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IM04yX0ltYWdlcyIpCiN2aXN1bGl6ZSB0aGUgZWZmZWN0IG9mIGRvd25zYW1wbGluZy4gCkNvZWZmVmFyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IGNvdmVyYWdlLCB5ID0gdmFyaWFuY2UsIGNvbG9yID0gYWxsZWxlX2ZyZXEpKSArIAogIGdlb21fcG9pbnQoKSArCiAgI2ZhY2V0X2dyaWQoY29scyA9IHZhcnMoYWxsZWxlX2ZyZXEpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoQ29lZmZWYXJfc2V0QUYpCiNnZ3NhdmUoIlNldEFGX0NvZWZmVmFyX0FsbGVsZUZyZXF1ZW5jeS5wbmciLENvZWZmVmFyX3NldEFGLAojICAgICAgIHBhdGggPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL01BRi9IM04yX0ltYWdlcyIpCiN2YXJpYW5jZXMgYWJvdmUgMTAwMDAgYXJlIHNpbWxpYXIKCmBgYAojIyBTdGF0cyBmb3IgUmFuZG9tQUYgRGF0YQpgYGB7cn0KQVZfcmFuZG9tQUZfc3BsaXQgPSBncm91cF9ieShBVl9yYW5kb21BRl90cnVlcG9zLCB0b29sLCBjb3ZlcmFnZSkgJT4lCiAgc3VtbWFyaXplKG1lYW4gPSBtZWFuKGFmX3dvcmtmbG93KSwgc2QgPSBzZChhZl93b3JrZmxvdyksIHZhcmlhbmNlID0gY29lZmZfdmFyKGFmX3dvcmtmbG93KSkgJT4lIGRyb3BsZXZlbHMoKQoKTWVhbl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRl9zcGxpdCwgYWVzKHggPSBjb3ZlcmFnZSwgeSA9IG1lYW4sIGNvbG9yID0gdG9vbCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChNZWFuX3JhbmRvbUFGKQojZ2dzYXZlKCJSYW5kb21BRl9NZWFuX0FsbGVsZUZyZXF1ZW5jeS5wbmciLE1lYW5fcmFuZG9tQUYsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gzTjJfSW1hZ2VzIikKCkNvZWZmVmFyX3JhbmRvbUFGID0gZ2dwbG90KEFWX3JhbmRvbUFGX3NwbGl0LCBhZXMoeCA9IGNvdmVyYWdlLCB5ID0gdmFyaWFuY2UsIGNvbG9yID0gdG9vbCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChDb2VmZlZhcl9yYW5kb21BRikKI2dnc2F2ZSgiUmFuZG9tQUZfQ29lZmZWYXJfQWxsZWxlRnJlcXVlbmN5LnBuZyIsQ29lZmZWYXJfcmFuZG9tQUYsCiMgICAgICAgcGF0aCA9ICIvVXNlcnMvbWFyaXNzYWtub2xsL0Rlc2t0b3AvTUFGL0gzTjJfSW1hZ2VzIikKYGBgCgpgYGB7cn0KZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGxvZzEwKGRwKSwgeSA9IGFmX3dvcmtmbG93LCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGNvdmVyYWdlKSwgY29scyA9IHZhcnMoYWxsZWxlX2ZyZXEpKSArCiAgeGxpbSgwLDYpCgojIGRvIHRoaXMgd2l0aCBhbGwgYmFtZmlsZXMsIG5vdCBqdXN0IHZhcmlhbnRzCmdncGxvdChBVl9zZXRBRiwgYWVzKHggPSBsb2cxMChkcCksIGZpbGwgPSB0b29sKSkgKwogIGdlb21faGlzdG9ncmFtKCkrCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhjb3ZlcmFnZSksIGNvbHMgPSB2YXJzKGFsbGVsZV9mcmVxKSkKCmBgYAo=