1 An attempt at running Steve’s analyses without significant (any?) modifications.

My goal in this document is to repeat Steve’s analyses without changing anything more signifcant than the fact that I copied his count tables to the directory ‘count_tables’.

When I do change things, I will leave the original text in a non-evaluated block immediately before my modified version. The completely unmodified script is in the scripts/ directory.

I will also break up the various pieces into separate blocks so that I can comment on anything along the way.

require(rtracklayer)
## Loading required package: rtracklayer
## Loading required package: GenomicRanges
## Loading required package: stats4
## Loading required package: BiocGenerics
## Loading required package: parallel
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:parallel':
## 
##     clusterApply, clusterApplyLB, clusterCall, clusterEvalQ,
##     clusterExport, clusterMap, parApply, parCapply, parLapply,
##     parLapplyLB, parRapply, parSapply, parSapplyLB
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, append, as.data.frame, cbind, colMeans,
##     colnames, colSums, do.call, duplicated, eval, evalq, Filter,
##     Find, get, grep, grepl, intersect, is.unsorted, lapply,
##     lengths, Map, mapply, match, mget, order, paste, pmax,
##     pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce,
##     rowMeans, rownames, rowSums, sapply, setdiff, sort, table,
##     tapply, union, unique, unsplit, which, which.max, which.min
## Loading required package: S4Vectors
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:base':
## 
##     expand.grid
## Loading required package: IRanges
## Loading required package: GenomeInfoDb
library(gplots)
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:rtracklayer':
## 
##     space
## The following object is masked from 'package:IRanges':
## 
##     space
## The following object is masked from 'package:S4Vectors':
## 
##     space
## The following object is masked from 'package:stats':
## 
##     lowess
library(RColorBrewer)
library(edgeR)
## Loading required package: limma
## 
## Attaching package: 'limma'
## The following object is masked from 'package:BiocGenerics':
## 
##     plotMA
library(cbcbSEQ)
## Loading required package: corpcor
## Loading required package: preprocessCore
## Loading required package: sva
## Loading required package: mgcv
## Loading required package: nlme
## 
## Attaching package: 'nlme'
## The following object is masked from 'package:IRanges':
## 
##     collapse
## This is mgcv 1.8-23. For overview type 'help("mgcv-package")'.
## Loading required package: genefilter
## Loading required package: BiocParallel
## 
## Attaching package: 'cbcbSEQ'
## The following object is masked from 'package:hpgltools':
## 
##     pcRes
library(hpgltools)

2 Read the count tables, original

I am of course not working in dropbox and I put Steve’s count tables into a directory ‘count_tables’ from within this tree.

setwd('~/Dropbox/lab_work/Leishmania Research/La')

###### Reading & collapsing tables, calculating RPKMs ######
hpgl0721.lmexicana <- read.table("hpgl0721_lmexicana.count",col.names=c("id","hpgl0721"))
hpgl0722.lmexicana <- read.table("hpgl0722_lmexicana.count",col.names=c("id","hpgl0722"))
hpgl0723.lmexicana <- read.table("hpgl0723_lmexicana.count",col.names=c("id","hpgl0723"))
hpgl0724.lmexicana <- read.table("hpgl0724_lmexicana.count",col.names=c("id","hpgl0724"))
hpgl0725.lmexicana <- read.table("hpgl0725_lmexicana.count",col.names=c("id","hpgl0725"))
hpgl0726.lmexicana <- read.table("hpgl0726_lmexicana.count",col.names=c("id","hpgl0726"))
hpgl0727.lmexicana <- read.table("hpgl0727_lmexicana.count",col.names=c("id","hpgl0727"))
hpgl0728.lmexicana <- read.table("hpgl0728_lmexicana.count",col.names=c("id","hpgl0728"))
hpgl0729.lmexicana <- read.table("hpgl0729_lmexicana.count",col.names=c("id","hpgl0729"))
hpgl0730.lmexicana <- read.table("hpgl0730_lmexicana.count",col.names=c("id","hpgl0730"))

In conversations with Steve, it sppears that the first 4 tables were not used.

###### Reading & collapsing tables, calculating RPKMs ######
##hpgl0721.lmexicana <- read.table("count_tables/hpgl0721_lmexicana.count",col.names=c("id","hpgl0721"))
##hpgl0722.lmexicana <- read.table("count_tables/hpgl0722_lmexicana.count",col.names=c("id","hpgl0722"))
##hpgl0723.lmexicana <- read.table("count_tables/hpgl0723_lmexicana.count",col.names=c("id","hpgl0723"))
##hpgl0724.lmexicana <- read.table("count_tables/hpgl0724_lmexicana.count",col.names=c("id","hpgl0724"))
hpgl0725.lmexicana <- read.table("count_tables/hpgl0725_lmexicana.count",col.names=c("id","hpgl0725"))
hpgl0726.lmexicana <- read.table("count_tables/hpgl0726_lmexicana.count",col.names=c("id","hpgl0726"))
hpgl0727.lmexicana <- read.table("count_tables/hpgl0727_lmexicana.count",col.names=c("id","hpgl0727"))
hpgl0728.lmexicana <- read.table("count_tables/hpgl0728_lmexicana.count",col.names=c("id","hpgl0728"))
hpgl0729.lmexicana <- read.table("count_tables/hpgl0729_lmexicana.count",col.names=c("id","hpgl0729"))
hpgl0730.lmexicana <- read.table("count_tables/hpgl0730_lmexicana.count",col.names=c("id","hpgl0730"))

3 Making a list of counts, original

##list.of.data.frames <- list(hpgl0721.lmexicana,hpgl0722.lmexicana,hpgl0723.lmexicana,hpgl0724.lmexicana,hpgl0725.lmexicana,hpgl0726.lmexicana,hpgl0727.lmexicana,hpgl0728.lmexicana,hpgl0729.lmexicana,hpgl0730.lmexicana)
list.of.data.frames <- list(hpgl0725.lmexicana,hpgl0726.lmexicana,hpgl0727.lmexicana,hpgl0728.lmexicana,hpgl0729.lmexicana,hpgl0730.lmexicana)
countsTable = Reduce(function(...) merge(..., by="id", all=T), list.of.data.frames)
countsTable <- countsTable[-c(1:5),]
countsTable <- countsTable[-grep("rfamscan",countsTable$id),]
rownames(countsTable) <- countsTable$id
countsTable <- data.matrix(countsTable[,-1])
## This is interesting, doing this peculiar sapply strsplit/substr operation allows one to have
## non-unique rownames in a matrix.
rownames(countsTable) <- sapply(rownames(countsTable), function(x) strsplit(x,'-')[[1]][1])
rownames(countsTable) <- sapply(rownames(countsTable), function(x) substr(x,6,nchar(x)))
df_list <- list(hpgl0725.lmexicana,
                hpgl0726.lmexicana,
                hpgl0727.lmexicana,
                hpgl0728.lmexicana,
                hpgl0729.lmexicana,
                hpgl0730.lmexicana)
my_counts <- Reduce(function(...) merge(..., by="id", all=TRUE), df_list)
rownames(my_counts) <- my_counts[["id"]]
my_counts <- my_counts[, -1]
keepers_idx <- !grepl(pattern="^_", x=rownames(my_counts))
my_counts <- my_counts[keepers_idx, ]
keepers_idx <- !grepl(pattern="rfamscan", x=rownames(my_counts))
my_counts <- my_counts[keepers_idx, ]
rownames(my_counts) <- gsub(pattern="^exon_", replacement="", x=rownames(my_counts))
rownames(my_counts) <- gsub(pattern="\\-1$", replacement="", x=rownames(my_counts))

4 Summing exons, original

This is an interesting method of getting all the exon data from multiple transcripts into a final count table.

##lmex.collapse <- matrix(0,0,nrow=length(unique(rownames(countsTable))),ncol=10)
## atb changed the static ncol=10 to the number of columns in countsTable
## because we are no longer using 721,722,723,724.
lmex.collapse <- matrix(0,0,nrow=length(unique(rownames(countsTable))),ncol=ncol(countsTable))
rownames(lmex.collapse) <- unique(rownames(countsTable))
for(i in 1:nrow(lmex.collapse)){
  temp.mat <- subset(countsTable,rownames(countsTable) %in% rownames(lmex.collapse)[i])
  if(nrow(temp.mat)==1){
    lmex.collapse[i,] <- temp.mat
  }
  if(nrow(temp.mat)>1){
    lmex.collapse[i,] <- colSums(countsTable[rownames(countsTable) %in% rownames(lmex.collapse)[i],])
  }
}
## Added by atb
colnames(lmex.collapse) <- colnames(countsTable)

5 My method of summing exons

multi_exon_idx <- grep(pattern="\\-\\d+$", x=rownames(my_counts))
for (idx in multi_exon_idx) {
  gene <- gsub(pattern="\\-\\d+$", replacement="", x=rownames(my_counts)[idx])
  exon_counts <- my_counts[idx, ]
  gene_counts <- my_counts[gene, ]
  total_counts <- gene_counts + exon_counts
  my_counts[gene, ] <- total_counts
}
my_counts <- my_counts[-multi_exon_idx, ]
my_counts <- as.matrix(my_counts)
all.equal(my_counts, lmex.collapse)
## Error in mode(current): object 'lmex.collapse' not found
lmexvitro.countsTable <- read.table("../Lb/20141211_Lmexicana81_434-435_437_440_443_446_453-454_458_462_466_470_491-492_496_500_504_508_CDSonly.count", header=T)
rownames(lmexvitro.countsTable) <- lmexvitro.countsTable$id
lmexvitro.countsTable <- data.matrix(lmexvitro.countsTable[,c(2:6,8:12,14:18)])
rownames(lmexvitro.countsTable) <- sapply(rownames(lmexvitro.countsTable), function(x) strsplit(x,'-')[[1]][1])
lmexvitro.collapse <- matrix(0,0,nrow=length(unique(rownames(lmexvitro.countsTable))),ncol=15)
rownames(lmexvitro.collapse) <- unique(rownames(lmexvitro.countsTable))
for(i in 1:nrow(lmexvitro.collapse)){
  temp.mat <- subset(lmexvitro.countsTable,rownames(lmexvitro.countsTable) %in% rownames(lmexvitro.collapse)[i])
  if(nrow(temp.mat)==1){
    lmexvitro.collapse[i,] <- temp.mat
  }
  if(nrow(temp.mat)>1){
    lmexvitro.collapse[i,] <- colSums(lmexvitro.countsTable[rownames(lmexvitro.countsTable) %in% rownames(lmexvitro.collapse)[i],])
  }
}

lb.countsTable <- read.table('../Lb/20170215_Lb_allgenes_countTable.txt') #Read in Lb counts
lb.countsTable <- data.matrix(lb.countsTable[,c(2,3,5,16,19,23)])
rownames(lb.countsTable) <- sapply(rownames(lb.countsTable), function(x) strsplit(x,'-')[[1]][1])
lb.collapse <- matrix(0,0,nrow=length(unique(rownames(lb.countsTable))),ncol=6)
rownames(lb.collapse) <- unique(rownames(lb.countsTable))
for(i in 1:nrow(lb.collapse)){
  temp.mat <- subset(lb.countsTable,rownames(lb.countsTable) %in% rownames(lb.collapse)[i])
  if(nrow(temp.mat)==1){
    lb.collapse[i,] <- temp.mat
  }
  if(nrow(temp.mat)>1){
    lb.collapse[i,] <- colSums(lb.countsTable[rownames(lb.countsTable) %in% rownames(lb.collapse)[i],])
  }
}
lb.collapse <- lb.collapse[!rownames(lb.collapse)=='LbrM.26.0210a',]
rownames(lb.collapse)[rownames(lb.collapse)=='LbrM.20.0191'] <- 'LbrM.10.0191'

{
  lmajor.72counts <- read.table('../Lb/Lmajor_72hrs.txt',header=F,sep='\t',col.names=c("id","lm72.1","lm72.2","lm72.3","lm72.4"))
  hpgl0364.lmajor <- read.table("htseq_HPGL0364_Lmajor60_20140329.txt",col.names=c("id","hpgl0364"))
  hpgl0374.lmajor <- read.table("htseq_HPGL0374_Lmajor60_20140329.txt",col.names=c("id","hpgl0374"))
  hpgl0397.lmajor <- read.table("htseq_HPGL0397_Lmajor60_20140712.txt",col.names=c("id","hpgl0397"))
  hpgl0456.lmajor <- read.table("htseq_HPGL0456_Lmajor60_20141001.txt",col.names=c("id","hpgl0456"))
  hpgl0494.lmajor <- read.table("htseq_HPGL0494_Lmajor60_20141211.txt",col.names=c("id","hpgl0494"))
  hpgl0366.lmajor <- read.table("htseq_HPGL0366_Lmajor60_20140329.txt",col.names=c("id","hpgl0366"))
  hpgl0376.lmajor <- read.table("htseq_HPGL0376_Lmajor60_20140329.txt",col.names=c("id","hpgl0376"))
  hpgl0399.lmajor <- read.table("htseq_HPGL0399_Lmajor60_20140712.txt",col.names=c("id","hpgl0399"))
  hpgl0459.lmajor <- read.table("htseq_HPGL0459_Lmajor60_20141001.txt",col.names=c("id","hpgl0459"))
  hpgl0497.lmajor <- read.table("htseq_HPGL0497_Lmajor60_20141211.txt",col.names=c("id","hpgl0497"))
  hpgl0368.lmajor <- read.table("htseq_HPGL0368_Lmajor60_20140329.txt",col.names=c("id","hpgl0368"))
  hpgl0378.lmajor <- read.table("htseq_HPGL0378_Lmajor60_20140329.txt",col.names=c("id","hpgl0378"))
  hpgl0401.lmajor <- read.table("htseq_HPGL0401_Lmajor60_20140712.txt",col.names=c("id","hpgl0401"))
  hpgl0463.lmajor <- read.table("htseq_HPGL0463_Lmajor60_20141001.txt",col.names=c("id","hpgl0463"))
  hpgl0501.lmajor <- read.table("htseq_HPGL0501_Lmajor60_20141211.txt",col.names=c("id","hpgl0501"))
  hpgl0370.lmajor <- read.table("htseq_HPGL0370_Lmajor60_20140329.txt",col.names=c("id","hpgl0370"))
  hpgl0380.lmajor <- read.table("htseq_HPGL0380_Lmajor60_20140329.txt",col.names=c("id","hpgl0380"))
  hpgl0403.lmajor <- read.table("htseq_HPGL0403_Lmajor60_20140712.txt",col.names=c("id","hpgl0403"))
  hpgl0467.lmajor <- read.table("htseq_HPGL0467_Lmajor60_20141001.txt",col.names=c("id","hpgl0467"))
  hpgl0505.lmajor <- read.table("htseq_HPGL0505_Lmajor60_20141211.txt",col.names=c("id","hpgl0505"))

  list.of.data.frames <- list(hpgl0364.lmajor,hpgl0374.lmajor,hpgl0397.lmajor,hpgl0456.lmajor,hpgl0494.lmajor,
                              hpgl0366.lmajor,hpgl0376.lmajor,hpgl0399.lmajor,hpgl0459.lmajor,hpgl0497.lmajor,
                              hpgl0368.lmajor,hpgl0378.lmajor,hpgl0401.lmajor,hpgl0463.lmajor,hpgl0501.lmajor,
                              hpgl0370.lmajor,hpgl0380.lmajor,hpgl0403.lmajor,hpgl0467.lmajor,hpgl0505.lmajor,
                              lmajor.72counts)
}
lmaj.countsTable = Reduce(function(...) merge(..., by="id", all=T), list.of.data.frames)
lmaj.countsTable <- lmaj.countsTable[-c(1:2,9466:9474),]
rownames(lmaj.countsTable) <- lmaj.countsTable$id
lmaj.countsTable <- data.matrix(lmaj.countsTable[,-1])
rownames(lmaj.countsTable) <- sapply(rownames(lmaj.countsTable), function(x) substr(x,6,nchar(x)))
rownames(lmaj.countsTable) <- sapply(rownames(lmaj.countsTable), function(x) strsplit(x,'-')[[1]][1])
lmaj.collapse <- matrix(0,0,nrow=length(unique(rownames(lmaj.countsTable))),ncol=24)
rownames(lmaj.collapse) <- unique(rownames(lmaj.countsTable))
for(i in 1:nrow(lmaj.collapse)){
  temp.mat <- subset(lmaj.countsTable,rownames(lmaj.countsTable) %in% rownames(lmaj.collapse)[i])
  if(nrow(temp.mat)==1){
    lmaj.collapse[i,] <- temp.mat
  }
  if(nrow(temp.mat)>1){
    lmaj.collapse[i,] <- colSums(lmaj.countsTable[rownames(lmaj.countsTable) %in% rownames(lmaj.collapse)[i],])
  }
}

lmex.db <- import.gff('../Lb/TriTrypDB-27_LmexicanaMHOMGT2001U1103.gff')
lmex.hist <- data.frame(chr=seqnames(lmex.db),ID=lmex.db$ID,
                        Name=lmex.db$type,
                        size=width(lmex.db),
                        start=start(lmex.db),end=end(lmex.db))
lmex.hist <- lmex.hist[lmex.hist$Name %in% 'CDS',]
lmexhist.collapse <- matrix(0,0,nrow=nrow(lmex.collapse),ncol=2)
rownames(lmexhist.collapse) <- rownames(lmex.collapse)
for(i in 1:nrow(lmexhist.collapse)){
  temp.mat <- lmex.hist[grep(rownames(lmexhist.collapse)[i],lmex.hist$ID),]
  if(nrow(temp.mat)==1){
    lmexhist.collapse[i,2] <- temp.mat$size
  }
  if(nrow(temp.mat)>1){
    lmexhist.collapse[i,2] <- sum(temp.mat$size)
  }
}
lmex_rpkm <- rpkm(lmex.collapse,as.numeric(lmexhist.collapse[,2]))
lmexvitro_rpkm <- rpkm(lmexvitro.collapse,as.numeric(lmexhist.collapse[,2]))

lmex_rpkm <- lmex_rpkm[order(rowSums(lmex_rpkm[,5:10]),decreasing=T),]
datCor <- cor(lmex_rpkm[,5:10])
heatmap.2(datCor,
          margins=c(10, 10),
          labRow=c('DCL.1','DCL.2','DCL.3','DCL.4','DCL.5','DCL.6'),
          labCol=c('DCL.1','DCL.2','DCL.3','DCL.4','DCL.5','DCL.6'),
          scale="none", cellnote = format(round(datCor, 2), nsmall = 0),
          breaks = seq(0,1,0.01),
          notecex=0.5, notecol = 'black', trace="none",
          srtCol=45,main='Pearson correlation (RPKMs)')

lb.db <- import.gff("../Lb/TriTrypDB-26_LbraziliensisMHOMBR75M2904.gff")
lb.hist <- data.frame(chr=seqnames(lb.db),ID=lb.db$ID,
                      Name=lb.db$type,
                      size=width(lb.db),
                      start=start(lb.db),end=end(lb.db))
lb.hist <- lb.hist[lb.hist$Name %in% 'CDS',]
lbhist.collapse <- matrix(0,0,nrow=nrow(lb.collapse),ncol=2)
rownames(lbhist.collapse) <- rownames(lb.collapse)
for(i in 1:nrow(lbhist.collapse)){
  temp.mat <- lb.hist[grep(rownames(lbhist.collapse)[i],lb.hist$ID),]
  if(nrow(temp.mat)==1){
    lbhist.collapse[i,2] <- temp.mat$size
  }
  if(nrow(temp.mat)>1){
    lbhist.collapse[i,2] <- sum(temp.mat$size)
  }
}
lbhist.collapse[rownames(lbhist.collapse)=="LbrM.10.0191",2] <- 645
lb_rpkm <- rpkm(lb.collapse,gene.length=as.numeric(lbhist.collapse[,2]))

lmajor.db <- import.gff('../Lb/TriTrypDB-27_LmajorFriedlin.gff')
lmaj.hist <- data.frame(chr=seqnames(lmajor.db),ID=lmajor.db$ID,
                        Name=lmajor.db$type,
                        size=width(lmajor.db),
                        start=start(lmajor.db),end=end(lmajor.db))
lmaj.hist <- lmaj.hist[lmaj.hist$Name %in% 'exon',]
lmajhist.collapse <- matrix(0,0,nrow=nrow(lmaj.collapse),ncol=2)
rownames(lmajhist.collapse) <- rownames(lmaj.collapse)
for(i in 1:nrow(lmajhist.collapse)){
  temp.mat <- lmaj.hist[grep(rownames(lmajhist.collapse)[i],lmaj.hist$ID),]
  if(nrow(temp.mat)==1){
    lmajhist.collapse[i,2] <- temp.mat$size
  }
  if(nrow(temp.mat)>1){
    lmajhist.collapse[i,2] <- sum(temp.mat$size)
  }
}
lmaj_rpkm <- rpkm(lmaj.collapse,as.numeric(lmajhist.collapse[,2]))

nrow(lmex_rpkm)
nrow(lb_rpkm)
nrow(lmaj_rpkm)

## Coverage of *L. amazonensis* DCL lesions
barplot(colSums(countsTable), las=3, main='Lmx Raw Counts By Sample (DCL)')
dim(lmex_rpkm)

## Coverage of *L. amazonensis* LCL parasite *in vitro* macrophage infection
barplot(colSums(lmexvitro.countsTable), las=3, main='Lmx Raw Counts By Sample (LCL in vitro)')
dim(lmexvitro_rpkm)

## Coverage of *L. braziliensis* LCL lesions
barplot(colSums(lb.countsTable), las=3, main='Lbr Raw Counts By Sample (LCL in vivo)')
dim(lb_rpkm)

## Coverage of *L. major* LCL parasite *in vitro* macrophage infection
barplot(colSums(lmaj.countsTable), las=3, main='Lmj Raw Counts By Sample (LCL in vitro)')
dim(lmaj_rpkm)

## Coverage of all parasites, all conditions
barplot(c(colSums(countsTable),colSums(lmexvitro.countsTable),
          colSums(lb.countsTable),colSums(lmaj.countsTable)),
        las=3)

##### Generate single-reciprocal ortholog tables #####
##Compare Lmex vs. all
lmex_rpkm <- rpkm(lmex.collapse,as.numeric(lmexhist.collapse[,2]))
Lmex.to.paralogs <- read.table("../Lb/Lmx_ama.paralogs.ids.txt")
Lmex.paralogs <- matrix(0,0,ncol=2,nrow=nrow(Lmex.to.paralogs))
row=1
pb <- txtProgressBar(0,nrow(lmex_rpkm),initial=0,style=3)
for(i in 1:nrow(lmex_rpkm)){
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
  if(rownames(lmex_rpkm)[i] %in% Lmex.to.paralogs[,1] & rownames(lmex_rpkm)[i+1] %in% Lmex.to.paralogs[,1]){
    row1 <- which(Lmex.to.paralogs[,1]==rownames(lmex_rpkm)[i]) #row of current gene
    row2 <- which(Lmex.to.paralogs[,1]==rownames(lmex_rpkm)[i+1]) #row of next gene
    if((row2-row1)>1){ #if there are paralogs
      for(j in (row1+1):(row2-1)){ #loop from the row after current gene to row before next gene
        Lmex.paralogs[row,1] <- rownames(lmex_rpkm)[i] #Lmex gene
        Lmex.paralogs[row,2] <- as.character(Lmex.to.paralogs[j,]) #Paralog gene
        row=row+1
      }
    }
  }
}

lmex_hom <- matrix(0,0,ncol=3,nrow=nrow(lmex_rpkm))
lmex_hom[,1] <- rownames(lmex_rpkm)
pb <- txtProgressBar(0,nrow(lmex_rpkm),initial=0,style=3)
for(i in 1:nrow(lmex_rpkm)){
  tempid <- lmex_hom[i,1]
  if(!tempid %in% Lmex.paralogs[,1]){
    lmex_hom[i,2:3] <- 0
  }
  if(tempid %in% Lmex.paralogs[,1]){
    temphom.bra <- subset(Lmex.paralogs, Lmex.paralogs[,1] %in% tempid)
    temphom.bra <- subset(temphom.bra,substr(temphom.bra[,2],1,3)=="Lbr")
    temphom.bra <- subset(temphom.bra,temphom.bra[,2] %in% rownames(lb_rpkm))
    temphom.maj <- subset(Lmex.paralogs, Lmex.paralogs[,1] %in% tempid)
    temphom.maj <- subset(temphom.maj,substr(temphom.maj[,2],1,4)=="LmjF")
    temphom.maj <- subset(temphom.maj,temphom.maj[,2] %in% rownames(lmaj_rpkm))
    if(nrow(temphom.bra)==0 | nrow(temphom.maj)==0){
      lmex_hom[i,2:3] <- 0
    }
    if(nrow(temphom.bra)==1 & nrow(temphom.maj)==1){
      lmex_hom[i,2] <- temphom.bra[,2]
      lmex_hom[i,3] <- temphom.maj[,2]
    }
    if(nrow(temphom.bra)>1 | nrow(temphom.maj)>1){
      lmex_hom[i,2:3] <- 0
    }
  }
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
}
lmex_hom <- lmex_hom[lmex_hom[,2]!=0 & lmex_hom[,3]!=0,]

#Compare Lbraz vs. all
Lb.to.paralogs <- read.table("../Lb/Lbraz.paralogs.ids.txt")
Lb.paralogs <- matrix(0,0,ncol=2,nrow=nrow(Lb.to.paralogs))
row=1
pb <- txtProgressBar(0,nrow(lb_rpkm),initial=0,style=3)
for(i in 1:nrow(lb_rpkm)){
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
  if(rownames(lb_rpkm)[i] %in% Lb.to.paralogs[,1] & rownames(lb_rpkm)[i+1] %in% Lb.to.paralogs[,1]){
    row1 <- which(Lb.to.paralogs[,1]==rownames(lb_rpkm)[i]) #row of current gene
    row2 <- which(Lb.to.paralogs[,1]==rownames(lb_rpkm)[i+1]) #row of next gene
    if((row2-row1)>1){ #if there are paralogs
      for(j in (row1+1):(row2-1)){ #loop from the row after current gene to row before next gene
        Lb.paralogs[row,1] <- rownames(lb_rpkm)[i] #Lmex gene
        Lb.paralogs[row,2] <- as.character(Lb.to.paralogs[j,]) #Paralog gene
        row=row+1
      }
    }
  }
}

lb_hom <- matrix(0,0,ncol=3,nrow=nrow(lb_rpkm))
lb_hom[,1] <- rownames(lb_rpkm)
pb <- txtProgressBar(0,nrow(lb_rpkm),initial=0,style=3)
for(i in 1:nrow(lb_rpkm)){
  tempid <- lb_hom[i,1]
  if(!tempid %in% Lb.paralogs[,1]){
    lb_hom[i,2:3] <- 0
  }
  if(tempid %in% Lb.paralogs[,1]){
    temphom.1 <- subset(Lb.paralogs, Lb.paralogs[,1] %in% tempid)
    temphom.1 <- subset(temphom.1,substr(temphom.1[,2],1,3)=="Lmx")
    temphom.1 <- subset(temphom.1,temphom.1[,2] %in% rownames(lmex_rpkm))
    temphom.2 <- subset(Lb.paralogs, Lb.paralogs[,1] %in% tempid)
    temphom.2 <- subset(temphom.2,substr(temphom.2[,2],1,3)=="Lmj")
    temphom.2 <- subset(temphom.2,temphom.2[,2] %in% rownames(lmaj_rpkm))
    if(nrow(temphom.1)==0 | nrow(temphom.2)==0){
      lb_hom[i,2:3] <- 0
    }
    if(nrow(temphom.1)==1 & nrow(temphom.2)==1){
      lb_hom[i,2] <- temphom.1[,2]
      lb_hom[i,3] <- temphom.2[,2]
    }
    if(nrow(temphom.1)>1 | nrow(temphom.2)>1){
      lb_hom[i,2:3] <- 0
    }
  }
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
}
lb_hom <- lb_hom[lb_hom[,2]!=0 & lb_hom[,3]!=0,]

#Compare Lmaj vs. all
Lmaj.to.paralogs <- read.csv("../Lb/LmjF.paralogs.ids.txt",header=F)
Lmaj.paralogs <- matrix(0,0,ncol=2,nrow=nrow(Lmaj.to.paralogs))
row=1
pb <- txtProgressBar(0,nrow(lmaj_rpkm),initial=0,style=3)
for(i in 1:nrow(lmaj_rpkm)){
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
  if(rownames(lmaj_rpkm)[i] %in% Lmaj.to.paralogs[,1] & rownames(lmaj_rpkm)[i+1] %in% Lmaj.to.paralogs[,1]){
    row1 <- which(Lmaj.to.paralogs[,1]==rownames(lmaj_rpkm)[i]) #row of current gene
    row2 <- which(Lmaj.to.paralogs[,1]==rownames(lmaj_rpkm)[i+1]) #row of next gene
    if((row2-row1)>1){ #if there are paralogs
      for(j in (row1+1):(row2-1)){ #loop from the row after current gene to row before next gene
        Lmaj.paralogs[row,1] <- rownames(lmaj_rpkm)[i] #Lmex gene
        Lmaj.paralogs[row,2] <- as.character(Lmaj.to.paralogs[j,]) #Paralog gene
        row=row+1
      }
    }
  }
}

lmaj_hom <- matrix(0,0,ncol=3,nrow=nrow(lmaj_rpkm))
lmaj_hom[,1] <- rownames(lmaj_rpkm)
pb <- txtProgressBar(0,nrow(lmaj_rpkm),initial=0,style=3)
for(i in 1:nrow(lmaj_rpkm)){
  tempid <- lmaj_hom[i,1]
  if(!tempid %in% Lmaj.paralogs[,1]){
    lmaj_hom[i,2:3] <- 0
  }
  if(tempid %in% Lmaj.paralogs[,1]){
    temphom.1 <- subset(Lmaj.paralogs, Lmaj.paralogs[,1] %in% tempid)
    temphom.1 <- subset(temphom.1,substr(temphom.1[,2],1,3)=="Lmx")
    temphom.1 <- subset(temphom.1,temphom.1[,2] %in% rownames(lmex_rpkm))
    temphom.2 <- subset(Lmaj.paralogs, Lmaj.paralogs[,1] %in% tempid)
    temphom.2 <- subset(temphom.2,substr(temphom.2[,2],1,3)=="Lbr")
    temphom.2 <- subset(temphom.2,temphom.2[,2] %in% rownames(lb_rpkm))
    if(nrow(temphom.1)==0 | nrow(temphom.2)==0){
      lmaj_hom[i,2:3] <- 0
    }
    if(nrow(temphom.1)==1 & nrow(temphom.2)==1){
      lmaj_hom[i,2] <- temphom.1[,2]
      lmaj_hom[i,3] <- temphom.2[,2]
    }
    if(nrow(temphom.1)>1 | nrow(temphom.2)>1){
      lmaj_hom[i,2:3] <- 0
    }
  }
  Sys.sleep(0.01); setTxtProgressBar(pb,i)
}
lmaj_hom <- lmaj_hom[lmaj_hom[,2]!=0 & lmaj_hom[,3]!=0,]

lmex_hom.all <- lmex_hom[lmex_hom[,1] %in% lb_hom[,2] &
                           lmex_hom[,1] %in% lmaj_hom[,2] &
                           lmex_hom[,2] %in% lb_hom[,1] &
                           lmex_hom[,2] %in% lmaj_hom[,3] &
                           lmex_hom[,3] %in% lb_hom[,3] &
                           lmex_hom[,3] %in% lmaj_hom[,1],]
colnames(lmex_hom.all) <- c('lmx.id','lbr.id','lmj.id')

lmex.rpkm.homs <- cbind(rownames(lmex_rpkm),lmex_rpkm[,5:10])
colnames(lmex.rpkm.homs) <- c('lmx.id',paste(rep('lmxvivo',times=6), c(1:6), sep="."))
lmex.rpkm.homs <- merge(lmex.rpkm.homs, lmex_hom.all, by='lmx.id')

lmex.vitro.rpkm.homs <- cbind(rownames(lmexvitro_rpkm),lmexvitro_rpkm)
colnames(lmex.vitro.rpkm.homs) <- c('lmx.id',paste(rep(c("lmxexternal", "lmxvitro4","lmxvitro24",
                                                         "lmxvitro48", "lmxvitro72"),times=3), c(1:15), sep="."))
lmex.vitro.rpkm.homs <- merge(lmex.vitro.rpkm.homs, lmex_hom.all, by='lmx.id')

lb.rpkm.homs <- cbind(rownames(lb_rpkm),lb_rpkm)
colnames(lb.rpkm.homs) <- c('lbr.id',paste(rep('lbrvivo',times=6), c(1:6), sep="."))
lb.rpkm.homs <- merge(lb.rpkm.homs, lmex_hom.all, by='lbr.id')

lmaj.rpkm.homs <- cbind(rownames(lmaj_rpkm),lmaj_rpkm)
colnames(lmaj.rpkm.homs) <- c('lmj.id',paste(c(rep("lmjexternal",times=5),rep("lmjvitro4",times=5),rep("lmjvitro24",times=5),
                                               rep("lmjvitro48",times=5),rep("lmjvitro72",times=4)),c(1:24), sep="."))
lmaj.rpkm.homs <- merge(lmaj.rpkm.homs, lmex_hom.all, by='lmj.id')

list.of.data.frames <- list(lmex.rpkm.homs,lmex.vitro.rpkm.homs,lb.rpkm.homs,lmaj.rpkm.homs)
all.rpkm = Reduce(function(...) merge(..., by="lmx.id", all=T), list.of.data.frames)
all.rpkm <- all.rpkm[,c(2:7,10:24,28:33,36:59)]
all.rpkm <- apply(all.rpkm,2,as.numeric)
rownames(all.rpkm) <- lmex_hom.all[,1]
q.rpkm <- cbind(lmex_hom.all,qNorm(all.rpkm))

dim(lmex_hom)
dim(lb_hom)
dim(lmaj_hom)
head(lmex_hom.all)
nrow(lmex_hom.all)

###### RPKM correlations#####
col.nam <- c(paste(rep('Lmex-vivo',times=6), c(1:6), sep="."),
             rep(c("external","Lmex-vitro4","Lmex-vitro24","Lmex-vitro48","Lmex-vitro72"),times=3),
             paste(rep('Lb-vivo',times=6), c(1:6), sep="."),
             paste(rep("lmjexternal",times=5),c(1:5), sep='.'),
             paste(rep("lmjvitro4",times=5),c(1:5), sep='.'),
             paste(rep("lmjvitro24",times=5),c(1:5), sep='.'),
             paste(rep("lmjvitro48",times=5),c(1:5), sep='.'),
             paste(rep("lmjvitro72",times=4),c(1:4), sep='.'))
# Ran correlations using pearson, spearman, and by correlating rpkms of top quartile and bottom three quartiles
#Top quartile of DCL L.mx is 1:2063 after sorting on rowSums of columns 1:6
#Also looked at quantile normalization effect on correlations
#all.rpkm <- all.rpkm[order(rowSums(all.rpkm),decreasing=T),]
datCor <- cor(all.rpkm,method='spearman')
heatmap.2(datCor,
          margins=c(10, 10),
          labRow=col.nam,
          labCol=col.nam,
          scale="none",breaks=seq(0,1,length=100),
          trace="none",
          srtCol=45,main='Spearman correlation (RPKMs)')

#Quantile normalize rpkm values across samples
q.rpkm <- qNorm(all.rpkm)
datCor <- cor(q.rpkm,method='pearson')
heatmap.2(datCor,
          margins=c(10, 10),
          labRow=col.nam,
          labCol=col.nam,
          scale="none",breaks=seq(0,1,length=100),
          trace="none",
          srtCol=45,main='Pearson correlation (qnorm RPKMs)')

#Correlation between L. amazonensis samples
lmexvitro_rpkm <- lmexvitro_rpkm[match(rownames(lmex_rpkm),rownames(lmexvitro_rpkm)),]
lmexall.rpkm <- cbind(lmex_rpkm[,5:10],lmexvitro_rpkm)
lmexall.rpkm <- apply(lmexall.rpkm,2,as.numeric)
rownames(lmexall.rpkm) <- rownames(lmex_rpkm)
col.nam <- c(paste(rep('Lmex-vivo',times=6), c(1:6), sep="."),
             rep(c("external", "Lmex-vitro4","Lmex-vitro24", "Lmex-vitro48", "Lmex-vitro72"),times=3))
datCor <- cor(lmexall.rpkm,method='pearson')
heatmap.2(datCor,
          margins=c(10, 10),
          labRow=col.nam,
          labCol=col.nam,
          scale="none",breaks=seq(0.55,1,length=100),
          trace="none",
          srtCol=45,main='Pearson correlation (Lmx RPKMs)')
qmex.rpkm <- qNorm(lmexall.rpkm)
rownames(qmex.rpkm) <- rownames(lmex_rpkm)
datCor <- cor(qmex.rpkm,method='pearson')
heatmap.2(datCor,
          margins=c(10, 10),
          labRow=col.nam,
          labCol=col.nam,
          scale="none",breaks=seq(0.55,1,length=100),
          trace="none",
          srtCol=45,main='Pearson correlation (qnorm Lmx RPKMs)')

#######All Leishmania comparison/table generation#####
lmaj_rpkm <- lmaj_rpkm[rownames(lmaj_rpkm) %in% lmajor.tritrypdb[,1],]
lmex_rpkm <- lmex_rpkm[rownames(lmex_rpkm) %in% lmex.tritrypdb[,1],]
lmexvitro_rpkm <- lmexvitro_rpkm[rownames(lmexvitro_rpkm) %in% lmex.tritrypdb[,1],]
lb_rpkm <- lb_rpkm[rownames(lb_rpkm) %in% lb.tritrypdb[,1],]

all_comp <- matrix(0,0,nrow=nrow(all.rpkm)+
                     (nrow(lb_rpkm)-nrow(all.rpkm))+
                     (nrow(lmaj_rpkm)-nrow(all.rpkm))+
                     (nrow(lmex_rpkm)-nrow(all.rpkm)),ncol=16)
common.genes = Reduce(function(...) merge(..., by="lmx.id", all=T), list.of.data.frames)
common.genes <- common.genes[,c(1,8,9)]
all_comp[1:nrow(all.rpkm),2] <- as.character(common.genes[,1])
all_comp[1:nrow(all.rpkm),9] <- as.character(common.genes[,2])
all_comp[1:nrow(all.rpkm),13] <- as.character(common.genes[,3])
all_comp[1:nrow(all.rpkm),4] <- rowMeans(all.rpkm[,1:6])
all_comp[1:nrow(all.rpkm),7] <- rowMeans(all.rpkm[,c(11,16,21)])
all_comp[1:nrow(all.rpkm),11] <- rowMeans(all.rpkm[,22:26])
all_comp[1:nrow(all.rpkm),15] <- rowMeans(all.rpkm[,48:51])
for(i in 1:nrow(all.rpkm)){
  all_comp[i,1] <- as.character(lmex.tritrypdb[lmex.tritrypdb[,1] == as.character(all_comp[i,2]),][,2])
  all_comp[i,5] <- sd(all.rpkm[i,1:6])/sqrt(6)
  all_comp[i,8] <- sd(all.rpkm[i,c(11,16,21)])/sqrt(3)
  all_comp[i,12] <- sd(all.rpkm[i,22:26])/sqrt(6)
  all_comp[i,16] <- sd(all.rpkm[i,48:51])/sqrt(4)
}
lmexvivo_unique <- lmex_rpkm[!rownames(lmex_rpkm) %in% common.genes[,1],]
lmexvitro_unique <- lmexvitro_rpkm[!rownames(lmexvitro_rpkm) %in% common.genes[,1],]
lmexvitro_unique <- lmexvitro_unique[match(rownames(lmexvivo_unique),rownames(lmexvitro_unique)),]
all_comp[(nrow(all.rpkm)+1):nrow(lmex_rpkm),2] <- rownames(lmexvivo_unique)
all_comp[(nrow(all.rpkm)+1):nrow(lmex_rpkm),4] <- rowMeans(lmexvivo_unique[,5:10])
all_comp[(nrow(all.rpkm)+1):nrow(lmex_rpkm),7] <- rowMeans(lmexvitro_unique[,c(5,10,15)])
for(i in (nrow(all.rpkm)+1):nrow(lmex_rpkm)){
  row = i-nrow(all.rpkm)
  all_comp[i,1] <- as.character(lmex.tritrypdb[lmex.tritrypdb[,1] == as.character(all_comp[i,2]),][,2])
  all_comp[i,5] <- sd(lmexvivo_unique[row,5:10])/sqrt(6)
  all_comp[i,8] <- sd(lmexvitro_unique[row,])/sqrt(3)
}
lb_unique <- lb_rpkm[!rownames(lb_rpkm) %in% common.genes[,2],]
all_comp[(nrow(lmex_rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)),9] <- rownames(lb_unique)
all_comp[(nrow(lmex_rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)),11] <- rowMeans(lb_unique)
for(i in (nrow(lmex_rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm))){
  row = i-nrow(lmex_rpkm)
  all_comp[i,1] <- as.character(lb.tritrypdb[lb.tritrypdb[,1] == as.character(all_comp[i,9]),][,2])
  all_comp[i,12] <- sd(lb_unique[row,])/sqrt(6)
}
lmj_unique <- lmaj_rpkm[!rownames(lmaj_rpkm) %in% common.genes[,3],]
lmajor.tritrypdb <- lmajor.tritrypdb[lmajor.tritrypdb[,1] %in% rownames(lmaj_rpkm),]
all_comp[(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+nrow(lmaj_rpkm)-nrow(all.rpkm)),13] <- rownames(lmj_unique)
all_comp[(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+nrow(lmaj_rpkm)-nrow(all.rpkm)),15] <- rowMeans(lmj_unique[,21:24])
for(i in (nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+1):(nrow(lmex_rpkm)+nrow(lb_rpkm)-nrow(all.rpkm)+nrow(lmaj_rpkm)-nrow(all.rpkm))){
  row = i-nrow(lmex_rpkm)-(nrow(lb_rpkm)-nrow(all.rpkm))
  all_comp[i,1] <- as.character(lmajor.tritrypdb[lmajor.tritrypdb[,1] == as.character(all_comp[i,13]),][,2][1])
  all_comp[i,16] <- sd(lmj_unique[row,21:24])/sqrt(4)
}

all_comp <- all_comp[order(as.numeric(all_comp[,4]),decreasing=T),]
all_comp[1:nrow(lmex_rpkm),3] <- c(1:nrow(lmex_rpkm))
all_comp <- all_comp[order(as.numeric(all_comp[,7]),decreasing=T),]
all_comp[1:nrow(lmexvitro_rpkm),6] <- c(1:nrow(lmexvitro_rpkm))
all_comp <- all_comp[order(as.numeric(all_comp[,11]),decreasing=T),]
all_comp[1:nrow(lb_rpkm),10] <- c(1:nrow(lb_rpkm))
all_comp <- all_comp[order(as.numeric(all_comp[,15]),decreasing=T),]
all_comp[1:nrow(lmaj_rpkm),14] <- c(1:nrow(lmaj_rpkm))

write.table(all_comp,'Lmx_vivo_72hrvitro_Lbr_vivo_Lmaj_72hrvitro_genecomp_20180106.txt',sep='\t')

all_comp <- all_comp[order(as.numeric(all_comp[,3])),]
plot(all_comp[4313:4912,3],all_comp[4313:4912,6],pch=19,cex=0.2,
     xlab='Rank (DCL in vivo)',ylab='Rank (LCL in vitro-72hrs)')
abline(h=1000,col='red',lty=2)
la72low <- as.numeric(all_comp[4313:4912,6])>2000
text(x=as.numeric(all_comp[4313:4912,3])[la72low],
     y=as.numeric(all_comp[4313:4912,6])[la72low],
     labels=all_comp[4313:4912,2][la72low], cex=.7, pos=2)
all_comp <- all_comp[all_comp[,2] %in% common.genes[,1],]
for(i in 1:nrow(all_comp)){
  all_comp[i,4] <- 1-(as.numeric(all_comp[i,3])/nrow(lmex_rpkm))
  all_comp[i,7] <- 1-(as.numeric(all_comp[i,6])/nrow(lmex_rpkm))
  all_comp[i,11] <- 1-(as.numeric(all_comp[i,10])/nrow(lb_rpkm))
  all_comp[i,15] <- 1-(as.numeric(all_comp[i,14])/nrow(lmaj_rpkm))
}

lmxrank <- lmex_rpkm[,5:10]
for(i in 1:ncol(lmxrank)){
  lmxrank <- lmxrank[order(as.numeric(lmxrank[,i]),decreasing = T),]
  lmxrank[,i] <- c(1:nrow(lmxrank))
  for(j in 1:nrow(lmxrank)){
    lmxrank[j,i] <- 1-(as.numeric(lmxrank[j,i])/nrow(lmxrank))
  }
}
lmxrank <- lmxrank[rownames(lmxrank) %in% all_comp[,2],]
lmxrank <- lmxrank[match(all_comp[,2],rownames(lmxrank)),]
lmxvitrorank <- lmexvitro_rpkm[,c(5,10,15)]
for(i in 1:ncol(lmxvitrorank)){
  lmxvitrorank <- lmxvitrorank[order(as.numeric(lmxvitrorank[,i]),decreasing = T),]
  lmxvitrorank[,i] <- c(1:nrow(lmxvitrorank))
  for(j in 1:nrow(lmxvitrorank)){
    lmxvitrorank[j,i] <- 1-(as.numeric(lmxvitrorank[j,i])/nrow(lmxvitrorank))
  }
}
lmxvitrorank <- lmxvitrorank[rownames(lmxvitrorank) %in% all_comp[,2],]
lmxvitrorank <- lmxvitrorank[match(all_comp[,2],rownames(lmxvitrorank)),]
lbrrank <- lb_rpkm
for(i in 1:ncol(lbrrank)){
  lbrrank <- lbrrank[order(as.numeric(lbrrank[,i]),decreasing = T),]
  lbrrank[,i] <- c(1:nrow(lbrrank))
  for(j in 1:nrow(lbrrank)){
    lbrrank[j,i] <- 1-(as.numeric(lbrrank[j,i])/nrow(lbrrank))
  }
}
lbrrank <- lbrrank[rownames(lbrrank) %in% all_comp[,9],]
lbrrank <- lbrrank[match(all_comp[,9],rownames(lbrrank)),]
lmajrank <- lmaj_rpkm[,21:24]
for(i in 1:ncol(lmajrank)){
  lmajrank <- lmajrank[order(as.numeric(lmajrank[,i]),decreasing = T),]
  lmajrank[,i] <- c(1:nrow(lmajrank))
  for(j in 1:nrow(lmajrank)){
    lmajrank[j,i] <- 1-(as.numeric(lmajrank[j,i])/nrow(lmajrank))
  }
}
lmajrank <- lmajrank[rownames(lmajrank) %in% all_comp[,13],]
lmajrank <- lmajrank[match(all_comp[,13],rownames(lmajrank)),]

all_pctl <- cbind(lmxrank,lmxvitrorank,lbrrank,lmajrank)
pctl <- all_pctl
heatmap.2(pctl[rowMeans(all_pctl[,1:6])>0.95,],trace='none',
          col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
heatmap.2(pctl[rowMeans(all_pctl[,7:9])>0.95,],trace='none',
          col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
heatmap.2(pctl[rowMeans(all_pctl[,10:15])>0.95,],trace='none',
          col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
heatmap.2(pctl[rowMeans(all_pctl[,16:19])>0.9,],trace='none',
          col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
datCor <- cor(pctl,method='pearson')
heatmap.2(datCor,
          margins=c(10, 10),
          scale="none",breaks=seq(0,1,length=101),
          trace="none",col= colorRampPalette(brewer.pal(9, "GnBu"))(100),
          srtCol=45,main='Pearson correlation')

q.all <- log2CPM(all_pctl,
                 lib.size = c(colSums(lmex_rpkm)[5:10],colSums(lmexvitro_rpkm)[c(5,10,15)],
                              colSums(lb_rpkm),colSums(lmaj_rpkm)[21:24]))
s <- makeSVD(all_pctl)
col <- c(rep("red",times=6),rep("blue",times=3),rep("orange",times=6),rep("purple",times=4))
plotPC(s$v,
       s$d,
       col="black",
       pch=22,
       bg=col, cex=2.6)
library(pca3d)
pca_3d <- prcomp(t(all_pctl))
pca3d(pca_3d, components = 1:3,
      group = col)
pcRes(s$v, s$d, col)[1:5,]


pctl <- read.table('allspec_rank.txt',sep='\t',header=T)[,1:4]

sum(as.numeric(pctl[,1]) > 0.95 & as.numeric(pctl[,2]) > 0.95)/sum(pctl[,1] > 0.95)
sum(as.numeric(pctl[,1]) > 0.95 & as.numeric(pctl[,3]) > 0.95)/sum(pctl[,1] > 0.95)
sum(as.numeric(pctl[,1]) > 0.95 & as.numeric(pctl[,4]) > 0.95)/sum(pctl[,1] > 0.95)
sum(as.numeric(pctl[,2]) > 0.95 & as.numeric(pctl[,1]) > 0.95)/sum(pctl[,2] > 0.95)
sum(as.numeric(pctl[,2]) > 0.95 & as.numeric(pctl[,3]) > 0.95)/sum(pctl[,2] > 0.95)
sum(as.numeric(pctl[,2]) > 0.95 & as.numeric(pctl[,4]) > 0.95)/sum(pctl[,2] > 0.95)
sum(as.numeric(pctl[,3]) > 0.95 & as.numeric(pctl[,1]) > 0.95)/sum(pctl[,3] > 0.95)
sum(as.numeric(pctl[,3]) > 0.95 & as.numeric(pctl[,2]) > 0.95)/sum(pctl[,3] > 0.95)
sum(as.numeric(pctl[,3]) > 0.95 & as.numeric(pctl[,4]) > 0.95)/sum(pctl[,3] > 0.95)
sum(as.numeric(pctl[,4]) > 0.95 & as.numeric(pctl[,1]) > 0.95)/sum(pctl[,4] > 0.95)
sum(as.numeric(pctl[,4]) > 0.95 & as.numeric(pctl[,2]) > 0.95)/sum(pctl[,4] > 0.95)
sum(as.numeric(pctl[,4]) > 0.95 & as.numeric(pctl[,3]) > 0.95)/sum(pctl[,4] > 0.95)

pctl <- pctl[order(as.numeric(pctl[,1]),decreasing=T),]
heatmap.2(apply(pctl[pctl[,1] > 0.8,],2,as.numeric),trace='none',
          Rowv = F, Colv = F, dendrogram = 'none',col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
pctl <- pctl[order(as.numeric(pctl[,2]),decreasing=T),]
heatmap.2(apply(pctl[pctl[,2] > 0.8,],2,as.numeric),trace='none',
          Rowv = F, Colv = F, dendrogram = 'none',col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
pctl <- pctl[order(as.numeric(pctl[,3]),decreasing=T),]
heatmap.2(apply(pctl[pctl[,3] > 0.8,],2,as.numeric),trace='none',
          Rowv = F, Colv = F, dendrogram = 'none',col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
pctl <- pctl[order(as.numeric(pctl[,4]),decreasing=T),]
heatmap.2(apply(pctl[pctl[,4] > 0.8,],2,as.numeric),trace='none',
          Rowv = F, Colv = F, dendrogram = 'none',col = colorRampPalette(brewer.pal(9, "GnBu"))(500))
LS0tCnRpdGxlOiAiTGVpc2htYW5pYSBzdHJhaW5zIDIwMTgwNTogQ29sbGVjdGluZyBhbm5vdGF0aW9uIGluZm9ybWF0aW9uLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgIGNvbGxhcHNlZDogZmFsc2UKICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgbGlicmFyeShocGdsdG9vbHMpCiAgdHQgPC0gc20oZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQogIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKICBrbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQogIG9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCiAgZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMikpCiAgdmVyIDwtICIyMDE4MDUwNyIKICBwcmV2aW91c19maWxlIDwtIHBhc3RlMCgiaW5kZXhfdiIsIHZlciwgIi5SbWQiKQoKICB0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZT1nc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IlxcLnJkYVxcLnh6IiwgeD1wcmV2aW91c19maWxlKSkpKQogIHJtZF9maWxlIDwtIHBhc3RlMCgiMjAxODAyMjBfbGVpc2hfY29tcGFsbC5SbWQiKQogIHNhdmVmaWxlIDwtIGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iXFwucmRhXFwueHoiLCB4PXJtZF9maWxlKQp9CmBgYAoKIyBBbiBhdHRlbXB0IGF0IHJ1bm5pbmcgU3RldmUncyBhbmFseXNlcyB3aXRob3V0IHNpZ25pZmljYW50IChhbnk/KSBtb2RpZmljYXRpb25zLgoKTXkgZ29hbCBpbiB0aGlzIGRvY3VtZW50IGlzIHRvIHJlcGVhdCBTdGV2ZSdzIGFuYWx5c2VzIHdpdGhvdXQgY2hhbmdpbmcgYW55dGhpbmcKbW9yZSBzaWduaWZjYW50IHRoYW4gdGhlIGZhY3QgdGhhdCBJIGNvcGllZCBoaXMgY291bnQgdGFibGVzIHRvIHRoZSBkaXJlY3RvcnkKJ2NvdW50X3RhYmxlcycuCgpXaGVuIEkgZG8gY2hhbmdlIHRoaW5ncywgSSB3aWxsIGxlYXZlIHRoZSBvcmlnaW5hbCB0ZXh0IGluIGEgbm9uLWV2YWx1YXRlZCBibG9jawppbW1lZGlhdGVseSBiZWZvcmUgbXkgbW9kaWZpZWQgdmVyc2lvbi4gIFRoZSBjb21wbGV0ZWx5IHVubW9kaWZpZWQgc2NyaXB0IGlzIGluCnRoZSBzY3JpcHRzLyBkaXJlY3RvcnkuCgpJIHdpbGwgYWxzbyBicmVhayB1cCB0aGUgdmFyaW91cyBwaWVjZXMgaW50byBzZXBhcmF0ZSBibG9ja3Mgc28gdGhhdCBJIGNhbgpjb21tZW50IG9uIGFueXRoaW5nIGFsb25nIHRoZSB3YXkuCgpgYGB7ciBsb2FkaW5nfQpyZXF1aXJlKHJ0cmFja2xheWVyKQpsaWJyYXJ5KGdwbG90cykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZWRnZVIpCmxpYnJhcnkoY2JjYlNFUSkKbGlicmFyeShocGdsdG9vbHMpCmBgYAoKIyBSZWFkIHRoZSBjb3VudCB0YWJsZXMsIG9yaWdpbmFsCgpJIGFtIG9mIGNvdXJzZSBub3Qgd29ya2luZyBpbiBkcm9wYm94IGFuZCBJIHB1dCBTdGV2ZSdzIGNvdW50IHRhYmxlcyBpbnRvIGEKZGlyZWN0b3J5ICdjb3VudF90YWJsZXMnIGZyb20gd2l0aGluIHRoaXMgdHJlZS4KCmBgYHtyIGNvdW50X3RhYmxlcywgZXZhbD1GQUxTRX0Kc2V0d2QoJ34vRHJvcGJveC9sYWJfd29yay9MZWlzaG1hbmlhIFJlc2VhcmNoL0xhJykKCiMjIyMjIyBSZWFkaW5nICYgY29sbGFwc2luZyB0YWJsZXMsIGNhbGN1bGF0aW5nIFJQS01zICMjIyMjIwpocGdsMDcyMS5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjFfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyMSIpKQpocGdsMDcyMi5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjJfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyMiIpKQpocGdsMDcyMy5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjNfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyMyIpKQpocGdsMDcyNC5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjRfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyNCIpKQpocGdsMDcyNS5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjVfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyNSIpKQpocGdsMDcyNi5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjZfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyNiIpKQpocGdsMDcyNy5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjdfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyNyIpKQpocGdsMDcyOC5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjhfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyOCIpKQpocGdsMDcyOS5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MjlfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyOSIpKQpocGdsMDczMC5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiaHBnbDA3MzBfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDczMCIpKQpgYGAKCkluIGNvbnZlcnNhdGlvbnMgd2l0aCBTdGV2ZSwgaXQgc3BwZWFycyB0aGF0IHRoZSBmaXJzdCA0IHRhYmxlcyB3ZXJlIG5vdCB1c2VkLgoKYGBge3IgbXlfY291bnRfdGFibGVzfQojIyMjIyMgUmVhZGluZyAmIGNvbGxhcHNpbmcgdGFibGVzLCBjYWxjdWxhdGluZyBSUEtNcyAjIyMjIyMKIyNocGdsMDcyMS5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzIxX2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MjEiKSkKIyNocGdsMDcyMi5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzIyX2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MjIiKSkKIyNocGdsMDcyMy5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzIzX2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MjMiKSkKIyNocGdsMDcyNC5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzI0X2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MjQiKSkKaHBnbDA3MjUubG1leGljYW5hIDwtIHJlYWQudGFibGUoImNvdW50X3RhYmxlcy9ocGdsMDcyNV9sbWV4aWNhbmEuY291bnQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwNzI1IikpCmhwZ2wwNzI2LmxtZXhpY2FuYSA8LSByZWFkLnRhYmxlKCJjb3VudF90YWJsZXMvaHBnbDA3MjZfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyNiIpKQpocGdsMDcyNy5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzI3X2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MjciKSkKaHBnbDA3MjgubG1leGljYW5hIDwtIHJlYWQudGFibGUoImNvdW50X3RhYmxlcy9ocGdsMDcyOF9sbWV4aWNhbmEuY291bnQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwNzI4IikpCmhwZ2wwNzI5LmxtZXhpY2FuYSA8LSByZWFkLnRhYmxlKCJjb3VudF90YWJsZXMvaHBnbDA3MjlfbG1leGljYW5hLmNvdW50Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDcyOSIpKQpocGdsMDczMC5sbWV4aWNhbmEgPC0gcmVhZC50YWJsZSgiY291bnRfdGFibGVzL2hwZ2wwNzMwX2xtZXhpY2FuYS5jb3VudCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA3MzAiKSkKYGBgCgojIE1ha2luZyBhIGxpc3Qgb2YgY291bnRzLCBvcmlnaW5hbAoKYGBge3IgY291bnRfbGlzdF9vcmlnaW5hbH0KIyNsaXN0Lm9mLmRhdGEuZnJhbWVzIDwtIGxpc3QoaHBnbDA3MjEubG1leGljYW5hLGhwZ2wwNzIyLmxtZXhpY2FuYSxocGdsMDcyMy5sbWV4aWNhbmEsaHBnbDA3MjQubG1leGljYW5hLGhwZ2wwNzI1LmxtZXhpY2FuYSxocGdsMDcyNi5sbWV4aWNhbmEsaHBnbDA3MjcubG1leGljYW5hLGhwZ2wwNzI4LmxtZXhpY2FuYSxocGdsMDcyOS5sbWV4aWNhbmEsaHBnbDA3MzAubG1leGljYW5hKQpsaXN0Lm9mLmRhdGEuZnJhbWVzIDwtIGxpc3QoaHBnbDA3MjUubG1leGljYW5hLGhwZ2wwNzI2LmxtZXhpY2FuYSxocGdsMDcyNy5sbWV4aWNhbmEsaHBnbDA3MjgubG1leGljYW5hLGhwZ2wwNzI5LmxtZXhpY2FuYSxocGdsMDczMC5sbWV4aWNhbmEpCmNvdW50c1RhYmxlID0gUmVkdWNlKGZ1bmN0aW9uKC4uLikgbWVyZ2UoLi4uLCBieT0iaWQiLCBhbGw9VCksIGxpc3Qub2YuZGF0YS5mcmFtZXMpCmNvdW50c1RhYmxlIDwtIGNvdW50c1RhYmxlWy1jKDE6NSksXQpjb3VudHNUYWJsZSA8LSBjb3VudHNUYWJsZVstZ3JlcCgicmZhbXNjYW4iLGNvdW50c1RhYmxlJGlkKSxdCnJvd25hbWVzKGNvdW50c1RhYmxlKSA8LSBjb3VudHNUYWJsZSRpZApjb3VudHNUYWJsZSA8LSBkYXRhLm1hdHJpeChjb3VudHNUYWJsZVssLTFdKQojIyBUaGlzIGlzIGludGVyZXN0aW5nLCBkb2luZyB0aGlzIHBlY3VsaWFyIHNhcHBseSBzdHJzcGxpdC9zdWJzdHIgb3BlcmF0aW9uIGFsbG93cyBvbmUgdG8gaGF2ZQojIyBub24tdW5pcXVlIHJvd25hbWVzIGluIGEgbWF0cml4Lgpyb3duYW1lcyhjb3VudHNUYWJsZSkgPC0gc2FwcGx5KHJvd25hbWVzKGNvdW50c1RhYmxlKSwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwnLScpW1sxXV1bMV0pCnJvd25hbWVzKGNvdW50c1RhYmxlKSA8LSBzYXBwbHkocm93bmFtZXMoY291bnRzVGFibGUpLCBmdW5jdGlvbih4KSBzdWJzdHIoeCw2LG5jaGFyKHgpKSkKYGBgCgpgYGB7ciBteV9jb3VudF9saXN0fQpkZl9saXN0IDwtIGxpc3QoaHBnbDA3MjUubG1leGljYW5hLAogICAgICAgICAgICAgICAgaHBnbDA3MjYubG1leGljYW5hLAogICAgICAgICAgICAgICAgaHBnbDA3MjcubG1leGljYW5hLAogICAgICAgICAgICAgICAgaHBnbDA3MjgubG1leGljYW5hLAogICAgICAgICAgICAgICAgaHBnbDA3MjkubG1leGljYW5hLAogICAgICAgICAgICAgICAgaHBnbDA3MzAubG1leGljYW5hKQpteV9jb3VudHMgPC0gUmVkdWNlKGZ1bmN0aW9uKC4uLikgbWVyZ2UoLi4uLCBieT0iaWQiLCBhbGw9VFJVRSksIGRmX2xpc3QpCnJvd25hbWVzKG15X2NvdW50cykgPC0gbXlfY291bnRzW1siaWQiXV0KbXlfY291bnRzIDwtIG15X2NvdW50c1ssIC0xXQprZWVwZXJzX2lkeCA8LSAhZ3JlcGwocGF0dGVybj0iXl8iLCB4PXJvd25hbWVzKG15X2NvdW50cykpCm15X2NvdW50cyA8LSBteV9jb3VudHNba2VlcGVyc19pZHgsIF0Ka2VlcGVyc19pZHggPC0gIWdyZXBsKHBhdHRlcm49InJmYW1zY2FuIiwgeD1yb3duYW1lcyhteV9jb3VudHMpKQpteV9jb3VudHMgPC0gbXlfY291bnRzW2tlZXBlcnNfaWR4LCBdCnJvd25hbWVzKG15X2NvdW50cykgPC0gZ3N1YihwYXR0ZXJuPSJeZXhvbl8iLCByZXBsYWNlbWVudD0iIiwgeD1yb3duYW1lcyhteV9jb3VudHMpKQpyb3duYW1lcyhteV9jb3VudHMpIDwtIGdzdWIocGF0dGVybj0iXFwtMSQiLCByZXBsYWNlbWVudD0iIiwgeD1yb3duYW1lcyhteV9jb3VudHMpKQpgYGAKCiMgU3VtbWluZyBleG9ucywgb3JpZ2luYWwKClRoaXMgaXMgYW4gaW50ZXJlc3RpbmcgbWV0aG9kIG9mIGdldHRpbmcgYWxsIHRoZSBleG9uIGRhdGEgZnJvbSBtdWx0aXBsZQp0cmFuc2NyaXB0cyBpbnRvIGEgZmluYWwgY291bnQgdGFibGUuCgpgYGB7ciBzdW1fZXhvbnNfb3JpZ2luYWwsIGV2YWw9RkFMU0V9CiMjbG1leC5jb2xsYXBzZSA8LSBtYXRyaXgoMCwwLG5yb3c9bGVuZ3RoKHVuaXF1ZShyb3duYW1lcyhjb3VudHNUYWJsZSkpKSxuY29sPTEwKQojIyBhdGIgY2hhbmdlZCB0aGUgc3RhdGljIG5jb2w9MTAgdG8gdGhlIG51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50c1RhYmxlCiMjIGJlY2F1c2Ugd2UgYXJlIG5vIGxvbmdlciB1c2luZyA3MjEsNzIyLDcyMyw3MjQuCmxtZXguY29sbGFwc2UgPC0gbWF0cml4KDAsMCxucm93PWxlbmd0aCh1bmlxdWUocm93bmFtZXMoY291bnRzVGFibGUpKSksbmNvbD1uY29sKGNvdW50c1RhYmxlKSkKcm93bmFtZXMobG1leC5jb2xsYXBzZSkgPC0gdW5pcXVlKHJvd25hbWVzKGNvdW50c1RhYmxlKSkKZm9yKGkgaW4gMTpucm93KGxtZXguY29sbGFwc2UpKXsKICB0ZW1wLm1hdCA8LSBzdWJzZXQoY291bnRzVGFibGUscm93bmFtZXMoY291bnRzVGFibGUpICVpbiUgcm93bmFtZXMobG1leC5jb2xsYXBzZSlbaV0pCiAgaWYobnJvdyh0ZW1wLm1hdCk9PTEpewogICAgbG1leC5jb2xsYXBzZVtpLF0gPC0gdGVtcC5tYXQKICB9CiAgaWYobnJvdyh0ZW1wLm1hdCk+MSl7CiAgICBsbWV4LmNvbGxhcHNlW2ksXSA8LSBjb2xTdW1zKGNvdW50c1RhYmxlW3Jvd25hbWVzKGNvdW50c1RhYmxlKSAlaW4lIHJvd25hbWVzKGxtZXguY29sbGFwc2UpW2ldLF0pCiAgfQp9CiMjIEFkZGVkIGJ5IGF0Ygpjb2xuYW1lcyhsbWV4LmNvbGxhcHNlKSA8LSBjb2xuYW1lcyhjb3VudHNUYWJsZSkKYGBgCgojIE15IG1ldGhvZCBvZiBzdW1taW5nIGV4b25zCgpgYGB7ciBzdW1fZXhvbnN9Cm11bHRpX2V4b25faWR4IDwtIGdyZXAocGF0dGVybj0iXFwtXFxkKyQiLCB4PXJvd25hbWVzKG15X2NvdW50cykpCmZvciAoaWR4IGluIG11bHRpX2V4b25faWR4KSB7CiAgZ2VuZSA8LSBnc3ViKHBhdHRlcm49IlxcLVxcZCskIiwgcmVwbGFjZW1lbnQ9IiIsIHg9cm93bmFtZXMobXlfY291bnRzKVtpZHhdKQogIGV4b25fY291bnRzIDwtIG15X2NvdW50c1tpZHgsIF0KICBnZW5lX2NvdW50cyA8LSBteV9jb3VudHNbZ2VuZSwgXQogIHRvdGFsX2NvdW50cyA8LSBnZW5lX2NvdW50cyArIGV4b25fY291bnRzCiAgbXlfY291bnRzW2dlbmUsIF0gPC0gdG90YWxfY291bnRzCn0KbXlfY291bnRzIDwtIG15X2NvdW50c1stbXVsdGlfZXhvbl9pZHgsIF0KbXlfY291bnRzIDwtIGFzLm1hdHJpeChteV9jb3VudHMpCmFsbC5lcXVhbChteV9jb3VudHMsIGxtZXguY29sbGFwc2UpCmBgYAoKCgpgYGB7ciB0aGVfcmVzdCwgZXZhbD1GQUxTRX0KbG1leHZpdHJvLmNvdW50c1RhYmxlIDwtIHJlYWQudGFibGUoIi4uL0xiLzIwMTQxMjExX0xtZXhpY2FuYTgxXzQzNC00MzVfNDM3XzQ0MF80NDNfNDQ2XzQ1My00NTRfNDU4XzQ2Ml80NjZfNDcwXzQ5MS00OTJfNDk2XzUwMF81MDRfNTA4X0NEU29ubHkuY291bnQiLCBoZWFkZXI9VCkKcm93bmFtZXMobG1leHZpdHJvLmNvdW50c1RhYmxlKSA8LSBsbWV4dml0cm8uY291bnRzVGFibGUkaWQKbG1leHZpdHJvLmNvdW50c1RhYmxlIDwtIGRhdGEubWF0cml4KGxtZXh2aXRyby5jb3VudHNUYWJsZVssYygyOjYsODoxMiwxNDoxOCldKQpyb3duYW1lcyhsbWV4dml0cm8uY291bnRzVGFibGUpIDwtIHNhcHBseShyb3duYW1lcyhsbWV4dml0cm8uY291bnRzVGFibGUpLCBmdW5jdGlvbih4KSBzdHJzcGxpdCh4LCctJylbWzFdXVsxXSkKbG1leHZpdHJvLmNvbGxhcHNlIDwtIG1hdHJpeCgwLDAsbnJvdz1sZW5ndGgodW5pcXVlKHJvd25hbWVzKGxtZXh2aXRyby5jb3VudHNUYWJsZSkpKSxuY29sPTE1KQpyb3duYW1lcyhsbWV4dml0cm8uY29sbGFwc2UpIDwtIHVuaXF1ZShyb3duYW1lcyhsbWV4dml0cm8uY291bnRzVGFibGUpKQpmb3IoaSBpbiAxOm5yb3cobG1leHZpdHJvLmNvbGxhcHNlKSl7CiAgdGVtcC5tYXQgPC0gc3Vic2V0KGxtZXh2aXRyby5jb3VudHNUYWJsZSxyb3duYW1lcyhsbWV4dml0cm8uY291bnRzVGFibGUpICVpbiUgcm93bmFtZXMobG1leHZpdHJvLmNvbGxhcHNlKVtpXSkKICBpZihucm93KHRlbXAubWF0KT09MSl7CiAgICBsbWV4dml0cm8uY29sbGFwc2VbaSxdIDwtIHRlbXAubWF0CiAgfQogIGlmKG5yb3codGVtcC5tYXQpPjEpewogICAgbG1leHZpdHJvLmNvbGxhcHNlW2ksXSA8LSBjb2xTdW1zKGxtZXh2aXRyby5jb3VudHNUYWJsZVtyb3duYW1lcyhsbWV4dml0cm8uY291bnRzVGFibGUpICVpbiUgcm93bmFtZXMobG1leHZpdHJvLmNvbGxhcHNlKVtpXSxdKQogIH0KfQoKbGIuY291bnRzVGFibGUgPC0gcmVhZC50YWJsZSgnLi4vTGIvMjAxNzAyMTVfTGJfYWxsZ2VuZXNfY291bnRUYWJsZS50eHQnKSAjUmVhZCBpbiBMYiBjb3VudHMKbGIuY291bnRzVGFibGUgPC0gZGF0YS5tYXRyaXgobGIuY291bnRzVGFibGVbLGMoMiwzLDUsMTYsMTksMjMpXSkKcm93bmFtZXMobGIuY291bnRzVGFibGUpIDwtIHNhcHBseShyb3duYW1lcyhsYi5jb3VudHNUYWJsZSksIGZ1bmN0aW9uKHgpIHN0cnNwbGl0KHgsJy0nKVtbMV1dWzFdKQpsYi5jb2xsYXBzZSA8LSBtYXRyaXgoMCwwLG5yb3c9bGVuZ3RoKHVuaXF1ZShyb3duYW1lcyhsYi5jb3VudHNUYWJsZSkpKSxuY29sPTYpCnJvd25hbWVzKGxiLmNvbGxhcHNlKSA8LSB1bmlxdWUocm93bmFtZXMobGIuY291bnRzVGFibGUpKQpmb3IoaSBpbiAxOm5yb3cobGIuY29sbGFwc2UpKXsKICB0ZW1wLm1hdCA8LSBzdWJzZXQobGIuY291bnRzVGFibGUscm93bmFtZXMobGIuY291bnRzVGFibGUpICVpbiUgcm93bmFtZXMobGIuY29sbGFwc2UpW2ldKQogIGlmKG5yb3codGVtcC5tYXQpPT0xKXsKICAgIGxiLmNvbGxhcHNlW2ksXSA8LSB0ZW1wLm1hdAogIH0KICBpZihucm93KHRlbXAubWF0KT4xKXsKICAgIGxiLmNvbGxhcHNlW2ksXSA8LSBjb2xTdW1zKGxiLmNvdW50c1RhYmxlW3Jvd25hbWVzKGxiLmNvdW50c1RhYmxlKSAlaW4lIHJvd25hbWVzKGxiLmNvbGxhcHNlKVtpXSxdKQogIH0KfQpsYi5jb2xsYXBzZSA8LSBsYi5jb2xsYXBzZVshcm93bmFtZXMobGIuY29sbGFwc2UpPT0nTGJyTS4yNi4wMjEwYScsXQpyb3duYW1lcyhsYi5jb2xsYXBzZSlbcm93bmFtZXMobGIuY29sbGFwc2UpPT0nTGJyTS4yMC4wMTkxJ10gPC0gJ0xick0uMTAuMDE5MScKCnsKICBsbWFqb3IuNzJjb3VudHMgPC0gcmVhZC50YWJsZSgnLi4vTGIvTG1ham9yXzcyaHJzLnR4dCcsaGVhZGVyPUYsc2VwPSdcdCcsY29sLm5hbWVzPWMoImlkIiwibG03Mi4xIiwibG03Mi4yIiwibG03Mi4zIiwibG03Mi40IikpCiAgaHBnbDAzNjQubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwMzY0X0xtYWpvcjYwXzIwMTQwMzI5LnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDAzNjQiKSkKICBocGdsMDM3NC5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDAzNzRfTG1ham9yNjBfMjAxNDAzMjkudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDM3NCIpKQogIGhwZ2wwMzk3LmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDM5N19MbWFqb3I2MF8yMDE0MDcxMi50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwMzk3IikpCiAgaHBnbDA0NTYubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwNDU2X0xtYWpvcjYwXzIwMTQxMDAxLnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA0NTYiKSkKICBocGdsMDQ5NC5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDA0OTRfTG1ham9yNjBfMjAxNDEyMTEudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDQ5NCIpKQogIGhwZ2wwMzY2LmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDM2Nl9MbWFqb3I2MF8yMDE0MDMyOS50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwMzY2IikpCiAgaHBnbDAzNzYubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwMzc2X0xtYWpvcjYwXzIwMTQwMzI5LnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDAzNzYiKSkKICBocGdsMDM5OS5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDAzOTlfTG1ham9yNjBfMjAxNDA3MTIudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDM5OSIpKQogIGhwZ2wwNDU5LmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDQ1OV9MbWFqb3I2MF8yMDE0MTAwMS50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwNDU5IikpCiAgaHBnbDA0OTcubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwNDk3X0xtYWpvcjYwXzIwMTQxMjExLnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA0OTciKSkKICBocGdsMDM2OC5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDAzNjhfTG1ham9yNjBfMjAxNDAzMjkudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDM2OCIpKQogIGhwZ2wwMzc4LmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDM3OF9MbWFqb3I2MF8yMDE0MDMyOS50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwMzc4IikpCiAgaHBnbDA0MDEubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwNDAxX0xtYWpvcjYwXzIwMTQwNzEyLnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA0MDEiKSkKICBocGdsMDQ2My5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDA0NjNfTG1ham9yNjBfMjAxNDEwMDEudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDQ2MyIpKQogIGhwZ2wwNTAxLmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDUwMV9MbWFqb3I2MF8yMDE0MTIxMS50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwNTAxIikpCiAgaHBnbDAzNzAubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwMzcwX0xtYWpvcjYwXzIwMTQwMzI5LnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDAzNzAiKSkKICBocGdsMDM4MC5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDAzODBfTG1ham9yNjBfMjAxNDAzMjkudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDM4MCIpKQogIGhwZ2wwNDAzLmxtYWpvciA8LSByZWFkLnRhYmxlKCJodHNlcV9IUEdMMDQwM19MbWFqb3I2MF8yMDE0MDcxMi50eHQiLGNvbC5uYW1lcz1jKCJpZCIsImhwZ2wwNDAzIikpCiAgaHBnbDA0NjcubG1ham9yIDwtIHJlYWQudGFibGUoImh0c2VxX0hQR0wwNDY3X0xtYWpvcjYwXzIwMTQxMDAxLnR4dCIsY29sLm5hbWVzPWMoImlkIiwiaHBnbDA0NjciKSkKICBocGdsMDUwNS5sbWFqb3IgPC0gcmVhZC50YWJsZSgiaHRzZXFfSFBHTDA1MDVfTG1ham9yNjBfMjAxNDEyMTEudHh0Iixjb2wubmFtZXM9YygiaWQiLCJocGdsMDUwNSIpKQoKICBsaXN0Lm9mLmRhdGEuZnJhbWVzIDwtIGxpc3QoaHBnbDAzNjQubG1ham9yLGhwZ2wwMzc0LmxtYWpvcixocGdsMDM5Ny5sbWFqb3IsaHBnbDA0NTYubG1ham9yLGhwZ2wwNDk0LmxtYWpvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHBnbDAzNjYubG1ham9yLGhwZ2wwMzc2LmxtYWpvcixocGdsMDM5OS5sbWFqb3IsaHBnbDA0NTkubG1ham9yLGhwZ2wwNDk3LmxtYWpvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHBnbDAzNjgubG1ham9yLGhwZ2wwMzc4LmxtYWpvcixocGdsMDQwMS5sbWFqb3IsaHBnbDA0NjMubG1ham9yLGhwZ2wwNTAxLmxtYWpvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHBnbDAzNzAubG1ham9yLGhwZ2wwMzgwLmxtYWpvcixocGdsMDQwMy5sbWFqb3IsaHBnbDA0NjcubG1ham9yLGhwZ2wwNTA1LmxtYWpvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG1ham9yLjcyY291bnRzKQp9CmxtYWouY291bnRzVGFibGUgPSBSZWR1Y2UoZnVuY3Rpb24oLi4uKSBtZXJnZSguLi4sIGJ5PSJpZCIsIGFsbD1UKSwgbGlzdC5vZi5kYXRhLmZyYW1lcykKbG1hai5jb3VudHNUYWJsZSA8LSBsbWFqLmNvdW50c1RhYmxlWy1jKDE6Miw5NDY2Ojk0NzQpLF0Kcm93bmFtZXMobG1hai5jb3VudHNUYWJsZSkgPC0gbG1hai5jb3VudHNUYWJsZSRpZApsbWFqLmNvdW50c1RhYmxlIDwtIGRhdGEubWF0cml4KGxtYWouY291bnRzVGFibGVbLC0xXSkKcm93bmFtZXMobG1hai5jb3VudHNUYWJsZSkgPC0gc2FwcGx5KHJvd25hbWVzKGxtYWouY291bnRzVGFibGUpLCBmdW5jdGlvbih4KSBzdWJzdHIoeCw2LG5jaGFyKHgpKSkKcm93bmFtZXMobG1hai5jb3VudHNUYWJsZSkgPC0gc2FwcGx5KHJvd25hbWVzKGxtYWouY291bnRzVGFibGUpLCBmdW5jdGlvbih4KSBzdHJzcGxpdCh4LCctJylbWzFdXVsxXSkKbG1hai5jb2xsYXBzZSA8LSBtYXRyaXgoMCwwLG5yb3c9bGVuZ3RoKHVuaXF1ZShyb3duYW1lcyhsbWFqLmNvdW50c1RhYmxlKSkpLG5jb2w9MjQpCnJvd25hbWVzKGxtYWouY29sbGFwc2UpIDwtIHVuaXF1ZShyb3duYW1lcyhsbWFqLmNvdW50c1RhYmxlKSkKZm9yKGkgaW4gMTpucm93KGxtYWouY29sbGFwc2UpKXsKICB0ZW1wLm1hdCA8LSBzdWJzZXQobG1hai5jb3VudHNUYWJsZSxyb3duYW1lcyhsbWFqLmNvdW50c1RhYmxlKSAlaW4lIHJvd25hbWVzKGxtYWouY29sbGFwc2UpW2ldKQogIGlmKG5yb3codGVtcC5tYXQpPT0xKXsKICAgIGxtYWouY29sbGFwc2VbaSxdIDwtIHRlbXAubWF0CiAgfQogIGlmKG5yb3codGVtcC5tYXQpPjEpewogICAgbG1hai5jb2xsYXBzZVtpLF0gPC0gY29sU3VtcyhsbWFqLmNvdW50c1RhYmxlW3Jvd25hbWVzKGxtYWouY291bnRzVGFibGUpICVpbiUgcm93bmFtZXMobG1hai5jb2xsYXBzZSlbaV0sXSkKICB9Cn0KCmxtZXguZGIgPC0gaW1wb3J0LmdmZignLi4vTGIvVHJpVHJ5cERCLTI3X0xtZXhpY2FuYU1IT01HVDIwMDFVMTEwMy5nZmYnKQpsbWV4Lmhpc3QgPC0gZGF0YS5mcmFtZShjaHI9c2VxbmFtZXMobG1leC5kYiksSUQ9bG1leC5kYiRJRCwKICAgICAgICAgICAgICAgICAgICAgICAgTmFtZT1sbWV4LmRiJHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9d2lkdGgobG1leC5kYiksCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0PXN0YXJ0KGxtZXguZGIpLGVuZD1lbmQobG1leC5kYikpCmxtZXguaGlzdCA8LSBsbWV4Lmhpc3RbbG1leC5oaXN0JE5hbWUgJWluJSAnQ0RTJyxdCmxtZXhoaXN0LmNvbGxhcHNlIDwtIG1hdHJpeCgwLDAsbnJvdz1ucm93KGxtZXguY29sbGFwc2UpLG5jb2w9MikKcm93bmFtZXMobG1leGhpc3QuY29sbGFwc2UpIDwtIHJvd25hbWVzKGxtZXguY29sbGFwc2UpCmZvcihpIGluIDE6bnJvdyhsbWV4aGlzdC5jb2xsYXBzZSkpewogIHRlbXAubWF0IDwtIGxtZXguaGlzdFtncmVwKHJvd25hbWVzKGxtZXhoaXN0LmNvbGxhcHNlKVtpXSxsbWV4Lmhpc3QkSUQpLF0KICBpZihucm93KHRlbXAubWF0KT09MSl7CiAgICBsbWV4aGlzdC5jb2xsYXBzZVtpLDJdIDwtIHRlbXAubWF0JHNpemUKICB9CiAgaWYobnJvdyh0ZW1wLm1hdCk+MSl7CiAgICBsbWV4aGlzdC5jb2xsYXBzZVtpLDJdIDwtIHN1bSh0ZW1wLm1hdCRzaXplKQogIH0KfQpsbWV4X3Jwa20gPC0gcnBrbShsbWV4LmNvbGxhcHNlLGFzLm51bWVyaWMobG1leGhpc3QuY29sbGFwc2VbLDJdKSkKbG1leHZpdHJvX3Jwa20gPC0gcnBrbShsbWV4dml0cm8uY29sbGFwc2UsYXMubnVtZXJpYyhsbWV4aGlzdC5jb2xsYXBzZVssMl0pKQoKbG1leF9ycGttIDwtIGxtZXhfcnBrbVtvcmRlcihyb3dTdW1zKGxtZXhfcnBrbVssNToxMF0pLGRlY3JlYXNpbmc9VCksXQpkYXRDb3IgPC0gY29yKGxtZXhfcnBrbVssNToxMF0pCmhlYXRtYXAuMihkYXRDb3IsCiAgICAgICAgICBtYXJnaW5zPWMoMTAsIDEwKSwKICAgICAgICAgIGxhYlJvdz1jKCdEQ0wuMScsJ0RDTC4yJywnRENMLjMnLCdEQ0wuNCcsJ0RDTC41JywnRENMLjYnKSwKICAgICAgICAgIGxhYkNvbD1jKCdEQ0wuMScsJ0RDTC4yJywnRENMLjMnLCdEQ0wuNCcsJ0RDTC41JywnRENMLjYnKSwKICAgICAgICAgIHNjYWxlPSJub25lIiwgY2VsbG5vdGUgPSBmb3JtYXQocm91bmQoZGF0Q29yLCAyKSwgbnNtYWxsID0gMCksCiAgICAgICAgICBicmVha3MgPSBzZXEoMCwxLDAuMDEpLAogICAgICAgICAgbm90ZWNleD0wLjUsIG5vdGVjb2wgPSAnYmxhY2snLCB0cmFjZT0ibm9uZSIsCiAgICAgICAgICBzcnRDb2w9NDUsbWFpbj0nUGVhcnNvbiBjb3JyZWxhdGlvbiAoUlBLTXMpJykKCmxiLmRiIDwtIGltcG9ydC5nZmYoIi4uL0xiL1RyaVRyeXBEQi0yNl9MYnJhemlsaWVuc2lzTUhPTUJSNzVNMjkwNC5nZmYiKQpsYi5oaXN0IDwtIGRhdGEuZnJhbWUoY2hyPXNlcW5hbWVzKGxiLmRiKSxJRD1sYi5kYiRJRCwKICAgICAgICAgICAgICAgICAgICAgIE5hbWU9bGIuZGIkdHlwZSwKICAgICAgICAgICAgICAgICAgICAgIHNpemU9d2lkdGgobGIuZGIpLAogICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9c3RhcnQobGIuZGIpLGVuZD1lbmQobGIuZGIpKQpsYi5oaXN0IDwtIGxiLmhpc3RbbGIuaGlzdCROYW1lICVpbiUgJ0NEUycsXQpsYmhpc3QuY29sbGFwc2UgPC0gbWF0cml4KDAsMCxucm93PW5yb3cobGIuY29sbGFwc2UpLG5jb2w9MikKcm93bmFtZXMobGJoaXN0LmNvbGxhcHNlKSA8LSByb3duYW1lcyhsYi5jb2xsYXBzZSkKZm9yKGkgaW4gMTpucm93KGxiaGlzdC5jb2xsYXBzZSkpewogIHRlbXAubWF0IDwtIGxiLmhpc3RbZ3JlcChyb3duYW1lcyhsYmhpc3QuY29sbGFwc2UpW2ldLGxiLmhpc3QkSUQpLF0KICBpZihucm93KHRlbXAubWF0KT09MSl7CiAgICBsYmhpc3QuY29sbGFwc2VbaSwyXSA8LSB0ZW1wLm1hdCRzaXplCiAgfQogIGlmKG5yb3codGVtcC5tYXQpPjEpewogICAgbGJoaXN0LmNvbGxhcHNlW2ksMl0gPC0gc3VtKHRlbXAubWF0JHNpemUpCiAgfQp9CmxiaGlzdC5jb2xsYXBzZVtyb3duYW1lcyhsYmhpc3QuY29sbGFwc2UpPT0iTGJyTS4xMC4wMTkxIiwyXSA8LSA2NDUKbGJfcnBrbSA8LSBycGttKGxiLmNvbGxhcHNlLGdlbmUubGVuZ3RoPWFzLm51bWVyaWMobGJoaXN0LmNvbGxhcHNlWywyXSkpCgpsbWFqb3IuZGIgPC0gaW1wb3J0LmdmZignLi4vTGIvVHJpVHJ5cERCLTI3X0xtYWpvckZyaWVkbGluLmdmZicpCmxtYWouaGlzdCA8LSBkYXRhLmZyYW1lKGNocj1zZXFuYW1lcyhsbWFqb3IuZGIpLElEPWxtYWpvci5kYiRJRCwKICAgICAgICAgICAgICAgICAgICAgICAgTmFtZT1sbWFqb3IuZGIkdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT13aWR0aChsbWFqb3IuZGIpLAogICAgICAgICAgICAgICAgICAgICAgICBzdGFydD1zdGFydChsbWFqb3IuZGIpLGVuZD1lbmQobG1ham9yLmRiKSkKbG1hai5oaXN0IDwtIGxtYWouaGlzdFtsbWFqLmhpc3QkTmFtZSAlaW4lICdleG9uJyxdCmxtYWpoaXN0LmNvbGxhcHNlIDwtIG1hdHJpeCgwLDAsbnJvdz1ucm93KGxtYWouY29sbGFwc2UpLG5jb2w9MikKcm93bmFtZXMobG1hamhpc3QuY29sbGFwc2UpIDwtIHJvd25hbWVzKGxtYWouY29sbGFwc2UpCmZvcihpIGluIDE6bnJvdyhsbWFqaGlzdC5jb2xsYXBzZSkpewogIHRlbXAubWF0IDwtIGxtYWouaGlzdFtncmVwKHJvd25hbWVzKGxtYWpoaXN0LmNvbGxhcHNlKVtpXSxsbWFqLmhpc3QkSUQpLF0KICBpZihucm93KHRlbXAubWF0KT09MSl7CiAgICBsbWFqaGlzdC5jb2xsYXBzZVtpLDJdIDwtIHRlbXAubWF0JHNpemUKICB9CiAgaWYobnJvdyh0ZW1wLm1hdCk+MSl7CiAgICBsbWFqaGlzdC5jb2xsYXBzZVtpLDJdIDwtIHN1bSh0ZW1wLm1hdCRzaXplKQogIH0KfQpsbWFqX3Jwa20gPC0gcnBrbShsbWFqLmNvbGxhcHNlLGFzLm51bWVyaWMobG1hamhpc3QuY29sbGFwc2VbLDJdKSkKCm5yb3cobG1leF9ycGttKQpucm93KGxiX3Jwa20pCm5yb3cobG1hal9ycGttKQoKIyMgQ292ZXJhZ2Ugb2YgKkwuIGFtYXpvbmVuc2lzKiBEQ0wgbGVzaW9ucwpiYXJwbG90KGNvbFN1bXMoY291bnRzVGFibGUpLCBsYXM9MywgbWFpbj0nTG14IFJhdyBDb3VudHMgQnkgU2FtcGxlIChEQ0wpJykKZGltKGxtZXhfcnBrbSkKCiMjIENvdmVyYWdlIG9mICpMLiBhbWF6b25lbnNpcyogTENMIHBhcmFzaXRlICppbiB2aXRybyogbWFjcm9waGFnZSBpbmZlY3Rpb24KYmFycGxvdChjb2xTdW1zKGxtZXh2aXRyby5jb3VudHNUYWJsZSksIGxhcz0zLCBtYWluPSdMbXggUmF3IENvdW50cyBCeSBTYW1wbGUgKExDTCBpbiB2aXRybyknKQpkaW0obG1leHZpdHJvX3Jwa20pCgojIyBDb3ZlcmFnZSBvZiAqTC4gYnJhemlsaWVuc2lzKiBMQ0wgbGVzaW9ucwpiYXJwbG90KGNvbFN1bXMobGIuY291bnRzVGFibGUpLCBsYXM9MywgbWFpbj0nTGJyIFJhdyBDb3VudHMgQnkgU2FtcGxlIChMQ0wgaW4gdml2byknKQpkaW0obGJfcnBrbSkKCiMjIENvdmVyYWdlIG9mICpMLiBtYWpvciogTENMIHBhcmFzaXRlICppbiB2aXRybyogbWFjcm9waGFnZSBpbmZlY3Rpb24KYmFycGxvdChjb2xTdW1zKGxtYWouY291bnRzVGFibGUpLCBsYXM9MywgbWFpbj0nTG1qIFJhdyBDb3VudHMgQnkgU2FtcGxlIChMQ0wgaW4gdml0cm8pJykKZGltKGxtYWpfcnBrbSkKCiMjIENvdmVyYWdlIG9mIGFsbCBwYXJhc2l0ZXMsIGFsbCBjb25kaXRpb25zCmJhcnBsb3QoYyhjb2xTdW1zKGNvdW50c1RhYmxlKSxjb2xTdW1zKGxtZXh2aXRyby5jb3VudHNUYWJsZSksCiAgICAgICAgICBjb2xTdW1zKGxiLmNvdW50c1RhYmxlKSxjb2xTdW1zKGxtYWouY291bnRzVGFibGUpKSwKICAgICAgICBsYXM9MykKCiMjIyMjIEdlbmVyYXRlIHNpbmdsZS1yZWNpcHJvY2FsIG9ydGhvbG9nIHRhYmxlcyAjIyMjIwojI0NvbXBhcmUgTG1leCB2cy4gYWxsCmxtZXhfcnBrbSA8LSBycGttKGxtZXguY29sbGFwc2UsYXMubnVtZXJpYyhsbWV4aGlzdC5jb2xsYXBzZVssMl0pKQpMbWV4LnRvLnBhcmFsb2dzIDwtIHJlYWQudGFibGUoIi4uL0xiL0xteF9hbWEucGFyYWxvZ3MuaWRzLnR4dCIpCkxtZXgucGFyYWxvZ3MgPC0gbWF0cml4KDAsMCxuY29sPTIsbnJvdz1ucm93KExtZXgudG8ucGFyYWxvZ3MpKQpyb3c9MQpwYiA8LSB0eHRQcm9ncmVzc0JhcigwLG5yb3cobG1leF9ycGttKSxpbml0aWFsPTAsc3R5bGU9MykKZm9yKGkgaW4gMTpucm93KGxtZXhfcnBrbSkpewogIFN5cy5zbGVlcCgwLjAxKTsgc2V0VHh0UHJvZ3Jlc3NCYXIocGIsaSkKICBpZihyb3duYW1lcyhsbWV4X3Jwa20pW2ldICVpbiUgTG1leC50by5wYXJhbG9nc1ssMV0gJiByb3duYW1lcyhsbWV4X3Jwa20pW2krMV0gJWluJSBMbWV4LnRvLnBhcmFsb2dzWywxXSl7CiAgICByb3cxIDwtIHdoaWNoKExtZXgudG8ucGFyYWxvZ3NbLDFdPT1yb3duYW1lcyhsbWV4X3Jwa20pW2ldKSAjcm93IG9mIGN1cnJlbnQgZ2VuZQogICAgcm93MiA8LSB3aGljaChMbWV4LnRvLnBhcmFsb2dzWywxXT09cm93bmFtZXMobG1leF9ycGttKVtpKzFdKSAjcm93IG9mIG5leHQgZ2VuZQogICAgaWYoKHJvdzItcm93MSk+MSl7ICNpZiB0aGVyZSBhcmUgcGFyYWxvZ3MKICAgICAgZm9yKGogaW4gKHJvdzErMSk6KHJvdzItMSkpeyAjbG9vcCBmcm9tIHRoZSByb3cgYWZ0ZXIgY3VycmVudCBnZW5lIHRvIHJvdyBiZWZvcmUgbmV4dCBnZW5lCiAgICAgICAgTG1leC5wYXJhbG9nc1tyb3csMV0gPC0gcm93bmFtZXMobG1leF9ycGttKVtpXSAjTG1leCBnZW5lCiAgICAgICAgTG1leC5wYXJhbG9nc1tyb3csMl0gPC0gYXMuY2hhcmFjdGVyKExtZXgudG8ucGFyYWxvZ3NbaixdKSAjUGFyYWxvZyBnZW5lCiAgICAgICAgcm93PXJvdysxCiAgICAgIH0KICAgIH0KICB9Cn0KCmxtZXhfaG9tIDwtIG1hdHJpeCgwLDAsbmNvbD0zLG5yb3c9bnJvdyhsbWV4X3Jwa20pKQpsbWV4X2hvbVssMV0gPC0gcm93bmFtZXMobG1leF9ycGttKQpwYiA8LSB0eHRQcm9ncmVzc0JhcigwLG5yb3cobG1leF9ycGttKSxpbml0aWFsPTAsc3R5bGU9MykKZm9yKGkgaW4gMTpucm93KGxtZXhfcnBrbSkpewogIHRlbXBpZCA8LSBsbWV4X2hvbVtpLDFdCiAgaWYoIXRlbXBpZCAlaW4lIExtZXgucGFyYWxvZ3NbLDFdKXsKICAgIGxtZXhfaG9tW2ksMjozXSA8LSAwCiAgfQogIGlmKHRlbXBpZCAlaW4lIExtZXgucGFyYWxvZ3NbLDFdKXsKICAgIHRlbXBob20uYnJhIDwtIHN1YnNldChMbWV4LnBhcmFsb2dzLCBMbWV4LnBhcmFsb2dzWywxXSAlaW4lIHRlbXBpZCkKICAgIHRlbXBob20uYnJhIDwtIHN1YnNldCh0ZW1waG9tLmJyYSxzdWJzdHIodGVtcGhvbS5icmFbLDJdLDEsMyk9PSJMYnIiKQogICAgdGVtcGhvbS5icmEgPC0gc3Vic2V0KHRlbXBob20uYnJhLHRlbXBob20uYnJhWywyXSAlaW4lIHJvd25hbWVzKGxiX3Jwa20pKQogICAgdGVtcGhvbS5tYWogPC0gc3Vic2V0KExtZXgucGFyYWxvZ3MsIExtZXgucGFyYWxvZ3NbLDFdICVpbiUgdGVtcGlkKQogICAgdGVtcGhvbS5tYWogPC0gc3Vic2V0KHRlbXBob20ubWFqLHN1YnN0cih0ZW1waG9tLm1halssMl0sMSw0KT09IkxtakYiKQogICAgdGVtcGhvbS5tYWogPC0gc3Vic2V0KHRlbXBob20ubWFqLHRlbXBob20ubWFqWywyXSAlaW4lIHJvd25hbWVzKGxtYWpfcnBrbSkpCiAgICBpZihucm93KHRlbXBob20uYnJhKT09MCB8IG5yb3codGVtcGhvbS5tYWopPT0wKXsKICAgICAgbG1leF9ob21baSwyOjNdIDwtIDAKICAgIH0KICAgIGlmKG5yb3codGVtcGhvbS5icmEpPT0xICYgbnJvdyh0ZW1waG9tLm1haik9PTEpewogICAgICBsbWV4X2hvbVtpLDJdIDwtIHRlbXBob20uYnJhWywyXQogICAgICBsbWV4X2hvbVtpLDNdIDwtIHRlbXBob20ubWFqWywyXQogICAgfQogICAgaWYobnJvdyh0ZW1waG9tLmJyYSk+MSB8IG5yb3codGVtcGhvbS5tYWopPjEpewogICAgICBsbWV4X2hvbVtpLDI6M10gPC0gMAogICAgfQogIH0KICBTeXMuc2xlZXAoMC4wMSk7IHNldFR4dFByb2dyZXNzQmFyKHBiLGkpCn0KbG1leF9ob20gPC0gbG1leF9ob21bbG1leF9ob21bLDJdIT0wICYgbG1leF9ob21bLDNdIT0wLF0KCiNDb21wYXJlIExicmF6IHZzLiBhbGwKTGIudG8ucGFyYWxvZ3MgPC0gcmVhZC50YWJsZSgiLi4vTGIvTGJyYXoucGFyYWxvZ3MuaWRzLnR4dCIpCkxiLnBhcmFsb2dzIDwtIG1hdHJpeCgwLDAsbmNvbD0yLG5yb3c9bnJvdyhMYi50by5wYXJhbG9ncykpCnJvdz0xCnBiIDwtIHR4dFByb2dyZXNzQmFyKDAsbnJvdyhsYl9ycGttKSxpbml0aWFsPTAsc3R5bGU9MykKZm9yKGkgaW4gMTpucm93KGxiX3Jwa20pKXsKICBTeXMuc2xlZXAoMC4wMSk7IHNldFR4dFByb2dyZXNzQmFyKHBiLGkpCiAgaWYocm93bmFtZXMobGJfcnBrbSlbaV0gJWluJSBMYi50by5wYXJhbG9nc1ssMV0gJiByb3duYW1lcyhsYl9ycGttKVtpKzFdICVpbiUgTGIudG8ucGFyYWxvZ3NbLDFdKXsKICAgIHJvdzEgPC0gd2hpY2goTGIudG8ucGFyYWxvZ3NbLDFdPT1yb3duYW1lcyhsYl9ycGttKVtpXSkgI3JvdyBvZiBjdXJyZW50IGdlbmUKICAgIHJvdzIgPC0gd2hpY2goTGIudG8ucGFyYWxvZ3NbLDFdPT1yb3duYW1lcyhsYl9ycGttKVtpKzFdKSAjcm93IG9mIG5leHQgZ2VuZQogICAgaWYoKHJvdzItcm93MSk+MSl7ICNpZiB0aGVyZSBhcmUgcGFyYWxvZ3MKICAgICAgZm9yKGogaW4gKHJvdzErMSk6KHJvdzItMSkpeyAjbG9vcCBmcm9tIHRoZSByb3cgYWZ0ZXIgY3VycmVudCBnZW5lIHRvIHJvdyBiZWZvcmUgbmV4dCBnZW5lCiAgICAgICAgTGIucGFyYWxvZ3Nbcm93LDFdIDwtIHJvd25hbWVzKGxiX3Jwa20pW2ldICNMbWV4IGdlbmUKICAgICAgICBMYi5wYXJhbG9nc1tyb3csMl0gPC0gYXMuY2hhcmFjdGVyKExiLnRvLnBhcmFsb2dzW2osXSkgI1BhcmFsb2cgZ2VuZQogICAgICAgIHJvdz1yb3crMQogICAgICB9CiAgICB9CiAgfQp9CgpsYl9ob20gPC0gbWF0cml4KDAsMCxuY29sPTMsbnJvdz1ucm93KGxiX3Jwa20pKQpsYl9ob21bLDFdIDwtIHJvd25hbWVzKGxiX3Jwa20pCnBiIDwtIHR4dFByb2dyZXNzQmFyKDAsbnJvdyhsYl9ycGttKSxpbml0aWFsPTAsc3R5bGU9MykKZm9yKGkgaW4gMTpucm93KGxiX3Jwa20pKXsKICB0ZW1waWQgPC0gbGJfaG9tW2ksMV0KICBpZighdGVtcGlkICVpbiUgTGIucGFyYWxvZ3NbLDFdKXsKICAgIGxiX2hvbVtpLDI6M10gPC0gMAogIH0KICBpZih0ZW1waWQgJWluJSBMYi5wYXJhbG9nc1ssMV0pewogICAgdGVtcGhvbS4xIDwtIHN1YnNldChMYi5wYXJhbG9ncywgTGIucGFyYWxvZ3NbLDFdICVpbiUgdGVtcGlkKQogICAgdGVtcGhvbS4xIDwtIHN1YnNldCh0ZW1waG9tLjEsc3Vic3RyKHRlbXBob20uMVssMl0sMSwzKT09IkxteCIpCiAgICB0ZW1waG9tLjEgPC0gc3Vic2V0KHRlbXBob20uMSx0ZW1waG9tLjFbLDJdICVpbiUgcm93bmFtZXMobG1leF9ycGttKSkKICAgIHRlbXBob20uMiA8LSBzdWJzZXQoTGIucGFyYWxvZ3MsIExiLnBhcmFsb2dzWywxXSAlaW4lIHRlbXBpZCkKICAgIHRlbXBob20uMiA8LSBzdWJzZXQodGVtcGhvbS4yLHN1YnN0cih0ZW1waG9tLjJbLDJdLDEsMyk9PSJMbWoiKQogICAgdGVtcGhvbS4yIDwtIHN1YnNldCh0ZW1waG9tLjIsdGVtcGhvbS4yWywyXSAlaW4lIHJvd25hbWVzKGxtYWpfcnBrbSkpCiAgICBpZihucm93KHRlbXBob20uMSk9PTAgfCBucm93KHRlbXBob20uMik9PTApewogICAgICBsYl9ob21baSwyOjNdIDwtIDAKICAgIH0KICAgIGlmKG5yb3codGVtcGhvbS4xKT09MSAmIG5yb3codGVtcGhvbS4yKT09MSl7CiAgICAgIGxiX2hvbVtpLDJdIDwtIHRlbXBob20uMVssMl0KICAgICAgbGJfaG9tW2ksM10gPC0gdGVtcGhvbS4yWywyXQogICAgfQogICAgaWYobnJvdyh0ZW1waG9tLjEpPjEgfCBucm93KHRlbXBob20uMik+MSl7CiAgICAgIGxiX2hvbVtpLDI6M10gPC0gMAogICAgfQogIH0KICBTeXMuc2xlZXAoMC4wMSk7IHNldFR4dFByb2dyZXNzQmFyKHBiLGkpCn0KbGJfaG9tIDwtIGxiX2hvbVtsYl9ob21bLDJdIT0wICYgbGJfaG9tWywzXSE9MCxdCgojQ29tcGFyZSBMbWFqIHZzLiBhbGwKTG1hai50by5wYXJhbG9ncyA8LSByZWFkLmNzdigiLi4vTGIvTG1qRi5wYXJhbG9ncy5pZHMudHh0IixoZWFkZXI9RikKTG1hai5wYXJhbG9ncyA8LSBtYXRyaXgoMCwwLG5jb2w9Mixucm93PW5yb3coTG1hai50by5wYXJhbG9ncykpCnJvdz0xCnBiIDwtIHR4dFByb2dyZXNzQmFyKDAsbnJvdyhsbWFqX3Jwa20pLGluaXRpYWw9MCxzdHlsZT0zKQpmb3IoaSBpbiAxOm5yb3cobG1hal9ycGttKSl7CiAgU3lzLnNsZWVwKDAuMDEpOyBzZXRUeHRQcm9ncmVzc0JhcihwYixpKQogIGlmKHJvd25hbWVzKGxtYWpfcnBrbSlbaV0gJWluJSBMbWFqLnRvLnBhcmFsb2dzWywxXSAmIHJvd25hbWVzKGxtYWpfcnBrbSlbaSsxXSAlaW4lIExtYWoudG8ucGFyYWxvZ3NbLDFdKXsKICAgIHJvdzEgPC0gd2hpY2goTG1hai50by5wYXJhbG9nc1ssMV09PXJvd25hbWVzKGxtYWpfcnBrbSlbaV0pICNyb3cgb2YgY3VycmVudCBnZW5lCiAgICByb3cyIDwtIHdoaWNoKExtYWoudG8ucGFyYWxvZ3NbLDFdPT1yb3duYW1lcyhsbWFqX3Jwa20pW2krMV0pICNyb3cgb2YgbmV4dCBnZW5lCiAgICBpZigocm93Mi1yb3cxKT4xKXsgI2lmIHRoZXJlIGFyZSBwYXJhbG9ncwogICAgICBmb3IoaiBpbiAocm93MSsxKToocm93Mi0xKSl7ICNsb29wIGZyb20gdGhlIHJvdyBhZnRlciBjdXJyZW50IGdlbmUgdG8gcm93IGJlZm9yZSBuZXh0IGdlbmUKICAgICAgICBMbWFqLnBhcmFsb2dzW3JvdywxXSA8LSByb3duYW1lcyhsbWFqX3Jwa20pW2ldICNMbWV4IGdlbmUKICAgICAgICBMbWFqLnBhcmFsb2dzW3JvdywyXSA8LSBhcy5jaGFyYWN0ZXIoTG1hai50by5wYXJhbG9nc1tqLF0pICNQYXJhbG9nIGdlbmUKICAgICAgICByb3c9cm93KzEKICAgICAgfQogICAgfQogIH0KfQoKbG1hal9ob20gPC0gbWF0cml4KDAsMCxuY29sPTMsbnJvdz1ucm93KGxtYWpfcnBrbSkpCmxtYWpfaG9tWywxXSA8LSByb3duYW1lcyhsbWFqX3Jwa20pCnBiIDwtIHR4dFByb2dyZXNzQmFyKDAsbnJvdyhsbWFqX3Jwa20pLGluaXRpYWw9MCxzdHlsZT0zKQpmb3IoaSBpbiAxOm5yb3cobG1hal9ycGttKSl7CiAgdGVtcGlkIDwtIGxtYWpfaG9tW2ksMV0KICBpZighdGVtcGlkICVpbiUgTG1hai5wYXJhbG9nc1ssMV0pewogICAgbG1hal9ob21baSwyOjNdIDwtIDAKICB9CiAgaWYodGVtcGlkICVpbiUgTG1hai5wYXJhbG9nc1ssMV0pewogICAgdGVtcGhvbS4xIDwtIHN1YnNldChMbWFqLnBhcmFsb2dzLCBMbWFqLnBhcmFsb2dzWywxXSAlaW4lIHRlbXBpZCkKICAgIHRlbXBob20uMSA8LSBzdWJzZXQodGVtcGhvbS4xLHN1YnN0cih0ZW1waG9tLjFbLDJdLDEsMyk9PSJMbXgiKQogICAgdGVtcGhvbS4xIDwtIHN1YnNldCh0ZW1waG9tLjEsdGVtcGhvbS4xWywyXSAlaW4lIHJvd25hbWVzKGxtZXhfcnBrbSkpCiAgICB0ZW1waG9tLjIgPC0gc3Vic2V0KExtYWoucGFyYWxvZ3MsIExtYWoucGFyYWxvZ3NbLDFdICVpbiUgdGVtcGlkKQogICAgdGVtcGhvbS4yIDwtIHN1YnNldCh0ZW1waG9tLjIsc3Vic3RyKHRlbXBob20uMlssMl0sMSwzKT09IkxiciIpCiAgICB0ZW1waG9tLjIgPC0gc3Vic2V0KHRlbXBob20uMix0ZW1waG9tLjJbLDJdICVpbiUgcm93bmFtZXMobGJfcnBrbSkpCiAgICBpZihucm93KHRlbXBob20uMSk9PTAgfCBucm93KHRlbXBob20uMik9PTApewogICAgICBsbWFqX2hvbVtpLDI6M10gPC0gMAogICAgfQogICAgaWYobnJvdyh0ZW1waG9tLjEpPT0xICYgbnJvdyh0ZW1waG9tLjIpPT0xKXsKICAgICAgbG1hal9ob21baSwyXSA8LSB0ZW1waG9tLjFbLDJdCiAgICAgIGxtYWpfaG9tW2ksM10gPC0gdGVtcGhvbS4yWywyXQogICAgfQogICAgaWYobnJvdyh0ZW1waG9tLjEpPjEgfCBucm93KHRlbXBob20uMik+MSl7CiAgICAgIGxtYWpfaG9tW2ksMjozXSA8LSAwCiAgICB9CiAgfQogIFN5cy5zbGVlcCgwLjAxKTsgc2V0VHh0UHJvZ3Jlc3NCYXIocGIsaSkKfQpsbWFqX2hvbSA8LSBsbWFqX2hvbVtsbWFqX2hvbVssMl0hPTAgJiBsbWFqX2hvbVssM10hPTAsXQoKbG1leF9ob20uYWxsIDwtIGxtZXhfaG9tW2xtZXhfaG9tWywxXSAlaW4lIGxiX2hvbVssMl0gJgogICAgICAgICAgICAgICAgICAgICAgICAgICBsbWV4X2hvbVssMV0gJWluJSBsbWFqX2hvbVssMl0gJgogICAgICAgICAgICAgICAgICAgICAgICAgICBsbWV4X2hvbVssMl0gJWluJSBsYl9ob21bLDFdICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgbG1leF9ob21bLDJdICVpbiUgbG1hal9ob21bLDNdICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgbG1leF9ob21bLDNdICVpbiUgbGJfaG9tWywzXSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxtZXhfaG9tWywzXSAlaW4lIGxtYWpfaG9tWywxXSxdCmNvbG5hbWVzKGxtZXhfaG9tLmFsbCkgPC0gYygnbG14LmlkJywnbGJyLmlkJywnbG1qLmlkJykKCmxtZXgucnBrbS5ob21zIDwtIGNiaW5kKHJvd25hbWVzKGxtZXhfcnBrbSksbG1leF9ycGttWyw1OjEwXSkKY29sbmFtZXMobG1leC5ycGttLmhvbXMpIDwtIGMoJ2xteC5pZCcscGFzdGUocmVwKCdsbXh2aXZvJyx0aW1lcz02KSwgYygxOjYpLCBzZXA9Ii4iKSkKbG1leC5ycGttLmhvbXMgPC0gbWVyZ2UobG1leC5ycGttLmhvbXMsIGxtZXhfaG9tLmFsbCwgYnk9J2xteC5pZCcpCgpsbWV4LnZpdHJvLnJwa20uaG9tcyA8LSBjYmluZChyb3duYW1lcyhsbWV4dml0cm9fcnBrbSksbG1leHZpdHJvX3Jwa20pCmNvbG5hbWVzKGxtZXgudml0cm8ucnBrbS5ob21zKSA8LSBjKCdsbXguaWQnLHBhc3RlKHJlcChjKCJsbXhleHRlcm5hbCIsICJsbXh2aXRybzQiLCJsbXh2aXRybzI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxteHZpdHJvNDgiLCAibG14dml0cm83MiIpLHRpbWVzPTMpLCBjKDE6MTUpLCBzZXA9Ii4iKSkKbG1leC52aXRyby5ycGttLmhvbXMgPC0gbWVyZ2UobG1leC52aXRyby5ycGttLmhvbXMsIGxtZXhfaG9tLmFsbCwgYnk9J2xteC5pZCcpCgpsYi5ycGttLmhvbXMgPC0gY2JpbmQocm93bmFtZXMobGJfcnBrbSksbGJfcnBrbSkKY29sbmFtZXMobGIucnBrbS5ob21zKSA8LSBjKCdsYnIuaWQnLHBhc3RlKHJlcCgnbGJydml2bycsdGltZXM9NiksIGMoMTo2KSwgc2VwPSIuIikpCmxiLnJwa20uaG9tcyA8LSBtZXJnZShsYi5ycGttLmhvbXMsIGxtZXhfaG9tLmFsbCwgYnk9J2xici5pZCcpCgpsbWFqLnJwa20uaG9tcyA8LSBjYmluZChyb3duYW1lcyhsbWFqX3Jwa20pLGxtYWpfcnBrbSkKY29sbmFtZXMobG1hai5ycGttLmhvbXMpIDwtIGMoJ2xtai5pZCcscGFzdGUoYyhyZXAoImxtamV4dGVybmFsIix0aW1lcz01KSxyZXAoImxtanZpdHJvNCIsdGltZXM9NSkscmVwKCJsbWp2aXRybzI0Iix0aW1lcz01KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImxtanZpdHJvNDgiLHRpbWVzPTUpLHJlcCgibG1qdml0cm83MiIsdGltZXM9NCkpLGMoMToyNCksIHNlcD0iLiIpKQpsbWFqLnJwa20uaG9tcyA8LSBtZXJnZShsbWFqLnJwa20uaG9tcywgbG1leF9ob20uYWxsLCBieT0nbG1qLmlkJykKCmxpc3Qub2YuZGF0YS5mcmFtZXMgPC0gbGlzdChsbWV4LnJwa20uaG9tcyxsbWV4LnZpdHJvLnJwa20uaG9tcyxsYi5ycGttLmhvbXMsbG1hai5ycGttLmhvbXMpCmFsbC5ycGttID0gUmVkdWNlKGZ1bmN0aW9uKC4uLikgbWVyZ2UoLi4uLCBieT0ibG14LmlkIiwgYWxsPVQpLCBsaXN0Lm9mLmRhdGEuZnJhbWVzKQphbGwucnBrbSA8LSBhbGwucnBrbVssYygyOjcsMTA6MjQsMjg6MzMsMzY6NTkpXQphbGwucnBrbSA8LSBhcHBseShhbGwucnBrbSwyLGFzLm51bWVyaWMpCnJvd25hbWVzKGFsbC5ycGttKSA8LSBsbWV4X2hvbS5hbGxbLDFdCnEucnBrbSA8LSBjYmluZChsbWV4X2hvbS5hbGwscU5vcm0oYWxsLnJwa20pKQoKZGltKGxtZXhfaG9tKQpkaW0obGJfaG9tKQpkaW0obG1hal9ob20pCmhlYWQobG1leF9ob20uYWxsKQpucm93KGxtZXhfaG9tLmFsbCkKCiMjIyMjIyBSUEtNIGNvcnJlbGF0aW9ucyMjIyMjCmNvbC5uYW0gPC0gYyhwYXN0ZShyZXAoJ0xtZXgtdml2bycsdGltZXM9NiksIGMoMTo2KSwgc2VwPSIuIiksCiAgICAgICAgICAgICByZXAoYygiZXh0ZXJuYWwiLCJMbWV4LXZpdHJvNCIsIkxtZXgtdml0cm8yNCIsIkxtZXgtdml0cm80OCIsIkxtZXgtdml0cm83MiIpLHRpbWVzPTMpLAogICAgICAgICAgICAgcGFzdGUocmVwKCdMYi12aXZvJyx0aW1lcz02KSwgYygxOjYpLCBzZXA9Ii4iKSwKICAgICAgICAgICAgIHBhc3RlKHJlcCgibG1qZXh0ZXJuYWwiLHRpbWVzPTUpLGMoMTo1KSwgc2VwPScuJyksCiAgICAgICAgICAgICBwYXN0ZShyZXAoImxtanZpdHJvNCIsdGltZXM9NSksYygxOjUpLCBzZXA9Jy4nKSwKICAgICAgICAgICAgIHBhc3RlKHJlcCgibG1qdml0cm8yNCIsdGltZXM9NSksYygxOjUpLCBzZXA9Jy4nKSwKICAgICAgICAgICAgIHBhc3RlKHJlcCgibG1qdml0cm80OCIsdGltZXM9NSksYygxOjUpLCBzZXA9Jy4nKSwKICAgICAgICAgICAgIHBhc3RlKHJlcCgibG1qdml0cm83MiIsdGltZXM9NCksYygxOjQpLCBzZXA9Jy4nKSkKIyBSYW4gY29ycmVsYXRpb25zIHVzaW5nIHBlYXJzb24sIHNwZWFybWFuLCBhbmQgYnkgY29ycmVsYXRpbmcgcnBrbXMgb2YgdG9wIHF1YXJ0aWxlIGFuZCBib3R0b20gdGhyZWUgcXVhcnRpbGVzCiNUb3AgcXVhcnRpbGUgb2YgRENMIEwubXggaXMgMToyMDYzIGFmdGVyIHNvcnRpbmcgb24gcm93U3VtcyBvZiBjb2x1bW5zIDE6NgojQWxzbyBsb29rZWQgYXQgcXVhbnRpbGUgbm9ybWFsaXphdGlvbiBlZmZlY3Qgb24gY29ycmVsYXRpb25zCiNhbGwucnBrbSA8LSBhbGwucnBrbVtvcmRlcihyb3dTdW1zKGFsbC5ycGttKSxkZWNyZWFzaW5nPVQpLF0KZGF0Q29yIDwtIGNvcihhbGwucnBrbSxtZXRob2Q9J3NwZWFybWFuJykKaGVhdG1hcC4yKGRhdENvciwKICAgICAgICAgIG1hcmdpbnM9YygxMCwgMTApLAogICAgICAgICAgbGFiUm93PWNvbC5uYW0sCiAgICAgICAgICBsYWJDb2w9Y29sLm5hbSwKICAgICAgICAgIHNjYWxlPSJub25lIixicmVha3M9c2VxKDAsMSxsZW5ndGg9MTAwKSwKICAgICAgICAgIHRyYWNlPSJub25lIiwKICAgICAgICAgIHNydENvbD00NSxtYWluPSdTcGVhcm1hbiBjb3JyZWxhdGlvbiAoUlBLTXMpJykKCiNRdWFudGlsZSBub3JtYWxpemUgcnBrbSB2YWx1ZXMgYWNyb3NzIHNhbXBsZXMKcS5ycGttIDwtIHFOb3JtKGFsbC5ycGttKQpkYXRDb3IgPC0gY29yKHEucnBrbSxtZXRob2Q9J3BlYXJzb24nKQpoZWF0bWFwLjIoZGF0Q29yLAogICAgICAgICAgbWFyZ2lucz1jKDEwLCAxMCksCiAgICAgICAgICBsYWJSb3c9Y29sLm5hbSwKICAgICAgICAgIGxhYkNvbD1jb2wubmFtLAogICAgICAgICAgc2NhbGU9Im5vbmUiLGJyZWFrcz1zZXEoMCwxLGxlbmd0aD0xMDApLAogICAgICAgICAgdHJhY2U9Im5vbmUiLAogICAgICAgICAgc3J0Q29sPTQ1LG1haW49J1BlYXJzb24gY29ycmVsYXRpb24gKHFub3JtIFJQS01zKScpCgojQ29ycmVsYXRpb24gYmV0d2VlbiBMLiBhbWF6b25lbnNpcyBzYW1wbGVzCmxtZXh2aXRyb19ycGttIDwtIGxtZXh2aXRyb19ycGttW21hdGNoKHJvd25hbWVzKGxtZXhfcnBrbSkscm93bmFtZXMobG1leHZpdHJvX3Jwa20pKSxdCmxtZXhhbGwucnBrbSA8LSBjYmluZChsbWV4X3Jwa21bLDU6MTBdLGxtZXh2aXRyb19ycGttKQpsbWV4YWxsLnJwa20gPC0gYXBwbHkobG1leGFsbC5ycGttLDIsYXMubnVtZXJpYykKcm93bmFtZXMobG1leGFsbC5ycGttKSA8LSByb3duYW1lcyhsbWV4X3Jwa20pCmNvbC5uYW0gPC0gYyhwYXN0ZShyZXAoJ0xtZXgtdml2bycsdGltZXM9NiksIGMoMTo2KSwgc2VwPSIuIiksCiAgICAgICAgICAgICByZXAoYygiZXh0ZXJuYWwiLCAiTG1leC12aXRybzQiLCJMbWV4LXZpdHJvMjQiLCAiTG1leC12aXRybzQ4IiwgIkxtZXgtdml0cm83MiIpLHRpbWVzPTMpKQpkYXRDb3IgPC0gY29yKGxtZXhhbGwucnBrbSxtZXRob2Q9J3BlYXJzb24nKQpoZWF0bWFwLjIoZGF0Q29yLAogICAgICAgICAgbWFyZ2lucz1jKDEwLCAxMCksCiAgICAgICAgICBsYWJSb3c9Y29sLm5hbSwKICAgICAgICAgIGxhYkNvbD1jb2wubmFtLAogICAgICAgICAgc2NhbGU9Im5vbmUiLGJyZWFrcz1zZXEoMC41NSwxLGxlbmd0aD0xMDApLAogICAgICAgICAgdHJhY2U9Im5vbmUiLAogICAgICAgICAgc3J0Q29sPTQ1LG1haW49J1BlYXJzb24gY29ycmVsYXRpb24gKExteCBSUEtNcyknKQpxbWV4LnJwa20gPC0gcU5vcm0obG1leGFsbC5ycGttKQpyb3duYW1lcyhxbWV4LnJwa20pIDwtIHJvd25hbWVzKGxtZXhfcnBrbSkKZGF0Q29yIDwtIGNvcihxbWV4LnJwa20sbWV0aG9kPSdwZWFyc29uJykKaGVhdG1hcC4yKGRhdENvciwKICAgICAgICAgIG1hcmdpbnM9YygxMCwgMTApLAogICAgICAgICAgbGFiUm93PWNvbC5uYW0sCiAgICAgICAgICBsYWJDb2w9Y29sLm5hbSwKICAgICAgICAgIHNjYWxlPSJub25lIixicmVha3M9c2VxKDAuNTUsMSxsZW5ndGg9MTAwKSwKICAgICAgICAgIHRyYWNlPSJub25lIiwKICAgICAgICAgIHNydENvbD00NSxtYWluPSdQZWFyc29uIGNvcnJlbGF0aW9uIChxbm9ybSBMbXggUlBLTXMpJykKCiMjIyMjIyNBbGwgTGVpc2htYW5pYSBjb21wYXJpc29uL3RhYmxlIGdlbmVyYXRpb24jIyMjIwpsbWFqX3Jwa20gPC0gbG1hal9ycGttW3Jvd25hbWVzKGxtYWpfcnBrbSkgJWluJSBsbWFqb3IudHJpdHJ5cGRiWywxXSxdCmxtZXhfcnBrbSA8LSBsbWV4X3Jwa21bcm93bmFtZXMobG1leF9ycGttKSAlaW4lIGxtZXgudHJpdHJ5cGRiWywxXSxdCmxtZXh2aXRyb19ycGttIDwtIGxtZXh2aXRyb19ycGttW3Jvd25hbWVzKGxtZXh2aXRyb19ycGttKSAlaW4lIGxtZXgudHJpdHJ5cGRiWywxXSxdCmxiX3Jwa20gPC0gbGJfcnBrbVtyb3duYW1lcyhsYl9ycGttKSAlaW4lIGxiLnRyaXRyeXBkYlssMV0sXQoKYWxsX2NvbXAgPC0gbWF0cml4KDAsMCxucm93PW5yb3coYWxsLnJwa20pKwogICAgICAgICAgICAgICAgICAgICAobnJvdyhsYl9ycGttKS1ucm93KGFsbC5ycGttKSkrCiAgICAgICAgICAgICAgICAgICAgIChucm93KGxtYWpfcnBrbSktbnJvdyhhbGwucnBrbSkpKwogICAgICAgICAgICAgICAgICAgICAobnJvdyhsbWV4X3Jwa20pLW5yb3coYWxsLnJwa20pKSxuY29sPTE2KQpjb21tb24uZ2VuZXMgPSBSZWR1Y2UoZnVuY3Rpb24oLi4uKSBtZXJnZSguLi4sIGJ5PSJsbXguaWQiLCBhbGw9VCksIGxpc3Qub2YuZGF0YS5mcmFtZXMpCmNvbW1vbi5nZW5lcyA8LSBjb21tb24uZ2VuZXNbLGMoMSw4LDkpXQphbGxfY29tcFsxOm5yb3coYWxsLnJwa20pLDJdIDwtIGFzLmNoYXJhY3Rlcihjb21tb24uZ2VuZXNbLDFdKQphbGxfY29tcFsxOm5yb3coYWxsLnJwa20pLDldIDwtIGFzLmNoYXJhY3Rlcihjb21tb24uZ2VuZXNbLDJdKQphbGxfY29tcFsxOm5yb3coYWxsLnJwa20pLDEzXSA8LSBhcy5jaGFyYWN0ZXIoY29tbW9uLmdlbmVzWywzXSkKYWxsX2NvbXBbMTpucm93KGFsbC5ycGttKSw0XSA8LSByb3dNZWFucyhhbGwucnBrbVssMTo2XSkKYWxsX2NvbXBbMTpucm93KGFsbC5ycGttKSw3XSA8LSByb3dNZWFucyhhbGwucnBrbVssYygxMSwxNiwyMSldKQphbGxfY29tcFsxOm5yb3coYWxsLnJwa20pLDExXSA8LSByb3dNZWFucyhhbGwucnBrbVssMjI6MjZdKQphbGxfY29tcFsxOm5yb3coYWxsLnJwa20pLDE1XSA8LSByb3dNZWFucyhhbGwucnBrbVssNDg6NTFdKQpmb3IoaSBpbiAxOm5yb3coYWxsLnJwa20pKXsKICBhbGxfY29tcFtpLDFdIDwtIGFzLmNoYXJhY3RlcihsbWV4LnRyaXRyeXBkYltsbWV4LnRyaXRyeXBkYlssMV0gPT0gYXMuY2hhcmFjdGVyKGFsbF9jb21wW2ksMl0pLF1bLDJdKQogIGFsbF9jb21wW2ksNV0gPC0gc2QoYWxsLnJwa21baSwxOjZdKS9zcXJ0KDYpCiAgYWxsX2NvbXBbaSw4XSA8LSBzZChhbGwucnBrbVtpLGMoMTEsMTYsMjEpXSkvc3FydCgzKQogIGFsbF9jb21wW2ksMTJdIDwtIHNkKGFsbC5ycGttW2ksMjI6MjZdKS9zcXJ0KDYpCiAgYWxsX2NvbXBbaSwxNl0gPC0gc2QoYWxsLnJwa21baSw0ODo1MV0pL3NxcnQoNCkKfQpsbWV4dml2b191bmlxdWUgPC0gbG1leF9ycGttWyFyb3duYW1lcyhsbWV4X3Jwa20pICVpbiUgY29tbW9uLmdlbmVzWywxXSxdCmxtZXh2aXRyb191bmlxdWUgPC0gbG1leHZpdHJvX3Jwa21bIXJvd25hbWVzKGxtZXh2aXRyb19ycGttKSAlaW4lIGNvbW1vbi5nZW5lc1ssMV0sXQpsbWV4dml0cm9fdW5pcXVlIDwtIGxtZXh2aXRyb191bmlxdWVbbWF0Y2gocm93bmFtZXMobG1leHZpdm9fdW5pcXVlKSxyb3duYW1lcyhsbWV4dml0cm9fdW5pcXVlKSksXQphbGxfY29tcFsobnJvdyhhbGwucnBrbSkrMSk6bnJvdyhsbWV4X3Jwa20pLDJdIDwtIHJvd25hbWVzKGxtZXh2aXZvX3VuaXF1ZSkKYWxsX2NvbXBbKG5yb3coYWxsLnJwa20pKzEpOm5yb3cobG1leF9ycGttKSw0XSA8LSByb3dNZWFucyhsbWV4dml2b191bmlxdWVbLDU6MTBdKQphbGxfY29tcFsobnJvdyhhbGwucnBrbSkrMSk6bnJvdyhsbWV4X3Jwa20pLDddIDwtIHJvd01lYW5zKGxtZXh2aXRyb191bmlxdWVbLGMoNSwxMCwxNSldKQpmb3IoaSBpbiAobnJvdyhhbGwucnBrbSkrMSk6bnJvdyhsbWV4X3Jwa20pKXsKICByb3cgPSBpLW5yb3coYWxsLnJwa20pCiAgYWxsX2NvbXBbaSwxXSA8LSBhcy5jaGFyYWN0ZXIobG1leC50cml0cnlwZGJbbG1leC50cml0cnlwZGJbLDFdID09IGFzLmNoYXJhY3RlcihhbGxfY29tcFtpLDJdKSxdWywyXSkKICBhbGxfY29tcFtpLDVdIDwtIHNkKGxtZXh2aXZvX3VuaXF1ZVtyb3csNToxMF0pL3NxcnQoNikKICBhbGxfY29tcFtpLDhdIDwtIHNkKGxtZXh2aXRyb191bmlxdWVbcm93LF0pL3NxcnQoMykKfQpsYl91bmlxdWUgPC0gbGJfcnBrbVshcm93bmFtZXMobGJfcnBrbSkgJWluJSBjb21tb24uZ2VuZXNbLDJdLF0KYWxsX2NvbXBbKG5yb3cobG1leF9ycGttKSsxKToobnJvdyhsbWV4X3Jwa20pK25yb3cobGJfcnBrbSktbnJvdyhhbGwucnBrbSkpLDldIDwtIHJvd25hbWVzKGxiX3VuaXF1ZSkKYWxsX2NvbXBbKG5yb3cobG1leF9ycGttKSsxKToobnJvdyhsbWV4X3Jwa20pK25yb3cobGJfcnBrbSktbnJvdyhhbGwucnBrbSkpLDExXSA8LSByb3dNZWFucyhsYl91bmlxdWUpCmZvcihpIGluIChucm93KGxtZXhfcnBrbSkrMSk6KG5yb3cobG1leF9ycGttKStucm93KGxiX3Jwa20pLW5yb3coYWxsLnJwa20pKSl7CiAgcm93ID0gaS1ucm93KGxtZXhfcnBrbSkKICBhbGxfY29tcFtpLDFdIDwtIGFzLmNoYXJhY3RlcihsYi50cml0cnlwZGJbbGIudHJpdHJ5cGRiWywxXSA9PSBhcy5jaGFyYWN0ZXIoYWxsX2NvbXBbaSw5XSksXVssMl0pCiAgYWxsX2NvbXBbaSwxMl0gPC0gc2QobGJfdW5pcXVlW3JvdyxdKS9zcXJ0KDYpCn0KbG1qX3VuaXF1ZSA8LSBsbWFqX3Jwa21bIXJvd25hbWVzKGxtYWpfcnBrbSkgJWluJSBjb21tb24uZ2VuZXNbLDNdLF0KbG1ham9yLnRyaXRyeXBkYiA8LSBsbWFqb3IudHJpdHJ5cGRiW2xtYWpvci50cml0cnlwZGJbLDFdICVpbiUgcm93bmFtZXMobG1hal9ycGttKSxdCmFsbF9jb21wWyhucm93KGxtZXhfcnBrbSkrbnJvdyhsYl9ycGttKS1ucm93KGFsbC5ycGttKSsxKToobnJvdyhsbWV4X3Jwa20pK25yb3cobGJfcnBrbSktbnJvdyhhbGwucnBrbSkrbnJvdyhsbWFqX3Jwa20pLW5yb3coYWxsLnJwa20pKSwxM10gPC0gcm93bmFtZXMobG1qX3VuaXF1ZSkKYWxsX2NvbXBbKG5yb3cobG1leF9ycGttKStucm93KGxiX3Jwa20pLW5yb3coYWxsLnJwa20pKzEpOihucm93KGxtZXhfcnBrbSkrbnJvdyhsYl9ycGttKS1ucm93KGFsbC5ycGttKStucm93KGxtYWpfcnBrbSktbnJvdyhhbGwucnBrbSkpLDE1XSA8LSByb3dNZWFucyhsbWpfdW5pcXVlWywyMToyNF0pCmZvcihpIGluIChucm93KGxtZXhfcnBrbSkrbnJvdyhsYl9ycGttKS1ucm93KGFsbC5ycGttKSsxKToobnJvdyhsbWV4X3Jwa20pK25yb3cobGJfcnBrbSktbnJvdyhhbGwucnBrbSkrbnJvdyhsbWFqX3Jwa20pLW5yb3coYWxsLnJwa20pKSl7CiAgcm93ID0gaS1ucm93KGxtZXhfcnBrbSktKG5yb3cobGJfcnBrbSktbnJvdyhhbGwucnBrbSkpCiAgYWxsX2NvbXBbaSwxXSA8LSBhcy5jaGFyYWN0ZXIobG1ham9yLnRyaXRyeXBkYltsbWFqb3IudHJpdHJ5cGRiWywxXSA9PSBhcy5jaGFyYWN0ZXIoYWxsX2NvbXBbaSwxM10pLF1bLDJdWzFdKQogIGFsbF9jb21wW2ksMTZdIDwtIHNkKGxtal91bmlxdWVbcm93LDIxOjI0XSkvc3FydCg0KQp9CgphbGxfY29tcCA8LSBhbGxfY29tcFtvcmRlcihhcy5udW1lcmljKGFsbF9jb21wWyw0XSksZGVjcmVhc2luZz1UKSxdCmFsbF9jb21wWzE6bnJvdyhsbWV4X3Jwa20pLDNdIDwtIGMoMTpucm93KGxtZXhfcnBrbSkpCmFsbF9jb21wIDwtIGFsbF9jb21wW29yZGVyKGFzLm51bWVyaWMoYWxsX2NvbXBbLDddKSxkZWNyZWFzaW5nPVQpLF0KYWxsX2NvbXBbMTpucm93KGxtZXh2aXRyb19ycGttKSw2XSA8LSBjKDE6bnJvdyhsbWV4dml0cm9fcnBrbSkpCmFsbF9jb21wIDwtIGFsbF9jb21wW29yZGVyKGFzLm51bWVyaWMoYWxsX2NvbXBbLDExXSksZGVjcmVhc2luZz1UKSxdCmFsbF9jb21wWzE6bnJvdyhsYl9ycGttKSwxMF0gPC0gYygxOm5yb3cobGJfcnBrbSkpCmFsbF9jb21wIDwtIGFsbF9jb21wW29yZGVyKGFzLm51bWVyaWMoYWxsX2NvbXBbLDE1XSksZGVjcmVhc2luZz1UKSxdCmFsbF9jb21wWzE6bnJvdyhsbWFqX3Jwa20pLDE0XSA8LSBjKDE6bnJvdyhsbWFqX3Jwa20pKQoKd3JpdGUudGFibGUoYWxsX2NvbXAsJ0xteF92aXZvXzcyaHJ2aXRyb19MYnJfdml2b19MbWFqXzcyaHJ2aXRyb19nZW5lY29tcF8yMDE4MDEwNi50eHQnLHNlcD0nXHQnKQoKYWxsX2NvbXAgPC0gYWxsX2NvbXBbb3JkZXIoYXMubnVtZXJpYyhhbGxfY29tcFssM10pKSxdCnBsb3QoYWxsX2NvbXBbNDMxMzo0OTEyLDNdLGFsbF9jb21wWzQzMTM6NDkxMiw2XSxwY2g9MTksY2V4PTAuMiwKICAgICB4bGFiPSdSYW5rIChEQ0wgaW4gdml2byknLHlsYWI9J1JhbmsgKExDTCBpbiB2aXRyby03MmhycyknKQphYmxpbmUoaD0xMDAwLGNvbD0ncmVkJyxsdHk9MikKbGE3MmxvdyA8LSBhcy5udW1lcmljKGFsbF9jb21wWzQzMTM6NDkxMiw2XSk+MjAwMAp0ZXh0KHg9YXMubnVtZXJpYyhhbGxfY29tcFs0MzEzOjQ5MTIsM10pW2xhNzJsb3ddLAogICAgIHk9YXMubnVtZXJpYyhhbGxfY29tcFs0MzEzOjQ5MTIsNl0pW2xhNzJsb3ddLAogICAgIGxhYmVscz1hbGxfY29tcFs0MzEzOjQ5MTIsMl1bbGE3Mmxvd10sIGNleD0uNywgcG9zPTIpCmFsbF9jb21wIDwtIGFsbF9jb21wW2FsbF9jb21wWywyXSAlaW4lIGNvbW1vbi5nZW5lc1ssMV0sXQpmb3IoaSBpbiAxOm5yb3coYWxsX2NvbXApKXsKICBhbGxfY29tcFtpLDRdIDwtIDEtKGFzLm51bWVyaWMoYWxsX2NvbXBbaSwzXSkvbnJvdyhsbWV4X3Jwa20pKQogIGFsbF9jb21wW2ksN10gPC0gMS0oYXMubnVtZXJpYyhhbGxfY29tcFtpLDZdKS9ucm93KGxtZXhfcnBrbSkpCiAgYWxsX2NvbXBbaSwxMV0gPC0gMS0oYXMubnVtZXJpYyhhbGxfY29tcFtpLDEwXSkvbnJvdyhsYl9ycGttKSkKICBhbGxfY29tcFtpLDE1XSA8LSAxLShhcy5udW1lcmljKGFsbF9jb21wW2ksMTRdKS9ucm93KGxtYWpfcnBrbSkpCn0KCmxteHJhbmsgPC0gbG1leF9ycGttWyw1OjEwXQpmb3IoaSBpbiAxOm5jb2wobG14cmFuaykpewogIGxteHJhbmsgPC0gbG14cmFua1tvcmRlcihhcy5udW1lcmljKGxteHJhbmtbLGldKSxkZWNyZWFzaW5nID0gVCksXQogIGxteHJhbmtbLGldIDwtIGMoMTpucm93KGxteHJhbmspKQogIGZvcihqIGluIDE6bnJvdyhsbXhyYW5rKSl7CiAgICBsbXhyYW5rW2osaV0gPC0gMS0oYXMubnVtZXJpYyhsbXhyYW5rW2osaV0pL25yb3cobG14cmFuaykpCiAgfQp9CmxteHJhbmsgPC0gbG14cmFua1tyb3duYW1lcyhsbXhyYW5rKSAlaW4lIGFsbF9jb21wWywyXSxdCmxteHJhbmsgPC0gbG14cmFua1ttYXRjaChhbGxfY29tcFssMl0scm93bmFtZXMobG14cmFuaykpLF0KbG14dml0cm9yYW5rIDwtIGxtZXh2aXRyb19ycGttWyxjKDUsMTAsMTUpXQpmb3IoaSBpbiAxOm5jb2wobG14dml0cm9yYW5rKSl7CiAgbG14dml0cm9yYW5rIDwtIGxteHZpdHJvcmFua1tvcmRlcihhcy5udW1lcmljKGxteHZpdHJvcmFua1ssaV0pLGRlY3JlYXNpbmcgPSBUKSxdCiAgbG14dml0cm9yYW5rWyxpXSA8LSBjKDE6bnJvdyhsbXh2aXRyb3JhbmspKQogIGZvcihqIGluIDE6bnJvdyhsbXh2aXRyb3JhbmspKXsKICAgIGxteHZpdHJvcmFua1tqLGldIDwtIDEtKGFzLm51bWVyaWMobG14dml0cm9yYW5rW2osaV0pL25yb3cobG14dml0cm9yYW5rKSkKICB9Cn0KbG14dml0cm9yYW5rIDwtIGxteHZpdHJvcmFua1tyb3duYW1lcyhsbXh2aXRyb3JhbmspICVpbiUgYWxsX2NvbXBbLDJdLF0KbG14dml0cm9yYW5rIDwtIGxteHZpdHJvcmFua1ttYXRjaChhbGxfY29tcFssMl0scm93bmFtZXMobG14dml0cm9yYW5rKSksXQpsYnJyYW5rIDwtIGxiX3Jwa20KZm9yKGkgaW4gMTpuY29sKGxicnJhbmspKXsKICBsYnJyYW5rIDwtIGxicnJhbmtbb3JkZXIoYXMubnVtZXJpYyhsYnJyYW5rWyxpXSksZGVjcmVhc2luZyA9IFQpLF0KICBsYnJyYW5rWyxpXSA8LSBjKDE6bnJvdyhsYnJyYW5rKSkKICBmb3IoaiBpbiAxOm5yb3cobGJycmFuaykpewogICAgbGJycmFua1tqLGldIDwtIDEtKGFzLm51bWVyaWMobGJycmFua1tqLGldKS9ucm93KGxicnJhbmspKQogIH0KfQpsYnJyYW5rIDwtIGxicnJhbmtbcm93bmFtZXMobGJycmFuaykgJWluJSBhbGxfY29tcFssOV0sXQpsYnJyYW5rIDwtIGxicnJhbmtbbWF0Y2goYWxsX2NvbXBbLDldLHJvd25hbWVzKGxicnJhbmspKSxdCmxtYWpyYW5rIDwtIGxtYWpfcnBrbVssMjE6MjRdCmZvcihpIGluIDE6bmNvbChsbWFqcmFuaykpewogIGxtYWpyYW5rIDwtIGxtYWpyYW5rW29yZGVyKGFzLm51bWVyaWMobG1hanJhbmtbLGldKSxkZWNyZWFzaW5nID0gVCksXQogIGxtYWpyYW5rWyxpXSA8LSBjKDE6bnJvdyhsbWFqcmFuaykpCiAgZm9yKGogaW4gMTpucm93KGxtYWpyYW5rKSl7CiAgICBsbWFqcmFua1tqLGldIDwtIDEtKGFzLm51bWVyaWMobG1hanJhbmtbaixpXSkvbnJvdyhsbWFqcmFuaykpCiAgfQp9CmxtYWpyYW5rIDwtIGxtYWpyYW5rW3Jvd25hbWVzKGxtYWpyYW5rKSAlaW4lIGFsbF9jb21wWywxM10sXQpsbWFqcmFuayA8LSBsbWFqcmFua1ttYXRjaChhbGxfY29tcFssMTNdLHJvd25hbWVzKGxtYWpyYW5rKSksXQoKYWxsX3BjdGwgPC0gY2JpbmQobG14cmFuayxsbXh2aXRyb3JhbmssbGJycmFuayxsbWFqcmFuaykKcGN0bCA8LSBhbGxfcGN0bApoZWF0bWFwLjIocGN0bFtyb3dNZWFucyhhbGxfcGN0bFssMTo2XSk+MC45NSxdLHRyYWNlPSdub25lJywKICAgICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSg1MDApKQpoZWF0bWFwLjIocGN0bFtyb3dNZWFucyhhbGxfcGN0bFssNzo5XSk+MC45NSxdLHRyYWNlPSdub25lJywKICAgICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSg1MDApKQpoZWF0bWFwLjIocGN0bFtyb3dNZWFucyhhbGxfcGN0bFssMTA6MTVdKT4wLjk1LF0sdHJhY2U9J25vbmUnLAogICAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHbkJ1IikpKDUwMCkpCmhlYXRtYXAuMihwY3RsW3Jvd01lYW5zKGFsbF9wY3RsWywxNjoxOV0pPjAuOSxdLHRyYWNlPSdub25lJywKICAgICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSg1MDApKQpkYXRDb3IgPC0gY29yKHBjdGwsbWV0aG9kPSdwZWFyc29uJykKaGVhdG1hcC4yKGRhdENvciwKICAgICAgICAgIG1hcmdpbnM9YygxMCwgMTApLAogICAgICAgICAgc2NhbGU9Im5vbmUiLGJyZWFrcz1zZXEoMCwxLGxlbmd0aD0xMDEpLAogICAgICAgICAgdHJhY2U9Im5vbmUiLGNvbD0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHbkJ1IikpKDEwMCksCiAgICAgICAgICBzcnRDb2w9NDUsbWFpbj0nUGVhcnNvbiBjb3JyZWxhdGlvbicpCgpxLmFsbCA8LSBsb2cyQ1BNKGFsbF9wY3RsLAogICAgICAgICAgICAgICAgIGxpYi5zaXplID0gYyhjb2xTdW1zKGxtZXhfcnBrbSlbNToxMF0sY29sU3VtcyhsbWV4dml0cm9fcnBrbSlbYyg1LDEwLDE1KV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbFN1bXMobGJfcnBrbSksY29sU3VtcyhsbWFqX3Jwa20pWzIxOjI0XSkpCnMgPC0gbWFrZVNWRChhbGxfcGN0bCkKY29sIDwtIGMocmVwKCJyZWQiLHRpbWVzPTYpLHJlcCgiYmx1ZSIsdGltZXM9MykscmVwKCJvcmFuZ2UiLHRpbWVzPTYpLHJlcCgicHVycGxlIix0aW1lcz00KSkKcGxvdFBDKHMkdiwKICAgICAgIHMkZCwKICAgICAgIGNvbD0iYmxhY2siLAogICAgICAgcGNoPTIyLAogICAgICAgYmc9Y29sLCBjZXg9Mi42KQpsaWJyYXJ5KHBjYTNkKQpwY2FfM2QgPC0gcHJjb21wKHQoYWxsX3BjdGwpKQpwY2EzZChwY2FfM2QsIGNvbXBvbmVudHMgPSAxOjMsCiAgICAgIGdyb3VwID0gY29sKQpwY1JlcyhzJHYsIHMkZCwgY29sKVsxOjUsXQoKCnBjdGwgPC0gcmVhZC50YWJsZSgnYWxsc3BlY19yYW5rLnR4dCcsc2VwPSdcdCcsaGVhZGVyPVQpWywxOjRdCgpzdW0oYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1KS9zdW0ocGN0bFssMV0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1KS9zdW0ocGN0bFssMV0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1KS9zdW0ocGN0bFssMV0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1KS9zdW0ocGN0bFssMl0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1KS9zdW0ocGN0bFssMl0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1KS9zdW0ocGN0bFssMl0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1KS9zdW0ocGN0bFssM10gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1KS9zdW0ocGN0bFssM10gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1KS9zdW0ocGN0bFssM10gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywxXSkgPiAwLjk1KS9zdW0ocGN0bFssNF0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywyXSkgPiAwLjk1KS9zdW0ocGN0bFssNF0gPiAwLjk1KQpzdW0oYXMubnVtZXJpYyhwY3RsWyw0XSkgPiAwLjk1ICYgYXMubnVtZXJpYyhwY3RsWywzXSkgPiAwLjk1KS9zdW0ocGN0bFssNF0gPiAwLjk1KQoKcGN0bCA8LSBwY3RsW29yZGVyKGFzLm51bWVyaWMocGN0bFssMV0pLGRlY3JlYXNpbmc9VCksXQpoZWF0bWFwLjIoYXBwbHkocGN0bFtwY3RsWywxXSA+IDAuOCxdLDIsYXMubnVtZXJpYyksdHJhY2U9J25vbmUnLAogICAgICAgICAgUm93diA9IEYsIENvbHYgPSBGLCBkZW5kcm9ncmFtID0gJ25vbmUnLGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSg1MDApKQpwY3RsIDwtIHBjdGxbb3JkZXIoYXMubnVtZXJpYyhwY3RsWywyXSksZGVjcmVhc2luZz1UKSxdCmhlYXRtYXAuMihhcHBseShwY3RsW3BjdGxbLDJdID4gMC44LF0sMixhcy5udW1lcmljKSx0cmFjZT0nbm9uZScsCiAgICAgICAgICBSb3d2ID0gRiwgQ29sdiA9IEYsIGRlbmRyb2dyYW0gPSAnbm9uZScsY29sID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHbkJ1IikpKDUwMCkpCnBjdGwgPC0gcGN0bFtvcmRlcihhcy5udW1lcmljKHBjdGxbLDNdKSxkZWNyZWFzaW5nPVQpLF0KaGVhdG1hcC4yKGFwcGx5KHBjdGxbcGN0bFssM10gPiAwLjgsXSwyLGFzLm51bWVyaWMpLHRyYWNlPSdub25lJywKICAgICAgICAgIFJvd3YgPSBGLCBDb2x2ID0gRiwgZGVuZHJvZ3JhbSA9ICdub25lJyxjb2wgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwgIkduQnUiKSkoNTAwKSkKcGN0bCA8LSBwY3RsW29yZGVyKGFzLm51bWVyaWMocGN0bFssNF0pLGRlY3JlYXNpbmc9VCksXQpoZWF0bWFwLjIoYXBwbHkocGN0bFtwY3RsWyw0XSA+IDAuOCxdLDIsYXMubnVtZXJpYyksdHJhY2U9J25vbmUnLAogICAgICAgICAgUm93diA9IEYsIENvbHYgPSBGLCBkZW5kcm9ncmFtID0gJ25vbmUnLGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSg1MDApKQpgYGAK