1 Repeat a previous set of analyses and see where we differ

I am going to intersperse the original comments and code, then compare with my own analyses.

#lminfectome_dillonl_20150714_PCA_heatmap_samplediagnostics_limma_Lmajor60_metac_amast_no471_CDSonly_cecilia_forpublication.log
#Purpose: To repeat the analysis from 20150315, including the metacyclic samples in addition to the amastigote
#samples for the 5 batches for the human publication. HPGL0471 is excluded because it was found not to be an infected sample.cludes sample diagnostic, PCA, and heatmap analyses, as well as differential expression analysis to compare the o 4-hr amastigote transition and the amastigote samples across timepoints.
#This log is for parasite samples only using the count table restricted to CDS only.

#Count table generation is described in logs:
#lminfectome_dillonl_20140329_TopHat_HTSeq_Count_Table_hg19_Lmajor_HPGL0363-382_cecilia.log
#lminfectome_dillonl_20140712_TopHat_HTSeq_Count_Table_hg19_Lmajor_HPGL0396-405_cecilia.log
#lminfectome_dillonl_20141001_TopHat_HTSeq_Count_Table_hg19_Lamazonensis_Lmajor_beads_HPGL0434-446_452-472_cecilia.logectome_dillonl_20141211_TopHat_HTSeq_Count_Table_hg19_Lamazonensis_Lmajor_beads_HPGL0491-510_cecilia.log

#Name           condition       batch
#HPGL0364       metac (PNA)     A
#HPGL0366       amastLM4        A
#HPGL0368       amastLM24       A
#HPGL0370       amastLM48       A
#HPGL0372       amastLM72       A
#HPGL0374       metac (PNA)     B
#HPGL0376       amastLM4        B
#HPGL0380       amastLM48       B
#HPGL0382       amastLM72       B
#HPGL0397       metac (PNA)     C
#HPGL0399       amastLM4        C
#HPGL0401       amastLM24       C
#HPGL0403       amastLM48       C
#HPGL0405       amastLM72       C
#HPGL0456       metac (PNA)     E
#HPGL0459       amastLM4        E
#HPGL0463       amastLM24       E
#HPGL0467       amastLM48       E
#HPGL0494       metac (PNA)     F
#HPGL0497       amastLM4        F
#HPGL0501       amastLM24       F
#HPGL0505       amastLM48       F
#HPGL0509       amastLM72       F
#Count table is:
#20141211_Lmajor60_346_347_349_351_353_355_363_364_366_368_370_372_373_374_376_378_380_382_396_397_399_401_403_405_455-456_459_463_467_471_493-494_497_501_505_509_CDSonly.count
#Includes headers

#7-14-15

#L. major
#Create diagnostic plots
#Hector recommended that all diagnostics be done using the rawest data possible. For correlation analyses between samples,
#use countsTable data without filtering out lowly expressed genes and without normalization. Size factor normalization
#will be used to show the distribution of gene expression levels.

#This analysis uses count tables that have not been restricted to no471_CDS only.
#20141211_Lmajor60_346_347_349_351_353_355_363_364_366_368_370_372_373_374_376_378_380_382_396_397_399_401_403_405_455-456_459_463_467_471_493-494_497_501_505_509_CDSonly.count
library(cbcbSEQ)
## Loading required package: limma
## Loading required package: corpcor
## Loading required package: preprocessCore
## Loading required package: sva
## Loading required package: mgcv
## Loading required package: nlme
## 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(gplots)
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
library(matrixStats)
## 
## Attaching package: 'matrixStats'
## The following objects are masked from 'package:genefilter':
## 
##     rowSds, rowVars
library(siggenes)
## Loading required package: Biobase
## 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 object is masked from 'package:limma':
## 
##     plotMA
## 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
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## Attaching package: 'Biobase'
## The following objects are masked from 'package:matrixStats':
## 
##     anyMissing, rowMedians
## Loading required package: multtest
## 
## Attaching package: 'multtest'
## The following object is masked from 'package:gplots':
## 
##     wapply
## Loading required package: splines
library(ReportingTools)
## Error in library(ReportingTools): there is no package called 'ReportingTools'
library(hwriter)
library(DESeq2)
## Loading required package: S4Vectors
## Loading required package: stats4
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:gplots':
## 
##     space
## The following object is masked from 'package:base':
## 
##     expand.grid
## Loading required package: IRanges
## 
## Attaching package: 'IRanges'
## The following object is masked from 'package:nlme':
## 
##     collapse
## Loading required package: GenomicRanges
## Loading required package: GenomeInfoDb
## Loading required package: SummarizedExperiment
## Loading required package: DelayedArray
## 
## Attaching package: 'DelayedArray'
## The following objects are masked from 'package:matrixStats':
## 
##     colMaxs, colMins, colRanges, rowMaxs, rowMins, rowRanges
## The following object is masked from 'package:base':
## 
##     apply
library(RColorBrewer)

#Read in counts table
countsTable <- read.table("preprocessing/dillonl/20141211_Lmajor60_346_347_349_351_353_355_363_364_366_368_370_372_373_374_376_378_380_382_396_397_399_401_403_405_455-456_459_463_467_471_493-494_497_501_505_509_CDSonly.count.xz", header=TRUE)
#Remove id as an actual column, use as row names instead
rownames(countsTable) <- countsTable$id
countsTable <- countsTable[, -1, drop=FALSE]

#Restrict to samples of interest (exclude procyclic promastigote samples and HPGL0471)
countsTable <- countsTable[,-c(1:7, 13, 19, 25, 30:31)]

#Establish metadata for samples
sampleID <- colnames(countsTable)
condition <- rep(c("metac", "amast4", "amast24", "amast48", "amast72"), times=5)
batch <- rep(c("A", "B", "C", "E", "F"), each=5)
condition <- condition[-20]
batch <- batch[-20]

condition <- factor(condition, levels=c("metac", "amast4", "amast24", "amast48", "amast72"))
batch <- factor(batch, levels=c("A", "B", "C", "E", "F"))
design <- data.frame(sampleID=sampleID, condition=condition, batch=batch)
knitr::kable(design)
sampleID condition batch
HPGL0364 metac A
HPGL0366 amast4 A
HPGL0368 amast24 A
HPGL0370 amast48 A
HPGL0372 amast72 A
HPGL0374 metac B
HPGL0376 amast4 B
HPGL0378 amast24 B
HPGL0380 amast48 B
HPGL0382 amast72 B
HPGL0397 metac C
HPGL0399 amast4 C
HPGL0401 amast24 C
HPGL0403 amast48 C
HPGL0405 amast72 C
HPGL0456 metac E
HPGL0459 amast4 E
HPGL0463 amast24 E
HPGL0467 amast48 E
HPGL0494 metac F
HPGL0497 amast4 F
HPGL0501 amast24 F
HPGL0505 amast48 F
HPGL0509 amast72 F

2 Plots!

colnames(countsTable) <- paste(condition, batch, 1:length(condition), sep=".")
#View barplot of raw counts by sample
barplot(colSums(countsTable), las=3, ylim=c(0,3e+07))

df <- data.frame(cond=(condition))
dds <- DESeqDataSetFromMatrix(countData=countsTable, colData = df, design = ~ cond)
dds <- estimateSizeFactors(dds)
ncts <- counts(dds, normalized=TRUE)
y <- log(ncts + 1)

#Determine median and quantiles of the size factor normalized, log2 counts
median(y)
## [1] 5.886
#[1] 5.886309

quantile(y)
##     0%    25%    50%    75%   100% 
##  0.000  5.436  5.886  6.357 10.833
#       0%       25%       50%       75%      100%
# 0.000000  5.435910  5.886309  6.357313 10.832889

#Determine number of genes per sample with less than log2 of 2 counts (less than 4 counts per mill)
ydf <- as.data.frame(y)
colnames(ydf) <- sampleID

col.nam <- paste(condition, batch, 1:length(condition), sep=".")
#Boxplot of per sample log of size-factor-normalized counts (+ 1)
par(mar=c(10.5,4.5,2,1))
par(oma=c(0,0,0,0))
boxplot(y, names=col.nam, las=3)

#Heatmap of Pearson correlation between samples
#(delete Rowv, Colv, and dendrogram parameters if want samples to sort and show dendrogram)
#Correlation analysis (Pearson is default for cor unless othewise specified)
#Using raw counts
datCor <- cor(countsTable)
heatmap.2(datCor, Rowv=NA, Colv=NA,
          margins=c(10, 10),
          labRow=col.nam,
          labCol=col.nam,
          dendrogram="none",
          scale="none",
          trace="none",
          srtCol=45)

#Using raw counts
corM <- matrixStats::rowMedians(cor(countsTable))
qs <- quantile(corM,p=c(1,3)/4)
iqr <- diff(qs)
outLimit <- qs[1] - 1.5 * iqr
ylim <- c(pmin(min(corM),outLimit),max(corM))
col <-  ifelse(condition=="amast4", "cornflowerblue",
        ifelse(condition=="amast24", "gold",
        ifelse(condition=="amast48", "green3",
        ifelse(condition=="amast72", "coral", "mediumorchid4"))))

plot(corM, xaxt="n", ylim=ylim, ylab="Median Pairwise Correlation", xlab="", main="", col=col, pch=16, cex=2.2)
axis(side=1,at=seq(along=corM),labels=paste(condition,batch,sep=":"),las=2)
abline(h=outLimit,lty=2)
abline(v=1:length(col.nam), lty=3, col="black")

#Use filterCounts method to filter for low counts
#Define filterCounts function
filterCounts = function (counts, lib.size = NULL, thresh = 1, minSamples = 2) {
    cpms <- 2^log2CPM(counts, lib.size = lib.size)$y
    keep <- rowSums(cpms > thresh) >= minSamples
    counts <- counts[keep, ]
    counts
}
x <- table(condition)
dim(countsTable)
## [1] 8486   24
#[1] 8486   24
counts <- filterCounts(countsTable, thresh=1, minSamples=min(x))
dim(counts)
## [1] 8480   24
#[1] 8480   24

#Quantile normalize counts
countsSubQ <- qNorm(counts)
#Explore data for batch effects
#Transform data to log2 counts per million
x <- log2CPM(countsSubQ)
#Compute principal components
s <- makeSVD(x$y)

#Compute variance of each PC and how they correlate with batch and condition
pcRes(s$v, s$d, condition, batch)
##    propVar cumPropVar cond.R2 batch.R2
## 1    39.68      39.68   82.46    13.46
## 2    12.96      52.64   14.53    61.01
## 3     8.02      60.66   35.08    18.08
## 4     7.13      67.79   54.67    13.29
## 5     5.35      73.14    7.61    63.48
## 6     4.23      77.37   14.21    37.35
## 7     3.48      80.85   16.10    35.96
## 8     2.94      83.79   23.22    22.08
## 9     2.15      85.94   13.26    46.74
## 10    2.11      88.05   16.58    18.60
## 11    1.76      89.81    8.03    24.71
## 12    1.58      91.39    5.81     3.39
## 13    1.36      92.75   34.83     4.28
## 14    1.28      94.03    2.16     7.12
## 15    1.08      95.11    7.23     6.02
## 16    0.87      95.98    6.08     3.74
## 17    0.77      96.75    0.84     8.10
## 18    0.72      97.47    0.49     0.82
## 19    0.60      98.07    4.59     4.24
## 20    0.57      98.64    2.70     2.46
## 21    0.48      99.12   36.70     1.44
## 22    0.46      99.58    9.52     0.94
## 23    0.41      99.99    3.29     2.70
#   propVar cumPropVar cond.R2 batch.R2
#1    39.68      39.68   82.46    13.46
#2    12.96      52.64   14.53    61.01
#3     8.02      60.66   35.08    18.08
#4     7.13      67.79   54.67    13.29
#5     5.35      73.14    7.61    63.48
#6     4.23      77.37   14.21    37.35
#7     3.48      80.85   16.10    35.96
#8     2.94      83.79   23.22    22.08
#9     2.15      85.94   13.26    46.74
#10    2.11      88.05   16.58    18.60
#11    1.76      89.81    8.03    24.71
#12    1.58      91.39    5.81     3.39
#13    1.36      92.75   34.83     4.28
#14    1.28      94.03    2.16     7.12
#15    1.08      95.11    7.23     6.02
#16    0.87      95.98    6.08     3.74
#17    0.77      96.75    0.84     8.10
#18    0.72      97.47    0.49     0.82
#19    0.60      98.07    4.59     4.24
#20    0.57      98.64    2.70     2.46
#21    0.48      99.12   36.70     1.44
#22    0.46      99.58    9.52     0.94
#23    0.41      99.99    3.29     2.70

#Plot PC1 vs. PC2, with black outlines and color fills
#Save as eps
condnum <- as.numeric(condition)
plotPC(s$v,
       s$d,
       col="black",
       pch=ifelse(batch=="A", 25, ifelse(batch=="B", 21, ifelse(batch=="C", 22, ifelse(batch=="E", 24, 23)))),
       bg=ifelse(condnum==1, "mediumorchid4", ifelse(condnum==2, "cornflowerblue", ifelse(condnum==3, "gold", ifelse(condnum==4, "green3", "coral")))), cex=2.6
       )
legend(x=-0.11, y=-0.40, legend=c("metac", "amast4", "amast24", "amast48", "amast72"), pch=22, col=0,
pt.bg=c("mediumorchid4", "cornflowerblue", "gold", "green3", "coral"), pt.cex=2.6, bty="n")
text(s$v[,1], s$v[,2], colnames(countsTable), cex=.7, pos=4)

#View as a Euclidean distance heatmap
dists <- dist(t(counts))
mat <- as.matrix(dists)
rownames(mat) <- colnames(mat) <- with(design, paste(colnames(countsTable)))
hmcol <- colorRampPalette(brewer.pal(9, "GnBu"))(100)
vec.batch <- rainbow(nlevels(batch), start=0, end=.8)
batch.color <- rep(0, length(batch))
for (i in 1:length(batch)) {
    batch.color[i] <- vec.batch[batch[i]==levels(batch)]
}
vec.condition <- c("mediumorchid4", "cornflowerblue", "gold", "green3", "coral")
condition.color <- rep(0, length(condition))
for (i in 1:length(condition)) {
    condition.color[i] <- vec.condition[condition[i]==levels(condition)]
}
heatmap <- heatmap.2(mat, trace="none", col = rev(hmcol), margin=c(11,11), ColSideColors=condition.color,
RowSideColors=batch.color, key="FALSE", srtCol=45)

#I would like to create a PCA plot and heatmap to reflect the use of batch in the limma model
#Specify model
mod <- model.matrix(~batch)

#Use voom to determine weights for fitting the mean-variance trend for each gene
v <- voom(countsSubQ, mod)
#Fit the linear model for each gene
fit <- lmFit(v)

#Get the residual (i.e. everything except for the batch effect)
newData <- residuals(fit, v)
#Explore data for batch effects
#Compute principal components
s <- makeSVD(newData)

#Compute variance of each PC and how they correlate with batch and condition
pcRes(s$v, s$d, condition, batch)
##    propVar cumPropVar cond.R2 batch.R2
## 1    47.04      47.04   93.02        0
## 2    10.77      57.81   56.14        0
## 3     8.74      66.55   54.42        0
## 4     7.16      73.71    7.30        0
## 5     4.45      78.16   49.96        0
## 6     3.73      81.89    4.61        0
## 7     3.11      85.00    8.66        0
## 8     2.22      87.22    1.08        0
## 9     2.10      89.32   13.03        0
## 10    1.89      91.21   14.31        0
## 11    1.63      92.84   27.11        0
## 12    1.42      94.26    1.27        0
## 13    1.13      95.39    7.26        0
## 14    0.97      96.36    0.42        0
## 15    0.92      97.28    2.73        0
## 16    0.80      98.08    4.79        0
## 17    0.68      98.76   22.51        0
## 18    0.64      99.40   19.19        0
## 19    0.58      99.98    8.19        0
## 20    0.00      99.98    0.34      100
## 21    0.00      99.98    1.23      100
## 22    0.00      99.98    2.13      100
#   propVar cumPropVar cond.R2 batch.R2
#1    47.04      47.04   93.02        0
#2    10.77      57.81   56.14        0
#3     8.74      66.55   54.42        0
#4     7.16      73.71    7.30        0
#5     4.45      78.16   49.96        0
#6     3.73      81.89    4.61        0
#7     3.11      85.00    8.66        0
#8     2.22      87.22    1.08        0
#9     2.10      89.32   13.03        0
#10    1.89      91.21   14.31        0
#11    1.63      92.84   27.11        0
#12    1.42      94.26    1.27        0
#13    1.13      95.39    7.26        0
#14    0.97      96.36    0.42        0
#15    0.92      97.28    2.73        0
#16    0.80      98.08    4.79        0
#17    0.68      98.76   22.51        0
#18    0.64      99.40   19.19        0
#19    0.58      99.98    8.19        0
#20    0.00      99.98    0.34      100
#21    0.00      99.98    1.24      100
#22    0.00      99.98    2.12      100

#Plot PC1 vs. PC2, with black outlines and color fills
#Save as eps
condnum <- as.numeric(condition)
plotPC(s$v,
       s$d,
       col="black",
       pch=ifelse(batch=="A", 25, ifelse(batch=="B", 21, ifelse(batch=="C", 22, ifelse(batch=="E", 24, 23)))),
       bg=ifelse(condnum==1, "mediumorchid4", ifelse(condnum==2, "cornflowerblue", ifelse(condnum==3, "gold", ifelse(condnum==4, "green3", "coral")))), cex=2.6
       )
legend(x=-0.48, y=-0.24, legend=c("metac", "amast4", "amast24", "amast48", "amast72"), pch=22, col=0,
pt.bg=c("mediumorchid4", "cornflowerblue", "gold", "green3", "coral"), pt.cex=2.6, bty="n")
text(s$v[,1], s$v[,2], colnames(countsTable), cex=.7, pos=4)

#View as a Euclidean distance heatmap
dists <- dist(t(newData))
mat <- as.matrix(dists)
rownames(mat) <- colnames(mat) <- with(design, paste(colnames(countsTable)))
hmcol <- colorRampPalette(brewer.pal(9, "GnBu"))(100)

vec.batch <- rainbow(nlevels(batch), start=0, end=.8)
batch.color <- rep(0, length(batch))
for (i in 1:length(batch)) {
    batch.color[i] <- vec.batch[batch[i]==levels(batch)]
}
vec.condition <- c("mediumorchid4", "cornflowerblue", "gold", "green3", "coral")
condition.color <- rep(0, length(condition))
for (i in 1:length(condition)) {
    condition.color[i] <- vec.condition[condition[i]==levels(condition)]
}

heatmap <- heatmap.2(mat, trace="none", col = rev(hmcol), margin=c(11,11), ColSideColors=condition.color,
                     RowSideColors=batch.color, key="FALSE", srtCol=45)

countsSubQ <- qNorm(counts)
#Specify model
mod = model.matrix(~0+condition+batch)
#View mean-variance trend
v <- voom(countsSubQ, mod, plot=TRUE)

#Fit a linear model for each gene using the specified design contained in v
fit <- lmFit(v)
##metac v amast4##
#eBayes finds an F-statistic from the set of t-statistics for that gene
metac.amast4.contr.mat <- makeContrasts(metac_v_amast4=conditionamast4-conditionmetac, levels=v$design)
metac.amast4.fit <- contrasts.fit(fit, metac.amast4.contr.mat)
metac.amast4.eb <- eBayes(metac.amast4.fit)
metac.amast4.topTab <- topTable(metac.amast4.eb, coef="metac_v_amast4", number=nrow(v$E))
metac.amast4.topTab[["fold_change"]] <- 2 ^ metac.amast4.topTab[["logFC"]]
write.csv(file="csv/lmajor_metac_vs_amast4.csv", x=metac.amast4.topTab)

#View the list of DE genes
head(metac.amast4.topTab, n=3L)
##                logFC AveExpr     t   P.Value adj.P.Val     B fold_change
## LmjF.19.1530-1 1.480   8.453 14.50 8.359e-14 3.599e-10 21.44       2.790
## LmjF.26.0640-1 1.822   7.266 14.49 8.488e-14 3.599e-10 21.31       3.537
## LmjF.36.2030-1 1.387   8.786 11.68 1.026e-11 1.822e-08 16.86       2.616
#                  logFC  AveExpr        t      P.Value    adj.P.Val        B
#LmjF.19.1530-1 1.480236 8.453253 14.50158 8.359353e-14 3.598949e-10 21.43701
#LmjF.26.0640-1 1.822403 7.266265 14.49185 8.488086e-14 3.598949e-10 21.30901
#LmjF.36.2030-1 1.387168 8.785515 11.67783 1.026427e-11 1.822331e-08 16.85840


#Limit list to genes with an adjusted p value < 0.05
metac.amast4.sigGenes <- metac.amast4.topTab[metac.amast4.topTab$adj.P.Val <0.05, ]
length(metac.amast4.sigGenes$logFC)
## [1] 3224
#3224

#Filter out rows with less than 2-fold change (log2 fold change of > 1)
metac.amast4.sigGenesFold1 <- subset(metac.amast4.sigGenes, abs(logFC) > 1)
length(metac.amast4.sigGenesFold1$logFC)
## [1] 304
#304

#Filter out rows with less than 4-fold change (log2 fold change of > 2)
metac.amast4.sigGenesFold2 <- subset(metac.amast4.sigGenes, abs(logFC) > 2)
length(metac.amast4.sigGenesFold2$logFC)
## [1] 12
#12

metac.amast4.sigGenes <- metac.amast4.sigGenes[order(-metac.amast4.sigGenes$logFC), ]

#Make an MA plot
sel = metac.amast4.topTab$adj.P.Val < 0.05
top = metac.amast4.topTab
sub = paste("No. of sig. genes: ", sum(sel),"/",length(sel))
cpm = v$E

plot(rowMeans(cpm[rownames(top),]), top$logFC, pch=16, cex=0.5,col="darkgrey",
        main="metac_amast4 model batch adjusted",
        ylab="log FC", xlab="Average Expression",
        ylim=c(-3,3), sub=sub)
points(rowMeans(cpm[rownames(top),])[sel], top$logFC[sel], col="red", cex=0.5)
abline(h=c(-1,0,1), col="red")

##amast4 v amast24##
#eBayes finds an F-statistic from the set of t-statistics for that gene
amast4.amast24.contr.mat <- makeContrasts(amast4_v_amast24=conditionamast24-conditionamast4, levels=v$design)
amast4.amast24.fit <- contrasts.fit(fit, amast4.amast24.contr.mat)
amast4.amast24.eb <- eBayes(amast4.amast24.fit)
amast4.amast24.topTab <- topTable(amast4.amast24.eb, coef="amast4_v_amast24", number=nrow(v$E))
#View the list of DE genes
head(amast4.amast24.topTab, n=3L)
##                 logFC AveExpr     t   P.Value adj.P.Val      B
## LmjF.28.1570-1 1.5786   6.136 8.744 3.870e-09 3.282e-05 10.769
## LmjF.05.0010-1 0.9452   8.273 8.130 1.540e-08 5.636e-05  9.638
## LmjF.36.2760-1 1.3463   5.846 8.018 1.994e-08 5.636e-05  9.229
#                   logFC  AveExpr        t      P.Value    adj.P.Val         B
#LmjF.28.1570-1 1.5785593 6.135850 8.744485 3.869906e-09 3.281680e-05 10.769201
#LmjF.05.0010-1 0.9451551 8.273246 8.130366 1.539908e-08 5.635831e-05  9.638152
#LmjF.36.2760-1 1.3462634 5.845910 8.017909 1.993808e-08 5.635831e-05  9.229250

#Limit list to genes with an adjusted p value < 0.05
amast4.amast24.sigGenes <- amast4.amast24.topTab[amast4.amast24.topTab$adj.P.Val <0.05, ]
length(amast4.amast24.sigGenes$logFC)
## [1] 356
#356

#Filter out rows with less than 2-fold change (log2 fold change of > 1)
amast4.amast24.sigGenesFold1 <- subset(amast4.amast24.sigGenes, abs(logFC) > 1)
length(amast4.amast24.sigGenesFold1$logFC)
## [1] 38
#38

#Filter out rows with less than 4-fold change (log2 fold change of > 2)
amast4.amast24.sigGenesFold2 <- subset(amast4.amast24.sigGenes, abs(logFC) > 2)
length(amast4.amast24.sigGenesFold2$logFC)
## [1] 1
#1

amast4.amast24.sigGenes <- amast4.amast24.sigGenes[order(-amast4.amast24.sigGenes$logFC), ]
#Make an MA plot
sel = amast4.amast24.topTab$adj.P.Val < 0.05
top = amast4.amast24.topTab
sub = paste("No. of sig. genes: ", sum(sel),"/",length(sel))
cpm = v$E


plot(rowMeans(cpm[rownames(top),]), top$logFC, pch=16, cex=0.5,col="darkgrey",
        main="amast4_amast24 model batch adjusted",
        ylab="log FC", xlab="Average Expression",
        ylim=c(-3,3), sub=sub)
points(rowMeans(cpm[rownames(top),])[sel], top$logFC[sel], col="red", cex=0.5)
abline(h=c(-1,0,1), col="red")

dev.off()
## null device 
##           1
##amast24 v amast48##
#eBayes finds an F-statistic from the set of t-statistics for that gene
amast24.amast48.contr.mat <- makeContrasts(amast24_v_amast48=conditionamast48-conditionamast24, levels=v$design)
amast24.amast48.fit <- contrasts.fit(fit, amast24.amast48.contr.mat)
amast24.amast48.eb <- eBayes(amast24.amast48.fit)
amast24.amast48.topTab <- topTable(amast24.amast48.eb, coef="amast24_v_amast48", number=nrow(v$E))

#View the list of DE genes
head(amast24.amast48.topTab, n=3L)
##                  logFC AveExpr      t   P.Value adj.P.Val     B
## LmjF.36.2760-1 -0.9615   5.846 -5.831 4.143e-06   0.02907 3.175
## LmjF.04.0310-1 -1.0496   6.963 -5.552 8.498e-06   0.02907 2.911
## LmjF.29.2710-1  0.6017   6.277  5.478 1.028e-05   0.02907 2.662
#                    logFC  AveExpr         t      P.Value  adj.P.Val        B
#LmjF.36.2760-1 -0.9614720 5.845910 -5.831286 4.142968e-06 0.02907032 3.175088
#LmjF.04.0310-1 -1.0496414 6.963380 -5.551887 8.497593e-06 0.02907032 2.910560
#LmjF.29.2710-1  0.6016944 6.277076  5.478035 1.028431e-05 0.02907032 2.661694

#Limit list to genes with an adjusted p value < 0.05
amast24.amast48.sigGenes <- amast24.amast48.topTab[amast24.amast48.topTab$adj.P.Val <0.05, ]
length(amast24.amast48.sigGenes$logFC)
## [1] 3
#3

#Filter out rows with less than 2-fold change (log2 fold change of > 1)
amast24.amast48.sigGenesFold1 <- subset(amast24.amast48.sigGenes, abs(logFC) > 1)
length(amast24.amast48.sigGenesFold1$logFC)
## [1] 1
#1

#Filter out rows with less than 4-fold change (log2 fold change of > 2)
amast24.amast48.sigGenesFold2 <- subset(amast24.amast48.sigGenes, abs(logFC) > 2)
length(amast24.amast48.sigGenesFold2$logFC)
## [1] 0
amast24.amast48.sigGenes <- amast24.amast48.sigGenes[order(-amast24.amast48.sigGenes$logFC), ]

#Make an MA plot
sel = amast24.amast48.topTab$adj.P.Val < 0.05
top = amast24.amast48.topTab
sub = paste("No. of sig. genes: ", sum(sel),"/",length(sel))
cpm = v$E
plot(rowMeans(cpm[rownames(top),]), top$logFC, pch=16, cex=0.5,col="darkgrey",
        main="amast24_amast48 model batch adjusted",
        ylab="log FC", xlab="Average Expression",
        ylim=c(-3,3), sub=sub)
points(rowMeans(cpm[rownames(top),])[sel], top$logFC[sel], col="red", cex=0.5)
abline(h=c(-1,0,1), col="red")

##amast48 v amast72##
#eBayes finds an F-statistic from the set of t-statistics for that gene
amast48.amast72.contr.mat <- makeContrasts(amast48_v_amast72=conditionamast72-conditionamast48, levels=v$design)
amast48.amast72.fit <- contrasts.fit(fit, amast48.amast72.contr.mat)
amast48.amast72.eb <- eBayes(amast48.amast72.fit)
amast48.amast72.topTab <- topTable(amast48.amast72.eb, coef="amast48_v_amast72", number=nrow(v$E))

#View the list of DE genes
head(amast48.amast72.topTab, n=3L)
##                  logFC AveExpr      t   P.Value adj.P.Val       B
## LmjF.23.0025-1 -0.5558   6.033 -4.173 0.0003087    0.3816 -0.2582
## LmjF.13.1500-1  0.5284   7.658  3.932 0.0005761    0.3816 -0.5304
## LmjF.22.1640-1 -0.6805   6.958 -3.882 0.0006544    0.3816 -0.6542
#                    logFC  AveExpr         t      P.Value adj.P.Val          B
#LmjF.23.0025-1 -0.5557985 6.033048 -4.172762 0.0003086924 0.3815768 -0.2582314
#LmjF.13.1500-1  0.5283509 7.658283  3.931807 0.0005760897 0.3815768 -0.5303752
#LmjF.22.1640-1 -0.6805308 6.957837 -3.882314 0.0006544461 0.3815768 -0.6542054

#Limit list to genes with an adjusted p value < 0.05
amast48.amast72.sigGenes <- amast48.amast72.topTab[amast48.amast72.topTab$adj.P.Val <0.05, ]
length(amast48.amast72.sigGenes$logFC)
## [1] 0
#0

#Make an MA plot
sel = amast48.amast72.topTab$adj.P.Val < 0.05
top = amast48.amast72.topTab
sub = paste("No. of sig. genes: ", sum(sel),"/",length(sel))
cpm = v$E

plot(rowMeans(cpm[rownames(top),]), top$logFC, pch=16, cex=0.5,col="darkgrey",
        main="amast48_amast72 model batch adjusted",
        ylab="log FC", xlab="Average Expression",
        ylim=c(-3,3), sub=sub)
points(rowMeans(cpm[rownames(top),])[sel], top$logFC[sel], col="red", cex=0.5)
abline(h=c(-1,0,1), col="red")
if (isTRUE(get0("skip_load"))) {
  pander::pander(sessionInfo())
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  message(paste0("Saving to ", savefile))
  tmp <- sm(saveme(filename=savefile))
}
LS0tCnRpdGxlOiAiTC5tYWpvci9hbWF6b25lbnNpcyAyMDE2OiBSZXBlYXQgcHJldmlvdXMgbG1ham9yIGh1bWFuIGxvZ3MuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogIGNvZGVfZG93bmxvYWQ6IHRydWUKICBjb2RlX2ZvbGRpbmc6IHNob3cKICBmaWdfY2FwdGlvbjogdHJ1ZQogIGZpZ19oZWlnaHQ6IDcKICBmaWdfd2lkdGg6IDcKICBoaWdobGlnaHQ6IHRhbmdvCiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogY29zbW8KICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgIGNvbGxhcHNlZDogZmFsc2UKICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CmJvZHkgLm1haW4tY29udGFpbmVyIHsKbWF4LXdpZHRoOiAxNjAwcHg7Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIGxpYnJhcnkoaHBnbHRvb2xzKQogIHR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQogIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKICBrbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQogIG9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCiAgZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCiAgdmVyIDwtICIyMDE4MDQyNCIKICBwcmV2aW91c19maWxlIDwtIHBhc3RlMCgiaW5kZXguUm1kIikKCiAgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9Z3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSJcXC5yZGFcXC54eiIsIHg9cHJldmlvdXNfZmlsZSkpKSkKICBybWRfZmlsZSA8LSBwYXN0ZTAoInJlcGVhdF9sb2dfbG1ham9yX2hzYXBpZW5zLlJtZCIpCiAgc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSJcXC5yZGFcXC54eiIsIHg9cm1kX2ZpbGUpCn0KYGBgCgojIFJlcGVhdCBhIHByZXZpb3VzIHNldCBvZiBhbmFseXNlcyBhbmQgc2VlIHdoZXJlIHdlIGRpZmZlcgoKSSBhbSBnb2luZyB0byBpbnRlcnNwZXJzZSB0aGUgb3JpZ2luYWwgY29tbWVudHMgYW5kIGNvZGUsIHRoZW4gY29tcGFyZSB3aXRoIG15IG93biBhbmFseXNlcy4KCjxwcmU+CiNsbWluZmVjdG9tZV9kaWxsb25sXzIwMTUwNzE0X1BDQV9oZWF0bWFwX3NhbXBsZWRpYWdub3N0aWNzX2xpbW1hX0xtYWpvcjYwX21ldGFjX2FtYXN0X25vNDcxX0NEU29ubHlfY2VjaWxpYV9mb3JwdWJsaWNhdGlvbi5sb2cKI1B1cnBvc2U6IFRvIHJlcGVhdCB0aGUgYW5hbHlzaXMgZnJvbSAyMDE1MDMxNSwgaW5jbHVkaW5nIHRoZSBtZXRhY3ljbGljIHNhbXBsZXMgaW4gYWRkaXRpb24gdG8gdGhlIGFtYXN0aWdvdGUKI3NhbXBsZXMgZm9yIHRoZSA1IGJhdGNoZXMgZm9yIHRoZSBodW1hbiBwdWJsaWNhdGlvbi4gSFBHTDA0NzEgaXMgZXhjbHVkZWQgYmVjYXVzZSBpdCB3YXMgZm91bmQgbm90IHRvIGJlIGFuIGluZmVjdGVkIHNhbXBsZS5jbHVkZXMgc2FtcGxlIGRpYWdub3N0aWMsIFBDQSwgYW5kIGhlYXRtYXAgYW5hbHlzZXMsIGFzIHdlbGwgYXMgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgdG8gY29tcGFyZSB0aGUgbyA0LWhyIGFtYXN0aWdvdGUgdHJhbnNpdGlvbiBhbmQgdGhlIGFtYXN0aWdvdGUgc2FtcGxlcyBhY3Jvc3MgdGltZXBvaW50cy4KI1RoaXMgbG9nIGlzIGZvciBwYXJhc2l0ZSBzYW1wbGVzIG9ubHkgdXNpbmcgdGhlIGNvdW50IHRhYmxlIHJlc3RyaWN0ZWQgdG8gQ0RTIG9ubHkuCgojQ291bnQgdGFibGUgZ2VuZXJhdGlvbiBpcyBkZXNjcmliZWQgaW4gbG9nczoKI2xtaW5mZWN0b21lX2RpbGxvbmxfMjAxNDAzMjlfVG9wSGF0X0hUU2VxX0NvdW50X1RhYmxlX2hnMTlfTG1ham9yX0hQR0wwMzYzLTM4Ml9jZWNpbGlhLmxvZwojbG1pbmZlY3RvbWVfZGlsbG9ubF8yMDE0MDcxMl9Ub3BIYXRfSFRTZXFfQ291bnRfVGFibGVfaGcxOV9MbWFqb3JfSFBHTDAzOTYtNDA1X2NlY2lsaWEubG9nCiNsbWluZmVjdG9tZV9kaWxsb25sXzIwMTQxMDAxX1RvcEhhdF9IVFNlcV9Db3VudF9UYWJsZV9oZzE5X0xhbWF6b25lbnNpc19MbWFqb3JfYmVhZHNfSFBHTDA0MzQtNDQ2XzQ1Mi00NzJfY2VjaWxpYS5sb2dlY3RvbWVfZGlsbG9ubF8yMDE0MTIxMV9Ub3BIYXRfSFRTZXFfQ291bnRfVGFibGVfaGcxOV9MYW1hem9uZW5zaXNfTG1ham9yX2JlYWRzX0hQR0wwNDkxLTUxMF9jZWNpbGlhLmxvZwoKI05hbWUgICAgICAgICAgIGNvbmRpdGlvbiAgICAgICBiYXRjaAojSFBHTDAzNjQgICAgICAgbWV0YWMgKFBOQSkgICAgIEEKI0hQR0wwMzY2ICAgICAgIGFtYXN0TE00ICAgICAgICBBCiNIUEdMMDM2OCAgICAgICBhbWFzdExNMjQgICAgICAgQQojSFBHTDAzNzAgICAgICAgYW1hc3RMTTQ4ICAgICAgIEEKI0hQR0wwMzcyICAgICAgIGFtYXN0TE03MiAgICAgICBBCiNIUEdMMDM3NCAgICAgICBtZXRhYyAoUE5BKSAgICAgQgojSFBHTDAzNzYgICAgICAgYW1hc3RMTTQgICAgICAgIEIKI0hQR0wwMzgwICAgICAgIGFtYXN0TE00OCAgICAgICBCCiNIUEdMMDM4MiAgICAgICBhbWFzdExNNzIgICAgICAgQgojSFBHTDAzOTcgICAgICAgbWV0YWMgKFBOQSkgICAgIEMKI0hQR0wwMzk5ICAgICAgIGFtYXN0TE00ICAgICAgICBDCiNIUEdMMDQwMSAgICAgICBhbWFzdExNMjQgICAgICAgQwojSFBHTDA0MDMgICAgICAgYW1hc3RMTTQ4ICAgICAgIEMKI0hQR0wwNDA1ICAgICAgIGFtYXN0TE03MiAgICAgICBDCiNIUEdMMDQ1NiAgICAgICBtZXRhYyAoUE5BKSAgICAgRQojSFBHTDA0NTkgICAgICAgYW1hc3RMTTQgICAgICAgIEUKI0hQR0wwNDYzICAgICAgIGFtYXN0TE0yNCAgICAgICBFCiNIUEdMMDQ2NyAgICAgICBhbWFzdExNNDggICAgICAgRQojSFBHTDA0OTQgICAgICAgbWV0YWMgKFBOQSkgICAgIEYKI0hQR0wwNDk3ICAgICAgIGFtYXN0TE00ICAgICAgICBGCiNIUEdMMDUwMSAgICAgICBhbWFzdExNMjQgICAgICAgRgojSFBHTDA1MDUgICAgICAgYW1hc3RMTTQ4ICAgICAgIEYKI0hQR0wwNTA5ICAgICAgIGFtYXN0TE03MiAgICAgICBGCiNDb3VudCB0YWJsZSBpczoKIzIwMTQxMjExX0xtYWpvcjYwXzM0Nl8zNDdfMzQ5XzM1MV8zNTNfMzU1XzM2M18zNjRfMzY2XzM2OF8zNzBfMzcyXzM3M18zNzRfMzc2XzM3OF8zODBfMzgyXzM5Nl8zOTdfMzk5XzQwMV80MDNfNDA1XzQ1NS00NTZfNDU5XzQ2M180NjdfNDcxXzQ5My00OTRfNDk3XzUwMV81MDVfNTA5X0NEU29ubHkuY291bnQKI0luY2x1ZGVzIGhlYWRlcnMKCiM3LTE0LTE1CgojTC4gbWFqb3IKI0NyZWF0ZSBkaWFnbm9zdGljIHBsb3RzCiNIZWN0b3IgcmVjb21tZW5kZWQgdGhhdCBhbGwgZGlhZ25vc3RpY3MgYmUgZG9uZSB1c2luZyB0aGUgcmF3ZXN0IGRhdGEgcG9zc2libGUuIEZvciBjb3JyZWxhdGlvbiBhbmFseXNlcyBiZXR3ZWVuIHNhbXBsZXMsCiN1c2UgY291bnRzVGFibGUgZGF0YSB3aXRob3V0IGZpbHRlcmluZyBvdXQgbG93bHkgZXhwcmVzc2VkIGdlbmVzIGFuZCB3aXRob3V0IG5vcm1hbGl6YXRpb24uIFNpemUgZmFjdG9yIG5vcm1hbGl6YXRpb24KI3dpbGwgYmUgdXNlZCB0byBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgZ2VuZSBleHByZXNzaW9uIGxldmVscy4KCiNUaGlzIGFuYWx5c2lzIHVzZXMgY291bnQgdGFibGVzIHRoYXQgaGF2ZSBub3QgYmVlbiByZXN0cmljdGVkIHRvIG5vNDcxX0NEUyBvbmx5Lgo8L3ByZT4KCmBgYHtyIHJlcGVhdF9sb2d9CiMyMDE0MTIxMV9MbWFqb3I2MF8zNDZfMzQ3XzM0OV8zNTFfMzUzXzM1NV8zNjNfMzY0XzM2Nl8zNjhfMzcwXzM3Ml8zNzNfMzc0XzM3Nl8zNzhfMzgwXzM4Ml8zOTZfMzk3XzM5OV80MDFfNDAzXzQwNV80NTUtNDU2XzQ1OV80NjNfNDY3XzQ3MV80OTMtNDk0XzQ5N181MDFfNTA1XzUwOV9DRFNvbmx5LmNvdW50CmxpYnJhcnkoY2JjYlNFUSkKbGlicmFyeShncGxvdHMpCmxpYnJhcnkobWF0cml4U3RhdHMpCmxpYnJhcnkoc2lnZ2VuZXMpCmxpYnJhcnkoUmVwb3J0aW5nVG9vbHMpCmxpYnJhcnkoaHdyaXRlcikKbGlicmFyeShERVNlcTIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKI1JlYWQgaW4gY291bnRzIHRhYmxlCmNvdW50c1RhYmxlIDwtIHJlYWQudGFibGUoInByZXByb2Nlc3NpbmcvZGlsbG9ubC8yMDE0MTIxMV9MbWFqb3I2MF8zNDZfMzQ3XzM0OV8zNTFfMzUzXzM1NV8zNjNfMzY0XzM2Nl8zNjhfMzcwXzM3Ml8zNzNfMzc0XzM3Nl8zNzhfMzgwXzM4Ml8zOTZfMzk3XzM5OV80MDFfNDAzXzQwNV80NTUtNDU2XzQ1OV80NjNfNDY3XzQ3MV80OTMtNDk0XzQ5N181MDFfNTA1XzUwOV9DRFNvbmx5LmNvdW50Lnh6IiwgaGVhZGVyPVRSVUUpCiNSZW1vdmUgaWQgYXMgYW4gYWN0dWFsIGNvbHVtbiwgdXNlIGFzIHJvdyBuYW1lcyBpbnN0ZWFkCnJvd25hbWVzKGNvdW50c1RhYmxlKSA8LSBjb3VudHNUYWJsZSRpZApjb3VudHNUYWJsZSA8LSBjb3VudHNUYWJsZVssIC0xLCBkcm9wPUZBTFNFXQoKI1Jlc3RyaWN0IHRvIHNhbXBsZXMgb2YgaW50ZXJlc3QgKGV4Y2x1ZGUgcHJvY3ljbGljIHByb21hc3RpZ290ZSBzYW1wbGVzIGFuZCBIUEdMMDQ3MSkKY291bnRzVGFibGUgPC0gY291bnRzVGFibGVbLC1jKDE6NywgMTMsIDE5LCAyNSwgMzA6MzEpXQoKI0VzdGFibGlzaCBtZXRhZGF0YSBmb3Igc2FtcGxlcwpzYW1wbGVJRCA8LSBjb2xuYW1lcyhjb3VudHNUYWJsZSkKY29uZGl0aW9uIDwtIHJlcChjKCJtZXRhYyIsICJhbWFzdDQiLCAiYW1hc3QyNCIsICJhbWFzdDQ4IiwgImFtYXN0NzIiKSwgdGltZXM9NSkKYmF0Y2ggPC0gcmVwKGMoIkEiLCAiQiIsICJDIiwgIkUiLCAiRiIpLCBlYWNoPTUpCmNvbmRpdGlvbiA8LSBjb25kaXRpb25bLTIwXQpiYXRjaCA8LSBiYXRjaFstMjBdCgpjb25kaXRpb24gPC0gZmFjdG9yKGNvbmRpdGlvbiwgbGV2ZWxzPWMoIm1ldGFjIiwgImFtYXN0NCIsICJhbWFzdDI0IiwgImFtYXN0NDgiLCAiYW1hc3Q3MiIpKQpiYXRjaCA8LSBmYWN0b3IoYmF0Y2gsIGxldmVscz1jKCJBIiwgIkIiLCAiQyIsICJFIiwgIkYiKSkKZGVzaWduIDwtIGRhdGEuZnJhbWUoc2FtcGxlSUQ9c2FtcGxlSUQsIGNvbmRpdGlvbj1jb25kaXRpb24sIGJhdGNoPWJhdGNoKQprbml0cjo6a2FibGUoZGVzaWduKQpgYGAKCiMgUGxvdHMhCgpgYGB7ciBwbG90c30KY29sbmFtZXMoY291bnRzVGFibGUpIDwtIHBhc3RlKGNvbmRpdGlvbiwgYmF0Y2gsIDE6bGVuZ3RoKGNvbmRpdGlvbiksIHNlcD0iLiIpCiNWaWV3IGJhcnBsb3Qgb2YgcmF3IGNvdW50cyBieSBzYW1wbGUKYmFycGxvdChjb2xTdW1zKGNvdW50c1RhYmxlKSwgbGFzPTMsIHlsaW09YygwLDNlKzA3KSkKCmRmIDwtIGRhdGEuZnJhbWUoY29uZD0oY29uZGl0aW9uKSkKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhPWNvdW50c1RhYmxlLCBjb2xEYXRhID0gZGYsIGRlc2lnbiA9IH4gY29uZCkKZGRzIDwtIGVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzKQpuY3RzIDwtIGNvdW50cyhkZHMsIG5vcm1hbGl6ZWQ9VFJVRSkKeSA8LSBsb2cobmN0cyArIDEpCgojRGV0ZXJtaW5lIG1lZGlhbiBhbmQgcXVhbnRpbGVzIG9mIHRoZSBzaXplIGZhY3RvciBub3JtYWxpemVkLCBsb2cyIGNvdW50cwptZWRpYW4oeSkKI1sxXSA1Ljg4NjMwOQoKcXVhbnRpbGUoeSkKIyAgICAgICAwJSAgICAgICAyNSUgICAgICAgNTAlICAgICAgIDc1JSAgICAgIDEwMCUKIyAwLjAwMDAwMCAgNS40MzU5MTAgIDUuODg2MzA5ICA2LjM1NzMxMyAxMC44MzI4ODkKCiNEZXRlcm1pbmUgbnVtYmVyIG9mIGdlbmVzIHBlciBzYW1wbGUgd2l0aCBsZXNzIHRoYW4gbG9nMiBvZiAyIGNvdW50cyAobGVzcyB0aGFuIDQgY291bnRzIHBlciBtaWxsKQp5ZGYgPC0gYXMuZGF0YS5mcmFtZSh5KQpjb2xuYW1lcyh5ZGYpIDwtIHNhbXBsZUlECgpjb2wubmFtIDwtIHBhc3RlKGNvbmRpdGlvbiwgYmF0Y2gsIDE6bGVuZ3RoKGNvbmRpdGlvbiksIHNlcD0iLiIpCiNCb3hwbG90IG9mIHBlciBzYW1wbGUgbG9nIG9mIHNpemUtZmFjdG9yLW5vcm1hbGl6ZWQgY291bnRzICgrIDEpCnBhcihtYXI9YygxMC41LDQuNSwyLDEpKQpwYXIob21hPWMoMCwwLDAsMCkpCmJveHBsb3QoeSwgbmFtZXM9Y29sLm5hbSwgbGFzPTMpCgojSGVhdG1hcCBvZiBQZWFyc29uIGNvcnJlbGF0aW9uIGJldHdlZW4gc2FtcGxlcwojKGRlbGV0ZSBSb3d2LCBDb2x2LCBhbmQgZGVuZHJvZ3JhbSBwYXJhbWV0ZXJzIGlmIHdhbnQgc2FtcGxlcyB0byBzb3J0IGFuZCBzaG93IGRlbmRyb2dyYW0pCiNDb3JyZWxhdGlvbiBhbmFseXNpcyAoUGVhcnNvbiBpcyBkZWZhdWx0IGZvciBjb3IgdW5sZXNzIG90aGV3aXNlIHNwZWNpZmllZCkKI1VzaW5nIHJhdyBjb3VudHMKZGF0Q29yIDwtIGNvcihjb3VudHNUYWJsZSkKaGVhdG1hcC4yKGRhdENvciwgUm93dj1OQSwgQ29sdj1OQSwKICAgICAgICAgIG1hcmdpbnM9YygxMCwgMTApLAogICAgICAgICAgbGFiUm93PWNvbC5uYW0sCiAgICAgICAgICBsYWJDb2w9Y29sLm5hbSwKICAgICAgICAgIGRlbmRyb2dyYW09Im5vbmUiLAogICAgICAgICAgc2NhbGU9Im5vbmUiLAogICAgICAgICAgdHJhY2U9Im5vbmUiLAogICAgICAgICAgc3J0Q29sPTQ1KQoKCiNVc2luZyByYXcgY291bnRzCmNvck0gPC0gbWF0cml4U3RhdHM6OnJvd01lZGlhbnMoY29yKGNvdW50c1RhYmxlKSkKcXMgPC0gcXVhbnRpbGUoY29yTSxwPWMoMSwzKS80KQppcXIgPC0gZGlmZihxcykKb3V0TGltaXQgPC0gcXNbMV0gLSAxLjUgKiBpcXIKeWxpbSA8LSBjKHBtaW4obWluKGNvck0pLG91dExpbWl0KSxtYXgoY29yTSkpCmNvbCA8LSAgaWZlbHNlKGNvbmRpdGlvbj09ImFtYXN0NCIsICJjb3JuZmxvd2VyYmx1ZSIsCiAgICAgICAgaWZlbHNlKGNvbmRpdGlvbj09ImFtYXN0MjQiLCAiZ29sZCIsCiAgICAgICAgaWZlbHNlKGNvbmRpdGlvbj09ImFtYXN0NDgiLCAiZ3JlZW4zIiwKICAgICAgICBpZmVsc2UoY29uZGl0aW9uPT0iYW1hc3Q3MiIsICJjb3JhbCIsICJtZWRpdW1vcmNoaWQ0IikpKSkKCnBsb3QoY29yTSwgeGF4dD0ibiIsIHlsaW09eWxpbSwgeWxhYj0iTWVkaWFuIFBhaXJ3aXNlIENvcnJlbGF0aW9uIiwgeGxhYj0iIiwgbWFpbj0iIiwgY29sPWNvbCwgcGNoPTE2LCBjZXg9Mi4yKQpheGlzKHNpZGU9MSxhdD1zZXEoYWxvbmc9Y29yTSksbGFiZWxzPXBhc3RlKGNvbmRpdGlvbixiYXRjaCxzZXA9IjoiKSxsYXM9MikKYWJsaW5lKGg9b3V0TGltaXQsbHR5PTIpCmFibGluZSh2PTE6bGVuZ3RoKGNvbC5uYW0pLCBsdHk9MywgY29sPSJibGFjayIpCgojVXNlIGZpbHRlckNvdW50cyBtZXRob2QgdG8gZmlsdGVyIGZvciBsb3cgY291bnRzCiNEZWZpbmUgZmlsdGVyQ291bnRzIGZ1bmN0aW9uCmZpbHRlckNvdW50cyA9IGZ1bmN0aW9uIChjb3VudHMsIGxpYi5zaXplID0gTlVMTCwgdGhyZXNoID0gMSwgbWluU2FtcGxlcyA9IDIpIHsKICAgIGNwbXMgPC0gMl5sb2cyQ1BNKGNvdW50cywgbGliLnNpemUgPSBsaWIuc2l6ZSkkeQogICAga2VlcCA8LSByb3dTdW1zKGNwbXMgPiB0aHJlc2gpID49IG1pblNhbXBsZXMKICAgIGNvdW50cyA8LSBjb3VudHNba2VlcCwgXQogICAgY291bnRzCn0KeCA8LSB0YWJsZShjb25kaXRpb24pCmRpbShjb3VudHNUYWJsZSkKI1sxXSA4NDg2ICAgMjQKY291bnRzIDwtIGZpbHRlckNvdW50cyhjb3VudHNUYWJsZSwgdGhyZXNoPTEsIG1pblNhbXBsZXM9bWluKHgpKQpkaW0oY291bnRzKQojWzFdIDg0ODAgICAyNAoKI1F1YW50aWxlIG5vcm1hbGl6ZSBjb3VudHMKY291bnRzU3ViUSA8LSBxTm9ybShjb3VudHMpCiNFeHBsb3JlIGRhdGEgZm9yIGJhdGNoIGVmZmVjdHMKI1RyYW5zZm9ybSBkYXRhIHRvIGxvZzIgY291bnRzIHBlciBtaWxsaW9uCnggPC0gbG9nMkNQTShjb3VudHNTdWJRKQojQ29tcHV0ZSBwcmluY2lwYWwgY29tcG9uZW50cwpzIDwtIG1ha2VTVkQoeCR5KQoKI0NvbXB1dGUgdmFyaWFuY2Ugb2YgZWFjaCBQQyBhbmQgaG93IHRoZXkgY29ycmVsYXRlIHdpdGggYmF0Y2ggYW5kIGNvbmRpdGlvbgpwY1JlcyhzJHYsIHMkZCwgY29uZGl0aW9uLCBiYXRjaCkKIyAgIHByb3BWYXIgY3VtUHJvcFZhciBjb25kLlIyIGJhdGNoLlIyCiMxICAgIDM5LjY4ICAgICAgMzkuNjggICA4Mi40NiAgICAxMy40NgojMiAgICAxMi45NiAgICAgIDUyLjY0ICAgMTQuNTMgICAgNjEuMDEKIzMgICAgIDguMDIgICAgICA2MC42NiAgIDM1LjA4ICAgIDE4LjA4CiM0ICAgICA3LjEzICAgICAgNjcuNzkgICA1NC42NyAgICAxMy4yOQojNSAgICAgNS4zNSAgICAgIDczLjE0ICAgIDcuNjEgICAgNjMuNDgKIzYgICAgIDQuMjMgICAgICA3Ny4zNyAgIDE0LjIxICAgIDM3LjM1CiM3ICAgICAzLjQ4ICAgICAgODAuODUgICAxNi4xMCAgICAzNS45NgojOCAgICAgMi45NCAgICAgIDgzLjc5ICAgMjMuMjIgICAgMjIuMDgKIzkgICAgIDIuMTUgICAgICA4NS45NCAgIDEzLjI2ICAgIDQ2Ljc0CiMxMCAgICAyLjExICAgICAgODguMDUgICAxNi41OCAgICAxOC42MAojMTEgICAgMS43NiAgICAgIDg5LjgxICAgIDguMDMgICAgMjQuNzEKIzEyICAgIDEuNTggICAgICA5MS4zOSAgICA1LjgxICAgICAzLjM5CiMxMyAgICAxLjM2ICAgICAgOTIuNzUgICAzNC44MyAgICAgNC4yOAojMTQgICAgMS4yOCAgICAgIDk0LjAzICAgIDIuMTYgICAgIDcuMTIKIzE1ICAgIDEuMDggICAgICA5NS4xMSAgICA3LjIzICAgICA2LjAyCiMxNiAgICAwLjg3ICAgICAgOTUuOTggICAgNi4wOCAgICAgMy43NAojMTcgICAgMC43NyAgICAgIDk2Ljc1ICAgIDAuODQgICAgIDguMTAKIzE4ICAgIDAuNzIgICAgICA5Ny40NyAgICAwLjQ5ICAgICAwLjgyCiMxOSAgICAwLjYwICAgICAgOTguMDcgICAgNC41OSAgICAgNC4yNAojMjAgICAgMC41NyAgICAgIDk4LjY0ICAgIDIuNzAgICAgIDIuNDYKIzIxICAgIDAuNDggICAgICA5OS4xMiAgIDM2LjcwICAgICAxLjQ0CiMyMiAgICAwLjQ2ICAgICAgOTkuNTggICAgOS41MiAgICAgMC45NAojMjMgICAgMC40MSAgICAgIDk5Ljk5ICAgIDMuMjkgICAgIDIuNzAKCiNQbG90IFBDMSB2cy4gUEMyLCB3aXRoIGJsYWNrIG91dGxpbmVzIGFuZCBjb2xvciBmaWxscwojU2F2ZSBhcyBlcHMKY29uZG51bSA8LSBhcy5udW1lcmljKGNvbmRpdGlvbikKcGxvdFBDKHMkdiwKICAgICAgIHMkZCwKICAgICAgIGNvbD0iYmxhY2siLAogICAgICAgcGNoPWlmZWxzZShiYXRjaD09IkEiLCAyNSwgaWZlbHNlKGJhdGNoPT0iQiIsIDIxLCBpZmVsc2UoYmF0Y2g9PSJDIiwgMjIsIGlmZWxzZShiYXRjaD09IkUiLCAyNCwgMjMpKSkpLAogICAgICAgYmc9aWZlbHNlKGNvbmRudW09PTEsICJtZWRpdW1vcmNoaWQ0IiwgaWZlbHNlKGNvbmRudW09PTIsICJjb3JuZmxvd2VyYmx1ZSIsIGlmZWxzZShjb25kbnVtPT0zLCAiZ29sZCIsIGlmZWxzZShjb25kbnVtPT00LCAiZ3JlZW4zIiwgImNvcmFsIikpKSksIGNleD0yLjYKICAgICAgICkKbGVnZW5kKHg9LTAuMTEsIHk9LTAuNDAsIGxlZ2VuZD1jKCJtZXRhYyIsICJhbWFzdDQiLCAiYW1hc3QyNCIsICJhbWFzdDQ4IiwgImFtYXN0NzIiKSwgcGNoPTIyLCBjb2w9MCwKcHQuYmc9YygibWVkaXVtb3JjaGlkNCIsICJjb3JuZmxvd2VyYmx1ZSIsICJnb2xkIiwgImdyZWVuMyIsICJjb3JhbCIpLCBwdC5jZXg9Mi42LCBidHk9Im4iKQp0ZXh0KHMkdlssMV0sIHMkdlssMl0sIGNvbG5hbWVzKGNvdW50c1RhYmxlKSwgY2V4PS43LCBwb3M9NCkKCiNWaWV3IGFzIGEgRXVjbGlkZWFuIGRpc3RhbmNlIGhlYXRtYXAKZGlzdHMgPC0gZGlzdCh0KGNvdW50cykpCm1hdCA8LSBhcy5tYXRyaXgoZGlzdHMpCnJvd25hbWVzKG1hdCkgPC0gY29sbmFtZXMobWF0KSA8LSB3aXRoKGRlc2lnbiwgcGFzdGUoY29sbmFtZXMoY291bnRzVGFibGUpKSkKaG1jb2wgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHbkJ1IikpKDEwMCkKdmVjLmJhdGNoIDwtIHJhaW5ib3cobmxldmVscyhiYXRjaCksIHN0YXJ0PTAsIGVuZD0uOCkKYmF0Y2guY29sb3IgPC0gcmVwKDAsIGxlbmd0aChiYXRjaCkpCmZvciAoaSBpbiAxOmxlbmd0aChiYXRjaCkpIHsKICAgIGJhdGNoLmNvbG9yW2ldIDwtIHZlYy5iYXRjaFtiYXRjaFtpXT09bGV2ZWxzKGJhdGNoKV0KfQp2ZWMuY29uZGl0aW9uIDwtIGMoIm1lZGl1bW9yY2hpZDQiLCAiY29ybmZsb3dlcmJsdWUiLCAiZ29sZCIsICJncmVlbjMiLCAiY29yYWwiKQpjb25kaXRpb24uY29sb3IgPC0gcmVwKDAsIGxlbmd0aChjb25kaXRpb24pKQpmb3IgKGkgaW4gMTpsZW5ndGgoY29uZGl0aW9uKSkgewogICAgY29uZGl0aW9uLmNvbG9yW2ldIDwtIHZlYy5jb25kaXRpb25bY29uZGl0aW9uW2ldPT1sZXZlbHMoY29uZGl0aW9uKV0KfQpoZWF0bWFwIDwtIGhlYXRtYXAuMihtYXQsIHRyYWNlPSJub25lIiwgY29sID0gcmV2KGhtY29sKSwgbWFyZ2luPWMoMTEsMTEpLCBDb2xTaWRlQ29sb3JzPWNvbmRpdGlvbi5jb2xvciwKUm93U2lkZUNvbG9ycz1iYXRjaC5jb2xvciwga2V5PSJGQUxTRSIsIHNydENvbD00NSkKCiNJIHdvdWxkIGxpa2UgdG8gY3JlYXRlIGEgUENBIHBsb3QgYW5kIGhlYXRtYXAgdG8gcmVmbGVjdCB0aGUgdXNlIG9mIGJhdGNoIGluIHRoZSBsaW1tYSBtb2RlbAojU3BlY2lmeSBtb2RlbAptb2QgPC0gbW9kZWwubWF0cml4KH5iYXRjaCkKCiNVc2Ugdm9vbSB0byBkZXRlcm1pbmUgd2VpZ2h0cyBmb3IgZml0dGluZyB0aGUgbWVhbi12YXJpYW5jZSB0cmVuZCBmb3IgZWFjaCBnZW5lCnYgPC0gdm9vbShjb3VudHNTdWJRLCBtb2QpCiNGaXQgdGhlIGxpbmVhciBtb2RlbCBmb3IgZWFjaCBnZW5lCmZpdCA8LSBsbUZpdCh2KQoKI0dldCB0aGUgcmVzaWR1YWwgKGkuZS4gZXZlcnl0aGluZyBleGNlcHQgZm9yIHRoZSBiYXRjaCBlZmZlY3QpCm5ld0RhdGEgPC0gcmVzaWR1YWxzKGZpdCwgdikKI0V4cGxvcmUgZGF0YSBmb3IgYmF0Y2ggZWZmZWN0cwojQ29tcHV0ZSBwcmluY2lwYWwgY29tcG9uZW50cwpzIDwtIG1ha2VTVkQobmV3RGF0YSkKCiNDb21wdXRlIHZhcmlhbmNlIG9mIGVhY2ggUEMgYW5kIGhvdyB0aGV5IGNvcnJlbGF0ZSB3aXRoIGJhdGNoIGFuZCBjb25kaXRpb24KcGNSZXMocyR2LCBzJGQsIGNvbmRpdGlvbiwgYmF0Y2gpCiMgICBwcm9wVmFyIGN1bVByb3BWYXIgY29uZC5SMiBiYXRjaC5SMgojMSAgICA0Ny4wNCAgICAgIDQ3LjA0ICAgOTMuMDIgICAgICAgIDAKIzIgICAgMTAuNzcgICAgICA1Ny44MSAgIDU2LjE0ICAgICAgICAwCiMzICAgICA4Ljc0ICAgICAgNjYuNTUgICA1NC40MiAgICAgICAgMAojNCAgICAgNy4xNiAgICAgIDczLjcxICAgIDcuMzAgICAgICAgIDAKIzUgICAgIDQuNDUgICAgICA3OC4xNiAgIDQ5Ljk2ICAgICAgICAwCiM2ICAgICAzLjczICAgICAgODEuODkgICAgNC42MSAgICAgICAgMAojNyAgICAgMy4xMSAgICAgIDg1LjAwICAgIDguNjYgICAgICAgIDAKIzggICAgIDIuMjIgICAgICA4Ny4yMiAgICAxLjA4ICAgICAgICAwCiM5ICAgICAyLjEwICAgICAgODkuMzIgICAxMy4wMyAgICAgICAgMAojMTAgICAgMS44OSAgICAgIDkxLjIxICAgMTQuMzEgICAgICAgIDAKIzExICAgIDEuNjMgICAgICA5Mi44NCAgIDI3LjExICAgICAgICAwCiMxMiAgICAxLjQyICAgICAgOTQuMjYgICAgMS4yNyAgICAgICAgMAojMTMgICAgMS4xMyAgICAgIDk1LjM5ICAgIDcuMjYgICAgICAgIDAKIzE0ICAgIDAuOTcgICAgICA5Ni4zNiAgICAwLjQyICAgICAgICAwCiMxNSAgICAwLjkyICAgICAgOTcuMjggICAgMi43MyAgICAgICAgMAojMTYgICAgMC44MCAgICAgIDk4LjA4ICAgIDQuNzkgICAgICAgIDAKIzE3ICAgIDAuNjggICAgICA5OC43NiAgIDIyLjUxICAgICAgICAwCiMxOCAgICAwLjY0ICAgICAgOTkuNDAgICAxOS4xOSAgICAgICAgMAojMTkgICAgMC41OCAgICAgIDk5Ljk4ICAgIDguMTkgICAgICAgIDAKIzIwICAgIDAuMDAgICAgICA5OS45OCAgICAwLjM0ICAgICAgMTAwCiMyMSAgICAwLjAwICAgICAgOTkuOTggICAgMS4yNCAgICAgIDEwMAojMjIgICAgMC4wMCAgICAgIDk5Ljk4ICAgIDIuMTIgICAgICAxMDAKCiNQbG90IFBDMSB2cy4gUEMyLCB3aXRoIGJsYWNrIG91dGxpbmVzIGFuZCBjb2xvciBmaWxscwojU2F2ZSBhcyBlcHMKY29uZG51bSA8LSBhcy5udW1lcmljKGNvbmRpdGlvbikKcGxvdFBDKHMkdiwKICAgICAgIHMkZCwKICAgICAgIGNvbD0iYmxhY2siLAogICAgICAgcGNoPWlmZWxzZShiYXRjaD09IkEiLCAyNSwgaWZlbHNlKGJhdGNoPT0iQiIsIDIxLCBpZmVsc2UoYmF0Y2g9PSJDIiwgMjIsIGlmZWxzZShiYXRjaD09IkUiLCAyNCwgMjMpKSkpLAogICAgICAgYmc9aWZlbHNlKGNvbmRudW09PTEsICJtZWRpdW1vcmNoaWQ0IiwgaWZlbHNlKGNvbmRudW09PTIsICJjb3JuZmxvd2VyYmx1ZSIsIGlmZWxzZShjb25kbnVtPT0zLCAiZ29sZCIsIGlmZWxzZShjb25kbnVtPT00LCAiZ3JlZW4zIiwgImNvcmFsIikpKSksIGNleD0yLjYKICAgICAgICkKbGVnZW5kKHg9LTAuNDgsIHk9LTAuMjQsIGxlZ2VuZD1jKCJtZXRhYyIsICJhbWFzdDQiLCAiYW1hc3QyNCIsICJhbWFzdDQ4IiwgImFtYXN0NzIiKSwgcGNoPTIyLCBjb2w9MCwKcHQuYmc9YygibWVkaXVtb3JjaGlkNCIsICJjb3JuZmxvd2VyYmx1ZSIsICJnb2xkIiwgImdyZWVuMyIsICJjb3JhbCIpLCBwdC5jZXg9Mi42LCBidHk9Im4iKQp0ZXh0KHMkdlssMV0sIHMkdlssMl0sIGNvbG5hbWVzKGNvdW50c1RhYmxlKSwgY2V4PS43LCBwb3M9NCkKCiNWaWV3IGFzIGEgRXVjbGlkZWFuIGRpc3RhbmNlIGhlYXRtYXAKZGlzdHMgPC0gZGlzdCh0KG5ld0RhdGEpKQptYXQgPC0gYXMubWF0cml4KGRpc3RzKQpyb3duYW1lcyhtYXQpIDwtIGNvbG5hbWVzKG1hdCkgPC0gd2l0aChkZXNpZ24sIHBhc3RlKGNvbG5hbWVzKGNvdW50c1RhYmxlKSkpCmhtY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiR25CdSIpKSgxMDApCgp2ZWMuYmF0Y2ggPC0gcmFpbmJvdyhubGV2ZWxzKGJhdGNoKSwgc3RhcnQ9MCwgZW5kPS44KQpiYXRjaC5jb2xvciA8LSByZXAoMCwgbGVuZ3RoKGJhdGNoKSkKZm9yIChpIGluIDE6bGVuZ3RoKGJhdGNoKSkgewogICAgYmF0Y2guY29sb3JbaV0gPC0gdmVjLmJhdGNoW2JhdGNoW2ldPT1sZXZlbHMoYmF0Y2gpXQp9CnZlYy5jb25kaXRpb24gPC0gYygibWVkaXVtb3JjaGlkNCIsICJjb3JuZmxvd2VyYmx1ZSIsICJnb2xkIiwgImdyZWVuMyIsICJjb3JhbCIpCmNvbmRpdGlvbi5jb2xvciA8LSByZXAoMCwgbGVuZ3RoKGNvbmRpdGlvbikpCmZvciAoaSBpbiAxOmxlbmd0aChjb25kaXRpb24pKSB7CiAgICBjb25kaXRpb24uY29sb3JbaV0gPC0gdmVjLmNvbmRpdGlvbltjb25kaXRpb25baV09PWxldmVscyhjb25kaXRpb24pXQp9CgpoZWF0bWFwIDwtIGhlYXRtYXAuMihtYXQsIHRyYWNlPSJub25lIiwgY29sID0gcmV2KGhtY29sKSwgbWFyZ2luPWMoMTEsMTEpLCBDb2xTaWRlQ29sb3JzPWNvbmRpdGlvbi5jb2xvciwKICAgICAgICAgICAgICAgICAgICAgUm93U2lkZUNvbG9ycz1iYXRjaC5jb2xvciwga2V5PSJGQUxTRSIsIHNydENvbD00NSkKCmNvdW50c1N1YlEgPC0gcU5vcm0oY291bnRzKQojU3BlY2lmeSBtb2RlbAptb2QgPSBtb2RlbC5tYXRyaXgofjArY29uZGl0aW9uK2JhdGNoKQojVmlldyBtZWFuLXZhcmlhbmNlIHRyZW5kCnYgPC0gdm9vbShjb3VudHNTdWJRLCBtb2QsIHBsb3Q9VFJVRSkKI0ZpdCBhIGxpbmVhciBtb2RlbCBmb3IgZWFjaCBnZW5lIHVzaW5nIHRoZSBzcGVjaWZpZWQgZGVzaWduIGNvbnRhaW5lZCBpbiB2CmZpdCA8LSBsbUZpdCh2KQojI21ldGFjIHYgYW1hc3Q0IyMKI2VCYXllcyBmaW5kcyBhbiBGLXN0YXRpc3RpYyBmcm9tIHRoZSBzZXQgb2YgdC1zdGF0aXN0aWNzIGZvciB0aGF0IGdlbmUKbWV0YWMuYW1hc3Q0LmNvbnRyLm1hdCA8LSBtYWtlQ29udHJhc3RzKG1ldGFjX3ZfYW1hc3Q0PWNvbmRpdGlvbmFtYXN0NC1jb25kaXRpb25tZXRhYywgbGV2ZWxzPXYkZGVzaWduKQptZXRhYy5hbWFzdDQuZml0IDwtIGNvbnRyYXN0cy5maXQoZml0LCBtZXRhYy5hbWFzdDQuY29udHIubWF0KQptZXRhYy5hbWFzdDQuZWIgPC0gZUJheWVzKG1ldGFjLmFtYXN0NC5maXQpCm1ldGFjLmFtYXN0NC50b3BUYWIgPC0gdG9wVGFibGUobWV0YWMuYW1hc3Q0LmViLCBjb2VmPSJtZXRhY192X2FtYXN0NCIsIG51bWJlcj1ucm93KHYkRSkpCm1ldGFjLmFtYXN0NC50b3BUYWJbWyJmb2xkX2NoYW5nZSJdXSA8LSAyIF4gbWV0YWMuYW1hc3Q0LnRvcFRhYltbImxvZ0ZDIl1dCndyaXRlLmNzdihmaWxlPSJjc3YvbG1ham9yX21ldGFjX3ZzX2FtYXN0NC5jc3YiLCB4PW1ldGFjLmFtYXN0NC50b3BUYWIpCgojVmlldyB0aGUgbGlzdCBvZiBERSBnZW5lcwpoZWFkKG1ldGFjLmFtYXN0NC50b3BUYWIsIG49M0wpCiMgICAgICAgICAgICAgICAgICBsb2dGQyAgQXZlRXhwciAgICAgICAgdCAgICAgIFAuVmFsdWUgICAgYWRqLlAuVmFsICAgICAgICBCCiNMbWpGLjE5LjE1MzAtMSAxLjQ4MDIzNiA4LjQ1MzI1MyAxNC41MDE1OCA4LjM1OTM1M2UtMTQgMy41OTg5NDllLTEwIDIxLjQzNzAxCiNMbWpGLjI2LjA2NDAtMSAxLjgyMjQwMyA3LjI2NjI2NSAxNC40OTE4NSA4LjQ4ODA4NmUtMTQgMy41OTg5NDllLTEwIDIxLjMwOTAxCiNMbWpGLjM2LjIwMzAtMSAxLjM4NzE2OCA4Ljc4NTUxNSAxMS42Nzc4MyAxLjAyNjQyN2UtMTEgMS44MjIzMzFlLTA4IDE2Ljg1ODQwCgoKI0xpbWl0IGxpc3QgdG8gZ2VuZXMgd2l0aCBhbiBhZGp1c3RlZCBwIHZhbHVlIDwgMC4wNQptZXRhYy5hbWFzdDQuc2lnR2VuZXMgPC0gbWV0YWMuYW1hc3Q0LnRvcFRhYlttZXRhYy5hbWFzdDQudG9wVGFiJGFkai5QLlZhbCA8MC4wNSwgXQpsZW5ndGgobWV0YWMuYW1hc3Q0LnNpZ0dlbmVzJGxvZ0ZDKQojMzIyNAoKI0ZpbHRlciBvdXQgcm93cyB3aXRoIGxlc3MgdGhhbiAyLWZvbGQgY2hhbmdlIChsb2cyIGZvbGQgY2hhbmdlIG9mID4gMSkKbWV0YWMuYW1hc3Q0LnNpZ0dlbmVzRm9sZDEgPC0gc3Vic2V0KG1ldGFjLmFtYXN0NC5zaWdHZW5lcywgYWJzKGxvZ0ZDKSA+IDEpCmxlbmd0aChtZXRhYy5hbWFzdDQuc2lnR2VuZXNGb2xkMSRsb2dGQykKIzMwNAoKI0ZpbHRlciBvdXQgcm93cyB3aXRoIGxlc3MgdGhhbiA0LWZvbGQgY2hhbmdlIChsb2cyIGZvbGQgY2hhbmdlIG9mID4gMikKbWV0YWMuYW1hc3Q0LnNpZ0dlbmVzRm9sZDIgPC0gc3Vic2V0KG1ldGFjLmFtYXN0NC5zaWdHZW5lcywgYWJzKGxvZ0ZDKSA+IDIpCmxlbmd0aChtZXRhYy5hbWFzdDQuc2lnR2VuZXNGb2xkMiRsb2dGQykKIzEyCgptZXRhYy5hbWFzdDQuc2lnR2VuZXMgPC0gbWV0YWMuYW1hc3Q0LnNpZ0dlbmVzW29yZGVyKC1tZXRhYy5hbWFzdDQuc2lnR2VuZXMkbG9nRkMpLCBdCgojTWFrZSBhbiBNQSBwbG90CnNlbCA9IG1ldGFjLmFtYXN0NC50b3BUYWIkYWRqLlAuVmFsIDwgMC4wNQp0b3AgPSBtZXRhYy5hbWFzdDQudG9wVGFiCnN1YiA9IHBhc3RlKCJOby4gb2Ygc2lnLiBnZW5lczogIiwgc3VtKHNlbCksIi8iLGxlbmd0aChzZWwpKQpjcG0gPSB2JEUKCnBsb3Qocm93TWVhbnMoY3BtW3Jvd25hbWVzKHRvcCksXSksIHRvcCRsb2dGQywgcGNoPTE2LCBjZXg9MC41LGNvbD0iZGFya2dyZXkiLAogICAgICAgIG1haW49Im1ldGFjX2FtYXN0NCBtb2RlbCBiYXRjaCBhZGp1c3RlZCIsCiAgICAgICAgeWxhYj0ibG9nIEZDIiwgeGxhYj0iQXZlcmFnZSBFeHByZXNzaW9uIiwKICAgICAgICB5bGltPWMoLTMsMyksIHN1Yj1zdWIpCnBvaW50cyhyb3dNZWFucyhjcG1bcm93bmFtZXModG9wKSxdKVtzZWxdLCB0b3AkbG9nRkNbc2VsXSwgY29sPSJyZWQiLCBjZXg9MC41KQphYmxpbmUoaD1jKC0xLDAsMSksIGNvbD0icmVkIikKCiMjYW1hc3Q0IHYgYW1hc3QyNCMjCiNlQmF5ZXMgZmluZHMgYW4gRi1zdGF0aXN0aWMgZnJvbSB0aGUgc2V0IG9mIHQtc3RhdGlzdGljcyBmb3IgdGhhdCBnZW5lCmFtYXN0NC5hbWFzdDI0LmNvbnRyLm1hdCA8LSBtYWtlQ29udHJhc3RzKGFtYXN0NF92X2FtYXN0MjQ9Y29uZGl0aW9uYW1hc3QyNC1jb25kaXRpb25hbWFzdDQsIGxldmVscz12JGRlc2lnbikKYW1hc3Q0LmFtYXN0MjQuZml0IDwtIGNvbnRyYXN0cy5maXQoZml0LCBhbWFzdDQuYW1hc3QyNC5jb250ci5tYXQpCmFtYXN0NC5hbWFzdDI0LmViIDwtIGVCYXllcyhhbWFzdDQuYW1hc3QyNC5maXQpCmFtYXN0NC5hbWFzdDI0LnRvcFRhYiA8LSB0b3BUYWJsZShhbWFzdDQuYW1hc3QyNC5lYiwgY29lZj0iYW1hc3Q0X3ZfYW1hc3QyNCIsIG51bWJlcj1ucm93KHYkRSkpCiNWaWV3IHRoZSBsaXN0IG9mIERFIGdlbmVzCmhlYWQoYW1hc3Q0LmFtYXN0MjQudG9wVGFiLCBuPTNMKQojICAgICAgICAgICAgICAgICAgIGxvZ0ZDICBBdmVFeHByICAgICAgICB0ICAgICAgUC5WYWx1ZSAgICBhZGouUC5WYWwgICAgICAgICBCCiNMbWpGLjI4LjE1NzAtMSAxLjU3ODU1OTMgNi4xMzU4NTAgOC43NDQ0ODUgMy44Njk5MDZlLTA5IDMuMjgxNjgwZS0wNSAxMC43NjkyMDEKI0xtakYuMDUuMDAxMC0xIDAuOTQ1MTU1MSA4LjI3MzI0NiA4LjEzMDM2NiAxLjUzOTkwOGUtMDggNS42MzU4MzFlLTA1ICA5LjYzODE1MgojTG1qRi4zNi4yNzYwLTEgMS4zNDYyNjM0IDUuODQ1OTEwIDguMDE3OTA5IDEuOTkzODA4ZS0wOCA1LjYzNTgzMWUtMDUgIDkuMjI5MjUwCgojTGltaXQgbGlzdCB0byBnZW5lcyB3aXRoIGFuIGFkanVzdGVkIHAgdmFsdWUgPCAwLjA1CmFtYXN0NC5hbWFzdDI0LnNpZ0dlbmVzIDwtIGFtYXN0NC5hbWFzdDI0LnRvcFRhYlthbWFzdDQuYW1hc3QyNC50b3BUYWIkYWRqLlAuVmFsIDwwLjA1LCBdCmxlbmd0aChhbWFzdDQuYW1hc3QyNC5zaWdHZW5lcyRsb2dGQykKIzM1NgoKI0ZpbHRlciBvdXQgcm93cyB3aXRoIGxlc3MgdGhhbiAyLWZvbGQgY2hhbmdlIChsb2cyIGZvbGQgY2hhbmdlIG9mID4gMSkKYW1hc3Q0LmFtYXN0MjQuc2lnR2VuZXNGb2xkMSA8LSBzdWJzZXQoYW1hc3Q0LmFtYXN0MjQuc2lnR2VuZXMsIGFicyhsb2dGQykgPiAxKQpsZW5ndGgoYW1hc3Q0LmFtYXN0MjQuc2lnR2VuZXNGb2xkMSRsb2dGQykKIzM4CgojRmlsdGVyIG91dCByb3dzIHdpdGggbGVzcyB0aGFuIDQtZm9sZCBjaGFuZ2UgKGxvZzIgZm9sZCBjaGFuZ2Ugb2YgPiAyKQphbWFzdDQuYW1hc3QyNC5zaWdHZW5lc0ZvbGQyIDwtIHN1YnNldChhbWFzdDQuYW1hc3QyNC5zaWdHZW5lcywgYWJzKGxvZ0ZDKSA+IDIpCmxlbmd0aChhbWFzdDQuYW1hc3QyNC5zaWdHZW5lc0ZvbGQyJGxvZ0ZDKQojMQoKYW1hc3Q0LmFtYXN0MjQuc2lnR2VuZXMgPC0gYW1hc3Q0LmFtYXN0MjQuc2lnR2VuZXNbb3JkZXIoLWFtYXN0NC5hbWFzdDI0LnNpZ0dlbmVzJGxvZ0ZDKSwgXQojTWFrZSBhbiBNQSBwbG90CnNlbCA9IGFtYXN0NC5hbWFzdDI0LnRvcFRhYiRhZGouUC5WYWwgPCAwLjA1CnRvcCA9IGFtYXN0NC5hbWFzdDI0LnRvcFRhYgpzdWIgPSBwYXN0ZSgiTm8uIG9mIHNpZy4gZ2VuZXM6ICIsIHN1bShzZWwpLCIvIixsZW5ndGgoc2VsKSkKY3BtID0gdiRFCgoKcGxvdChyb3dNZWFucyhjcG1bcm93bmFtZXModG9wKSxdKSwgdG9wJGxvZ0ZDLCBwY2g9MTYsIGNleD0wLjUsY29sPSJkYXJrZ3JleSIsCiAgICAgICAgbWFpbj0iYW1hc3Q0X2FtYXN0MjQgbW9kZWwgYmF0Y2ggYWRqdXN0ZWQiLAogICAgICAgIHlsYWI9ImxvZyBGQyIsIHhsYWI9IkF2ZXJhZ2UgRXhwcmVzc2lvbiIsCiAgICAgICAgeWxpbT1jKC0zLDMpLCBzdWI9c3ViKQpwb2ludHMocm93TWVhbnMoY3BtW3Jvd25hbWVzKHRvcCksXSlbc2VsXSwgdG9wJGxvZ0ZDW3NlbF0sIGNvbD0icmVkIiwgY2V4PTAuNSkKYWJsaW5lKGg9YygtMSwwLDEpLCBjb2w9InJlZCIpCmRldi5vZmYoKQoKIyNhbWFzdDI0IHYgYW1hc3Q0OCMjCiNlQmF5ZXMgZmluZHMgYW4gRi1zdGF0aXN0aWMgZnJvbSB0aGUgc2V0IG9mIHQtc3RhdGlzdGljcyBmb3IgdGhhdCBnZW5lCmFtYXN0MjQuYW1hc3Q0OC5jb250ci5tYXQgPC0gbWFrZUNvbnRyYXN0cyhhbWFzdDI0X3ZfYW1hc3Q0OD1jb25kaXRpb25hbWFzdDQ4LWNvbmRpdGlvbmFtYXN0MjQsIGxldmVscz12JGRlc2lnbikKYW1hc3QyNC5hbWFzdDQ4LmZpdCA8LSBjb250cmFzdHMuZml0KGZpdCwgYW1hc3QyNC5hbWFzdDQ4LmNvbnRyLm1hdCkKYW1hc3QyNC5hbWFzdDQ4LmViIDwtIGVCYXllcyhhbWFzdDI0LmFtYXN0NDguZml0KQphbWFzdDI0LmFtYXN0NDgudG9wVGFiIDwtIHRvcFRhYmxlKGFtYXN0MjQuYW1hc3Q0OC5lYiwgY29lZj0iYW1hc3QyNF92X2FtYXN0NDgiLCBudW1iZXI9bnJvdyh2JEUpKQoKI1ZpZXcgdGhlIGxpc3Qgb2YgREUgZ2VuZXMKaGVhZChhbWFzdDI0LmFtYXN0NDgudG9wVGFiLCBuPTNMKQojICAgICAgICAgICAgICAgICAgICBsb2dGQyAgQXZlRXhwciAgICAgICAgIHQgICAgICBQLlZhbHVlICBhZGouUC5WYWwgICAgICAgIEIKI0xtakYuMzYuMjc2MC0xIC0wLjk2MTQ3MjAgNS44NDU5MTAgLTUuODMxMjg2IDQuMTQyOTY4ZS0wNiAwLjAyOTA3MDMyIDMuMTc1MDg4CiNMbWpGLjA0LjAzMTAtMSAtMS4wNDk2NDE0IDYuOTYzMzgwIC01LjU1MTg4NyA4LjQ5NzU5M2UtMDYgMC4wMjkwNzAzMiAyLjkxMDU2MAojTG1qRi4yOS4yNzEwLTEgIDAuNjAxNjk0NCA2LjI3NzA3NiAgNS40NzgwMzUgMS4wMjg0MzFlLTA1IDAuMDI5MDcwMzIgMi42NjE2OTQKCiNMaW1pdCBsaXN0IHRvIGdlbmVzIHdpdGggYW4gYWRqdXN0ZWQgcCB2YWx1ZSA8IDAuMDUKYW1hc3QyNC5hbWFzdDQ4LnNpZ0dlbmVzIDwtIGFtYXN0MjQuYW1hc3Q0OC50b3BUYWJbYW1hc3QyNC5hbWFzdDQ4LnRvcFRhYiRhZGouUC5WYWwgPDAuMDUsIF0KbGVuZ3RoKGFtYXN0MjQuYW1hc3Q0OC5zaWdHZW5lcyRsb2dGQykKIzMKCiNGaWx0ZXIgb3V0IHJvd3Mgd2l0aCBsZXNzIHRoYW4gMi1mb2xkIGNoYW5nZSAobG9nMiBmb2xkIGNoYW5nZSBvZiA+IDEpCmFtYXN0MjQuYW1hc3Q0OC5zaWdHZW5lc0ZvbGQxIDwtIHN1YnNldChhbWFzdDI0LmFtYXN0NDguc2lnR2VuZXMsIGFicyhsb2dGQykgPiAxKQpsZW5ndGgoYW1hc3QyNC5hbWFzdDQ4LnNpZ0dlbmVzRm9sZDEkbG9nRkMpCiMxCgojRmlsdGVyIG91dCByb3dzIHdpdGggbGVzcyB0aGFuIDQtZm9sZCBjaGFuZ2UgKGxvZzIgZm9sZCBjaGFuZ2Ugb2YgPiAyKQphbWFzdDI0LmFtYXN0NDguc2lnR2VuZXNGb2xkMiA8LSBzdWJzZXQoYW1hc3QyNC5hbWFzdDQ4LnNpZ0dlbmVzLCBhYnMobG9nRkMpID4gMikKbGVuZ3RoKGFtYXN0MjQuYW1hc3Q0OC5zaWdHZW5lc0ZvbGQyJGxvZ0ZDKQoKYW1hc3QyNC5hbWFzdDQ4LnNpZ0dlbmVzIDwtIGFtYXN0MjQuYW1hc3Q0OC5zaWdHZW5lc1tvcmRlcigtYW1hc3QyNC5hbWFzdDQ4LnNpZ0dlbmVzJGxvZ0ZDKSwgXQoKI01ha2UgYW4gTUEgcGxvdApzZWwgPSBhbWFzdDI0LmFtYXN0NDgudG9wVGFiJGFkai5QLlZhbCA8IDAuMDUKdG9wID0gYW1hc3QyNC5hbWFzdDQ4LnRvcFRhYgpzdWIgPSBwYXN0ZSgiTm8uIG9mIHNpZy4gZ2VuZXM6ICIsIHN1bShzZWwpLCIvIixsZW5ndGgoc2VsKSkKY3BtID0gdiRFCnBsb3Qocm93TWVhbnMoY3BtW3Jvd25hbWVzKHRvcCksXSksIHRvcCRsb2dGQywgcGNoPTE2LCBjZXg9MC41LGNvbD0iZGFya2dyZXkiLAogICAgICAgIG1haW49ImFtYXN0MjRfYW1hc3Q0OCBtb2RlbCBiYXRjaCBhZGp1c3RlZCIsCiAgICAgICAgeWxhYj0ibG9nIEZDIiwgeGxhYj0iQXZlcmFnZSBFeHByZXNzaW9uIiwKICAgICAgICB5bGltPWMoLTMsMyksIHN1Yj1zdWIpCnBvaW50cyhyb3dNZWFucyhjcG1bcm93bmFtZXModG9wKSxdKVtzZWxdLCB0b3AkbG9nRkNbc2VsXSwgY29sPSJyZWQiLCBjZXg9MC41KQphYmxpbmUoaD1jKC0xLDAsMSksIGNvbD0icmVkIikKCiMjYW1hc3Q0OCB2IGFtYXN0NzIjIwojZUJheWVzIGZpbmRzIGFuIEYtc3RhdGlzdGljIGZyb20gdGhlIHNldCBvZiB0LXN0YXRpc3RpY3MgZm9yIHRoYXQgZ2VuZQphbWFzdDQ4LmFtYXN0NzIuY29udHIubWF0IDwtIG1ha2VDb250cmFzdHMoYW1hc3Q0OF92X2FtYXN0NzI9Y29uZGl0aW9uYW1hc3Q3Mi1jb25kaXRpb25hbWFzdDQ4LCBsZXZlbHM9diRkZXNpZ24pCmFtYXN0NDguYW1hc3Q3Mi5maXQgPC0gY29udHJhc3RzLmZpdChmaXQsIGFtYXN0NDguYW1hc3Q3Mi5jb250ci5tYXQpCmFtYXN0NDguYW1hc3Q3Mi5lYiA8LSBlQmF5ZXMoYW1hc3Q0OC5hbWFzdDcyLmZpdCkKYW1hc3Q0OC5hbWFzdDcyLnRvcFRhYiA8LSB0b3BUYWJsZShhbWFzdDQ4LmFtYXN0NzIuZWIsIGNvZWY9ImFtYXN0NDhfdl9hbWFzdDcyIiwgbnVtYmVyPW5yb3codiRFKSkKCiNWaWV3IHRoZSBsaXN0IG9mIERFIGdlbmVzCmhlYWQoYW1hc3Q0OC5hbWFzdDcyLnRvcFRhYiwgbj0zTCkKIyAgICAgICAgICAgICAgICAgICAgbG9nRkMgIEF2ZUV4cHIgICAgICAgICB0ICAgICAgUC5WYWx1ZSBhZGouUC5WYWwgICAgICAgICAgQgojTG1qRi4yMy4wMDI1LTEgLTAuNTU1Nzk4NSA2LjAzMzA0OCAtNC4xNzI3NjIgMC4wMDAzMDg2OTI0IDAuMzgxNTc2OCAtMC4yNTgyMzE0CiNMbWpGLjEzLjE1MDAtMSAgMC41MjgzNTA5IDcuNjU4MjgzICAzLjkzMTgwNyAwLjAwMDU3NjA4OTcgMC4zODE1NzY4IC0wLjUzMDM3NTIKI0xtakYuMjIuMTY0MC0xIC0wLjY4MDUzMDggNi45NTc4MzcgLTMuODgyMzE0IDAuMDAwNjU0NDQ2MSAwLjM4MTU3NjggLTAuNjU0MjA1NAoKI0xpbWl0IGxpc3QgdG8gZ2VuZXMgd2l0aCBhbiBhZGp1c3RlZCBwIHZhbHVlIDwgMC4wNQphbWFzdDQ4LmFtYXN0NzIuc2lnR2VuZXMgPC0gYW1hc3Q0OC5hbWFzdDcyLnRvcFRhYlthbWFzdDQ4LmFtYXN0NzIudG9wVGFiJGFkai5QLlZhbCA8MC4wNSwgXQpsZW5ndGgoYW1hc3Q0OC5hbWFzdDcyLnNpZ0dlbmVzJGxvZ0ZDKQojMAoKI01ha2UgYW4gTUEgcGxvdApzZWwgPSBhbWFzdDQ4LmFtYXN0NzIudG9wVGFiJGFkai5QLlZhbCA8IDAuMDUKdG9wID0gYW1hc3Q0OC5hbWFzdDcyLnRvcFRhYgpzdWIgPSBwYXN0ZSgiTm8uIG9mIHNpZy4gZ2VuZXM6ICIsIHN1bShzZWwpLCIvIixsZW5ndGgoc2VsKSkKY3BtID0gdiRFCgpwbG90KHJvd01lYW5zKGNwbVtyb3duYW1lcyh0b3ApLF0pLCB0b3AkbG9nRkMsIHBjaD0xNiwgY2V4PTAuNSxjb2w9ImRhcmtncmV5IiwKICAgICAgICBtYWluPSJhbWFzdDQ4X2FtYXN0NzIgbW9kZWwgYmF0Y2ggYWRqdXN0ZWQiLAogICAgICAgIHlsYWI9ImxvZyBGQyIsIHhsYWI9IkF2ZXJhZ2UgRXhwcmVzc2lvbiIsCiAgICAgICAgeWxpbT1jKC0zLDMpLCBzdWI9c3ViKQpwb2ludHMocm93TWVhbnMoY3BtW3Jvd25hbWVzKHRvcCksXSlbc2VsXSwgdG9wJGxvZ0ZDW3NlbF0sIGNvbD0icmVkIiwgY2V4PTAuNSkKYWJsaW5lKGg9YygtMSwwLDEpLCBjb2w9InJlZCIpCgpgYGAKCmBgYHtyIHNhdmVtZX0KaWYgKGlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9c2F2ZWZpbGUpKQp9CmBgYAo=