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 For viral variant callers!

Loading Libraries

library('ggplot2')
library('tidyverse')
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
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
v purrr   0.3.3     
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library('plyr')
------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
------------------------------------------------------------------------------

Attaching package: 'plyr'
The following objects are masked from 'package:dplyr':

    arrange, count, desc, failwith, id, mutate, rename, summarise,
    summarize
The following object is masked from 'package:purrr':

    compact
library('ggpubr')

Attaching package: 'ggpubr'
The following object is masked from 'package:plyr':

    mutate
library("MLmetrics")

Attaching package: 'MLmetrics'
The following object is masked from 'package:base':

    Recall
MyColors = c("#E76F51", "#E9C369", "#2A9D8F","#2B4FA2", "#119DAC", "#672D7B", "#262366", "#BCBCBC")
ggplot2::theme_set(theme_minimal())
detach(package:plyr, unload=TRUE)
library("plotrix") 

Making Transition/Transversion Function

TsTv = function(dataframe) {
  transitions = 0
  for (row in 1:nrow(dataframe)) {
  
   REF <- dataframe[row, "ref"] #requires dataframe to have column name "ref"
   ALT <- dataframe[row, "alt"] # requires dataframe to have column name "alt"

    if(REF == "A" & ALT == "G")
      transitions = transitions + 1
    if(REF == "G" & ALT == "A")
      transitions = transitions + 1
    if(REF == "C" & ALT == "T")
      transitions = transitions + 1
    if(REF == "T" & ALT == "C")
      transitions = transitions + 1
  }

  transversions = 0
  for (row in 1:nrow(dataframe)) {
  
    REF <- dataframe[row, "ref"]
    ALT <- dataframe[row, "alt"]
  
    if(REF == "A" & ALT == "T")
      transversions = transversions + 1
    if(REF == "T" & ALT == "A")
      transversions = transversions + 1
    if(REF == "C" & ALT == "A")
      transversions = transversions + 1
    if(REF == "A" & ALT == "C")
      transversions = transversions + 1
    if(REF == "G" & ALT == "T")
      transversions = transversions + 1
    if(REF == "T" & ALT == "G")
      transversions = transversions + 1
    if(REF == "C" & ALT == "G")
      transversions = transversions + 1
    if(REF == "G" & ALT == "C")
      transversions = transversions + 1
  }

  TsTv_df = data.frame(transitions,transversions)
  print(TsTv_df)
  TsTv_ratio = (transitions/transversions)
  print(TsTv_ratio)
  
}

Reading in Variant Data and Evaluating

AV = read.csv(af_report,header = T)
AV$sample_id = as.character(AV$sample_id)
AV$dp = as.numeric(AV$dp)
AV = separate(AV, sample_id, sep = "_", 
               into = c(NA,NA,"allele_freq",NA,"seq_depth","tool","parameter"))%>% 
  filter(ref == "A" | ref == "C" | ref == "T" | ref == "G") %>% 
  filter(alt == "A" | alt == "C" | alt == "T" | alt == "G") %>% droplevels()
Warning: Expected 7 pieces. Additional pieces discarded in 1845 rows [247, 248,
249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, ...].
Warning: Expected 7 pieces. Missing pieces filled with `NA` in 8763 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 * 100000)

AV$parameter = NULL
head(AV)
Dp_Variation = ggplot(AV, aes(x = log10(coverage), y = log10(dp), color = tool)) +
  geom_point() + 
  facet_wrap(~tool, scales = "free_y") +
  scale_color_manual(values = MyColors)
Warning: namespace 'plyr' is not available and has been replaced
by .GlobalEnv when processing object ''
print(Dp_Variation)
Warning: Removed 1704 rows containing missing values (geom_point).

ggsave(Dp_Variation, file = "AV_Dp_Coverage.png")
Saving 7 x 5 in image
Warning: Removed 1704 rows containing missing values (geom_point).

Reading in Golden Data and Evaluating

viral_golden = read.table(golden_vcf, stringsAsFactors = F)
colnames(viral_golden) = c("chrom","pos","ID","ref","alt","qual","filter","info","codes","genotype")
viral_golden = separate(viral_golden, info, sep = "=", into = c("label","AF"))
viral_golden$label = NULL
head(viral_golden)
dim(viral_golden)
[1] 123  10
viral_golden_pos = ggplot(viral_golden, aes(x = pos, y = ref, color = alt)) +
  geom_point()
print(viral_golden_pos)

TsTv(viral_golden)
  transitions transversions
1         101            22
[1] 4.590909

SetAF - Separating Data into TP, FP, FN

AV_setAF = filter(AV, allele_freq != "random") %>% droplevels()

AV_setAF_falsepos = filter(AV_setAF, af_golden == 0 & af_workflow != 0) %>% droplevels()
  AV_setAF_falsepos$category = c("FP")
AV_setAF_falseneg = filter(AV_setAF, af_workflow == 0 & af_golden != 0) %>% droplevels()
  AV_setAF_falseneg$category = c("FN")
AV_setAF_truepos = filter(AV_setAF, af_golden != 0 & af_workflow != 0)
  AV_setAF_truepos$category = c("TP")
  
AV_setAF = rbind(AV_setAF_truepos, AV_setAF_falseneg, AV_setAF_falsepos)

FP_All = group_by(AV_setAF_falsepos, allele_freq,coverage,tool) %>% tally()
  colnames(FP_All) = c("allele_freq","coverage","tool","FP")
FN_All = group_by(AV_setAF_falseneg, allele_freq,coverage,tool) %>% tally()
  colnames(FN_All) = c("allele_freq","coverage","tool","FN")
TP_All = group_by(AV_setAF_truepos, allele_freq,coverage,tool) %>% tally()
  colnames(TP_All) = c("allele_freq","coverage","tool","TP")
    
AllVar = merge(FP_All,FN_All, by=c("allele_freq","coverage","tool"),all=T)
AllVar = merge(AllVar,TP_All, by=c("allele_freq","coverage","tool"), all=T)
head(AllVar)
AllVar[is.na(AllVar)] = 0
head(AllVar)
AllVar$prec = (AllVar$TP)/(AllVar$TP + AllVar$FP)
AllVar$recall = (AllVar$TP)/(AllVar$TP + AllVar$FN)
AllVar$area = AllVar$prec * AllVar$recall
head(AllVar)

RandomAF - Separating Data into TP, FP, FN

AV_randomAF = filter(AV, allele_freq == "random") %>% droplevels()

AV_randomAF_falsepos = filter(AV_randomAF, af_golden == 0 & af_workflow != 0) %>% droplevels()
  AV_randomAF_falsepos$category = c("FP")
AV_randomAF_falseneg = filter(AV_randomAF, af_workflow == 0 & af_golden != 0) %>% droplevels()
  AV_randomAF_falseneg$category = c("FN")
AV_randomAF_truepos = filter(AV_randomAF, af_golden != 0 & af_workflow != 0)
  AV_randomAF_truepos$category = c("TP")
  
AV_randomAF = rbind(AV_randomAF_truepos, AV_randomAF_falseneg, AV_randomAF_falsepos)

rFP_All = group_by(AV_randomAF_falsepos, allele_freq,coverage,tool) %>% tally()
  colnames(rFP_All) = c("allele_freq","coverage","tool","FP")
rFN_All = group_by(AV_randomAF_falseneg, allele_freq,coverage,tool) %>% tally()
  colnames(rFN_All) = c("allele_freq","coverage","tool","FN")
rTP_All = group_by(AV_randomAF_truepos, allele_freq,coverage,tool) %>% tally()
  colnames(rTP_All) = c("allele_freq","coverage","tool","TP")

rAllVar = merge(rFP_All,rFN_All, by=c("allele_freq","coverage","tool"),all=T)
rAllVar = merge(rAllVar, rTP_All, by=c("allele_freq","coverage","tool"), all=T)
head(rAllVar)
rAllVar[is.na(rAllVar)] = 0

rAllVar$prec = (rAllVar$TP)/(rAllVar$TP + rAllVar$FP)
rAllVar$recall = (rAllVar$TP)/(rAllVar$TP + rAllVar$FN)
rAllVar$area = rAllVar$prec * rAllVar$recall
head(rAllVar)

1. Precision_Recall Curves

PR_AllVarSet_freq = ggplot(AllVar,aes(x=recall, y=prec, group = tool, color = tool)) +
  geom_point() + 
  geom_line() +
  facet_wrap(~allele_freq) +
  scale_color_manual(values = MyColors)
print(PR_AllVarSet_freq)
Warning: Removed 21 rows containing missing values (geom_point).
Warning: Removed 21 row(s) containing missing values (geom_path).

ggsave("PR_AllVarSet_byAF.png",PR_AllVarSet_freq)
Saving 7 x 5 in image
Warning: Removed 21 rows containing missing values (geom_point).

Warning: Removed 21 row(s) containing missing values (geom_path).
PR_AllVarSet_cover = ggplot(AllVar,aes(x=recall, y=prec, group = tool, color=tool)) +
  geom_point() + 
  geom_line() +
  facet_wrap(~coverage) +
  scale_color_manual(values = MyColors)
print(PR_AllVarSet_cover)
Warning: Removed 21 rows containing missing values (geom_point).
Warning: Removed 7 row(s) containing missing values (geom_path).

ggsave("PR_AllVarSet_byCov.png",PR_AllVarSet_cover)
Saving 7 x 5 in image
Warning: Removed 21 rows containing missing values (geom_point).

Warning: Removed 7 row(s) containing missing values (geom_path).
PR_AllVarRandom = ggplot(rAllVar,aes(x=recall, y=prec, group = tool, color=tool)) +
  geom_point() + 
  geom_line() +
  scale_color_manual(values = MyColors)
print(PR_AllVarRandom)

ggsave("PR_AllVarRandom.png",PR_AllVarRandom)
Saving 7 x 5 in image
# Examining Data

AllVar_PR_zeros = filter(AllVar, prec == 0 & recall == 0)
AllVar_PR_high = filter(AllVar, prec > 0.9 & recall > 0.9)

AllVar_PR_highest = group_by(AllVar, tool, allele_freq, coverage) %>%
  arrange(area, decreasing = TRUE)
write.csv(AllVar_PR_highest, file = "AllVar_PR_Thresholds.csv")

2.1 SetAF - Proportion of Variants Found

AV_setAF_counts = group_by(AV_setAF_truepos, tool, allele_freq, coverage) %>% tally()
AV_setAF_counts$proportion = (AV_setAF_counts$n / nrow(viral_golden))

AV_setAF_proportion = ggplot(AV_setAF_counts,aes(x = log10(coverage), y = proportion,
                                                group = tool, color = tool)) +
  geom_point() +
  geom_line() +
  facet_grid(~allele_freq) +
  scale_color_manual(values = MyColors)
print(AV_setAF_proportion)

ggsave("AllVarSet_Proportion.png", AV_setAF_proportion)
Saving 7 x 5 in image

2.2 RandomAF - Proportion of Variants Found

AV_randomAF_counts = group_by(AV_randomAF_truepos, tool, allele_freq, coverage) %>% tally()
AV_randomAF_counts$proportion = (AV_randomAF_counts$n / nrow(viral_golden))

AV_randomAF_proportion = ggplot(AV_randomAF_counts, aes(x = log10(coverage), y = proportion, 
                                                        group = tool, color = tool)) +
  geom_point() +
  geom_line() +
  scale_color_manual(values = MyColors)
print(AV_randomAF_proportion)

ggsave("AllVarRandom_Proportion.png", AV_randomAF_proportion)
Saving 7 x 5 in image
## Only looking at coverage between 100-1000
AV_randomAF_truepos_f = filter(AV_randomAF_truepos, coverage > 99 & coverage < 1001)
AV_randomAF_counts_f = group_by(AV_randomAF_truepos_f, tool, allele_freq, coverage) %>% tally()
AV_randomAF_counts_f$proportion = (AV_randomAF_counts_f$n / nrow(viral_golden))
 
AV_randomAF_proportion_f = ggplot(AV_randomAF_counts_f, aes(x = log10(coverage), y = proportion, 
                                                             group = tool, color = tool)) +
  geom_point() +
  geom_line() +
  scale_color_manual(values = MyColors)
print(AV_randomAF_proportion_f)
geom_path: Each group consists of only one observation. Do you need to adjust
the group aesthetic?

ggsave("AllVarRandom_Proportion_Filtered.png", AV_randomAF_proportion_f)
Saving 7 x 5 in image
geom_path: Each group consists of only one observation. Do you need to adjust
the group aesthetic?

3.1 SetAF - Correlation Between Golden and Workflow

## Only looking at true positives
AV_Corr_setAF = ggplot(AV_setAF, aes(x = af_golden, y = af_workflow,
                                                color = tool, shape = category)) +
  geom_point() +
  scale_color_manual(values = MyColors) +
  geom_boxplot(aes(group = allele_freq)) + 
  facet_grid(tool~coverage) +
  ylim(-0.001,1.0) + xlim(-0.001,1.0)
print(AV_Corr_setAF)
Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

ggsave("AllVarSet_Correlation.png",AV_Corr_setAF)
Saving 7 x 5 in image
Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

Warning: Removed 1 rows containing missing values (geom_segment).

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

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

ggsave("AllVarSet_CorrelationF_Filtered_Zoom.png", AV_Corr_setAF_Zoom)
Saving 7 x 5 in image
Warning: Removed 2984 rows containing missing values (geom_point).

3.2 RandomAF - Correlation Between Golden and Workflow

## Only looking at true positives
AV_Corr_randomAF = ggplot(AV_randomAF, aes(x = af_golden, y = af_workflow,
                                                      color = tool, shape = category)) +
  geom_point() +
  scale_color_manual(values = MyColors) +
  facet_grid(tool~coverage) +
  ylim(-0.001,1.0) + xlim(-0.001,1.0)
print(AV_Corr_randomAF)

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

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

ggsave("AllVarRandom_Correlation_Filtered_Zoom.png", AV_Corr_randomAF_Zoom)
Saving 7 x 5 in image
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 2462 rows containing non-finite values (stat_smooth).

Warning: Removed 2462 rows containing missing values (geom_point).

Stats for SetAF Data

coeff_var <- function(x) {
  CV <- sd(x) / mean(x) * 100
  return(CV)
}

AV_setAF_split = group_by(AV_setAF_truepos, tool, allele_freq, coverage) %>%
  summarize(mean(af_workflow), sd(af_workflow), coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool', 'allele_freq' (override with `.groups` argument)
colnames(AV_setAF_split) = c("tool","AF","cov","mean","sd","variance")

Mean_setAF = ggplot(AV_setAF_split, aes(x = tool, y = mean, color = cov)) + 
  geom_point() +
  facet_grid(rows = vars(tool), cols = vars(AF)) +
  theme(text = element_text(size = 15),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
print(Mean_setAF)

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

ggsave("SetAF_CoeffVar_AlleleFrequency.png",CoeffVar_setAF)
Saving 7 x 5 in image

Set Up for Stats for RandomAF Data

AV_randomAF_split = group_by(AV_randomAF_truepos, tool, coverage) %>%
  summarize(mean(af_workflow), sd(af_workflow), coeff_var(af_workflow)) %>% droplevels()
`summarise()` regrouping output by 'tool' (override with `.groups` argument)
colnames(AV_randomAF_split) = c("tool","cov","mean","sd","variance")

Mean_randomAF = ggplot(AV_randomAF_split, aes(x = tool, y = mean, color = cov)) + 
  geom_point()
  theme(text = element_text(size = 15),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
List of 2
 $ text       :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : num 15
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : num 0.5
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE
print(Mean_randomAF)

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

ggsave("RandomAF_CoeffVar_AlleleFrequency.png",CoeffVar_randomAF)
Saving 7 x 5 in image

4. Look at how each tool compares at each AF and seq-depth

AVSet_Corr = ggplot(AV_setAF_truepos, aes(x = tool, y = af_workflow)) + 
  geom_point() +
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  facet_grid(allele_freq~coverage, scales = "free_y")
print(AVSet_Corr)

ggsave("AllVarSet_Tool_Comparison.pdf", AVSet_Corr, width = 15, height = 20)
# y axes are set per row at the moment (scales = "free_y")

AVRandom_Corr = ggplot(AV_randomAF_truepos, aes(x = tool, y = af_workflow)) + 
  geom_point() +
  geom_violin() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  facet_grid(allele_freq~coverage)
print(AVRandom_Corr)

ggsave("AllVarRandom_Tool_Comparison.pdf", AVRandom_Corr, width = 15, height = 20)

5.1. Looks at where the SNPS are located throughout the genome

# Set AF Data
AV_Pos = ggplot(AV_setAF_truepos, aes(x = pos, y = af_workflow)) +
  geom_point()
print(AV_Pos)

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

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

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

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

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

5.2.Transitions/Transversions

setAF_TP_pos = ggplot(AV_setAF_truepos, aes(x = pos, y = ref, color = tool, shape = alt)) +
  geom_point()
print(setAF_TP_pos)

TsTv(AV_setAF_truepos)
  transitions transversions
1        5629          1214
[1] 4.636738
#counts variants from all tools/seq_depth/AF trials

randomAF_TP_pos = ggplot(AV_randomAF_truepos, aes(x = pos, y = ref, color = tool, shape = alt)) +
  geom_point()
print(randomAF_TP_pos)

TsTv(AV_randomAF_truepos)
  transitions transversions
1        1855           400
[1] 4.6375
LS0tCnRpdGxlOiAiVmFyaWFudHNfQWxsQ2FsbGVycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyNUaGlzIG5vdGVib29rIHRha2VzIHRoZSBvdXRwdXQgZm9yIHRoZSBNQUYgUGlwZWxpbmUgKG15Y3N2ZmlsZS5jc3YpIGFuZCBkb2VzOgoxLiBDYWxjdWxhdGVzIHRydWUgcG9zLCBmYWxzZSBwb3MsIGFuZCBmYWxzZSBuZWcgYW5kIG1ha2VzIGEgcHJlY2lzaW9uIHJlY2FsbCBjdXJ2ZSBmb3IgYWxsIHRvb2xzCjIuIEZpbmRzIHRvdGFsIG51bWJlcnMgb2YgdmFyaWFudHMgZm91bmQgYnkgdG9vbHMgYXQgZGlmZmVyZW50IGFsbGVsZSBmcmVxdWVuY2llcyBhbmQgc2VxdWVuY2luZyBkZXB0aHMKMy4gTG9va3MgYXQgY29ycmVsYXRpb24gYmV0d2VlbiBTTlBTIGluIHRoZSBnb2xkZW4gdmNmIGFuZCB3b3JmbG93IHZjZgpGb3IgdmlyYWwgdmFyaWFudCBjYWxsZXJzIQoKCiMjTG9hZGluZyBMaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoJ2dncGxvdDInKQpsaWJyYXJ5KCd0aWR5dmVyc2UnKQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgiTUxtZXRyaWNzIikKCk15Q29sb3JzID0gYygiI0U3NkY1MSIsICIjRTlDMzY5IiwgIiMyQTlEOEYiLCIjMkI0RkEyIiwgIiMxMTlEQUMiLCAiIzY3MkQ3QiIsICIjMjYyMzY2IiwgIiNCQ0JDQkMiKQpnZ3Bsb3QyOjp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQoKYGBgCgpgYGB7cn0KZGV0YWNoKHBhY2thZ2U6cGx5ciwgdW5sb2FkPVRSVUUpCmxpYnJhcnkoInBsb3RyaXgiKSAKYGBgCgojI01ha2luZyBUcmFuc2l0aW9uL1RyYW5zdmVyc2lvbiBGdW5jdGlvbgpgYGB7cn0KVHNUdiA9IGZ1bmN0aW9uKGRhdGFmcmFtZSkgewogIHRyYW5zaXRpb25zID0gMAogIGZvciAocm93IGluIDE6bnJvdyhkYXRhZnJhbWUpKSB7CiAgCiAgIFJFRiA8LSBkYXRhZnJhbWVbcm93LCAicmVmIl0gI3JlcXVpcmVzIGRhdGFmcmFtZSB0byBoYXZlIGNvbHVtbiBuYW1lICJyZWYiCiAgIEFMVCA8LSBkYXRhZnJhbWVbcm93LCAiYWx0Il0gIyByZXF1aXJlcyBkYXRhZnJhbWUgdG8gaGF2ZSBjb2x1bW4gbmFtZSAiYWx0IgoKICAgIGlmKFJFRiA9PSAiQSIgJiBBTFQgPT0gIkciKQogICAgICB0cmFuc2l0aW9ucyA9IHRyYW5zaXRpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zaXRpb25zID0gdHJhbnNpdGlvbnMgKyAxCiAgICBpZihSRUYgPT0gIkMiICYgQUxUID09ICJUIikKICAgICAgdHJhbnNpdGlvbnMgPSB0cmFuc2l0aW9ucyArIDEKICAgIGlmKFJFRiA9PSAiVCIgJiBBTFQgPT0gIkMiKQogICAgICB0cmFuc2l0aW9ucyA9IHRyYW5zaXRpb25zICsgMQogIH0KCiAgdHJhbnN2ZXJzaW9ucyA9IDAKICBmb3IgKHJvdyBpbiAxOm5yb3coZGF0YWZyYW1lKSkgewogIAogICAgUkVGIDwtIGRhdGFmcmFtZVtyb3csICJyZWYiXQogICAgQUxUIDwtIGRhdGFmcmFtZVtyb3csICJhbHQiXQogIAogICAgaWYoUkVGID09ICJBIiAmIEFMVCA9PSAiVCIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJUIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJDIiAmIEFMVCA9PSAiQSIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJBIiAmIEFMVCA9PSAiQyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiVCIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJUIiAmIEFMVCA9PSAiRyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJDIiAmIEFMVCA9PSAiRyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogICAgaWYoUkVGID09ICJHIiAmIEFMVCA9PSAiQyIpCiAgICAgIHRyYW5zdmVyc2lvbnMgPSB0cmFuc3ZlcnNpb25zICsgMQogIH0KCiAgVHNUdl9kZiA9IGRhdGEuZnJhbWUodHJhbnNpdGlvbnMsdHJhbnN2ZXJzaW9ucykKICBwcmludChUc1R2X2RmKQogIFRzVHZfcmF0aW8gPSAodHJhbnNpdGlvbnMvdHJhbnN2ZXJzaW9ucykKICBwcmludChUc1R2X3JhdGlvKQogIAp9CmBgYAoKIyNSZWFkaW5nIGluIFZhcmlhbnQgRGF0YSBhbmQgRXZhbHVhdGluZwpgYGB7cn0KQVYgPSByZWFkLmNzdihhZl9yZXBvcnQsaGVhZGVyID0gVCkKQVYkc2FtcGxlX2lkID0gYXMuY2hhcmFjdGVyKEFWJHNhbXBsZV9pZCkKQVYkZHAgPSBhcy5udW1lcmljKEFWJGRwKQpBViA9IHNlcGFyYXRlKEFWLCBzYW1wbGVfaWQsIHNlcCA9ICJfIiwgCiAgICAgICAgICAgICAgIGludG8gPSBjKE5BLE5BLCJhbGxlbGVfZnJlcSIsTkEsInNlcV9kZXB0aCIsInRvb2wiLCJwYXJhbWV0ZXIiKSklPiUgCiAgZmlsdGVyKHJlZiA9PSAiQSIgfCByZWYgPT0gIkMiIHwgcmVmID09ICJUIiB8IHJlZiA9PSAiRyIpICU+JSAKICBmaWx0ZXIoYWx0ID09ICJBIiB8IGFsdCA9PSAiQyIgfCBhbHQgPT0gIlQiIHwgYWx0ID09ICJHIikgJT4lIGRyb3BsZXZlbHMoKQpBViRzZXFfZGVwdGggPSBhcy5udW1lcmljKEFWJHNlcV9kZXB0aCkKQVYkY292ZXJhZ2UgPSAoQVYkc2VxX2RlcHRoICogMTAwMDAwKQoKQVYkcGFyYW1ldGVyID0gTlVMTApoZWFkKEFWKQoKRHBfVmFyaWF0aW9uID0gZ2dwbG90KEFWLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IGxvZzEwKGRwKSwgY29sb3IgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X3dyYXAofnRvb2wsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChEcF9WYXJpYXRpb24pCmdnc2F2ZShEcF9WYXJpYXRpb24sIGZpbGUgPSAiQVZfRHBfQ292ZXJhZ2UucG5nIikKYGBgCgojI1JlYWRpbmcgaW4gR29sZGVuIERhdGEgYW5kIEV2YWx1YXRpbmcKYGBge3J9CnZpcmFsX2dvbGRlbiA9IHJlYWQudGFibGUoZ29sZGVuX3ZjZiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKHZpcmFsX2dvbGRlbikgPSBjKCJjaHJvbSIsInBvcyIsIklEIiwicmVmIiwiYWx0IiwicXVhbCIsImZpbHRlciIsImluZm8iLCJjb2RlcyIsImdlbm90eXBlIikKdmlyYWxfZ29sZGVuID0gc2VwYXJhdGUodmlyYWxfZ29sZGVuLCBpbmZvLCBzZXAgPSAiPSIsIGludG8gPSBjKCJsYWJlbCIsIkFGIikpCnZpcmFsX2dvbGRlbiRsYWJlbCA9IE5VTEwKaGVhZCh2aXJhbF9nb2xkZW4pCmRpbSh2aXJhbF9nb2xkZW4pCgp2aXJhbF9nb2xkZW5fcG9zID0gZ2dwbG90KHZpcmFsX2dvbGRlbiwgYWVzKHggPSBwb3MsIHkgPSByZWYsIGNvbG9yID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludCh2aXJhbF9nb2xkZW5fcG9zKQoKVHNUdih2aXJhbF9nb2xkZW4pCmBgYAoKIyNTZXRBRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3NldEFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSAhPSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfc2V0QUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3NldEFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9zZXRBRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9zZXRBRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfc2V0QUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3NldEFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfc2V0QUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9zZXRBRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9zZXRBRiA9IHJiaW5kKEFWX3NldEFGX3RydWVwb3MsIEFWX3NldEFGX2ZhbHNlbmVnLCBBVl9zZXRBRl9mYWxzZXBvcykKCkZQX0FsbCA9IGdyb3VwX2J5KEFWX3NldEFGX2ZhbHNlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKEZQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZQIikKRk5fQWxsID0gZ3JvdXBfYnkoQVZfc2V0QUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoRk5fQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRk4iKQpUUF9BbGwgPSBncm91cF9ieShBVl9zZXRBRl90cnVlcG9zLCBhbGxlbGVfZnJlcSxjb3ZlcmFnZSx0b29sKSAlPiUgdGFsbHkoKQogIGNvbG5hbWVzKFRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKICAgIApBbGxWYXIgPSBtZXJnZShGUF9BbGwsRk5fQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLGFsbD1UKQpBbGxWYXIgPSBtZXJnZShBbGxWYXIsVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChBbGxWYXIpCgpBbGxWYXJbaXMubmEoQWxsVmFyKV0gPSAwCmhlYWQoQWxsVmFyKQoKQWxsVmFyJHByZWMgPSAoQWxsVmFyJFRQKS8oQWxsVmFyJFRQICsgQWxsVmFyJEZQKQpBbGxWYXIkcmVjYWxsID0gKEFsbFZhciRUUCkvKEFsbFZhciRUUCArIEFsbFZhciRGTikKQWxsVmFyJGFyZWEgPSBBbGxWYXIkcHJlYyAqIEFsbFZhciRyZWNhbGwKaGVhZChBbGxWYXIpCmBgYAoKIyNSYW5kb21BRiAtIFNlcGFyYXRpbmcgRGF0YSBpbnRvIFRQLCBGUCwgRk4KYGBge3J9CkFWX3JhbmRvbUFGID0gZmlsdGVyKEFWLCBhbGxlbGVfZnJlcSA9PSAicmFuZG9tIikgJT4lIGRyb3BsZXZlbHMoKQoKQVZfcmFuZG9tQUZfZmFsc2Vwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiA9PSAwICYgYWZfd29ya2Zsb3cgIT0gMCkgJT4lIGRyb3BsZXZlbHMoKQogIEFWX3JhbmRvbUFGX2ZhbHNlcG9zJGNhdGVnb3J5ID0gYygiRlAiKQpBVl9yYW5kb21BRl9mYWxzZW5lZyA9IGZpbHRlcihBVl9yYW5kb21BRiwgYWZfd29ya2Zsb3cgPT0gMCAmIGFmX2dvbGRlbiAhPSAwKSAlPiUgZHJvcGxldmVscygpCiAgQVZfcmFuZG9tQUZfZmFsc2VuZWckY2F0ZWdvcnkgPSBjKCJGTiIpCkFWX3JhbmRvbUFGX3RydWVwb3MgPSBmaWx0ZXIoQVZfcmFuZG9tQUYsIGFmX2dvbGRlbiAhPSAwICYgYWZfd29ya2Zsb3cgIT0gMCkKICBBVl9yYW5kb21BRl90cnVlcG9zJGNhdGVnb3J5ID0gYygiVFAiKQogIApBVl9yYW5kb21BRiA9IHJiaW5kKEFWX3JhbmRvbUFGX3RydWVwb3MsIEFWX3JhbmRvbUFGX2ZhbHNlbmVnLCBBVl9yYW5kb21BRl9mYWxzZXBvcykKCnJGUF9BbGwgPSBncm91cF9ieShBVl9yYW5kb21BRl9mYWxzZXBvcywgYWxsZWxlX2ZyZXEsY292ZXJhZ2UsdG9vbCkgJT4lIHRhbGx5KCkKICBjb2xuYW1lcyhyRlBfQWxsKSA9IGMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiwiRlAiKQpyRk5fQWxsID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfZmFsc2VuZWcsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMockZOX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIkZOIikKclRQX0FsbCA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3MsIGFsbGVsZV9mcmVxLGNvdmVyYWdlLHRvb2wpICU+JSB0YWxseSgpCiAgY29sbmFtZXMoclRQX0FsbCkgPSBjKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIsIlRQIikKCnJBbGxWYXIgPSBtZXJnZShyRlBfQWxsLHJGTl9BbGwsIGJ5PWMoImFsbGVsZV9mcmVxIiwiY292ZXJhZ2UiLCJ0b29sIiksYWxsPVQpCnJBbGxWYXIgPSBtZXJnZShyQWxsVmFyLCByVFBfQWxsLCBieT1jKCJhbGxlbGVfZnJlcSIsImNvdmVyYWdlIiwidG9vbCIpLCBhbGw9VCkKaGVhZChyQWxsVmFyKQoKckFsbFZhcltpcy5uYShyQWxsVmFyKV0gPSAwCgpyQWxsVmFyJHByZWMgPSAockFsbFZhciRUUCkvKHJBbGxWYXIkVFAgKyByQWxsVmFyJEZQKQpyQWxsVmFyJHJlY2FsbCA9IChyQWxsVmFyJFRQKS8ockFsbFZhciRUUCArIHJBbGxWYXIkRk4pCnJBbGxWYXIkYXJlYSA9IHJBbGxWYXIkcHJlYyAqIHJBbGxWYXIkcmVjYWxsCmhlYWQockFsbFZhcikKYGBgCgojMS4gUHJlY2lzaW9uX1JlY2FsbCBDdXJ2ZXMKYGBge3J9ClBSX0FsbFZhclNldF9mcmVxID0gZ2dwbG90KEFsbFZhcixhZXMoeD1yZWNhbGwsIHk9cHJlYywgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmFsbGVsZV9mcmVxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChQUl9BbGxWYXJTZXRfZnJlcSkKZ2dzYXZlKCJQUl9BbGxWYXJTZXRfYnlBRi5wbmciLFBSX0FsbFZhclNldF9mcmVxKQoKUFJfQWxsVmFyU2V0X2NvdmVyID0gZ2dwbG90KEFsbFZhcixhZXMoeD1yZWNhbGwsIHk9cHJlYywgZ3JvdXAgPSB0b29sLCBjb2xvcj10b29sKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5jb3ZlcmFnZSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoUFJfQWxsVmFyU2V0X2NvdmVyKQpnZ3NhdmUoIlBSX0FsbFZhclNldF9ieUNvdi5wbmciLFBSX0FsbFZhclNldF9jb3ZlcikKClBSX0FsbFZhclJhbmRvbSA9IGdncGxvdChyQWxsVmFyLGFlcyh4PXJlY2FsbCwgeT1wcmVjLCBncm91cCA9IHRvb2wsIGNvbG9yPXRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoUFJfQWxsVmFyUmFuZG9tKQpnZ3NhdmUoIlBSX0FsbFZhclJhbmRvbS5wbmciLFBSX0FsbFZhclJhbmRvbSkKCiMgRXhhbWluaW5nIERhdGEKCkFsbFZhcl9QUl96ZXJvcyA9IGZpbHRlcihBbGxWYXIsIHByZWMgPT0gMCAmIHJlY2FsbCA9PSAwKQpBbGxWYXJfUFJfaGlnaCA9IGZpbHRlcihBbGxWYXIsIHByZWMgPiAwLjkgJiByZWNhbGwgPiAwLjkpCgpBbGxWYXJfUFJfaGlnaGVzdCA9IGdyb3VwX2J5KEFsbFZhciwgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUKICBhcnJhbmdlKGFyZWEsIGRlY3JlYXNpbmcgPSBUUlVFKQp3cml0ZS5jc3YoQWxsVmFyX1BSX2hpZ2hlc3QsIGZpbGUgPSAiQWxsVmFyX1BSX1RocmVzaG9sZHMuY3N2IikKYGBgCgojMi4xIFNldEFGIC0gUHJvcG9ydGlvbiBvZiBWYXJpYW50cyBGb3VuZApgYGB7cn0KQVZfc2V0QUZfY291bnRzID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9zZXRBRl9jb3VudHMkcHJvcG9ydGlvbiA9IChBVl9zZXRBRl9jb3VudHMkbiAvIG5yb3codmlyYWxfZ29sZGVuKSkKCkFWX3NldEFGX3Byb3BvcnRpb24gPSBnZ3Bsb3QoQVZfc2V0QUZfY291bnRzLGFlcyh4ID0gbG9nMTAoY292ZXJhZ2UpLCB5ID0gcHJvcG9ydGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfZ3JpZCh+YWxsZWxlX2ZyZXEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpCnByaW50KEFWX3NldEFGX3Byb3BvcnRpb24pCmdnc2F2ZSgiQWxsVmFyU2V0X1Byb3BvcnRpb24ucG5nIiwgQVZfc2V0QUZfcHJvcG9ydGlvbikKYGBgCgojMi4yIFJhbmRvbUFGIC0gUHJvcG9ydGlvbiBvZiBWYXJpYW50cyBGb3VuZApgYGB7cn0KQVZfcmFuZG9tQUZfY291bnRzID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9yYW5kb21BRl9jb3VudHMkcHJvcG9ydGlvbiA9IChBVl9yYW5kb21BRl9jb3VudHMkbiAvIG5yb3codmlyYWxfZ29sZGVuKSkKCkFWX3JhbmRvbUFGX3Byb3BvcnRpb24gPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfY291bnRzLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IHByb3BvcnRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gdG9vbCwgY29sb3IgPSB0b29sKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykKcHJpbnQoQVZfcmFuZG9tQUZfcHJvcG9ydGlvbikKZ2dzYXZlKCJBbGxWYXJSYW5kb21fUHJvcG9ydGlvbi5wbmciLCBBVl9yYW5kb21BRl9wcm9wb3J0aW9uKQogCiMjIE9ubHkgbG9va2luZyBhdCBjb3ZlcmFnZSBiZXR3ZWVuIDEwMC0xMDAwCkFWX3JhbmRvbUFGX3RydWVwb3NfZiA9IGZpbHRlcihBVl9yYW5kb21BRl90cnVlcG9zLCBjb3ZlcmFnZSA+IDk5ICYgY292ZXJhZ2UgPCAxMDAxKQpBVl9yYW5kb21BRl9jb3VudHNfZiA9IGdyb3VwX2J5KEFWX3JhbmRvbUFGX3RydWVwb3NfZiwgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUgdGFsbHkoKQpBVl9yYW5kb21BRl9jb3VudHNfZiRwcm9wb3J0aW9uID0gKEFWX3JhbmRvbUFGX2NvdW50c19mJG4gLyBucm93KHZpcmFsX2dvbGRlbikpCiAKQVZfcmFuZG9tQUZfcHJvcG9ydGlvbl9mID0gZ2dwbG90KEFWX3JhbmRvbUFGX2NvdW50c19mLCBhZXMoeCA9IGxvZzEwKGNvdmVyYWdlKSwgeSA9IHByb3BvcnRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB0b29sLCBjb2xvciA9IHRvb2wpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKQpwcmludChBVl9yYW5kb21BRl9wcm9wb3J0aW9uX2YpCmdnc2F2ZSgiQWxsVmFyUmFuZG9tX1Byb3BvcnRpb25fRmlsdGVyZWQucG5nIiwgQVZfcmFuZG9tQUZfcHJvcG9ydGlvbl9mKQpgYGAKCiMzLjEgU2V0QUYgLSBDb3JyZWxhdGlvbiBCZXR3ZWVuIEdvbGRlbiBhbmQgV29ya2Zsb3cKYGBge3J9CiMjIE9ubHkgbG9va2luZyBhdCB0cnVlIHBvc2l0aXZlcwpBVl9Db3JyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBnZW9tX2JveHBsb3QoYWVzKGdyb3VwID0gYWxsZWxlX2ZyZXEpKSArIAogIGZhY2V0X2dyaWQodG9vbH5jb3ZlcmFnZSkgKwogIHlsaW0oLTAuMDAxLDEuMCkgKyB4bGltKC0wLjAwMSwxLjApCnByaW50KEFWX0NvcnJfc2V0QUYpCmdnc2F2ZSgiQWxsVmFyU2V0X0NvcnJlbGF0aW9uLnBuZyIsQVZfQ29ycl9zZXRBRikKCiMjTG9va2luZyBhdCBhbGwgU2V0QUYgRGF0YQpBVl9Db3JyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBncm91cCA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKH5jb3ZlcmFnZSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgeWxpbSgtMC4wMDEsMS4wKSArIHhsaW0oLTAuMDAxLDEuMCkKcHJpbnQoQVZfQ29ycl9zZXRBRikKZ2dzYXZlKCJBbGxWYXJTZXRfQ29ycmVsYXRpb25fRmlsdGVyZWQucG5nIixBVl9Db3JyX3NldEFGKQoKQVZfQ29ycl9zZXRBRl9ab29tID0gZ2dwbG90KEFWX3NldEFGLCBhZXMoeCA9IGFmX2dvbGRlbiwgeSA9IGFmX3dvcmtmbG93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gdG9vbCwgZ3JvdXAgPSB0b29sLCBzaGFwZSA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC40KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZCh+Y292ZXJhZ2UpICsKICB5bGltKC0wLjAxLDAuMTUpICsgeGxpbSgtMC4wMSwwLjE1KQpwcmludChBVl9Db3JyX3NldEFGX1pvb20pCmdnc2F2ZSgiQWxsVmFyU2V0X0NvcnJlbGF0aW9uRl9GaWx0ZXJlZF9ab29tLnBuZyIsIEFWX0NvcnJfc2V0QUZfWm9vbSkKYGBgCgojMy4yIFJhbmRvbUFGIC0gQ29ycmVsYXRpb24gQmV0d2VlbiBHb2xkZW4gYW5kIFdvcmtmbG93CmBgYHtyfQojIyBPbmx5IGxvb2tpbmcgYXQgdHJ1ZSBwb3NpdGl2ZXMKQVZfQ29ycl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRiwgYWVzKHggPSBhZl9nb2xkZW4sIHkgPSBhZl93b3JrZmxvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBzaGFwZSA9IGNhdGVnb3J5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IE15Q29sb3JzKSArCiAgZmFjZXRfZ3JpZCh0b29sfmNvdmVyYWdlKSArCiAgeWxpbSgtMC4wMDEsMS4wKSArIHhsaW0oLTAuMDAxLDEuMCkKcHJpbnQoQVZfQ29ycl9yYW5kb21BRikKZ2dzYXZlKCJBbGxWYXJSYW5kb21fQ29ycmVsYXRpb24ucG5nIixBVl9Db3JyX3JhbmRvbUFGKQoKIyNMb29raW5nIGF0IGFsbCBSYW5kb21BRiBEYXRhCkFWX0NvcnJfcmFuZG9tQUYgPSBnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gYWZfZ29sZGVuLCB5ID0gYWZfd29ya2Zsb3csIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHRvb2wsIGdyb3VwID0gdG9vbCwgc2hhcGUgPSBjYXRlZ29yeSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IDAuNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBNeUNvbG9ycykgKwogIGZhY2V0X2dyaWQofmNvdmVyYWdlKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIHNpemUgPSAxLjUpICsKICB5bGltKC0wLjAxLDEpICsgeGxpbSgtMC4wMSwxKQpwcmludChBVl9Db3JyX3JhbmRvbUFGKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Db3JyZWxhdGlvbl9GaWx0ZXJlZC5wbmciLEFWX0NvcnJfcmFuZG9tQUYpCgpBVl9Db3JyX3JhbmRvbUFGX1pvb20gPSBnZ3Bsb3QoQVZfcmFuZG9tQUYsIGFlcyh4ID0gYWZfZ29sZGVuLCB5ID0gYWZfd29ya2Zsb3csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0b29sLCBncm91cCA9IHRvb2wsIHNoYXBlID0gY2F0ZWdvcnkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gTXlDb2xvcnMpICsKICBmYWNldF9ncmlkKH5jb3ZlcmFnZSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0nbG0nLCBzaXplID0gMS41KSArCiAgeWxpbSgtMC4wMSwwLjE1KSArIHhsaW0oLTAuMDEsMC4xNSkKcHJpbnQoQVZfQ29ycl9yYW5kb21BRl9ab29tKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Db3JyZWxhdGlvbl9GaWx0ZXJlZF9ab29tLnBuZyIsIEFWX0NvcnJfcmFuZG9tQUZfWm9vbSkKYGBgCgojIyBTdGF0cyBmb3IgU2V0QUYgRGF0YQpgYGB7cn0KY29lZmZfdmFyIDwtIGZ1bmN0aW9uKHgpIHsKICBDViA8LSBzZCh4KSAvIG1lYW4oeCkgKiAxMDAKICByZXR1cm4oQ1YpCn0KCkFWX3NldEFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfc2V0QUZfdHJ1ZXBvcywgdG9vbCwgYWxsZWxlX2ZyZXEsIGNvdmVyYWdlKSAlPiUKICBzdW1tYXJpemUobWVhbihhZl93b3JrZmxvdyksIHNkKGFmX3dvcmtmbG93KSwgY29lZmZfdmFyKGFmX3dvcmtmbG93KSkgJT4lIGRyb3BsZXZlbHMoKQpjb2xuYW1lcyhBVl9zZXRBRl9zcGxpdCkgPSBjKCJ0b29sIiwiQUYiLCJjb3YiLCJtZWFuIiwic2QiLCJ2YXJpYW5jZSIpCgpNZWFuX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSBtZWFuLCBjb2xvciA9IGNvdikpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHRvb2wpLCBjb2xzID0gdmFycyhBRikpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpwcmludChNZWFuX3NldEFGKQpnZ3NhdmUoIlNldEFGX01lYW5fQWxsZWxlRnJlcXVlbmN5LnBuZyIsTWVhbl9zZXRBRikKCkNvZWZmVmFyX3NldEFGID0gZ2dwbG90KEFWX3NldEFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSB2YXJpYW5jZSwgY29sb3IgPSBjb3YpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh0b29sKSwgY29scyA9IHZhcnMoQUYpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoQ29lZmZWYXJfc2V0QUYpCmdnc2F2ZSgiU2V0QUZfQ29lZmZWYXJfQWxsZWxlRnJlcXVlbmN5LnBuZyIsQ29lZmZWYXJfc2V0QUYpCmBgYAoKCiMjIFNldCBVcCBmb3IgU3RhdHMgZm9yIFJhbmRvbUFGIERhdGEKYGBge3J9CkFWX3JhbmRvbUFGX3NwbGl0ID0gZ3JvdXBfYnkoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgdG9vbCwgY292ZXJhZ2UpICU+JQogIHN1bW1hcml6ZShtZWFuKGFmX3dvcmtmbG93KSwgc2QoYWZfd29ya2Zsb3cpLCBjb2VmZl92YXIoYWZfd29ya2Zsb3cpKSAlPiUgZHJvcGxldmVscygpCmNvbG5hbWVzKEFWX3JhbmRvbUFGX3NwbGl0KSA9IGMoInRvb2wiLCJjb3YiLCJtZWFuIiwic2QiLCJ2YXJpYW5jZSIpCgpNZWFuX3JhbmRvbUFGID0gZ2dwbG90KEFWX3JhbmRvbUFGX3NwbGl0LCBhZXMoeCA9IHRvb2wsIHkgPSBtZWFuLCBjb2xvciA9IGNvdikpICsgCiAgZ2VvbV9wb2ludCgpCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKcHJpbnQoTWVhbl9yYW5kb21BRikKZ2dzYXZlKCJSYW5kb21BRl9NZWFuX0FsbGVsZUZyZXF1ZW5jeS5wbmciLE1lYW5fcmFuZG9tQUYpCgpDb2VmZlZhcl9yYW5kb21BRiA9IGdncGxvdChBVl9yYW5kb21BRl9zcGxpdCwgYWVzKHggPSB0b29sLCB5ID0gdmFyaWFuY2UsIGNvbG9yID0gY292KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCnByaW50KENvZWZmVmFyX3JhbmRvbUFGKQpnZ3NhdmUoIlJhbmRvbUFGX0NvZWZmVmFyX0FsbGVsZUZyZXF1ZW5jeS5wbmciLENvZWZmVmFyX3JhbmRvbUFGKQpgYGAKCiM0LiBMb29rIGF0IGhvdyBlYWNoIHRvb2wgY29tcGFyZXMgYXQgZWFjaCBBRiBhbmQgc2VxLWRlcHRoCmBgYHtyfQpBVlNldF9Db3JyID0gZ2dwbG90KEFWX3NldEFGX3RydWVwb3MsIGFlcyh4ID0gdG9vbCwgeSA9IGFmX3dvcmtmbG93KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fYm94cGxvdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIGZhY2V0X2dyaWQoYWxsZWxlX2ZyZXF+Y292ZXJhZ2UsIHNjYWxlcyA9ICJmcmVlX3kiKQpwcmludChBVlNldF9Db3JyKQpnZ3NhdmUoIkFsbFZhclNldF9Ub29sX0NvbXBhcmlzb24ucGRmIiwgQVZTZXRfQ29yciwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMjApCiMgeSBheGVzIGFyZSBzZXQgcGVyIHJvdyBhdCB0aGUgbW9tZW50IChzY2FsZXMgPSAiZnJlZV95IikKCkFWUmFuZG9tX0NvcnIgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgYWVzKHggPSB0b29sLCB5ID0gYWZfd29ya2Zsb3cpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV92aW9saW4oKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICsKICBmYWNldF9ncmlkKGFsbGVsZV9mcmVxfmNvdmVyYWdlKQpwcmludChBVlJhbmRvbV9Db3JyKQpnZ3NhdmUoIkFsbFZhclJhbmRvbV9Ub29sX0NvbXBhcmlzb24ucGRmIiwgQVZSYW5kb21fQ29yciwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMjApCmBgYAoKIzUuMS4gTG9va3MgYXQgd2hlcmUgdGhlIFNOUFMgYXJlIGxvY2F0ZWQgdGhyb3VnaG91dCB0aGUgZ2Vub21lCmBgYHtyfQojIFNldCBBRiBEYXRhCkFWX1BvcyA9IGdncGxvdChBVl9zZXRBRl90cnVlcG9zLCBhZXMoeCA9IHBvcywgeSA9IGFmX3dvcmtmbG93KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChBVl9Qb3MpCkFWX1Bvc19mYWxzZXBvcyA9IGdncGxvdChBVl9zZXRBRl9mYWxzZXBvcywgYWVzKHggPSBwb3MsIHkgPSBhZl93b3JrZmxvdykpICsKICBnZW9tX3BvaW50KCkKcHJpbnQoQVZfUG9zX2ZhbHNlcG9zKQpBVl9Qb3NfZmFsc2VuZWcgPSBnZ3Bsb3QoQVZfc2V0QUZfZmFsc2VuZWcsIGFlcyh4ID0gcG9zLCB5ID0gYWZfd29ya2Zsb3cpKSArCiAgZ2VvbV9wb2ludCgpCnByaW50KEFWX1Bvc19mYWxzZW5lZykKCiMgUmFuZG9tIEFGIERhdGEKQVZfUG9zX3IgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfdHJ1ZXBvcywgYWVzKHggPSBwb3MsIHkgPSBhZl93b3JrZmxvdykpICsKICBnZW9tX3BvaW50KCkKcHJpbnQoQVZfUG9zX3IpCkFWX1Bvc19mYWxzZXBvc19yID0gZ2dwbG90KEFWX3JhbmRvbUFGX2ZhbHNlcG9zLCBhZXMoeCA9IHBvcywgeSA9IGFmX3dvcmtmbG93KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChBVl9Qb3NfZmFsc2Vwb3NfcikKQVZfUG9zX2ZhbHNlbmVnX3IgPSBnZ3Bsb3QoQVZfcmFuZG9tQUZfZmFsc2VuZWcsIGFlcyh4ID0gcG9zLCB5ID0gYWZfd29ya2Zsb3cpKSArCiAgZ2VvbV9wb2ludCgpCnByaW50KEFWX1Bvc19mYWxzZW5lZ19yKQpgYGAKCiM1LjIuVHJhbnNpdGlvbnMvVHJhbnN2ZXJzaW9ucwpgYGB7cn0Kc2V0QUZfVFBfcG9zID0gZ2dwbG90KEFWX3NldEFGX3RydWVwb3MsIGFlcyh4ID0gcG9zLCB5ID0gcmVmLCBjb2xvciA9IHRvb2wsIHNoYXBlID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChzZXRBRl9UUF9wb3MpCgpUc1R2KEFWX3NldEFGX3RydWVwb3MpCiNjb3VudHMgdmFyaWFudHMgZnJvbSBhbGwgdG9vbHMvc2VxX2RlcHRoL0FGIHRyaWFscwoKcmFuZG9tQUZfVFBfcG9zID0gZ2dwbG90KEFWX3JhbmRvbUFGX3RydWVwb3MsIGFlcyh4ID0gcG9zLCB5ID0gcmVmLCBjb2xvciA9IHRvb2wsIHNoYXBlID0gYWx0KSkgKwogIGdlb21fcG9pbnQoKQpwcmludChyYW5kb21BRl9UUF9wb3MpCgpUc1R2KEFWX3JhbmRvbUFGX3RydWVwb3MpCmBgYAo=