2 Create expressionset

Note that as of 20190124, two samples are still missing: hpgl0914 and hpgl0749. I am rerunning their mapping with salmon now with the assumption that I just missed them previously. I noted their status in the ‘skipped’ column of the online sample sheet.

Note 20190125: hpgl0749 mapped; but hpgl0914 has some weirdness still. It looks like the forward reads have a gzip CRC error, so I used zcat to extract the available data and will then retrim/remap.

Note: 20190210: All samples mapped.

Another note, I am using the ‘state’ column, which was missing the field ‘la_infected’ for the Leishmania amazonensis samples; this resulted in a set of ‘NA’ conditions. I therefore added la_infected to the relevant fields to the sample sheet online and my working sheet.

I also found an error in the time attribution for sample hpgl0461. The time was set to undefined, while in the study it was t24h. That has been changed in both the online and my copy of the sample sheet.

## Reading the sample metadata.
## The sample definitions comprises: 421 rows(samples) and 55 columns(metadata fields).
## Reading count tables.
## Using the transcript to gene mapping.
## Reading salmon data with tximport.
## Finished reading count tables.
## Matched 19629 annotations and counts.
## Bringing together the count matrix and gene information.
## The mapped IDs are not the rownames of your gene information, changing them now.
## Some annotations were lost in merging, setting them to 'undefined'.

3 Extract the mbio data

Now we have a 291 sample data set, but we only want the samples from the human portion of the mBio paper, which Najib helpfully defined in the ‘study’ column of the sample sheet as ‘mBio’.

Thus I will pull those samples from the sample sheet and set the conditions/batches to what I am assuming are reasonable values. An important caveat: we need to concatenate the existing columns: ‘expt_time’ and ‘state’ in order to get useful values for the condition.

In addition, I am removing the L. amazonensis samples for the moment.

## There were 267, now there are 82 samples.
## There were 82, now there are 66 samples.

4 Perform a few metrics

Now make some plots and see if I get similar ones to those observed in the paper.

Here is the link with the PCA plots and such: https://mbio.asm.org/content/7/3/e00027-16/figures-only

Unless I am mistaken, the only things I have to compare against are some fancy PCA plots in the main paper and a few raw-ish ones in the supplemental.

5 Normalize and plot more

5.1 No batch adjust

This first plot makes no attempt to handle the various batch effects in the data.

## Not putting labels on the plot.
## Warning: Removed 1 rows containing missing values (geom_point).
## Error in grid.Call.graphics(C_setviewport, vp, TRUE): non-finite location and/or size for viewport

5.2 limma batch adjust

In this iteration, we use limma’s function to remove batch effect, which I think is what was used in order to make the figure in the paper. This is borne out by the fact that the image generated is nearly identical to the one in the paper.

## This function will replace the expt$expressionset slot with:
## log2(limma(cpm(quant(cbcb(data)))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Step 1: performing count filter with option: cbcb
## Removing 7800 low-count genes (11829 remaining).
## Step 2: normalizing the data with quant.
## Using normalize.quantiles.robust due to a thread error in preprocessCore.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 1572 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with limma.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 47979 entries 0<=x<1.
## batch_counts: Before batch correction, 1572 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 731163 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 1572 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 47979 entries are 0<x<1.
## The be method chose 9 surrogate variable(s).
## batch_counts: Using limma's removeBatchEffect to remove batch effect.
## If you receive a warning: 'NANs produced', one potential reason is that the data was quantile normalized.
## The number of elements which are < 0 after batch correction is: 1815
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE
## Not putting labels on the plot.
## Warning: Removed 1 rows containing missing values (geom_point).
## Error in grid.Call.graphics(C_setviewport, vp, TRUE): non-finite location and/or size for viewport

5.3 svaseq batch adjust

Finally, I employ my favorite method: svaseq(). This squishes the time-based differences in the data and highlights the differences between the various infection states.

## This function will replace the expt$expressionset slot with:
## log2(svaseq(cpm(cbcb(data))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Step 1: performing count filter with option: cbcb
## Removing 7800 low-count genes (11829 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 5634 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with svaseq.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 47040 entries 0<=x<1.
## batch_counts: Before batch correction, 5634 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 728040 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 5634 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 47040 entries are 0<x<1.
## The be method chose 8 surrogate variable(s).
## Attempting svaseq estimation with 8 surrogates.
## The number of elements which are < 0 after batch correction is: 1120
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE
## Not putting labels on the plot.
## Warning: Removed 1 rows containing missing values (geom_point).
## Error in grid.Call.graphics(C_setviewport, vp, TRUE): non-finite location and/or size for viewport

5.4 Bead effect

I do not recall what methods were used to estimate the ‘bead effect’ in the data. Therefore I am copy/pasting the relevant logs from Laura and will then try to recapitulate the tasks performed separately.

I think the makeTab() function is what was used to regenerate the p-values for the bead-adjusted data.

Following the function definition is a representative invocation performed by Laura. (I copy/pasted from her log with minor formatting changes).

## Quantile normalize counts
countsSubQ <- qNorm(counts)
## Specify model
mod = model.matrix(~0+condition+batch)
## Use voom to transform quantile-normalized count data to log2-counts per million, estimate mean-variance relationship
## and use m-v relationship to computer appropriate observational-level weights
v <- voom(countsSubQ, mod)
## Fit a linear model for each gene using the specified design contained in v
fit <- lmFit(v)

makeTab <- function(contrFit, coef1, coef2, ...) {
  ## Compute test statistic
  stat <- pmin(abs(contrFit$t[, coef1]), abs(contrFit$t[, coef2]))
  ## Compute pvalue for stat
  pval <- pmax(contrFit$p.value[, coef1], contrFit$p.value[, coef2])
  ## Adjust pvalue for multiple testing
  adj.pval <- p.adjust(pval, method="BH")
  ## Make the toptable
  tab <- topTable(contrFit, coef=coef1, sort.by="none", ...)
  coef1_name <- colnames(contrFit$coef)[coef1]
  coef2_name <- colnames(contrFit$coef)[coef2]
  new_tab <- data.frame(tab$ID, tab$logFC, contrFit$coef[, coef2], tab$AveExpr,
                        tab$t, contrFit$t[, coef2], stat, pval, adj.pval)
  new_tab <- new_tab[order(-stat), ]

  colnames(new_tab) <- c("ID", paste0("logFC_", coef1_name),
                         paste0("logFC_", coef2_name),
                         "AveExpr",
                         paste0("t_", coef1_name),
                         paste0("t_", coef2_name),
                         "stat",
                         "P.Value",
                         "adj.P.Value")
  new_tab
}

## eBayes finds an F-statistic from the set of t-statistics for that gene
beads24.infLM24.contr.mat <- makeContrasts(uninf_inf=(conditioninfLM24-conditionuninf24),
                                           beads_inf=(conditioninfLM24-conditionbeads24),
                                           levels=v$design)
beads24.infLM24.fit <- contrasts.fit(fit, beads24.infLM24.contr.mat)
beads24.infLM24.eb <- eBayes(beads24.infLM24.fit)

beads24.infLM24.topTab <- makeTab(beads24.infLM24.eb, 1, 2, number=nrow(v$E))

As far as the above goes, it mostly makes sense. My question is, how do we get the modified logFC values? Presumably that is later down in the log.

5.5 makeTab2

Looking further down I found the following invocations, which partially but incompletely answer my question.

## Define makeTab2 function
## construct a DE result table for infection vs. uninfected and beads
## contrFit: the result of eBayes after conrasts.fit
## cellmeansFit: the cell means fit (lmFit(v) above)
## conjContrasts: the 'conjuctive' null test (infection vs. uninf AND infect vs. beads)
## disjContrast: the 'other' test (beads vs. uninf)
makeTab2 <- function(contrFit, cellmeansFit, conjContrasts, disjContrast) {
  ## Get average expression for all relevant terms
  contr_level_counts <- rowSums(contrFit$contrasts[, c(conjContrasts, disjContrast)] != 0)
  ## Define the condition levels involved in the tests
  levels_to_use <- names(contr_level_counts)[contr_level_counts > 0]
  ## Extract the average counts for each, make into table
  ave_expression_mat <- cellmeansFit$coef[, levels_to_use]
  exp_table <- data.frame(ID=rownames(ave_expression_mat))
  exp_table <- cbind(exp_table, as.data.frame(ave_expression_mat))
  names(exp_table)[-1] <- paste(
    "AveExpr", gsub("condition","",levels_to_use),
    sep=":")
  ## Compute test statistic, adjusted pval, and logFC for conjuctive test
  ## Add to table
  stat <- rowMins(abs(contrFit$t[, conjContrasts]))
  pval <- rowMaxs(contrFit$p.value[, conjContrasts])
  adj.pval <- p.adjust(pval, method="BH")
  fcs <- as.data.frame(contrFit$coef[, conjContrasts])
  names(fcs) <- paste("logFC", names(fcs), sep=":")
  conj_pvals <- as.data.frame(apply(contrFit$p.value[, conjContrasts], 2,
                                    p.adjust, method="BH"))
  names(conj_pvals) <- paste("adj.P.Val", names(conj_pvals), sep=":")
  conj_table <- data.frame(ID=rownames(contrFit))
  conj_table <- cbind(conj_table, fcs, conj_pvals, stat=stat, adj.P.Value=adj.pval)
  names(conj_table)[seq(2 + 2 * length(conjContrasts), ncol(conj_table))] <- paste(
    c("stat","adj.P.Value"),
    paste(conjContrasts,collapse=":"),
    sep=":")
  ## Make the table for the 'other' test
  disj_table <- data.frame(ID=rownames(contrFit),
                           logFC=contrFit$coef[, disjContrast],
                           adj.P.Value=p.adjust(contrFit$p.value[, disjContrast], method="BH"))
  names(disj_table)[-1] <- paste(c("logFC", "adj.P.Value"), disjContrast, sep=":")
  ## Combine tables, making sure all tables are in the same order
  stopifnot(all(exp_table$ID == conj_table$ID & exp_table$ID == disj_table$ID))
  out_table <- cbind(exp_table, conj_table[, -1], disj_table[, -1])

  ## order output table by the statistic in the disjunctive test
  o <- order(-stat)
  out_table[o,]
}

infLM4.infLM24.contr.mat <- makeContrasts(uninf_inf=((conditioninfLM24-conditionuninf24)-(conditioninfLM4-conditionuninf4)),
                                          beads_inf=((conditioninfLM24-conditionbeads24)-(conditioninfLM4-conditionbeads4)),
                                          uninf_beads=((conditionbeads24-conditionuninf24)-(conditionbeads4-conditionuninf4)), levels=v$design)
infLM4.infLM24.fit <- contrasts.fit(fit, infLM4.infLM24.contr.mat)
infLM4.infLM24.eb <- eBayes(infLM4.infLM24.fit)

infLM4.infLM24.topTab <- makeTab2(infLM4.infLM24.eb, fit, c("uninf_inf", "beads_inf"),
                                  c("uninf_beads"))

I think that is everything performed. If I understand what I see, then it is doing the following:

  • quantile normalize and filter the count table.
  • perform voom with a condition+batch experimental model.
  • invoke lmFit on the result.
  • set up a set of contrasts which include:
    • uninf_inf = (infected at time y - uninfected at time y) - (infected at time x - uninfected at time x)
    • beads_inf = (infected at time y - beads at time y) - (infected at time x - beads at time x)
    • uninf_beads = (beads at time y - uninfected at time y) - (beads at time x - uninfected at time x)
  • Invoke contrasts.fit and eBayes
  • Invoke the makeTab(2)() function with the eBayes result as arg1, the lmFit result as arg2, and the character list of c(“uninf_inf”, “beads_inf”) as the third arg and finally “uninf_beads” as the final argument. makeTab2() does the following:
    • uses the original fit to extract the average expression values.
    • finds the minimum t statistic and maximum pvalue for each gene from the uninf_inf and beads_inf columns.
    • uses p.adjust on this set of maximized pvalues.
    • pulls the logFC values for each of the uninf_inf and beads_inf columns.
    • does p.adjust on the pvalues of the contrast pvalues.
    • uses cbind on these pieces to make a single table.
    • uses cbind on the expression table, the newly created table (conj) and the disjunct table.
    • orders them according to the t statistic.

I do not see how this set of operations gives us a better picture of the effect of beads during an infection. The primary thing I see in it is the modification of the p-values and the compound contrast of (infy-uninfy)-(infx-uninfx) It seems to me that this is the perfect time for an interaction model?

6 Implementing the contrasts from the paper

With the above in mind, it is pretty trivial for me to perform limma/edger with the same contrasts. I will first invoke my interpretation of the paper contrasts using limma_pairwise() and for the 4 hour data lmajor data.

After rereading the previous implementation, I think I get it. It was in fact using two contrasts: infected/uninfected and infected/beads. It reported the infected/beads result and then took the least significant of the p-value and t statistics of the two contrasts, re-adjusted them, and reported these.

6.1 hpgltools method

## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 7800 low-count genes (11829 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
## Plotting a PCA before surrogates/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

6.2 Compare against a sheet I downloaded from the paper.

I saved the worksheet ‘infLM4_before’ as inline-supplementary-material-5_infLM4_before.csv It is 4 hpi / uninfected, which is happily a contrast I performed.

## Warning: Missing column names filled in: 'X2' [2], 'X3' [3], 'X4' [4],
## 'X5' [5]
## Parsed with column specification:
## cols(
##   `DE genes in L. major-infected human macrophages relative to uninfected controls, 4 hpi, not accounting for phagocytosis` = col_character(),
##   X2 = col_character(),
##   X3 = col_character(),
##   X4 = col_character(),
##   X5 = col_character()
## )
## [1] 5119   52
## Warning: NaNs produced
## 
##  Pearson's product-moment correlation
## 
## data:  common[["Fold change"]] and common[["limma_logfc"]]
## t = 160, df = 2000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9612 0.9674
## sample estimates:
##    cor 
## 0.9644
## Used Bon Ferroni corrected t test(s) between columns.

## Warning: Missing column names filled in: 'X2' [2], 'X3' [3], 'X4' [4],
## 'X5' [5]
## Parsed with column specification:
## cols(
##   `DE genes in L. major-infected human macrophages relative to uninfected controls, 4 hpi, not accounting for phagocytosis` = col_character(),
##   X2 = col_character(),
##   X3 = col_character(),
##   X4 = col_character(),
##   X5 = col_character()
## )
## [1] 5119   52
## Warning: NaNs produced
## 
##  Pearson's product-moment correlation
## 
## data:  common[["Fold change beads v inf"]] and common[["limma_logfc"]]
## t = 120, df = 2000, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9283 0.9395
## sample estimates:
##    cor 
## 0.9341
## Used Bon Ferroni corrected t test(s) between columns.

6.3 Compare modified p-value data (after bead effect)

## Warning: Missing column names filled in: 'X2' [2], 'X3' [3], 'X4' [4],
## 'X5' [5], 'X6' [6]
## Parsed with column specification:
## cols(
##   `DE genes in L. major-infected human macrophages relative to uninfected controls, 4 hpi, with accounting for phagocytosis` = col_character(),
##   X2 = col_character(),
##   X3 = col_character(),
##   X4 = col_character(),
##   X5 = col_character(),
##   X6 = col_character()
## )
## [1] 2956   53
## Warning: NaNs produced
## 
##  Pearson's product-moment correlation
## 
## data:  common[["Fold change beads v inf"]] and common[["limma_logfc"]]
## t = 87, df = 1200, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9209 0.9365
## sample estimates:
##    cor 
## 0.9291
## Used Bon Ferroni corrected t test(s) between columns.

## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:hpgltools':
## 
##     combine
## The following object is masked from 'package:Biobase':
## 
##     combine
## The following objects are masked from 'package:BiocGenerics':
## 
##     combine, intersect, setdiff, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Error in cor.test.default(as.numeric(merged[["adj.P.Val"]]), as.numeric(merged[["worst"]])): 'x' and 'y' must have the same length
## Error in cor.test.default(as.numeric(merged[["adj.P.Val"]]), as.numeric(merged[["infuninf"]])): 'x' and 'y' must have the same length
## Error in cor.test.default(as.numeric(merged[["adj.P.Val"]]), as.numeric(merged[["beaduninf"]])): 'x' and 'y' must have the same length
## Error in cor.test.default(log2(as.numeric(merged[["Fold change"]])), as.numeric(merged[["l2fc"]])): 'x' and 'y' must have the same length

7 Repeat figure 5

In order to recreate figure 5, I think all I need to do is generate a set of logFCs for the mouse data used in Figure 5/Table S7 and compare them. If my regenerated logFCs are similar, then I can call it success, as my human logFCs have a correlation coefficient of ~ 0.96.

The only problem with doing this is that it looks to me that I have data from multiple mouse experiments all with the study name ‘lminfectome’. I think therefore, I must figure out what samples I actually want to use and therefore presumably split the ‘lminfectome’ experiment into a couple/few separate experiments.

## The biomart annotations file already exists, loading from it.
## Reading the sample metadata.
## The sample definitions comprises: 421 rows(samples) and 55 columns(metadata fields).
## Reading count tables.
## Using the transcript to gene mapping.
## Reading salmon data with tximport.
## Finished reading count tables.
## Matched 19660 annotations and counts.
## Bringing together the count matrix and gene information.
## The mapped IDs are not the rownames of your gene information, changing them now.
## Some annotations were lost in merging, setting them to 'undefined'.
## There were 100, now there are 24 samples.
## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 9148 low-count genes (10512 remaining).
## Step 2: normalizing the data with quant.
## Using normalize.quantiles.robust due to a thread error in preprocessCore.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 130 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.

## This function will replace the expt$expressionset slot with:
## log2(limma(cpm(quant(cbcb(data)))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Step 1: performing count filter with option: cbcb
## Removing 9148 low-count genes (10512 remaining).
## Step 2: normalizing the data with quant.
## Using normalize.quantiles.robust due to a thread error in preprocessCore.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 130 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with limma.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 10663 entries 0<=x<1.
## batch_counts: Before batch correction, 130 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 241495 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 130 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 10663 entries are 0<x<1.
## The be method chose 4 surrogate variable(s).
## batch_counts: Using limma's removeBatchEffect to remove batch effect.
## If you receive a warning: 'NANs produced', one potential reason is that the data was quantile normalized.
## The number of elements which are < 0 after batch correction is: 171
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE

## Plotting a PCA before surrogates/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

## Writing a legend of columns.
## Working on table 1/28: no_t48h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 2/28: no_t4h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 3/28: no_t72h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 4/28: yes_t24h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 5/28: yes_t48h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 6/28: yes_t4h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 7/28: yes_t72h_vs_no_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 8/28: no_t4h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 9/28: no_t72h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 10/28: yes_t24h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 11/28: yes_t48h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 12/28: yes_t4h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 13/28: yes_t72h_vs_no_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 14/28: no_t72h_vs_no_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 15/28: yes_t24h_vs_no_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 16/28: yes_t48h_vs_no_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 17/28: yes_t4h_vs_no_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 18/28: yes_t72h_vs_no_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 19/28: yes_t24h_vs_no_t72h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 20/28: yes_t48h_vs_no_t72h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 21/28: yes_t4h_vs_no_t72h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 22/28: yes_t72h_vs_no_t72h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 23/28: yes_t48h_vs_yes_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 24/28: yes_t4h_vs_yes_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 25/28: yes_t72h_vs_yes_t24h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 26/28: yes_t4h_vs_yes_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 27/28: yes_t72h_vs_yes_t48h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Working on table 28/28: yes_t72h_vs_yes_t4h
## The ebseq table is null.
## 20181210 a pthread error in normalize.quantiles leads me to robust.
## Used Bon Ferroni corrected t test(s) between columns.
## Used Bon Ferroni corrected t test(s) between columns.
## Parsed with column specification:
## cols(
##   `Gene Symbol` = col_character(),
##   `Human ID` = col_character(),
##   `logFC in human` = col_double(),
##   `Mouse ID` = col_character(),
##   `logFC in mouse` = col_double()
## )
## 
##  Pearson's product-moment correlation
## 
## data:  compare_merged[["logFC in mouse"]] and compare_merged[["limma_logfc"]]
## t = 130, df = 1600, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9542 0.9623
## sample estimates:
##    cor 
## 0.9584

8 Big Questions from Najib

In the following blocks, I will attempt to directly address the ‘Big Questions’ posed by Najib in my TODO document. For the moment, it will not be very well organized, as I did some of this stuff before Najib’s questions appeared. Once I finish, I will reorganize it though.

8.1 4 hour human macrophages

Which genes are DE in human macrophages at 4 hours upon infection with L. major?

This question was addressed above.

8.2 4 hour bead effect

This question is mostly addressed above, but needs to be expanded slightly. It is not a very interesting question to me, to be honest; since my degree of agreement with Laura’s previous analyses is very high, I am content to just say: “whatever she said is correct for this question, lets move to something new.”

8.3 Shared with CIDEIM

How many of those are shared with DE genes in CIDEIM’s human macrophages infected with L. panamensis?

## There were 267, now there are 50 samples.
## There were 50, now there are 23 samples.
## There were 23, now there are 23 samples.
## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 7130 low-count genes (12499 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
## This function will replace the expt$expressionset slot with:
## log2(limma(cpm(quant(cbcb(data)))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Step 1: performing count filter with option: cbcb
## Removing 7130 low-count genes (12499 remaining).
## Step 2: normalizing the data with quant.
## Using normalize.quantiles.robust due to a thread error in preprocessCore.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 547 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with limma.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 12773 entries 0<=x<1.
## batch_counts: Before batch correction, 547 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 274157 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 547 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 12773 entries are 0<x<1.
## The be method chose 4 surrogate variable(s).
## batch_counts: Using limma's removeBatchEffect to remove batch effect.
## Warning in do_batch(count_table, ...): The batch_counts call failed.
## Returning non-batch reduced data.
## Not putting labels on the plot.

## This function will replace the expt$expressionset slot with:
## log2(svaseq(cpm(quant(cbcb(data)))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Warning in normalize_expt(test_expt, norm = "quant", convert = "cpm",
## transform = "log2", : Quantile normalization and sva do not always play
## well together.
## Step 1: performing count filter with option: cbcb
## Removing 7130 low-count genes (12499 remaining).
## Step 2: normalizing the data with quant.
## Using normalize.quantiles.robust due to a thread error in preprocessCore.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 547 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with svaseq.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 12773 entries 0<=x<1.
## batch_counts: Before batch correction, 547 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 274157 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 547 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 12773 entries are 0<x<1.
## The be method chose 4 surrogate variable(s).
## Attempting svaseq estimation with 4 surrogates.
## The number of elements which are < 0 after batch correction is: 232
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE
## Not putting labels on the plot.

## batch_counts: Before batch/surrogate estimation, 285309 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 1373 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 150 entries are 0<x<1.
## The be method chose 2 surrogate variable(s).
## Attempting svaseq estimation with 2 surrogates.
## Warning in plot_batchsv(input, model_adjust): NAs introduced by coercion
## Plotting a PCA before surrogates/batch inclusion.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## This function will replace the expt$expressionset slot with:
## log2(svaseq(cpm(cbcb(data))))
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Step 1: performing count filter with option: cbcb
## Removing 0 low-count genes (12499 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 1373 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with svaseq.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## batch_counts: Before batch correction, 13255 entries 0<=x<1.
## batch_counts: Before batch correction, 1373 entries are >= 0.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 272849 entries are x>1.
## batch_counts: Before batch/surrogate estimation, 1373 entries are x==0.
## batch_counts: Before batch/surrogate estimation, 13255 entries are 0<x<1.
## The be method chose 4 surrogate variable(s).
## Attempting svaseq estimation with 4 surrogates.
## The number of elements which are < 0 after batch correction is: 275
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

## Writing a legend of columns.
## Working on 1/2: lm_t4h which is: lm_infected_t4h/uninfected_t4h.
## Found neither lm_infected_t4h_vs_uninfected_t4h nor uninfected_t4h_vs_lm_infected_t4h.
## Error in test_table$data[[1]]: subscript out of bounds
## Error in data.frame(df[, c(1, 2)]): object 'comparison_df' not found
## Error in eval(expr, envir, enclos): object 'compare_scatter' not found
## Error in eval(expr, envir, enclos): object 'compare_scatter' not found

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: tibble(v.2.0.1), dplyr(v.0.7.8), tidyr(v.0.8.2), ruv(v.0.9.7), bindrcpp(v.0.2.2), hpgltools(v.1.0), Biobase(v.2.42.0) and BiocGenerics(v.0.28.0)

loaded via a namespace (and not attached): 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), 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), withr(v.2.1.2), colorspace(v.1.4-0), GOSemSim(v.2.8.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), tximport(v.1.10.1), GenomeInfoDbData(v.1.2.0), bit64(v.0.9-7), farver(v.1.1.0), rprojroot(v.1.3-2), xfun(v.0.4), 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), 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), europepmc(v.0.3), checkmate(v.1.9.1), 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), RBGL(v.1.58.1), clusterProfiler(v.3.10.1), tools(v.3.5.2), usethis(v.1.4.0), ggplotify(v.0.0.3), ggplot2(v.3.1.0), gplots(v.3.0.1), RColorBrewer(v.1.1-2), 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), DO.db(v.2.9), openxlsx(v.4.1.0), triebeard(v.0.3.0), packrat(v.0.5.0), matrixStats(v.0.54.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), KernSmooth(v.2.23-15), crayon(v.1.3.4), minqa(v.1.2.4), htmltools(v.0.3.6), mgcv(v.1.8-26), corpcor(v.1.6.9), Formula(v.1.2-3), geneplotter(v.1.60.0), DBI(v.1.0.0), tweenr(v.1.0.1), MASS(v.7.3-51.1), Matrix(v.1.2-15), readr(v.1.3.1), cli(v.1.0.1), 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), rvcheck(v.0.1.3), GenomicAlignments(v.1.18.1), foreign(v.0.8-71), xml2(v.1.2.0), foreach(v.1.4.4), annotate(v.1.60.0), XVector(v.0.22.0), 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), edgeR(v.3.24.3), 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), latticeExtra(v.0.6-28), caTools(v.1.17.1.1) and memoise(v.1.1.0)

## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 801f62ba31ba525c6db9453255c6262fb1162d5c
## This is hpgltools commit: Thu Feb 21 14:03:11 2019 -0500: 801f62ba31ba525c6db9453255c6262fb1162d5c
LS0tCnRpdGxlOiAiMjAxOTAxMjQgUmVjYXBpdHVsYXRpbmcgcHJldmlvdXMgcmVzdWx0czogd2hpY2ggZ2VuZXMgYXJlIERFIGluIGh1bWFuIG1hY3JvcGhhZ2VzIGF0IDRocnMgdXBvbiBpbmZlY3Rpb24gd2l0aCBMLiBtYWpvcj8iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHdpZHRoOiAzMDAKICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5LCB0ZCB7CiAgZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDE2cHg7Cn0KcHJlIHsKIGZvbnQtc2l6ZTogMTZweAp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGhwZ2x0b29scykKdHQgPC0gc20oZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgZWNobz1UUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aD04LAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodD04LAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTIpKQp2ZXIgPC0gIjIwMTkwMTI0IgpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQ9IiVZJW0lZCIpCnJtZF9maWxlIDwtIHBhc3RlMCgiMjAxOTAxMjRfbWJpb19odW1hbi5SbWQiKQpgYGAKCiMgR2F0aGVyIGFubm90YXRpb24gZGF0YQoKYGBge3IgYW5ub3RhdGlvbnN9CmhzX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucygpJGFubm90YXRpb24Kcm93bmFtZXMoaHNfYW5ub3QpIDwtIG1ha2UubmFtZXMoCiAgcGFzdGUwKGhzX2Fubm90W1siZW5zZW1ibF90cmFuc2NyaXB0X2lkIl1dLCAiLiIsCiAgICAgICAgIGhzX2Fubm90W1sidHJhbnNjcmlwdF92ZXJzaW9uIl1dKSwKICB1bmlxdWU9VFJVRSkKaHNfdHhfZ2VuZSA8LSBoc19hbm5vdFssIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiKV0KaHNfdHhfZ2VuZVtbImlkIl1dIDwtIHJvd25hbWVzKGhzX3R4X2dlbmUpCmhzX3R4X2dlbmUgPC0gaHNfdHhfZ2VuZVssIGMoImlkIiwgImVuc2VtYmxfZ2VuZV9pZCIpXQpuZXdfaHNfYW5ub3QgPC0gaHNfYW5ub3QKcm93bmFtZXMobmV3X2hzX2Fubm90KSA8LSBtYWtlLm5hbWVzKGhzX2Fubm90W1siZW5zZW1ibF9nZW5lX2lkIl1dLCB1bmlxdWU9VFJVRSkKYGBgCgojIENyZWF0ZSBleHByZXNzaW9uc2V0CgpOb3RlIHRoYXQgYXMgb2YgMjAxOTAxMjQsIHR3byBzYW1wbGVzIGFyZSBzdGlsbCBtaXNzaW5nOiBocGdsMDkxNCBhbmQgaHBnbDA3NDkuCkkgYW0gcmVydW5uaW5nIHRoZWlyIG1hcHBpbmcgd2l0aCBzYWxtb24gbm93IHdpdGggdGhlIGFzc3VtcHRpb24gdGhhdCBJIGp1c3QKbWlzc2VkIHRoZW0gcHJldmlvdXNseS4gIEkgbm90ZWQgdGhlaXIgc3RhdHVzIGluIHRoZSAnc2tpcHBlZCcgY29sdW1uIG9mIHRoZQpvbmxpbmUgc2FtcGxlIHNoZWV0LgoKTm90ZSAyMDE5MDEyNTogaHBnbDA3NDkgbWFwcGVkOyBidXQgaHBnbDA5MTQgaGFzIHNvbWUgd2VpcmRuZXNzIHN0aWxsLiAgSXQgbG9va3MKbGlrZSB0aGUgZm9yd2FyZCByZWFkcyBoYXZlIGEgZ3ppcCBDUkMgZXJyb3IsIHNvIEkgdXNlZCB6Y2F0IHRvIGV4dHJhY3QgdGhlCmF2YWlsYWJsZSBkYXRhIGFuZCB3aWxsIHRoZW4gcmV0cmltL3JlbWFwLgoKTm90ZTogMjAxOTAyMTA6IEFsbCBzYW1wbGVzIG1hcHBlZC4KCkFub3RoZXIgbm90ZSwgSSBhbSB1c2luZyB0aGUgJ3N0YXRlJyBjb2x1bW4sIHdoaWNoIHdhcyBtaXNzaW5nIHRoZSBmaWVsZAonbGFfaW5mZWN0ZWQnIGZvciB0aGUgTGVpc2htYW5pYSBhbWF6b25lbnNpcyBzYW1wbGVzOyB0aGlzIHJlc3VsdGVkIGluIGEgc2V0IG9mCidOQScgY29uZGl0aW9ucy4gIEkgdGhlcmVmb3JlIGFkZGVkIGxhX2luZmVjdGVkIHRvIHRoZSByZWxldmFudCBmaWVsZHMgdG8gdGhlCnNhbXBsZSBzaGVldCBvbmxpbmUgYW5kIG15IHdvcmtpbmcgc2hlZXQuCgpJIGFsc28gZm91bmQgYW4gZXJyb3IgaW4gdGhlIHRpbWUgYXR0cmlidXRpb24gZm9yIHNhbXBsZSBocGdsMDQ2MS4gIFRoZSB0aW1lIHdhcwpzZXQgdG8gdW5kZWZpbmVkLCB3aGlsZSBpbiB0aGUgc3R1ZHkgaXQgd2FzIHQyNGguICBUaGF0IGhhcyBiZWVuIGNoYW5nZWQgaW4gYm90aAp0aGUgb25saW5lIGFuZCBteSBjb3B5IG9mIHRoZSBzYW1wbGUgc2hlZXQuCgpgYGB7ciBleHByZXNzaW9uc2V0fQojI3NhbXBsZV9zaGVldCA8LSAic2FtcGxlX3NoZWV0cy9hbGxfbGVpc2htYW5pYV9zYW1wbGVzXzIwMTkwMTI0Lnhsc3giCnNhbXBsZV9zaGVldCA8LSAic2FtcGxlX3NoZWV0cy9hbGxfbGVpc2htYW5pYV9zYW1wbGVzXzIwMTkwMjI1Lnhsc3giCmxvdHMgPC0gY3JlYXRlX2V4cHQoc2FtcGxlX3NoZWV0LAogICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uPSJoc2FwaWVuc2ZpbGUiLAogICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1uZXdfaHNfYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgdHhfZ2VuZV9tYXA9aHNfdHhfZ2VuZSkKYGBgCgojIEV4dHJhY3QgdGhlIG1iaW8gZGF0YQoKTm93IHdlIGhhdmUgYSAyOTEgc2FtcGxlIGRhdGEgc2V0LCBidXQgd2Ugb25seSB3YW50IHRoZSBzYW1wbGVzIGZyb20gdGhlIGh1bWFuCnBvcnRpb24gb2YgdGhlIG1CaW8gcGFwZXIsIHdoaWNoIE5hamliIGhlbHBmdWxseSBkZWZpbmVkIGluIHRoZSAnc3R1ZHknIGNvbHVtbgpvZiB0aGUgc2FtcGxlIHNoZWV0IGFzICdtQmlvJy4KClRodXMgSSB3aWxsIHB1bGwgdGhvc2Ugc2FtcGxlcyBmcm9tIHRoZSBzYW1wbGUgc2hlZXQgYW5kIHNldCB0aGUKY29uZGl0aW9ucy9iYXRjaGVzIHRvIHdoYXQgSSBhbSBhc3N1bWluZyBhcmUgcmVhc29uYWJsZSB2YWx1ZXMuCkFuIGltcG9ydGFudCBjYXZlYXQ6IHdlIG5lZWQgdG8gY29uY2F0ZW5hdGUgdGhlIGV4aXN0aW5nIGNvbHVtbnM6ICdleHB0X3RpbWUnCmFuZCAnc3RhdGUnIGluIG9yZGVyIHRvIGdldCB1c2VmdWwgdmFsdWVzIGZvciB0aGUgY29uZGl0aW9uLgoKSW4gYWRkaXRpb24sIEkgYW0gcmVtb3ZpbmcgdGhlIEwuIGFtYXpvbmVuc2lzIHNhbXBsZXMgZm9yIHRoZSBtb21lbnQuCgpgYGB7ciBzdWJzZXRfZXhwdH0KbWJpb19leHB0IDwtIHN1YnNldF9leHB0KGxvdHMsIHN1YnNldD0ic3R1ZHk9PSdtYmlvJyIpCm1iaW9fZXhwdCA8LSBzdWJzZXRfZXhwdChtYmlvX2V4cHQsIHN1YnNldD0ic3R1ZHliYXRjaCE9J3VudXNlZCciKQojI21iaW9fZXhwdCA8LSBzdWJzZXRfZXhwdChtYmlvX2V4cHQsIHN1YnNldD0icGF0aG9nZW5zcGVjaWVzIT0nbGFtYXpvbmVuc2lzJyIpCiMjbWJpb19leHB0IDwtIHN1YnNldF9leHB0KG1iaW9fZXhwdCwgc3Vic2V0PSJkb25vciE9J3RocDEnIikKbWJpb19leHB0IDwtIHNldF9leHB0X2JhdGNoZXMobWJpb19leHB0LCAic3R1ZHliYXRjaCIpCm1ldGFkYXRhIDwtIHBEYXRhKG1iaW9fZXhwdCkKbmV3X2NvbmRpdGlvbiA8LSBwYXN0ZTAobWV0YWRhdGFbWyJzdGF0ZSJdXSwgIl8iLCBtZXRhZGF0YVtbImV4cHR0aW1lIl1dKQptYmlvX2V4cHQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtYmlvX2V4cHQsICJzdGF0ZSIpCmBgYAoKIyBQZXJmb3JtIGEgZmV3IG1ldHJpY3MKCk5vdyBtYWtlIHNvbWUgcGxvdHMgYW5kIHNlZSBpZiBJIGdldCBzaW1pbGFyIG9uZXMgdG8gdGhvc2Ugb2JzZXJ2ZWQgaW4gdGhlCnBhcGVyLgoKSGVyZSBpcyB0aGUgbGluayB3aXRoIHRoZSBQQ0EgcGxvdHMgYW5kIHN1Y2g6Cmh0dHBzOi8vbWJpby5hc20ub3JnL2NvbnRlbnQvNy8zL2UwMDAyNy0xNi9maWd1cmVzLW9ubHkKClVubGVzcyBJIGFtIG1pc3Rha2VuLCB0aGUgb25seSB0aGluZ3MgSSBoYXZlIHRvIGNvbXBhcmUgYWdhaW5zdCBhcmUgc29tZSBmYW5jeQpQQ0EgcGxvdHMgaW4gdGhlIG1haW4gcGFwZXIgYW5kIGEgZmV3IHJhdy1pc2ggb25lcyBpbiB0aGUgc3VwcGxlbWVudGFsLgoKYGBge3Igc2hvd19pbml0aWFsX21ldHJpY3N9CmxpYnNpemUgPC0gcGxvdF9saWJzaXplKG1iaW9fZXhwdCkKbGlic2l6ZSRwbG90CmBgYAoKIyBOb3JtYWxpemUgYW5kIHBsb3QgbW9yZQoKIyMgTm8gYmF0Y2ggYWRqdXN0CgpUaGlzIGZpcnN0IHBsb3QgbWFrZXMgbm8gYXR0ZW1wdCB0byBoYW5kbGUgdGhlIHZhcmlvdXMgYmF0Y2ggZWZmZWN0cyBpbiB0aGUgZGF0YS4KCmBgYHtyIG5vcm1hbGl6ZV9yZXBsb3R9Cm1iaW9fbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChtYmlvX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIpKQptYmlvX3BjYSA8LSBwbG90X3BjYShtYmlvX25vcm0sIHNpemVfY29sdW1uPSJleHB0dGltZSIsIHBsb3RfbGFiZWxzPUZBTFNFLCBjaXM9TlVMTCwKICAgICAgICAgICAgICAgICAgICAgc2l6ZV9vcmRlcj1jKCJ0NGgiLCAidDI0aCIsICJ0NDhoIiwgInQ3MmgiKSkKIyNtYmlvX3BjYSA8LSBwbG90X3BjYShtYmlvX25vcm0pCm1iaW9fcGNhJHBsb3QKYGBgCgojIyBsaW1tYSBiYXRjaCBhZGp1c3QKCkluIHRoaXMgaXRlcmF0aW9uLCB3ZSB1c2UgbGltbWEncyBmdW5jdGlvbiB0byByZW1vdmUgYmF0Y2ggZWZmZWN0LCB3aGljaCBJIHRoaW5rCmlzIHdoYXQgd2FzIHVzZWQgaW4gb3JkZXIgdG8gbWFrZSB0aGUgZmlndXJlIGluIHRoZSBwYXBlci4gIFRoaXMgaXMgYm9ybmUgb3V0IGJ5CnRoZSBmYWN0IHRoYXQgdGhlIGltYWdlIGdlbmVyYXRlZCBpcyBuZWFybHkgaWRlbnRpY2FsIHRvIHRoZSBvbmUgaW4gdGhlIHBhcGVyLgoKYGBge3Igbm9ybWFsaXplX2xpbW1hX3JlcGxvdH0KbWJpb19iYXRjaDEgPC0gbm9ybWFsaXplX2V4cHQobWJpb19leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgbm9ybT0icXVhbnQiLCBiYXRjaD0ibGltbWEiKQptYmlvX3BjYTEgPC0gcGxvdF9wY2EobWJpb19iYXRjaDEsIHNpemVfY29sdW1uPSJleHB0dGltZSIsIHBsb3RfbGFiZWxzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgY2lzPU5VTEwsIHNpemVfb3JkZXI9YygidDRoIiwgInQyNGgiLCAidDQ4aCIsICJ0NzJoIikpCiMjbWJpb19wY2EgPC0gcGxvdF9wY2EobWJpb19ub3JtKQptYmlvX3BjYTEkcGxvdApgYGAKCiMjIHN2YXNlcSBiYXRjaCBhZGp1c3QKCkZpbmFsbHksIEkgZW1wbG95IG15IGZhdm9yaXRlIG1ldGhvZDogc3Zhc2VxKCkuICBUaGlzIHNxdWlzaGVzIHRoZSB0aW1lLWJhc2VkCmRpZmZlcmVuY2VzIGluIHRoZSBkYXRhIGFuZCBoaWdobGlnaHRzIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB2YXJpb3VzCmluZmVjdGlvbiBzdGF0ZXMuCgpgYGB7ciBub3JtYWxpemVfc3Zhc2VxX3JlcGxvdH0KbWJpb19iYXRjaDIgPC0gbm9ybWFsaXplX2V4cHQobWJpb19leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIpCm1iaW9fcGNhMiA8LSBwbG90X3BjYShtYmlvX2JhdGNoMiwgc2l6ZV9jb2x1bW49ImV4cHR0aW1lIiwgcGxvdF9sYWJlbHM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBjaXM9TlVMTCwgc2l6ZV9vcmRlcj1jKCJ0NGgiLCAidDI0aCIsICJ0NDhoIiwgInQ3MmgiKSkKIyNtYmlvX3BjYSA8LSBwbG90X3BjYShtYmlvX25vcm0pCm1iaW9fcGNhMiRwbG90CmBgYAoKIyMgQmVhZCBlZmZlY3QKCkkgZG8gbm90IHJlY2FsbCB3aGF0IG1ldGhvZHMgd2VyZSB1c2VkIHRvIGVzdGltYXRlIHRoZSAnYmVhZCBlZmZlY3QnIGluIHRoZQpkYXRhLiAgVGhlcmVmb3JlIEkgYW0gY29weS9wYXN0aW5nIHRoZSByZWxldmFudCBsb2dzIGZyb20gTGF1cmEgYW5kIHdpbGwgdGhlbgp0cnkgdG8gcmVjYXBpdHVsYXRlIHRoZSB0YXNrcyBwZXJmb3JtZWQgc2VwYXJhdGVseS4KCkkgdGhpbmsgdGhlIG1ha2VUYWIoKSBmdW5jdGlvbiBpcyB3aGF0IHdhcyB1c2VkIHRvIHJlZ2VuZXJhdGUgdGhlIHAtdmFsdWVzIGZvcgp0aGUgYmVhZC1hZGp1c3RlZCBkYXRhLgoKRm9sbG93aW5nIHRoZSBmdW5jdGlvbiBkZWZpbml0aW9uIGlzIGEgcmVwcmVzZW50YXRpdmUgaW52b2NhdGlvbiBwZXJmb3JtZWQgYnkKTGF1cmEuIChJIGNvcHkvcGFzdGVkIGZyb20gaGVyIGxvZyB3aXRoIG1pbm9yIGZvcm1hdHRpbmcgY2hhbmdlcykuCgpgYGB7ciBsYXVyYXNfY29kZSwgZXZhbD1GQUxTRX0KIyMgUXVhbnRpbGUgbm9ybWFsaXplIGNvdW50cwpjb3VudHNTdWJRIDwtIHFOb3JtKGNvdW50cykKIyMgU3BlY2lmeSBtb2RlbAptb2QgPSBtb2RlbC5tYXRyaXgofjArY29uZGl0aW9uK2JhdGNoKQojIyBVc2Ugdm9vbSB0byB0cmFuc2Zvcm0gcXVhbnRpbGUtbm9ybWFsaXplZCBjb3VudCBkYXRhIHRvIGxvZzItY291bnRzIHBlciBtaWxsaW9uLCBlc3RpbWF0ZSBtZWFuLXZhcmlhbmNlIHJlbGF0aW9uc2hpcAojIyBhbmQgdXNlIG0tdiByZWxhdGlvbnNoaXAgdG8gY29tcHV0ZXIgYXBwcm9wcmlhdGUgb2JzZXJ2YXRpb25hbC1sZXZlbCB3ZWlnaHRzCnYgPC0gdm9vbShjb3VudHNTdWJRLCBtb2QpCiMjIEZpdCBhIGxpbmVhciBtb2RlbCBmb3IgZWFjaCBnZW5lIHVzaW5nIHRoZSBzcGVjaWZpZWQgZGVzaWduIGNvbnRhaW5lZCBpbiB2CmZpdCA8LSBsbUZpdCh2KQoKbWFrZVRhYiA8LSBmdW5jdGlvbihjb250ckZpdCwgY29lZjEsIGNvZWYyLCAuLi4pIHsKICAjIyBDb21wdXRlIHRlc3Qgc3RhdGlzdGljCiAgc3RhdCA8LSBwbWluKGFicyhjb250ckZpdCR0WywgY29lZjFdKSwgYWJzKGNvbnRyRml0JHRbLCBjb2VmMl0pKQogICMjIENvbXB1dGUgcHZhbHVlIGZvciBzdGF0CiAgcHZhbCA8LSBwbWF4KGNvbnRyRml0JHAudmFsdWVbLCBjb2VmMV0sIGNvbnRyRml0JHAudmFsdWVbLCBjb2VmMl0pCiAgIyMgQWRqdXN0IHB2YWx1ZSBmb3IgbXVsdGlwbGUgdGVzdGluZwogIGFkai5wdmFsIDwtIHAuYWRqdXN0KHB2YWwsIG1ldGhvZD0iQkgiKQogICMjIE1ha2UgdGhlIHRvcHRhYmxlCiAgdGFiIDwtIHRvcFRhYmxlKGNvbnRyRml0LCBjb2VmPWNvZWYxLCBzb3J0LmJ5PSJub25lIiwgLi4uKQogIGNvZWYxX25hbWUgPC0gY29sbmFtZXMoY29udHJGaXQkY29lZilbY29lZjFdCiAgY29lZjJfbmFtZSA8LSBjb2xuYW1lcyhjb250ckZpdCRjb2VmKVtjb2VmMl0KICBuZXdfdGFiIDwtIGRhdGEuZnJhbWUodGFiJElELCB0YWIkbG9nRkMsIGNvbnRyRml0JGNvZWZbLCBjb2VmMl0sIHRhYiRBdmVFeHByLAogICAgICAgICAgICAgICAgICAgICAgICB0YWIkdCwgY29udHJGaXQkdFssIGNvZWYyXSwgc3RhdCwgcHZhbCwgYWRqLnB2YWwpCiAgbmV3X3RhYiA8LSBuZXdfdGFiW29yZGVyKC1zdGF0KSwgXQoKICBjb2xuYW1lcyhuZXdfdGFiKSA8LSBjKCJJRCIsIHBhc3RlMCgibG9nRkNfIiwgY29lZjFfbmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoImxvZ0ZDXyIsIGNvZWYyX25hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZUV4cHIiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJ0XyIsIGNvZWYxX25hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJ0XyIsIGNvZWYyX25hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgInN0YXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIlAuVmFsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgImFkai5QLlZhbHVlIikKICBuZXdfdGFiCn0KCiMjIGVCYXllcyBmaW5kcyBhbiBGLXN0YXRpc3RpYyBmcm9tIHRoZSBzZXQgb2YgdC1zdGF0aXN0aWNzIGZvciB0aGF0IGdlbmUKYmVhZHMyNC5pbmZMTTI0LmNvbnRyLm1hdCA8LSBtYWtlQ29udHJhc3RzKHVuaW5mX2luZj0oY29uZGl0aW9uaW5mTE0yNC1jb25kaXRpb251bmluZjI0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlYWRzX2luZj0oY29uZGl0aW9uaW5mTE0yNC1jb25kaXRpb25iZWFkczI0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz12JGRlc2lnbikKYmVhZHMyNC5pbmZMTTI0LmZpdCA8LSBjb250cmFzdHMuZml0KGZpdCwgYmVhZHMyNC5pbmZMTTI0LmNvbnRyLm1hdCkKYmVhZHMyNC5pbmZMTTI0LmViIDwtIGVCYXllcyhiZWFkczI0LmluZkxNMjQuZml0KQoKYmVhZHMyNC5pbmZMTTI0LnRvcFRhYiA8LSBtYWtlVGFiKGJlYWRzMjQuaW5mTE0yNC5lYiwgMSwgMiwgbnVtYmVyPW5yb3codiRFKSkKYGBgCgpBcyBmYXIgYXMgdGhlIGFib3ZlIGdvZXMsIGl0IG1vc3RseSBtYWtlcyBzZW5zZS4gIE15IHF1ZXN0aW9uIGlzLCBob3cgZG8gd2UgZ2V0CnRoZSBtb2RpZmllZCBsb2dGQyB2YWx1ZXM/ICBQcmVzdW1hYmx5IHRoYXQgaXMgbGF0ZXIgZG93biBpbiB0aGUgbG9nLgoKIyMgbWFrZVRhYjIKCkxvb2tpbmcgZnVydGhlciBkb3duIEkgZm91bmQgdGhlIGZvbGxvd2luZyBpbnZvY2F0aW9ucywgd2hpY2ggcGFydGlhbGx5IGJ1dAppbmNvbXBsZXRlbHkgYW5zd2VyIG15IHF1ZXN0aW9uLgoKYGBge3IgbGF1cmFzX21ha2V0YWIyLCBldmFsPUZBTFNFfQojIyBEZWZpbmUgbWFrZVRhYjIgZnVuY3Rpb24KIyMgY29uc3RydWN0IGEgREUgcmVzdWx0IHRhYmxlIGZvciBpbmZlY3Rpb24gdnMuIHVuaW5mZWN0ZWQgYW5kIGJlYWRzCiMjIGNvbnRyRml0OiB0aGUgcmVzdWx0IG9mIGVCYXllcyBhZnRlciBjb25yYXN0cy5maXQKIyMgY2VsbG1lYW5zRml0OiB0aGUgY2VsbCBtZWFucyBmaXQgKGxtRml0KHYpIGFib3ZlKQojIyBjb25qQ29udHJhc3RzOiB0aGUgJ2Nvbmp1Y3RpdmUnIG51bGwgdGVzdCAoaW5mZWN0aW9uIHZzLiB1bmluZiBBTkQgaW5mZWN0IHZzLiBiZWFkcykKIyMgZGlzakNvbnRyYXN0OiB0aGUgJ290aGVyJyB0ZXN0IChiZWFkcyB2cy4gdW5pbmYpCm1ha2VUYWIyIDwtIGZ1bmN0aW9uKGNvbnRyRml0LCBjZWxsbWVhbnNGaXQsIGNvbmpDb250cmFzdHMsIGRpc2pDb250cmFzdCkgewogICMjIEdldCBhdmVyYWdlIGV4cHJlc3Npb24gZm9yIGFsbCByZWxldmFudCB0ZXJtcwogIGNvbnRyX2xldmVsX2NvdW50cyA8LSByb3dTdW1zKGNvbnRyRml0JGNvbnRyYXN0c1ssIGMoY29uakNvbnRyYXN0cywgZGlzakNvbnRyYXN0KV0gIT0gMCkKICAjIyBEZWZpbmUgdGhlIGNvbmRpdGlvbiBsZXZlbHMgaW52b2x2ZWQgaW4gdGhlIHRlc3RzCiAgbGV2ZWxzX3RvX3VzZSA8LSBuYW1lcyhjb250cl9sZXZlbF9jb3VudHMpW2NvbnRyX2xldmVsX2NvdW50cyA+IDBdCiAgIyMgRXh0cmFjdCB0aGUgYXZlcmFnZSBjb3VudHMgZm9yIGVhY2gsIG1ha2UgaW50byB0YWJsZQogIGF2ZV9leHByZXNzaW9uX21hdCA8LSBjZWxsbWVhbnNGaXQkY29lZlssIGxldmVsc190b191c2VdCiAgZXhwX3RhYmxlIDwtIGRhdGEuZnJhbWUoSUQ9cm93bmFtZXMoYXZlX2V4cHJlc3Npb25fbWF0KSkKICBleHBfdGFibGUgPC0gY2JpbmQoZXhwX3RhYmxlLCBhcy5kYXRhLmZyYW1lKGF2ZV9leHByZXNzaW9uX21hdCkpCiAgbmFtZXMoZXhwX3RhYmxlKVstMV0gPC0gcGFzdGUoCiAgICAiQXZlRXhwciIsIGdzdWIoImNvbmRpdGlvbiIsIiIsbGV2ZWxzX3RvX3VzZSksCiAgICBzZXA9IjoiKQogICMjIENvbXB1dGUgdGVzdCBzdGF0aXN0aWMsIGFkanVzdGVkIHB2YWwsIGFuZCBsb2dGQyBmb3IgY29uanVjdGl2ZSB0ZXN0CiAgIyMgQWRkIHRvIHRhYmxlCiAgc3RhdCA8LSByb3dNaW5zKGFicyhjb250ckZpdCR0WywgY29uakNvbnRyYXN0c10pKQogIHB2YWwgPC0gcm93TWF4cyhjb250ckZpdCRwLnZhbHVlWywgY29uakNvbnRyYXN0c10pCiAgYWRqLnB2YWwgPC0gcC5hZGp1c3QocHZhbCwgbWV0aG9kPSJCSCIpCiAgZmNzIDwtIGFzLmRhdGEuZnJhbWUoY29udHJGaXQkY29lZlssIGNvbmpDb250cmFzdHNdKQogIG5hbWVzKGZjcykgPC0gcGFzdGUoImxvZ0ZDIiwgbmFtZXMoZmNzKSwgc2VwPSI6IikKICBjb25qX3B2YWxzIDwtIGFzLmRhdGEuZnJhbWUoYXBwbHkoY29udHJGaXQkcC52YWx1ZVssIGNvbmpDb250cmFzdHNdLCAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdCwgbWV0aG9kPSJCSCIpKQogIG5hbWVzKGNvbmpfcHZhbHMpIDwtIHBhc3RlKCJhZGouUC5WYWwiLCBuYW1lcyhjb25qX3B2YWxzKSwgc2VwPSI6IikKICBjb25qX3RhYmxlIDwtIGRhdGEuZnJhbWUoSUQ9cm93bmFtZXMoY29udHJGaXQpKQogIGNvbmpfdGFibGUgPC0gY2JpbmQoY29ual90YWJsZSwgZmNzLCBjb25qX3B2YWxzLCBzdGF0PXN0YXQsIGFkai5QLlZhbHVlPWFkai5wdmFsKQogIG5hbWVzKGNvbmpfdGFibGUpW3NlcSgyICsgMiAqIGxlbmd0aChjb25qQ29udHJhc3RzKSwgbmNvbChjb25qX3RhYmxlKSldIDwtIHBhc3RlKAogICAgYygic3RhdCIsImFkai5QLlZhbHVlIiksCiAgICBwYXN0ZShjb25qQ29udHJhc3RzLGNvbGxhcHNlPSI6IiksCiAgICBzZXA9IjoiKQogICMjIE1ha2UgdGhlIHRhYmxlIGZvciB0aGUgJ290aGVyJyB0ZXN0CiAgZGlzal90YWJsZSA8LSBkYXRhLmZyYW1lKElEPXJvd25hbWVzKGNvbnRyRml0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nRkM9Y29udHJGaXQkY29lZlssIGRpc2pDb250cmFzdF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkai5QLlZhbHVlPXAuYWRqdXN0KGNvbnRyRml0JHAudmFsdWVbLCBkaXNqQ29udHJhc3RdLCBtZXRob2Q9IkJIIikpCiAgbmFtZXMoZGlzal90YWJsZSlbLTFdIDwtIHBhc3RlKGMoImxvZ0ZDIiwgImFkai5QLlZhbHVlIiksIGRpc2pDb250cmFzdCwgc2VwPSI6IikKICAjIyBDb21iaW5lIHRhYmxlcywgbWFraW5nIHN1cmUgYWxsIHRhYmxlcyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIKICBzdG9waWZub3QoYWxsKGV4cF90YWJsZSRJRCA9PSBjb25qX3RhYmxlJElEICYgZXhwX3RhYmxlJElEID09IGRpc2pfdGFibGUkSUQpKQogIG91dF90YWJsZSA8LSBjYmluZChleHBfdGFibGUsIGNvbmpfdGFibGVbLCAtMV0sIGRpc2pfdGFibGVbLCAtMV0pCgogICMjIG9yZGVyIG91dHB1dCB0YWJsZSBieSB0aGUgc3RhdGlzdGljIGluIHRoZSBkaXNqdW5jdGl2ZSB0ZXN0CiAgbyA8LSBvcmRlcigtc3RhdCkKICBvdXRfdGFibGVbbyxdCn0KCmluZkxNNC5pbmZMTTI0LmNvbnRyLm1hdCA8LSBtYWtlQ29udHJhc3RzKHVuaW5mX2luZj0oKGNvbmRpdGlvbmluZkxNMjQtY29uZGl0aW9udW5pbmYyNCktKGNvbmRpdGlvbmluZkxNNC1jb25kaXRpb251bmluZjQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVhZHNfaW5mPSgoY29uZGl0aW9uaW5mTE0yNC1jb25kaXRpb25iZWFkczI0KS0oY29uZGl0aW9uaW5mTE00LWNvbmRpdGlvbmJlYWRzNCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmluZl9iZWFkcz0oKGNvbmRpdGlvbmJlYWRzMjQtY29uZGl0aW9udW5pbmYyNCktKGNvbmRpdGlvbmJlYWRzNC1jb25kaXRpb251bmluZjQpKSwgbGV2ZWxzPXYkZGVzaWduKQppbmZMTTQuaW5mTE0yNC5maXQgPC0gY29udHJhc3RzLmZpdChmaXQsIGluZkxNNC5pbmZMTTI0LmNvbnRyLm1hdCkKaW5mTE00LmluZkxNMjQuZWIgPC0gZUJheWVzKGluZkxNNC5pbmZMTTI0LmZpdCkKCmluZkxNNC5pbmZMTTI0LnRvcFRhYiA8LSBtYWtlVGFiMihpbmZMTTQuaW5mTE0yNC5lYiwgZml0LCBjKCJ1bmluZl9pbmYiLCAiYmVhZHNfaW5mIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJ1bmluZl9iZWFkcyIpKQpgYGAKCkkgdGhpbmsgdGhhdCBpcyBldmVyeXRoaW5nIHBlcmZvcm1lZC4gIElmIEkgdW5kZXJzdGFuZCB3aGF0IEkgc2VlLCB0aGVuIGl0IGlzCmRvaW5nIHRoZSBmb2xsb3dpbmc6CgoqIHF1YW50aWxlIG5vcm1hbGl6ZSBhbmQgZmlsdGVyIHRoZSBjb3VudCB0YWJsZS4KKiBwZXJmb3JtIHZvb20gd2l0aCBhIGNvbmRpdGlvbitiYXRjaCBleHBlcmltZW50YWwgbW9kZWwuCiogaW52b2tlIGxtRml0IG9uIHRoZSByZXN1bHQuCiogc2V0IHVwIGEgc2V0IG9mIGNvbnRyYXN0cyB3aGljaCBpbmNsdWRlOgogICAgKiB1bmluZl9pbmYgPSAoaW5mZWN0ZWQgYXQgdGltZSB5IC0gdW5pbmZlY3RlZCBhdCB0aW1lIHkpIC0gKGluZmVjdGVkIGF0IHRpbWUgeCAtIHVuaW5mZWN0ZWQgYXQgdGltZSB4KQogICAgKiBiZWFkc19pbmYgPSAoaW5mZWN0ZWQgYXQgdGltZSB5IC0gYmVhZHMgYXQgdGltZSB5KSAtIChpbmZlY3RlZCBhdCB0aW1lIHggLSBiZWFkcyBhdCB0aW1lIHgpCiAgICAqIHVuaW5mX2JlYWRzID0gKGJlYWRzIGF0IHRpbWUgeSAtIHVuaW5mZWN0ZWQgYXQgdGltZSB5KSAtIChiZWFkcyBhdCB0aW1lIHggLSB1bmluZmVjdGVkIGF0IHRpbWUgeCkKKiBJbnZva2UgY29udHJhc3RzLmZpdCBhbmQgZUJheWVzCiogSW52b2tlIHRoZSBtYWtlVGFiKDIpKCkgZnVuY3Rpb24gd2l0aCB0aGUgZUJheWVzIHJlc3VsdCBhcyBhcmcxLCB0aGUgbG1GaXQgcmVzdWx0IGFzIGFyZzIsIGFuZAogIHRoZSBjaGFyYWN0ZXIgbGlzdCBvZiBjKCJ1bmluZl9pbmYiLCAiYmVhZHNfaW5mIikgYXMgdGhlIHRoaXJkIGFyZyBhbmQgZmluYWxseSAidW5pbmZfYmVhZHMiCiAgYXMgdGhlIGZpbmFsIGFyZ3VtZW50LiAgbWFrZVRhYjIoKSBkb2VzIHRoZSBmb2xsb3dpbmc6CiAgICAqIHVzZXMgdGhlIG9yaWdpbmFsIGZpdCB0byBleHRyYWN0IHRoZSBhdmVyYWdlIGV4cHJlc3Npb24gdmFsdWVzLgogICAgKiBmaW5kcyB0aGUgbWluaW11bSB0IHN0YXRpc3RpYyBhbmQgbWF4aW11bSBwdmFsdWUgZm9yIGVhY2ggZ2VuZSBmcm9tIHRoZSB1bmluZl9pbmYgYW5kIGJlYWRzX2luZiBjb2x1bW5zLgogICAgKiB1c2VzIHAuYWRqdXN0IG9uIHRoaXMgc2V0IG9mIG1heGltaXplZCBwdmFsdWVzLgogICAgKiBwdWxscyB0aGUgbG9nRkMgdmFsdWVzIGZvciBlYWNoIG9mIHRoZSB1bmluZl9pbmYgYW5kIGJlYWRzX2luZiBjb2x1bW5zLgogICAgKiBkb2VzIHAuYWRqdXN0IG9uIHRoZSBwdmFsdWVzIG9mIHRoZSBjb250cmFzdCBwdmFsdWVzLgogICAgKiB1c2VzIGNiaW5kIG9uIHRoZXNlIHBpZWNlcyB0byBtYWtlIGEgc2luZ2xlIHRhYmxlLgogICAgKiB1c2VzIGNiaW5kIG9uIHRoZSBleHByZXNzaW9uIHRhYmxlLCB0aGUgbmV3bHkgY3JlYXRlZCB0YWJsZSAoY29uaikgYW5kIHRoZSBkaXNqdW5jdCB0YWJsZS4KICAgICogb3JkZXJzIHRoZW0gYWNjb3JkaW5nIHRvIHRoZSB0IHN0YXRpc3RpYy4KCkkgZG8gbm90IHNlZSBob3cgdGhpcyBzZXQgb2Ygb3BlcmF0aW9ucyBnaXZlcyB1cyBhIGJldHRlciBwaWN0dXJlIG9mIHRoZSBlZmZlY3QKb2YgYmVhZHMgZHVyaW5nIGFuIGluZmVjdGlvbi4gIFRoZSBwcmltYXJ5IHRoaW5nIEkgc2VlIGluIGl0IGlzIHRoZSBtb2RpZmljYXRpb24Kb2YgdGhlIHAtdmFsdWVzIGFuZCB0aGUgY29tcG91bmQgY29udHJhc3Qgb2YgKGluZnktdW5pbmZ5KS0oaW5meC11bmluZngpCkl0IHNlZW1zIHRvIG1lIHRoYXQgdGhpcyBpcyB0aGUgcGVyZmVjdCB0aW1lIGZvciBhbiBpbnRlcmFjdGlvbiBtb2RlbD8KCiMgSW1wbGVtZW50aW5nIHRoZSBjb250cmFzdHMgZnJvbSB0aGUgcGFwZXIKCldpdGggdGhlIGFib3ZlIGluIG1pbmQsIGl0IGlzIHByZXR0eSB0cml2aWFsIGZvciBtZSB0byBwZXJmb3JtIGxpbW1hL2VkZ2VyIHdpdGggdGhlIHNhbWUgY29udHJhc3RzLgpJIHdpbGwgZmlyc3QgaW52b2tlIG15IGludGVycHJldGF0aW9uIG9mIHRoZSBwYXBlciBjb250cmFzdHMgdXNpbmcgbGltbWFfcGFpcndpc2UoKSBhbmQgZm9yIHRoZQo0IGhvdXIgZGF0YSBsbWFqb3IgZGF0YS4KCkFmdGVyIHJlcmVhZGluZyB0aGUgcHJldmlvdXMgaW1wbGVtZW50YXRpb24sIEkgdGhpbmsgSSBnZXQgaXQuICBJdCB3YXMgaW4gZmFjdAp1c2luZyB0d28gY29udHJhc3RzOiBpbmZlY3RlZC91bmluZmVjdGVkIGFuZCBpbmZlY3RlZC9iZWFkcy4gIEl0IHJlcG9ydGVkIHRoZQppbmZlY3RlZC9iZWFkcyByZXN1bHQgYW5kIHRoZW4gdG9vayB0aGUgbGVhc3Qgc2lnbmlmaWNhbnQgb2YgdGhlIHAtdmFsdWUgYW5kIHQKc3RhdGlzdGljcyBvZiB0aGUgdHdvIGNvbnRyYXN0cywgcmUtYWRqdXN0ZWQgdGhlbSwgYW5kIHJlcG9ydGVkIHRoZXNlLgoKIyMgaHBnbHRvb2xzIG1ldGhvZAoKYGBge3IgcGFpcndpc2UsIGZpZy5zaG93PSJoaWRlIn0Ka2VlcGVycyA8LSBsaXN0KAogICI0aHBpX3VuaW5mIiA9IGMoImxtX2luZmVjdGVkX3Q0aCIsICJ1bmluZmVjdGVkX3Q0aCIpLAogICI0aHBpX2JlYWRzIiA9IGMoImxtX2luZmVjdGVkX3Q0aCIsICJiZWFkX3Q0aCIpCikKbWJpb19maWx0IDwtIHNldF9leHB0X2NvbmRpdGlvbnMobWJpb19leHB0LCBuZXdfY29uZGl0aW9uKQptYmlvX2ZpbHQgPC0gbm9ybWFsaXplX2V4cHQobWJpb19maWx0LCBmaWx0ZXI9VFJVRSkKIyMgU29tZXRoaW5nIHdlaXJkIGhhcHBlbmVkLCBteSBjb3VudHMgYXJlIHNvbWVob3cgZ2V0dGluZyBjYXN0IGFzIG5vbi1pbnRlZ2VycyEKIyMgVGh1cyBJIGFtIGludm9raW5nIGZvcmNlPVRSVUUgdW50aWwgSSBmaWd1cmUgb3V0IHdoYXQgaXMgZ29pbmcgb24uCm1iaW9fcGFpcndpc2UgPC0gYWxsX3BhaXJ3aXNlKG1iaW9fZmlsdCwgbW9kZWxfYmF0Y2g9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fZWJzZXE9RkFMU0UsIGZvcmNlPVRSVUUpCmV4Y2VsX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X21iaW9fcGFpcndpc2VfdGFibGVzLXZ7dmVyfS54bHN4IikKbWJpb190YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMobWJpb19wYWlyd2lzZSwga2VlcGVycz1rZWVwZXJzLCBleGNlbD1leGNlbF9maWxlKSkKYGBgCgpgYGB7ciBwYWlyd2lzZV9wbG90c30KbWJpb19wYWlyd2lzZSRjb21wJGhlYXQKbWJpb190YWJsZXNbWyJkZXNlcV9tYV9wbG90cyJdXVtbIjRocGlfdW5pbmYiXV1bWyJwbG90Il1dCmBgYAoKIyMgQ29tcGFyZSBhZ2FpbnN0IGEgc2hlZXQgSSBkb3dubG9hZGVkIGZyb20gdGhlIHBhcGVyLgoKSSBzYXZlZCB0aGUgd29ya3NoZWV0ICdpbmZMTTRfYmVmb3JlJyBhcyBpbmxpbmUtc3VwcGxlbWVudGFyeS1tYXRlcmlhbC01X2luZkxNNF9iZWZvcmUuY3N2Ckl0IGlzIDQgaHBpIC8gdW5pbmZlY3RlZCwgd2hpY2ggaXMgaGFwcGlseSBhIGNvbnRyYXN0IEkgcGVyZm9ybWVkLgoKYGBge3IgY29tcGFyZV9wYWlyd2lzZX0Kb2xkX3RhYmxlIDwtIHJlYWRyOjpyZWFkX2NzdigiZXhjZWwvaW5saW5lLXN1cHBsZW1lbnRhcnktbWF0ZXJpYWwtNV9pbmZMTTRfYmVmb3JlLmNzdiIpCmNvbG5hbWVzKG9sZF90YWJsZSkgPC0gb2xkX3RhYmxlWzEsIF0Kb2xkX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUob2xkX3RhYmxlWy0xLCBdKQoKcm93bmFtZXMob2xkX3RhYmxlKSA8LSBvbGRfdGFibGVbWyJJRCJdXQpuZXdfdGFibGUgPC0gbWJpb190YWJsZXNbWyJkYXRhIl1dW1siNGhwaV91bmluZiJdXQpjb21tb24gPC0gbWVyZ2Uob2xkX3RhYmxlLCBuZXdfdGFibGUsIGJ5PSJyb3cubmFtZXMiKQpkaW0oY29tbW9uKQpjb21tb25bWyJGb2xkIGNoYW5nZSJdXSA8LSBsb2cyKGFzLm51bWVyaWMoY29tbW9uW1siRm9sZCBjaGFuZ2UiXV0pKQpjb3IudGVzdChjb21tb25bWyJGb2xkIGNoYW5nZSJdXSwgY29tbW9uW1sibGltbWFfbG9nZmMiXV0pCnRlc3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihjb21tb25bLCBjKCJGb2xkIGNoYW5nZSIsICJsaW1tYV9sb2dmYyIpXSkKdGVzdCRzY2F0dGVyCgpvbGRfdGFibGUgPC0gcmVhZHI6OnJlYWRfY3N2KCJleGNlbC9pbmxpbmUtc3VwcGxlbWVudGFyeS1tYXRlcmlhbC01X2luZkxNNF9iZWZvcmUuY3N2IikKY29sbmFtZXMob2xkX3RhYmxlKSA8LSBvbGRfdGFibGVbMSwgXQpvbGRfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShvbGRfdGFibGVbLTEsIF0pCnJvd25hbWVzKG9sZF90YWJsZSkgPC0gb2xkX3RhYmxlW1siSUQiXV0KbmV3X3RhYmxlIDwtIG1iaW9fdGFibGVzW1siZGF0YSJdXVtbIjRocGlfYmVhZHMiXV0KY29tbW9uIDwtIG1lcmdlKG9sZF90YWJsZSwgbmV3X3RhYmxlLCBieT0icm93Lm5hbWVzIikKZGltKGNvbW1vbikKY29tbW9uW1siRm9sZCBjaGFuZ2UgYmVhZHMgdiBpbmYiXV0gPC0gbG9nMihhcy5udW1lcmljKGNvbW1vbltbIkZvbGQgY2hhbmdlIl1dKSkKY29yLnRlc3QoY29tbW9uW1siRm9sZCBjaGFuZ2UgYmVhZHMgdiBpbmYiXV0sIGNvbW1vbltbImxpbW1hX2xvZ2ZjIl1dKQp0ZXN0IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoY29tbW9uWywgYygiRm9sZCBjaGFuZ2UgYmVhZHMgdiBpbmYiLCAibGltbWFfbG9nZmMiKV0pCnRlc3Qkc2NhdHRlcgpgYGAKCiMjIENvbXBhcmUgbW9kaWZpZWQgcC12YWx1ZSBkYXRhIChhZnRlciBiZWFkIGVmZmVjdCkKCmBgYHtyIG1vZGlmaWVkfQpvbGRfdGFibGUgPC0gcmVhZHI6OnJlYWRfY3N2KCJleGNlbC9pbmxpbmUtc3VwcGxlbWVudGFyeS1tYXRlcmlhbC01X2luZkxNNF9hZnRlci5jc3YiKQpjb2xuYW1lcyhvbGRfdGFibGUpIDwtIG9sZF90YWJsZVsxLCBdCm9sZF90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKG9sZF90YWJsZVstMSwgXSkKcm93bmFtZXMob2xkX3RhYmxlKSA8LSBvbGRfdGFibGVbWyJJRCJdXQpuZXdfdGFibGUgPC0gbWJpb190YWJsZXNbWyJkYXRhIl1dW1siNGhwaV9iZWFkcyJdXQpjb21tb24gPC0gbWVyZ2Uob2xkX3RhYmxlLCBuZXdfdGFibGUsIGJ5PSJyb3cubmFtZXMiKQpkaW0oY29tbW9uKQpjb21tb25bWyJGb2xkIGNoYW5nZSBiZWFkcyB2IGluZiJdXSA8LSBsb2cyKGFzLm51bWVyaWMoY29tbW9uW1siRm9sZCBjaGFuZ2UgdW5pbmYgdiBpbmYiXV0pKQpjb3IudGVzdChjb21tb25bWyJGb2xkIGNoYW5nZSBiZWFkcyB2IGluZiJdXSwgY29tbW9uW1sibGltbWFfbG9nZmMiXV0pCnRlc3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihjb21tb25bLCBjKCJGb2xkIGNoYW5nZSBiZWFkcyB2IGluZiIsICJsaW1tYV9sb2dmYyIpXSkKdGVzdCRzY2F0dGVyCgp0MV9pbmZ1bmluZiA8LSBtYmlvX3RhYmxlc1tbImRhdGEiXV1bWzFdXQp0Ml9iZWFkdW5pbmYgPC0gbWJpb190YWJsZXNbWyJkYXRhIl1dW1syXV0KbGZjX3B2YWxzIDwtIGRhdGEuZnJhbWUoCiAgcm93Lm5hbWVzPXJvd25hbWVzKHQxX2luZnVuaW5mKSwKICAibDJmYyIgPSB0MV9pbmZ1bmluZltbImxpbW1hX2xvZ2ZjIl1dLAogICJpbmZ1bmluZiIgPSB0MV9pbmZ1bmluZltbImxpbW1hX2FkanAiXV0sCiAgImJlYWR1bmluZiIgPSB0Ml9iZWFkdW5pbmZbWyJsaW1tYV9hZGpwIl1dKQpyb3duYW1lcyhsZmNfcHZhbHMpIDwtIHJvd25hbWVzKHQxX2luZnVuaW5mKQpsZmNfcHZhbHNbWyJ3b3JzdCJdXSA8LSAxLjAKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWJibGUpCmxmY19wdmFscyA8LSBsZmNfcHZhbHMgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJyb3duYW1lcyIpICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUod29yc3Q9cG1heChpbmZ1bmluZiwgYmVhZHVuaW5mKSkKCm1lcmdlZCA8LSBtZXJnZShvbGRfdGFibGUsIGxmY19wdmFscywgYnkueD0icm93Lm5hbWVzIiwgYnkueT0icm93bmFtZXMiLCBhbGwueD1UUlVFKQpjb3IudGVzdChhcy5udW1lcmljKG1lcmdlZFtbImFkai5QLlZhbCJdXSksIGFzLm51bWVyaWMobWVyZ2VkW1sid29yc3QiXV0pKQpjb3IudGVzdChhcy5udW1lcmljKG1lcmdlZFtbImFkai5QLlZhbCJdXSksIGFzLm51bWVyaWMobWVyZ2VkW1siaW5mdW5pbmYiXV0pKQpjb3IudGVzdChhcy5udW1lcmljKG1lcmdlZFtbImFkai5QLlZhbCJdXSksIGFzLm51bWVyaWMobWVyZ2VkW1siYmVhZHVuaW5mIl1dKSkKIyMgSSB0aGluayB0aGlzIGlzIHN1Z2dlc3RpdmUgdGhhdCB0aGUgdHdvIHB2YWx1ZSBtZXRyaWNzIGFyZSBzaW1pbGFyPwoKIyMgSnVzdCB0byByZXBlYXQgb3VyIHByZXZpb3VzIGNoZWNrIHRoYXQgdGhlIGZvbGQgY2hhbmdlcyBhcmUgbWFpbnRhaW5lZC4KY29yLnRlc3QobG9nMihhcy5udW1lcmljKG1lcmdlZFtbIkZvbGQgY2hhbmdlIl1dKSksIGFzLm51bWVyaWMobWVyZ2VkW1sibDJmYyJdXSkpCmBgYAoKIyBSZXBlYXQgZmlndXJlIDUKCkluIG9yZGVyIHRvIHJlY3JlYXRlIGZpZ3VyZSA1LCBJIHRoaW5rIGFsbCBJIG5lZWQgdG8gZG8gaXMgZ2VuZXJhdGUgYSBzZXQgb2YKbG9nRkNzIGZvciB0aGUgbW91c2UgZGF0YSB1c2VkIGluIEZpZ3VyZSA1L1RhYmxlIFM3IGFuZCBjb21wYXJlIHRoZW0uICBJZiBteQpyZWdlbmVyYXRlZCBsb2dGQ3MgYXJlIHNpbWlsYXIsIHRoZW4gSSBjYW4gY2FsbCBpdCBzdWNjZXNzLCBhcyBteSBodW1hbiBsb2dGQ3MKaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIH4gMC45Ni4KClRoZSBvbmx5IHByb2JsZW0gd2l0aCBkb2luZyB0aGlzIGlzIHRoYXQgaXQgbG9va3MgdG8gbWUgdGhhdCBJIGhhdmUgZGF0YSBmcm9tCm11bHRpcGxlIG1vdXNlIGV4cGVyaW1lbnRzIGFsbCB3aXRoIHRoZSBzdHVkeSBuYW1lICdsbWluZmVjdG9tZScuICBJIHRoaW5rCnRoZXJlZm9yZSwgSSBtdXN0IGZpZ3VyZSBvdXQgd2hhdCBzYW1wbGVzIEkgYWN0dWFsbHkgd2FudCB0byB1c2UgYW5kIHRoZXJlZm9yZQpwcmVzdW1hYmx5IHNwbGl0IHRoZSAnbG1pbmZlY3RvbWUnIGV4cGVyaW1lbnQgaW50byBhIGNvdXBsZS9mZXcgc2VwYXJhdGUKZXhwZXJpbWVudHMuCgpgYGB7ciBtb3VzZV9kYXRhfQptbV9hbm5vdCA8LSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoc3BlY2llcz0ibW11c2N1bHVzIikkYW5ub3RhdGlvbgpyb3duYW1lcyhtbV9hbm5vdCkgPC0gbWFrZS5uYW1lcygKICBwYXN0ZTAobW1fYW5ub3RbWyJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiXV0sICIuIiwKICAgICAgICAgbW1fYW5ub3RbWyJ0cmFuc2NyaXB0X3ZlcnNpb24iXV0pLAogIHVuaXF1ZT1UUlVFKQptbV90eF9nZW5lIDwtIG1tX2Fubm90WywgYygiZW5zZW1ibF9nZW5lX2lkIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIpXQptbV90eF9nZW5lW1siaWQiXV0gPC0gcm93bmFtZXMobW1fdHhfZ2VuZSkKbW1fdHhfZ2VuZSA8LSBtbV90eF9nZW5lWywgYygiaWQiLCAiZW5zZW1ibF9nZW5lX2lkIildCm5ld19tbV9hbm5vdCA8LSBtbV9hbm5vdApyb3duYW1lcyhuZXdfbW1fYW5ub3QpIDwtIG1ha2UubmFtZXMobW1fYW5ub3RbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZT1UUlVFKQoKbG90c19tbSA8LSBjcmVhdGVfZXhwdChzYW1wbGVfc2hlZXQsCiAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW49Im1tdXNjdWx1c2ZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1uZXdfbW1fYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgdHhfZ2VuZV9tYXA9bW1fdHhfZ2VuZSkKCmJtY19leHB0IDwtIHN1YnNldF9leHB0KGxvdHNfbW0sIHN1YnNldD0ic3R1ZHk9PSdibWMnIikKYm1jX2V4cHQgPC0gc2V0X2V4cHRfYmF0Y2hlcyhibWNfZXhwdCwgInN0dWR5YmF0Y2giKQptZXRhZGF0YSA8LSBwRGF0YShibWNfZXhwdCkKbmV3X2NvbmRpdGlvbiA8LSBwYXN0ZTAobWV0YWRhdGFbWyJpbmZlY3RzdGF0ZSJdXSwgIl8iLCBtZXRhZGF0YVtbImV4cHR0aW1lIl1dKQpibWNfZXhwdCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGJtY19leHB0LCBuZXdfY29uZGl0aW9uKQoKYm1jX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoYm1jX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGZpbHRlcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIpCnRlc3QgPC0gcGxvdF9wY2EoYm1jX25vcm0pCnRlc3QkcGxvdAoKYm1jX25vcm1iYXRjaCA8LSBub3JtYWxpemVfZXhwdChibWNfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLCBiYXRjaD0ibGltbWEiKQp0ZXN0IDwtIHBsb3RfcGNhKGJtY19ub3JtYmF0Y2gpCnRlc3QkcGxvdAojIyBUaGlzIHBsb3QgaXMgc2hvY2tpbmdseSBzaW1pbGFyIHRvIHRoZSBvbmUgb2JzZXJ2ZWQgaW4gZmlndXJlIDJCIG9mCiMjIGh0dHBzOi8vYm1jZ2Vub21pY3MuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni9zMTI4NjQtMDE1LTIyMzctMgojIyBZQVkhCgpibWNfcGFpcndpc2UgPC0gYWxsX3BhaXJ3aXNlKGJtY19leHB0LCBtb2RlbF9iYXRjaD1UUlVFLCBmb3JjZT1UUlVFKQpibWNfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKGJtY19wYWlyd2lzZSkKCmNvbXBhcmVfdGFibGUgPC0gcmVhZHI6OnJlYWRfdHN2KCJleGNlbC9pbmxpbmUtc3VwcGxlbWVudGFyeS1tYXRlcmlhbC03LmNzdiIsIHNraXA9MSkKYm1jX3RhYmxlIDwtIGJtY190YWJsZXMkZGF0YVtbInllc190NGhfdnNfbm9fdDRoIl1dCmNvbXBhcmVfbWVyZ2VkIDwtIG1lcmdlKGNvbXBhcmVfdGFibGUsIGJtY190YWJsZSwgYnkueD0iTW91c2UgSUQiLCBieS55PSJyb3cubmFtZXMiLCBhbGwueD1UUlVFKQpjb3IudGVzdChjb21wYXJlX21lcmdlZFtbImxvZ0ZDIGluIG1vdXNlIl1dLCBjb21wYXJlX21lcmdlZFtbImxpbW1hX2xvZ2ZjIl1dKQpgYGAKCiMgQmlnIFF1ZXN0aW9ucyBmcm9tIE5hamliCgpJbiB0aGUgZm9sbG93aW5nIGJsb2NrcywgSSB3aWxsIGF0dGVtcHQgdG8gZGlyZWN0bHkgYWRkcmVzcyB0aGUgJ0JpZyBRdWVzdGlvbnMnCnBvc2VkIGJ5IE5hamliIGluIG15IFRPRE8gZG9jdW1lbnQuICBGb3IgdGhlIG1vbWVudCwgaXQgd2lsbCBub3QgYmUgdmVyeSB3ZWxsCm9yZ2FuaXplZCwgYXMgSSBkaWQgc29tZSBvZiB0aGlzIHN0dWZmIGJlZm9yZSBOYWppYidzIHF1ZXN0aW9ucyBhcHBlYXJlZC4gIE9uY2UKSSBmaW5pc2gsIEkgd2lsbCByZW9yZ2FuaXplIGl0IHRob3VnaC4KCiMjIDQgaG91ciBodW1hbiBtYWNyb3BoYWdlcwoKV2hpY2ggZ2VuZXMgYXJlIERFIGluIGh1bWFuIG1hY3JvcGhhZ2VzIGF0IDQgaG91cnMgdXBvbiBpbmZlY3Rpb24gd2l0aCBMLiBtYWpvcj8KClRoaXMgcXVlc3Rpb24gd2FzIGFkZHJlc3NlZCBhYm92ZS4KCiMjIDQgaG91ciBiZWFkIGVmZmVjdAoKVGhpcyBxdWVzdGlvbiBpcyBtb3N0bHkgYWRkcmVzc2VkIGFib3ZlLCBidXQgbmVlZHMgdG8gYmUgZXhwYW5kZWQgc2xpZ2h0bHkuICBJdAppcyBub3QgYSB2ZXJ5IGludGVyZXN0aW5nIHF1ZXN0aW9uIHRvIG1lLCB0byBiZSBob25lc3Q7IHNpbmNlIG15IGRlZ3JlZSBvZgphZ3JlZW1lbnQgd2l0aCBMYXVyYSdzIHByZXZpb3VzIGFuYWx5c2VzIGlzIHZlcnkgaGlnaCwgSSBhbSBjb250ZW50IHRvIGp1c3Qgc2F5Ogoid2hhdGV2ZXIgc2hlIHNhaWQgaXMgY29ycmVjdCBmb3IgdGhpcyBxdWVzdGlvbiwgbGV0cyBtb3ZlIHRvIHNvbWV0aGluZyBuZXcuIgoKIyMgU2hhcmVkIHdpdGggQ0lERUlNCgpIb3cgbWFueSBvZiB0aG9zZSBhcmUgc2hhcmVkIHdpdGggREUgZ2VuZXMgaW4gQ0lERUlNJ3MgaHVtYW4gbWFjcm9waGFnZXMKaW5mZWN0ZWQgd2l0aCBMLiBwYW5hbWVuc2lzPwoKYGBge3IgY2lkZWltX2NvbXBhcmlzb259CnRlc3RfZXhwdCA8LSBzdWJzZXRfZXhwdChsb3RzLCBzdWJzZXQ9InN0dWR5PT0nbUJpbyd8bGFiPT0nYWRlJyIpCnRlc3RfZXhwdCA8LSBzdWJzZXRfZXhwdCh0ZXN0X2V4cHQsIHN1YnNldD0iY2VsbHR5cGU9PSdtYWNyb3BoYWdlJyIpCnRlc3RfZXhwdCA8LSBzdWJzZXRfZXhwdCh0ZXN0X2V4cHQsIHN1YnNldD0ic3RhdGUhPSdiZWFkJyIpCgp0ZXN0X2V4cHQgPC0gc2V0X2V4cHRfYmF0Y2hlcyh0ZXN0X2V4cHQsICJsYWIiKQptZXRhZGF0YSA8LSBwRGF0YSh0ZXN0X2V4cHQpCm5ld19jb25kaXRpb24gPC0gcGFzdGUwKG1ldGFkYXRhW1sic3RhdGUiXV0sICJfIiwgbWV0YWRhdGFbWyJleHB0dGltZSJdXSkKdGVzdF9leHB0IDwtIHNldF9leHB0X2NvbmRpdGlvbnModGVzdF9leHB0LCBuZXdfY29uZGl0aW9uKQptZXRhZGF0YSA8LSBwRGF0YSh0ZXN0X2V4cHQpCm5ld19jb25kaXRpb24gPC0gcGFzdGUwKG1ldGFkYXRhW1sic3RhdGUiXV0sICJfIiwgbWV0YWRhdGFbWyJleHB0dGltZSJdXSkKCnRlc3RfZXhwdCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHRlc3RfZXhwdCwgbmV3X2NvbmRpdGlvbikKYGBgCgpgYGB7ciBwbG90X21iaW9fY2lkZWltfQp0ZXN0X2ZpbHQgPC0gbm9ybWFsaXplX2V4cHQodGVzdF9leHB0LCBmaWx0ZXI9VFJVRSkKCnRlc3Rfbm9ybSA8LSBub3JtYWxpemVfZXhwdCh0ZXN0X2V4cHQsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2g9ImxpbW1hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFKQp0ZXN0X3BjYSA8LSBwbG90X3BjYSh0ZXN0X25vcm0sIHBsb3RfbGFiZWxzPUZBTFNFLCBjaXM9RkFMU0UpCnRlc3RfcGNhJHBsb3QKCnRlc3Rfbm9ybSA8LSBub3JtYWxpemVfZXhwdCh0ZXN0X2V4cHQsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSkKdGVzdF9wY2EgPC0gcGxvdF9wY2EodGVzdF9ub3JtLCBwbG90X2xhYmVscz1GQUxTRSwgY2lzPUZBTFNFKQp0ZXN0X3BjYSRwbG90CmBgYAoKYGBge3IgZGVfbWJpb19jaWRlaW19Cm5ld19jb25kaXRpb24gPC0gcGFzdGUwKG1ldGFkYXRhW1sic3RhdGUiXV0sICJfIiwgbWV0YWRhdGFbWyJleHB0dGltZSJdXSkKdGVzdF9kZSA8LSBhbGxfcGFpcndpc2UodGVzdF9maWx0LCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZm9yY2U9VFJVRSkKa2VlcGVycyA8LSBsaXN0KAogICJsbV90NGgiID0gYygibG1faW5mZWN0ZWRfdDRoIiwgInVuaW5mZWN0ZWRfdDRoIiksCiAgIm1iaW8iID0gYygibHBfaGVhbGluZ191bmRlZmluZWQiLCAidW5pbmZlY3RlZF91bmRlZmluZWQiKSkKdGVzdF90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcyh0ZXN0X2RlLCBrZWVwZXJzPWtlZXBlcnMpCgpjb21wYXJpc29uX2RmIDwtIG1lcmdlKHRlc3RfdGFibGUkZGF0YVtbMV1dLCB0ZXN0X3RhYmxlJGRhdGFbWzJdXSwgYnk9InJvdy5uYW1lcyIpCmNvbXBhcmVfc2NhdHRlciA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGNvbXBhcmlzb25fZGZbLCBjKCJkZXNlcV9sb2dmYy54IiwgImRlc2VxX2xvZ2ZjLnkiKV0pCmNvbXBhcmVfc2NhdHRlciRzY2F0dGVyCmNvbXBhcmVfc2NhdHRlciRjb3JyZWxhdGlvbgpgYGAKCmBgYHtyIHNhdmVtZX0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCiMjIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQojIyB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXNhdmVmaWxlKSkKYGBgCg==