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")
# 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 59262 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] 97 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 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 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 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

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

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

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

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