1 Differential Expression, Macrophage: 20190205

2 Differential expression analyses

It appears that it is possible though somewhat difficult to apply batch estimations generated by sva to the model given to DESeq/EdgeR/limma. In the case of limma it is fairly simple, but in the other two it is a bit more difficult. There is a nice discussion of this at: https://www.biostars.org/p/156186/ I am attempting to apply that logic to this data with limited success.

3 Table S2 and Figure 1b, Table S3

  • Table S2 is taking only the DESeq2 results.
  • Figure 1c is intended to be a volcano plot of the DESeq2 results.
##                 hgncsymbol ensembltranscriptid   ensemblgeneid
## ENSG00000000003     TSPAN6     ENST00000373020 ENSG00000000003
## ENSG00000000005       TNMD     ENST00000373031 ENSG00000000005
## ENSG00000000419       DPM1     ENST00000371582 ENSG00000000419
## ENSG00000000457      SCYL3     ENST00000367770 ENSG00000000457
## ENSG00000000460   C1orf112     ENST00000286031 ENSG00000000460
## ENSG00000000938        FGR     ENST00000374003 ENSG00000000938
##                                                                                                    description
## ENSG00000000003                                              tetraspanin 6 [Source:HGNC Symbol;Acc:HGNC:11858]
## ENSG00000000005                                                tenomodulin [Source:HGNC Symbol;Acc:HGNC:17757]
## ENSG00000000419 dolichyl-phosphate mannosyltransferase subunit 1, catalytic [Source:HGNC Symbol;Acc:HGNC:3005]
## ENSG00000000457                                   SCY1 like pseudokinase 3 [Source:HGNC Symbol;Acc:HGNC:19285]
## ENSG00000000460                        chromosome 1 open reading frame 112 [Source:HGNC Symbol;Acc:HGNC:25565]
## ENSG00000000938              FGR proto-oncogene, Src family tyrosine kinase [Source:HGNC Symbol;Acc:HGNC:3697]
##                    genebiotype
## ENSG00000000003 protein_coding
## ENSG00000000005 protein_coding
## ENSG00000000419 protein_coding
## ENSG00000000457 protein_coding
## ENSG00000000460 protein_coding
## ENSG00000000938 protein_coding
##                                                        xcelltypes
## ENSG00000000003                                                  
## ENSG00000000005                                                  
## ENSG00000000419                               CD4+ memory T-cells
## ENSG00000000457                                                  
## ENSG00000000460                                      Erythrocytes
## ENSG00000000938 Basophils, Macrophages, Macrophages M2, Monocytes
##                 deseq_logfc deseq_adjp deseq_basemean deseq_lfcse
## ENSG00000000003     -1.4690    1.00000          1.347      1.8780
## ENSG00000000005      0.0000    1.00000          0.000      0.0000
## ENSG00000000419      0.0913    0.73270        368.500      0.1413
## ENSG00000000457     -0.1052    0.79820        188.800      0.2085
## ENSG00000000460     -0.3300    0.29490        156.600      0.2085
## ENSG00000000938      0.8099    0.01497       4846.000      0.2535
##                 deseq_stat deseq_p deseq_adjp_fdr
## ENSG00000000003    -0.7826  0.4339      1.000e+00
## ENSG00000000005     0.0000  1.0000      1.000e+00
## ENSG00000000419     0.6460  0.5183      1.000e+00
## ENSG00000000457    -0.5045  0.6139      1.000e+00
## ENSG00000000460    -1.5830  0.1135      1.000e+00
## ENSG00000000938     3.1950  0.0014      5.743e-02
## The color list must have 4, setting it to the default.
## Going to write the image to: images/Figure_1c.pdf when dev.off() is called.
## png 
##   2

3.2 Batch correction via ruv residuals

3.2.1 Set up ruvresiduals

## batch_counts: Before batch/surrogate estimation, 92 entries are x<=0.
## The be method chose 1 surrogate variable(s).
## Attempting ruvseq residual surrogate estimation with 1 surrogates.

## batch_counts: Before batch/surrogate estimation, 92 entries are x<=0.
## The be method chose 1 surrogate variable(s).
## Attempting ruvseq residual surrogate estimation with 1 surrogates.

4 Figure out how to compare these results

I have 4 methods of performing this differential expression analysis. Each one comes with a set of metrics defining ‘significant’. Perhaps I can make a table of the # of genes defined as significant by contrast for each. In addition it may be worth while to do a scatter plots of the logFCs between these comparisons and see how well they agree?

5 Look first at the de counts

##               change_counts_up change_counts_down
## macro_chr-sh              2036                560
## macro_chr-nil              949               1176
## macro_sh-nil               458               1791

5.1 Compare DeSeq / Basic without batch in model

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 370, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9545 0.9574
## sample estimates:
##   cor 
## 0.956

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 81, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5683 0.5911
## sample estimates:
##    cor 
## 0.5798

5.2 Compare SVA to batch in model, DESeq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 71, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5176 0.5423
## sample estimates:
##    cor 
## 0.5301

5.2.1 Include p-value estimations

Try putting some information of the p-values with the comparative log2fc

cutoff <- 0.1
lfc_b_s$state <- ifelse(lfc_b_s$psva > cutoff & lfc_b_s$pbatch > cutoff, "bothinsig",
                 ifelse(lfc_b_s$psva <= cutoff & lfc_b_s$pbatch <= cutoff, "bothsig",
                 ifelse(lfc_b_s$psva <= cutoff, "svasig", "batchsig")))
##lfcp_b_s$lfcstate <- ifelse(lfcp_b_s$l2fcsva >= 0.75 & lfcp_b_s$l2fcbatch, "", "")
num_bothinsig <- sum(lfc_b_s$state == "bothinsig")
num_bothsig <- sum(lfc_b_s$state == "bothsig")
num_svasig <- sum(lfc_b_s$state == "svasig")
num_batchsig <- sum(lfc_b_s$state == "batchsig")

library(ggplot2)
aes_color = "(l2fcsva >= 0.75 | l2fcsva <= -0.75 | l2fcbatch >= 0.75 | l2fcbatch <= -0.75)"
plt <- ggplot2::ggplot(lfc_b_s, aes_string(x="l2fcsva", y="l2fcbatch")) +
    ## ggplot2::geom_point(stat="identity", size=2, alpha=0.2, aes_string(shape="as.factor(aes_color)", colour="as.factor(state)", fill="as.factor(state)")) +
    ggplot2::geom_abline(colour="blue", slope=1, intercept=0, size=0.5) +
    ggplot2::geom_hline(yintercept=c(-0.75, 0.75), color="red", size=0.5) +
    ggplot2::geom_vline(xintercept=c(-0.75, 0.75), color="red", size=0.5) +
    ggplot2::geom_point(stat="identity", size=2, alpha=0.2, aes_string(colour="as.factor(state)", fill="as.factor(state)")) +
    ggplot2::scale_color_manual(name="state", values=c("bothinsig"="grey", "bothsig"="forestgreen", "svasig"="darkred", "batchsig"="darkblue")) +
    ggplot2::scale_fill_manual(name="state", values=c("bothinsig"="grey", "bothsig"="forestgreen", "svasig"="darkred", "batchsig"="darkblue"),
                               labels=c(
                                   paste0("Both InSig.: ", num_bothinsig),
                                   paste0("Both Sig.: ", num_bothsig),
                                   paste0("Sva Sig.: ", num_svasig),
                                   paste0("Batch Sig.: ", num_batchsig)),
                               guide=ggplot2::guide_legend(override.aes=aes(size=3, fill="grey"))) +
    ggplot2::guides(fill=ggplot2::guide_legend(override.aes=list(size=3))) +
    ggplot2::theme_bw()
plt

5.3 Compare ruvresid to batch in model, DESeq

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 400, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9601 0.9627
## sample estimates:
##    cor 
## 0.9614

5.4 Compare no batch to batch in model, limma

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0

## Warning in lmrob.S(x, y, control = control): find_scale() did not converge
## in 'maxit.scale' (= 200) iterations with tol=1e-10, last rel.diff=0
## Warning in lmrob.S(x, y, control = control): S refinements did not converge
## (to refine.tol=1e-07) in 200 (= k.max) steps

## Warning in lmrob.S(x, y, control = control): S refinements did not converge
## (to refine.tol=1e-07) in 200 (= k.max) steps
## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 110, df = 51000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4196 0.4338
## sample estimates:
##    cor 
## 0.4267

5.5 Batch in model vs. SVA, limma

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 70, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5092 0.5342
## sample estimates:
##    cor 
## 0.5218

5.6 Nobatch vs. batch in model, edger

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 260, df = 51000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7567 0.7640
## sample estimates:
##    cor 
## 0.7604

5.7 Batch in model vs. SVA, edger

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 71, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5183 0.5429
## sample estimates:
##    cor 
## 0.5307

5.8 Compare nobatch vs. batch, deseq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 150, df = 51000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5443 0.5564
## sample estimates:
##    cor 
## 0.5503

5.9 Compare batch vs. SVA, deseq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 71, df = 13000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5176 0.5423
## sample estimates:
##    cor 
## 0.5301

6 Repeat using the parasite data

In ‘macrophage_estimation’, we did a series of analyses to try to pick out some of the surrogate variables in the data. Now we will perform a set of differential expression analyses using the results from that. Since the ‘batch’ element of the data is reasonably well explained, we will not abuse the data with sva/combat, but instead include batch in the experimental model.

It appears that it is possible though somewhat difficult to apply batch estimations generated by sva to the model given to DESeq/EdgeR/limma. In the case of limma it is fairly simple, but in the other two it is a bit more difficult. There is a nice discussion of this at: https://www.biostars.org/p/156186/ I am attempting to apply that logic to this data with limited success.

7 Figure out how to compare these results

I have 4 methods of performing this differential expression analysis. Each one comes with a set of metrics defining ‘significant’. Perhaps I can make a table of the # of genes defined as significant by contrast for each. In addition it may be worth while to do a scatter plots of the logFCs between these comparisons and see how well they agree?

7.1 Compare DeSeq / Basic without batch in model

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 130, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7992 0.8139
## sample estimates:
##    cor 
## 0.8067

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 100, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7386 0.7572
## sample estimates:
##   cor 
## 0.748

7.2 Compare SVA to batch in model, DESeq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 80, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6378 0.6622
## sample estimates:
##    cor 
## 0.6502

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 43, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4051 0.4397
## sample estimates:
##    cor 
## 0.4225

7.2.1 Include p-value estimations

Try putting some information of the p-values with the comparative log2fc

cutoff <- 0.1
lfcp_b_s$state <- ifelse(lfcp_b_s$psva > cutoff & lfcp_b_s$pbatch > cutoff, "bothinsig",
                  ifelse(lfcp_b_s$psva <= cutoff & lfcp_b_s$pbatch <= cutoff, "bothsig",
                  ifelse(lfcp_b_s$psva <= cutoff, "svasig", "batchsig")))
##lfcp_b_s$lfcstate <- ifelse(lfcp_b_s$l2fcsva >= 0.75 & lfcp_b_s$l2fcbatch, "", "")
num_bothinsig <- sum(lfcp_b_s$state == "bothinsig")
num_bothsig <- sum(lfcp_b_s$state == "bothsig")
num_svasig <- sum(lfcp_b_s$state == "svasig")
num_batchsig <- sum(lfcp_b_s$state == "batchsig")

library(ggplot2)
aes_color = "(l2fcsva >= 0.75 | l2fcsva <= -0.75 | l2fcbatch >= 0.75 | l2fcbatch <= -0.75)"
plt <- ggplot2::ggplot(lfcp_b_s, aes_string(x="l2fcsva", y="l2fcbatch")) +
    ## ggplot2::geom_point(stat="identity", size=2, alpha=0.2, aes_string(shape="as.factor(aes_color)", colour="as.factor(state)", fill="as.factor(state)")) +
    ggplot2::geom_abline(colour="blue", slope=1, intercept=0, size=0.5) +
    ggplot2::geom_hline(yintercept=c(-0.75, 0.75), color="red", size=0.5) +
    ggplot2::geom_vline(xintercept=c(-0.75, 0.75), color="red", size=0.5) +
    ggplot2::geom_point(stat="identity", size=2, alpha=0.2, aes_string(colour="as.factor(state)", fill="as.factor(state)")) +
    ggplot2::scale_color_manual(name="state", values=c("bothinsig"="grey", "bothsig"="forestgreen", "svasig"="darkred", "batchsig"="darkblue")) +
    ggplot2::scale_fill_manual(name="state", values=c("bothinsig"="grey", "bothsig"="forestgreen", "svasig"="darkred", "batchsig"="darkblue"),
                               labels=c(
                                   paste0("Both InSig.: ", num_bothinsig),
                                   paste0("Both Sig.: ", num_bothsig),
                                   paste0("Sva Sig.: ", num_svasig),
                                   paste0("Batch Sig.: ", num_batchsig)),
                               guide=ggplot2::guide_legend(override.aes=aes(size=3, fill="grey"))) +
    ggplot2::guides(fill=ggplot2::guide_legend(override.aes=list(size=3))) +
    ggplot2::theme_bw()
plt

7.3 Compare no batch to batch in model, limma

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 77, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6235 0.6486
## sample estimates:
##    cor 
## 0.6362

7.4 Batch in model vs. SVA, limma

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 85, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6608 0.6839
## sample estimates:
##    cor 
## 0.6725

7.5 Nobatch vs. batch in model, edger

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 65, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5599 0.5881
## sample estimates:
##    cor 
## 0.5741

7.6 Batch in model vs. SVA, edger

## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 80, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6391 0.6634
## sample estimates:
##    cor 
## 0.6514

7.7 Compare nobatch vs. batch, deseq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 66, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5634 0.5915
## sample estimates:
##    cor 
## 0.5776

7.8 Compare batch vs. SVA, deseq

## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 80, df = 8700, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6378 0.6622
## sample estimates:
##    cor 
## 0.6502

R version 3.5.2 (2018-12-20)

Platform: x86_64-pc-linux-gnu (64-bit)

locale: LC_CTYPE=en_US.utf8, LC_NUMERIC=C, LC_TIME=en_US.utf8, LC_COLLATE=en_US.utf8, LC_MONETARY=en_US.utf8, LC_MESSAGES=en_US.utf8, LC_PAPER=en_US.utf8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.utf8 and LC_IDENTIFICATION=C

attached base packages: parallel, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: ggplot2(v.3.1.0), ruv(v.0.9.7), foreach(v.1.4.4), edgeR(v.3.24.3), bindrcpp(v.0.2.2), hpgltools(v.2018.11), Biobase(v.2.42.0) and BiocGenerics(v.0.28.0)

loaded via a namespace (and not attached): R.utils(v.2.7.0), tidyselect(v.0.2.5), lme4(v.1.1-19), htmlwidgets(v.1.3), RSQLite(v.2.1.1), AnnotationDbi(v.1.44.0), grid(v.3.5.2), BiocParallel(v.1.16.5), DESeq(v.1.34.1), devtools(v.2.0.1), munsell(v.0.5.0), codetools(v.0.2-16), preprocessCore(v.1.45.0), units(v.0.6-2), statmod(v.1.4.30), withr(v.2.1.2), colorspace(v.1.4-0), GOSemSim(v.2.8.0), OrganismDbi(v.1.24.0), knitr(v.1.21), rstudioapi(v.0.9.0), stats4(v.3.5.2), Vennerable(v.3.1.0.9000), robustbase(v.0.93-3), DOSE(v.3.8.2), labeling(v.0.3), urltools(v.1.7.1), GenomeInfoDbData(v.1.2.0), hwriter(v.1.3.2), bit64(v.0.9-7), farver(v.1.1.0), rprojroot(v.1.3-2), xfun(v.0.4), EDASeq(v.2.16.3), R6(v.2.3.0), doParallel(v.1.0.14), GenomeInfoDb(v.1.18.1), locfit(v.1.5-9.1), bitops(v.1.0-6), fgsea(v.1.8.0), gridGraphics(v.0.3-0), DelayedArray(v.0.8.0), assertthat(v.0.2.0), scales(v.1.0.0), ggraph(v.1.0.2), nnet(v.7.3-12), enrichplot(v.1.2.0), gtable(v.0.2.0), RUVSeq(v.1.16.1), sva(v.3.30.1), processx(v.3.2.1), rlang(v.0.3.1), genefilter(v.1.64.0), splines(v.3.5.2), rtracklayer(v.1.42.1), lazyeval(v.0.2.1), acepack(v.1.4.1), checkmate(v.1.9.1), europepmc(v.0.3), BiocManager(v.1.30.4), yaml(v.2.2.0), reshape2(v.1.4.3), GenomicFeatures(v.1.34.1), backports(v.1.1.3), qvalue(v.2.14.1), Hmisc(v.4.1-1), clusterProfiler(v.3.10.1), RBGL(v.1.58.1), tools(v.3.5.2), usethis(v.1.4.0), ggplotify(v.0.0.3), gplots(v.3.0.1), RColorBrewer(v.1.1-2), blockmodeling(v.0.3.4), sessioninfo(v.1.1.1), ggridges(v.0.5.1), Rcpp(v.1.0.0), plyr(v.1.8.4), base64enc(v.0.1-3), progress(v.1.2.0), zlibbioc(v.1.28.0), purrr(v.0.2.5), RCurl(v.1.95-4.11), ps(v.1.3.0), prettyunits(v.1.0.2), rpart(v.4.1-13), viridis(v.0.5.1), cowplot(v.0.9.4), S4Vectors(v.0.20.1), SummarizedExperiment(v.1.12.0), ggrepel(v.0.8.0), cluster(v.2.0.7-1), colorRamps(v.2.3), fs(v.1.2.6), variancePartition(v.1.12.1), magrittr(v.1.5), data.table(v.1.12.0), openxlsx(v.4.1.0), DO.db(v.2.9), triebeard(v.0.3.0), packrat(v.0.5.0), matrixStats(v.0.54.0), aroma.light(v.3.12.0), pkgload(v.1.0.2), hms(v.0.4.2), evaluate(v.0.12), xtable(v.1.8-3), pbkrtest(v.0.4-7), XML(v.3.98-1.16), IRanges(v.2.16.0), gridExtra(v.2.3), testthat(v.2.0.1), compiler(v.3.5.2), biomaRt(v.2.38.0), tibble(v.2.0.1), KernSmooth(v.2.23-15), crayon(v.1.3.4), R.oo(v.1.22.0), minqa(v.1.2.4), htmltools(v.0.3.6), mgcv(v.1.8-26), corpcor(v.1.6.9), snow(v.0.4-3), Formula(v.1.2-3), geneplotter(v.1.60.0), tidyr(v.0.8.2), DBI(v.1.0.0), tweenr(v.1.0.1), MASS(v.7.3-51.1), ShortRead(v.1.40.0), Matrix(v.1.2-15), cli(v.1.0.1), R.methodsS3(v.1.7.1), quadprog(v.1.5-5), gdata(v.2.18.0), bindr(v.0.1.1), igraph(v.1.2.2), GenomicRanges(v.1.34.0), pkgconfig(v.2.0.2), registry(v.0.5), rvcheck(v.0.1.3), GenomicAlignments(v.1.18.1), foreign(v.0.8-71), xml2(v.1.2.0), annotate(v.1.60.0), rngtools(v.1.3.1), pkgmaker(v.0.27), XVector(v.0.22.0), bibtex(v.0.4.2), doRNG(v.1.7.1), EBSeq(v.1.22.1), stringr(v.1.3.1), callr(v.3.1.1), digest(v.0.6.18), graph(v.1.60.0), Biostrings(v.2.50.2), rmarkdown(v.1.11), fastmatch(v.1.1-0), htmlTable(v.1.13.1), directlabels(v.2018.05.22), Rsamtools(v.1.34.0), gtools(v.3.8.1), nloptr(v.1.2.1), nlme(v.3.1-137), jsonlite(v.1.6), desc(v.1.2.0), viridisLite(v.0.3.0), limma(v.3.38.3), pillar(v.1.3.1), lattice(v.0.20-38), DEoptimR(v.1.0-8), httr(v.1.4.0), pkgbuild(v.1.0.2), survival(v.2.43-3), GO.db(v.3.7.0), glue(v.1.3.0), remotes(v.2.0.2), zip(v.1.0.0), UpSetR(v.1.3.3), iterators(v.1.0.10), pander(v.0.6.3), bit(v.1.1-14), ggforce(v.0.1.3), stringi(v.1.2.4), blob(v.1.1.1), DESeq2(v.1.22.2), doSNOW(v.1.0.16), latticeExtra(v.0.6-28), caTools(v.1.17.1.1), memoise(v.1.1.0) and dplyr(v.0.7.8)

## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 45b7ec8bad3682886965df63000dc4e98bcbf69f
## This is hpgltools commit: Wed Feb 6 16:38:23 2019 -0500: 45b7ec8bad3682886965df63000dc4e98bcbf69f
## Saving to 03_expression_macrophage_20190205-v20190205.rda.xz
LS0tCnRpdGxlOiAiTC5wYW5hbWVuc2lzIDIwMTY6IERpZmZlcmVudGlhbCBFeHByZXNzaW9uIGluIGh1bWFuIG1hY3JvcGhhZ2VzLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHdpZHRoOiAzMDAKICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoImhwZ2x0b29scyIpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0PTgsCiAgICAgICAgICAgICAgICAgICAgICBkcGk9OTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdD0iJVklbSVkIikKcHJldmlvdXNfZmlsZSA8LSAiMDJfZXN0aW1hdGlvbl9tYWNyb3BoYWdlXzIwMTkwMjA1LlJtZCIKdmVyIDwtICIyMDE5MDIwNSIKCnRtcCA8LSBzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkKcm1kX2ZpbGUgPC0gIjAzX2V4cHJlc3Npb25fbWFjcm9waGFnZV8yMDE5MDIwNS5SbWQiCmBgYAoKIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiwgTWFjcm9waGFnZTogYHIgdmVyYAoKIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNlcwoKSXQgYXBwZWFycyB0aGF0IGl0IGlzIHBvc3NpYmxlIHRob3VnaCBzb21ld2hhdCBkaWZmaWN1bHQgdG8gYXBwbHkgYmF0Y2ggZXN0aW1hdGlvbnMgZ2VuZXJhdGVkIGJ5IHN2YQp0byB0aGUgbW9kZWwgZ2l2ZW4gdG8gREVTZXEvRWRnZVIvbGltbWEuICBJbiB0aGUgY2FzZSBvZiBsaW1tYSBpdCBpcyBmYWlybHkgc2ltcGxlLCBidXQgaW4gdGhlIG90aGVyCnR3byBpdCBpcyBhIGJpdCBtb3JlIGRpZmZpY3VsdC4gIFRoZXJlIGlzIGEgbmljZSBkaXNjdXNzaW9uIG9mIHRoaXMgYXQ6IGh0dHBzOi8vd3d3LmJpb3N0YXJzLm9yZy9wLzE1NjE4Ni8KSSBhbSBhdHRlbXB0aW5nIHRvIGFwcGx5IHRoYXQgbG9naWMgdG8gdGhpcyBkYXRhIHdpdGggbGltaXRlZCBzdWNjZXNzLgoKYGBge3Igc2V0dXBfZGVfbm9ybSwgZmlnLnNob3c9ImhpZGUifQpoc19jb250cmFzdHMgPC0gbGlzdCgKICAgICJtYWNyb19jaHItc2giID0gYygiY2hyIiwic2giKSwKICAgICJtYWNyb19jaHItbmlsIiA9IGMoImNociIsInVuaW5mIiksCiAgICAibWFjcm9fc2gtbmlsIiA9IGMoInNoIiwgInVuaW5mIikpCiMjIFNldCB1cCB0aGUgZGF0YSB1c2VkIGluIHRoZSBjb21wYXJhdGl2ZSBjb250cmFzdCBzZXRzLgpgYGAKCiMjIE5vIGJhdGNoIGluIHRoZSBtb2RlbAoKIyMjIFNldCB1cCBubyBiYXRjaAoKUHJpbnQgYSByZW1pbmRlciBvZiB3aGF0IHdlIGNhbiBleHBlY3Qgd2hlbiBkb2luZyB0aGlzIHdpdGggbm8gYmF0Y2ggaW5mb3JtYXRpb24uCgpgYGB7ciBub2JhdGNoX3NldHVwfQpoc19tYWNyX2xvd2ZpbHQgPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2RzX21hY3IsIGZpbHRlcj1UUlVFKSkKaHNfbG93ZmlsdF9wY2EgPC0gc20ocGxvdF9wY2EoaHNfY2RzX21hY3IsIHRyYW5zZm9ybT0ibG9nMiIpKQpoc19sb3dmaWx0X3BjYSRwbG90CmBgYAoKYGBge3IgbWFjcm9fbm9iYXRjaDEsIGZpZy5zaG93PSJoaWRlIn0KaHNfbWFjcl9ub2JhdGNoIDwtIHNtKGFsbF9wYWlyd2lzZShpbnB1dD1oc19jZHNfbWFjciwgbW9kZWxfYmF0Y2g9RkFMU0UsIHBhcmFsbGVsPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbW1hX21ldGhvZD0icm9idXN0IikpCiMjIHdvdywgYWxsIHRvb2xzIGluY2x1ZGluZyBiYXNpYyBhZ3JlZSBhbG1vc3QgY29tcGxldGVseQptZWRpYW5zX2J5X2NvbmRpdGlvbiA8LSBoc19tYWNyX25vYmF0Y2gkYmFzaWMkbWVkaWFucwpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX25vYmF0Y2hfY29udHItdnt2ZXJ9Lnhsc3giKQpoc19tYWNyX25vYmF0Y2hfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKGhzX21hY3Jfbm9iYXRjaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1leGNlbF9maWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnM9aHNfY29udHJhc3RzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2Fubm90PW1lZGlhbnNfYnlfY29uZGl0aW9uKSkKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1faHNfbWFjcl9ub2JhdGNoX3NpZy12e3Zlcn0ueGxzeCIpCmhzX21hY3Jfbm9iYXRjaF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhoc19tYWNyX25vYmF0Y2hfdGFibGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ZXhjZWxfZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY29yZGluZ190bz0iYWxsIikpCmBgYAoKIyMgQmF0Y2ggaW4gdGhlIG1vZGVsCgojIyMgQmF0Y2ggc2V0dXAKCmBgYHtyIGJhdGNoX3NldHVwfQpoc19sb3dmaWx0X2JhdGNoX3BjYSA8LSBzbShwbG90X3BjYShoc19jZHNfbWFjciwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2g9ImxpbW1hIikpCmhzX2xvd2ZpbHRfYmF0Y2hfcGNhJHBsb3QKYGBgCgpJbiB0aGlzICBhdHRlbXB0LCB3ZSBhZGQgYSBiYXRjaCBmYWN0b3IgaW4gdGhlIGV4cGVyaW1lbnRhbCBtb2RlbCBhbmQgc2VlIGhvdyBpdCBkb2VzLgoKYGBge3IgbWFjcm9fYmF0Y2gxLCBmaWcuc2hvdz0iaGlkZSJ9CiMjIEhlcmUganVzdCBsZXQgYWxsX3BhaXJ3aXNlIHJ1biBvbiBmaWx0ZXJlZCBkYXRhIGFuZCBkbyBpdHMgbm9ybWFsIH4gMCArIGNvbmRpdGlvbiArIGJhdGNoIGFuYWx5c2VzCmhzX21hY3JfYmF0Y2ggPC0gc20oYWxsX3BhaXJ3aXNlKGlucHV0PWhzX2Nkc19tYWNyLCBsaW1tYV9tZXRob2Q9InJvYnVzdCIsIHBhcmFsbGVsPUZBTFNFKSkKbWVkaWFuc19ieV9jb25kaXRpb24gPC0gaHNfbWFjcl9iYXRjaCRiYXNpYyRtZWRpYW5zCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X2hzX21hY3JfYmF0Y2htb2RlbF9jb250ci12e3Zlcn0ueGxzeCIpCmhzX21hY3JfYmF0Y2hfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGhzX21hY3JfYmF0Y2gsCiAga2VlcGVycz1oc19jb250cmFzdHMsCiAgZXh0cmFfYW5ub3Q9bWVkaWFuc19ieV9jb25kaXRpb24sCiAgaW5jbHVkZV9saW1tYT1GQUxTRSwgaW5jbHVkZV9lZGdlcj1GQUxTRSwgaW5jbHVkZV9iYXNpYz1GQUxTRSwgaW5jbHVkZV9lYnNlcT1GQUxTRSwKICBleGNlbD1leGNlbF9maWxlKSkKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1faHNfbWFjcl9iYXRjaG1vZGVsX3NpZy12e3Zlcn0ueGxzeCIpCmhzX21hY3JfYmF0Y2hfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaHNfbWFjcl9iYXRjaF90YWJsZXMsIGV4Y2VsPWV4Y2VsX2ZpbGUsCiAgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX2JhdGNobW9kZWxfYWJ1bmQtdnt2ZXJ9Lnhsc3giKQpoc19tYWNyX2JhdGNoX2FidW4gPC0gc20oZXh0cmFjdF9hYnVuZGFudF9nZW5lcygKICBoc19tYWNyX2JhdGNoX3RhYmxlcywgZXhjZWw9ZXhjZWxfZmlsZSwKICBhY2NvcmRpbmdfdG89ImRlc2VxIikpCmBgYAoKIyBUYWJsZSBTMiBhbmQgRmlndXJlIDFiLCBUYWJsZSBTMwoKICogVGFibGUgUzIgaXMgdGFraW5nIG9ubHkgdGhlIERFU2VxMiByZXN1bHRzLgogKiBGaWd1cmUgMWMgaXMgaW50ZW5kZWQgdG8gYmUgYSB2b2xjYW5vIHBsb3Qgb2YgdGhlIERFU2VxMiByZXN1bHRzLgoKYGBge3IgdGFibGVfczJ9CnMyX2NvbnRyYXN0cyA8LSBsaXN0KAogICJtYWNyb19jaHItc2giID0gYygiY2hyIiwic2giKSkKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1fdGFibGUtczJfaHNfbWFjcl9iYXRjaG1vZGVsX2NvbnRyLXZ7dmVyfS54bHN4IikKdGFibGVfczIgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgaHNfbWFjcl9iYXRjaCwKICBleGNlbD1leGNlbF9maWxlLAogIGtlZXBlcnM9czJfY29udHJhc3RzLAogIGluY2x1ZGVfYmFzaWM9RkFMU0UsIGluY2x1ZGVfbGltbWE9RkFMU0UsCiAgaW5jbHVkZV9lYnNlcT1GQUxTRSwgaW5jbHVkZV9lZGdlcj1GQUxTRSkpCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X3RhYmxlLXMzX2hzX21hY3JfYmF0Y2htb2RlbF9zaWctdnt2ZXJ9Lnhsc3giKQp0YWJsZV9zMyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIHRhYmxlX3MyLAogIGV4Y2VsPWV4Y2VsX2ZpbGUsCiAgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQoKY2hvc2VuX3RhYmxlIDwtIHRhYmxlX3MyW1siZGF0YSJdXVtbMV1dCmhlYWQoY2hvc2VuX3RhYmxlKQp2b2wgPC0gcGxvdF92b2xjYW5vX2RlKHRhYmxlPWNob3Nlbl90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieT0ic3RhdGUiLAogICAgICAgICAgICAgICAgICAgICAgIGZjX2NvbD0iZGVzZXFfbG9nZmMiLAogICAgICAgICAgICAgICAgICAgICAgIHBfY29sPSJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICBzaGFwZXNfYnlfc3RhdGU9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgbGluZV9wb3NpdGlvbj0idG9wIikKcHAoZmlsZT0iaW1hZ2VzL0ZpZ3VyZV8xYy5wZGYiKQp2b2wkcGxvdApkZXYub2ZmKCkKYGBgCgojIyBCYXRjaCBlc3RpbWF0ZWQgd2l0aCBTVkEKCiMjIyBTZXQgdXAgc3ZhCgpgYGB7ciBzZXR1cF9zdmF9CmhzX2xvd2ZpbHRfc3Zhc2VxX3BjYSA8LSBzbShwbG90X3BjYShoc19jZHNfbWFjciwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKSkKaHNfbG93ZmlsdF9zdmFzZXFfcGNhJHBsb3QKYGBgCgpgYGB7ciBtYWNyb19zdmExLCBmaWcuc2hvdz0iaGlkZSJ9CmhzX2Nkc19tYWNyX2xvd2ZpbHQgPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2RzX21hY3IsIGZpbHRlcj1UUlVFKSkKIyMgSGVyZSBqdXN0IGxldCBhbGxfcGFpcndpc2UgcnVuIG9uIGZpbHRlcmVkIGRhdGEgYW5kIGRvIGl0cyBub3JtYWwgfiAwICsgY29uZGl0aW9uICsgYmF0Y2ggYW5hbHlzZXMKaHNfbWFjcl9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKAogIGlucHV0PWhzX2Nkc19tYWNyX2xvd2ZpbHQsCiAgbW9kZWxfYmF0Y2g9InN2YXNlcSIsCiAgbGltbWFfbWV0aG9kPSJyb2J1c3QiKSkKbWVkaWFuc19ieV9jb25kaXRpb24gPC0gaHNfbWFjcl9zdmEkYmFzaWMkbWVkaWFucwpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX3N2YV9jb250ci12e3Zlcn0ueGxzeCIpCmhzX21hY3Jfc3ZhX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICBoc19tYWNyX3N2YSwKICBleGNlbD1leGNlbF9maWxlLAogIGtlZXBlcnM9aHNfY29udHJhc3RzLAogIGV4dHJhX2Fubm90PW1lZGlhbnNfYnlfY29uZGl0aW9uKSkKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1faHNfbWFjcl9zdmFfc2lnLXZ7dmVyfS54bHN4IikKaHNfbWFjcl9zdmFfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaHNfbWFjcl9zdmFfdGFibGVzLAogIGV4Y2VsPWV4Y2VsX2ZpbGUpKQpoc19tYWNyX3N2YV9tYV9saW1tYSA8LSBleHRyYWN0X2RlX3Bsb3RzKAogIHBhaXJ3aXNlPWhzX21hY3Jfc3ZhLAogIHR5cGU9ImxpbW1hIiwKICB0YWJsZT0ic2hfdnNfY2hyIikKYGBgCgpgYGB7ciBzdmFfbWFfcGxvdH0KaHNfbWFjcl9zdmFfbWFfbGltbWEkbWEkcGxvdApgYGAKCiMjIEJhdGNoIGNvcnJlY3Rpb24gdmlhIHJ1diByZXNpZHVhbHMKCiMjIyBTZXQgdXAgcnV2cmVzaWR1YWxzCgpgYGB7ciBzZXR1cF9ydXZyZXNpZH0KIyMgaG1tIEkgZ290IHRoZSBSVVZyIGVycm9yIGFnYWluLCBidXQgd2hlbiBJIHJhbiBpdCBtYW51YWxseSBkaWQgbm90LgojIyBFdmVuIG1vcmUgc3RyYW5nZWx5LCBpZiBJIGp1c3QgcnVuIHRoZSBzYW1lIHRoaW5nIGFnYWluLCBubyBlcnJvci4uLgp0ZXN0bWUgPC0gdHJ5KGFsbF9hZGp1c3RlcnMoaW5wdXQ9aHNfbWFjcl9sb3dmaWx0LCBlc3RpbWF0ZV90eXBlPSJydXZfcmVzaWR1YWxzIiksIHNpbGVudD1UUlVFKQoKaHNfbG93ZmlsdF9ydXZyZXNpZF9wY2EgPC0gc20ocGxvdF9wY2EoaHNfbWFjcl9sb3dmaWx0LCB0cmFuc2Zvcm09ImxvZzIiLCBiYXRjaD0icnV2X3Jlc2lkdWFscyIpKQpoc19sb3dmaWx0X3J1dnJlc2lkX3BjYSRwbG90CmBgYAoKYGBge3IgbWFjcm9fcnV2cmVzaWQxLCBmaWcuc2hvdz0iaGlkZSJ9CiMjIEhlcmUganVzdCBsZXQgYWxsX3BhaXJ3aXNlIHJ1biBvbiBmaWx0ZXJlZCBkYXRhIGFuZCBkbyBpdHMgbm9ybWFsIH4gMCArIGNvbmRpdGlvbiArIGJhdGNoIGFuYWx5c2VzCiMjIEJpemFycmVseSwgc29tZXRpbWVzIGlmIG9uZSBydW5zIHRoaXMsIGl0IGdpdmVzIGFuIGVycm9yICJFcnJvciBpbiAoZnVuY3Rpb24gKGNsYXNzZXMsIGZkZWYsIG10YWJsZSkgOiB1bmFibGUgdG8gZmluZCBhbiBpbmhlcml0ZWQgbWV0aG9kIGZvciBmdW5jdGlvbiAnUlVWcicgZm9yIHNpZ25hdHVyZSAnIm1hdHJpeCIsICJsb2dpY2FsIiwgIm51bWVyaWMiLCAiTlVMTCInIiAgLS0gaG93ZXZlciwgaWYgb25lIHRoZW4gc2ltcGx5IHJ1bnMgaXQgYWdhaW4gaXQgd29ya3MgZmluZS4KIyMgSSBhbSBnb2luZyB0byBhc3N1bWUgdGhhdCBpdCBpcyBiZWNhdXNlIEkgZG8gbm90IGV4cGxpY2l0bHkgaW52b2tlIHRoZSBsaWJyYXJ5LgojIyBsaWJyYXJ5KHJ1dikgICMjIGhvcGVmdWxseSBhIHNtYWxsIGNvZGUgY2hhbmdlIG1hZGUgdGhpcyBub3QgbmVlZGVkLgp0ZXN0bWUgPC0gYWxsX2FkanVzdGVycyhpbnB1dD1oc19tYWNyX2xvd2ZpbHQsIGVzdGltYXRlX3R5cGU9InJ1dl9yZXNpZHVhbHMiKQpoc19tYWNyX3J1dnJlcyA8LSBzbShhbGxfcGFpcndpc2UoCiAgaW5wdXQ9aHNfbWFjcl9sb3dmaWx0LAogIG1vZGVsX2JhdGNoPSJydXZfcmVzaWR1YWxzIiwKICBsaW1tYV9tZXRob2Q9InJvYnVzdCIpKQptZWRpYW5zX2J5X2NvbmRpdGlvbiA8LSBoc19tYWNyX3J1dnJlcyRiYXNpYyRtZWRpYW5zCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X2hzX21hY3JfcnV2cmVzX2NvbnRyLXZ7dmVyfS54bHN4IikKaHNfbWFjcl9ydXZyZXNfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGhzX21hY3JfcnV2cmVzLAogIGV4Y2VsPWV4Y2VsX2ZpbGUsCiAgZXh0cmFfYW5ub3Q9bWVkaWFuc19ieV9jb25kaXRpb24sCiAga2VlcGVycz1oc19jb250cmFzdHMpKQpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX3J1dnJlc19zaWctdnt2ZXJ9Lnhsc3giKQpoc19tYWNyX3J1dnJlc19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBoc19tYWNyX3J1dnJlc190YWJsZXMsCiAgZXhjZWw9ZXhjZWxfZmlsZSkpCmBgYAoKIyMgQmF0Y2ggY29ycmVjdGlvbiB3aXRoIHBjYQoKIyMjIFNldHVwIHBjYQoKYGBge3Igc2V0dXBfcGNhMDF9CmhzX2xvd2ZpbHRfcGNhX3BjYSA8LSBzbShwbG90X3BjYShoc19tYWNyX2xvd2ZpbHQsIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJwY2EiKSkKaHNfbG93ZmlsdF9wY2FfcGNhJHBsb3QKYGBgCgpgYGB7ciBtYWNyb19wY2ExLCBmaWcuc2hvdz0iaGlkZSJ9CiMjIEhlcmUganVzdCBsZXQgYWxsX3BhaXJ3aXNlIHJ1biBvbiBmaWx0ZXJlZCBkYXRhIGFuZCBkbyBpdHMgbm9ybWFsIH4gMCArIGNvbmRpdGlvbiArIGJhdGNoIGFuYWx5c2VzCmhzX21hY3JfcGNhIDwtIHNtKGFsbF9wYWlyd2lzZSgKICBpbnB1dD1oc19tYWNyX2xvd2ZpbHQsCiAgbW9kZWxfYmF0Y2g9InBjYSIsCiAgbGltbWFfbWV0aG9kPSJyb2J1c3QiKSkKbWVkaWFuc19ieV9jb25kaXRpb24gPC0gaHNfbWFjcl9wY2EkYmFzaWMkbWVkaWFucwpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX3BjYV9jb250ci12e3Zlcn0ueGxzeCIpCmhzX21hY3JfcGNhX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICBoc19tYWNyX3BjYSwKICBleGNlbD1leGNlbF9maWxlLAogIGtlZXBlcnM9aHNfY29udHJhc3RzLAogIGV4dHJhX2Fubm90PW1lZGlhbnNfYnlfY29uZGl0aW9uKSkKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1faHNfbWFjcl9wY2Ffc2lnLXZ7dmVyfS54bHN4IikKaHNfbWFjcl9wY2Ffc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaHNfbWFjcl9wY2FfdGFibGVzLAogIGV4Y2VsPWV4Y2VsX2ZpbGUpKQpgYGAKCiMjIEJhdGNoIGNvcnJlY3Rpb24gd2l0aCBydXYgZW1waXJpY2FsCgojIyMgU2V0dXAgcnV2IGVtcGlyaWNhbAoKYGBge3Igc2V0dXBfcGNhMDJ9CmhzX2xvd2ZpbHRfcnV2ZW1wX3BjYSA8LSBzbShwbG90X3BjYShoc19tYWNyX2xvd2ZpbHQsIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJydXZfZW1waXJpY2FsIikpCmhzX2xvd2ZpbHRfcnV2ZW1wX3BjYSRwbG90CmBgYAoKYGBge3IgbWFjcm9fcnV2ZW1wMSwgZmlnLnNob3c9ImhpZGUifQpoc19tYWNyX3J1dmVtcCA8LSBzbShhbGxfcGFpcndpc2UoCiAgaW5wdXQ9aHNfbWFjcl9sb3dmaWx0LAogIG1vZGVsX2JhdGNoPSJydXZfZW1waXJpY2FsIiwKICBsaW1tYV9tZXRob2Q9InJvYnVzdCIpKQptZWRpYW5zX2J5X2NvbmRpdGlvbiA8LSBoc19tYWNyX3J1dmVtcCRiYXNpYyRtZWRpYW5zCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X2hzX21hY3JfcnV2ZW1wX2NvbnRyLXZ7dmVyfS54bHN4IikKaHNfbWFjcl9ydXZlbXBfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGhzX21hY3JfcnV2ZW1wLAogIGV4Y2VsPWV4Y2VsX2ZpbGUsCiAga2VlcGVycz1oc19jb250cmFzdHMsCiAgZXh0cmFfYW5ub3Q9bWVkaWFuc19ieV9jb25kaXRpb24pKQpleGNlbF9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9oc19tYWNyX3J1dmVtcF9zaWctdnt2ZXJ9Lnhsc3giKQpoc19tYWNyX3J1dmVtcF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBoc19tYWNyX3J1dmVtcF90YWJsZXMsCiAgZXhjZWw9ZXhjZWxfZmlsZSkpCmBgYAoKIyMgQmF0Y2ggY29ycmVjdGlvbiB3aXRoIGNvbWJhdAoKVGhlbiByZXBlYXQgd2l0aCB0aGUgYmF0Y2gtY29ycmVjdGVkIGRhdGEgYW5kIHNlZSB0aGUgZGlmZmVyZW5jZXMuCgojIyMgU2V0dXAgY29tYmF0CgpgYGB7ciBzZXR1cF9jb21iYXR9CmhzX2xvd2ZpbHRfY29tYmF0X3BjYSA8LSBzbShwbG90X3BjYShoc19tYWNyX2xvd2ZpbHQsIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJjb21iYXRfbm9wcmlvciIpKQpoc19sb3dmaWx0X2NvbWJhdF9wY2EkcGxvdApgYGAKCmBgYHtyIHJlcGVhdF9wYWlyd2lzZV9iYXRjaDEsIGZpZy5zaG93PSJoaWRlIn0KaHNfbWFjcl9jb21iYXRfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChoc19tYWNyX2xvd2ZpbHQsIGJhdGNoPSJjb21iYXRfbm9zY2FsZSIpKQpoc19tYWNyX2NvbWJhdCA8LSBzbShhbGxfcGFpcndpc2UoCiAgaW5wdXQ9aHNfbWFjcl9jb21iYXRfbm9ybSwKICBmb3JjZT1UUlVFLAogIGxpbW1hX21ldGhvZD0icm9idXN0IikpCm1lZGlhbnNfYnlfY29uZGl0aW9uIDwtIGhzX21hY3JfY29tYmF0JGJhc2ljJG1lZGlhbnMKZXhjZWxfZmlsZSA8LSBnbHVlOjpnbHVlKCJleGNlbC97cnVuZGF0ZX1faHNfbWFjcl9jb21iYXRfY29udHItdnt2ZXJ9Lnhsc3giKQpoc19tYWNyX2NvbWJhdF90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgaHNfbWFjcl9jb21iYXQsCiAgZXhjZWw9ZXhjZWxfZmlsZSwKICBrZWVwZXJzPWhzX2NvbnRyYXN0cywKICBleHRyYV9hbm5vdD1tZWRpYW5zX2J5X2NvbmRpdGlvbikpCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X2hzX21hY3JfY29tYmF0X2NvbnRyLXZ7dmVyfS54bHN4IikKaHNfbWFjcl9jb21iYXRfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaHNfbWFjcl9jb21iYXRfdGFibGVzLAogIGV4Y2VsPWV4Y2VsX2ZpbGUpKQoKYGBgCgpgYGB7ciBmaW5pc2hlZF9tYV9wbG90c30KaHNfbWFjcl9jb21iYXRfbWFfbGltbWEgPC0gZXh0cmFjdF9kZV9wbG90cygKICBwYWlyd2lzZT1oc19tYWNyX2NvbWJhdCwKICB0eXBlPSJsaW1tYSIsCiAgdGFibGU9InNoX3ZzX2NociIpCmhzX21hY3JfY29tYmF0X21hX2xpbW1hJG1hJHBsb3QKCmhzX21hY3JfY29tYmF0X21hX2VkZ2VyIDwtIGV4dHJhY3RfZGVfcGxvdHMoCiAgcGFpcndpc2U9aHNfbWFjcl9jb21iYXQsCiAgdHlwZT0iZWRnZXIiLAogIHRhYmxlPSJzaF92c19jaHIiKQpoc19tYWNyX2NvbWJhdF9tYV9lZGdlciRtYSRwbG90Cgpoc19tYWNyX2NvbWJhdF9tYV9kZXNlcSA8LSBleHRyYWN0X2RlX3Bsb3RzKAogIHBhaXJ3aXNlPWhzX21hY3JfY29tYmF0LAogIHR5cGU9ImRlc2VxIiwKICB0YWJsZT0ic2hfdnNfY2hyIikKaHNfbWFjcl9jb21iYXRfbWFfZGVzZXEkbWEkcGxvdApgYGAKCiMgRmlndXJlIG91dCBob3cgdG8gY29tcGFyZSB0aGVzZSByZXN1bHRzCgpJIGhhdmUgNCBtZXRob2RzIG9mIHBlcmZvcm1pbmcgdGhpcyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcy4gIEVhY2ggb25lIGNvbWVzIHdpdGggYSBzZXQgb2YKbWV0cmljcyBkZWZpbmluZyAnc2lnbmlmaWNhbnQnLiAgUGVyaGFwcyBJIGNhbiBtYWtlIGEgdGFibGUgb2YgdGhlICMgb2YgZ2VuZXMgZGVmaW5lZCBhcyBzaWduaWZpY2FudApieSBjb250cmFzdCBmb3IgZWFjaC4gIEluIGFkZGl0aW9uIGl0IG1heSBiZSB3b3J0aCB3aGlsZSB0byBkbyBhIHNjYXR0ZXIgcGxvdHMgb2YgdGhlIGxvZ0ZDcyBiZXR3ZWVuCnRoZXNlIGNvbXBhcmlzb25zIGFuZCBzZWUgaG93IHdlbGwgdGhleSBhZ3JlZT8KCiMgTG9vayBmaXJzdCBhdCB0aGUgZGUgY291bnRzCgpgYGB7ciBjb21wYXJlX2RlX3NldHVwMX0KaHNfbWFjcl9ub2JhdGNoX3NpZyRsaW1tYSRjb3VudHMKIyNoc19tYWNyX2JhdGNoX3RhYmxlcyRzaWduaWZpY2FudCRsaW1tYSRjb3VudHMKIyNoc19tYWNyX3N2YV90YWJsZXMkc2lnbmlmaWNhbnQkbGltbWEkY291bnRzCiMjaHNfbWFjcl9ydXZyZXNfdGFibGVzJHNpZ25pZmljYW50JGxpbW1hJGNvdW50cwojI2hzX21hY3JfcGNhX3RhYmxlcyRzaWduaWZpY2FudCRsaW1tYSRjb3VudHMKIyNoc19tYWNyX3J1dmVtcF90YWJsZXMkc2lnbmlmaWNhbnQkbGltbWEkY291bnRzCiMjaHNfbWFjcl9jb21iYXRfdGFibGVzJHNpZ25pZmljYW50JGxpbW1hJGNvdW50cwpgYGAKCiMjIENvbXBhcmUgRGVTZXEgLyBCYXNpYyB3aXRob3V0IGJhdGNoIGluIG1vZGVsCgpgYGB7ciBiYXNpY19kZXNlcV9ub2JhdGNoMX0KaHNfbWFjcl9ub2JhdGNoX2Jhc2ljIDwtIG1lcmdlKAogIGhzX21hY3Jfbm9iYXRjaCRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBoc19tYWNyX2JhdGNoJGJhc2ljJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGJ5PSJyb3cubmFtZXMiKQpyb3duYW1lcyhoc19tYWNyX25vYmF0Y2hfYmFzaWMpIDwtIGhzX21hY3Jfbm9iYXRjaF9iYXNpY1tbIlJvdy5uYW1lcyJdXQpoc19tYWNyX25vYmF0Y2hfbG9nZmMgPC0gaHNfbWFjcl9ub2JhdGNoX2Jhc2ljWywgYygibG9nRkMueCIsICJsb2dGQy55IildCmNvbG5hbWVzKGhzX21hY3Jfbm9iYXRjaF9sb2dmYykgPC0gYygibm9iYXRjaCIsICJiYXNpYyIpCmxmY19uYl9iIDwtIHNtKHBsb3RfbGluZWFyX3NjYXR0ZXIoaHNfbWFjcl9ub2JhdGNoX2xvZ2ZjLCBwcmV0dHlfY29sb3JzPUZBTFNFKSkKbGZjX25iX2Ikc2NhdHRlcgpsZmNfbmJfYiRjb3JyZWxhdGlvbgpoc19tYWNyX25vYmF0Y2hfcCA8LSBoc19tYWNyX25vYmF0Y2hfYmFzaWNbLCBjKCJQLlZhbHVlIiwicCIpXQpoc19tYWNyX25vYmF0Y2hfcFtbMl1dIDwtIGFzLm51bWVyaWMoaHNfbWFjcl9ub2JhdGNoX3BbWzJdXSkKY29sbmFtZXMoaHNfbWFjcl9ub2JhdGNoX3ApIDwtIGMoIm5vYmF0Y2giLCJiYXNpYyIpCmhzX21hY3Jfbm9iYXRjaF9wIDwtIC0xICogbG9nKGhzX21hY3Jfbm9iYXRjaF9wKQpoc19tYWNyX3BfbmJfYiA8LSBzbShwbG90X2xpbmVhcl9zY2F0dGVyKGhzX21hY3Jfbm9iYXRjaF9wLCBwcmV0dHlfY29sb3JzPUZBTFNFKSkKaHNfbWFjcl9wX25iX2Ikc2NhdHRlcgpoc19tYWNyX3BfbmJfYiRjb3JyZWxhdGlvbgpgYGAKCiMjIENvbXBhcmUgU1ZBIHRvIGJhdGNoIGluIG1vZGVsLCBERVNlcQoKYGBge3IgZGVzZXFfc3ZhX2JhdGNoMX0KaHNfbWFjcl9zdmFfYmF0Y2ggPC0gbWVyZ2UoCiAgaHNfbWFjcl9zdmEkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgaHNfbWFjcl9iYXRjaCRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoaHNfbWFjcl9zdmFfYmF0Y2gpIDwtIGhzX21hY3Jfc3ZhX2JhdGNoW1siUm93Lm5hbWVzIl1dCmhzX21hY3Jfc3ZhX2xvZ2ZjIDwtIGhzX21hY3Jfc3ZhX2JhdGNoWywgYygibG9nRkMueCIsImxvZ0ZDLnkiKV0KY29sbmFtZXMoaHNfbWFjcl9zdmFfbG9nZmMpIDwtIGMoInN2YSIsImJhdGNoIikKaHNfbWFjcl9sZmNfYl9zIDwtIHNtKHBsb3RfbGluZWFyX3NjYXR0ZXIoaHNfbWFjcl9zdmFfbG9nZmMsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpoc19tYWNyX2xmY19iX3Mkc2NhdHRlcgpoc19tYWNyX2xmY19iX3MkY29ycmVsYXRpb24KYGBgCgojIyMgSW5jbHVkZSBwLXZhbHVlIGVzdGltYXRpb25zCgpUcnkgcHV0dGluZyBzb21lIGluZm9ybWF0aW9uIG9mIHRoZSBwLXZhbHVlcyB3aXRoIHRoZSBjb21wYXJhdGl2ZSBsb2cyZmMKCmBgYHtyIGwyZnNfcHZhbHMxfQpsZmNfYl9zIDwtIGhzX21hY3Jfc3ZhX2JhdGNoWywgYygibG9nRkMueCIsICJsb2dGQy55IiwgIlAuVmFsdWUueCIsICJQLlZhbHVlLnkiKV0KY29sbmFtZXMobGZjX2JfcykgPC0gYygibDJmY3N2YSIsICJsMmZjYmF0Y2giLCAicHN2YSIsICJwYmF0Y2giKQpoc19tYWNyX2xmY19iX3Mkc2NhdHRlcgpjdXRvZmYgPC0gMC4xCmxmY19iX3Mkc3RhdGUgPC0gaWZlbHNlKGxmY19iX3MkcHN2YSA+IGN1dG9mZiAmIGxmY19iX3MkcGJhdGNoID4gY3V0b2ZmLCAiYm90aGluc2lnIiwKICAgICAgICAgICAgICAgICBpZmVsc2UobGZjX2JfcyRwc3ZhIDw9IGN1dG9mZiAmIGxmY19iX3MkcGJhdGNoIDw9IGN1dG9mZiwgImJvdGhzaWciLAogICAgICAgICAgICAgICAgIGlmZWxzZShsZmNfYl9zJHBzdmEgPD0gY3V0b2ZmLCAic3Zhc2lnIiwgImJhdGNoc2lnIikpKQojI2xmY3BfYl9zJGxmY3N0YXRlIDwtIGlmZWxzZShsZmNwX2JfcyRsMmZjc3ZhID49IDAuNzUgJiBsZmNwX2JfcyRsMmZjYmF0Y2gsICIiLCAiIikKbnVtX2JvdGhpbnNpZyA8LSBzdW0obGZjX2JfcyRzdGF0ZSA9PSAiYm90aGluc2lnIikKbnVtX2JvdGhzaWcgPC0gc3VtKGxmY19iX3Mkc3RhdGUgPT0gImJvdGhzaWciKQpudW1fc3Zhc2lnIDwtIHN1bShsZmNfYl9zJHN0YXRlID09ICJzdmFzaWciKQpudW1fYmF0Y2hzaWcgPC0gc3VtKGxmY19iX3Mkc3RhdGUgPT0gImJhdGNoc2lnIikKCmxpYnJhcnkoZ2dwbG90MikKYWVzX2NvbG9yID0gIihsMmZjc3ZhID49IDAuNzUgfCBsMmZjc3ZhIDw9IC0wLjc1IHwgbDJmY2JhdGNoID49IDAuNzUgfCBsMmZjYmF0Y2ggPD0gLTAuNzUpIgpwbHQgPC0gZ2dwbG90Mjo6Z2dwbG90KGxmY19iX3MsIGFlc19zdHJpbmcoeD0ibDJmY3N2YSIsIHk9ImwyZmNiYXRjaCIpKSArCiAgICAjIyBnZ3Bsb3QyOjpnZW9tX3BvaW50KHN0YXQ9ImlkZW50aXR5Iiwgc2l6ZT0yLCBhbHBoYT0wLjIsIGFlc19zdHJpbmcoc2hhcGU9ImFzLmZhY3RvcihhZXNfY29sb3IpIiwgY29sb3VyPSJhcy5mYWN0b3Ioc3RhdGUpIiwgZmlsbD0iYXMuZmFjdG9yKHN0YXRlKSIpKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2FibGluZShjb2xvdXI9ImJsdWUiLCBzbG9wZT0xLCBpbnRlcmNlcHQ9MCwgc2l6ZT0wLjUpICsKICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdD1jKC0wLjc1LCAwLjc1KSwgY29sb3I9InJlZCIsIHNpemU9MC41KSArCiAgICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YygtMC43NSwgMC43NSksIGNvbG9yPSJyZWQiLCBzaXplPTAuNSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIHNpemU9MiwgYWxwaGE9MC4yLCBhZXNfc3RyaW5nKGNvbG91cj0iYXMuZmFjdG9yKHN0YXRlKSIsIGZpbGw9ImFzLmZhY3RvcihzdGF0ZSkiKSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKG5hbWU9InN0YXRlIiwgdmFsdWVzPWMoImJvdGhpbnNpZyI9ImdyZXkiLCAiYm90aHNpZyI9ImZvcmVzdGdyZWVuIiwgInN2YXNpZyI9ImRhcmtyZWQiLCAiYmF0Y2hzaWciPSJkYXJrYmx1ZSIpKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbChuYW1lPSJzdGF0ZSIsIHZhbHVlcz1jKCJib3RoaW5zaWciPSJncmV5IiwgImJvdGhzaWciPSJmb3Jlc3RncmVlbiIsICJzdmFzaWciPSJkYXJrcmVkIiwgImJhdGNoc2lnIj0iZGFya2JsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiQm90aCBJblNpZy46ICIsIG51bV9ib3RoaW5zaWcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiQm90aCBTaWcuOiAiLCBudW1fYm90aHNpZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJTdmEgU2lnLjogIiwgbnVtX3N2YXNpZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJCYXRjaCBTaWcuOiAiLCBudW1fYmF0Y2hzaWcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlPWdncGxvdDI6Omd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXM9YWVzKHNpemU9MywgZmlsbD0iZ3JleSIpKSkgKwogICAgZ2dwbG90Mjo6Z3VpZGVzKGZpbGw9Z2dwbG90Mjo6Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcz1saXN0KHNpemU9MykpKSArCiAgICBnZ3Bsb3QyOjp0aGVtZV9idygpCnBsdApgYGAKCiMjIENvbXBhcmUgcnV2cmVzaWQgdG8gYmF0Y2ggaW4gbW9kZWwsIERFU2VxCgpgYGB7ciBiYXRjaF9ydXZyZXNpZF9kZXNlcTF9CmhzX21hY3JfYmF0Y2hfcnV2cmVzaWRfZGVzZXEgPC0gbWVyZ2UoCiAgaHNfbWFjcl9ydXZyZXMkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgaHNfbWFjcl9iYXRjaCRiYXNpYyRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoaHNfbWFjcl9iYXRjaF9ydXZyZXNpZF9kZXNlcSkgPC0gaHNfbWFjcl9iYXRjaF9ydXZyZXNpZF9kZXNlcVtbIlJvdy5uYW1lcyJdXQpoc19tYWNyX2JhdGNoX3J1dnJlc2lkX2xvZ2ZjIDwtIGhzX21hY3JfYmF0Y2hfcnV2cmVzaWRfZGVzZXFbLCBjKCJsb2dGQy54IiwibG9nRkMueSIpXQpjb2xuYW1lcyhoc19tYWNyX2JhdGNoX3J1dnJlc2lkX2xvZ2ZjKSA8LSBjKCJub2JhdGNoIiwiYmFzaWMiKQpsZmNfcnV2X2JhdCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGhzX21hY3JfYmF0Y2hfcnV2cmVzaWRfbG9nZmMsIHByZXR0eV9jb2xvcnM9RkFMU0UpCmxmY19ydXZfYmF0JHNjYXR0ZXIKbGZjX3J1dl9iYXQkY29ycmVsYXRpb24KYGBgCgojIyBDb21wYXJlIG5vIGJhdGNoIHRvIGJhdGNoIGluIG1vZGVsLCBsaW1tYQoKYGBge3IgY29tcGFyZV9iYXRjaF9ub2JhdGNoX2xpbW1hMX0KaHNfbWFjcl9ub2JhdGNoX2JhdGNoIDwtIG1lcmdlKAogIGhzX21hY3Jfbm9iYXRjaCRsaW1tYSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBoc19tYWNyX2JhdGNoJGxpbW1hJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGJ5PSJyb3cubmFtZXMiKQpyb3duYW1lcyhoc19tYWNyX25vYmF0Y2hfYmF0Y2gpIDwtIGhzX21hY3Jfbm9iYXRjaF9iYXRjaFtbIlJvdy5uYW1lcyJdXQpoc19tYWNyX25vYmF0Y2hfYmF0Y2ggPC0gaHNfbWFjcl9ub2JhdGNoX2JhdGNoWywgYygibG9nRkMueCIsImxvZ0ZDLnkiKV0KY29sbmFtZXMoaHNfbWFjcl9ub2JhdGNoX2JhdGNoKSA8LSBjKCJub2JhdGNoIiwiYmF0Y2giKQpuYl9iIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoaHNfbWFjcl9ub2JhdGNoX2JhdGNoLCBwcmV0dHlfY29sb3JzPUZBTFNFKQpuYl9iJHNjYXR0ZXIKbmJfYiRjb3JyZWxhdGlvbgpgYGAKCiMjIEJhdGNoIGluIG1vZGVsIHZzLiBTVkEsIGxpbW1hCgpgYGB7ciBjb21wYXJlX2JhdGNoX3N2YV9saW1tYTF9CmhzX21hY3JfYmF0Y2hfc3ZhIDwtIG1lcmdlKAogIGhzX21hY3JfYmF0Y2gkbGltbWEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgaHNfbWFjcl9zdmEkbGltbWEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGhzX21hY3JfYmF0Y2hfc3ZhKSA8LSBoc19tYWNyX2JhdGNoX3N2YVtbIlJvdy5uYW1lcyJdXQpoc19tYWNyX2JhdGNoX3N2YSA8LSBoc19tYWNyX2JhdGNoX3N2YVssIGMoImxvZ0ZDLngiLCJsb2dGQy55IildCmNvbG5hbWVzKGhzX21hY3JfYmF0Y2hfc3ZhKSA8LSBjKCJiYXRjaCIsInN2YSIpCmJfcyA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGhzX21hY3JfYmF0Y2hfc3ZhLCBwcmV0dHlfY29sb3JzPUZBTFNFKQpiX3Mkc2NhdHRlcgpiX3MkY29ycmVsYXRpb24KYGBgCgojIyBOb2JhdGNoIHZzLiBiYXRjaCBpbiBtb2RlbCwgZWRnZXIKCmBgYHtyIGNvbXBhcmVfbm9iYXRjaF9iYXRjaF9lZGdlcjF9CmhzX21hY3Jfbm9iYXRjaF9iYXRjaCA8LSBtZXJnZSgKICBoc19tYWNyX25vYmF0Y2gkZWRnZXIkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgaHNfbWFjcl9iYXRjaCRlZGdlciRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoaHNfbWFjcl9ub2JhdGNoX2JhdGNoKSA8LSBoc19tYWNyX25vYmF0Y2hfYmF0Y2hbWyJSb3cubmFtZXMiXV0KaHNfbWFjcl9ub2JhdGNoX2JhdGNoIDwtIGhzX21hY3Jfbm9iYXRjaF9iYXRjaFssIGMoImxvZ0ZDLngiLCJsb2dGQy55IildCmNvbG5hbWVzKGhzX21hY3Jfbm9iYXRjaF9iYXRjaCkgPC0gYygibm9iYXRjaCIsImJhdGNoIikKbmJfYiA8LSBzbShwbG90X2xpbmVhcl9zY2F0dGVyKGhzX21hY3Jfbm9iYXRjaF9iYXRjaCwgcHJldHR5X2NvbG9ycz1GQUxTRSkpCm5iX2Ikc2NhdHRlcgpuYl9iJGNvcnJlbGF0aW9uCmBgYAoKIyMgQmF0Y2ggaW4gbW9kZWwgdnMuIFNWQSwgZWRnZXIKCmBgYHtyIGNvbXBhcmVfYmF0Y2hfc3ZhX2VkZ2VyMX0KaHNfbWFjcl9iYXRjaF9zdmEgPC0gbWVyZ2UoCiAgaHNfbWFjcl9iYXRjaCRlZGdlciRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBoc19tYWNyX3N2YSRlZGdlciRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoaHNfbWFjcl9iYXRjaF9zdmEpIDwtIGhzX21hY3JfYmF0Y2hfc3ZhW1siUm93Lm5hbWVzIl1dCmhzX21hY3JfYmF0Y2hfc3ZhIDwtIGhzX21hY3JfYmF0Y2hfc3ZhWywgYygibG9nRkMueCIsImxvZ0ZDLnkiKV0KY29sbmFtZXMoaHNfbWFjcl9iYXRjaF9zdmEpIDwtIGMoImJhdGNoIiwic3ZhIikKYl9zIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoaHNfbWFjcl9iYXRjaF9zdmEsIHByZXR0eV9jb2xvcnM9RkFMU0UpCmJfcyRzY2F0dGVyCmJfcyRjb3JyZWxhdGlvbgpgYGAKCiMjIENvbXBhcmUgbm9iYXRjaCB2cy4gYmF0Y2gsIGRlc2VxCgpgYGB7ciBjb21wYXJlX25vYmF0Y2hfYmF0Y2hfZGVzZXExfQpoc19tYWNyX25vYmF0Y2hfYmF0Y2ggPC0gbWVyZ2UoCiAgaHNfbWFjcl9ub2JhdGNoJGRlc2VxJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGhzX21hY3JfYmF0Y2gkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGhzX21hY3Jfbm9iYXRjaF9iYXRjaCkgPC0gaHNfbWFjcl9ub2JhdGNoX2JhdGNoW1siUm93Lm5hbWVzIl1dCmhzX21hY3Jfbm9iYXRjaF9iYXRjaCA8LSBoc19tYWNyX25vYmF0Y2hfYmF0Y2hbLCBjKCJsb2dGQy54IiwibG9nRkMueSIpXQpjb2xuYW1lcyhoc19tYWNyX25vYmF0Y2hfYmF0Y2gpIDwtIGMoIm5vYmF0Y2giLCJiYXRjaCIpCm5iX2IgPC0gc20ocGxvdF9saW5lYXJfc2NhdHRlcihoc19tYWNyX25vYmF0Y2hfYmF0Y2gsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpuYl9iJHNjYXR0ZXIKbmJfYiRjb3JyZWxhdGlvbgpgYGAKCiMjIENvbXBhcmUgYmF0Y2ggdnMuIFNWQSwgZGVzZXEKCmBgYHtyIGNvbXBhcmVfYmF0Y2hfc3ZhX2Rlc2VxMX0KaHNfbWFjcl9iYXRjaF9zdmEgPC0gbWVyZ2UoCiAgaHNfbWFjcl9iYXRjaCRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBoc19tYWNyX3N2YSRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoaHNfbWFjcl9iYXRjaF9zdmEpIDwtIGhzX21hY3JfYmF0Y2hfc3ZhW1siUm93Lm5hbWVzIl1dCmhzX21hY3JfYmF0Y2hfc3ZhIDwtIGhzX21hY3JfYmF0Y2hfc3ZhWywgYygibG9nRkMueCIsICJsb2dGQy55IildCmNvbG5hbWVzKGhzX21hY3JfYmF0Y2hfc3ZhKSA8LSBjKCJiYXRjaCIsICJzdmEiKQpiX3MgPC0gc20ocGxvdF9saW5lYXJfc2NhdHRlcihoc19tYWNyX2JhdGNoX3N2YSwgcHJldHR5X2NvbG9ycz1GQUxTRSkpCmJfcyRzY2F0dGVyCmJfcyRjb3JyZWxhdGlvbgpgYGAKCiMgUmVwZWF0IHVzaW5nIHRoZSBwYXJhc2l0ZSBkYXRhCgpJbiAnbWFjcm9waGFnZV9lc3RpbWF0aW9uJywgd2UgZGlkIGEgc2VyaWVzIG9mIGFuYWx5c2VzIHRvIHRyeSB0byBwaWNrIG91dCBzb21lIG9mIHRoZSBzdXJyb2dhdGUKdmFyaWFibGVzIGluIHRoZSBkYXRhLiAgTm93IHdlIHdpbGwgcGVyZm9ybSBhIHNldCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNlcyB1c2luZyB0aGUKcmVzdWx0cyBmcm9tIHRoYXQuICBTaW5jZSB0aGUgJ2JhdGNoJyBlbGVtZW50IG9mIHRoZSBkYXRhIGlzIHJlYXNvbmFibHkgd2VsbCBleHBsYWluZWQsIHdlIHdpbGwgbm90CmFidXNlIHRoZSBkYXRhIHdpdGggc3ZhL2NvbWJhdCwgYnV0IGluc3RlYWQgaW5jbHVkZSBiYXRjaCBpbiB0aGUgZXhwZXJpbWVudGFsIG1vZGVsLgoKSXQgYXBwZWFycyB0aGF0IGl0IGlzIHBvc3NpYmxlIHRob3VnaCBzb21ld2hhdCBkaWZmaWN1bHQgdG8gYXBwbHkgYmF0Y2ggZXN0aW1hdGlvbnMgZ2VuZXJhdGVkIGJ5IHN2YQp0byB0aGUgbW9kZWwgZ2l2ZW4gdG8gREVTZXEvRWRnZVIvbGltbWEuICBJbiB0aGUgY2FzZSBvZiBsaW1tYSBpdCBpcyBmYWlybHkgc2ltcGxlLCBidXQgaW4gdGhlIG90aGVyCnR3byBpdCBpcyBhIGJpdCBtb3JlIGRpZmZpY3VsdC4gIFRoZXJlIGlzIGEgbmljZSBkaXNjdXNzaW9uIG9mIHRoaXMgYXQ6IGh0dHBzOi8vd3d3LmJpb3N0YXJzLm9yZy9wLzE1NjE4Ni8KSSBhbSBhdHRlbXB0aW5nIHRvIGFwcGx5IHRoYXQgbG9naWMgdG8gdGhpcyBkYXRhIHdpdGggbGltaXRlZCBzdWNjZXNzLgoKYGBge3Igc2V0dXBfZGUsIGZpZy5zaG93PSJoaWRlIn0KbHBfY29udHJhc3RzIDwtIGxpc3QoCiAgICAibWFjcm9fY2hyLXNoIiA9IGMoImNociIsICJzaCIpKQpscF9tYWNyX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobHBfbWFjciwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IikpCmxwX21hY3JfY29tYmF0X25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobHBfbWFjciwgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dfdG9femVybz1UUlVFLCBiYXRjaD0iY29tYmF0IikpCmxwX21hY3JfbG93ZmlsdCA8LSBzbShub3JtYWxpemVfZXhwdChscF9tYWNyLCBmaWx0ZXI9VFJVRSkpCiMjIFNldCB1cCB0aGUgZGF0YSB1c2VkIGluIHRoZSAzIGNvbXBhcmF0aXZlIGNvbnRyYXN0IHNldHMuCmBgYAoKIyMgTm8gYmF0Y2ggaW4gdGhlIG1vZGVsCgpgYGB7ciBtYWNyb19ub2JhdGNoLCBmaWcuc2hvdz0iaGlkZSJ9CmxwX21hY3Jfbm9iYXRjaCA8LSBzbShhbGxfcGFpcndpc2UobHBfbWFjcl9sb3dmaWx0LCBsaW1tYV9tZXRob2Q9InJvYnVzdCIsIG1vZGVsX2JhdGNoPUZBTFNFKSkKIyMgd293LCBhbGwgdG9vbHMgaW5jbHVkaW5nIGJhc2ljIGFncmVlIGFsbW9zdCBjb21wbGV0ZWx5Cm1lZGlhbnNfYnlfY29uZGl0aW9uIDwtIGxwX21hY3Jfbm9iYXRjaCRiYXNpYyRtZWRpYW5zCmxwX21hY3Jfbm9iYXRjaF90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgbHBfbWFjcl9ub2JhdGNoLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvbHBfbWFjcl9ub2JhdGNoLXYiLCB2ZXIsICIueGxzeCIpLAogIGtlZXBlcnM9bHBfY29udHJhc3RzLAogIGV4dHJhX2Fubm90PW1lZGlhbnNfYnlfY29uZGl0aW9uKSkKbHBfbWFjcl9ub2JhdGNoX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGxwX21hY3Jfbm9iYXRjaF90YWJsZXMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9scF9tYWNyX25vYmF0Y2hfc2lnbmlmaWNhbnQtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIEJhdGNoIGluIHRoZSBtb2RlbAoKSW4gdGhpcyAgYXR0ZW1wdCwgd2UgYWRkIGEgYmF0Y2ggZmFjdG9yIGluIHRoZSBleHBlcmltZW50YWwgbW9kZWwgYW5kIHNlZSBob3cgaXQgZG9lcy4KCmBgYHtyIG1hY3JvX2JhdGNoLCBmaWcuc2hvdz0iaGlkZSJ9CiMjIEhlcmUganVzdCBsZXQgYWxsX3BhaXJ3aXNlIHJ1biBvbiBmaWx0ZXJlZCBkYXRhIGFuZCBkbyBpdHMgbm9ybWFsIH4gMCArIGNvbmRpdGlvbiArIGJhdGNoIGFuYWx5c2VzCmxwX21hY3JfYmF0Y2ggPC0gc20oYWxsX3BhaXJ3aXNlKGxwX21hY3JfbG93ZmlsdCwgbGltbWFfbWV0aG9kPSJyb2J1c3QiKSkKbWVkaWFuc19ieV9jb25kaXRpb24gPC0gbHBfbWFjcl9iYXRjaCRiYXNpYyRtZWRpYW5zCmxwX21hY3JfYmF0Y2hfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGxwX21hY3JfYmF0Y2gsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9scF9tYWNyX2JhdGNobW9kZWwtdiIsIHZlciwgIi54bHN4IiksCiAga2VlcGVycz1scF9jb250cmFzdHMsCiAgZXh0cmFfYW5ub3Q9bWVkaWFuc19ieV9jb25kaXRpb24pKQpscF9tYWNyX2JhdGNoX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGxwX21hY3JfYmF0Y2hfdGFibGVzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvbHBfbWFjcl9iYXRjaG1vZGVsX3NpZ25pZmljYW50LXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBCYXRjaCBlc3RpbWF0ZWQgd2l0aCBTVkEKCmBgYHtyIG1hY3JvX3N2YSwgZmlnLnNob3c9ImhpZGUifQojIyBIZXJlIGp1c3QgbGV0IGFsbF9wYWlyd2lzZSBydW4gb24gZmlsdGVyZWQgZGF0YSBhbmQgZG8gaXRzIG5vcm1hbCB+IDAgKyBjb25kaXRpb24gKyBiYXRjaCBhbmFseXNlcwpscF9tYWNyX3N2YSA8LSBzbShhbGxfcGFpcndpc2UobHBfbWFjcl9sb3dmaWx0LCBsaW1tYV9tZXRob2Q9InJvYnVzdCIsIG1vZGVsX2JhdGNoPSJzdmEiKSkKbWVkaWFuc19ieV9jb25kaXRpb24gPC0gbHBfbWFjcl9zdmEkYmFzaWMkbWVkaWFucwpscF9tYWNyX3N2YV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgbHBfbWFjcl9zdmEsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9scF9tYWNyX3N2YS12IiwgdmVyLCAiLnhsc3giKSwKICBrZWVwZXJzPWxwX2NvbnRyYXN0cywKICBleHRyYV9hbm5vdD1tZWRpYW5zX2J5X2NvbmRpdGlvbikpCmxwX21hY3Jfc3ZhX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGxwX21hY3Jfc3ZhX3RhYmxlcywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL2xwX21hY3Jfc3ZhX3NpZ25pZmljYW50LXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIEZpZ3VyZSBvdXQgaG93IHRvIGNvbXBhcmUgdGhlc2UgcmVzdWx0cwoKSSBoYXZlIDQgbWV0aG9kcyBvZiBwZXJmb3JtaW5nIHRoaXMgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuICBFYWNoIG9uZSBjb21lcyB3aXRoIGEgc2V0IG9mCm1ldHJpY3MgZGVmaW5pbmcgJ3NpZ25pZmljYW50Jy4gIFBlcmhhcHMgSSBjYW4gbWFrZSBhIHRhYmxlIG9mIHRoZSAjIG9mIGdlbmVzIGRlZmluZWQgYXMgc2lnbmlmaWNhbnQKYnkgY29udHJhc3QgZm9yIGVhY2guICBJbiBhZGRpdGlvbiBpdCBtYXkgYmUgd29ydGggd2hpbGUgdG8gZG8gYSBzY2F0dGVyIHBsb3RzIG9mIHRoZSBsb2dGQ3MgYmV0d2Vlbgp0aGVzZSBjb21wYXJpc29ucyBhbmQgc2VlIGhvdyB3ZWxsIHRoZXkgYWdyZWU/CgojIyBDb21wYXJlIERlU2VxIC8gQmFzaWMgd2l0aG91dCBiYXRjaCBpbiBtb2RlbAoKYGBge3IgYmFzaWNfZGVzZXFfbm9iYXRjaH0KbHBfbWFjcl9ub2JhdGNoX2Jhc2ljIDwtIG1lcmdlKAogIGxwX21hY3Jfbm9iYXRjaCRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBscF9tYWNyX2JhdGNoJGJhc2ljJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGJ5PSJyb3cubmFtZXMiKQpyb3duYW1lcyhscF9tYWNyX25vYmF0Y2hfYmFzaWMpIDwtIGxwX21hY3Jfbm9iYXRjaF9iYXNpY1tbIlJvdy5uYW1lcyJdXQpscF9tYWNyX25vYmF0Y2hfbG9nZmMgPC0gbHBfbWFjcl9ub2JhdGNoX2Jhc2ljWywgYygibG9nRkMueCIsICJsb2dGQy55IildCmNvbG5hbWVzKGxwX21hY3Jfbm9iYXRjaF9sb2dmYykgPC0gYygibm9iYXRjaCIsImJhc2ljIikKbGZjX25iX2IgPC0gc20ocGxvdF9saW5lYXJfc2NhdHRlcihscF9tYWNyX25vYmF0Y2hfbG9nZmMsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpsZmNfbmJfYiRzY2F0dGVyCmxmY19uYl9iJGNvcnJlbGF0aW9uCgpscF9tYWNyX25vYmF0Y2hfcCA8LSBscF9tYWNyX25vYmF0Y2hfYmFzaWNbLCBjKCJQLlZhbHVlIiwicCIpXQpscF9tYWNyX25vYmF0Y2hfcFtbMl1dIDwtIGFzLm51bWVyaWMobHBfbWFjcl9ub2JhdGNoX3BbWzJdXSkKY29sbmFtZXMobHBfbWFjcl9ub2JhdGNoX3ApIDwtIGMoIm5vYmF0Y2giLCJiYXNpYyIpCmxwX21hY3Jfbm9iYXRjaF9wIDwtIC0xICogbG9nKGxwX21hY3Jfbm9iYXRjaF9wKQpwX25iX2IgPC0gc20ocGxvdF9saW5lYXJfc2NhdHRlcihscF9tYWNyX25vYmF0Y2hfcCwgcHJldHR5X2NvbG9ycz1GQUxTRSkpCnBfbmJfYiRzY2F0dGVyCnBfbmJfYiRjb3JyZWxhdGlvbgpgYGAKCiMjIENvbXBhcmUgU1ZBIHRvIGJhdGNoIGluIG1vZGVsLCBERVNlcQoKYGBge3IgZGVzZXFfc3ZhX2JhdGNofQpscF9tYWNyX3N2YV9iYXRjaCA8LSBtZXJnZSgKICBscF9tYWNyX3N2YSRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBscF9tYWNyX2JhdGNoJGRlc2VxJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGJ5PSJyb3cubmFtZXMiKQpyb3duYW1lcyhscF9tYWNyX3N2YV9iYXRjaCkgPC0gbHBfbWFjcl9zdmFfYmF0Y2hbWyJSb3cubmFtZXMiXV0KbHBfbWFjcl9zdmFfbG9nZmMgPC0gbHBfbWFjcl9zdmFfYmF0Y2hbLCBjKCJsb2dGQy54IiwibG9nRkMueSIpXQpjb2xuYW1lcyhscF9tYWNyX3N2YV9sb2dmYykgPC0gYygic3ZhIiwiYmF0Y2giKQpsZmNfYl9zIDwtIHNtKHBsb3RfbGluZWFyX3NjYXR0ZXIobHBfbWFjcl9zdmFfbG9nZmMsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpsZmNfYl9zJHNjYXR0ZXIKbGZjX2JfcyRjb3JyZWxhdGlvbgoKbHBfbWFjcl9zdmFfcCA8LSBscF9tYWNyX3N2YV9iYXRjaFssIGMoIlAuVmFsdWUueCIsIlAuVmFsdWUueSIpXQpscF9tYWNyX3N2YV9wW1syXV0gPC0gYXMubnVtZXJpYyhscF9tYWNyX3N2YV9wW1syXV0pCmNvbG5hbWVzKGxwX21hY3Jfc3ZhX3ApIDwtIGMoInN2YSIsImJhdGNoIikKbHBfbWFjcl9zdmFfcCA8LSAtMSAqIGxvZyhscF9tYWNyX3N2YV9wKQpwX2JfcyA8LSBzbShwbG90X2xpbmVhcl9zY2F0dGVyKGxwX21hY3Jfc3ZhX3AsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpwX2JfcyRzY2F0dGVyCnBfYl9zJGNvcnJlbGF0aW9uCmBgYAoKIyMjIEluY2x1ZGUgcC12YWx1ZSBlc3RpbWF0aW9ucwoKVHJ5IHB1dHRpbmcgc29tZSBpbmZvcm1hdGlvbiBvZiB0aGUgcC12YWx1ZXMgd2l0aCB0aGUgY29tcGFyYXRpdmUgbG9nMmZjCgpgYGB7ciBsMmZzX3B2YWxzfQpsZmNwX2JfcyA8LSBscF9tYWNyX3N2YV9iYXRjaFssIGMoImxvZ0ZDLngiLCAibG9nRkMueSIsICJQLlZhbHVlLngiLCAiUC5WYWx1ZS55IildCmNvbG5hbWVzKGxmY3BfYl9zKSA8LSBjKCJsMmZjc3ZhIiwgImwyZmNiYXRjaCIsICJwc3ZhIiwgInBiYXRjaCIpCmxmY19iX3Mkc2NhdHRlcgpjdXRvZmYgPC0gMC4xCmxmY3BfYl9zJHN0YXRlIDwtIGlmZWxzZShsZmNwX2JfcyRwc3ZhID4gY3V0b2ZmICYgbGZjcF9iX3MkcGJhdGNoID4gY3V0b2ZmLCAiYm90aGluc2lnIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGxmY3BfYl9zJHBzdmEgPD0gY3V0b2ZmICYgbGZjcF9iX3MkcGJhdGNoIDw9IGN1dG9mZiwgImJvdGhzaWciLAogICAgICAgICAgICAgICAgICBpZmVsc2UobGZjcF9iX3MkcHN2YSA8PSBjdXRvZmYsICJzdmFzaWciLCAiYmF0Y2hzaWciKSkpCiMjbGZjcF9iX3MkbGZjc3RhdGUgPC0gaWZlbHNlKGxmY3BfYl9zJGwyZmNzdmEgPj0gMC43NSAmIGxmY3BfYl9zJGwyZmNiYXRjaCwgIiIsICIiKQpudW1fYm90aGluc2lnIDwtIHN1bShsZmNwX2JfcyRzdGF0ZSA9PSAiYm90aGluc2lnIikKbnVtX2JvdGhzaWcgPC0gc3VtKGxmY3BfYl9zJHN0YXRlID09ICJib3Roc2lnIikKbnVtX3N2YXNpZyA8LSBzdW0obGZjcF9iX3Mkc3RhdGUgPT0gInN2YXNpZyIpCm51bV9iYXRjaHNpZyA8LSBzdW0obGZjcF9iX3Mkc3RhdGUgPT0gImJhdGNoc2lnIikKCmxpYnJhcnkoZ2dwbG90MikKYWVzX2NvbG9yID0gIihsMmZjc3ZhID49IDAuNzUgfCBsMmZjc3ZhIDw9IC0wLjc1IHwgbDJmY2JhdGNoID49IDAuNzUgfCBsMmZjYmF0Y2ggPD0gLTAuNzUpIgpwbHQgPC0gZ2dwbG90Mjo6Z2dwbG90KGxmY3BfYl9zLCBhZXNfc3RyaW5nKHg9ImwyZmNzdmEiLCB5PSJsMmZjYmF0Y2giKSkgKwogICAgIyMgZ2dwbG90Mjo6Z2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIHNpemU9MiwgYWxwaGE9MC4yLCBhZXNfc3RyaW5nKHNoYXBlPSJhcy5mYWN0b3IoYWVzX2NvbG9yKSIsIGNvbG91cj0iYXMuZmFjdG9yKHN0YXRlKSIsIGZpbGw9ImFzLmZhY3RvcihzdGF0ZSkiKSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9hYmxpbmUoY29sb3VyPSJibHVlIiwgc2xvcGU9MSwgaW50ZXJjZXB0PTAsIHNpemU9MC41KSArCiAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9YygtMC43NSwgMC43NSksIGNvbG9yPSJyZWQiLCBzaXplPTAuNSkgKwogICAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0PWMoLTAuNzUsIDAuNzUpLCBjb2xvcj0icmVkIiwgc2l6ZT0wLjUpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoc3RhdD0iaWRlbnRpdHkiLCBzaXplPTIsIGFscGhhPTAuMiwgYWVzX3N0cmluZyhjb2xvdXI9ImFzLmZhY3RvcihzdGF0ZSkiLCBmaWxsPSJhcy5mYWN0b3Ioc3RhdGUpIikpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJzdGF0ZSIsIHZhbHVlcz1jKCJib3RoaW5zaWciPSJncmV5IiwgImJvdGhzaWciPSJmb3Jlc3RncmVlbiIsICJzdmFzaWciPSJkYXJrcmVkIiwgImJhdGNoc2lnIj0iZGFya2JsdWUiKSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwobmFtZT0ic3RhdGUiLCB2YWx1ZXM9YygiYm90aGluc2lnIj0iZ3JleSIsICJib3Roc2lnIj0iZm9yZXN0Z3JlZW4iLCAic3Zhc2lnIj0iZGFya3JlZCIsICJiYXRjaHNpZyI9ImRhcmtibHVlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIkJvdGggSW5TaWcuOiAiLCBudW1fYm90aGluc2lnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIkJvdGggU2lnLjogIiwgbnVtX2JvdGhzaWcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiU3ZhIFNpZy46ICIsIG51bV9zdmFzaWcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiQmF0Y2ggU2lnLjogIiwgbnVtX2JhdGNoc2lnKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZT1nZ3Bsb3QyOjpndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzPWFlcyhzaXplPTMsIGZpbGw9ImdyZXkiKSkpICsKICAgIGdncGxvdDI6Omd1aWRlcyhmaWxsPWdncGxvdDI6Omd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXM9bGlzdChzaXplPTMpKSkgKwogICAgZ2dwbG90Mjo6dGhlbWVfYncoKQpwbHQKYGBgCgojIyBDb21wYXJlIG5vIGJhdGNoIHRvIGJhdGNoIGluIG1vZGVsLCBsaW1tYQoKYGBge3IgY29tcGFyZV9iYXRjaF9ub2JhdGNoX2xpbW1hfQpscF9tYWNyX25vYmF0Y2hfYmF0Y2ggPC0gbWVyZ2UoCiAgbHBfbWFjcl9ub2JhdGNoJGxpbW1hJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGxwX21hY3JfYmF0Y2gkbGltbWEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGxwX21hY3Jfbm9iYXRjaF9iYXRjaCkgPC0gbHBfbWFjcl9ub2JhdGNoX2JhdGNoW1siUm93Lm5hbWVzIl1dCmxwX21hY3Jfbm9iYXRjaF9iYXRjaCA8LSBscF9tYWNyX25vYmF0Y2hfYmF0Y2hbLCBjKCJsb2dGQy54IiwibG9nRkMueSIpXQpjb2xuYW1lcyhscF9tYWNyX25vYmF0Y2hfYmF0Y2gpIDwtIGMoIm5vYmF0Y2giLCJiYXRjaCIpCm5iX2IgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihscF9tYWNyX25vYmF0Y2hfYmF0Y2gsIHByZXR0eV9jb2xvcnM9RkFMU0UpCm5iX2Ikc2NhdHRlcgpuYl9iJGNvcnJlbGF0aW9uCmBgYAoKIyMgQmF0Y2ggaW4gbW9kZWwgdnMuIFNWQSwgbGltbWEKCmBgYHtyIGNvbXBhcmVfYmF0Y2hfc3ZhX2xpbW1hMn0KbHBfbWFjcl9iYXRjaF9zdmEgPC0gbWVyZ2UoCiAgbHBfbWFjcl9iYXRjaCRsaW1tYSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBscF9tYWNyX3N2YSRsaW1tYSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMobHBfbWFjcl9iYXRjaF9zdmEpIDwtIGxwX21hY3JfYmF0Y2hfc3ZhW1siUm93Lm5hbWVzIl1dCmxwX21hY3JfYmF0Y2hfc3ZhIDwtIGxwX21hY3JfYmF0Y2hfc3ZhWywgYygibG9nRkMueCIsImxvZ0ZDLnkiKV0KY29sbmFtZXMobHBfbWFjcl9iYXRjaF9zdmEpIDwtIGMoImJhdGNoIiwic3ZhIikKYl9zIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIobHBfbWFjcl9iYXRjaF9zdmEsIHByZXR0eV9jb2xvcnM9RkFMU0UpCmJfcyRzY2F0dGVyCmJfcyRjb3JyZWxhdGlvbgpgYGAKCiMjIE5vYmF0Y2ggdnMuIGJhdGNoIGluIG1vZGVsLCBlZGdlcgoKYGBge3IgY29tcGFyZV9ub2JhdGNoX2JhdGNoX2VkZ2VyfQpscF9tYWNyX25vYmF0Y2hfYmF0Y2ggPC0gbWVyZ2UoCiAgbHBfbWFjcl9ub2JhdGNoJGVkZ2VyJGFsbF90YWJsZXMkc2hfdnNfY2hyLAogIGxwX21hY3JfYmF0Y2gkZWRnZXIkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGxwX21hY3Jfbm9iYXRjaF9iYXRjaCkgPC0gbHBfbWFjcl9ub2JhdGNoX2JhdGNoW1siUm93Lm5hbWVzIl1dCmxwX21hY3Jfbm9iYXRjaF9iYXRjaCA8LSBscF9tYWNyX25vYmF0Y2hfYmF0Y2hbLCBjKCJsb2dGQy54IiwibG9nRkMueSIpXQpjb2xuYW1lcyhscF9tYWNyX25vYmF0Y2hfYmF0Y2gpIDwtIGMoIm5vYmF0Y2giLCJiYXRjaCIpCm5iX2IgPC0gc20ocGxvdF9saW5lYXJfc2NhdHRlcihscF9tYWNyX25vYmF0Y2hfYmF0Y2gsIHByZXR0eV9jb2xvcnM9RkFMU0UpKQpuYl9iJHNjYXR0ZXIKbmJfYiRjb3JyZWxhdGlvbgpgYGAKCiMjIEJhdGNoIGluIG1vZGVsIHZzLiBTVkEsIGVkZ2VyCgpgYGB7ciBjb21wYXJlX2JhdGNoX3N2YV9lZGdlcn0KbHBfbWFjcl9iYXRjaF9zdmEgPC0gbWVyZ2UoCiAgbHBfbWFjcl9iYXRjaCRlZGdlciRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBscF9tYWNyX3N2YSRlZGdlciRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMobHBfbWFjcl9iYXRjaF9zdmEpIDwtIGxwX21hY3JfYmF0Y2hfc3ZhW1siUm93Lm5hbWVzIl1dCmxwX21hY3JfYmF0Y2hfc3ZhIDwtIGxwX21hY3JfYmF0Y2hfc3ZhWywgYygibG9nRkMueCIsImxvZ0ZDLnkiKV0KY29sbmFtZXMobHBfbWFjcl9iYXRjaF9zdmEpIDwtIGMoImJhdGNoIiwic3ZhIikKYl9zIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIobHBfbWFjcl9iYXRjaF9zdmEsIHByZXR0eV9jb2xvcnM9RkFMU0UpCmJfcyRzY2F0dGVyCmJfcyRjb3JyZWxhdGlvbgpgYGAKCiMjIENvbXBhcmUgbm9iYXRjaCB2cy4gYmF0Y2gsIGRlc2VxCgpgYGB7ciBjb21wYXJlX25vYmF0Y2hfYmF0Y2hfZGVzZXF9CmxwX21hY3Jfbm9iYXRjaF9iYXRjaCA8LSBtZXJnZSgKICBscF9tYWNyX25vYmF0Y2gkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgbHBfbWFjcl9iYXRjaCRkZXNlcSRhbGxfdGFibGVzJHNoX3ZzX2NociwKICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMobHBfbWFjcl9ub2JhdGNoX2JhdGNoKSA8LSBscF9tYWNyX25vYmF0Y2hfYmF0Y2hbWyJSb3cubmFtZXMiXV0KbHBfbWFjcl9ub2JhdGNoX2JhdGNoIDwtIGxwX21hY3Jfbm9iYXRjaF9iYXRjaFssIGMoImxvZ0ZDLngiLCJsb2dGQy55IildCmNvbG5hbWVzKGxwX21hY3Jfbm9iYXRjaF9iYXRjaCkgPC0gYygibm9iYXRjaCIsImJhdGNoIikKbmJfYiA8LSBzbShwbG90X2xpbmVhcl9zY2F0dGVyKGxwX21hY3Jfbm9iYXRjaF9iYXRjaCwgcHJldHR5X2NvbG9ycz1GQUxTRSkpCm5iX2Ikc2NhdHRlcgpuYl9iJGNvcnJlbGF0aW9uCmBgYAoKIyMgQ29tcGFyZSBiYXRjaCB2cy4gU1ZBLCBkZXNlcQoKYGBge3IgY29tcGFyZV9iYXRjaF9zdmFfZGVzZXF9CmxwX21hY3JfYmF0Y2hfc3ZhIDwtIG1lcmdlKAogIGxwX21hY3JfYmF0Y2gkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgbHBfbWFjcl9zdmEkZGVzZXEkYWxsX3RhYmxlcyRzaF92c19jaHIsCiAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKGxwX21hY3JfYmF0Y2hfc3ZhKSA8LSBscF9tYWNyX2JhdGNoX3N2YVtbIlJvdy5uYW1lcyJdXQpscF9tYWNyX2JhdGNoX3N2YSA8LSBscF9tYWNyX2JhdGNoX3N2YVssIGMoImxvZ0ZDLngiLCJsb2dGQy55IildCmNvbG5hbWVzKGxwX21hY3JfYmF0Y2hfc3ZhKSA8LSBjKCJiYXRjaCIsInN2YSIpCmJfcyA8LSBzbShwbG90X2xpbmVhcl9zY2F0dGVyKGxwX21hY3JfYmF0Y2hfc3ZhLCBwcmV0dHlfY29sb3JzPUZBTFNFKSkKYl9zJHNjYXR0ZXIKYl9zJGNvcnJlbGF0aW9uCmBgYAoKYGBge3Igc2F2ZW1lfQpwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQptZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKdGhpc19zYXZlIDwtIHBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cm1kX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikKbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCB0aGlzX3NhdmUpKQp0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCmBgYAo=