1 TODO

  • Remove MSstats logging. – done
  • Make explicit spearman correlations between methods. – done
    • Do both for all data and for the top-50/bottom-50 – done, but weird.
  • Make 100% certain that the samples are annotated correctly. – done.
  • Limma/MSstats/EdgeR venn disagram for all up in CF
  • Repeat in all down CF
  • Repeat with a cutoff, top-50
  • Individual plots for P/PE proteins.

2 Analyzing data from openMS and friends.

In preprocessing_comet_highres.Rmd, I used the openMS tutorials and supplemental materials from a couple papers to hopefully correctly perform the various preprocessing tasks required to extract intensity data from DIA/SWATH transitions.

The final steps of that process combined the transition intensities from every sample into a metadata frile (results/tric/HCD_meta.tsv), an intensity matrix (results/tric/HCD_outmatrix.tsv), and a feature aligned output matrix (results/tric/aligned_comet_HCD.tsv).

My reading of the SWATH2stats and MSstats source code suggests to me that the log2(intensities) of the feature aligned data are our final proxy for protein abundance. At first glance, this suggests to me that these data might follow a distribution similar to RNASeq data (negative binomial, but perhaps with a bigger tail?). In addition, by the time we use tric on the data, we have a count matrix and sample annotation data frames which look remarkably similar to those used in a RNASeq expressionset. Indeed, by the end of the MSstats processing, it creates a MSnSet class of its own which uses fData/exprs/pData.

For the curious, my reasoning for saying that the log intensities are our proxy for abundance comes from MSstats/R/DataProcess.R in a clause which looks like:

if (logTrans == 2) {
  work[["ABUNDANCE"]] <- log2(work[["ABUNDANCE"]])
} else if (logTrans == 10) {
  work[["ABUNDANCE"]] <- log10(work[["ABUNDANCE"]])
} else {
  ## Above there was a check for only log 2 and 10, but we can do e if we want.
  ## I might go back up there and remove that check. Long live e! 2.718282 rules!
  work[["ABUNDANCE"]] <- log(work[["ABUNDANCE"]]) / log(logTrans)
}

(Note: I added the natural log to the set of conditions, but otherwise the logic is unchanged.)

With that in mind, I want to use some tools with which I am familiar in order to try to understand these data. Therefore I will first attempt to coerce my tric aligned data and annotations into a ‘normal’ expressionset. Then I want to do some diagnostic plots which, if I am wrong and these distributions are not as expected, will be conceptually incorrect (I don’t yet think I am wrong).

2.1 Sample annotation via SWATH2stats

I am using the SWATH2stats vignette as my primary source of information. Thus I see that it uses the OpenSWATH_SM3_GoldStandardAutomatedResults_human_peakgroups.txt which has a format nearly identical to my tric output matrix. Thus for the moment I will assume that the proper input for SWATH2stats is ‘results/tric/comet_HCD.tsv’ and not the metadata nor output matrix.

I keep a sample sheet of all the DIA samples used in this analysis in ‘sample_sheets/dia_samples.xlsx’ It should contain all the other required data with one important caveat, I removed 1 sample by ‘commenting’ it (e.g. prefixing it with ‘##’ – which is an admittedly dumb thing to do in an excel file.

One last caveat: I hacked the SWATH2stats sample_annotation() function to add a couple columns in an attempt to make it a little more robust when faced with sample sheets with differently named columns.

In addition, SWATH2stats provides some nice filtering and combination functions which should be considered when generating various expressionset data structures later.

tric_data <- read.csv("results/tric/aligned_comet_HCD.tsv", sep="\t")

sample_annot <- openxlsx::read.xlsx("sample_sheets/dia_samples.xlsx")
rownames(sample_annot) <- sample_annot[["sampleid"]]
## Drop samples starting with comments
keep_idx <- ! grepl(pattern="##", x=rownames(sample_annot))
sample_annot <- sample_annot[keep_idx, ]
## Set the mzXML column to match the filename column in the data.
devtools::load_all("~/scratch/git/SWATH2stats")
## Loading SWATH2stats
## s2s, my witty way of shortening SWATH2stats...
s2s_exp <- SWATH2stats::sample_annotation(data=tric_data,
                                          sample_annotation=sample_annot,
                                          data_type="OpenSWATH",
                                          data_file_column="filename")
############
## IMPORTANT CAVEAT
############
## HEY YOU, TREY, READ THIS OR YOU WILL BE PISSED LATER
############
## I am keeping only those rows which are from the march run.
dim(s2s_exp)
## [1] 145308     70
kept_rows <- s2s_exp[["BioReplicate"]] == "mar"
s2s_exp <- s2s_exp[kept_rows, ]
dim(s2s_exp)
## [1] 92624    70
## Wow, that dropped 46% of the data

Now I have a couple data structures which should prove useful for the metrics provided by SWATH2stats, MSstats, and my own hpgltools.

3 SWATH2stats continued

Lets return to some of the metrics provided by swath2stats.

## Get correlations on a sample by sample basis
pp(file="images/swath2stats_sample_cor.png")
## Going to write the image to: images/swath2stats_sample_cor.png when dev.off() is called.
sample_cor <- SWATH2stats::plot_correlation_between_samples(s2s_exp,
                                                            Comparison=transition_group_id ~ Run,
                                                            fun.aggregate=sum,
                                                            column.values="Intensity")
## Warning: Ignoring unknown aesthetics: fill
dev.off()
## png 
##   2
sample_cond_rep_cor <- SWATH2stats::plot_correlation_between_samples(s2s_exp,
                                                                     Comparison=transition_group_id ~
                                                                       Condition + BioReplicate + Run,
                                                                     fun.aggregate=sum,
                                                                     column.values="Intensity")
## Warning: Ignoring unknown aesthetics: fill

## I am a little concerned that these values do not seem to change when I took
## filtered/normalized data.  So I am rerunning them manually for a moment --
## perhaps I messed something up when I rewrote portions of the
## sample_annotation() function in SWATH2stats.

## ahh I think I see the problem.  The default value for fun.aggregate is NULL,
## which causes dcast to default to length.  I think this is not likely to be
## valid for this data.  I am not certain, however, what is the appropriate
## function.  If I had to guess, I would go with sum()?

assess_decoy_rate(s2s_exp)
## Number of non-decoy peptides: 9558
## Number of decoy peptides: 1605
## Decoy rate: 0.1679
## This seems a bit high to me, yesno?
fdr_overall <- assess_fdr_overall(s2s_exp, output="Rconsole")

byrun_fdr <- assess_fdr_byrun(s2s_exp, FFT=0.7, plot=TRUE, output="Rconsole")
## The average FDR by run on assay level is 0.009
## The average FDR by run on peptide level is 0.009
## The average FDR by run on protein level is 0.034

mscore4assayfdr(s2s_exp, FFT=0.7, fdr_target=0.02)
## Target assay FDR: 0.02
## Required overall m-score cutoff:0.0044668
## achieving assay FDR =0.0194
## [1] 0.004467
prot_score <- mscore4protfdr(s2s_exp, FFT=0.7, fdr_target=0.02)
## Target protein FDR:0.02
## Required overall m-score cutoff:0.0014125
## achieving protein FDR =0.0199
mscore_filtered <- SWATH2stats::filter_mscore(s2s_exp, prot_score)
## Dimension difference: 12662, 0
data_filtered_mscore <- filter_mscore_freqobs(s2s_exp, 0.01, 0.8, rm.decoy=FALSE)
## Treshold, peptides need to have been quantified in more conditions than: 13.6
## Fraction of peptides selected: 0.16
## Dimension difference: 62450, 0
data_filtered_fdr <- filter_mscore_fdr(s2s_exp, FFT=0.7,
                                       overall_protein_fdr_target=0.03,
                                       upper_overall_peptide_fdr_limit=0.05)
## Target protein FDR:0.03
## Required overall m-score cutoff:0.0017783
## achieving protein FDR =0.0286
## filter_mscore_fdr is filtering the data...
## finding m-score cutoff to achieve desired protein FDR in protein master list..
## finding m-score cutoff to achieve desired global peptide FDR..
## Target peptide FDR:0.05
## Required overall m-score cutoff:0.0079433
## achieving peptide FDR =0.0485
## Proteins selected: 
## Total proteins selected: 1832
## Thereof target proteins: 1760
## Thereof decoy proteins: 72
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 9342
## Thereof target peptides: 9190
## Thereof decoy peptides: 152
## Total peptides selected from:
## Total peptides: 9853
## Thereof target peptides: 9847
## Thereof decoy peptides: 299
## The average FDR by run on assay level is 0.006
## The average FDR by run on peptide level is 0.007
## The average FDR by run on protein level is 0.025
## Individual run FDR quality of the peptides selected from:
## 0.00666
## The decoys have been removed from the returned data
only_proteotypic <- filter_proteotypic_peptides(data_filtered_fdr)
## Number of proteins detected: 1743
## Protein identifiers: Rv2050, Rv0516c, Rv0045c, Rv0704, Rv2555c, Rv2442c
## Number of proteins detected that are supported by a proteotypic peptide: 1717
## Number of proteotypic peptides detected: 9108
all_filtered <- filter_all_peptides(data_filtered_fdr)
## Number of proteins detected: 1745
## Protein identifiers: Rv2050, Rv0516c, Rv0045c, Rv0704, Rv2555c, Rv2442c
only_strong <- filter_on_max_peptides(data_filtered_fdr, 5)
## Before filtering: 
##   Number of proteins: 1756
##   Number of peptides: 9190
## 
## Percentage of peptides removed: 40.12%
## 
## After filtering: 
##   Number of proteins: 1756
##   Number of peptides: 5503
only_minimum <- filter_on_min_peptides(only_strong, 2)
## Before filtering: 
##   Number of proteins: 1756
##   Number of peptides: 5503
## 
## Percentage of peptides removed: 8.4%
## 
## After filtering: 
##   Number of proteins: 1294
##   Number of peptides: 5041
## I think these matrixes are probably smarter to use than the raw outmatrix from tric.
## But I am not a fan of rerwriting the sample column names.
protein_matrix_mscore <- write_matrix_proteins(mscore_filtered, write.csv=TRUE,
                                               filename="swath2stats_protein_matrix_mscore.csv",
                                               rm.decoy=FALSE)
## Protein overview matrix swath2stats_protein_matrix_mscore.csv written to working folder.
dim(protein_matrix_mscore)
## [1] 1755   18
peptide_matrix_mscore <- write_matrix_peptides(mscore_filtered, write.csv=TRUE,
                                               filename="swath2stats_peptide_matrix_mscore.csv",
                                               rm.decoy=FALSE)
## Peptide overview matrix swath2stats_peptide_matrix_mscore.csv written to working folder.
protein_matrix_minimum <- write_matrix_proteins(only_minimum, write.csv=TRUE,
                                                filename="swath2stats_protein_matrix_minimum.csv",
                                                rm.decoy=FALSE)
## Protein overview matrix swath2stats_protein_matrix_minimum.csv written to working folder.
dim(protein_matrix_minimum)
## [1] 1294   18
peptide_matrix_minimum <- write_matrix_peptides(only_minimum, write.csv=TRUE,
                                                filename="swath2stats_peptide_matrix_minimum.csv",
                                                rm.decoy=FALSE)
## Peptide overview matrix swath2stats_peptide_matrix_minimum.csv written to working folder.
SWATH2stats::plot_correlation_between_samples(s2s_exp,
                                              column.values="RT",
                                              fun.aggregate=sum)
## Warning: Ignoring unknown aesthetics: fill

##           Var1         Var2  value   method
## 1    wt_cf_mar    wt_cf_mar 1.0000  pearson
## 3    wt_cf_mar wt_whole_mar 0.3573  pearson
## 4 wt_whole_mar wt_whole_mar 1.0000  pearson
## 6 wt_whole_mar    wt_cf_mar 0.2628 spearman
## I have no effing clue what this plot means.
variation <- SWATH2stats::plot_variation(s2s_exp, fun.aggregate=sum,
                                         Comparison=transition_group_id ~ Condition)

## Something in SWATH2stats::disaggregate was written poorly and is looking for
## a variable named 'cols'
cols <- colnames(only_minimum)
disaggregated <- SWATH2stats::disaggregate(only_minimum, all.columns=TRUE)
## The library contains between 4 and 6 transitions per precursor.
## The data table was transformed into a table containing one row per transition.
msstats_input <- SWATH2stats::convert4MSstats(disaggregated)
## One or several columns required by MSstats were not in the data. The columns were created and filled with NAs.
## Missing columns: ProductCharge, IsotopeLabelType
## IsotopeLabelType was filled with light.
alfq_input <- sm(SWATH2stats::convert4aLFQ(disaggregated))
mapdia_input <- sm(SWATH2stats::convert4mapDIA(disaggregated, RT=TRUE))

3.1 MSstats

msstats.org seems to provide a complete solution for performing reasonable metrics of this data.

I am currently reading: http://msstats.org/wp-content/uploads/2017/01/MSstats_v3.7.3_manual.pdf

I made some moderately intrusive changes to MSstats to make it clearer, as well.

devtools::load_all("~/scratch/git/MSstats")
## Loading MSstats
## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)

## Warning: character(0)
msstats_quant <- sm(MSstats::dataProcess(msstats_input))

msstats_plots <- sm(MSstats::dataProcessPlots(msstats_quant, type="QCPLOT"))

my_levels <- levels(as.factor(msstats_input$Condition))
my_levels
## [1] "wt_cf"    "wt_whole"
comparison <- ghetto_contrast_matrix("wt_cf", "wt_whole")
msstats_comparison <- sm(MSstats::groupComparison(contrast.matrix=comparison,
                                                  data=msstats_quant))

3.2 Do the same comparison with the modified data.

## I want to test a hypothesis about the effect of 0/NA on the data, so I am replacing them with
## 2, which should give me a minimal value for all the log2fc calculations to work with.
msstats_modified <- msstats_quant
abundances <- msstats_quant$ProcessedData[["ABUNDANCE"]]
na_idx <- is.na(abundances)
msstats_modified$ProcessedData[na_idx, "ABUNDANCE"] <- 2
msstats_modified_comp <- sm(MSstats::groupComparison(contrast.matrix=comparison,
                                                     data=msstats_modified))

3.2.1 P/PE protein QC plots for Yan

Yan asked for the p/pe protein qc plots. ok. I changed the dataProcessPlots to return something useful, so that should be possible now.

pe_genes <- read.table("reference/annotated_pe_genes.txt")[[1]]

## Unfortunately, the names did not get set in my changed version of dataProcessPlots...
plotlst <- msstats_plots$QCPLOT
available_plots <- gsub(pattern="^1/", replacement="", x=levels(msstats_quant$ProcessedData$PROTEIN))
names(plotlst) <- available_plots

pe_in_avail_idx <- pe_genes %in% available_plots
pe_in_avail <- pe_genes[pe_in_avail_idx]
pe_plots <- plotlst[pe_in_avail]
pdf(file="pe_qc_plots.pdf")
for (p in 1:length(pe_plots)) {
  plot(pe_plots[[p]])
}
## Warning: Removed 114 rows containing non-finite values (stat_boxplot).
## Warning: Removed 108 rows containing non-finite values (stat_boxplot).
## Warning: Removed 12 rows containing non-finite values (stat_boxplot).
## Warning: Removed 174 rows containing non-finite values (stat_boxplot).
## Warning: Removed 240 rows containing non-finite values (stat_boxplot).
## Warning: Removed 138 rows containing non-finite values (stat_boxplot).
## Warning: Removed 66 rows containing non-finite values (stat_boxplot).
## Warning: Removed 89 rows containing non-finite values (stat_boxplot).
dev.off()
## png 
##   2

4 Create hpgltools expressionset

Since I am not certain I understand these data, I will take the intensities from SWATH2stats, metadata, and annotation data; attempt to create a ‘normal’ expressionset; poke at it to see what I can learn.

4.1 Massaging the metadata

I want to use the same metadata as were used for MSstats. It has a few important differences from the requirements of hpgltools: pretty much only that I do not allow rownames/sampleIDs to start with a number.

metadata <- sample_annot
metadata[["sampleid"]] <- paste0("s", metadata[["sampleid"]])
rownames(metadata) <- metadata[["sampleid"]]

4.2 Massaging the gene annotation data and adding the msstats data.

I have my own annotation data from the gff file/microbesonline/whatever, I can add the MSstats result to it so that later I can print them all together.

## Here is a neat little thing I can do:  Add the MSstats results to my annotation data.
## Then when I print out the tables of the limma/etc results, they MSstats
## results will come along for free.
msstats_table <- msstats_comparison[["ComparisonResult"]]
rownames(msstats_table) <- gsub(pattern="^1\\/", replacement="",
                                x=msstats_table[["Protein"]])
mtb_annotations_with_msstats <- merge(mtb_annotations, msstats_table,
                                      by="row.names", all.x=TRUE)
rownames(mtb_annotations_with_msstats) <- mtb_annotations_with_msstats[["Row.names"]]
mtb_annotations_with_msstats <- mtb_annotations_with_msstats[, -1]

msstats_table_modified <- msstats_modified_comp[["ComparisonResult"]]
rownames(msstats_table_modified) <- gsub(pattern="^1\\/", replacement="",
                                         x=msstats_table_modified[["Protein"]])
mtb_annotations_with_modified_msstats <- merge(mtb_annotations, msstats_table_modified,
                                               by="row.names", all.x=TRUE)
rownames(mtb_annotations_with_modified_msstats) <- mtb_annotations_with_modified_msstats[["Row.names"]]
mtb_annotations_with_modified_msstats <- mtb_annotations_with_modified_msstats[, -1]

4.3 Massaging the intensity matrix

I do not want the before the protein names, I already merged them into one entry per gene vis SWATH2stats.

prot_mtrx <- read.csv("swath2stats_protein_matrix_mscore.csv")
rownames(prot_mtrx) <- gsub(pattern="^1\\/", replacement="", x=prot_mtrx[["ProteinName"]])
prot_mtrx <- prot_mtrx[, -1]
## Important question: Did SWATH2stats reorder my data?
fun <- gsub(pattern="^.*_(2018.*$)", replacement="\\1", x=colnames(prot_mtrx))
colnames(prot_mtrx) <- paste0("s", fun)

decoy_idx <- ! grepl(pattern="DECOY", x=rownames(prot_mtrx))
prot_mtrx <- prot_mtrx[decoy_idx, ]

prot_mtrx_modified <- prot_mtrx
zero_idx <- prot_mtrx == 0
prot_mtrx_modified[zero_idx] <- 2

4.4 Merge the pieces

Now we should have sufficient pieces to make an expressionset.

## Drop the metadata not in the protein matrix:
## And ensure that they are the same order.
reordered <- colnames(prot_mtrx)
metadata <- metadata[reordered, ]

protein_expt <- create_expt(metadata,
                            count_dataframe=prot_mtrx,
                            gene_info=mtb_annotations_with_msstats)
## Reading the sample metadata.
## The sample definitions comprises: 17, 15 rows, columns.
## Matched 1708 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
protein_modified_expt <- create_expt(metadata,
                                     count_dataframe=prot_mtrx_modified,
                                     gene_info=mtb_annotations_with_modified_msstats)
## Reading the sample metadata.
## The sample definitions comprises: 17, 15 rows, columns.
## Matched 1708 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
protein_metrics <- sm(graph_metrics(protein_expt))
protein_norm <- sm(normalize_expt(protein_expt, transform="log2", convert="cpm",
                                  norm="quant", filter=TRUE))
protein_norm_metrics <- sm(graph_metrics(protein_norm))
protein_metrics$libsize

protein_norm_metrics$pcaplot

5 Attempt some quantification comparisons?

pairwise_filt <- sm(normalize_expt(protein_expt, filter=TRUE))
pairwise_comp <- all_pairwise(pairwise_filt, parallel=FALSE, force=TRUE)
## Using limma's removeBatchEffect to visualize before/after batch inclusion.
## Starting limma pairwise comparison.
## Leaving the data alone, regardless of normalization state.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Limma step 1/6: choosing model.
## Choosing the non-intercept containing model.
## Limma step 2/6: running limma::voom(), switch with the argument 'which_voom'.
## Using normalize.method=quantile for voom.
## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## Limma step 5/6: Running eBayes with robust=FALSE and trend=FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/1: Creating table: wt_whole_vs_wt_cf.  Adjust=BH
## Limma step 6/6: 1/2: Creating table: wt_cf.  Adjust=BH
## Limma step 6/6: 2/2: Creating table: wt_whole.  Adjust=BH
## Starting DESeq2 pairwise comparisons.
## About to round the data, this is a pretty terrible thing to do. But if you,
## like me, want to see what happens when you put non-standard data into deseq, then here you go.
## Warning in choose_binom_dataset(input, force = force): This data was inappropriately
## forced into integers.
## Choosing the non-intercept containing model.
## DESeq2 step 1/5: Including batch and condition in the deseq model.
## Warning in import_deseq(data, column_data, model_string, tximport = input[["tximport"]]
## [["raw"]]): Converted down 1458 elements because they are larger than the maximum integer
## size.
## converting counts to integer mode
## DESeq2 step 2/5: Estimate size factors.
## DESeq2 step 3/5: Estimate dispersions.
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## Using a parametric fitting seems to have worked.
## DESeq2 step 4/5: nbinomWaldTest.
## Plotting dispersions.

## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Starting edgeR pairwise comparisons.
## About to round the data, this is a pretty terrible thing to do. But if you,
## like me, want to see what happens when you put non-standard data into deseq, then here you go.
## Warning in choose_binom_dataset(input, force = force): This data was inappropriately
## forced into integers.
## Choosing the non-intercept containing model.
## EdgeR step 1/9: importing and normalizing data.
## EdgeR step 2/9: Estimating the common dispersion.
## EdgeR step 3/9: Estimating dispersion across genes.
## EdgeR step 4/9: Estimating GLM Common dispersion.
## EdgeR step 5/9: Estimating GLM Trended dispersion.
## EdgeR step 6/9: Estimating GLM Tagged dispersion.
## EdgeR step 7/9: Running glmFit, switch to glmQLFit by changing the argument 'edger_test'.
## EdgeR step 8/9: Making pairwise contrasts.

## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Starting basic pairwise comparison.
## Leaving the data alone, regardless of normalization state.
## Basic step 0/3: Transforming data.
## Basic step 1/3: Creating median and variance tables.
## Basic step 2/3: Performing 3 comparisons.
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Basic step 3/3: Creating faux DE Tables.
## Basic: Returning tables.
## Comparing analyses 1/1: wt_whole_vs_wt_cf

keepers <- list("filtrate_vs_cells" = c("wt_cf", "wt_whole"))
pairwise_tables <- combine_de_tables(pairwise_comp,
                                     excel="excel/test_pairwise_de_with_msstats.xlsx",
                                     keepers=keepers)
## Deleting the file excel/test_pairwise_de_with_msstats.xlsx before writing the tables.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/1: filtrate_vs_cells
## Found inverse table with wt_whole_vs_wt_cf
## Adding venn plots for wt_cf_vs_wt_whole.

## Limma expression coefficients for wt_cf_vs_wt_whole; R^2: 0.433; equation: y = 0.562x - 0.965
## Edger expression coefficients for wt_cf_vs_wt_whole; R^2: 0.461; equation: y = 1.42x - 25
## DESeq2 expression coefficients for wt_cf_vs_wt_whole; R^2: 0.408; equation: y = 1.4x - 23.5
## Writing summary information.
## Attempting to add the comparison plot to pairwise_summary at row: 19 and column: 1
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Performing save of the workbook.

droppers <- c("undefined")
names(droppers) <- "log2fc"
pairwise_onlyall <- combine_de_tables(pairwise_comp,
                                      excel="excel/test_pairwise_de_only_msstats.xlsx",
                                      keepers=keepers,
                                      excludes=droppers)
## Deleting the file excel/test_pairwise_de_only_msstats.xlsx before writing the tables.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/1: filtrate_vs_cells
## Found inverse table with wt_whole_vs_wt_cf
## Removed 741261 genes using undefined as a string against column log2fc.
## Adding venn plots for wt_cf_vs_wt_whole.

## Limma expression coefficients for wt_cf_vs_wt_whole; R^2: 0.433; equation: y = 0.562x - 0.965
## Edger expression coefficients for wt_cf_vs_wt_whole; R^2: 0.461; equation: y = 1.42x - 25
## DESeq2 expression coefficients for wt_cf_vs_wt_whole; R^2: 0.408; equation: y = 1.4x - 23.5
## Writing summary information.
## Attempting to add the comparison plot to pairwise_summary at row: 19 and column: 1
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Performing save of the workbook.

pairwise_sig <- sm(extract_significant_genes(pairwise_tables,
                                             excel="excel/test_pairwise_sig_with_msstats.xlsx"))

solo_proteins <- features_in_single_condition(protein_expt)
proteins_only_cf <- solo_proteins[["solo_this"]][["wt_cf"]]
proteins_only_cf
##  [1] "Rv0116c" "Rv0256c" "Rv0398c" "Rv1184c" "Rv2080"  "Rv2240c" "Rv2623"  "Rv2668" 
##  [9] "Rv3312A" "Rv3568c"
proteins_only_whole <- solo_proteins[["solo_this"]][["wt_whole"]]
length(proteins_only_whole)
## [1] 788
pairwise_modified_comp <- all_pairwise(protein_modified_expt, parallel=FALSE, force=TRUE)
## Using limma's removeBatchEffect to visualize before/after batch inclusion.
## Starting limma pairwise comparison.
## Leaving the data alone, regardless of normalization state.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$libsize.
## Limma step 1/6: choosing model.
## Choosing the non-intercept containing model.
## Limma step 2/6: running limma::voom(), switch with the argument 'which_voom'.
## Using normalize.method=quantile for voom.
## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## Limma step 5/6: Running eBayes with robust=FALSE and trend=FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/1: Creating table: wt_whole_vs_wt_cf.  Adjust=BH
## Limma step 6/6: 1/2: Creating table: wt_cf.  Adjust=BH
## Limma step 6/6: 2/2: Creating table: wt_whole.  Adjust=BH
## Starting DESeq2 pairwise comparisons.
## About to round the data, this is a pretty terrible thing to do. But if you,
## like me, want to see what happens when you put non-standard data into deseq, then here you go.
## Warning in choose_binom_dataset(input, force = force): This data was inappropriately
## forced into integers.
## Choosing the non-intercept containing model.
## DESeq2 step 1/5: Including batch and condition in the deseq model.
## Warning in import_deseq(data, column_data, model_string, tximport = input[["tximport"]]
## [["raw"]]): Converted down 1458 elements because they are larger than the maximum integer
## size.
## converting counts to integer mode
## DESeq2 step 2/5: Estimate size factors.
## DESeq2 step 3/5: Estimate dispersions.
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## Using a parametric fitting seems to have worked.
## DESeq2 step 4/5: nbinomWaldTest.
## Plotting dispersions.

## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Starting edgeR pairwise comparisons.
## About to round the data, this is a pretty terrible thing to do. But if you,
## like me, want to see what happens when you put non-standard data into deseq, then here you go.
## Warning in choose_binom_dataset(input, force = force): This data was inappropriately
## forced into integers.
## Choosing the non-intercept containing model.
## EdgeR step 1/9: importing and normalizing data.
## EdgeR step 2/9: Estimating the common dispersion.
## EdgeR step 3/9: Estimating dispersion across genes.
## EdgeR step 4/9: Estimating GLM Common dispersion.
## EdgeR step 5/9: Estimating GLM Trended dispersion.
## EdgeR step 6/9: Estimating GLM Tagged dispersion.
## EdgeR step 7/9: Running glmFit, switch to glmQLFit by changing the argument 'edger_test'.
## EdgeR step 8/9: Making pairwise contrasts.

## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Starting basic pairwise comparison.
## Leaving the data alone, regardless of normalization state.
## Basic step 0/3: Transforming data.
## Basic step 1/3: Creating median and variance tables.
## Basic step 2/3: Performing 3 comparisons.
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Basic step 3/3: Creating faux DE Tables.
## Basic: Returning tables.
## Comparing analyses 1/1: wt_whole_vs_wt_cf

pairwise_modified_tables <- combine_de_tables(pairwise_modified_comp,
                                              excel="excel/test_pairwise_modified_de_with_msstats.xlsx",
                                              keepers=keepers)
## Deleting the file excel/test_pairwise_modified_de_with_msstats.xlsx before writing the tables.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/1: filtrate_vs_cells
## Found inverse table with wt_whole_vs_wt_cf
## Adding venn plots for wt_cf_vs_wt_whole.

## Limma expression coefficients for wt_cf_vs_wt_whole; R^2: 0.438; equation: y = 0.547x - 0.718
## Edger expression coefficients for wt_cf_vs_wt_whole; R^2: 0.247; equation: y = 0.966x - 6.19
## DESeq2 expression coefficients for wt_cf_vs_wt_whole; R^2: 0.199; equation: y = 0.861x + 2.28
## Writing summary information.
## Attempting to add the comparison plot to pairwise_summary at row: 19 and column: 1
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Performing save of the workbook.

droppers <- c("undefined")
names(droppers) <- "log2fc"
pairwise_modified_onlyall <- combine_de_tables(pairwise_modified_comp,
                                               excel="excel/test_pairwise_de_only_msstats.xlsx",
                                               keepers=keepers,
                                               excludes=droppers)
## Deleting the file excel/test_pairwise_de_only_msstats.xlsx before writing the tables.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/1: filtrate_vs_cells
## Found inverse table with wt_whole_vs_wt_cf
## Removed 770556 genes using undefined as a string against column log2fc.
## Adding venn plots for wt_cf_vs_wt_whole.

## Limma expression coefficients for wt_cf_vs_wt_whole; R^2: 0.438; equation: y = 0.547x - 0.718
## Edger expression coefficients for wt_cf_vs_wt_whole; R^2: 0.247; equation: y = 0.966x - 6.19
## DESeq2 expression coefficients for wt_cf_vs_wt_whole; R^2: 0.199; equation: y = 0.861x + 2.28
## Writing summary information.
## Attempting to add the comparison plot to pairwise_summary at row: 19 and column: 1
## 
  |                                                                                      
  |                                                                                |   0%
  |                                                                                      
  |================================================================================| 100%
## Performing save of the workbook.

pairwise_modified_sig <- sm(extract_significant_genes(
  pairwise_modified_tables,
  excel="excel/test_pairwise_modified_sig_with_msstats.xlsx"))

5.1 Compare hpgltools/MSstats

Can we compare limma and riends to MSstats?

hpgl_table <- pairwise_tables$data[[1]]
msstats_table <- msstats_comparison$ComparisonResult
rownames(msstats_table) <- gsub(pattern="^1/", replacement="", x=msstats_table$Protein)

merged_table <- merge(hpgl_table, msstats_table, by="row.names")
write.csv(file="images/merged_table.csv", merged_table)
cor.test(merged_table$limma_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$limma_logfc and merged_table$log2FC
## t = 35, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7290 0.7844
## sample estimates:
##    cor 
## 0.7581
cor.test(merged_table$limma_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$limma_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$limma_logfc and merged_table$log2FC
## S = 2.9e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.7698
cor.test(merged_table$deseq_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$deseq_logfc and merged_table$log2FC
## t = 15, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3832 0.4885
## sample estimates:
##    cor 
## 0.4374
cor.test(merged_table$deseq_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$deseq_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$deseq_logfc and merged_table$log2FC
## S = 3.9e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.6907
cor.test(merged_table$edger_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$edger_logfc and merged_table$log2FC
## t = 16, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4117 0.5139
## sample estimates:
##    cor 
## 0.4643
cor.test(merged_table$edger_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$edger_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$edger_logfc and merged_table$log2FC
## S = 3.4e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.7282
combined_table <- pairwise_tables$data[[1]]
undefined_idx <- combined_table[["log2fc"]] == "undefined"
combined_table[undefined_idx, "log2fc"] <- NA
combined_table[["log2fc"]] <- as.numeric(combined_table[["log2fc"]])
cor.test(combined_table[["limma_logfc"]], combined_table[["log2fc"]])
## 
##  Pearson's product-moment correlation
## 
## data:  combined_table[["limma_logfc"]] and combined_table[["log2fc"]]
## t = 35, df = 900, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7272 0.7830
## sample estimates:
##    cor 
## 0.7565
cor.test(combined_table[["limma_logfc"]], combined_table[["log2fc"]], method="spearman")
## Warning in cor.test.default(combined_table[["limma_logfc"]], combined_table[["log2fc"]], :
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  combined_table[["limma_logfc"]] and combined_table[["log2fc"]]
## S = 2.9e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##   rho 
## 0.769
high_to_low_idx <- order(combined_table[["log2fc"]], na.last=TRUE, decreasing=TRUE)
low_to_high_idx <- order(combined_table[["log2fc"]], na.last=TRUE, decreasing=FALSE)
top_50 <- head(combined_table[high_to_low_idx, ], n=100)
bottom_50 <- head(combined_table[low_to_high_idx, ], n=100)

cor.test(top_50$limma_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$limma_logfc and top_50$log2fc
## t = 7.1, df = 98, p-value = 2e-10
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4342 0.6978
## sample estimates:
##    cor 
## 0.5811
cor.test(top_50$limma_logfc, top_50$log2fc, method="spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$limma_logfc and top_50$log2fc
## S = 70000, p-value = 5e-11
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.5802
cor.test(top_50$deseq_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$deseq_logfc and top_50$log2fc
## t = 5.3, df = 98, p-value = 6e-07
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3074 0.6142
## sample estimates:
##    cor 
## 0.4751
cor.test(top_50$deseq_logfc, top_50$log2fc, method="spearman")
## Warning in cor.test.default(top_50$deseq_logfc, top_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$deseq_logfc and top_50$log2fc
## S = 19000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.8865
cor.test(top_50$edger_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$edger_logfc and top_50$log2fc
## t = 6.5, df = 98, p-value = 3e-09
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3960 0.6734
## sample estimates:
##    cor 
## 0.5497
cor.test(top_50$edger_logfc, top_50$log2fc, method="spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$edger_logfc and top_50$log2fc
## S = 15000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.9088
cor.test(bottom_50$limma_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$limma_logfc and bottom_50$log2fc
## t = 1.8, df = 98, p-value = 0.08
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.01932  0.36157
## sample estimates:
##    cor 
## 0.1778
cor.test(bottom_50$limma_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$limma_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$limma_logfc and bottom_50$log2fc
## S = 130000, p-value = 0.04
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.2049
cor.test(bottom_50$deseq_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$deseq_logfc and bottom_50$log2fc
## t = -0.27, df = 98, p-value = 0.8
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.2225  0.1701
## sample estimates:
##      cor 
## -0.02726
cor.test(bottom_50$deseq_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$deseq_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$deseq_logfc and bottom_50$log2fc
## S = 150000, p-value = 0.4
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##     rho 
## 0.08359
cor.test(bottom_50$edger_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$edger_logfc and bottom_50$log2fc
## t = 0.11, df = 98, p-value = 0.9
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.1856  0.2072
## sample estimates:
##     cor 
## 0.01123
cor.test(bottom_50$edger_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$edger_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$edger_logfc and bottom_50$log2fc
## S = 140000, p-value = 0.2
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.1402
up_in_msstats <- rownames(combined_table)[combined_table[["log2fc"]] > 0]
up_in_msstats <- up_in_msstats[!is.na(up_in_msstats)]
up_in_limma <- rownames(combined_table)[combined_table[["limma_logfc"]] > 0]
up_in_limma <- up_in_limma[!is.na(up_in_limma)]
up_in_edger <- rownames(combined_table)[combined_table[["edger_logfc"]] > 0]
up_in_edger <- up_in_edger[!is.na(up_in_edger)]
up_venn_sets <- list(
  "msstats" = up_in_msstats,
  "limma" = up_in_limma,
  "edger" = up_in_edger)
testing <- Vennerable::Venn(Sets=up_venn_sets, )
pp(file="/tmp/up_venn.png")
## Going to write the image to: /tmp/up_venn.png when dev.off() is called.
Vennerable::plot(testing, doWeights=FALSE)
dev.off()
## png 
##   2
Vennerable::plot(testing, doWeights=FALSE)

down_in_msstats <- rownames(combined_table)[combined_table[["log2fc"]] < 0]
down_in_msstats <- down_in_msstats[!is.na(down_in_msstats)]
down_in_limma <- rownames(combined_table)[combined_table[["limma_logfc"]] < 0]
down_in_limma <- down_in_limma[!is.na(down_in_limma)]
down_in_edger <- rownames(combined_table)[combined_table[["edger_logfc"]] < 0]
down_in_edger <- down_in_edger[!is.na(down_in_edger)]
down_venn_sets <- list(
  "msstats" = down_in_msstats,
  "limma" = down_in_limma,
  "edger" = down_in_edger)
testing <- Vennerable::Venn(Sets=down_venn_sets, )
pp(file="/tmp/down_venn.png")
## Going to write the image to: /tmp/down_venn.png when dev.off() is called.
Vennerable::plot(testing, doWeights=FALSE)
dev.off()
## png 
##   2

6 Repeat with the modified data

hpgl_table <- pairwise_modified_tables$data[[1]]
msstats_table <- msstats_modified_comp$ComparisonResult
rownames(msstats_table) <- gsub(pattern="^1/", replacement="", x=msstats_table_modified$Protein)

merged_table <- merge(hpgl_table, msstats_table, by="row.names")
write.csv(file="images/merged_table_modified.csv", merged_table)
cor.test(merged_table$limma_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$limma_logfc and merged_table$log2FC
## t = 36, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7375 0.7914
## sample estimates:
##    cor 
## 0.7658
cor.test(merged_table$limma_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$limma_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$limma_logfc and merged_table$log2FC
## S = 2.8e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.7768
cor.test(merged_table$deseq_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$deseq_logfc and merged_table$log2FC
## t = 18, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4648 0.5606
## sample estimates:
##    cor 
## 0.5143
cor.test(merged_table$deseq_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$deseq_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$deseq_logfc and merged_table$log2FC
## S = 3.8e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.6923
cor.test(merged_table$edger_logfc, merged_table$log2FC)
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table$edger_logfc and merged_table$log2FC
## t = 18, df = 910, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4744 0.5690
## sample estimates:
##    cor 
## 0.5233
cor.test(merged_table$edger_logfc, merged_table$log2FC, method="spearman")
## Warning in cor.test.default(merged_table$edger_logfc, merged_table$log2FC, : Cannot
## compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  merged_table$edger_logfc and merged_table$log2FC
## S = 3.3e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.7357
combined_table <- pairwise_tables$data[[1]]
undefined_idx <- combined_table[["log2fc"]] == "undefined"
combined_table[undefined_idx, "log2fc"] <- NA
combined_table[["log2fc"]] <- as.numeric(combined_table[["log2fc"]])
cor.test(combined_table[["limma_logfc"]], combined_table[["log2fc"]])
## 
##  Pearson's product-moment correlation
## 
## data:  combined_table[["limma_logfc"]] and combined_table[["log2fc"]]
## t = 35, df = 900, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7272 0.7830
## sample estimates:
##    cor 
## 0.7565
cor.test(combined_table[["limma_logfc"]], combined_table[["log2fc"]], method="spearman")
## Warning in cor.test.default(combined_table[["limma_logfc"]], combined_table[["log2fc"]], :
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  combined_table[["limma_logfc"]] and combined_table[["log2fc"]]
## S = 2.9e+07, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##   rho 
## 0.769
high_to_low_idx <- order(combined_table[["log2fc"]], na.last=TRUE, decreasing=TRUE)
low_to_high_idx <- order(combined_table[["log2fc"]], na.last=TRUE, decreasing=FALSE)
top_50 <- head(combined_table[high_to_low_idx, ], n=100)
bottom_50 <- head(combined_table[low_to_high_idx, ], n=100)

cor.test(top_50$limma_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$limma_logfc and top_50$log2fc
## t = 7.1, df = 98, p-value = 2e-10
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.4342 0.6978
## sample estimates:
##    cor 
## 0.5811
cor.test(top_50$limma_logfc, top_50$log2fc, method="spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$limma_logfc and top_50$log2fc
## S = 70000, p-value = 5e-11
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.5802
cor.test(top_50$deseq_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$deseq_logfc and top_50$log2fc
## t = 5.3, df = 98, p-value = 6e-07
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3074 0.6142
## sample estimates:
##    cor 
## 0.4751
cor.test(top_50$deseq_logfc, top_50$log2fc, method="spearman")
## Warning in cor.test.default(top_50$deseq_logfc, top_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$deseq_logfc and top_50$log2fc
## S = 19000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.8865
cor.test(top_50$edger_logfc, top_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  top_50$edger_logfc and top_50$log2fc
## t = 6.5, df = 98, p-value = 3e-09
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.3960 0.6734
## sample estimates:
##    cor 
## 0.5497
cor.test(top_50$edger_logfc, top_50$log2fc, method="spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  top_50$edger_logfc and top_50$log2fc
## S = 15000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.9088
cor.test(bottom_50$limma_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$limma_logfc and bottom_50$log2fc
## t = 1.8, df = 98, p-value = 0.08
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.01932  0.36157
## sample estimates:
##    cor 
## 0.1778
cor.test(bottom_50$limma_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$limma_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$limma_logfc and bottom_50$log2fc
## S = 130000, p-value = 0.04
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.2049
cor.test(bottom_50$deseq_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$deseq_logfc and bottom_50$log2fc
## t = -0.27, df = 98, p-value = 0.8
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.2225  0.1701
## sample estimates:
##      cor 
## -0.02726
cor.test(bottom_50$deseq_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$deseq_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$deseq_logfc and bottom_50$log2fc
## S = 150000, p-value = 0.4
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##     rho 
## 0.08359
cor.test(bottom_50$edger_logfc, bottom_50$log2fc)
## 
##  Pearson's product-moment correlation
## 
## data:  bottom_50$edger_logfc and bottom_50$log2fc
## t = 0.11, df = 98, p-value = 0.9
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.1856  0.2072
## sample estimates:
##     cor 
## 0.01123
cor.test(bottom_50$edger_logfc, bottom_50$log2fc, method="spearman")
## Warning in cor.test.default(bottom_50$edger_logfc, bottom_50$log2fc, method = "spearman"):
## Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  bottom_50$edger_logfc and bottom_50$log2fc
## S = 140000, p-value = 0.2
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.1402
up_in_msstats <- rownames(combined_table)[combined_table[["log2fc"]] > 0]
up_in_msstats <- up_in_msstats[!is.na(up_in_msstats)]
up_in_limma <- rownames(combined_table)[combined_table[["limma_logfc"]] > 0]
up_in_limma <- up_in_limma[!is.na(up_in_limma)]
up_in_edger <- rownames(combined_table)[combined_table[["edger_logfc"]] > 0]
up_in_edger <- up_in_edger[!is.na(up_in_edger)]
up_venn_sets <- list(
  "msstats" = up_in_msstats,
  "limma" = up_in_limma,
  "edger" = up_in_edger)
testing <- Vennerable::Venn(Sets=up_venn_sets, )
pp(file="/tmp/up_venn.png")
## Going to write the image to: /tmp/up_venn.png when dev.off() is called.
Vennerable::plot(testing, doWeights=FALSE)
dev.off()
## png 
##   2
Vennerable::plot(testing, doWeights=FALSE)

down_in_msstats <- rownames(combined_table)[combined_table[["log2fc"]] < 0]
down_in_msstats <- down_in_msstats[!is.na(down_in_msstats)]
down_in_limma <- rownames(combined_table)[combined_table[["limma_logfc"]] < 0]
down_in_limma <- down_in_limma[!is.na(down_in_limma)]
down_in_edger <- rownames(combined_table)[combined_table[["edger_logfc"]] < 0]
down_in_edger <- down_in_edger[!is.na(down_in_edger)]
down_venn_sets <- list(
  "msstats" = down_in_msstats,
  "limma" = down_in_limma,
  "edger" = down_in_edger)
testing <- Vennerable::Venn(Sets=down_venn_sets, )
pp(file="/tmp/down_venn.png")
## Going to write the image to: /tmp/down_venn.png when dev.off() is called.
Vennerable::plot(testing, doWeights=FALSE)
dev.off()
## png 
##   2

7 Everything below here might get dropped?

I think I wedged all of the following work into that short block above. So, stop evaluating the following blocks and see if that is true.

7.0.1 Expressionset from the TRIC intensity matrix

intensity_mtrx <- read.csv(file="results/tric/HCD_outmatrix.tsv", sep="\t")
## The HCD_outmatrix has columns including: Peptide, Protein,
## A series of Intensity_sample_id columns
## A series of RT_sample_id columns
## A series of score_sample_id columns
## And at the end: RT_mean, RT_std, and pg_pvalue.
## Since SWATH2stats/MSstats uses the intensities, lets get those columns out,
## standardize the column names to match the annotation data, and use them for
## creating an expressionset.
intensity_mtrx[["rownames"]] <- intensity_mtrx[["Protein"]]
intensity_mtrx[["rownames"]] <- gsub(pattern="^[[:digit:]]+\\/",
                                     replacement="", x=intensity_mtrx[["rownames"]])
## Standardize the rownames, this might be a bad idea, as this will keep
## separate every peptide from each protein and not do anything to
## sum/median/whatever them.  But for the purposes of testing out the data I
## think it is ok.
rownames(intensity_mtrx) <- make.names(intensity_mtrx[["rownames"]], unique=TRUE)

## Now lets get rid of the extraneous text in the column names and simplify them
## to the sample names as referenced in the sample sheet.
all_columns <- colnames(intensity_mtrx)
intense_columns <- grepl(pattern="Intensity", x=all_columns)
intensity_mtrx <- intensity_mtrx[, intense_columns]
all_columns <- colnames(intensity_mtrx)
new_columns <- gsub(pattern="Intensity_", replacement="", x=all_columns)
new_columns <- gsub(pattern="_dia_.*$", replacement="", x=new_columns)
colnames(intensity_mtrx) <- paste0("s", new_columns)
intensity_mtrx[is.na(intensity_mtrx)] <- 0

## No columns in an expression set are allowed to start with a number.  I have
## unsed prefixing samples with 's' as a standard to handle this problem...
metadata <- sample_annot
metadata$sampleid <- paste0("s", metadata$sampleid)
colnames(intensity_mtrx) <- gsub(pattern="_vs_HCD", replacement="", x=colnames(intensity_mtrx))
rownames(metadata) <- metadata$sampleid
## Theoretically this is not needed anymore...
intensity_mtrx <- intensity_mtrx[, rownames(metadata)]
## Ok, at this point, we should have all the pieces for a more or less normal expressionset.
dim(intensity_mtrx)
test_expt <- create_expt(metadata=metadata,
                         count_dataframe=intensity_mtrx,
                         gene_info=mtb_annotations)

7.0.2 Play with the hpgltools derived expressionset of peptide intensities

Lets see if anything makes sense in this intensity expressionset.

## First, log2 and normalize the data.
test_norm <- normalize_expt(test_expt, transform="log2", convert="cpm", norm="quantile", filter=TRUE)
test_normbatch <- sm(normalize_expt(test_expt, transform="log2", convert="cpm",
                                    norm="quantile", filter=TRUE, batch="limma"))

test_metrics <- sm(graph_metrics(test_expt))
test_metrics_norm <- sm(graph_metrics(test_norm))
test_metrics_normbatch <- sm(graph_metrics(test_normbatch))

Now lets see what the data looks like, assuming I did not do anything horrible to it.

test_metrics$legend
test_metrics$libsize  ## Wow the intensities get ridiculous, what?
test_metrics$nonzero
## Interesting, but nothing which super-jumps out at me
test_metrics$density
## hmm very interesting, the good news is that they all have basically the same
## distribution.  I did not expect the CF samples to have such a stronger
## distribution though.

test_metrics_norm$corheat
## This suggests to me a likely batch effect
test_metrics_norm$disheat
test_metrics$smc
test_metrics$tsneplot
## Yeah there is some wonkyness between the old/new samples.

test_metrics_normbatch$pcaplot
## Wow, this is after invoking 'removeBatchEffect' from limma.  That suggests
## pretty strongly to me that we should probalby not examine the new and old
## data together.  In addition I am thinking that one whole-cell lysate sample
## might not be.

7.1 Remove old batch/weirdo sample

kept_testing <- subset_expt(test_expt,
                            subset="bioreplicate == 'mar'")
## The new batch IDs: x,y,z are associated with the 3 runs of these samples, one
## which is 8 m/z, one which is 20 m/z, and one which is a reordered 20 m/z.

test_norm <- normalize_expt(kept_testing, transform="log2", convert="cpm", norm="quantile", filter=TRUE)
test_normbatch <- sm(normalize_expt(kept_testing, transform="log2", convert="cpm",
                                    filter=TRUE, batch="limma"))
new_metrics <- sm(graph_metrics(kept_testing))
new_metrics_norm <- sm(graph_metrics(test_norm))
new_metrics_normbatch <- sm(graph_metrics(test_normbatch))

7.1.1 Plot only new data

Removing the January data seems to have made this a lot easier to look at. There might be some batchyness associated with reordering the samples, but I am thinking it is not huge.

tt = plot_topn(kept_testing, direct=TRUE)
new_metrics$legend
new_metrics$libsize
pp("images/kept_norm_topn.png", image=new_metrics$topnplot)
pp("images/kept_norm_hcd_pca.png", image=new_metrics_norm$pcaplot)
new_metrics_norm$tsneplot
pp("images/kept_norm_hcd_corheat.png", image=new_metrics_norm$corheat)
new_metrics_norm$disheat
new_metrics_normbatch$pcaplot
pp("images/normbatch_tsne.png", image=new_metrics_normbatch$tsneplot)

7.1.2 How is the variance?

Lets see what variancePartition has to say about this data.

new_varpart <- varpart(kept_testing, factors=c("condition", "batch"))
pp("images/varpart_partition.png", image=new_varpart$partition_plot)
## That is not terrible.

## the modified_expt slow from varpart() adds some metadata to the expressionset
## including the calculated % variance for condition/batch/residual for each peptide.
kept_testing <- new_varpart$modified_expt

7.2 Back to hpgltools

If you will recall, in the original block where I read the data into SWATH2stats, I invoked write_matrix_proteins() and write_matrix_peptides() and wrote out 2 csv files ‘swath2stats_protein_matrix.csv’ and ’_peptide_matrix.csv’. If my earlier work is correct, I should be able to use the protein matrix to get a truer sense of the relative abundances between my experimental conditions.

library(aLFQ)
alfq_process <- ProteinInference(alfq_input,
                                 peptide_method="top",
                                 peptide_topx=3,
                                 peptide_strictness="loose",
                                 peptide_summary="mean",
                                 transition_topx=3,
                                 transition_strictness="loose",
                                 transition_summary="sum",
                                 fasta=NA,
                                 model=NA,
                                 combine_precursors=FALSE)

8 Index version: 20180215

9 TODO

  • 2018-04-10: Make sure my invocations of SWATH2stats/MSstats are correct.
if (!isTRUE(get0("skip_load"))) {
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
  message(paste0("Saving to ", this_save))
  tmp <- sm(saveme(filename=this_save))
  pander::pander(sessionInfo())
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 7de4503f6bb5724c28cce24af5dbee22bb1c0cae
## R> packrat::restore()
## This is hpgltools commit: Thu Apr 12 22:08:53 2018 -0400: 7de4503f6bb5724c28cce24af5dbee22bb1c0cae
## Saving to 02_swath2stats-v20180215.rda.xz

R version 3.4.4 (2018-03-15)

**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: stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: foreach(v.1.4.4), Vennerable(v.3.1.0.9000), edgeR(v.3.20.9), ruv(v.0.9.7), MSstats(v.3.10.2), SWATH2stats(v.1.9.1) and hpgltools(v.2018.03)

loaded via a namespace (and not attached): snow(v.0.4-2), backports(v.1.1.2), Hmisc(v.4.1-1), plyr(v.1.8.4), lazyeval(v.0.2.1), splines(v.3.4.4), BiocParallel(v.1.12.0), GenomeInfoDb(v.1.14.0), ggplot2(v.2.2.1), sva(v.3.26.0), digest(v.0.6.15), BiocInstaller(v.1.28.0), htmltools(v.0.3.6), gdata(v.2.18.0), magrittr(v.1.5), checkmate(v.1.8.5), memoise(v.1.1.0), cluster(v.2.0.6), doParallel(v.1.0.11), openxlsx(v.4.0.17), limma(v.3.34.9), annotate(v.1.56.1), matrixStats(v.0.53.1), colorspace(v.1.3-2), blob(v.1.1.0), ggrepel(v.0.7.0), dplyr(v.0.7.4), RCurl(v.1.95-4.10), graph(v.1.56.0), roxygen2(v.6.0.1), genefilter(v.1.60.0), lme4(v.1.1-15), bindr(v.0.1.1), impute(v.1.52.0), survival(v.2.41-3), iterators(v.1.0.9), glue(v.1.2.0), gtable(v.0.2.0), zlibbioc(v.1.24.0), XVector(v.0.18.0), DelayedArray(v.0.4.1), BiocGenerics(v.0.24.0), DEoptimR(v.1.0-8), scales(v.0.5.0.9000), vsn(v.3.46.0), DBI(v.0.8), Rcpp(v.0.12.16), mzR(v.2.12.0), xtable(v.1.8-2), htmlTable(v.1.11.2), foreign(v.0.8-69), bit(v.1.1-12), preprocessCore(v.1.40.0), Formula(v.1.2-2), stats4(v.3.4.4), htmlwidgets(v.1.0), gplots(v.3.0.1), RColorBrewer(v.1.1-2), acepack(v.1.4.1), pkgconfig(v.2.0.1), XML(v.3.98-1.10), nnet(v.7.3-12), locfit(v.1.5-9.1), labeling(v.0.3), rlang(v.0.2.0.9001), reshape2(v.1.4.3), AnnotationDbi(v.1.40.0), munsell(v.0.4.3), tools(v.3.4.4), RSQLite(v.2.0), devtools(v.1.13.5), evaluate(v.0.10.1), stringr(v.1.3.0), mzID(v.1.16.0), yaml(v.2.1.18), knitr(v.1.20), bit64(v.0.9-7), pander(v.0.6.1), robustbase(v.0.92-8), caTools(v.1.17.1), bindrcpp(v.0.2), RBGL(v.1.54.0), nlme(v.3.1-131.1), xml2(v.1.2.0), compiler(v.3.4.4), rstudioapi(v.0.7), testthat(v.2.0.0), affyio(v.1.48.0), marray(v.1.56.0), tibble(v.1.4.2), geneplotter(v.1.56.0), stringi(v.1.1.7), highr(v.0.6), MSnbase(v.2.4.2), lattice(v.0.20-35), ProtGenerics(v.1.10.0), Matrix(v.1.2-12), commonmark(v.1.4), nloptr(v.1.0.4), pillar(v.1.2.1), MALDIquant(v.1.17), data.table(v.1.10.4-3), bitops(v.1.0-6), corpcor(v.1.6.9), GenomicRanges(v.1.30.3), R6(v.2.2.2), latticeExtra(v.0.6-28), pcaMethods(v.1.70.0), directlabels(v.2017.03.31), affy(v.1.56.0), KernSmooth(v.2.23-15), gridExtra(v.2.3), IRanges(v.2.12.0), codetools(v.0.2-15), MASS(v.7.3-49), gtools(v.3.5.0), assertthat(v.0.2.0), SummarizedExperiment(v.1.8.1), DESeq2(v.1.18.1), rprojroot(v.1.3-2), minpack.lm(v.1.2-1), withr(v.2.1.2), S4Vectors(v.0.16.0), GenomeInfoDbData(v.1.0.0), mgcv(v.1.8-23), parallel(v.3.4.4), doSNOW(v.1.0.16), quadprog(v.1.5-5), grid(v.3.4.4), rpart(v.4.1-13), minqa(v.1.2.4), rmarkdown(v.1.9), logging(v.0.7-103), Rtsne(v.0.13), Biobase(v.2.38.0) and base64enc(v.0.1-3)

LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxODogQW5hbHl6aW5nIGRhdGEgZnJvbSBPcGVuU3dhdGhXb3JrRmxvdy9UUklDLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKICB9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBsaWJyYXJ5KGhwZ2x0b29scykKICB0dCA8LSBkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikKICBrbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD05MCwKICAgICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCiAga25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aD04LAogICAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0PTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKICBvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQogIGdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQogIHZlciA8LSAiMjAxODAyMTUiCiAgcHJldmlvdXNfZmlsZSA8LSAiMDFfcHJlcHJvY2Vzc2luZ19jb21ldF9oaWdocmVzLlJtZCIKCiAgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCiAgcHJldmlvdXNfZmlsZSA8LSAiMDFfYW5ub3RhdGlvbi5SbWQiCiAgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCgogIHJtZF9maWxlIDwtICIwMl9zd2F0aDJzdGF0cy5SbWQiCn0KYGBgCgojIFRPRE8KCiogUmVtb3ZlIE1Tc3RhdHMgbG9nZ2luZy4gLS0gZG9uZQoqIE1ha2UgZXhwbGljaXQgc3BlYXJtYW4gY29ycmVsYXRpb25zIGJldHdlZW4gbWV0aG9kcy4gLS0gZG9uZQogICAgKiBEbyBib3RoIGZvciBhbGwgZGF0YSBhbmQgZm9yIHRoZSB0b3AtNTAvYm90dG9tLTUwIC0tIGRvbmUsIGJ1dCB3ZWlyZC4KKiBNYWtlIDEwMCUgY2VydGFpbiB0aGF0IHRoZSBzYW1wbGVzIGFyZSBhbm5vdGF0ZWQgY29ycmVjdGx5LiAtLSBkb25lLgoqIExpbW1hL01Tc3RhdHMvRWRnZVIgdmVubiBkaXNhZ3JhbSBmb3IgYWxsIHVwIGluIENGCiAgICogUmVwZWF0IGluIGFsbCBkb3duIENGCiAgICogUmVwZWF0IHdpdGggYSBjdXRvZmYsIHRvcC01MAoqIEluZGl2aWR1YWwgcGxvdHMgZm9yIFAvUEUgcHJvdGVpbnMuCgpBbmFseXppbmcgZGF0YSBmcm9tIG9wZW5NUyBhbmQgZnJpZW5kcy4KPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpJbiBwcmVwcm9jZXNzaW5nX2NvbWV0X2hpZ2hyZXMuUm1kLCBJIHVzZWQgdGhlIG9wZW5NUyB0dXRvcmlhbHMgYW5kIHN1cHBsZW1lbnRhbAptYXRlcmlhbHMgZnJvbSBhIGNvdXBsZSBwYXBlcnMgdG8gaG9wZWZ1bGx5IGNvcnJlY3RseSBwZXJmb3JtIHRoZSB2YXJpb3VzCnByZXByb2Nlc3NpbmcgdGFza3MgcmVxdWlyZWQgdG8gZXh0cmFjdCBpbnRlbnNpdHkgZGF0YSBmcm9tIERJQS9TV0FUSAp0cmFuc2l0aW9ucy4KClRoZSBmaW5hbCBzdGVwcyBvZiB0aGF0IHByb2Nlc3MgY29tYmluZWQgdGhlIHRyYW5zaXRpb24gaW50ZW5zaXRpZXMgZnJvbSBldmVyeQpzYW1wbGUgaW50byBhIG1ldGFkYXRhIGZyaWxlIChyZXN1bHRzL3RyaWMvSENEX21ldGEudHN2KSwgYW4gaW50ZW5zaXR5IG1hdHJpeAoocmVzdWx0cy90cmljL0hDRF9vdXRtYXRyaXgudHN2KSwgYW5kIGEgZmVhdHVyZSBhbGlnbmVkIG91dHB1dCBtYXRyaXgKKHJlc3VsdHMvdHJpYy9hbGlnbmVkX2NvbWV0X0hDRC50c3YpLgoKTXkgcmVhZGluZyBvZiB0aGUgU1dBVEgyc3RhdHMgYW5kIE1Tc3RhdHMgc291cmNlIGNvZGUgc3VnZ2VzdHMgdG8gbWUgdGhhdCB0aGUKbG9nMihpbnRlbnNpdGllcykgb2YgdGhlIGZlYXR1cmUgYWxpZ25lZCBkYXRhIGFyZSBvdXIgZmluYWwgcHJveHkgZm9yIHByb3RlaW4KYWJ1bmRhbmNlLiAgQXQgZmlyc3QgZ2xhbmNlLCB0aGlzIHN1Z2dlc3RzIHRvIG1lIHRoYXQgdGhlc2UgZGF0YSBtaWdodCBmb2xsb3cgYQpkaXN0cmlidXRpb24gc2ltaWxhciB0byBSTkFTZXEgZGF0YSAobmVnYXRpdmUgYmlub21pYWwsIGJ1dCBwZXJoYXBzIHdpdGggYQpiaWdnZXIgdGFpbD8pLiAgSW4gYWRkaXRpb24sIGJ5IHRoZSB0aW1lIHdlIHVzZSB0cmljIG9uIHRoZSBkYXRhLCB3ZSBoYXZlIGEKY291bnQgbWF0cml4IGFuZCBzYW1wbGUgYW5ub3RhdGlvbiBkYXRhIGZyYW1lcyB3aGljaCBsb29rIHJlbWFya2FibHkgc2ltaWxhciB0bwp0aG9zZSB1c2VkIGluIGEgUk5BU2VxIGV4cHJlc3Npb25zZXQuICBJbmRlZWQsIGJ5IHRoZSBlbmQgb2YgdGhlIE1Tc3RhdHMKcHJvY2Vzc2luZywgaXQgY3JlYXRlcyBhIE1TblNldCBjbGFzcyBvZiBpdHMgb3duIHdoaWNoIHVzZXMgZkRhdGEvZXhwcnMvcERhdGEuCgpGb3IgdGhlIGN1cmlvdXMsIG15IHJlYXNvbmluZyBmb3Igc2F5aW5nIHRoYXQgdGhlIGxvZyBpbnRlbnNpdGllcyBhcmUgb3VyIHByb3h5CmZvciBhYnVuZGFuY2UgY29tZXMgZnJvbSBNU3N0YXRzL1IvRGF0YVByb2Nlc3MuUiBpbiBhIGNsYXVzZSB3aGljaCBsb29rcyBsaWtlOgoKYGBge3Igc25pcHBldCwgZXZhbD1GQUxTRX0KaWYgKGxvZ1RyYW5zID09IDIpIHsKICB3b3JrW1siQUJVTkRBTkNFIl1dIDwtIGxvZzIod29ya1tbIkFCVU5EQU5DRSJdXSkKfSBlbHNlIGlmIChsb2dUcmFucyA9PSAxMCkgewogIHdvcmtbWyJBQlVOREFOQ0UiXV0gPC0gbG9nMTAod29ya1tbIkFCVU5EQU5DRSJdXSkKfSBlbHNlIHsKICAjIyBBYm92ZSB0aGVyZSB3YXMgYSBjaGVjayBmb3Igb25seSBsb2cgMiBhbmQgMTAsIGJ1dCB3ZSBjYW4gZG8gZSBpZiB3ZSB3YW50LgogICMjIEkgbWlnaHQgZ28gYmFjayB1cCB0aGVyZSBhbmQgcmVtb3ZlIHRoYXQgY2hlY2suIExvbmcgbGl2ZSBlISAyLjcxODI4MiBydWxlcyEKICB3b3JrW1siQUJVTkRBTkNFIl1dIDwtIGxvZyh3b3JrW1siQUJVTkRBTkNFIl1dKSAvIGxvZyhsb2dUcmFucykKfQpgYGAKCihOb3RlOiBJIGFkZGVkIHRoZSBuYXR1cmFsIGxvZyB0byB0aGUgc2V0IG9mIGNvbmRpdGlvbnMsIGJ1dCBvdGhlcndpc2UgdGhlIGxvZ2ljCmlzIHVuY2hhbmdlZC4pCgpXaXRoIHRoYXQgaW4gbWluZCwgSSB3YW50IHRvIHVzZSBzb21lIHRvb2xzIHdpdGggd2hpY2ggSSBhbSBmYW1pbGlhciBpbiBvcmRlciB0bwp0cnkgdG8gdW5kZXJzdGFuZCB0aGVzZSBkYXRhLiAgVGhlcmVmb3JlIEkgd2lsbCBmaXJzdCBhdHRlbXB0IHRvIGNvZXJjZSBteSB0cmljCmFsaWduZWQgZGF0YSBhbmQgYW5ub3RhdGlvbnMgaW50byBhICdub3JtYWwnIGV4cHJlc3Npb25zZXQuICBUaGVuIEkgd2FudCB0byBkbwpzb21lIGRpYWdub3N0aWMgcGxvdHMgd2hpY2gsIGlmIEkgYW0gd3JvbmcgYW5kIHRoZXNlIGRpc3RyaWJ1dGlvbnMgYXJlIG5vdCBhcwpleHBlY3RlZCwgd2lsbCBiZSBjb25jZXB0dWFsbHkgaW5jb3JyZWN0IChJIGRvbid0IHlldCB0aGluayBJIGFtIHdyb25nKS4KCiMjIFNhbXBsZSBhbm5vdGF0aW9uIHZpYSBTV0FUSDJzdGF0cwoKSSBhbSB1c2luZyB0aGUgU1dBVEgyc3RhdHMgdmlnbmV0dGUgYXMgbXkgcHJpbWFyeSBzb3VyY2Ugb2YgaW5mb3JtYXRpb24uICBUaHVzIEkKc2VlIHRoYXQgaXQgdXNlcyB0aGUKT3BlblNXQVRIX1NNM19Hb2xkU3RhbmRhcmRBdXRvbWF0ZWRSZXN1bHRzX2h1bWFuX3BlYWtncm91cHMudHh0IHdoaWNoIGhhcyBhCmZvcm1hdCBuZWFybHkgaWRlbnRpY2FsIHRvIG15IHRyaWMgb3V0cHV0IG1hdHJpeC4gIFRodXMgZm9yIHRoZSBtb21lbnQgSSB3aWxsCmFzc3VtZSB0aGF0IHRoZSBwcm9wZXIgaW5wdXQgZm9yIFNXQVRIMnN0YXRzIGlzICdyZXN1bHRzL3RyaWMvY29tZXRfSENELnRzdicgYW5kCm5vdCB0aGUgbWV0YWRhdGEgbm9yIG91dHB1dCBtYXRyaXguCgpJIGtlZXAgYSBzYW1wbGUgc2hlZXQgb2YgYWxsIHRoZSBESUEgc2FtcGxlcyB1c2VkIGluIHRoaXMgYW5hbHlzaXMgaW4KJ3NhbXBsZV9zaGVldHMvZGlhX3NhbXBsZXMueGxzeCcgIEl0IHNob3VsZCBjb250YWluIGFsbCB0aGUgb3RoZXIgcmVxdWlyZWQgZGF0YQp3aXRoIG9uZSBpbXBvcnRhbnQgY2F2ZWF0LCBJIHJlbW92ZWQgMSBzYW1wbGUgYnkgJ2NvbW1lbnRpbmcnIGl0IChlLmcuIHByZWZpeGluZwppdCB3aXRoICcjIycgLS0gd2hpY2ggaXMgYW4gYWRtaXR0ZWRseSBkdW1iIHRoaW5nIHRvIGRvIGluIGFuIGV4Y2VsIGZpbGUuCgpPbmUgbGFzdCBjYXZlYXQ6IEkgaGFja2VkIHRoZSBTV0FUSDJzdGF0cyBzYW1wbGVfYW5ub3RhdGlvbigpIGZ1bmN0aW9uIHRvIGFkZCBhCmNvdXBsZSBjb2x1bW5zIGluIGFuIGF0dGVtcHQgdG8gbWFrZSBpdCBhIGxpdHRsZSBtb3JlIHJvYnVzdCB3aGVuIGZhY2VkIHdpdGgKc2FtcGxlIHNoZWV0cyB3aXRoIGRpZmZlcmVudGx5IG5hbWVkIGNvbHVtbnMuCgpJbiBhZGRpdGlvbiwgU1dBVEgyc3RhdHMgcHJvdmlkZXMgc29tZSBuaWNlIGZpbHRlcmluZyBhbmQgY29tYmluYXRpb24KZnVuY3Rpb25zIHdoaWNoIHNob3VsZCBiZSBjb25zaWRlcmVkIHdoZW4gZ2VuZXJhdGluZyB2YXJpb3VzIGV4cHJlc3Npb25zZXQgZGF0YQpzdHJ1Y3R1cmVzIGxhdGVyLgoKYGBge3Igc3dhdGgyc3RhdHNfc2FtcGxlX2Fubm90YXRpb25zfQp0cmljX2RhdGEgPC0gcmVhZC5jc3YoInJlc3VsdHMvdHJpYy9hbGlnbmVkX2NvbWV0X0hDRC50c3YiLCBzZXA9Ilx0IikKCnNhbXBsZV9hbm5vdCA8LSBvcGVueGxzeDo6cmVhZC54bHN4KCJzYW1wbGVfc2hlZXRzL2RpYV9zYW1wbGVzLnhsc3giKQpyb3duYW1lcyhzYW1wbGVfYW5ub3QpIDwtIHNhbXBsZV9hbm5vdFtbInNhbXBsZWlkIl1dCiMjIERyb3Agc2FtcGxlcyBzdGFydGluZyB3aXRoIGNvbW1lbnRzCmtlZXBfaWR4IDwtICEgZ3JlcGwocGF0dGVybj0iIyMiLCB4PXJvd25hbWVzKHNhbXBsZV9hbm5vdCkpCnNhbXBsZV9hbm5vdCA8LSBzYW1wbGVfYW5ub3Rba2VlcF9pZHgsIF0KIyMgU2V0IHRoZSBtelhNTCBjb2x1bW4gdG8gbWF0Y2ggdGhlIGZpbGVuYW1lIGNvbHVtbiBpbiB0aGUgZGF0YS4KZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L3NjcmF0Y2gvZ2l0L1NXQVRIMnN0YXRzIikKIyMgczJzLCBteSB3aXR0eSB3YXkgb2Ygc2hvcnRlbmluZyBTV0FUSDJzdGF0cy4uLgpzMnNfZXhwIDwtIFNXQVRIMnN0YXRzOjpzYW1wbGVfYW5ub3RhdGlvbihkYXRhPXRyaWNfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2Fubm90YXRpb249c2FtcGxlX2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhX3R5cGU9Ik9wZW5TV0FUSCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFfZmlsZV9jb2x1bW49ImZpbGVuYW1lIikKIyMjIyMjIyMjIyMjCiMjIElNUE9SVEFOVCBDQVZFQVQKIyMjIyMjIyMjIyMjCiMjIEhFWSBZT1UsIFRSRVksIFJFQUQgVEhJUyBPUiBZT1UgV0lMTCBCRSBQSVNTRUQgTEFURVIKIyMjIyMjIyMjIyMjCiMjIEkgYW0ga2VlcGluZyBvbmx5IHRob3NlIHJvd3Mgd2hpY2ggYXJlIGZyb20gdGhlIG1hcmNoIHJ1bi4KZGltKHMyc19leHApCmtlcHRfcm93cyA8LSBzMnNfZXhwW1siQmlvUmVwbGljYXRlIl1dID09ICJtYXIiCnMyc19leHAgPC0gczJzX2V4cFtrZXB0X3Jvd3MsIF0KZGltKHMyc19leHApCiMjIFdvdywgdGhhdCBkcm9wcGVkIDQ2JSBvZiB0aGUgZGF0YQpgYGAKCk5vdyBJIGhhdmUgYSBjb3VwbGUgZGF0YSBzdHJ1Y3R1cmVzIHdoaWNoIHNob3VsZCBwcm92ZSB1c2VmdWwgZm9yIHRoZSBtZXRyaWNzCnByb3ZpZGVkIGJ5IFNXQVRIMnN0YXRzLCBNU3N0YXRzLCBhbmQgbXkgb3duIGhwZ2x0b29scy4KCiMgU1dBVEgyc3RhdHMgY29udGludWVkCgpMZXRzIHJldHVybiB0byBzb21lIG9mIHRoZSBtZXRyaWNzIHByb3ZpZGVkIGJ5IHN3YXRoMnN0YXRzLgoKYGBge3Igc3dhdGgyc3RhdHNfcHJvY2Vzc2luZ30KIyMgR2V0IGNvcnJlbGF0aW9ucyBvbiBhIHNhbXBsZSBieSBzYW1wbGUgYmFzaXMKcHAoZmlsZT0iaW1hZ2VzL3N3YXRoMnN0YXRzX3NhbXBsZV9jb3IucG5nIikKc2FtcGxlX2NvciA8LSBTV0FUSDJzdGF0czo6cGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXMoczJzX2V4cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29tcGFyaXNvbj10cmFuc2l0aW9uX2dyb3VwX2lkIH4gUnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW4uYWdncmVnYXRlPXN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnZhbHVlcz0iSW50ZW5zaXR5IikKZGV2Lm9mZigpCnNhbXBsZV9jb25kX3JlcF9jb3IgPC0gU1dBVEgyc3RhdHM6OnBsb3RfY29ycmVsYXRpb25fYmV0d2Vlbl9zYW1wbGVzKHMyc19leHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvbXBhcmlzb249dHJhbnNpdGlvbl9ncm91cF9pZCB+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29uZGl0aW9uICsgQmlvUmVwbGljYXRlICsgUnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW4uYWdncmVnYXRlPXN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnZhbHVlcz0iSW50ZW5zaXR5IikKIyMgSSBhbSBhIGxpdHRsZSBjb25jZXJuZWQgdGhhdCB0aGVzZSB2YWx1ZXMgZG8gbm90IHNlZW0gdG8gY2hhbmdlIHdoZW4gSSB0b29rCiMjIGZpbHRlcmVkL25vcm1hbGl6ZWQgZGF0YS4gIFNvIEkgYW0gcmVydW5uaW5nIHRoZW0gbWFudWFsbHkgZm9yIGEgbW9tZW50IC0tCiMjIHBlcmhhcHMgSSBtZXNzZWQgc29tZXRoaW5nIHVwIHdoZW4gSSByZXdyb3RlIHBvcnRpb25zIG9mIHRoZQojIyBzYW1wbGVfYW5ub3RhdGlvbigpIGZ1bmN0aW9uIGluIFNXQVRIMnN0YXRzLgoKIyMgYWhoIEkgdGhpbmsgSSBzZWUgdGhlIHByb2JsZW0uICBUaGUgZGVmYXVsdCB2YWx1ZSBmb3IgZnVuLmFnZ3JlZ2F0ZSBpcyBOVUxMLAojIyB3aGljaCBjYXVzZXMgZGNhc3QgdG8gZGVmYXVsdCB0byBsZW5ndGguICBJIHRoaW5rIHRoaXMgaXMgbm90IGxpa2VseSB0byBiZQojIyB2YWxpZCBmb3IgdGhpcyBkYXRhLiAgSSBhbSBub3QgY2VydGFpbiwgaG93ZXZlciwgd2hhdCBpcyB0aGUgYXBwcm9wcmlhdGUKIyMgZnVuY3Rpb24uICBJZiBJIGhhZCB0byBndWVzcywgSSB3b3VsZCBnbyB3aXRoIHN1bSgpPwoKYXNzZXNzX2RlY295X3JhdGUoczJzX2V4cCkKIyMgVGhpcyBzZWVtcyBhIGJpdCBoaWdoIHRvIG1lLCB5ZXNubz8KZmRyX292ZXJhbGwgPC0gYXNzZXNzX2Zkcl9vdmVyYWxsKHMyc19leHAsIG91dHB1dD0iUmNvbnNvbGUiKQoKYnlydW5fZmRyIDwtIGFzc2Vzc19mZHJfYnlydW4oczJzX2V4cCwgRkZUPTAuNywgcGxvdD1UUlVFLCBvdXRwdXQ9IlJjb25zb2xlIikKbXNjb3JlNGFzc2F5ZmRyKHMyc19leHAsIEZGVD0wLjcsIGZkcl90YXJnZXQ9MC4wMikKcHJvdF9zY29yZSA8LSBtc2NvcmU0cHJvdGZkcihzMnNfZXhwLCBGRlQ9MC43LCBmZHJfdGFyZ2V0PTAuMDIpCgptc2NvcmVfZmlsdGVyZWQgPC0gU1dBVEgyc3RhdHM6OmZpbHRlcl9tc2NvcmUoczJzX2V4cCwgcHJvdF9zY29yZSkKZGF0YV9maWx0ZXJlZF9tc2NvcmUgPC0gZmlsdGVyX21zY29yZV9mcmVxb2JzKHMyc19leHAsIDAuMDEsIDAuOCwgcm0uZGVjb3k9RkFMU0UpCmRhdGFfZmlsdGVyZWRfZmRyIDwtIGZpbHRlcl9tc2NvcmVfZmRyKHMyc19leHAsIEZGVD0wLjcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJhbGxfcHJvdGVpbl9mZHJfdGFyZ2V0PTAuMDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX292ZXJhbGxfcGVwdGlkZV9mZHJfbGltaXQ9MC4wNSkKb25seV9wcm90ZW90eXBpYyA8LSBmaWx0ZXJfcHJvdGVvdHlwaWNfcGVwdGlkZXMoZGF0YV9maWx0ZXJlZF9mZHIpCmFsbF9maWx0ZXJlZCA8LSBmaWx0ZXJfYWxsX3BlcHRpZGVzKGRhdGFfZmlsdGVyZWRfZmRyKQpvbmx5X3N0cm9uZyA8LSBmaWx0ZXJfb25fbWF4X3BlcHRpZGVzKGRhdGFfZmlsdGVyZWRfZmRyLCA1KQpvbmx5X21pbmltdW0gPC0gZmlsdGVyX29uX21pbl9wZXB0aWRlcyhvbmx5X3N0cm9uZywgMikKCiMjIEkgdGhpbmsgdGhlc2UgbWF0cml4ZXMgYXJlIHByb2JhYmx5IHNtYXJ0ZXIgdG8gdXNlIHRoYW4gdGhlIHJhdyBvdXRtYXRyaXggZnJvbSB0cmljLgojIyBCdXQgSSBhbSBub3QgYSBmYW4gb2YgcmVyd3JpdGluZyB0aGUgc2FtcGxlIGNvbHVtbiBuYW1lcy4KcHJvdGVpbl9tYXRyaXhfbXNjb3JlIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucyhtc2NvcmVfZmlsdGVyZWQsIHdyaXRlLmNzdj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lPSJzd2F0aDJzdGF0c19wcm90ZWluX21hdHJpeF9tc2NvcmUuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybS5kZWNveT1GQUxTRSkKZGltKHByb3RlaW5fbWF0cml4X21zY29yZSkKcGVwdGlkZV9tYXRyaXhfbXNjb3JlIDwtIHdyaXRlX21hdHJpeF9wZXB0aWRlcyhtc2NvcmVfZmlsdGVyZWQsIHdyaXRlLmNzdj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lPSJzd2F0aDJzdGF0c19wZXB0aWRlX21hdHJpeF9tc2NvcmUuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybS5kZWNveT1GQUxTRSkKcHJvdGVpbl9tYXRyaXhfbWluaW11bSA8LSB3cml0ZV9tYXRyaXhfcHJvdGVpbnMob25seV9taW5pbXVtLCB3cml0ZS5jc3Y9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWU9InN3YXRoMnN0YXRzX3Byb3RlaW5fbWF0cml4X21pbmltdW0uY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm0uZGVjb3k9RkFMU0UpCmRpbShwcm90ZWluX21hdHJpeF9taW5pbXVtKQpwZXB0aWRlX21hdHJpeF9taW5pbXVtIDwtIHdyaXRlX21hdHJpeF9wZXB0aWRlcyhvbmx5X21pbmltdW0sIHdyaXRlLmNzdj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlbmFtZT0ic3dhdGgyc3RhdHNfcGVwdGlkZV9tYXRyaXhfbWluaW11bS5jc3YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybS5kZWNveT1GQUxTRSkKClNXQVRIMnN0YXRzOjpwbG90X2NvcnJlbGF0aW9uX2JldHdlZW5fc2FtcGxlcyhzMnNfZXhwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnZhbHVlcz0iUlQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuLmFnZ3JlZ2F0ZT1zdW0pCiMjIEkgaGF2ZSBubyBlZmZpbmcgY2x1ZSB3aGF0IHRoaXMgcGxvdCBtZWFucy4KdmFyaWF0aW9uIDwtIFNXQVRIMnN0YXRzOjpwbG90X3ZhcmlhdGlvbihzMnNfZXhwLCBmdW4uYWdncmVnYXRlPXN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb21wYXJpc29uPXRyYW5zaXRpb25fZ3JvdXBfaWQgfiBDb25kaXRpb24pCgojIyBTb21ldGhpbmcgaW4gU1dBVEgyc3RhdHM6OmRpc2FnZ3JlZ2F0ZSB3YXMgd3JpdHRlbiBwb29ybHkgYW5kIGlzIGxvb2tpbmcgZm9yCiMjIGEgdmFyaWFibGUgbmFtZWQgJ2NvbHMnCmNvbHMgPC0gY29sbmFtZXMob25seV9taW5pbXVtKQpkaXNhZ2dyZWdhdGVkIDwtIFNXQVRIMnN0YXRzOjpkaXNhZ2dyZWdhdGUob25seV9taW5pbXVtLCBhbGwuY29sdW1ucz1UUlVFKQptc3N0YXRzX2lucHV0IDwtIFNXQVRIMnN0YXRzOjpjb252ZXJ0NE1Tc3RhdHMoZGlzYWdncmVnYXRlZCkKCmFsZnFfaW5wdXQgPC0gc20oU1dBVEgyc3RhdHM6OmNvbnZlcnQ0YUxGUShkaXNhZ2dyZWdhdGVkKSkKbWFwZGlhX2lucHV0IDwtIHNtKFNXQVRIMnN0YXRzOjpjb252ZXJ0NG1hcERJQShkaXNhZ2dyZWdhdGVkLCBSVD1UUlVFKSkKYGBgCgojIyBNU3N0YXRzCgptc3N0YXRzLm9yZyBzZWVtcyB0byBwcm92aWRlIGEgY29tcGxldGUgc29sdXRpb24gZm9yIHBlcmZvcm1pbmcgcmVhc29uYWJsZSBtZXRyaWNzIG9mIHRoaXMgZGF0YS4KCkkgYW0gY3VycmVudGx5IHJlYWRpbmc6IGh0dHA6Ly9tc3N0YXRzLm9yZy93cC1jb250ZW50L3VwbG9hZHMvMjAxNy8wMS9NU3N0YXRzX3YzLjcuM19tYW51YWwucGRmCgpJIG1hZGUgc29tZSBtb2RlcmF0ZWx5IGludHJ1c2l2ZSBjaGFuZ2VzIHRvIE1Tc3RhdHMgdG8gbWFrZSBpdCBjbGVhcmVyLCBhcyB3ZWxsLgoKYGBge3IgbXNzdGF0c19xdWFudH0KZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L3NjcmF0Y2gvZ2l0L01Tc3RhdHMiKQptc3N0YXRzX3F1YW50IDwtIHNtKE1Tc3RhdHM6OmRhdGFQcm9jZXNzKG1zc3RhdHNfaW5wdXQpKQoKbXNzdGF0c19wbG90cyA8LSBzbShNU3N0YXRzOjpkYXRhUHJvY2Vzc1Bsb3RzKG1zc3RhdHNfcXVhbnQsIHR5cGU9IlFDUExPVCIpKQoKbXlfbGV2ZWxzIDwtIGxldmVscyhhcy5mYWN0b3IobXNzdGF0c19pbnB1dCRDb25kaXRpb24pKQpteV9sZXZlbHMKCmNvbXBhcmlzb24gPC0gZ2hldHRvX2NvbnRyYXN0X21hdHJpeCgid3RfY2YiLCAid3Rfd2hvbGUiKQptc3N0YXRzX2NvbXBhcmlzb24gPC0gc20oTVNzdGF0czo6Z3JvdXBDb21wYXJpc29uKGNvbnRyYXN0Lm1hdHJpeD1jb21wYXJpc29uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bXNzdGF0c19xdWFudCkpCmBgYAoKIyMgRG8gdGhlIHNhbWUgY29tcGFyaXNvbiB3aXRoIHRoZSBtb2RpZmllZCBkYXRhLgoKYGBge3IgbXNzdGF0c19xdWFudF9tb2RpZmllZH0KIyMgSSB3YW50IHRvIHRlc3QgYSBoeXBvdGhlc2lzIGFib3V0IHRoZSBlZmZlY3Qgb2YgMC9OQSBvbiB0aGUgZGF0YSwgc28gSSBhbSByZXBsYWNpbmcgdGhlbSB3aXRoCiMjIDIsIHdoaWNoIHNob3VsZCBnaXZlIG1lIGEgbWluaW1hbCB2YWx1ZSBmb3IgYWxsIHRoZSBsb2cyZmMgY2FsY3VsYXRpb25zIHRvIHdvcmsgd2l0aC4KbXNzdGF0c19tb2RpZmllZCA8LSBtc3N0YXRzX3F1YW50CmFidW5kYW5jZXMgPC0gbXNzdGF0c19xdWFudCRQcm9jZXNzZWREYXRhW1siQUJVTkRBTkNFIl1dCm5hX2lkeCA8LSBpcy5uYShhYnVuZGFuY2VzKQptc3N0YXRzX21vZGlmaWVkJFByb2Nlc3NlZERhdGFbbmFfaWR4LCAiQUJVTkRBTkNFIl0gPC0gMgptc3N0YXRzX21vZGlmaWVkX2NvbXAgPC0gc20oTVNzdGF0czo6Z3JvdXBDb21wYXJpc29uKGNvbnRyYXN0Lm1hdHJpeD1jb21wYXJpc29uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bXNzdGF0c19tb2RpZmllZCkpCmBgYAoKIyMjIFAvUEUgcHJvdGVpbiBRQyBwbG90cyBmb3IgWWFuCgpZYW4gYXNrZWQgZm9yIHRoZSBwL3BlIHByb3RlaW4gcWMgcGxvdHMuIG9rLiAgSSBjaGFuZ2VkIHRoZSBkYXRhUHJvY2Vzc1Bsb3RzIHRvCnJldHVybiBzb21ldGhpbmcgdXNlZnVsLCBzbyB0aGF0IHNob3VsZCBiZSBwb3NzaWJsZSBub3cuCgpgYGB7ciBwZX0KcGVfZ2VuZXMgPC0gcmVhZC50YWJsZSgicmVmZXJlbmNlL2Fubm90YXRlZF9wZV9nZW5lcy50eHQiKVtbMV1dCgojIyBVbmZvcnR1bmF0ZWx5LCB0aGUgbmFtZXMgZGlkIG5vdCBnZXQgc2V0IGluIG15IGNoYW5nZWQgdmVyc2lvbiBvZiBkYXRhUHJvY2Vzc1Bsb3RzLi4uCnBsb3Rsc3QgPC0gbXNzdGF0c19wbG90cyRRQ1BMT1QKYXZhaWxhYmxlX3Bsb3RzIDwtIGdzdWIocGF0dGVybj0iXjEvIiwgcmVwbGFjZW1lbnQ9IiIsIHg9bGV2ZWxzKG1zc3RhdHNfcXVhbnQkUHJvY2Vzc2VkRGF0YSRQUk9URUlOKSkKbmFtZXMocGxvdGxzdCkgPC0gYXZhaWxhYmxlX3Bsb3RzCgpwZV9pbl9hdmFpbF9pZHggPC0gcGVfZ2VuZXMgJWluJSBhdmFpbGFibGVfcGxvdHMKcGVfaW5fYXZhaWwgPC0gcGVfZ2VuZXNbcGVfaW5fYXZhaWxfaWR4XQpwZV9wbG90cyA8LSBwbG90bHN0W3BlX2luX2F2YWlsXQpwZGYoZmlsZT0icGVfcWNfcGxvdHMucGRmIikKZm9yIChwIGluIDE6bGVuZ3RoKHBlX3Bsb3RzKSkgewogIHBsb3QocGVfcGxvdHNbW3BdXSkKfQpkZXYub2ZmKCkKYGBgCgojIENyZWF0ZSBocGdsdG9vbHMgZXhwcmVzc2lvbnNldAoKU2luY2UgSSBhbSBub3QgY2VydGFpbiBJIHVuZGVyc3RhbmQgdGhlc2UgZGF0YSwgSSB3aWxsIHRha2UgdGhlIGludGVuc2l0aWVzIGZyb20KU1dBVEgyc3RhdHMsIG1ldGFkYXRhLCBhbmQgYW5ub3RhdGlvbiBkYXRhOyAgYXR0ZW1wdCB0byBjcmVhdGUgYSAnbm9ybWFsJwpleHByZXNzaW9uc2V0OyBwb2tlIGF0IGl0IHRvIHNlZSB3aGF0IEkgY2FuIGxlYXJuLgoKIyMgTWFzc2FnaW5nIHRoZSBtZXRhZGF0YQoKSSB3YW50IHRvIHVzZSB0aGUgc2FtZSBtZXRhZGF0YSBhcyB3ZXJlIHVzZWQgZm9yIE1Tc3RhdHMuICBJdCBoYXMgYSBmZXcKaW1wb3J0YW50IGRpZmZlcmVuY2VzIGZyb20gdGhlIHJlcXVpcmVtZW50cyBvZiBocGdsdG9vbHM6IHByZXR0eSBtdWNoIG9ubHkgdGhhdApJIGRvIG5vdCBhbGxvdyByb3duYW1lcy9zYW1wbGVJRHMgdG8gc3RhcnQgd2l0aCBhIG51bWJlci4KCmBgYHtyIHByb3RlaW5fcGVwdGlkZV9tYXRyaWNlc30KbWV0YWRhdGEgPC0gc2FtcGxlX2Fubm90Cm1ldGFkYXRhW1sic2FtcGxlaWQiXV0gPC0gcGFzdGUwKCJzIiwgbWV0YWRhdGFbWyJzYW1wbGVpZCJdXSkKcm93bmFtZXMobWV0YWRhdGEpIDwtIG1ldGFkYXRhW1sic2FtcGxlaWQiXV0KYGBgCgojIyBNYXNzYWdpbmcgdGhlIGdlbmUgYW5ub3RhdGlvbiBkYXRhIGFuZCBhZGRpbmcgdGhlIG1zc3RhdHMgZGF0YS4KCkkgaGF2ZSBteSBvd24gYW5ub3RhdGlvbiBkYXRhIGZyb20gdGhlIGdmZiBmaWxlL21pY3JvYmVzb25saW5lL3doYXRldmVyLCBJIGNhbgphZGQgdGhlIE1Tc3RhdHMgcmVzdWx0IHRvIGl0IHNvIHRoYXQgbGF0ZXIgSSBjYW4gcHJpbnQgdGhlbSBhbGwgdG9nZXRoZXIuCgpgYGB7ciBtc3N0YXRzX2Fubm90YXRpb25zfQojIyBIZXJlIGlzIGEgbmVhdCBsaXR0bGUgdGhpbmcgSSBjYW4gZG86ICBBZGQgdGhlIE1Tc3RhdHMgcmVzdWx0cyB0byBteSBhbm5vdGF0aW9uIGRhdGEuCiMjIFRoZW4gd2hlbiBJIHByaW50IG91dCB0aGUgdGFibGVzIG9mIHRoZSBsaW1tYS9ldGMgcmVzdWx0cywgdGhleSBNU3N0YXRzCiMjIHJlc3VsdHMgd2lsbCBjb21lIGFsb25nIGZvciBmcmVlLgptc3N0YXRzX3RhYmxlIDwtIG1zc3RhdHNfY29tcGFyaXNvbltbIkNvbXBhcmlzb25SZXN1bHQiXV0Kcm93bmFtZXMobXNzdGF0c190YWJsZSkgPC0gZ3N1YihwYXR0ZXJuPSJeMVxcLyIsIHJlcGxhY2VtZW50PSIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9bXNzdGF0c190YWJsZVtbIlByb3RlaW4iXV0pCm10Yl9hbm5vdGF0aW9uc193aXRoX21zc3RhdHMgPC0gbWVyZ2UobXRiX2Fubm90YXRpb25zLCBtc3N0YXRzX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJyb3cubmFtZXMiLCBhbGwueD1UUlVFKQpyb3duYW1lcyhtdGJfYW5ub3RhdGlvbnNfd2l0aF9tc3N0YXRzKSA8LSBtdGJfYW5ub3RhdGlvbnNfd2l0aF9tc3N0YXRzW1siUm93Lm5hbWVzIl1dCm10Yl9hbm5vdGF0aW9uc193aXRoX21zc3RhdHMgPC0gbXRiX2Fubm90YXRpb25zX3dpdGhfbXNzdGF0c1ssIC0xXQoKbXNzdGF0c190YWJsZV9tb2RpZmllZCA8LSBtc3N0YXRzX21vZGlmaWVkX2NvbXBbWyJDb21wYXJpc29uUmVzdWx0Il1dCnJvd25hbWVzKG1zc3RhdHNfdGFibGVfbW9kaWZpZWQpIDwtIGdzdWIocGF0dGVybj0iXjFcXC8iLCByZXBsYWNlbWVudD0iIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW1zc3RhdHNfdGFibGVfbW9kaWZpZWRbWyJQcm90ZWluIl1dKQptdGJfYW5ub3RhdGlvbnNfd2l0aF9tb2RpZmllZF9tc3N0YXRzIDwtIG1lcmdlKG10Yl9hbm5vdGF0aW9ucywgbXNzdGF0c190YWJsZV9tb2RpZmllZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieT0icm93Lm5hbWVzIiwgYWxsLng9VFJVRSkKcm93bmFtZXMobXRiX2Fubm90YXRpb25zX3dpdGhfbW9kaWZpZWRfbXNzdGF0cykgPC0gbXRiX2Fubm90YXRpb25zX3dpdGhfbW9kaWZpZWRfbXNzdGF0c1tbIlJvdy5uYW1lcyJdXQptdGJfYW5ub3RhdGlvbnNfd2l0aF9tb2RpZmllZF9tc3N0YXRzIDwtIG10Yl9hbm5vdGF0aW9uc193aXRoX21vZGlmaWVkX21zc3RhdHNbLCAtMV0KYGBgCgojIyBNYXNzYWdpbmcgdGhlIGludGVuc2l0eSBtYXRyaXgKCkkgZG8gbm90IHdhbnQgdGhlIFwxIGJlZm9yZSB0aGUgcHJvdGVpbiBuYW1lcywgSSBhbHJlYWR5IG1lcmdlZCB0aGVtIGludG8gb25lCmVudHJ5IHBlciBnZW5lIHZpcyBTV0FUSDJzdGF0cy4KCmBgYHtyIHByb3RlaW5fbWF0cml4fQpwcm90X210cnggPC0gcmVhZC5jc3YoInN3YXRoMnN0YXRzX3Byb3RlaW5fbWF0cml4X21zY29yZS5jc3YiKQpyb3duYW1lcyhwcm90X210cngpIDwtIGdzdWIocGF0dGVybj0iXjFcXC8iLCByZXBsYWNlbWVudD0iIiwgeD1wcm90X210cnhbWyJQcm90ZWluTmFtZSJdXSkKcHJvdF9tdHJ4IDwtIHByb3RfbXRyeFssIC0xXQojIyBJbXBvcnRhbnQgcXVlc3Rpb246IERpZCBTV0FUSDJzdGF0cyByZW9yZGVyIG15IGRhdGE/CmZ1biA8LSBnc3ViKHBhdHRlcm49Il4uKl8oMjAxOC4qJCkiLCByZXBsYWNlbWVudD0iXFwxIiwgeD1jb2xuYW1lcyhwcm90X210cngpKQpjb2xuYW1lcyhwcm90X210cngpIDwtIHBhc3RlMCgicyIsIGZ1bikKCmRlY295X2lkeCA8LSAhIGdyZXBsKHBhdHRlcm49IkRFQ09ZIiwgeD1yb3duYW1lcyhwcm90X210cngpKQpwcm90X210cnggPC0gcHJvdF9tdHJ4W2RlY295X2lkeCwgXQoKcHJvdF9tdHJ4X21vZGlmaWVkIDwtIHByb3RfbXRyeAp6ZXJvX2lkeCA8LSBwcm90X210cnggPT0gMApwcm90X210cnhfbW9kaWZpZWRbemVyb19pZHhdIDwtIDIKYGBgCgojIyBNZXJnZSB0aGUgcGllY2VzCgpOb3cgd2Ugc2hvdWxkIGhhdmUgc3VmZmljaWVudCBwaWVjZXMgdG8gbWFrZSBhbiBleHByZXNzaW9uc2V0LgoKYGBge3IgZXhwdH0KIyMgRHJvcCB0aGUgbWV0YWRhdGEgbm90IGluIHRoZSBwcm90ZWluIG1hdHJpeDoKIyMgQW5kIGVuc3VyZSB0aGF0IHRoZXkgYXJlIHRoZSBzYW1lIG9yZGVyLgpyZW9yZGVyZWQgPC0gY29sbmFtZXMocHJvdF9tdHJ4KQptZXRhZGF0YSA8LSBtZXRhZGF0YVtyZW9yZGVyZWQsIF0KCnByb3RlaW5fZXhwdCA8LSBjcmVhdGVfZXhwdChtZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50X2RhdGFmcmFtZT1wcm90X210cngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bXRiX2Fubm90YXRpb25zX3dpdGhfbXNzdGF0cykKCnByb3RlaW5fbW9kaWZpZWRfZXhwdCA8LSBjcmVhdGVfZXhwdChtZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50X2RhdGFmcmFtZT1wcm90X210cnhfbW9kaWZpZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bXRiX2Fubm90YXRpb25zX3dpdGhfbW9kaWZpZWRfbXNzdGF0cykKYGBgCgpgYGB7ciBwcm90ZWluX21ldHJpY3MsIGZpZy5zaG93PSdoaWRlJ30KcHJvdGVpbl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MocHJvdGVpbl9leHB0KSkKcHJvdGVpbl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KHByb3RlaW5fZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQpwcm90ZWluX25vcm1fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHByb3RlaW5fbm9ybSkpCmBgYAoKYGBge3IgcHJpbnRfbWV0cmljc30KcHJvdGVpbl9tZXRyaWNzJGxpYnNpemUKcHJvdGVpbl9ub3JtX21ldHJpY3MkcGNhcGxvdApgYGAKCiMgQXR0ZW1wdCBzb21lIHF1YW50aWZpY2F0aW9uIGNvbXBhcmlzb25zPwoKYGBge3IgZGVfdGVzdGluZ30KcGFpcndpc2VfZmlsdCA8LSBzbShub3JtYWxpemVfZXhwdChwcm90ZWluX2V4cHQsIGZpbHRlcj1UUlVFKSkKcGFpcndpc2VfY29tcCA8LSBhbGxfcGFpcndpc2UocGFpcndpc2VfZmlsdCwgcGFyYWxsZWw9RkFMU0UsIGZvcmNlPVRSVUUpCgprZWVwZXJzIDwtIGxpc3QoImZpbHRyYXRlX3ZzX2NlbGxzIiA9IGMoInd0X2NmIiwgInd0X3dob2xlIikpCnBhaXJ3aXNlX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcyhwYWlyd2lzZV9jb21wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ImV4Y2VsL3Rlc3RfcGFpcndpc2VfZGVfd2l0aF9tc3N0YXRzLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycz1rZWVwZXJzKQpkcm9wcGVycyA8LSBjKCJ1bmRlZmluZWQiKQpuYW1lcyhkcm9wcGVycykgPC0gImxvZzJmYyIKcGFpcndpc2Vfb25seWFsbCA8LSBjb21iaW5lX2RlX3RhYmxlcyhwYWlyd2lzZV9jb21wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPSJleGNlbC90ZXN0X3BhaXJ3aXNlX2RlX29ubHlfbXNzdGF0cy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzPWtlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZXM9ZHJvcHBlcnMpCnBhaXJ3aXNlX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKHBhaXJ3aXNlX3RhYmxlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ImV4Y2VsL3Rlc3RfcGFpcndpc2Vfc2lnX3dpdGhfbXNzdGF0cy54bHN4IikpCgpzb2xvX3Byb3RlaW5zIDwtIGZlYXR1cmVzX2luX3NpbmdsZV9jb25kaXRpb24ocHJvdGVpbl9leHB0KQpwcm90ZWluc19vbmx5X2NmIDwtIHNvbG9fcHJvdGVpbnNbWyJzb2xvX3RoaXMiXV1bWyJ3dF9jZiJdXQpwcm90ZWluc19vbmx5X2NmCnByb3RlaW5zX29ubHlfd2hvbGUgPC0gc29sb19wcm90ZWluc1tbInNvbG9fdGhpcyJdXVtbInd0X3dob2xlIl1dCmxlbmd0aChwcm90ZWluc19vbmx5X3dob2xlKQpgYGAKCmBgYHtyIGRlX3Rlc3RpbmdfbW9kaWZpZWR9CnBhaXJ3aXNlX21vZGlmaWVkX2NvbXAgPC0gYWxsX3BhaXJ3aXNlKHByb3RlaW5fbW9kaWZpZWRfZXhwdCwgcGFyYWxsZWw9RkFMU0UsIGZvcmNlPVRSVUUpCgpwYWlyd2lzZV9tb2RpZmllZF90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMocGFpcndpc2VfbW9kaWZpZWRfY29tcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPSJleGNlbC90ZXN0X3BhaXJ3aXNlX21vZGlmaWVkX2RlX3dpdGhfbXNzdGF0cy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnM9a2VlcGVycykKZHJvcHBlcnMgPC0gYygidW5kZWZpbmVkIikKbmFtZXMoZHJvcHBlcnMpIDwtICJsb2cyZmMiCnBhaXJ3aXNlX21vZGlmaWVkX29ubHlhbGwgPC0gY29tYmluZV9kZV90YWJsZXMocGFpcndpc2VfbW9kaWZpZWRfY29tcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD0iZXhjZWwvdGVzdF9wYWlyd2lzZV9kZV9vbmx5X21zc3RhdHMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycz1rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVzPWRyb3BwZXJzKQpwYWlyd2lzZV9tb2RpZmllZF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBwYWlyd2lzZV9tb2RpZmllZF90YWJsZXMsCiAgZXhjZWw9ImV4Y2VsL3Rlc3RfcGFpcndpc2VfbW9kaWZpZWRfc2lnX3dpdGhfbXNzdGF0cy54bHN4IikpCmBgYAoKIyMgQ29tcGFyZSBocGdsdG9vbHMvTVNzdGF0cwoKQ2FuIHdlIGNvbXBhcmUgbGltbWEgYW5kIHJpZW5kcyB0byBNU3N0YXRzPwoKYGBge3IgY29tcGFyZV9jb21wYXJpc29uc30KaHBnbF90YWJsZSA8LSBwYWlyd2lzZV90YWJsZXMkZGF0YVtbMV1dCm1zc3RhdHNfdGFibGUgPC0gbXNzdGF0c19jb21wYXJpc29uJENvbXBhcmlzb25SZXN1bHQKcm93bmFtZXMobXNzdGF0c190YWJsZSkgPC0gZ3N1YihwYXR0ZXJuPSJeMS8iLCByZXBsYWNlbWVudD0iIiwgeD1tc3N0YXRzX3RhYmxlJFByb3RlaW4pCgptZXJnZWRfdGFibGUgPC0gbWVyZ2UoaHBnbF90YWJsZSwgbXNzdGF0c190YWJsZSwgYnk9InJvdy5uYW1lcyIpCndyaXRlLmNzdihmaWxlPSJpbWFnZXMvbWVyZ2VkX3RhYmxlLmNzdiIsIG1lcmdlZF90YWJsZSkKY29yLnRlc3QobWVyZ2VkX3RhYmxlJGxpbW1hX2xvZ2ZjLCBtZXJnZWRfdGFibGUkbG9nMkZDKQpjb3IudGVzdChtZXJnZWRfdGFibGUkbGltbWFfbG9nZmMsIG1lcmdlZF90YWJsZSRsb2cyRkMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChtZXJnZWRfdGFibGUkZGVzZXFfbG9nZmMsIG1lcmdlZF90YWJsZSRsb2cyRkMpCmNvci50ZXN0KG1lcmdlZF90YWJsZSRkZXNlcV9sb2dmYywgbWVyZ2VkX3RhYmxlJGxvZzJGQywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KG1lcmdlZF90YWJsZSRlZGdlcl9sb2dmYywgbWVyZ2VkX3RhYmxlJGxvZzJGQykKY29yLnRlc3QobWVyZ2VkX3RhYmxlJGVkZ2VyX2xvZ2ZjLCBtZXJnZWRfdGFibGUkbG9nMkZDLCBtZXRob2Q9InNwZWFybWFuIikKCmNvbWJpbmVkX3RhYmxlIDwtIHBhaXJ3aXNlX3RhYmxlcyRkYXRhW1sxXV0KdW5kZWZpbmVkX2lkeCA8LSBjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSA9PSAidW5kZWZpbmVkIgpjb21iaW5lZF90YWJsZVt1bmRlZmluZWRfaWR4LCAibG9nMmZjIl0gPC0gTkEKY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0gPC0gYXMubnVtZXJpYyhjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSkKY29yLnRlc3QoY29tYmluZWRfdGFibGVbWyJsaW1tYV9sb2dmYyJdXSwgY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0pCmNvci50ZXN0KGNvbWJpbmVkX3RhYmxlW1sibGltbWFfbG9nZmMiXV0sIGNvbWJpbmVkX3RhYmxlW1sibG9nMmZjIl1dLCBtZXRob2Q9InNwZWFybWFuIikKCmhpZ2hfdG9fbG93X2lkeCA8LSBvcmRlcihjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSwgbmEubGFzdD1UUlVFLCBkZWNyZWFzaW5nPVRSVUUpCmxvd190b19oaWdoX2lkeCA8LSBvcmRlcihjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSwgbmEubGFzdD1UUlVFLCBkZWNyZWFzaW5nPUZBTFNFKQp0b3BfNTAgPC0gaGVhZChjb21iaW5lZF90YWJsZVtoaWdoX3RvX2xvd19pZHgsIF0sIG49MTAwKQpib3R0b21fNTAgPC0gaGVhZChjb21iaW5lZF90YWJsZVtsb3dfdG9faGlnaF9pZHgsIF0sIG49MTAwKQoKY29yLnRlc3QodG9wXzUwJGxpbW1hX2xvZ2ZjLCB0b3BfNTAkbG9nMmZjKQpjb3IudGVzdCh0b3BfNTAkbGltbWFfbG9nZmMsIHRvcF81MCRsb2cyZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdCh0b3BfNTAkZGVzZXFfbG9nZmMsIHRvcF81MCRsb2cyZmMpCmNvci50ZXN0KHRvcF81MCRkZXNlcV9sb2dmYywgdG9wXzUwJGxvZzJmYywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KHRvcF81MCRlZGdlcl9sb2dmYywgdG9wXzUwJGxvZzJmYykKY29yLnRlc3QodG9wXzUwJGVkZ2VyX2xvZ2ZjLCB0b3BfNTAkbG9nMmZjLCBtZXRob2Q9InNwZWFybWFuIikKCmNvci50ZXN0KGJvdHRvbV81MCRsaW1tYV9sb2dmYywgYm90dG9tXzUwJGxvZzJmYykKY29yLnRlc3QoYm90dG9tXzUwJGxpbW1hX2xvZ2ZjLCBib3R0b21fNTAkbG9nMmZjLCBtZXRob2Q9InNwZWFybWFuIikKY29yLnRlc3QoYm90dG9tXzUwJGRlc2VxX2xvZ2ZjLCBib3R0b21fNTAkbG9nMmZjKQpjb3IudGVzdChib3R0b21fNTAkZGVzZXFfbG9nZmMsIGJvdHRvbV81MCRsb2cyZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChib3R0b21fNTAkZWRnZXJfbG9nZmMsIGJvdHRvbV81MCRsb2cyZmMpCmNvci50ZXN0KGJvdHRvbV81MCRlZGdlcl9sb2dmYywgYm90dG9tXzUwJGxvZzJmYywgbWV0aG9kPSJzcGVhcm1hbiIpCgp1cF9pbl9tc3N0YXRzIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSA+IDBdCnVwX2luX21zc3RhdHMgPC0gdXBfaW5fbXNzdGF0c1shaXMubmEodXBfaW5fbXNzdGF0cyldCnVwX2luX2xpbW1hIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxpbW1hX2xvZ2ZjIl1dID4gMF0KdXBfaW5fbGltbWEgPC0gdXBfaW5fbGltbWFbIWlzLm5hKHVwX2luX2xpbW1hKV0KdXBfaW5fZWRnZXIgPC0gcm93bmFtZXMoY29tYmluZWRfdGFibGUpW2NvbWJpbmVkX3RhYmxlW1siZWRnZXJfbG9nZmMiXV0gPiAwXQp1cF9pbl9lZGdlciA8LSB1cF9pbl9lZGdlclshaXMubmEodXBfaW5fZWRnZXIpXQp1cF92ZW5uX3NldHMgPC0gbGlzdCgKICAibXNzdGF0cyIgPSB1cF9pbl9tc3N0YXRzLAogICJsaW1tYSIgPSB1cF9pbl9saW1tYSwKICAiZWRnZXIiID0gdXBfaW5fZWRnZXIpCnRlc3RpbmcgPC0gVmVubmVyYWJsZTo6VmVubihTZXRzPXVwX3Zlbm5fc2V0cywgKQpwcChmaWxlPSIvdG1wL3VwX3Zlbm4ucG5nIikKVmVubmVyYWJsZTo6cGxvdCh0ZXN0aW5nLCBkb1dlaWdodHM9RkFMU0UpCmRldi5vZmYoKQpWZW5uZXJhYmxlOjpwbG90KHRlc3RpbmcsIGRvV2VpZ2h0cz1GQUxTRSkKCmRvd25faW5fbXNzdGF0cyA8LSByb3duYW1lcyhjb21iaW5lZF90YWJsZSlbY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0gPCAwXQpkb3duX2luX21zc3RhdHMgPC0gZG93bl9pbl9tc3N0YXRzWyFpcy5uYShkb3duX2luX21zc3RhdHMpXQpkb3duX2luX2xpbW1hIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxpbW1hX2xvZ2ZjIl1dIDwgMF0KZG93bl9pbl9saW1tYSA8LSBkb3duX2luX2xpbW1hWyFpcy5uYShkb3duX2luX2xpbW1hKV0KZG93bl9pbl9lZGdlciA8LSByb3duYW1lcyhjb21iaW5lZF90YWJsZSlbY29tYmluZWRfdGFibGVbWyJlZGdlcl9sb2dmYyJdXSA8IDBdCmRvd25faW5fZWRnZXIgPC0gZG93bl9pbl9lZGdlclshaXMubmEoZG93bl9pbl9lZGdlcildCmRvd25fdmVubl9zZXRzIDwtIGxpc3QoCiAgIm1zc3RhdHMiID0gZG93bl9pbl9tc3N0YXRzLAogICJsaW1tYSIgPSBkb3duX2luX2xpbW1hLAogICJlZGdlciIgPSBkb3duX2luX2VkZ2VyKQp0ZXN0aW5nIDwtIFZlbm5lcmFibGU6OlZlbm4oU2V0cz1kb3duX3Zlbm5fc2V0cywgKQpwcChmaWxlPSIvdG1wL2Rvd25fdmVubi5wbmciKQpWZW5uZXJhYmxlOjpwbG90KHRlc3RpbmcsIGRvV2VpZ2h0cz1GQUxTRSkKZGV2Lm9mZigpCmBgYAoKIyBSZXBlYXQgd2l0aCB0aGUgbW9kaWZpZWQgZGF0YQoKYGBge3IgY29tcGFyZV9jb21wYXJpc29uc19tb2RpZmllZH0KaHBnbF90YWJsZSA8LSBwYWlyd2lzZV9tb2RpZmllZF90YWJsZXMkZGF0YVtbMV1dCm1zc3RhdHNfdGFibGUgPC0gbXNzdGF0c19tb2RpZmllZF9jb21wJENvbXBhcmlzb25SZXN1bHQKcm93bmFtZXMobXNzdGF0c190YWJsZSkgPC0gZ3N1YihwYXR0ZXJuPSJeMS8iLCByZXBsYWNlbWVudD0iIiwgeD1tc3N0YXRzX3RhYmxlX21vZGlmaWVkJFByb3RlaW4pCgptZXJnZWRfdGFibGUgPC0gbWVyZ2UoaHBnbF90YWJsZSwgbXNzdGF0c190YWJsZSwgYnk9InJvdy5uYW1lcyIpCndyaXRlLmNzdihmaWxlPSJpbWFnZXMvbWVyZ2VkX3RhYmxlX21vZGlmaWVkLmNzdiIsIG1lcmdlZF90YWJsZSkKY29yLnRlc3QobWVyZ2VkX3RhYmxlJGxpbW1hX2xvZ2ZjLCBtZXJnZWRfdGFibGUkbG9nMkZDKQpjb3IudGVzdChtZXJnZWRfdGFibGUkbGltbWFfbG9nZmMsIG1lcmdlZF90YWJsZSRsb2cyRkMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChtZXJnZWRfdGFibGUkZGVzZXFfbG9nZmMsIG1lcmdlZF90YWJsZSRsb2cyRkMpCmNvci50ZXN0KG1lcmdlZF90YWJsZSRkZXNlcV9sb2dmYywgbWVyZ2VkX3RhYmxlJGxvZzJGQywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KG1lcmdlZF90YWJsZSRlZGdlcl9sb2dmYywgbWVyZ2VkX3RhYmxlJGxvZzJGQykKY29yLnRlc3QobWVyZ2VkX3RhYmxlJGVkZ2VyX2xvZ2ZjLCBtZXJnZWRfdGFibGUkbG9nMkZDLCBtZXRob2Q9InNwZWFybWFuIikKCmNvbWJpbmVkX3RhYmxlIDwtIHBhaXJ3aXNlX3RhYmxlcyRkYXRhW1sxXV0KdW5kZWZpbmVkX2lkeCA8LSBjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSA9PSAidW5kZWZpbmVkIgpjb21iaW5lZF90YWJsZVt1bmRlZmluZWRfaWR4LCAibG9nMmZjIl0gPC0gTkEKY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0gPC0gYXMubnVtZXJpYyhjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSkKY29yLnRlc3QoY29tYmluZWRfdGFibGVbWyJsaW1tYV9sb2dmYyJdXSwgY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0pCmNvci50ZXN0KGNvbWJpbmVkX3RhYmxlW1sibGltbWFfbG9nZmMiXV0sIGNvbWJpbmVkX3RhYmxlW1sibG9nMmZjIl1dLCBtZXRob2Q9InNwZWFybWFuIikKCmhpZ2hfdG9fbG93X2lkeCA8LSBvcmRlcihjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSwgbmEubGFzdD1UUlVFLCBkZWNyZWFzaW5nPVRSVUUpCmxvd190b19oaWdoX2lkeCA8LSBvcmRlcihjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSwgbmEubGFzdD1UUlVFLCBkZWNyZWFzaW5nPUZBTFNFKQp0b3BfNTAgPC0gaGVhZChjb21iaW5lZF90YWJsZVtoaWdoX3RvX2xvd19pZHgsIF0sIG49MTAwKQpib3R0b21fNTAgPC0gaGVhZChjb21iaW5lZF90YWJsZVtsb3dfdG9faGlnaF9pZHgsIF0sIG49MTAwKQoKY29yLnRlc3QodG9wXzUwJGxpbW1hX2xvZ2ZjLCB0b3BfNTAkbG9nMmZjKQpjb3IudGVzdCh0b3BfNTAkbGltbWFfbG9nZmMsIHRvcF81MCRsb2cyZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdCh0b3BfNTAkZGVzZXFfbG9nZmMsIHRvcF81MCRsb2cyZmMpCmNvci50ZXN0KHRvcF81MCRkZXNlcV9sb2dmYywgdG9wXzUwJGxvZzJmYywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KHRvcF81MCRlZGdlcl9sb2dmYywgdG9wXzUwJGxvZzJmYykKY29yLnRlc3QodG9wXzUwJGVkZ2VyX2xvZ2ZjLCB0b3BfNTAkbG9nMmZjLCBtZXRob2Q9InNwZWFybWFuIikKCmNvci50ZXN0KGJvdHRvbV81MCRsaW1tYV9sb2dmYywgYm90dG9tXzUwJGxvZzJmYykKY29yLnRlc3QoYm90dG9tXzUwJGxpbW1hX2xvZ2ZjLCBib3R0b21fNTAkbG9nMmZjLCBtZXRob2Q9InNwZWFybWFuIikKY29yLnRlc3QoYm90dG9tXzUwJGRlc2VxX2xvZ2ZjLCBib3R0b21fNTAkbG9nMmZjKQpjb3IudGVzdChib3R0b21fNTAkZGVzZXFfbG9nZmMsIGJvdHRvbV81MCRsb2cyZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChib3R0b21fNTAkZWRnZXJfbG9nZmMsIGJvdHRvbV81MCRsb2cyZmMpCmNvci50ZXN0KGJvdHRvbV81MCRlZGdlcl9sb2dmYywgYm90dG9tXzUwJGxvZzJmYywgbWV0aG9kPSJzcGVhcm1hbiIpCgp1cF9pbl9tc3N0YXRzIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxvZzJmYyJdXSA+IDBdCnVwX2luX21zc3RhdHMgPC0gdXBfaW5fbXNzdGF0c1shaXMubmEodXBfaW5fbXNzdGF0cyldCnVwX2luX2xpbW1hIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxpbW1hX2xvZ2ZjIl1dID4gMF0KdXBfaW5fbGltbWEgPC0gdXBfaW5fbGltbWFbIWlzLm5hKHVwX2luX2xpbW1hKV0KdXBfaW5fZWRnZXIgPC0gcm93bmFtZXMoY29tYmluZWRfdGFibGUpW2NvbWJpbmVkX3RhYmxlW1siZWRnZXJfbG9nZmMiXV0gPiAwXQp1cF9pbl9lZGdlciA8LSB1cF9pbl9lZGdlclshaXMubmEodXBfaW5fZWRnZXIpXQp1cF92ZW5uX3NldHMgPC0gbGlzdCgKICAibXNzdGF0cyIgPSB1cF9pbl9tc3N0YXRzLAogICJsaW1tYSIgPSB1cF9pbl9saW1tYSwKICAiZWRnZXIiID0gdXBfaW5fZWRnZXIpCnRlc3RpbmcgPC0gVmVubmVyYWJsZTo6VmVubihTZXRzPXVwX3Zlbm5fc2V0cywgKQpwcChmaWxlPSIvdG1wL3VwX3Zlbm4ucG5nIikKVmVubmVyYWJsZTo6cGxvdCh0ZXN0aW5nLCBkb1dlaWdodHM9RkFMU0UpCmRldi5vZmYoKQpWZW5uZXJhYmxlOjpwbG90KHRlc3RpbmcsIGRvV2VpZ2h0cz1GQUxTRSkKCmRvd25faW5fbXNzdGF0cyA8LSByb3duYW1lcyhjb21iaW5lZF90YWJsZSlbY29tYmluZWRfdGFibGVbWyJsb2cyZmMiXV0gPCAwXQpkb3duX2luX21zc3RhdHMgPC0gZG93bl9pbl9tc3N0YXRzWyFpcy5uYShkb3duX2luX21zc3RhdHMpXQpkb3duX2luX2xpbW1hIDwtIHJvd25hbWVzKGNvbWJpbmVkX3RhYmxlKVtjb21iaW5lZF90YWJsZVtbImxpbW1hX2xvZ2ZjIl1dIDwgMF0KZG93bl9pbl9saW1tYSA8LSBkb3duX2luX2xpbW1hWyFpcy5uYShkb3duX2luX2xpbW1hKV0KZG93bl9pbl9lZGdlciA8LSByb3duYW1lcyhjb21iaW5lZF90YWJsZSlbY29tYmluZWRfdGFibGVbWyJlZGdlcl9sb2dmYyJdXSA8IDBdCmRvd25faW5fZWRnZXIgPC0gZG93bl9pbl9lZGdlclshaXMubmEoZG93bl9pbl9lZGdlcildCmRvd25fdmVubl9zZXRzIDwtIGxpc3QoCiAgIm1zc3RhdHMiID0gZG93bl9pbl9tc3N0YXRzLAogICJsaW1tYSIgPSBkb3duX2luX2xpbW1hLAogICJlZGdlciIgPSBkb3duX2luX2VkZ2VyKQp0ZXN0aW5nIDwtIFZlbm5lcmFibGU6OlZlbm4oU2V0cz1kb3duX3Zlbm5fc2V0cywgKQpwcChmaWxlPSIvdG1wL2Rvd25fdmVubi5wbmciKQpWZW5uZXJhYmxlOjpwbG90KHRlc3RpbmcsIGRvV2VpZ2h0cz1GQUxTRSkKZGV2Lm9mZigpCmBgYAoKIyBFdmVyeXRoaW5nIGJlbG93IGhlcmUgbWlnaHQgZ2V0IGRyb3BwZWQ/CgpJIHRoaW5rIEkgd2VkZ2VkIGFsbCBvZiB0aGUgZm9sbG93aW5nIHdvcmsgaW50byB0aGF0IHNob3J0IGJsb2NrIGFib3ZlLgpTbywgc3RvcCBldmFsdWF0aW5nIHRoZSBmb2xsb3dpbmcgYmxvY2tzIGFuZCBzZWUgaWYgdGhhdCBpcyB0cnVlLgoKIyMjIEV4cHJlc3Npb25zZXQgZnJvbSB0aGUgVFJJQyBpbnRlbnNpdHkgbWF0cml4CgpgYGB7ciBocGdsdG9vbHNfZXhwdCwgZXZhbD1GQUxTRX0KaW50ZW5zaXR5X210cnggPC0gcmVhZC5jc3YoZmlsZT0icmVzdWx0cy90cmljL0hDRF9vdXRtYXRyaXgudHN2Iiwgc2VwPSJcdCIpCiMjIFRoZSBIQ0Rfb3V0bWF0cml4IGhhcyBjb2x1bW5zIGluY2x1ZGluZzogUGVwdGlkZSwgUHJvdGVpbiwKIyMgQSBzZXJpZXMgb2YgSW50ZW5zaXR5X3NhbXBsZV9pZCBjb2x1bW5zCiMjIEEgc2VyaWVzIG9mIFJUX3NhbXBsZV9pZCBjb2x1bW5zCiMjIEEgc2VyaWVzIG9mIHNjb3JlX3NhbXBsZV9pZCBjb2x1bW5zCiMjIEFuZCBhdCB0aGUgZW5kOiBSVF9tZWFuLCBSVF9zdGQsIGFuZCBwZ19wdmFsdWUuCiMjIFNpbmNlIFNXQVRIMnN0YXRzL01Tc3RhdHMgdXNlcyB0aGUgaW50ZW5zaXRpZXMsIGxldHMgZ2V0IHRob3NlIGNvbHVtbnMgb3V0LAojIyBzdGFuZGFyZGl6ZSB0aGUgY29sdW1uIG5hbWVzIHRvIG1hdGNoIHRoZSBhbm5vdGF0aW9uIGRhdGEsIGFuZCB1c2UgdGhlbSBmb3IKIyMgY3JlYXRpbmcgYW4gZXhwcmVzc2lvbnNldC4KaW50ZW5zaXR5X210cnhbWyJyb3duYW1lcyJdXSA8LSBpbnRlbnNpdHlfbXRyeFtbIlByb3RlaW4iXV0KaW50ZW5zaXR5X210cnhbWyJyb3duYW1lcyJdXSA8LSBnc3ViKHBhdHRlcm49Il5bWzpkaWdpdDpdXStcXC8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQ9IiIsIHg9aW50ZW5zaXR5X210cnhbWyJyb3duYW1lcyJdXSkKIyMgU3RhbmRhcmRpemUgdGhlIHJvd25hbWVzLCB0aGlzIG1pZ2h0IGJlIGEgYmFkIGlkZWEsIGFzIHRoaXMgd2lsbCBrZWVwCiMjIHNlcGFyYXRlIGV2ZXJ5IHBlcHRpZGUgZnJvbSBlYWNoIHByb3RlaW4gYW5kIG5vdCBkbyBhbnl0aGluZyB0bwojIyBzdW0vbWVkaWFuL3doYXRldmVyIHRoZW0uICBCdXQgZm9yIHRoZSBwdXJwb3NlcyBvZiB0ZXN0aW5nIG91dCB0aGUgZGF0YSBJCiMjIHRoaW5rIGl0IGlzIG9rLgpyb3duYW1lcyhpbnRlbnNpdHlfbXRyeCkgPC0gbWFrZS5uYW1lcyhpbnRlbnNpdHlfbXRyeFtbInJvd25hbWVzIl1dLCB1bmlxdWU9VFJVRSkKCiMjIE5vdyBsZXRzIGdldCByaWQgb2YgdGhlIGV4dHJhbmVvdXMgdGV4dCBpbiB0aGUgY29sdW1uIG5hbWVzIGFuZCBzaW1wbGlmeSB0aGVtCiMjIHRvIHRoZSBzYW1wbGUgbmFtZXMgYXMgcmVmZXJlbmNlZCBpbiB0aGUgc2FtcGxlIHNoZWV0LgphbGxfY29sdW1ucyA8LSBjb2xuYW1lcyhpbnRlbnNpdHlfbXRyeCkKaW50ZW5zZV9jb2x1bW5zIDwtIGdyZXBsKHBhdHRlcm49IkludGVuc2l0eSIsIHg9YWxsX2NvbHVtbnMpCmludGVuc2l0eV9tdHJ4IDwtIGludGVuc2l0eV9tdHJ4WywgaW50ZW5zZV9jb2x1bW5zXQphbGxfY29sdW1ucyA8LSBjb2xuYW1lcyhpbnRlbnNpdHlfbXRyeCkKbmV3X2NvbHVtbnMgPC0gZ3N1YihwYXR0ZXJuPSJJbnRlbnNpdHlfIiwgcmVwbGFjZW1lbnQ9IiIsIHg9YWxsX2NvbHVtbnMpCm5ld19jb2x1bW5zIDwtIGdzdWIocGF0dGVybj0iX2RpYV8uKiQiLCByZXBsYWNlbWVudD0iIiwgeD1uZXdfY29sdW1ucykKY29sbmFtZXMoaW50ZW5zaXR5X210cngpIDwtIHBhc3RlMCgicyIsIG5ld19jb2x1bW5zKQppbnRlbnNpdHlfbXRyeFtpcy5uYShpbnRlbnNpdHlfbXRyeCldIDwtIDAKCiMjIE5vIGNvbHVtbnMgaW4gYW4gZXhwcmVzc2lvbiBzZXQgYXJlIGFsbG93ZWQgdG8gc3RhcnQgd2l0aCBhIG51bWJlci4gIEkgaGF2ZQojIyB1bnNlZCBwcmVmaXhpbmcgc2FtcGxlcyB3aXRoICdzJyBhcyBhIHN0YW5kYXJkIHRvIGhhbmRsZSB0aGlzIHByb2JsZW0uLi4KbWV0YWRhdGEgPC0gc2FtcGxlX2Fubm90Cm1ldGFkYXRhJHNhbXBsZWlkIDwtIHBhc3RlMCgicyIsIG1ldGFkYXRhJHNhbXBsZWlkKQpjb2xuYW1lcyhpbnRlbnNpdHlfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJfdnNfSENEIiwgcmVwbGFjZW1lbnQ9IiIsIHg9Y29sbmFtZXMoaW50ZW5zaXR5X210cngpKQpyb3duYW1lcyhtZXRhZGF0YSkgPC0gbWV0YWRhdGEkc2FtcGxlaWQKIyMgVGhlb3JldGljYWxseSB0aGlzIGlzIG5vdCBuZWVkZWQgYW55bW9yZS4uLgppbnRlbnNpdHlfbXRyeCA8LSBpbnRlbnNpdHlfbXRyeFssIHJvd25hbWVzKG1ldGFkYXRhKV0KIyMgT2ssIGF0IHRoaXMgcG9pbnQsIHdlIHNob3VsZCBoYXZlIGFsbCB0aGUgcGllY2VzIGZvciBhIG1vcmUgb3IgbGVzcyBub3JtYWwgZXhwcmVzc2lvbnNldC4KZGltKGludGVuc2l0eV9tdHJ4KQp0ZXN0X2V4cHQgPC0gY3JlYXRlX2V4cHQobWV0YWRhdGE9bWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudF9kYXRhZnJhbWU9aW50ZW5zaXR5X210cngsCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bXRiX2Fubm90YXRpb25zKQpgYGAKCiMjIyBQbGF5IHdpdGggdGhlIGhwZ2x0b29scyBkZXJpdmVkIGV4cHJlc3Npb25zZXQgb2YgcGVwdGlkZSBpbnRlbnNpdGllcwoKTGV0cyBzZWUgaWYgYW55dGhpbmcgbWFrZXMgc2Vuc2UgaW4gdGhpcyBpbnRlbnNpdHkgZXhwcmVzc2lvbnNldC4KCmBgYHtyIGhwZ2x0b29sc19leHB0X2V4YW1pbmUsIGZpZy5zaG93PSJoaWRlIiwgZXZhbD1GQUxTRX0KIyMgRmlyc3QsIGxvZzIgYW5kIG5vcm1hbGl6ZSB0aGUgZGF0YS4KdGVzdF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHRlc3RfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnRpbGUiLCBmaWx0ZXI9VFJVRSkKdGVzdF9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQodGVzdF9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudGlsZSIsIGZpbHRlcj1UUlVFLCBiYXRjaD0ibGltbWEiKSkKCnRlc3RfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHRlc3RfZXhwdCkpCnRlc3RfbWV0cmljc19ub3JtIDwtIHNtKGdyYXBoX21ldHJpY3ModGVzdF9ub3JtKSkKdGVzdF9tZXRyaWNzX25vcm1iYXRjaCA8LSBzbShncmFwaF9tZXRyaWNzKHRlc3Rfbm9ybWJhdGNoKSkKYGBgCgpOb3cgbGV0cyBzZWUgd2hhdCB0aGUgZGF0YSBsb29rcyBsaWtlLCBhc3N1bWluZyBJIGRpZCBub3QgZG8gYW55dGhpbmcgaG9ycmlibGUKdG8gaXQuCgpgYGB7ciBocGdsdG9vbHNfcGxvdHMsIGV2YWw9RkFMU0V9CnRlc3RfbWV0cmljcyRsZWdlbmQKdGVzdF9tZXRyaWNzJGxpYnNpemUgICMjIFdvdyB0aGUgaW50ZW5zaXRpZXMgZ2V0IHJpZGljdWxvdXMsIHdoYXQ/CnRlc3RfbWV0cmljcyRub256ZXJvCiMjIEludGVyZXN0aW5nLCBidXQgbm90aGluZyB3aGljaCBzdXBlci1qdW1wcyBvdXQgYXQgbWUKdGVzdF9tZXRyaWNzJGRlbnNpdHkKIyMgaG1tIHZlcnkgaW50ZXJlc3RpbmcsIHRoZSBnb29kIG5ld3MgaXMgdGhhdCB0aGV5IGFsbCBoYXZlIGJhc2ljYWxseSB0aGUgc2FtZQojIyBkaXN0cmlidXRpb24uICBJIGRpZCBub3QgZXhwZWN0IHRoZSBDRiBzYW1wbGVzIHRvIGhhdmUgc3VjaCBhIHN0cm9uZ2VyCiMjIGRpc3RyaWJ1dGlvbiB0aG91Z2guCgp0ZXN0X21ldHJpY3Nfbm9ybSRjb3JoZWF0CiMjIFRoaXMgc3VnZ2VzdHMgdG8gbWUgYSBsaWtlbHkgYmF0Y2ggZWZmZWN0CnRlc3RfbWV0cmljc19ub3JtJGRpc2hlYXQKdGVzdF9tZXRyaWNzJHNtYwp0ZXN0X21ldHJpY3MkdHNuZXBsb3QKIyMgWWVhaCB0aGVyZSBpcyBzb21lIHdvbmt5bmVzcyBiZXR3ZWVuIHRoZSBvbGQvbmV3IHNhbXBsZXMuCgp0ZXN0X21ldHJpY3Nfbm9ybWJhdGNoJHBjYXBsb3QKIyMgV293LCB0aGlzIGlzIGFmdGVyIGludm9raW5nICdyZW1vdmVCYXRjaEVmZmVjdCcgZnJvbSBsaW1tYS4gIFRoYXQgc3VnZ2VzdHMKIyMgcHJldHR5IHN0cm9uZ2x5IHRvIG1lIHRoYXQgd2Ugc2hvdWxkIHByb2JhbGJ5IG5vdCBleGFtaW5lIHRoZSBuZXcgYW5kIG9sZAojIyBkYXRhIHRvZ2V0aGVyLiAgSW4gYWRkaXRpb24gSSBhbSB0aGlua2luZyB0aGF0IG9uZSB3aG9sZS1jZWxsIGx5c2F0ZSBzYW1wbGUKIyMgbWlnaHQgbm90IGJlLgpgYGAKCiMjIFJlbW92ZSBvbGQgYmF0Y2gvd2VpcmRvIHNhbXBsZQoKYGBge3IgcmVtb3ZhbHMsIGZpZy5zaG93PSJoaWRlIiwgZXZhbD1GQUxTRX0Ka2VwdF90ZXN0aW5nIDwtIHN1YnNldF9leHB0KHRlc3RfZXhwdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldD0iYmlvcmVwbGljYXRlID09ICdtYXInIikKIyMgVGhlIG5ldyBiYXRjaCBJRHM6IHgseSx6IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhlIDMgcnVucyBvZiB0aGVzZSBzYW1wbGVzLCBvbmUKIyMgd2hpY2ggaXMgOCBtL3osIG9uZSB3aGljaCBpcyAyMCBtL3osIGFuZCBvbmUgd2hpY2ggaXMgYSByZW9yZGVyZWQgMjAgbS96LgoKdGVzdF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGtlcHRfdGVzdGluZywgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnRpbGUiLCBmaWx0ZXI9VFJVRSkKdGVzdF9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQoa2VwdF90ZXN0aW5nLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImxpbW1hIikpCm5ld19tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Moa2VwdF90ZXN0aW5nKSkKbmV3X21ldHJpY3Nfbm9ybSA8LSBzbShncmFwaF9tZXRyaWNzKHRlc3Rfbm9ybSkpCm5ld19tZXRyaWNzX25vcm1iYXRjaCA8LSBzbShncmFwaF9tZXRyaWNzKHRlc3Rfbm9ybWJhdGNoKSkKYGBgCgojIyMgUGxvdCBvbmx5IG5ldyBkYXRhCgpSZW1vdmluZyB0aGUgSmFudWFyeSBkYXRhIHNlZW1zIHRvIGhhdmUgbWFkZSB0aGlzIGEgbG90IGVhc2llciB0byBsb29rIGF0LgpUaGVyZSBtaWdodCBiZSBzb21lIGJhdGNoeW5lc3MgYXNzb2NpYXRlZCB3aXRoIHJlb3JkZXJpbmcgdGhlIHNhbXBsZXMsIGJ1dCBJIGFtCnRoaW5raW5nIGl0IGlzIG5vdCBodWdlLgoKCmBgYHtyIG5ld19kYXRhX3Bsb3RzLCBldmFsPUZBTFNFfQp0dCA9IHBsb3RfdG9wbihrZXB0X3Rlc3RpbmcsIGRpcmVjdD1UUlVFKQpuZXdfbWV0cmljcyRsZWdlbmQKbmV3X21ldHJpY3MkbGlic2l6ZQpwcCgiaW1hZ2VzL2tlcHRfbm9ybV90b3BuLnBuZyIsIGltYWdlPW5ld19tZXRyaWNzJHRvcG5wbG90KQpwcCgiaW1hZ2VzL2tlcHRfbm9ybV9oY2RfcGNhLnBuZyIsIGltYWdlPW5ld19tZXRyaWNzX25vcm0kcGNhcGxvdCkKbmV3X21ldHJpY3Nfbm9ybSR0c25lcGxvdApwcCgiaW1hZ2VzL2tlcHRfbm9ybV9oY2RfY29yaGVhdC5wbmciLCBpbWFnZT1uZXdfbWV0cmljc19ub3JtJGNvcmhlYXQpCm5ld19tZXRyaWNzX25vcm0kZGlzaGVhdApuZXdfbWV0cmljc19ub3JtYmF0Y2gkcGNhcGxvdApwcCgiaW1hZ2VzL25vcm1iYXRjaF90c25lLnBuZyIsIGltYWdlPW5ld19tZXRyaWNzX25vcm1iYXRjaCR0c25lcGxvdCkKYGBgCgojIyMgSG93IGlzIHRoZSB2YXJpYW5jZT8KCkxldHMgc2VlIHdoYXQgdmFyaWFuY2VQYXJ0aXRpb24gaGFzIHRvIHNheSBhYm91dCB0aGlzIGRhdGEuCgpgYGB7ciB2YXJwYXJ0LCBldmFsPUZBTFNFfQpuZXdfdmFycGFydCA8LSB2YXJwYXJ0KGtlcHRfdGVzdGluZywgZmFjdG9ycz1jKCJjb25kaXRpb24iLCAiYmF0Y2giKSkKcHAoImltYWdlcy92YXJwYXJ0X3BhcnRpdGlvbi5wbmciLCBpbWFnZT1uZXdfdmFycGFydCRwYXJ0aXRpb25fcGxvdCkKIyMgVGhhdCBpcyBub3QgdGVycmlibGUuCgojIyB0aGUgbW9kaWZpZWRfZXhwdCBzbG93IGZyb20gdmFycGFydCgpIGFkZHMgc29tZSBtZXRhZGF0YSB0byB0aGUgZXhwcmVzc2lvbnNldAojIyBpbmNsdWRpbmcgdGhlIGNhbGN1bGF0ZWQgJSB2YXJpYW5jZSBmb3IgY29uZGl0aW9uL2JhdGNoL3Jlc2lkdWFsIGZvciBlYWNoIHBlcHRpZGUuCmtlcHRfdGVzdGluZyA8LSBuZXdfdmFycGFydCRtb2RpZmllZF9leHB0CmBgYAoKIyMgQmFjayB0byBocGdsdG9vbHMKCklmIHlvdSB3aWxsIHJlY2FsbCwgaW4gdGhlIG9yaWdpbmFsIGJsb2NrIHdoZXJlIEkgcmVhZCB0aGUgZGF0YSBpbnRvClNXQVRIMnN0YXRzLCBJIGludm9rZWQgd3JpdGVfbWF0cml4X3Byb3RlaW5zKCkgYW5kIHdyaXRlX21hdHJpeF9wZXB0aWRlcygpIGFuZAp3cm90ZSBvdXQgMiBjc3YgZmlsZXMgJ3N3YXRoMnN0YXRzX3Byb3RlaW5fbWF0cml4LmNzdicgYW5kCidfcGVwdGlkZV9tYXRyaXguY3N2Jy4gIElmIG15IGVhcmxpZXIgd29yayBpcyBjb3JyZWN0LCBJIHNob3VsZCBiZSBhYmxlIHRvIHVzZQp0aGUgcHJvdGVpbiBtYXRyaXggdG8gZ2V0IGEgdHJ1ZXIgc2Vuc2Ugb2YgdGhlIHJlbGF0aXZlIGFidW5kYW5jZXMgYmV0d2VlbiBteQpleHBlcmltZW50YWwgY29uZGl0aW9ucy4KCmBgYHtyIGFsZnFfcXVhbnQsIGV2YWw9RkFMU0V9CmxpYnJhcnkoYUxGUSkKYWxmcV9wcm9jZXNzIDwtIFByb3RlaW5JbmZlcmVuY2UoYWxmcV9pbnB1dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVwdGlkZV9tZXRob2Q9InRvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcHRpZGVfdG9weD0zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXB0aWRlX3N0cmljdG5lc3M9Imxvb3NlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVwdGlkZV9zdW1tYXJ5PSJtZWFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNpdGlvbl90b3B4PTMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25fc3RyaWN0bmVzcz0ibG9vc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2l0aW9uX3N1bW1hcnk9InN1bSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhc3RhPU5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbD1OQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tYmluZV9wcmVjdXJzb3JzPUZBTFNFKQpgYGAKCiMgSW5kZXggdmVyc2lvbjogYHIgdmVyYAoKIyBUT0RPCgoqIDIwMTgtMDQtMTA6ICBNYWtlIHN1cmUgbXkgaW52b2NhdGlvbnMgb2YgU1dBVEgyc3RhdHMvTVNzdGF0cyBhcmUgY29ycmVjdC4KCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCiAgdGhpc19zYXZlIDwtIHBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cm1kX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikKICBtZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCiAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZT10aGlzX3NhdmUpKQogIHBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCn0KYGBgCg==