1 TODO

  • This is a copy of the same file dated 20180611, but an attempt to react to a query from Yan:
  • I am using this worksheet to also attempt to address figure-specific TODO items.

"I was baffled by your result that protein (or peptide) abundance of identified peptides were not changed between March and May. That will completely counter my assumption that a complete cleaning of the mass spec will solve our problem. I wonder how much would it will take to generate more detailed data from our old friend PE/PPE proteins. The information that will be helpful would be intensity, mass accuracy, and chromatography peak width of each peptide in each sample. Please feel free to stop by tomorrow if you have questions.

I like this group of proteins because 1. it’s of extra interest to Volker and Dallas, 2. it’s a small list of proteins, so easy to evaluate. and 3. Protein abundance covers a wide range, from relatively high abundance to barely detectable."

I think therefore I will leave the analyses here alone, but jump down to where I parse/plot the DIA data and attempt to subset it for the PPE proteins in ways similar/identical to Yan’s query. With that in mind, I am going to set eval=FALSE on the blocks of code in this file until I find the one which is actually relevant.

In addition, I am moving blocks of code/analysis up to the top which I think will be relevant.

1.1 Plotting metrics of identified peaks from DIA data

The pyprophet data for all DIA samples should provide the metrics in which Yan is interested. I will focus on the tuberculist transition libraries because that was the one I saw first.

1.1.1 The tuberculist data

pe_genes <- read.table("reference/annotated_pe_genes.txt")[[1]]
tb_pyprophet_fun <- extract_pyprophet_data(metadata="sample_sheets/Mtb_dia_samples.xlsx",
                                           pyprophet_column="tuberculistscored")
## Attempting to read the tsv file for: 2018_0315Briken01: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken01_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken02: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken02_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken03: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken03_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken04: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken04_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken05: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken05_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken06: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken06_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken21: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken21_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken22: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken22_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken23: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken23_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken24: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken24_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken25: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken25_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken26: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken26_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA07: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA07_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA08: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA08_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA09: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA09_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA11: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA11_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA12: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA12_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA01: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA01_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA02: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA02_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA03: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA03_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA04: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA04_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA05: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA05_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA06: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA06_vs_whole_HCD_dia_scored.tsv.
pe_pyprophet_fun <- subset_pyprophet_data(tb_pyprophet_fun, subset=pe_genes)

tb_mass_plot <- sm(plot_pyprophet_distribution(pe_pyprophet_fun, column="mass"))
pp(file="images/20180720_ppe_mass_boxplot.png", image=tb_mass_plot[["dotboxplot"]])
## Writing the image to: images/20180720_ppe_mass_boxplot.png and calling dev.off().

tb_intensity_plot <- sm(plot_pyprophet_distribution(pe_pyprophet_fun, column="intensity"))
pp(file="images/20180720_ppe_intensity_boxplot.png", image=tb_intensity_plot[["dotboxplot"]])
## Writing the image to: images/20180720_ppe_intensity_boxplot.png and calling dev.off().

tb_lwidth_plot <- sm(plot_pyprophet_distribution(pe_pyprophet_fun, column="leftwidth"))
pp(file="images/20180720_ppe_lwidth_boxplot.png", image=tb_lwidth_plot[["dotboxplot"]])
## Writing the image to: images/20180720_ppe_lwidth_boxplot.png and calling dev.off().

tb_rwidth_plot <- sm(plot_pyprophet_distribution(pe_pyprophet_fun, column="rightwidth"))
pp(file="images/20180720_ppe_rwidth_boxplot.png", image=tb_rwidth_plot[["dotboxplot"]])
## Writing the image to: images/20180720_ppe_rwidth_boxplot.png and calling dev.off().

tb_pyprophet_fun <- extract_pyprophet_data(metadata="sample_sheets/Mtb_dia_samples.xlsx",
                                           pyprophet_column="tuberculistscored")
## Attempting to read the tsv file for: 2018_0315Briken01: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken01_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken02: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken02_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken03: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken03_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken04: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken04_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken05: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken05_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken06: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken06_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken21: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken21_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken22: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken22_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken23: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken23_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken24: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken24_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken25: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken25_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0315Briken26: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0315Briken26_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA07: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA07_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA08: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA08_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA09: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA09_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA11: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA11_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA12: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA12_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA01: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA01_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA02: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA02_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA03: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA03_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA04: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA04_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA05: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA05_vs_whole_HCD_dia_scored.tsv.
## Attempting to read the tsv file for: 2018_0502BrikenDIA06: results/pyprophet/20180611/whole_8mz_tuberculist/2018_0502BrikenDIA06_vs_whole_HCD_dia_scored.tsv.
tb_mass_plot <- sm(plot_pyprophet_distribution(tb_pyprophet_fun, column="mass"))
tb_mass_plot[["boxplot"]]

tb_deltart_plot_all <- sm(plot_pyprophet_distribution(
  tb_pyprophet_fun, column="delta_rt"))
tb_deltart_plot_all[["boxplot"]]

tb_deltart_plot_real <- sm(plot_pyprophet_distribution(
  tb_pyprophet_fun,
  column="delta_rt", keep_decoys=FALSE))
tb_deltart_plot_real[["boxplot"]]

tb_deltart_plot_decoys <- sm(plot_pyprophet_distribution(
  tb_pyprophet_fun,
  column="delta_rt", keep_real=FALSE))
tb_deltart_plot_decoys[["boxplot"]]

tb_deltart_plot_decoys[["density"]]

tb_deltart_plot_decoys[["violin"]]

tb_widthvsmass <- sm(plot_pyprophet_data(tb_pyprophet_fun, legend=FALSE))
tb_widthvsmass$plot

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 file (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 the 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. In addition, SWATH2stats provides a similar conversion function which takes the tric output and coerces it into a similar matrix after performing its various filtering tasks. Therefore I will use that.

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.

2.1.1 Creating a swath2stats experiment using our comet-derived library data

loaded <- sm(devtools::load_all("~/scratch/git/SWATH2stats"))

our_tric_data <- read.csv("results/tric/20180611/whole_8mz/comet_HCD.tsv", sep="\t")

sample_annot <- openxlsx::read.xlsx("sample_sheets/Mtb_dia_samples.xlsx")
colnames(sample_annot) <- gsub(pattern="\\.", replacement="", x=colnames(sample_annot))
## Drop samples starting with comments
keep_idx <- ! grepl(pattern="^#", x=sample_annot[["sampleid"]])
sample_annot <- sample_annot[keep_idx, ]
sample_annot[["sampleid"]] <- paste0("s", sample_annot[["sampleid"]])
rownames(sample_annot) <- make.names(sample_annot[["sampleid"]], unique=TRUE)

expt_idx <- sample_annot[["expt_id"]] == "may2018" | sample_annot[["expt_id"]] == "mar2018"
expt_idx[is.na(sample_annot[["expt_id"]])] <- FALSE
sample_annot <- sample_annot[expt_idx, ]
mz_idx <- sample_annot[["windowsize"]] == "8"
sample_annot <- sample_annot[mz_idx, ]
## Set the mzXML column to match the filename column in the data.

## s2s, my witty way of shortening SWATH2stats...
our_s2s_exp <- sample_annotation(data=our_tric_data,
                                 sample_annotation=sample_annot,
                                 run_column="run",
                                 fullpeptidename_column="fullunimodpeptidename")
## Found the same mzXML files in the annotations and data.

2.1.2 Creating a swath2stats experiment using the tuberculist-derived library data

This just repeats the previous stanza, but uses the tuberculist transition-library swath data as its input rather than our own comet data.

There is one important caveat in the following block: I used a regex to remove the second half of geneID_geneName so that later when I merge in the annotation data I have it will match.

tb_tric_data <- read.csv("results/tric/20180611/whole_8mz_tuberculist/comet_HCD.tsv", sep="\t")

tb_tric_data[["ProteinName"]] <- gsub(pattern="^(.*)_.*$", replacement="\\1",
                                      x=tb_tric_data[["ProteinName"]])
tb_s2s_exp <- sample_annotation(data=tb_tric_data,
                                sample_annotation=sample_annot,
                                fullpeptidename_column="fullunimodpeptidename")
## Found the same mzXML files in the annotations and 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

The various metrics and filters provided by SWATH2stats seem quite reasonable to me. The only thing that really bothers me is that they are all case sensitive and I found that the most recent tric changed the capitalization of a column, causing these to all fall down. Therefore I went in and made everything case insensitive in a fashion similar to that done by MSstats (except I hate capital letters, so I used tolower() rather than toupper()).

3.1 Run filters on our comet data

## Get correlations on a sample by sample basis
pp(file="images/20180611_our_swath2stats_sample_cor.png")
## Going to write the image to: images/20180611_our_swath2stats_sample_cor.png when dev.off() is called.
sample_cor <- plot_correlation_between_samples(our_s2s_exp, size=2,
                                               fun.aggregate=sum,
                                               column.values="intensity")
dev.off()
## png 
##   2
sample_cond_rep_cor <- plot_correlation_between_samples(our_s2s_exp, size=2,
                                                        comparison=transition_group_id ~
                                                          condition + bioreplicate + run,
                                                        fun.aggregate=sum,
                                                        column.values="intensity")

decoy_lists <- assess_decoy_rate(our_s2s_exp)
## Number of non-decoy peptides: 3259
## Number of decoy peptides: 182
## Decoy rate: 0.0558
## This seems a bit high to me, yesno?
fdr_overall <- assess_fdr_overall(our_s2s_exp, output="Rconsole", plot=TRUE)

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

chosen_mscore <- mscore4assayfdr(our_s2s_exp, FFT=0.7, fdr_target=0.02)
## Target assay FDR: 0.02
## Required overall m-score cutoff: 0.0019953
## achieving assay FDR: 0.0189
prot_score <- mscore4protfdr(our_s2s_exp, FFT=0.7, fdr_target=0.02)
## Target protein FDR: 0.02
## Required overall m-score cutoff: 0.00050119
## achieving protein FDR: 0.0181
our_mscore_filtered <- filter_mscore(our_s2s_exp, chosen_mscore)
## Original dimension: 47362, new dimension: 45761, difference: 1601.
our_freq_mscore <- filter_mscore_freqobs(our_s2s_exp, 0.01, 0.8, rm.decoy=FALSE)
## Peptides need to have been quantified in more conditions than: 18.4 in order to pass this percentage-based threshold.
## Fraction of peptides selected: 0.33
## Original dimension: 47841, new dimension: 26232, difference: 21609.
our_data_filtered_fdr <- filter_mscore_fdr(our_mscore_filtered, FFT=0.7,
                                           overall_protein_fdr_target=prot_score,
                                           upper_overall_peptide_fdr_limit=0.05)
## Target protein FDR: 0.000501187233627273
## Required overall m-score cutoff: 0.01
## achieving protein FDR: 0
## 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.01
## Achieving peptide FDR: 0
## Proteins selected: 
## Total proteins selected: 945
## Final target proteins: 945
## Final decoy proteins: 0
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 3203
## Final target peptides: 3203
## Final decoy peptides: 0
## Total peptides selected from:
## Total peptides: 3203
## Final target peptides: 3203
## Final decoy peptides: 0
## Individual run FDR quality of the peptides was not calculated
## as not every run contains a decoy.
## The decoys have been removed from the returned data.
our_only_proteotypic <- filter_proteotypic_peptides(our_data_filtered_fdr)
## Number of proteins detected: 947
## Protein identifiers: Rv1908c, Rv0242c, Rv3224, Rv0667, Rv1133c, Rv3036c
## Number of proteins detected that are supported by a proteotypic peptide: 930
## Number of proteotypic peptides detected: 3158
our_all_filtered <- filter_all_peptides(our_only_proteotypic)
## Number of proteins detected: 930
## First 6 protein identifiers: Rv1908c, Rv0242c, Rv3224, Rv0667, Rv1133c, Rv3036c
our_only_strong <- filter_on_max_peptides(data=our_all_filtered, n_peptides=10)
## Before filtering:
##   Number of proteins: 930
##   Number of peptides: 3158
## 
## Percentage of peptides removed: 8.61%
## 
## After filtering:
##   Number of proteins: 928
##   Number of peptides: 2886
our_only_minimum <- filter_on_min_peptides(data=our_only_strong, n_peptides=3)
## Before filtering:
##   Number of proteins: 928
##   Number of peptides: 2886
## 
## Percentage of peptides removed: 0%
## 
## After filtering:
##   Number of proteins: 895
##   Number of peptides: 2886
## 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.
matrix_prefix <- file.path("results", "swath2stats", ver)
if (!file.exists(matrix_prefix)) {
  dir.create(matrix_prefix)
}
protein_matrix_all <- write_matrix_proteins(
  our_s2s_exp, write.csv=TRUE,
  filename=file.path(matrix_prefix, "our_protein_all.csv"))
## Protein overview matrix results/swath2stats/20180611/our_protein_all.csv written to working folder.
dim(protein_matrix_all)
## [1] 1110   24
protein_matrix_mscore <- write_matrix_proteins(
  our_mscore_filtered, write.csv=TRUE,
  filename=file.path(matrix_prefix, "our_protein_matrix_mscore.csv"))
## Protein overview matrix results/swath2stats/20180611/our_protein_matrix_mscore.csv written to working folder.
dim(protein_matrix_mscore)
## [1] 945  24
peptide_matrix_mscore <- write_matrix_peptides(
  our_mscore_filtered, write.csv=TRUE,
  filename=file.path(matrix_prefix, "our_peptide_matrix_mscore.csv"))
## Peptide overview matrix results/swath2stats/20180611/our_peptide_matrix_mscore.csv written to working folder.
dim(peptide_matrix_mscore)
## [1] 3203   24
protein_matrix_minimum <- write_matrix_proteins(
  our_only_minimum, write.csv=TRUE,
  filename=file.path(matrix_prefix, "our_protein_matrix_minimum.csv"))
## Protein overview matrix results/swath2stats/20180611/our_protein_matrix_minimum.csv written to working folder.
dim(protein_matrix_minimum)
## [1] 895  24
peptide_matrix_minimum <- write_matrix_peptides(
  our_only_minimum, write.csv=TRUE,
  filename=file.path(matrix_prefix, "our_peptide_matrix_minimum.csv"))
## Peptide overview matrix results/swath2stats/20180611/our_peptide_matrix_minimum.csv written to working folder.
dim(peptide_matrix_minimum)
## [1] 38491    24
rt_cor <- plot_correlation_between_samples(
  our_only_minimum, column.values="intensity", fun.aggregate=sum, size=2)

## I have no effing clue what this plot means.
variation <- plot_variation(our_only_minimum, fun.aggregate=sum)

cols <- colnames(our_only_minimum)
our_disaggregated <- disaggregate(our_only_minimum, all.columns=TRUE)
## The library contains6transitions per precursor.
## The data table was transformed into a table containing one row per transition.
our_msstats_input <- convert_MSstats(our_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.

3.2 Run filters on the tuberculist

Repeat the above stanza using the tuberculist data.

## Get correlations on a sample by sample basis
pp(file="images/20180611_tb_swath2stats_sample_cor.png")
## Going to write the image to: images/20180611_tb_swath2stats_sample_cor.png when dev.off() is called.
sample_cor <- plot_correlation_between_samples(tb_s2s_exp, size=2,
                                               fun.aggregate=sum,
                                               column.values="intensity")
dev.off()
## png 
##   2
sample_cond_rep_cor <- plot_correlation_between_samples(tb_s2s_exp, size=2,
                                                        comparison=transition_group_id ~
                                                          condition + bioreplicate + run,
                                                        fun.aggregate=sum,
                                                        column.values="intensity")

decoy_lists <- assess_decoy_rate(tb_s2s_exp)
## Number of non-decoy peptides: 23975
## Number of decoy peptides: 1762
## Decoy rate: 0.0735
## This seems a bit high to me, yesno?
fdr_overall <- assess_fdr_overall(tb_s2s_exp, output="Rconsole", plot=TRUE)

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

chosen_mscore <- mscore4assayfdr(tb_s2s_exp, FFT=0.7, fdr_target=0.02)
## Target assay FDR: 0.02
## Required overall m-score cutoff: 0.0056234
## achieving assay FDR: 0.019
prot_score <- mscore4protfdr(tb_s2s_exp, FFT=0.7, fdr_target=0.02)
## Target protein FDR: 0.02
## Required overall m-score cutoff: 0.00070795
## achieving protein FDR: 0.0198
tb_mscore_filtered <- filter_mscore(tb_s2s_exp, chosen_mscore)
## Original dimension: 252491, new dimension: 231348, difference: 21143.
tb_freq_mscore <- filter_mscore_freqobs(tb_s2s_exp, 0.01, 0.8, rm.decoy=FALSE)
## Peptides need to have been quantified in more conditions than: 18.4 in order to pass this percentage-based threshold.
## Fraction of peptides selected: 0.083
## Original dimension: 256996, new dimension: 56485, difference: 200511.
tb_data_filtered_fdr <- filter_mscore_fdr(tb_mscore_filtered, FFT=0.7,
                                           overall_protein_fdr_target=prot_score,
                                           upper_overall_peptide_fdr_limit=0.05)
## Target protein FDR: 0.000707945784384137
## Required overall m-score cutoff: 0.01
## achieving protein FDR: 0
## 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.01
## Achieving peptide FDR: 0
## Proteins selected: 
## Total proteins selected: 3087
## Final target proteins: 3087
## Final decoy proteins: 0
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 22671
## Final target peptides: 22671
## Final decoy peptides: 0
## Total peptides selected from:
## Total peptides: 22671
## Final target peptides: 22671
## Final decoy peptides: 0
## Individual run FDR quality of the peptides was not calculated
## as not every run contains a decoy.
## The decoys have been removed from the returned data.
tb_only_proteotypic <- filter_proteotypic_peptides(tb_data_filtered_fdr)
## Number of proteins detected: 3101
## Protein identifiers: Rv1270c, Rv0161, Rv1613, Rv2540c, Rv0440, Rv1327c
## Number of proteins detected that are supported by a proteotypic peptide: 2964
## Number of proteotypic peptides detected: 22510
tb_all_filtered <- filter_all_peptides(tb_only_proteotypic)
## Number of proteins detected: 2966
## First 6 protein identifiers: Rv1270c, Rv0161, Rv1613, Rv2540c, Rv0440, Rv1327c
tb_only_strong <- filter_on_max_peptides(data=tb_all_filtered, n_peptides=10)
## Before filtering:
##   Number of proteins: 2964
##   Number of peptides: 22510
## 
## Percentage of peptides removed: 23.15%
## 
## After filtering:
##   Number of proteins: 2936
##   Number of peptides: 17299
tb_only_minimum <- filter_on_min_peptides(data=tb_only_strong, n_peptides=3)
## Before filtering:
##   Number of proteins: 2936
##   Number of peptides: 17299
## 
## Percentage of peptides removed: 0.03%
## 
## After filtering:
##   Number of proteins: 2679
##   Number of peptides: 17293
## 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.
matrix_prefix <- file.path("results", "swath2stats", ver)
if (!file.exists(matrix_prefix)) {
  dir.create(matrix_prefix)
}
protein_matrix_all <- write_matrix_proteins(
  tb_s2s_exp, write.csv=TRUE,
  filename=file.path(matrix_prefix, "tb_protein_all.csv"))
## Protein overview matrix results/swath2stats/20180611/tb_protein_all.csv written to working folder.
dim(protein_matrix_all)
## [1] 4570   24
protein_matrix_mscore <- write_matrix_proteins(
  tb_mscore_filtered, write.csv=TRUE,
  filename=file.path(matrix_prefix, "tb_protein_matrix_mscore.csv"))
## Protein overview matrix results/swath2stats/20180611/tb_protein_matrix_mscore.csv written to working folder.
dim(protein_matrix_mscore)
## [1] 3087   24
peptide_matrix_mscore <- write_matrix_peptides(
  tb_mscore_filtered, write.csv=TRUE,
  filename=file.path(matrix_prefix, "tb_peptide_matrix_mscore.csv"))
## Peptide overview matrix results/swath2stats/20180611/tb_peptide_matrix_mscore.csv written to working folder.
dim(peptide_matrix_mscore)
## [1] 22671    24
protein_matrix_minimum <- write_matrix_proteins(
  tb_only_minimum, write.csv=TRUE,
  filename=file.path(matrix_prefix, "tb_protein_matrix_minimum.csv"))
## Protein overview matrix results/swath2stats/20180611/tb_protein_matrix_minimum.csv written to working folder.
dim(protein_matrix_minimum)
## [1] 2679   24
peptide_matrix_minimum <- write_matrix_peptides(
  tb_only_minimum, write.csv=TRUE,
  filename=file.path(matrix_prefix, "tb_peptide_matrix_minimum.csv"))
## Peptide overview matrix results/swath2stats/20180611/tb_peptide_matrix_minimum.csv written to working folder.
dim(peptide_matrix_minimum)
## [1] 164565     24
rt_cor <- plot_correlation_between_samples(size=2,
  tb_only_minimum, column.values="intensity", fun.aggregate=sum)

## I have no effing clue what this plot means.
variation <- plot_variation(tb_only_minimum, fun.aggregate=sum)

cols <- colnames(tb_only_minimum)
tb_disaggregated <- disaggregate(tb_only_minimum, all.columns=TRUE)
## The library contains5transitions per precursor.
## The data table was transformed into a table containing one row per transition.
tb_msstats_input <- convert_MSstats(tb_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.

3.3 Some new plots

In response to some interesting queries from Yan, I made a few little functions which query and plot data from the scored data provided by openswath/pyprophet. Let us look at their results here.

3.3.1 Using the comet data

our_pyprophet_fun <- sm(extract_pyprophet_data(metadata="sample_sheets/Mtb_dia_samples.xlsx"))

our_mass_plot <- sm(plot_pyprophet_distribution(our_pyprophet_fun, column="mass"))
our_mass_plot[["boxplot"]]

our_mass_plot[["density"]]

our_deltart_plot_all <- sm(plot_pyprophet_distribution(
  our_pyprophet_fun, column="delta_rt"))
our_deltart_plot_all[["boxplot"]]

our_deltart_plot_real <- sm(plot_pyprophet_distribution(
  our_pyprophet_fun,
  column="delta_rt", keep_decoys=FALSE))
our_deltart_plot_real[["boxplot"]]

our_deltart_plot_decoys <- sm(plot_pyprophet_distribution(
  our_pyprophet_fun,
  column="delta_rt", keep_real=FALSE))
our_deltart_plot_decoys[["boxplot"]]

our_deltart_plot_decoys[["density"]]

our_widthvsmass <- sm(plot_pyprophet_data(our_pyprophet_fun, legend=FALSE))
our_widthvsmass$plot

3.4 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.

3.4.1 Comet derived msstats

devtools::load_all("~/scratch/git/MSstats")
our_msstats_quant <- dataProcess(our_msstats_input)
our_msstats_plots <- sm(dataProcessPlots(our_msstats_quant, type="QCPLOT"))

my_levels <- levels(as.factor(our_msstats_input$condition))
my_levels
comparisons <- ghetto_contrast_matrix(
  numerators=c("wt_filtrate", "delta_filtrate", "comp_filtrate",
               "delta_filtrate", "comp_filtrate", "delta_whole",
               "comp_whole"),
  denominators=c("wt_whole", "delta_whole", "comp_whole",
                 "wt_filtrate", "wt_filtrate", "wt_whole",
                 "wt_whole"))
our_results <- list()
for (c in 1:length(rownames(comparisons))) {
  name <- rownames(comparisons)[c]
  message("Starting ", name)
  comp <- comparisons[c, ]
  comparison <- t(as.matrix(comp))
  rownames(comparison) <- name
  our_results[name] <- sm(MSstats::groupComparison(contrast.matrix=comparison,
                                                   data=our_msstats_quant))
}

4 This is Relevant to Yan’s query!

4.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 <- our_msstats_plots$QCPLOT
available_plots <- gsub(pattern="^1/", replacement="",
                        x=levels(our_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]])
}
dev.off()
length(pe_plots)

4.1.1 Tuberculist derived msstats

tb_msstats_quant <- dataProcess(tb_msstats_input)
##tb_msstats_plots <- sm(dataProcessPlots(tb_msstats_quant, type="QCPLOT"))

my_levels <- levels(as.factor(tb_msstats_input$condition))
my_levels
comparisons <- ghetto_contrast_matrix(
  numerators=c("wt_filtrate", "delta_filtrate", "comp_filtrate",
               "delta_filtrate", "comp_filtrate", "delta_whole",
               "comp_whole"),
  denominators=c("wt_whole", "delta_whole", "comp_whole",
                 "wt_filtrate", "wt_filtrate", "wt_whole",
                 "wt_whole"))
tb_results <- list()
for (c in 1:length(rownames(comparisons))) {
  name <- rownames(comparisons)[c]
  message("Starting ", name)
  comp <- comparisons[c, ]
  comparison <- t(as.matrix(comp))
  rownames(comparison) <- name
  tb_results[name] <- sm(MSstats::groupComparison(contrast.matrix=comparison,
                                                   data=tb_msstats_quant))
}

5 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.

5.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.

5.2 Massaging the intensity matrix

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

5.2.1 Make matrices with our libraries

our_prot_mtrx <- read.csv(file.path("results", "swath2stats", ver, "our_protein_matrix_minimum.csv"))
rownames(our_prot_mtrx) <- gsub(pattern="^1\\/", replacement="", x=our_prot_mtrx[["proteinname"]])
our_prot_mtrx <- our_prot_mtrx[, -1]
## Important question: Did SWATH2stats reorder my data?
colnames(our_prot_mtrx) <- gsub(pattern="^.*2018", replacement="s2018", x=colnames(our_prot_mtrx))

5.2.2 Make matrices with the tb libraries

tb_prot_mtrx <- read.csv(file.path("results", "swath2stats", ver, "tb_protein_matrix_minimum.csv"))
rownames(tb_prot_mtrx) <- gsub(pattern="^1\\/", replacement="", x=tb_prot_mtrx[["proteinname"]])
tb_prot_mtrx <- tb_prot_mtrx[, -1]
## Important question: Did SWATH2stats reorder my data?
colnames(tb_prot_mtrx) <- gsub(pattern="^.*2018", replacement="s2018", x=colnames(tb_prot_mtrx))

5.3 Merge the pieces

Now we should have sufficient pieces to make an expressionset.

While here, I will also split the data into a cf and whole-cell pair of data structures.

5.3.1 Our data

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

our_protein_expt <- create_expt(metadata=our_metadata,
                                count_dataframe=our_prot_mtrx,
                                gene_info=mtb_annotations)
## Reading the sample metadata.
## The sample definitions comprises: 23, 27 rows, columns.
## Matched 892 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
new_colors <- c("#1B9E77", "#D95F02", "#7570B3", "#E7298A", "#66A61E", "#E6AB02")
names(new_colors) <- c("comp_filtrate", "comp_whole", "delta_filtrate", "delta_whole", "wt_filtrate", "wt_whole")
names(new_colors) <- c("wt_whole", "comp_whole", "delta_whole", "delta_filtrate", "wt_filtrate", "comp_filtrate")
our_protein_expt <- set_expt_colors(our_protein_expt, new_colors)
## The new colors are a character, changing according to condition.
our_whole_expt <- subset_expt(our_protein_expt, subset="collectiontype=='whole'")
## There were 23, now there are 11 samples.
our_cf_expt <- subset_expt(our_protein_expt, subset="collectiontype=='filtrate'")
## There were 23, now there are 12 samples.

5.3.2 Tb data

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

tb_protein_expt <- sm(create_expt(metadata,
                                  count_dataframe=tb_prot_mtrx,
                                  gene_info=mtb_annotations))
written <- write_expt(tb_protein_expt, excel=paste0("excel/written-v", ver, ".xlsx"))
## Writing the legend.
## Writing the raw reads.
## Graphing the raw reads.

## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Writing the normalized reads.
## Graphing the normalized reads.

## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Writing the median reads by factor.
## The factor comp_filtrate has 3 rows.
## The factor comp_whole has 2 rows.
## The factor delta_filtrate has 3 rows.
## The factor delta_whole has 3 rows.
## The factor wt_filtrate has 6 rows.
## The factor wt_whole has 6 rows.

tb_whole_expt <- subset_expt(tb_protein_expt, subset="collectiontype=='whole'")
## There were 23, now there are 11 samples.
tb_cf_expt <- subset_expt(tb_protein_expt, subset="collectiontype=='filtrate'")
## There were 23, now there are 12 samples.

5.4 Metrics of the full data set

5.4.1 Our libraries

our_protein_metrics <- sm(graph_metrics(our_protein_expt))
our_protein_norm <- sm(normalize_expt(our_protein_expt, transform="log2", convert="cpm",
                                      norm="quant", filter=TRUE))
our_protein_norm_metrics <- sm(graph_metrics(our_protein_norm))
our_protein_fsva <- sm(normalize_expt(our_protein_expt, transform="log2",
                                   batch="fsva", filter=TRUE))
our_protein_fsva_metrics <- sm(graph_metrics(our_protein_fsva))

5.4.2 Tb libraries

tb_protein_metrics <- sm(graph_metrics(tb_protein_expt))
tb_protein_varplot <- plot_variance_coefficients(tb_protein_expt, x_axis="batch")
## Naively calculating coefficient of variation and quartile dispersion with respect to batch.
## Finished calculating dispersion estimates.
tb_protein_varplot <- plot_variance_coefficients(tb_protein_expt)
## Naively calculating coefficient of variation and quartile dispersion with respect to condition.
## Finished calculating dispersion estimates.
tb_protein_norm <- sm(normalize_expt(tb_protein_expt, transform="log2", convert="cpm",
                                     norm="quant", filter=TRUE))
tb_protein_norm_metrics <- sm(graph_metrics(tb_protein_norm))
tb_protein_fsva <- sm(normalize_expt(tb_protein_expt, transform="log2", convert="cpm",
                                     batch="fsva", filter=TRUE))
tb_protein_fsva_metrics <- sm(graph_metrics(tb_protein_fsva))

5.5 Metrics of the whole-cell data set

5.5.1 Our libraries

our_whole_metrics <- sm(graph_metrics(our_whole_expt))
our_whole_norm <- sm(normalize_expt(our_whole_expt, transform="log2", convert="cpm",
                                    norm="quant", filter=TRUE))
our_whole_norm_metrics <- sm(graph_metrics(our_whole_norm))
our_whole_fsva <- sm(normalize_expt(our_whole_expt, transform="log2", convert="cpm",
                                    batch="fsva", filter=TRUE))
our_whole_fsva_metrics <- sm(graph_metrics(our_whole_fsva))

5.5.2 Tb libraries

tb_whole_metrics <- sm(graph_metrics(tb_whole_expt))
tb_whole_norm <- sm(normalize_expt(tb_whole_expt, transform="log2", convert="cpm",
                                    norm="quant", filter=TRUE))
tb_whole_norm_metrics <- sm(graph_metrics(tb_whole_norm))
tb_whole_fsva <- sm(normalize_expt(tb_whole_expt, transform="log2", convert="cpm",
                                    batch="fsva", filter=TRUE))
tb_whole_fsva_metrics <- sm(graph_metrics(tb_whole_fsva))

5.6 Metrics of the filtrate data set

5.6.1 Our libraries

our_cf_metrics <- sm(graph_metrics(our_cf_expt))
our_cf_norm <- sm(normalize_expt(our_cf_expt, transform="log2", convert="cpm",
                                 norm="quant", filter=TRUE))
our_cf_norm_metrics <- sm(graph_metrics(our_cf_norm))
our_cf_fsva <- sm(normalize_expt(our_cf_expt, transform="log2", convert="cpm",
                                 batch="fsva", filter=TRUE))
our_cf_fsva_metrics <- sm(graph_metrics(our_cf_fsva))

5.6.2 Tb libraries

tb_cf_metrics <- sm(graph_metrics(tb_cf_expt))
tb_cf_norm <- sm(normalize_expt(tb_cf_expt, transform="log2", convert="cpm",
                                 norm="quant", filter=TRUE))
tb_cf_norm_metrics <- sm(graph_metrics(tb_cf_norm))
tb_cf_fsva <- sm(normalize_expt(tb_cf_expt, transform="log2", convert="cpm",
                                 batch="fsva", filter=TRUE))
tb_cf_fsva_metrics <- sm(graph_metrics(tb_cf_fsva))

5.7 plot some metrics

5.7.1 Our libraries

pp(image=our_protein_metrics$libsize,
   file=file.path("images", paste0(ver, "_our_libsize.png")))
## It seems to me that the scale of the data is all within an order of magnitude or two.
## I cannot get used to these absurdly large numbers though.
pp(image=our_protein_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_our_norm_pca.png")))
## There appears to be a nice split in the data, however the un-assayable batch
## effect is a problem.
pp(image=our_protein_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_fsva_pca.png")))
## fsva seems to get some handle on the data, but I don't think we should rely
## upon it.
pp(image=our_protein_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_norm_corheat.png")))
## Once again, the whole-cell/culture-filtrate split is very large.
pp(image=our_protein_metrics$density,
   file=file.path("images", paste0(ver, "_raw_density.png")))
## There are two obvious distributions in the data, once again split between types.
pp(image=our_protein_metrics$boxplot,
   file=file.path("images", paste0(ver, "_boxplot.png")))
## This recapitulates the previous plot.

pp(image=our_whole_metrics$libsize,
   file=file.path("images", paste0(ver, "_whole_libsize.png")))
pp(image=our_whole_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_whole_norm_pca.png")))
pp(image=our_whole_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_whole_fsva_pca.png")))
pp(image=our_whole_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_whole_norm_corheat.png")))
pp(image=our_whole_metrics$density,
   file=file.path("images", paste0(ver, "_whole_raw_density.png")))
pp(image=our_whole_metrics$boxplot,
   file=file.path("images", paste0(ver, "_whole_boxplot.png")))

pp(image=our_cf_metrics$libsize,
   file=file.path("images", paste0(ver, "_libsize.png")))
pp(image=our_cf_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_norm_pca.png")))
pp(image=our_cf_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_fsva_pca.png")))
pp(image=our_cf_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_norm_corheat.png")))
pp(image=our_cf_metrics$density,
   file=file.path("images", paste0(ver, "_raw_density.png")))
pp(image=our_cf_metrics$boxplot,
   file=file.path("images", paste0(ver, "_boxplot.png")))

5.7.2 Tb libraries

I think the figure S1 intensities may come from these:

## Reminder:  tb_protein_metrics <- sm(graph_metrics(tb_protein_expt))
figure_expt <- set_expt_samplenames(tb_protein_expt, pData(tb_protein_expt)[["figurename"]])
fig_s1a <- plot_libsize(figure_expt, title="", order_by="condition", y_label="Sum(intensities) by run",
                        order=c("wt_whole", "delta_whole", "comp_whole",
                                "wt_filtrate", "delta_filtrate", "comp_filtrate"))
## Warning in mode(current): NAs introduced by coercion to integer range
## The scale difference between the smallest and largest
## libraries is > 10. Assuming a log10 scale is better, set scale=FALSE if not.
pp(file="images/fig_s1a.pdf", image=fig_s1a$plot)
## Writing the image to: images/fig_s1a.pdf and calling dev.off().

pp(image=tb_protein_metrics$libsize,
   file=file.path("images", paste0(ver, "_tb_libsize.png")))
## Writing the image to: images/20180611_tb_libsize.png and calling dev.off().

## It seems to me that the scale of the data is all within an order of magnitude or two.
## I cannot get used to these absurdly large numbers though.
pp(image=tb_protein_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_tb_norm_pca.png")))
## Writing the image to: images/20180611_tb_norm_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

## There appears to be a nice split in the data, however the un-assayable batch
## effect is a problem.
pp(image=tb_protein_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_fsva_pca.png")))
## Writing the image to: images/20180611_fsva_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

## fsva seems to get some handle on the data, but I don't think we should rely
## upon it.
pp(image=tb_protein_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_norm_corheat.png")))
## Writing the image to: images/20180611_norm_corheat.png and calling dev.off().

## Once again, the whole-cell/culture-filtrate split is very large.
pp(image=tb_protein_metrics$density,
   file=file.path("images", paste0(ver, "_raw_density.png")))
## Writing the image to: images/20180611_raw_density.png and calling dev.off().

## There are two obvious distributions in the data, once again split between types.
pp(image=tb_protein_metrics$boxplot,
   file=file.path("images", paste0(ver, "_boxplot.png")))
## Writing the image to: images/20180611_boxplot.png and calling dev.off().

## This recapitulates the previous plot.

pp(image=tb_whole_metrics$libsize,
   file=file.path("images", paste0(ver, "_whole_libsize.png")))
## Writing the image to: images/20180611_whole_libsize.png and calling dev.off().

pp(image=tb_whole_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_whole_norm_pca.png")))
## Writing the image to: images/20180611_whole_norm_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

pp(image=tb_whole_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_whole_fsva_pca.png")))
## Writing the image to: images/20180611_whole_fsva_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

pp(image=tb_whole_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_whole_norm_corheat.png")))
## Writing the image to: images/20180611_whole_norm_corheat.png and calling dev.off().

pp(image=tb_whole_metrics$density,
   file=file.path("images", paste0(ver, "_whole_raw_density.png")))
## Writing the image to: images/20180611_whole_raw_density.png and calling dev.off().

pp(image=tb_whole_metrics$boxplot,
   file=file.path("images", paste0(ver, "_whole_boxplot.png")))
## Writing the image to: images/20180611_whole_boxplot.png and calling dev.off().

pp(image=tb_cf_metrics$libsize,
   file=file.path("images", paste0(ver, "_libsize.png")))
## Writing the image to: images/20180611_libsize.png and calling dev.off().

pp(image=tb_cf_norm_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_norm_pca.png")))
## Writing the image to: images/20180611_norm_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

pp(image=tb_cf_fsva_metrics$pcaplot,
   file=file.path("images", paste0(ver, "_fsva_pca.png")))
## Writing the image to: images/20180611_fsva_pca.png and calling dev.off().
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse
## Too few points to calculate an ellipse

pp(image=tb_cf_norm_metrics$corheat,
   file=file.path("images", paste0(ver, "_norm_corheat.png")))
## Writing the image to: images/20180611_norm_corheat.png and calling dev.off().

pp(image=tb_cf_metrics$density,
   file=file.path("images", paste0(ver, "_raw_density.png")))
## Writing the image to: images/20180611_raw_density.png and calling dev.off().

pp(image=tb_cf_metrics$boxplot,
   file=file.path("images", paste0(ver, "_boxplot.png")))
## Writing the image to: images/20180611_boxplot.png and calling dev.off().

6 Attempt some quantification comparisons?

6.1 Our libraries

our_pairwise_filt <- sm(normalize_expt(our_protein_expt, filter=TRUE))
our_pairwise_comp <- sm(all_pairwise(our_pairwise_filt, model_batch="fsva", force=TRUE))
our_pairwise_nobatch <- sm(all_pairwise(our_pairwise_filt, model_batch=FALSE, force=TRUE))

6.2 Tb libraries

tb_pairwise_filt <- sm(normalize_expt(tb_protein_expt, filter=TRUE))
tb_pairwise_comp <- sm(all_pairwise(tb_pairwise_filt, model_batch="fsva", force=TRUE))
tb_pairwise_nobatch <- sm(all_pairwise(tb_pairwise_filt, model_batch=FALSE, force=TRUE))

6.2.1 Show a few metrics from the hpgltools pairwise comparisons

our_pairwise_comp$comparison$heat

tb_pairwise_comp$comparison$heat

7 For each msstats run, do a DE table

7.1 wt_filtrate vs wt_whole

7.1.1 Our libraries

keepers <- list(
  "wtcf_vs_wtwhole" = c("wt_filtrate", "wt_whole"))
droppers <- c("undefined")
names(droppers) <- "log2fc"

## Make sure to set the rownames so it will merge into the excel file.
set_name <- "wt_filtrate_vs_wt_whole"
rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
## Error in eval(expr, envir, enclos): object 'our_results' not found
wtcf_wtwhole_tables <- sm(combine_de_tables(
  ## our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excludes=droppers,
  excel=paste0("excel/our_wtcf_vs_wtwhole_tables-v", ver, ".xlsx")))
wtcf_nobatch_wtwhole_tables <- sm(combine_de_tables(
  ## our_pairwise_nobatch, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_nobatch, keepers=keepers,
  excludes=droppers,
  excel=paste0("excel/our_wtcf_vs_wtwhole_nobatch_tables-v", ver, ".xlsx")))
##comp_table <- wtcf_wtwhole_tables$data[[set_name]]
##cor.test(comp_table$log2fc, comp_table$deseq_logfc, method="spearman")

##comp_table <- wtcf_nobatch_wtwhole_tables$data[[set_name]]
##cor.test(comp_table$log2fc, comp_table$deseq_logfc, method="spearman")

7.1.2 Tb libraries

keepers <- list(
  "wtcf_vs_wtwhole" = c("wt_filtrate", "wt_whole"))
droppers <- c("undefined")
names(droppers) <- "log2fc"

## Make sure to set the rownames so it will merge into the excel file.
set_name <- "wt_filtrate_vs_wt_whole"
## rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
wtcf_wtwhole_tables <- sm(combine_de_tables(
  ## tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excludes=droppers,
  excel=paste0("excel/tb_wtcf_vs_wtwhole_tables-v", ver, ".xlsx")))
wtcf_nobatch_wtwhole_tables <- sm(combine_de_tables(
  ## tb_pairwise_nobatch, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_nobatch, keepers=keepers,
  excludes=droppers,
  excel=paste0("excel/tb_wtcf_vs_wtwhole_nobatch_tables-v", ver, ".xlsx")))
##comp_table <- wtcf_wtwhole_tables$data[[set_name]]
##cor.test(comp_table$log2fc, comp_table$deseq_logfc, method="spearman")

##comp_table <- wtcf_nobatch_wtwhole_tables$data[[set_name]]
##cor.test(comp_table$log2fc, comp_table$deseq_logfc, method="spearman")

7.2 delta_filtrate vs delta_whole

7.2.1 Our libraries

keepers <- list(
  "deltacf_vs_deltawhole" = c("delta_filtrate", "delta_whole"))
set_name <- "delta_filtrate_vs_delta_whole"
## rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
deltacf_deltawhole_tables <- sm(combine_de_tables(
  ##  our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_deltacf_vs_deltawhole_tables-v", ver, ".xlsx")))

7.2.2 Tb libraries

keepers <- list(
  "deltacf_vs_deltawhole" = c("delta_filtrate", "delta_whole"))
set_name <- "delta_filtrate_vs_delta_whole"
## rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
deltacf_deltawhole_tables <- sm(combine_de_tables(
##  tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_deltacf_vs_deltawhole_tables-v", ver, ".xlsx")))

7.3 comp_filtrate vs comp_whole

7.3.1 Our libraries

keepers <- list(
  "compcf_vs_compwhole" = c("comp_filtrate", "comp_whole"))
set_name <- "comp_filtrate_vs_comp_whole"
rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
## Error in eval(expr, envir, enclos): object 'our_results' not found
compcf_compwhole_tables <- sm(combine_de_tables(
##  our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_compcf_vs_compwhole_tables-v", ver, ".xlsx")))

7.3.2 Tb libraries

keepers <- list(
  "compcf_vs_compwhole" = c("comp_filtrate", "comp_whole"))
set_name <- "comp_filtrate_vs_comp_whole"
##rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
compcf_compwhole_tables <- sm(combine_de_tables(
##  tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_compcf_vs_compwhole_tables-v", ver, ".xlsx")))

7.4 delta_filtrate vs wt_filtrate

7.4.1 Our libraries

keepers <- list(
  "deltacf_vs_wtcf" = c("delta_filtrate", "wt_filtrate"))
set_name <- "delta_filtrate_vs_wt_filtrate"
##rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
deltacf_wtcf_tables <- sm(combine_de_tables(
##  our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_deltacf_vs_wtcf_tables-v", ver, ".xlsx")))

7.4.2 Tb libraries

keepers <- list(
  "deltacf_vs_wtcf" = c("delta_filtrate", "wt_filtrate"))
set_name <- "delta_filtrate_vs_wt_filtrate"
##rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
deltacf_wtcf_tables <- sm(combine_de_tables(
  ##tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_deltacf_vs_wtcf_tables-v", ver, ".xlsx")))

7.5 comp_filtrate vs wt_filtrate

7.5.1 Our libraries

keepers <- list(
  "compcf_vs_wtcf" = c("comp_filtrate", "wt_filtrate"))
set_name <- "comp_filtrate_vs_wt_filtrate"
##rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
compcf_wtcf_tables <- sm(combine_de_tables(
##  our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_compcf_vs_wtcf_tables-v", ver, ".xlsx")))

7.5.2 Tb libraries

keepers <- list(
  "compcf_vs_wtcf" = c("comp_filtrate", "wt_filtrate"))
set_name <- "comp_filtrate_vs_wt_filtrate"
##rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
compcf_wtcf_tables <- sm(combine_de_tables(
  ##  tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_compcf_vs_wtcf_tables-v", ver, ".xlsx")))

7.6 delta_whole vs wt_whole

7.6.1 Our libraries

keepers <- list(
  "wtcf_vs_wtwhole" = c("wt_filtrate", "wt_whole"))
set_name <- "delta_whole_vs_wt_whole"
##rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
wtcf_wtwhole_tables <- sm(combine_de_tables(
  ## our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_deltawhole_vs_wtwhole_tables-v", ver, ".xlsx")))

7.6.2 Tb libraries

keepers <- list(
  "wtcf_vs_wtwhole" = c("wt_filtrate", "wt_whole"))
set_name <- "delta_whole_vs_wt_whole"
##rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
wtcf_wtwhole_tables <- sm(combine_de_tables(
  ##tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_deltawhole_vs_wtwhole_tables-v", ver, ".xlsx")))

7.7 comp_whole vs wt_whole

7.7.1 Our libraries

keepers <- list(
  "compwhole_vs_wtwhole" = c("comp_whole", "wt_whole"))
set_name <- "comp_whole_vs_wt_whole"
##rownames(our_results[[set_name]]) <- our_results[[set_name]][["Protein"]]
compwhole_wtwhole_tables <- sm(combine_de_tables(
  ##our_pairwise_comp, keepers=keepers, extra_annot=our_results[[set_name]],
  our_pairwise_comp, keepers=keepers,
  excel=paste0("excel/our_compwhole_vs_wtwhole_tables-v", ver, ".xlsx")))

7.7.2 Tb libraries

keepers <- list(
  "compwhole_vs_wtwhole" = c("comp_whole", "wt_whole"))
set_name <- "comp_whole_vs_wt_whole"
##rownames(tb_results[[set_name]]) <- tb_results[[set_name]][["Protein"]]
compwhole_wtwhole_tables <- sm(combine_de_tables(
  ##tb_pairwise_comp, keepers=keepers, extra_annot=tb_results[[set_name]],
  tb_pairwise_comp, keepers=keepers,
  excel=paste0("excel/tb_compwhole_vs_wtwhole_tables-v", ver, ".xlsx")))
our_table <- our_pairwise_comp$deseq$all_tables$wt_whole_vs_wt_filtrate
tb_table <- tb_pairwise_comp$deseq$all_tables$wt_whole_vs_wt_filtrate
our_order <- order(our_table[["limma_logfc"]])
rownames(tb_table) <- gsub(pattern="^(.*)_.*", replacement="\\1", x=rownames(tb_table))

test_table <- merge(our_table, tb_table, by="row.names")
cor.test(test_table$logFC.x, test_table$logFC.y)

8 RNASeq vs proteomics

Take the analysis performed on 02_relative_pe_expression, which unfortunately was only using the DDA data, now reuse it with the DIA data and see what happens.

all_de <- read.table("external_data/limma_result.csv", header=TRUE, sep="\t")

pe_ids <- read.table("reference/annotated_pe_genes.txt")
colnames(pe_ids) <- "gene"
pe_annotations <- merge(pe_ids, mtb_annotations, by.x="gene", by.y="id")
## Error in fix.by(by.y, y): 'by' must specify a uniquely valid column
chosen_colnames <- c("rv_id", "chr", "start", "end", "width", "strand",
                     "source", "type", "score", "phase", "id", "gene_id",
                     "description", "function")
colnames(pe_annotations) <- chosen_colnames
## Error in colnames(pe_annotations) <- chosen_colnames: object 'pe_annotations' not found
rownames(pe_annotations) <- pe_annotations[["id"]]
## Error in eval(expr, envir, enclos): object 'pe_annotations' not found
tmp_de <- all_de
colnames(tmp_de) <- c("id", "logfc", "ave_expr", "adjp", "abbrev_id", "description", "gene_length", "type")
colnames(mtb_annotations) <- chosen_colnames
all_de <- merge(tmp_de, mtb_annotations, by="id")
colnames(all_de) <- c("id","logfc", "ave_expr", "adjp", "abbrev_id", "description", "gene_length", "type",
                      "rv_id", "start", "end", "width", "strand", "source", "type", "na", "anotherna",
                      "mtb_id", "another_abbrev_id", "another_description", "html_string")
all_de <- all_de[, c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)]

pe_de <- merge(pe_annotations, all_de, by="id")
## Error in merge(pe_annotations, all_de, by = "id"): object 'pe_annotations' not found
colnames(pe_de) <- c("id", "rv_id", "chromosome", "start", "end", "width", "strand",
                     "source", "type", "score", "phase", "gene_id", "description", "function",
                     "logfc", "ave_expr", "adjp", "another_gene", "another_description", "gene_length",
                     "another_type", "another_id", "another_start", "another_end", "another_width",
                     "another_strand", "another_source", "another_type")
## Error in colnames(pe_de) <- c("id", "rv_id", "chromosome", "start", "end", : object 'pe_de' not found
pe_de <- pe_de[, c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)]
## Error in eval(expr, envir, enclos): object 'pe_de' not found
## pe_de_annot <- merge(pe_de, mtb_annotations, by="locus_tag")
## The contrast is written as wt - delta, so add back the logFC I think
## Hopefully I did not reverse this in my head.
pe_de$ave_minus_log <- pe_de$ave_expr - pe_de$logfc
## Error in eval(expr, envir, enclos): object 'pe_de' not found
all_de$ave_minus_log <- all_de$ave_expr - all_de$logfc
pe_de$pseudo_rpkm <- (pe_de$ave_minus_log / pe_de$width) * 1000
## Error in eval(expr, envir, enclos): object 'pe_de' not found
all_de$pseudo_rpkm <- (all_de$ave_minus_log / all_de$width) * 1000

maximum_expression <- max(pe_de[["pseudo_rpkm"]])
## Error in eval(expr, envir, enclos): object 'pe_de' not found
maximum_all <- max(all_de$pseudo_rpkm)
pe_de[["exprs_vs_max"]] <- pe_de[["pseudo_rpkm"]] / maximum_expression
## Error in eval(expr, envir, enclos): object 'pe_de' not found
all_de$exprs_vs_max <- all_de$pseudo_rpkm / maximum_all

table_order <- order(pe_de[["exprs_vs_max"]], decreasing=TRUE)
## Error in order(pe_de[["exprs_vs_max"]], decreasing = TRUE): object 'pe_de' not found
pe_de <- pe_de[table_order, ]
## Error in eval(expr, envir, enclos): object 'pe_de' not found
knitr::kable(head(pe_de, n=50))
## Error in head(pe_de, n = 50): object 'pe_de' not found
write.csv(x=pe_de, file="pe_relative_expression.csv")
## Error in is.data.frame(x): object 'pe_de' not found
plot_histogram(pe_de$exprs_vs_max, bins=20)
## Error in plot_histogram(pe_de$exprs_vs_max, bins = 20): object 'pe_de' not found
prot_table <- tb_pairwise_nobatch$limma$all_tables[["wt_whole_vs_delta_whole"]]

all_combined_table <- merge(all_de, prot_table, by.x="id", by.y="row.names")
cor.test(all_combined_table$ave_expr, all_combined_table$AveExpr, method="spearman")
## Warning in cor.test.default(all_combined_table$ave_expr,
## all_combined_table$AveExpr, : Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  all_combined_table$ave_expr and all_combined_table$AveExpr
## S = 1.6e+09, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.4659
all_testing <- all_combined_table[, c("ave_expr", "AveExpr")]
all_comparison <- plot_linear_scatter(all_testing)
## Used Bon Ferroni corrected t test(s) between columns.
all_comparison$scatter

pe_combined_table <- merge(pe_de, prot_table, by.x="id", by.y="row.names")
## Error in merge(pe_de, prot_table, by.x = "id", by.y = "row.names"): object 'pe_de' not found
cor.test(pe_combined_table$ave_expr, pe_combined_table$AveExpr, method="spearman")
## Error in cor.test(pe_combined_table$ave_expr, pe_combined_table$AveExpr, : object 'pe_combined_table' not found
pe_testing <- pe_combined_table[, c("ave_expr", "AveExpr")]
## Error in eval(expr, envir, enclos): object 'pe_combined_table' not found
pe_comparison <- plot_linear_scatter(pe_testing)
## Error in data.frame(df[, c(1, 2)]): object 'pe_testing' not found
pe_comparison$scatter
## Error in eval(expr, envir, enclos): object 'pe_comparison' not found
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 96dbc75fdeb993475ff61dd47697873d31a447fc
## R> packrat::restore()
## This is hpgltools commit: Fri Jul 27 17:35:57 2018 -0400: 96dbc75fdeb993475ff61dd47697873d31a447fc
## Saving to 02_swath2stats_20180720-v20180611.rda.xz

R version 3.5.1 (2018-07-02)

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), ruv(v.0.9.7), SWATH2stats(v.1.11.3), bindrcpp(v.0.2.2) and hpgltools(v.2018.03)

loaded via a namespace (and not attached): Rtsne(v.0.13), colorspace(v.1.3-2), rprojroot(v.1.3-2), htmlTable(v.1.12), corpcor(v.1.6.9), XVector(v.0.20.0), GenomicRanges(v.1.32.6), base64enc(v.0.1-3), rstudioapi(v.0.7), roxygen2(v.6.1.0), ggrepel(v.0.8.0), bit64(v.0.9-7), AnnotationDbi(v.1.42.1), xml2(v.1.2.0), codetools(v.0.2-15), splines(v.3.5.1), doParallel(v.1.0.11), robustbase(v.0.93-2), geneplotter(v.1.58.0), knitr(v.1.20), Formula(v.1.2-3), annotate(v.1.58.0), cluster(v.2.0.7-1), graph(v.1.58.0), compiler(v.3.5.1), httr(v.1.3.1), backports(v.1.1.2), assertthat(v.0.2.0), Matrix(v.1.2-14), lazyeval(v.0.2.1), limma(v.3.36.2), acepack(v.1.4.1), htmltools(v.0.3.6), prettyunits(v.1.0.2), tools(v.3.5.1), gtable(v.0.2.0), glue(v.1.3.0), GenomeInfoDbData(v.1.1.0), reshape2(v.1.4.3), dplyr(v.0.7.6), Rcpp(v.0.12.18), Biobase(v.2.40.0), BRAIN(v.1.26.0), preprocessCore(v.1.42.0), nlme(v.3.1-137), iterators(v.1.0.10), stringr(v.1.3.1), openxlsx(v.4.1.0), testthat(v.2.0.0), PolynomF(v.1.0-2), gtools(v.3.8.1), devtools(v.1.13.6), XML(v.3.98-1.12), DEoptimR(v.1.0-8), edgeR(v.3.22.3), directlabels(v.2018.05.22), MASS(v.7.3-50), zlibbioc(v.1.26.0), scales(v.0.5.0), doSNOW(v.1.0.16), hms(v.0.4.2), RBGL(v.1.56.0), parallel(v.3.5.1), SummarizedExperiment(v.1.10.1), RColorBrewer(v.1.1-2), yaml(v.2.2.0), memoise(v.1.1.0), gridExtra(v.2.3), pander(v.0.6.2), ggplot2(v.3.0.0), rpart(v.4.1-13), biomaRt(v.2.36.1), latticeExtra(v.0.6-28), stringi(v.1.2.4), RSQLite(v.2.1.1), genefilter(v.1.62.0), S4Vectors(v.0.18.3), checkmate(v.1.8.5), BiocGenerics(v.0.26.0), zip(v.1.0.0), BiocParallel(v.1.14.2), GenomeInfoDb(v.1.16.0), rlang(v.0.2.1), pkgconfig(v.2.0.1), commonmark(v.1.5), matrixStats(v.0.54.0), bitops(v.1.0-6), evaluate(v.0.11), lattice(v.0.20-35), purrr(v.0.2.5), bindr(v.0.1.1), htmlwidgets(v.1.2), labeling(v.0.3), bit(v.1.1-14), tidyselect(v.0.2.4), plyr(v.1.8.4), magrittr(v.1.5), DESeq2(v.1.20.0), R6(v.2.2.2), snow(v.0.4-2), IRanges(v.2.14.10), Hmisc(v.4.1-1), DelayedArray(v.0.6.2), DBI(v.1.0.0), pillar(v.1.3.0), foreign(v.0.8-71), withr(v.2.1.2), mgcv(v.1.8-24), survival(v.2.42-6), RCurl(v.1.95-4.11), nnet(v.7.3-12), tibble(v.1.4.2), crayon(v.1.3.4), KernSmooth(v.2.23-15), rmarkdown(v.1.10), progress(v.1.2.0), locfit(v.1.5-9.1), grid(v.3.5.1), sva(v.3.28.0), data.table(v.1.11.4), blob(v.1.1.1), digest(v.0.6.15), xtable(v.1.8-2), stats4(v.3.5.1), munsell(v.0.5.0) and quadprog(v.1.5-5)

LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxODA2MTE6IEFuYWx5emluZyBkYXRhIGZyb20gT3BlblN3YXRoV29ya0Zsb3cvVFJJQyAoMjAxODA3MjApLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKICB9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBsaWJyYXJ5KGhwZ2x0b29scykKICB0dCA8LSBkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikKICBrbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD05MCwKICAgICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCiAga25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aD04LAogICAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0PTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKICBvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQogIGdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQogIHZlciA8LSAiMjAxODA2MTEiCiAgcHJldmlvdXNfZmlsZSA8LSAiMDFfcHJlcHJvY2Vzc2luZ19jb21ldF9oaWdocmVzLlJtZCIKCiAgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCiAgcHJldmlvdXNfZmlsZSA8LSAiMDFfYW5ub3RhdGlvbl8yMDE4MDYxMS5SbWQiCiAgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCgogIHJtZF9maWxlIDwtICIwMl9zd2F0aDJzdGF0c18yMDE4MDcyMC5SbWQiCn0KYGBgCgojIFRPRE8KCiogVGhpcyBpcyBhIGNvcHkgb2YgdGhlIHNhbWUgZmlsZSBkYXRlZCAyMDE4MDYxMSwgYnV0IGFuIGF0dGVtcHQgdG8gcmVhY3QgdG8gYQogIHF1ZXJ5IGZyb20gWWFuOgoqIEkgYW0gdXNpbmcgdGhpcyB3b3Jrc2hlZXQgdG8gYWxzbyBhdHRlbXB0IHRvIGFkZHJlc3MgZmlndXJlLXNwZWNpZmljIFRPRE8KICBpdGVtcy4KCiAiSSB3YXMgYmFmZmxlZCBieSB5b3VyIHJlc3VsdCB0aGF0IHByb3RlaW4gKG9yIHBlcHRpZGUpIGFidW5kYW5jZSBvZiBpZGVudGlmaWVkCiBwZXB0aWRlcyB3ZXJlIG5vdCBjaGFuZ2VkIGJldHdlZW4gTWFyY2ggYW5kIE1heS4gVGhhdCB3aWxsIGNvbXBsZXRlbHkgY291bnRlcgogbXkgYXNzdW1wdGlvbiB0aGF0IGEgY29tcGxldGUgY2xlYW5pbmcgb2YgdGhlIG1hc3Mgc3BlYyB3aWxsIHNvbHZlIG91cgogcHJvYmxlbS4gSSB3b25kZXIgaG93IG11Y2ggd291bGQgaXQgd2lsbCB0YWtlIHRvIGdlbmVyYXRlIG1vcmUgZGV0YWlsZWQgZGF0YQogZnJvbSBvdXIgb2xkIGZyaWVuZCBQRS9QUEUgcHJvdGVpbnMuIFRoZSBpbmZvcm1hdGlvbiB0aGF0IHdpbGwgYmUgaGVscGZ1bCB3b3VsZAogYmUgaW50ZW5zaXR5LCBtYXNzIGFjY3VyYWN5LCBhbmQgY2hyb21hdG9ncmFwaHkgcGVhayB3aWR0aCBvZiBlYWNoIHBlcHRpZGUgaW4KIGVhY2ggc2FtcGxlLiBQbGVhc2UgZmVlbCBmcmVlIHRvIHN0b3AgYnkgdG9tb3Jyb3cgaWYgeW91IGhhdmUgcXVlc3Rpb25zLgoKIEkgbGlrZSB0aGlzIGdyb3VwIG9mIHByb3RlaW5zIGJlY2F1c2UgMS4gaXQncyBvZiBleHRyYSBpbnRlcmVzdCB0byBWb2xrZXIgYW5kCiBEYWxsYXMsIDIuIGl0J3MgYSBzbWFsbCBsaXN0IG9mIHByb3RlaW5zLCBzbyBlYXN5IHRvIGV2YWx1YXRlLiBhbmQgMy4gUHJvdGVpbgogYWJ1bmRhbmNlIGNvdmVycyBhIHdpZGUgcmFuZ2UsIGZyb20gcmVsYXRpdmVseSBoaWdoIGFidW5kYW5jZSB0byBiYXJlbHkKIGRldGVjdGFibGUuIgoKSSB0aGluayB0aGVyZWZvcmUgSSB3aWxsIGxlYXZlIHRoZSBhbmFseXNlcyBoZXJlIGFsb25lLCBidXQganVtcCBkb3duIHRvIHdoZXJlIEkKcGFyc2UvcGxvdCB0aGUgRElBIGRhdGEgYW5kIGF0dGVtcHQgdG8gc3Vic2V0IGl0IGZvciB0aGUgUFBFIHByb3RlaW5zIGluIHdheXMKc2ltaWxhci9pZGVudGljYWwgdG8gWWFuJ3MgcXVlcnkuICBXaXRoIHRoYXQgaW4gbWluZCwgSSBhbSBnb2luZyB0byBzZXQKZXZhbD1GQUxTRSBvbiB0aGUgYmxvY2tzIG9mIGNvZGUgaW4gdGhpcyBmaWxlIHVudGlsIEkgZmluZCB0aGUgb25lIHdoaWNoIGlzCmFjdHVhbGx5IHJlbGV2YW50LgoKSW4gYWRkaXRpb24sIEkgYW0gbW92aW5nIGJsb2NrcyBvZiBjb2RlL2FuYWx5c2lzIHVwIHRvIHRoZSB0b3Agd2hpY2ggSSB0aGluawp3aWxsIGJlIHJlbGV2YW50LgoKIyMgUGxvdHRpbmcgbWV0cmljcyBvZiBpZGVudGlmaWVkIHBlYWtzIGZyb20gRElBIGRhdGEKClRoZSBweXByb3BoZXQgZGF0YSBmb3IgYWxsIERJQSBzYW1wbGVzIHNob3VsZCBwcm92aWRlIHRoZSBtZXRyaWNzIGluIHdoaWNoIFlhbgppcyBpbnRlcmVzdGVkLiAgSSB3aWxsIGZvY3VzIG9uIHRoZSB0dWJlcmN1bGlzdCB0cmFuc2l0aW9uIGxpYnJhcmllcyBiZWNhdXNlCnRoYXQgd2FzIHRoZSBvbmUgSSBzYXcgZmlyc3QuCgojIyMgVGhlIHR1YmVyY3VsaXN0IGRhdGEKCmBgYHtyIHRiX3BlX3B5cHJvcGhldF9wbG90c30KcGVfZ2VuZXMgPC0gcmVhZC50YWJsZSgicmVmZXJlbmNlL2Fubm90YXRlZF9wZV9nZW5lcy50eHQiKVtbMV1dCnRiX3B5cHJvcGhldF9mdW4gPC0gZXh0cmFjdF9weXByb3BoZXRfZGF0YShtZXRhZGF0YT0ic2FtcGxlX3NoZWV0cy9NdGJfZGlhX3NhbXBsZXMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBweXByb3BoZXRfY29sdW1uPSJ0dWJlcmN1bGlzdHNjb3JlZCIpCgpwZV9weXByb3BoZXRfZnVuIDwtIHN1YnNldF9weXByb3BoZXRfZGF0YSh0Yl9weXByb3BoZXRfZnVuLCBzdWJzZXQ9cGVfZ2VuZXMpCgp0Yl9tYXNzX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKHBlX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0ibWFzcyIpKQpwcChmaWxlPSJpbWFnZXMvMjAxODA3MjBfcHBlX21hc3NfYm94cGxvdC5wbmciLCBpbWFnZT10Yl9tYXNzX3Bsb3RbWyJkb3Rib3hwbG90Il1dKQoKdGJfaW50ZW5zaXR5X3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKHBlX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0iaW50ZW5zaXR5IikpCnBwKGZpbGU9ImltYWdlcy8yMDE4MDcyMF9wcGVfaW50ZW5zaXR5X2JveHBsb3QucG5nIiwgaW1hZ2U9dGJfaW50ZW5zaXR5X3Bsb3RbWyJkb3Rib3hwbG90Il1dKQoKdGJfbHdpZHRoX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKHBlX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0ibGVmdHdpZHRoIikpCnBwKGZpbGU9ImltYWdlcy8yMDE4MDcyMF9wcGVfbHdpZHRoX2JveHBsb3QucG5nIiwgaW1hZ2U9dGJfbHdpZHRoX3Bsb3RbWyJkb3Rib3hwbG90Il1dKQoKdGJfcndpZHRoX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKHBlX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0icmlnaHR3aWR0aCIpKQpwcChmaWxlPSJpbWFnZXMvMjAxODA3MjBfcHBlX3J3aWR0aF9ib3hwbG90LnBuZyIsIGltYWdlPXRiX3J3aWR0aF9wbG90W1siZG90Ym94cGxvdCJdXSkKYGBgCgpgYGB7ciB0Yl9weXByb3BoZXRfcGxvdHN9CnRiX3B5cHJvcGhldF9mdW4gPC0gZXh0cmFjdF9weXByb3BoZXRfZGF0YShtZXRhZGF0YT0ic2FtcGxlX3NoZWV0cy9NdGJfZGlhX3NhbXBsZXMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBweXByb3BoZXRfY29sdW1uPSJ0dWJlcmN1bGlzdHNjb3JlZCIpCgp0Yl9tYXNzX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKHRiX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0ibWFzcyIpKQp0Yl9tYXNzX3Bsb3RbWyJib3hwbG90Il1dCgp0Yl9kZWx0YXJ0X3Bsb3RfYWxsIDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICB0Yl9weXByb3BoZXRfZnVuLCBjb2x1bW49ImRlbHRhX3J0IikpCnRiX2RlbHRhcnRfcGxvdF9hbGxbWyJib3hwbG90Il1dCgp0Yl9kZWx0YXJ0X3Bsb3RfcmVhbCA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24oCiAgdGJfcHlwcm9waGV0X2Z1biwKICBjb2x1bW49ImRlbHRhX3J0Iiwga2VlcF9kZWNveXM9RkFMU0UpKQp0Yl9kZWx0YXJ0X3Bsb3RfcmVhbFtbImJveHBsb3QiXV0KCnRiX2RlbHRhcnRfcGxvdF9kZWNveXMgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKAogIHRiX3B5cHJvcGhldF9mdW4sCiAgY29sdW1uPSJkZWx0YV9ydCIsIGtlZXBfcmVhbD1GQUxTRSkpCnRiX2RlbHRhcnRfcGxvdF9kZWNveXNbWyJib3hwbG90Il1dCnRiX2RlbHRhcnRfcGxvdF9kZWNveXNbWyJkZW5zaXR5Il1dCnRiX2RlbHRhcnRfcGxvdF9kZWNveXNbWyJ2aW9saW4iXV0KCnRiX3dpZHRodnNtYXNzIDwtIHNtKHBsb3RfcHlwcm9waGV0X2RhdGEodGJfcHlwcm9waGV0X2Z1biwgbGVnZW5kPUZBTFNFKSkKdGJfd2lkdGh2c21hc3MkcGxvdApgYGAKCkFuYWx5emluZyBkYXRhIGZyb20gb3Blbk1TIGFuZCBmcmllbmRzLgo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCkluIHByZXByb2Nlc3NpbmdfY29tZXRfaGlnaHJlcy5SbWQsIEkgdXNlZCB0aGUgb3Blbk1TIHR1dG9yaWFscyBhbmQgc3VwcGxlbWVudGFsCm1hdGVyaWFscyBmcm9tIGEgY291cGxlIHBhcGVycyB0byBob3BlZnVsbHkgY29ycmVjdGx5IHBlcmZvcm0gdGhlIHZhcmlvdXMKcHJlcHJvY2Vzc2luZyB0YXNrcyByZXF1aXJlZCB0byBleHRyYWN0IGludGVuc2l0eSBkYXRhIGZyb20gRElBL1NXQVRICnRyYW5zaXRpb25zLgoKVGhlIGZpbmFsIHN0ZXBzIG9mIHRoYXQgcHJvY2VzcyBjb21iaW5lZCB0aGUgdHJhbnNpdGlvbiBpbnRlbnNpdGllcyBmcm9tIGV2ZXJ5CnNhbXBsZSBpbnRvIGEgbWV0YWRhdGEgZmlsZSAocmVzdWx0cy90cmljL0hDRF9tZXRhLnRzdiksIGFuIGludGVuc2l0eSBtYXRyaXgKKHJlc3VsdHMvdHJpYy9IQ0Rfb3V0bWF0cml4LnRzdiksIGFuZCBhIGZlYXR1cmUgYWxpZ25lZCBvdXRwdXQgbWF0cml4CihyZXN1bHRzL3RyaWMvYWxpZ25lZF9jb21ldF9IQ0QudHN2KS4KCk15IHJlYWRpbmcgb2YgdGhlIFNXQVRIMnN0YXRzIGFuZCBNU3N0YXRzIHNvdXJjZSBjb2RlIHN1Z2dlc3RzIHRvIG1lIHRoYXQgdGhlCmxvZzIoaW50ZW5zaXRpZXMpIG9mIHRoZSBmZWF0dXJlIGFsaWduZWQgZGF0YSBhcmUgb3VyIGZpbmFsIHByb3h5IGZvciBwcm90ZWluCmFidW5kYW5jZS4gIEF0IGZpcnN0IGdsYW5jZSwgdGhpcyBzdWdnZXN0cyB0byBtZSB0aGF0IHRoZXNlIGRhdGEgbWlnaHQgZm9sbG93IGEKZGlzdHJpYnV0aW9uIHNpbWlsYXIgdG8gUk5BU2VxIGRhdGEgKG5lZ2F0aXZlIGJpbm9taWFsLCBidXQgcGVyaGFwcyB3aXRoIGEKYmlnZ2VyIHRhaWw/KS4gIEluIGFkZGl0aW9uLCBieSB0aGUgdGltZSB3ZSB1c2UgdHJpYyBvbiB0aGUgZGF0YSwgd2UgaGF2ZSBhCmNvdW50IG1hdHJpeCBhbmQgc2FtcGxlIGFubm90YXRpb24gZGF0YSBmcmFtZXMgd2hpY2ggbG9vayByZW1hcmthYmx5IHNpbWlsYXIgdG8KdGhvc2UgdXNlZCBpbiBhIFJOQVNlcSBleHByZXNzaW9uc2V0LiAgSW5kZWVkLCBieSB0aGUgZW5kIG9mIHRoZSBNU3N0YXRzCnByb2Nlc3NpbmcsIGl0IGNyZWF0ZXMgYSBNU25TZXQgY2xhc3Mgb2YgaXRzIG93biB3aGljaCB1c2VzIGZEYXRhL2V4cHJzL3BEYXRhLgoKRm9yIHRoZSBjdXJpb3VzLCBteSByZWFzb25pbmcgZm9yIHNheWluZyB0aGF0IHRoZSBsb2cgaW50ZW5zaXRpZXMgYXJlIG91ciBwcm94eQpmb3IgYWJ1bmRhbmNlIGNvbWVzIGZyb20gTVNzdGF0cy9SL0RhdGFQcm9jZXNzLlIgaW4gYSBjbGF1c2Ugd2hpY2ggbG9va3MgbGlrZToKCmBgYHtyIHNuaXBwZXQsIGV2YWw9RkFMU0V9CmlmIChsb2dUcmFucyA9PSAyKSB7CiAgd29ya1tbIkFCVU5EQU5DRSJdXSA8LSBsb2cyKHdvcmtbWyJBQlVOREFOQ0UiXV0pCn0gZWxzZSBpZiAobG9nVHJhbnMgPT0gMTApIHsKICB3b3JrW1siQUJVTkRBTkNFIl1dIDwtIGxvZzEwKHdvcmtbWyJBQlVOREFOQ0UiXV0pCn0gZWxzZSB7CiAgIyMgQWJvdmUgdGhlcmUgd2FzIGEgY2hlY2sgZm9yIG9ubHkgbG9nIDIgYW5kIDEwLCBidXQgd2UgY2FuIGRvIGUgaWYgd2Ugd2FudC4KICAjIyBJIG1pZ2h0IGdvIGJhY2sgdXAgdGhlcmUgYW5kIHJlbW92ZSB0aGF0IGNoZWNrLiBMb25nIGxpdmUgZSEgMi43MTgyODIgcnVsZXMhCiAgd29ya1tbIkFCVU5EQU5DRSJdXSA8LSBsb2cod29ya1tbIkFCVU5EQU5DRSJdXSkgLyBsb2cobG9nVHJhbnMpCn0KYGBgCgooTm90ZTogSSBhZGRlZCB0aGUgbmF0dXJhbCBsb2cgdG8gdGhlIHNldCBvZiBjb25kaXRpb25zLCBidXQgb3RoZXJ3aXNlIHRoZSBsb2dpYwppcyB1bmNoYW5nZWQuKQoKV2l0aCB0aGF0IGluIG1pbmQsIEkgd2FudCB0byB1c2Ugc29tZSB0b29scyB3aXRoIHdoaWNoIEkgYW0gZmFtaWxpYXIgaW4gb3JkZXIgdG8KdHJ5IHRvIHVuZGVyc3RhbmQgdGhlc2UgZGF0YS4gIFRoZXJlZm9yZSBJIHdpbGwgZmlyc3QgYXR0ZW1wdCB0byBjb2VyY2UgbXkgdHJpYwphbGlnbmVkIGRhdGEgYW5kIGFubm90YXRpb25zIGludG8gYSAnbm9ybWFsJyBleHByZXNzaW9uc2V0LiAgVGhlbiBJIHdhbnQgdG8gZG8Kc29tZSBkaWFnbm9zdGljIHBsb3RzIHdoaWNoLCBpZiBJIGFtIHdyb25nIGFuZCB0aGVzZSBkaXN0cmlidXRpb25zIGFyZSBub3QgYXMKZXhwZWN0ZWQsIHdpbGwgYmUgY29uY2VwdHVhbGx5IGluY29ycmVjdCAoSSBkb24ndCB5ZXQgdGhpbmsgSSBhbSB3cm9uZykuCgojIyBTYW1wbGUgYW5ub3RhdGlvbiB2aWEgU1dBVEgyc3RhdHMKCkkgYW0gdXNpbmcgdGhlIFNXQVRIMnN0YXRzIHZpZ25ldHRlIGFzIG15IHByaW1hcnkgc291cmNlIG9mIGluZm9ybWF0aW9uLiAgVGh1cyBJCnNlZSB0aGF0IGl0IHVzZXMgdGhlCk9wZW5TV0FUSF9TTTNfR29sZFN0YW5kYXJkQXV0b21hdGVkUmVzdWx0c19odW1hbl9wZWFrZ3JvdXBzLnR4dCB3aGljaCBoYXMgYQpmb3JtYXQgbmVhcmx5IGlkZW50aWNhbCB0byB0aGUgdHJpYyBvdXRwdXQgbWF0cml4LiAgVGh1cyBmb3IgdGhlIG1vbWVudCBJIHdpbGwKYXNzdW1lIHRoYXQgdGhlIHByb3BlciBpbnB1dCBmb3IgU1dBVEgyc3RhdHMgaXMgJ3Jlc3VsdHMvdHJpYy9jb21ldF9IQ0QudHN2JyBhbmQKbm90IHRoZSBtZXRhZGF0YSBub3Igb3V0cHV0IG1hdHJpeC4gIEluIGFkZGl0aW9uLCBTV0FUSDJzdGF0cyBwcm92aWRlcyBhIHNpbWlsYXIKY29udmVyc2lvbiBmdW5jdGlvbiB3aGljaCB0YWtlcyB0aGUgdHJpYyBvdXRwdXQgYW5kIGNvZXJjZXMgaXQgaW50byBhIHNpbWlsYXIKbWF0cml4IGFmdGVyIHBlcmZvcm1pbmcgaXRzIHZhcmlvdXMgZmlsdGVyaW5nIHRhc2tzLiAgVGhlcmVmb3JlIEkgd2lsbCB1c2UgdGhhdC4KCkkga2VlcCBhIHNhbXBsZSBzaGVldCBvZiBhbGwgdGhlIERJQSBzYW1wbGVzIHVzZWQgaW4gdGhpcyBhbmFseXNpcyBpbgonc2FtcGxlX3NoZWV0cy9kaWFfc2FtcGxlcy54bHN4JyAgSXQgc2hvdWxkIGNvbnRhaW4gYWxsIHRoZSBvdGhlciByZXF1aXJlZCBkYXRhCndpdGggb25lIGltcG9ydGFudCBjYXZlYXQsIEkgcmVtb3ZlZCAxIHNhbXBsZSBieSAnY29tbWVudGluZycgaXQgKGUuZy4gcHJlZml4aW5nCml0IHdpdGggJyMjJyAtLSB3aGljaCBpcyBhbiBhZG1pdHRlZGx5IGR1bWIgdGhpbmcgdG8gZG8gaW4gYW4gZXhjZWwgZmlsZS4KCk9uZSBsYXN0IGNhdmVhdDogSSBoYWNrZWQgdGhlIFNXQVRIMnN0YXRzIHNhbXBsZV9hbm5vdGF0aW9uKCkgZnVuY3Rpb24gdG8gYWRkIGEKY291cGxlIGNvbHVtbnMgaW4gYW4gYXR0ZW1wdCB0byBtYWtlIGl0IGEgbGl0dGxlIG1vcmUgcm9idXN0IHdoZW4gZmFjZWQgd2l0aApzYW1wbGUgc2hlZXRzIHdpdGggZGlmZmVyZW50bHkgbmFtZWQgY29sdW1ucy4KCkluIGFkZGl0aW9uLCBTV0FUSDJzdGF0cyBwcm92aWRlcyBzb21lIG5pY2UgZmlsdGVyaW5nIGFuZCBjb21iaW5hdGlvbgpmdW5jdGlvbnMgd2hpY2ggc2hvdWxkIGJlIGNvbnNpZGVyZWQgd2hlbiBnZW5lcmF0aW5nIHZhcmlvdXMgZXhwcmVzc2lvbnNldCBkYXRhCnN0cnVjdHVyZXMgbGF0ZXIuCgojIyMgQ3JlYXRpbmcgYSBzd2F0aDJzdGF0cyBleHBlcmltZW50IHVzaW5nIG91ciBjb21ldC1kZXJpdmVkIGxpYnJhcnkgZGF0YQoKYGBge3Igb3VyX3N3YXRoMnN0YXRzX2luaXRpYWx9CmxvYWRlZCA8LSBzbShkZXZ0b29sczo6bG9hZF9hbGwoIn4vc2NyYXRjaC9naXQvU1dBVEgyc3RhdHMiKSkKCm91cl90cmljX2RhdGEgPC0gcmVhZC5jc3YoInJlc3VsdHMvdHJpYy8yMDE4MDYxMS93aG9sZV84bXovY29tZXRfSENELnRzdiIsIHNlcD0iXHQiKQoKc2FtcGxlX2Fubm90IDwtIG9wZW54bHN4OjpyZWFkLnhsc3goInNhbXBsZV9zaGVldHMvTXRiX2RpYV9zYW1wbGVzLnhsc3giKQpjb2xuYW1lcyhzYW1wbGVfYW5ub3QpIDwtIGdzdWIocGF0dGVybj0iXFwuIiwgcmVwbGFjZW1lbnQ9IiIsIHg9Y29sbmFtZXMoc2FtcGxlX2Fubm90KSkKIyMgRHJvcCBzYW1wbGVzIHN0YXJ0aW5nIHdpdGggY29tbWVudHMKa2VlcF9pZHggPC0gISBncmVwbChwYXR0ZXJuPSJeIyIsIHg9c2FtcGxlX2Fubm90W1sic2FtcGxlaWQiXV0pCnNhbXBsZV9hbm5vdCA8LSBzYW1wbGVfYW5ub3Rba2VlcF9pZHgsIF0Kc2FtcGxlX2Fubm90W1sic2FtcGxlaWQiXV0gPC0gcGFzdGUwKCJzIiwgc2FtcGxlX2Fubm90W1sic2FtcGxlaWQiXV0pCnJvd25hbWVzKHNhbXBsZV9hbm5vdCkgPC0gbWFrZS5uYW1lcyhzYW1wbGVfYW5ub3RbWyJzYW1wbGVpZCJdXSwgdW5pcXVlPVRSVUUpCgpleHB0X2lkeCA8LSBzYW1wbGVfYW5ub3RbWyJleHB0X2lkIl1dID09ICJtYXkyMDE4IiB8IHNhbXBsZV9hbm5vdFtbImV4cHRfaWQiXV0gPT0gIm1hcjIwMTgiCmV4cHRfaWR4W2lzLm5hKHNhbXBsZV9hbm5vdFtbImV4cHRfaWQiXV0pXSA8LSBGQUxTRQpzYW1wbGVfYW5ub3QgPC0gc2FtcGxlX2Fubm90W2V4cHRfaWR4LCBdCm16X2lkeCA8LSBzYW1wbGVfYW5ub3RbWyJ3aW5kb3dzaXplIl1dID09ICI4IgpzYW1wbGVfYW5ub3QgPC0gc2FtcGxlX2Fubm90W216X2lkeCwgXQojIyBTZXQgdGhlIG16WE1MIGNvbHVtbiB0byBtYXRjaCB0aGUgZmlsZW5hbWUgY29sdW1uIGluIHRoZSBkYXRhLgoKIyMgczJzLCBteSB3aXR0eSB3YXkgb2Ygc2hvcnRlbmluZyBTV0FUSDJzdGF0cy4uLgpvdXJfczJzX2V4cCA8LSBzYW1wbGVfYW5ub3RhdGlvbihkYXRhPW91cl90cmljX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9hbm5vdGF0aW9uPXNhbXBsZV9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuX2NvbHVtbj0icnVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbHBlcHRpZGVuYW1lX2NvbHVtbj0iZnVsbHVuaW1vZHBlcHRpZGVuYW1lIikKYGBgCgojIyMgQ3JlYXRpbmcgYSBzd2F0aDJzdGF0cyBleHBlcmltZW50IHVzaW5nIHRoZSB0dWJlcmN1bGlzdC1kZXJpdmVkIGxpYnJhcnkgZGF0YQoKVGhpcyBqdXN0IHJlcGVhdHMgdGhlIHByZXZpb3VzIHN0YW56YSwgYnV0IHVzZXMgdGhlIHR1YmVyY3VsaXN0CnRyYW5zaXRpb24tbGlicmFyeSBzd2F0aCBkYXRhIGFzIGl0cyBpbnB1dCByYXRoZXIgdGhhbiBvdXIgb3duIGNvbWV0CmRhdGEuCgpUaGVyZSBpcyBvbmUgaW1wb3J0YW50IGNhdmVhdCBpbiB0aGUgZm9sbG93aW5nIGJsb2NrOiBJIHVzZWQgYSByZWdleCB0byByZW1vdmUKdGhlIHNlY29uZCBoYWxmIG9mIGdlbmVJRF9nZW5lTmFtZSBzbyB0aGF0IGxhdGVyIHdoZW4gSSBtZXJnZSBpbiB0aGUgYW5ub3RhdGlvbgpkYXRhIEkgaGF2ZSBpdCB3aWxsIG1hdGNoLgoKYGBge3IgdGJfc3dhdGgyc3RhdHNfaW5pdGlhbH0KdGJfdHJpY19kYXRhIDwtIHJlYWQuY3N2KCJyZXN1bHRzL3RyaWMvMjAxODA2MTEvd2hvbGVfOG16X3R1YmVyY3VsaXN0L2NvbWV0X0hDRC50c3YiLCBzZXA9Ilx0IikKCnRiX3RyaWNfZGF0YVtbIlByb3RlaW5OYW1lIl1dIDwtIGdzdWIocGF0dGVybj0iXiguKilfLiokIiwgcmVwbGFjZW1lbnQ9IlxcMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD10Yl90cmljX2RhdGFbWyJQcm90ZWluTmFtZSJdXSkKdGJfczJzX2V4cCA8LSBzYW1wbGVfYW5ub3RhdGlvbihkYXRhPXRiX3RyaWNfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfYW5ub3RhdGlvbj1zYW1wbGVfYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbHBlcHRpZGVuYW1lX2NvbHVtbj0iZnVsbHVuaW1vZHBlcHRpZGVuYW1lIikKYGBgCgpOb3cgSSBoYXZlIGEgY291cGxlIGRhdGEgc3RydWN0dXJlcyB3aGljaCBzaG91bGQgcHJvdmUgdXNlZnVsIGZvciB0aGUgbWV0cmljcwpwcm92aWRlZCBieSBTV0FUSDJzdGF0cywgTVNzdGF0cywgYW5kIG15IG93biBocGdsdG9vbHMuCgojIFNXQVRIMnN0YXRzIGNvbnRpbnVlZAoKVGhlIHZhcmlvdXMgbWV0cmljcyBhbmQgZmlsdGVycyBwcm92aWRlZCBieSBTV0FUSDJzdGF0cyBzZWVtIHF1aXRlIHJlYXNvbmFibGUgdG8KbWUuICBUaGUgb25seSB0aGluZyB0aGF0IHJlYWxseSBib3RoZXJzIG1lIGlzIHRoYXQgdGhleSBhcmUgYWxsIGNhc2Ugc2Vuc2l0aXZlCmFuZCBJIGZvdW5kIHRoYXQgdGhlIG1vc3QgcmVjZW50IHRyaWMgY2hhbmdlZCB0aGUgY2FwaXRhbGl6YXRpb24gb2YgYSBjb2x1bW4sCmNhdXNpbmcgdGhlc2UgdG8gYWxsIGZhbGwgZG93bi4gIFRoZXJlZm9yZSBJIHdlbnQgaW4gYW5kIG1hZGUgZXZlcnl0aGluZyBjYXNlCmluc2Vuc2l0aXZlIGluIGEgZmFzaGlvbiBzaW1pbGFyIHRvIHRoYXQgZG9uZSBieSBNU3N0YXRzIChleGNlcHQgSSBoYXRlIGNhcGl0YWwKbGV0dGVycywgc28gSSB1c2VkIHRvbG93ZXIoKSByYXRoZXIgdGhhbiB0b3VwcGVyKCkpLgoKIyMgUnVuIGZpbHRlcnMgb24gb3VyIGNvbWV0IGRhdGEKCmBgYHtyIG91cl9zd2F0aDJzdGF0c19wcm9jZXNzaW5nfQojIyBHZXQgY29ycmVsYXRpb25zIG9uIGEgc2FtcGxlIGJ5IHNhbXBsZSBiYXNpcwpwcChmaWxlPSJpbWFnZXMvMjAxODA2MTFfb3VyX3N3YXRoMnN0YXRzX3NhbXBsZV9jb3IucG5nIikKc2FtcGxlX2NvciA8LSBwbG90X2NvcnJlbGF0aW9uX2JldHdlZW5fc2FtcGxlcyhvdXJfczJzX2V4cCwgc2l6ZT0yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bi5hZ2dyZWdhdGU9c3VtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi52YWx1ZXM9ImludGVuc2l0eSIpCmRldi5vZmYoKQpzYW1wbGVfY29uZF9yZXBfY29yIDwtIHBsb3RfY29ycmVsYXRpb25fYmV0d2Vlbl9zYW1wbGVzKG91cl9zMnNfZXhwLCBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbj10cmFuc2l0aW9uX2dyb3VwX2lkIH4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbiArIGJpb3JlcGxpY2F0ZSArIHJ1biwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW4uYWdncmVnYXRlPXN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4udmFsdWVzPSJpbnRlbnNpdHkiKQoKZGVjb3lfbGlzdHMgPC0gYXNzZXNzX2RlY295X3JhdGUob3VyX3Myc19leHApCiMjIFRoaXMgc2VlbXMgYSBiaXQgaGlnaCB0byBtZSwgeWVzbm8/CmZkcl9vdmVyYWxsIDwtIGFzc2Vzc19mZHJfb3ZlcmFsbChvdXJfczJzX2V4cCwgb3V0cHV0PSJSY29uc29sZSIsIHBsb3Q9VFJVRSkKCmJ5cnVuX2ZkciA8LSBhc3Nlc3NfZmRyX2J5cnVuKG91cl9zMnNfZXhwLCBGRlQ9MC43LCBwbG90PVRSVUUsIG91dHB1dD0iUmNvbnNvbGUiKQpjaG9zZW5fbXNjb3JlIDwtIG1zY29yZTRhc3NheWZkcihvdXJfczJzX2V4cCwgRkZUPTAuNywgZmRyX3RhcmdldD0wLjAyKQpwcm90X3Njb3JlIDwtIG1zY29yZTRwcm90ZmRyKG91cl9zMnNfZXhwLCBGRlQ9MC43LCBmZHJfdGFyZ2V0PTAuMDIpCgpvdXJfbXNjb3JlX2ZpbHRlcmVkIDwtIGZpbHRlcl9tc2NvcmUob3VyX3Myc19leHAsIGNob3Nlbl9tc2NvcmUpCm91cl9mcmVxX21zY29yZSA8LSBmaWx0ZXJfbXNjb3JlX2ZyZXFvYnMob3VyX3Myc19leHAsIDAuMDEsIDAuOCwgcm0uZGVjb3k9RkFMU0UpCm91cl9kYXRhX2ZpbHRlcmVkX2ZkciA8LSBmaWx0ZXJfbXNjb3JlX2ZkcihvdXJfbXNjb3JlX2ZpbHRlcmVkLCBGRlQ9MC43LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcmFsbF9wcm90ZWluX2Zkcl90YXJnZXQ9cHJvdF9zY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX292ZXJhbGxfcGVwdGlkZV9mZHJfbGltaXQ9MC4wNSkKb3VyX29ubHlfcHJvdGVvdHlwaWMgPC0gZmlsdGVyX3Byb3Rlb3R5cGljX3BlcHRpZGVzKG91cl9kYXRhX2ZpbHRlcmVkX2ZkcikKb3VyX2FsbF9maWx0ZXJlZCA8LSBmaWx0ZXJfYWxsX3BlcHRpZGVzKG91cl9vbmx5X3Byb3Rlb3R5cGljKQpvdXJfb25seV9zdHJvbmcgPC0gZmlsdGVyX29uX21heF9wZXB0aWRlcyhkYXRhPW91cl9hbGxfZmlsdGVyZWQsIG5fcGVwdGlkZXM9MTApCm91cl9vbmx5X21pbmltdW0gPC0gZmlsdGVyX29uX21pbl9wZXB0aWRlcyhkYXRhPW91cl9vbmx5X3N0cm9uZywgbl9wZXB0aWRlcz0zKQoKIyMgSSB0aGluayB0aGVzZSBtYXRyaXhlcyBhcmUgcHJvYmFibHkgc21hcnRlciB0byB1c2UgdGhhbiB0aGUgcmF3IG91dG1hdHJpeCBmcm9tIHRyaWMuCiMjIEJ1dCBJIGFtIG5vdCBhIGZhbiBvZiByZXJ3cml0aW5nIHRoZSBzYW1wbGUgY29sdW1uIG5hbWVzLgptYXRyaXhfcHJlZml4IDwtIGZpbGUucGF0aCgicmVzdWx0cyIsICJzd2F0aDJzdGF0cyIsIHZlcikKaWYgKCFmaWxlLmV4aXN0cyhtYXRyaXhfcHJlZml4KSkgewogIGRpci5jcmVhdGUobWF0cml4X3ByZWZpeCkKfQpwcm90ZWluX21hdHJpeF9hbGwgPC0gd3JpdGVfbWF0cml4X3Byb3RlaW5zKAogIG91cl9zMnNfZXhwLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgIm91cl9wcm90ZWluX2FsbC5jc3YiKSkKZGltKHByb3RlaW5fbWF0cml4X2FsbCkKcHJvdGVpbl9tYXRyaXhfbXNjb3JlIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucygKICBvdXJfbXNjb3JlX2ZpbHRlcmVkLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgIm91cl9wcm90ZWluX21hdHJpeF9tc2NvcmUuY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9tc2NvcmUpCnBlcHRpZGVfbWF0cml4X21zY29yZSA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgb3VyX21zY29yZV9maWx0ZXJlZCwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJvdXJfcGVwdGlkZV9tYXRyaXhfbXNjb3JlLmNzdiIpKQpkaW0ocGVwdGlkZV9tYXRyaXhfbXNjb3JlKQpwcm90ZWluX21hdHJpeF9taW5pbXVtIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucygKICBvdXJfb25seV9taW5pbXVtLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgIm91cl9wcm90ZWluX21hdHJpeF9taW5pbXVtLmNzdiIpKQpkaW0ocHJvdGVpbl9tYXRyaXhfbWluaW11bSkKcGVwdGlkZV9tYXRyaXhfbWluaW11bSA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgb3VyX29ubHlfbWluaW11bSwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJvdXJfcGVwdGlkZV9tYXRyaXhfbWluaW11bS5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X21pbmltdW0pCgpydF9jb3IgPC0gcGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXMoCiAgb3VyX29ubHlfbWluaW11bSwgY29sdW1uLnZhbHVlcz0iaW50ZW5zaXR5IiwgZnVuLmFnZ3JlZ2F0ZT1zdW0sIHNpemU9MikKIyMgSSBoYXZlIG5vIGVmZmluZyBjbHVlIHdoYXQgdGhpcyBwbG90IG1lYW5zLgp2YXJpYXRpb24gPC0gcGxvdF92YXJpYXRpb24ob3VyX29ubHlfbWluaW11bSwgZnVuLmFnZ3JlZ2F0ZT1zdW0pCgpjb2xzIDwtIGNvbG5hbWVzKG91cl9vbmx5X21pbmltdW0pCm91cl9kaXNhZ2dyZWdhdGVkIDwtIGRpc2FnZ3JlZ2F0ZShvdXJfb25seV9taW5pbXVtLCBhbGwuY29sdW1ucz1UUlVFKQpvdXJfbXNzdGF0c19pbnB1dCA8LSBjb252ZXJ0X01Tc3RhdHMob3VyX2Rpc2FnZ3JlZ2F0ZWQpCmBgYAoKIyMgUnVuIGZpbHRlcnMgb24gdGhlIHR1YmVyY3VsaXN0CgpSZXBlYXQgdGhlIGFib3ZlIHN0YW56YSB1c2luZyB0aGUgdHViZXJjdWxpc3QgZGF0YS4KCmBgYHtyIHRiX3N3YXRoMnN0YXRzX3Byb2Nlc3Npbmd9CiMjIEdldCBjb3JyZWxhdGlvbnMgb24gYSBzYW1wbGUgYnkgc2FtcGxlIGJhc2lzCnBwKGZpbGU9ImltYWdlcy8yMDE4MDYxMV90Yl9zd2F0aDJzdGF0c19zYW1wbGVfY29yLnBuZyIpCnNhbXBsZV9jb3IgPC0gcGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXModGJfczJzX2V4cCwgc2l6ZT0yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bi5hZ2dyZWdhdGU9c3VtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi52YWx1ZXM9ImludGVuc2l0eSIpCmRldi5vZmYoKQpzYW1wbGVfY29uZF9yZXBfY29yIDwtIHBsb3RfY29ycmVsYXRpb25fYmV0d2Vlbl9zYW1wbGVzKHRiX3Myc19leHAsIHNpemU9MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29uPXRyYW5zaXRpb25fZ3JvdXBfaWQgfgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZGl0aW9uICsgYmlvcmVwbGljYXRlICsgcnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bi5hZ2dyZWdhdGU9c3VtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi52YWx1ZXM9ImludGVuc2l0eSIpCgpkZWNveV9saXN0cyA8LSBhc3Nlc3NfZGVjb3lfcmF0ZSh0Yl9zMnNfZXhwKQojIyBUaGlzIHNlZW1zIGEgYml0IGhpZ2ggdG8gbWUsIHllc25vPwpmZHJfb3ZlcmFsbCA8LSBhc3Nlc3NfZmRyX292ZXJhbGwodGJfczJzX2V4cCwgb3V0cHV0PSJSY29uc29sZSIsIHBsb3Q9VFJVRSkKCmJ5cnVuX2ZkciA8LSBhc3Nlc3NfZmRyX2J5cnVuKHRiX3Myc19leHAsIEZGVD0wLjcsIHBsb3Q9VFJVRSwgb3V0cHV0PSJSY29uc29sZSIpCmNob3Nlbl9tc2NvcmUgPC0gbXNjb3JlNGFzc2F5ZmRyKHRiX3Myc19leHAsIEZGVD0wLjcsIGZkcl90YXJnZXQ9MC4wMikKcHJvdF9zY29yZSA8LSBtc2NvcmU0cHJvdGZkcih0Yl9zMnNfZXhwLCBGRlQ9MC43LCBmZHJfdGFyZ2V0PTAuMDIpCgp0Yl9tc2NvcmVfZmlsdGVyZWQgPC0gZmlsdGVyX21zY29yZSh0Yl9zMnNfZXhwLCBjaG9zZW5fbXNjb3JlKQp0Yl9mcmVxX21zY29yZSA8LSBmaWx0ZXJfbXNjb3JlX2ZyZXFvYnModGJfczJzX2V4cCwgMC4wMSwgMC44LCBybS5kZWNveT1GQUxTRSkKdGJfZGF0YV9maWx0ZXJlZF9mZHIgPC0gZmlsdGVyX21zY29yZV9mZHIodGJfbXNjb3JlX2ZpbHRlcmVkLCBGRlQ9MC43LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcmFsbF9wcm90ZWluX2Zkcl90YXJnZXQ9cHJvdF9zY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX292ZXJhbGxfcGVwdGlkZV9mZHJfbGltaXQ9MC4wNSkKdGJfb25seV9wcm90ZW90eXBpYyA8LSBmaWx0ZXJfcHJvdGVvdHlwaWNfcGVwdGlkZXModGJfZGF0YV9maWx0ZXJlZF9mZHIpCnRiX2FsbF9maWx0ZXJlZCA8LSBmaWx0ZXJfYWxsX3BlcHRpZGVzKHRiX29ubHlfcHJvdGVvdHlwaWMpCnRiX29ubHlfc3Ryb25nIDwtIGZpbHRlcl9vbl9tYXhfcGVwdGlkZXMoZGF0YT10Yl9hbGxfZmlsdGVyZWQsIG5fcGVwdGlkZXM9MTApCnRiX29ubHlfbWluaW11bSA8LSBmaWx0ZXJfb25fbWluX3BlcHRpZGVzKGRhdGE9dGJfb25seV9zdHJvbmcsIG5fcGVwdGlkZXM9MykKCiMjIEkgdGhpbmsgdGhlc2UgbWF0cml4ZXMgYXJlIHByb2JhYmx5IHNtYXJ0ZXIgdG8gdXNlIHRoYW4gdGhlIHJhdyBvdXRtYXRyaXggZnJvbSB0cmljLgojIyBCdXQgSSBhbSBub3QgYSBmYW4gb2YgcmVyd3JpdGluZyB0aGUgc2FtcGxlIGNvbHVtbiBuYW1lcy4KbWF0cml4X3ByZWZpeCA8LSBmaWxlLnBhdGgoInJlc3VsdHMiLCAic3dhdGgyc3RhdHMiLCB2ZXIpCmlmICghZmlsZS5leGlzdHMobWF0cml4X3ByZWZpeCkpIHsKICBkaXIuY3JlYXRlKG1hdHJpeF9wcmVmaXgpCn0KcHJvdGVpbl9tYXRyaXhfYWxsIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucygKICB0Yl9zMnNfZXhwLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInRiX3Byb3RlaW5fYWxsLmNzdiIpKQpkaW0ocHJvdGVpbl9tYXRyaXhfYWxsKQpwcm90ZWluX21hdHJpeF9tc2NvcmUgPC0gd3JpdGVfbWF0cml4X3Byb3RlaW5zKAogIHRiX21zY29yZV9maWx0ZXJlZCwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJ0Yl9wcm90ZWluX21hdHJpeF9tc2NvcmUuY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9tc2NvcmUpCnBlcHRpZGVfbWF0cml4X21zY29yZSA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgdGJfbXNjb3JlX2ZpbHRlcmVkLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInRiX3BlcHRpZGVfbWF0cml4X21zY29yZS5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X21zY29yZSkKcHJvdGVpbl9tYXRyaXhfbWluaW11bSA8LSB3cml0ZV9tYXRyaXhfcHJvdGVpbnMoCiAgdGJfb25seV9taW5pbXVtLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInRiX3Byb3RlaW5fbWF0cml4X21pbmltdW0uY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9taW5pbXVtKQpwZXB0aWRlX21hdHJpeF9taW5pbXVtIDwtIHdyaXRlX21hdHJpeF9wZXB0aWRlcygKICB0Yl9vbmx5X21pbmltdW0sIHdyaXRlLmNzdj1UUlVFLAogIGZpbGVuYW1lPWZpbGUucGF0aChtYXRyaXhfcHJlZml4LCAidGJfcGVwdGlkZV9tYXRyaXhfbWluaW11bS5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X21pbmltdW0pCgpydF9jb3IgPC0gcGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXMoc2l6ZT0yLAogIHRiX29ubHlfbWluaW11bSwgY29sdW1uLnZhbHVlcz0iaW50ZW5zaXR5IiwgZnVuLmFnZ3JlZ2F0ZT1zdW0pCiMjIEkgaGF2ZSBubyBlZmZpbmcgY2x1ZSB3aGF0IHRoaXMgcGxvdCBtZWFucy4KdmFyaWF0aW9uIDwtIHBsb3RfdmFyaWF0aW9uKHRiX29ubHlfbWluaW11bSwgZnVuLmFnZ3JlZ2F0ZT1zdW0pCgpjb2xzIDwtIGNvbG5hbWVzKHRiX29ubHlfbWluaW11bSkKdGJfZGlzYWdncmVnYXRlZCA8LSBkaXNhZ2dyZWdhdGUodGJfb25seV9taW5pbXVtLCBhbGwuY29sdW1ucz1UUlVFKQp0Yl9tc3N0YXRzX2lucHV0IDwtIGNvbnZlcnRfTVNzdGF0cyh0Yl9kaXNhZ2dyZWdhdGVkKQpgYGAKCiMjIFNvbWUgbmV3IHBsb3RzCgpJbiByZXNwb25zZSB0byBzb21lIGludGVyZXN0aW5nIHF1ZXJpZXMgZnJvbSBZYW4sIEkgbWFkZSBhIGZldyBsaXR0bGUgZnVuY3Rpb25zCndoaWNoIHF1ZXJ5IGFuZCBwbG90IGRhdGEgZnJvbSB0aGUgc2NvcmVkIGRhdGEgcHJvdmlkZWQgYnkgb3BlbnN3YXRoL3B5cHJvcGhldC4KTGV0IHVzIGxvb2sgYXQgdGhlaXIgcmVzdWx0cyBoZXJlLgoKIyMjIFVzaW5nIHRoZSBjb21ldCBkYXRhCgpgYGB7ciBvdXJfcHlwcm9waGV0X3Bsb3RzfQpvdXJfcHlwcm9waGV0X2Z1biA8LSBzbShleHRyYWN0X3B5cHJvcGhldF9kYXRhKG1ldGFkYXRhPSJzYW1wbGVfc2hlZXRzL010Yl9kaWFfc2FtcGxlcy54bHN4IikpCgpvdXJfbWFzc19wbG90IDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbihvdXJfcHlwcm9waGV0X2Z1biwgY29sdW1uPSJtYXNzIikpCm91cl9tYXNzX3Bsb3RbWyJib3hwbG90Il1dCm91cl9tYXNzX3Bsb3RbWyJkZW5zaXR5Il1dCgpvdXJfZGVsdGFydF9wbG90X2FsbCA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24oCiAgb3VyX3B5cHJvcGhldF9mdW4sIGNvbHVtbj0iZGVsdGFfcnQiKSkKb3VyX2RlbHRhcnRfcGxvdF9hbGxbWyJib3hwbG90Il1dCgpvdXJfZGVsdGFydF9wbG90X3JlYWwgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKAogIG91cl9weXByb3BoZXRfZnVuLAogIGNvbHVtbj0iZGVsdGFfcnQiLCBrZWVwX2RlY295cz1GQUxTRSkpCm91cl9kZWx0YXJ0X3Bsb3RfcmVhbFtbImJveHBsb3QiXV0KCm91cl9kZWx0YXJ0X3Bsb3RfZGVjb3lzIDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBvdXJfcHlwcm9waGV0X2Z1biwKICBjb2x1bW49ImRlbHRhX3J0Iiwga2VlcF9yZWFsPUZBTFNFKSkKb3VyX2RlbHRhcnRfcGxvdF9kZWNveXNbWyJib3hwbG90Il1dCm91cl9kZWx0YXJ0X3Bsb3RfZGVjb3lzW1siZGVuc2l0eSJdXQoKb3VyX3dpZHRodnNtYXNzIDwtIHNtKHBsb3RfcHlwcm9waGV0X2RhdGEob3VyX3B5cHJvcGhldF9mdW4sIGxlZ2VuZD1GQUxTRSkpCm91cl93aWR0aHZzbWFzcyRwbG90CmBgYAoKIyMgTVNzdGF0cwoKbXNzdGF0cy5vcmcgc2VlbXMgdG8gcHJvdmlkZSBhIGNvbXBsZXRlIHNvbHV0aW9uIGZvciBwZXJmb3JtaW5nIHJlYXNvbmFibGUgbWV0cmljcyBvZiB0aGlzIGRhdGEuCgpJIGFtIGN1cnJlbnRseSByZWFkaW5nOiBodHRwOi8vbXNzdGF0cy5vcmcvd3AtY29udGVudC91cGxvYWRzLzIwMTcvMDEvTVNzdGF0c192My43LjNfbWFudWFsLnBkZgoKSSBtYWRlIHNvbWUgbW9kZXJhdGVseSBpbnRydXNpdmUgY2hhbmdlcyB0byBNU3N0YXRzIHRvIG1ha2UgaXQgY2xlYXJlciwgYXMgd2VsbC4KCiMjIyBDb21ldCBkZXJpdmVkIG1zc3RhdHMKCmBgYHtyIG91cl9tc3N0YXRzX3F1YW50LCBldmFsPUZBTFNFfQpkZXZ0b29sczo6bG9hZF9hbGwoIn4vc2NyYXRjaC9naXQvTVNzdGF0cyIpCm91cl9tc3N0YXRzX3F1YW50IDwtIGRhdGFQcm9jZXNzKG91cl9tc3N0YXRzX2lucHV0KQpvdXJfbXNzdGF0c19wbG90cyA8LSBzbShkYXRhUHJvY2Vzc1Bsb3RzKG91cl9tc3N0YXRzX3F1YW50LCB0eXBlPSJRQ1BMT1QiKSkKCm15X2xldmVscyA8LSBsZXZlbHMoYXMuZmFjdG9yKG91cl9tc3N0YXRzX2lucHV0JGNvbmRpdGlvbikpCm15X2xldmVscwpjb21wYXJpc29ucyA8LSBnaGV0dG9fY29udHJhc3RfbWF0cml4KAogIG51bWVyYXRvcnM9Yygid3RfZmlsdHJhdGUiLCAiZGVsdGFfZmlsdHJhdGUiLCAiY29tcF9maWx0cmF0ZSIsCiAgICAgICAgICAgICAgICJkZWx0YV9maWx0cmF0ZSIsICJjb21wX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIiwKICAgICAgICAgICAgICAgImNvbXBfd2hvbGUiKSwKICBkZW5vbWluYXRvcnM9Yygid3Rfd2hvbGUiLCAiZGVsdGFfd2hvbGUiLCAiY29tcF93aG9sZSIsCiAgICAgICAgICAgICAgICAgInd0X2ZpbHRyYXRlIiwgInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIiwKICAgICAgICAgICAgICAgICAid3Rfd2hvbGUiKSkKb3VyX3Jlc3VsdHMgPC0gbGlzdCgpCmZvciAoYyBpbiAxOmxlbmd0aChyb3duYW1lcyhjb21wYXJpc29ucykpKSB7CiAgbmFtZSA8LSByb3duYW1lcyhjb21wYXJpc29ucylbY10KICBtZXNzYWdlKCJTdGFydGluZyAiLCBuYW1lKQogIGNvbXAgPC0gY29tcGFyaXNvbnNbYywgXQogIGNvbXBhcmlzb24gPC0gdChhcy5tYXRyaXgoY29tcCkpCiAgcm93bmFtZXMoY29tcGFyaXNvbikgPC0gbmFtZQogIG91cl9yZXN1bHRzW25hbWVdIDwtIHNtKE1Tc3RhdHM6Omdyb3VwQ29tcGFyaXNvbihjb250cmFzdC5tYXRyaXg9Y29tcGFyaXNvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1vdXJfbXNzdGF0c19xdWFudCkpCn0KYGBgCgojIFRoaXMgaXMgUmVsZXZhbnQgdG8gWWFuJ3MgcXVlcnkhCgojIyBQL1BFIHByb3RlaW4gUUMgcGxvdHMgZm9yIFlhbgoKWWFuIGFza2VkIGZvciB0aGUgcC9wZSBwcm90ZWluIHFjIHBsb3RzLiBvay4gIEkgY2hhbmdlZCB0aGUgZGF0YVByb2Nlc3NQbG90cyB0bwpyZXR1cm4gc29tZXRoaW5nIHVzZWZ1bCwgc28gdGhhdCBzaG91bGQgYmUgcG9zc2libGUgbm93LgoKYGBge3IgcGUsIGV2YWw9RkFMU0V9CnBlX2dlbmVzIDwtIHJlYWQudGFibGUoInJlZmVyZW5jZS9hbm5vdGF0ZWRfcGVfZ2VuZXMudHh0IilbWzFdXQoKIyMgVW5mb3J0dW5hdGVseSwgdGhlIG5hbWVzIGRpZCBub3QgZ2V0IHNldCBpbiBteSBjaGFuZ2VkIHZlcnNpb24gb2YgZGF0YVByb2Nlc3NQbG90cy4uLgpwbG90bHN0IDwtIG91cl9tc3N0YXRzX3Bsb3RzJFFDUExPVAphdmFpbGFibGVfcGxvdHMgPC0gZ3N1YihwYXR0ZXJuPSJeMS8iLCByZXBsYWNlbWVudD0iIiwKICAgICAgICAgICAgICAgICAgICAgICAgeD1sZXZlbHMob3VyX21zc3RhdHNfcXVhbnQkUHJvY2Vzc2VkRGF0YSRQUk9URUlOKSkKbmFtZXMocGxvdGxzdCkgPC0gYXZhaWxhYmxlX3Bsb3RzCgpwZV9pbl9hdmFpbF9pZHggPC0gcGVfZ2VuZXMgJWluJSBhdmFpbGFibGVfcGxvdHMKcGVfaW5fYXZhaWwgPC0gcGVfZ2VuZXNbcGVfaW5fYXZhaWxfaWR4XQpwZV9wbG90cyA8LSBwbG90bHN0W3BlX2luX2F2YWlsXQpwZGYoZmlsZT0icGVfcWNfcGxvdHMucGRmIikKZm9yIChwIGluIDE6bGVuZ3RoKHBlX3Bsb3RzKSkgewogIHBsb3QocGVfcGxvdHNbW3BdXSkKfQpkZXYub2ZmKCkKbGVuZ3RoKHBlX3Bsb3RzKQpgYGAKCiMjIyBUdWJlcmN1bGlzdCBkZXJpdmVkIG1zc3RhdHMKCmBgYHtyIHRiX21zc3RhdHNfcXVhbnQsIGV2YWw9RkFMU0V9CnRiX21zc3RhdHNfcXVhbnQgPC0gZGF0YVByb2Nlc3ModGJfbXNzdGF0c19pbnB1dCkKIyN0Yl9tc3N0YXRzX3Bsb3RzIDwtIHNtKGRhdGFQcm9jZXNzUGxvdHModGJfbXNzdGF0c19xdWFudCwgdHlwZT0iUUNQTE9UIikpCgpteV9sZXZlbHMgPC0gbGV2ZWxzKGFzLmZhY3Rvcih0Yl9tc3N0YXRzX2lucHV0JGNvbmRpdGlvbikpCm15X2xldmVscwpjb21wYXJpc29ucyA8LSBnaGV0dG9fY29udHJhc3RfbWF0cml4KAogIG51bWVyYXRvcnM9Yygid3RfZmlsdHJhdGUiLCAiZGVsdGFfZmlsdHJhdGUiLCAiY29tcF9maWx0cmF0ZSIsCiAgICAgICAgICAgICAgICJkZWx0YV9maWx0cmF0ZSIsICJjb21wX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIiwKICAgICAgICAgICAgICAgImNvbXBfd2hvbGUiKSwKICBkZW5vbWluYXRvcnM9Yygid3Rfd2hvbGUiLCAiZGVsdGFfd2hvbGUiLCAiY29tcF93aG9sZSIsCiAgICAgICAgICAgICAgICAgInd0X2ZpbHRyYXRlIiwgInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIiwKICAgICAgICAgICAgICAgICAid3Rfd2hvbGUiKSkKdGJfcmVzdWx0cyA8LSBsaXN0KCkKZm9yIChjIGluIDE6bGVuZ3RoKHJvd25hbWVzKGNvbXBhcmlzb25zKSkpIHsKICBuYW1lIDwtIHJvd25hbWVzKGNvbXBhcmlzb25zKVtjXQogIG1lc3NhZ2UoIlN0YXJ0aW5nICIsIG5hbWUpCiAgY29tcCA8LSBjb21wYXJpc29uc1tjLCBdCiAgY29tcGFyaXNvbiA8LSB0KGFzLm1hdHJpeChjb21wKSkKICByb3duYW1lcyhjb21wYXJpc29uKSA8LSBuYW1lCiAgdGJfcmVzdWx0c1tuYW1lXSA8LSBzbShNU3N0YXRzOjpncm91cENvbXBhcmlzb24oY29udHJhc3QubWF0cml4PWNvbXBhcmlzb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9dGJfbXNzdGF0c19xdWFudCkpCn0KYGBgCgojIENyZWF0ZSBocGdsdG9vbHMgZXhwcmVzc2lvbnNldAoKU2luY2UgSSBhbSBub3QgY2VydGFpbiBJIHVuZGVyc3RhbmQgdGhlc2UgZGF0YSwgSSB3aWxsIHRha2UgdGhlIGludGVuc2l0aWVzIGZyb20KU1dBVEgyc3RhdHMsIG1ldGFkYXRhLCBhbmQgYW5ub3RhdGlvbiBkYXRhOyAgYXR0ZW1wdCB0byBjcmVhdGUgYSAnbm9ybWFsJwpleHByZXNzaW9uc2V0OyBwb2tlIGF0IGl0IHRvIHNlZSB3aGF0IEkgY2FuIGxlYXJuLgoKIyMgTWFzc2FnaW5nIHRoZSBtZXRhZGF0YQoKSSB3YW50IHRvIHVzZSB0aGUgc2FtZSBtZXRhZGF0YSBhcyB3ZXJlIHVzZWQgZm9yIE1Tc3RhdHMuICBJdCBoYXMgYSBmZXcKaW1wb3J0YW50IGRpZmZlcmVuY2VzIGZyb20gdGhlIHJlcXVpcmVtZW50cyBvZiBocGdsdG9vbHM6IHByZXR0eSBtdWNoIG9ubHkgdGhhdApJIGRvIG5vdCBhbGxvdyByb3duYW1lcy9zYW1wbGVJRHMgdG8gc3RhcnQgd2l0aCBhIG51bWJlci4KCiMjIE1hc3NhZ2luZyB0aGUgaW50ZW5zaXR5IG1hdHJpeAoKSSBkbyBub3Qgd2FudCB0aGUgXDEgYmVmb3JlIHRoZSBwcm90ZWluIG5hbWVzLCBJIGFscmVhZHkgbWVyZ2VkIHRoZW0gaW50byBvbmUKZW50cnkgcGVyIGdlbmUgdmlzIFNXQVRIMnN0YXRzLgoKIyMjIE1ha2UgbWF0cmljZXMgd2l0aCBvdXIgbGlicmFyaWVzCgpgYGB7ciBvdXJfcHJvdGVpbl9tYXRyaXh9Cm91cl9wcm90X210cnggPC0gcmVhZC5jc3YoZmlsZS5wYXRoKCJyZXN1bHRzIiwgInN3YXRoMnN0YXRzIiwgdmVyLCAib3VyX3Byb3RlaW5fbWF0cml4X21pbmltdW0uY3N2IikpCnJvd25hbWVzKG91cl9wcm90X210cngpIDwtIGdzdWIocGF0dGVybj0iXjFcXC8iLCByZXBsYWNlbWVudD0iIiwgeD1vdXJfcHJvdF9tdHJ4W1sicHJvdGVpbm5hbWUiXV0pCm91cl9wcm90X210cnggPC0gb3VyX3Byb3RfbXRyeFssIC0xXQojIyBJbXBvcnRhbnQgcXVlc3Rpb246IERpZCBTV0FUSDJzdGF0cyByZW9yZGVyIG15IGRhdGE/CmNvbG5hbWVzKG91cl9wcm90X210cngpIDwtIGdzdWIocGF0dGVybj0iXi4qMjAxOCIsIHJlcGxhY2VtZW50PSJzMjAxOCIsIHg9Y29sbmFtZXMob3VyX3Byb3RfbXRyeCkpCmBgYAoKIyMjIE1ha2UgbWF0cmljZXMgd2l0aCB0aGUgdGIgbGlicmFyaWVzCgpgYGB7ciB0Yl9wcm90ZWluX21hdHJpeH0KdGJfcHJvdF9tdHJ4IDwtIHJlYWQuY3N2KGZpbGUucGF0aCgicmVzdWx0cyIsICJzd2F0aDJzdGF0cyIsIHZlciwgInRiX3Byb3RlaW5fbWF0cml4X21pbmltdW0uY3N2IikpCnJvd25hbWVzKHRiX3Byb3RfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJeMVxcLyIsIHJlcGxhY2VtZW50PSIiLCB4PXRiX3Byb3RfbXRyeFtbInByb3RlaW5uYW1lIl1dKQp0Yl9wcm90X210cnggPC0gdGJfcHJvdF9tdHJ4WywgLTFdCiMjIEltcG9ydGFudCBxdWVzdGlvbjogRGlkIFNXQVRIMnN0YXRzIHJlb3JkZXIgbXkgZGF0YT8KY29sbmFtZXModGJfcHJvdF9tdHJ4KSA8LSBnc3ViKHBhdHRlcm49Il4uKjIwMTgiLCByZXBsYWNlbWVudD0iczIwMTgiLCB4PWNvbG5hbWVzKHRiX3Byb3RfbXRyeCkpCmBgYAoKIyMgTWVyZ2UgdGhlIHBpZWNlcwoKTm93IHdlIHNob3VsZCBoYXZlIHN1ZmZpY2llbnQgcGllY2VzIHRvIG1ha2UgYW4gZXhwcmVzc2lvbnNldC4KCldoaWxlIGhlcmUsIEkgd2lsbCBhbHNvIHNwbGl0IHRoZSBkYXRhIGludG8gYSBjZiBhbmQgd2hvbGUtY2VsbCBwYWlyIG9mIGRhdGEgc3RydWN0dXJlcy4KCiMjIyBPdXIgZGF0YQoKYGBge3Igb3VyX2V4cHR9CiMjIERyb3AgdGhlIG1ldGFkYXRhIG5vdCBpbiB0aGUgcHJvdGVpbiBtYXRyaXg6CiMjIEFuZCBlbnN1cmUgdGhhdCB0aGV5IGFyZSB0aGUgc2FtZSBvcmRlci4KcmVvcmRlcmVkIDwtIGNvbG5hbWVzKG91cl9wcm90X210cngpCm91cl9tZXRhZGF0YSA8LSBzYW1wbGVfYW5ub3RbcmVvcmRlcmVkLCBdCgpvdXJfcHJvdGVpbl9leHB0IDwtIGNyZWF0ZV9leHB0KG1ldGFkYXRhPW91cl9tZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudF9kYXRhZnJhbWU9b3VyX3Byb3RfbXRyeCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bXRiX2Fubm90YXRpb25zKQpuZXdfY29sb3JzIDwtIGMoIiMxQjlFNzciLCAiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiNFNzI5OEEiLCAiIzY2QTYxRSIsICIjRTZBQjAyIikKbmFtZXMobmV3X2NvbG9ycykgPC0gYygiY29tcF9maWx0cmF0ZSIsICJjb21wX3dob2xlIiwgImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIiwgInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIikKbmFtZXMobmV3X2NvbG9ycykgPC0gYygid3Rfd2hvbGUiLCAiY29tcF93aG9sZSIsICJkZWx0YV93aG9sZSIsICJkZWx0YV9maWx0cmF0ZSIsICJ3dF9maWx0cmF0ZSIsICJjb21wX2ZpbHRyYXRlIikKb3VyX3Byb3RlaW5fZXhwdCA8LSBzZXRfZXhwdF9jb2xvcnMob3VyX3Byb3RlaW5fZXhwdCwgbmV3X2NvbG9ycykKCm91cl93aG9sZV9leHB0IDwtIHN1YnNldF9leHB0KG91cl9wcm90ZWluX2V4cHQsIHN1YnNldD0iY29sbGVjdGlvbnR5cGU9PSd3aG9sZSciKQpvdXJfY2ZfZXhwdCA8LSBzdWJzZXRfZXhwdChvdXJfcHJvdGVpbl9leHB0LCBzdWJzZXQ9ImNvbGxlY3Rpb250eXBlPT0nZmlsdHJhdGUnIikKYGBgCgojIyMgVGIgZGF0YQoKYGBge3IgdGJfZXhwdH0KIyMgRHJvcCB0aGUgbWV0YWRhdGEgbm90IGluIHRoZSBwcm90ZWluIG1hdHJpeDoKIyMgQW5kIGVuc3VyZSB0aGF0IHRoZXkgYXJlIHRoZSBzYW1lIG9yZGVyLgpyZW9yZGVyZWQgPC0gY29sbmFtZXModGJfcHJvdF9tdHJ4KQptZXRhZGF0YSA8LSBzYW1wbGVfYW5ub3RbcmVvcmRlcmVkLCBdCgp0Yl9wcm90ZWluX2V4cHQgPC0gc20oY3JlYXRlX2V4cHQobWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudF9kYXRhZnJhbWU9dGJfcHJvdF9tdHJ4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvPW10Yl9hbm5vdGF0aW9ucykpCndyaXR0ZW4gPC0gd3JpdGVfZXhwdCh0Yl9wcm90ZWluX2V4cHQsIGV4Y2VsPXBhc3RlMCgiZXhjZWwvd3JpdHRlbi12IiwgdmVyLCAiLnhsc3giKSkKdGJfd2hvbGVfZXhwdCA8LSBzdWJzZXRfZXhwdCh0Yl9wcm90ZWluX2V4cHQsIHN1YnNldD0iY29sbGVjdGlvbnR5cGU9PSd3aG9sZSciKQp0Yl9jZl9leHB0IDwtIHN1YnNldF9leHB0KHRiX3Byb3RlaW5fZXhwdCwgc3Vic2V0PSJjb2xsZWN0aW9udHlwZT09J2ZpbHRyYXRlJyIpCmBgYAoKIyMgTWV0cmljcyBvZiB0aGUgZnVsbCBkYXRhIHNldAoKIyMjIE91ciBsaWJyYXJpZXMKCmBgYHtyIG91cl9wcm90ZWluX21ldHJpY3MsIGZpZy5zaG93PSdoaWRlJ30Kb3VyX3Byb3RlaW5fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG91cl9wcm90ZWluX2V4cHQpKQpvdXJfcHJvdGVpbl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG91cl9wcm90ZWluX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSkpCm91cl9wcm90ZWluX25vcm1fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG91cl9wcm90ZWluX25vcm0pKQpvdXJfcHJvdGVpbl9mc3ZhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG91cl9wcm90ZWluX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9ImZzdmEiLCBmaWx0ZXI9VFJVRSkpCm91cl9wcm90ZWluX2ZzdmFfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG91cl9wcm90ZWluX2ZzdmEpKQpgYGAKCiMjIyBUYiBsaWJyYXJpZXMKCmBgYHtyIHRiX3Byb3RlaW5fbWV0cmljcywgZmlnLnNob3c9J2hpZGUnfQp0Yl9wcm90ZWluX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyh0Yl9wcm90ZWluX2V4cHQpKQp0Yl9wcm90ZWluX3ZhcnBsb3QgPC0gcGxvdF92YXJpYW5jZV9jb2VmZmljaWVudHModGJfcHJvdGVpbl9leHB0LCB4X2F4aXM9ImJhdGNoIikKdGJfcHJvdGVpbl92YXJwbG90IDwtIHBsb3RfdmFyaWFuY2VfY29lZmZpY2llbnRzKHRiX3Byb3RlaW5fZXhwdCkKdGJfcHJvdGVpbl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KHRiX3Byb3RlaW5fZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQp0Yl9wcm90ZWluX25vcm1fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHRiX3Byb3RlaW5fbm9ybSkpCnRiX3Byb3RlaW5fZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdCh0Yl9wcm90ZWluX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0iZnN2YSIsIGZpbHRlcj1UUlVFKSkKdGJfcHJvdGVpbl9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyh0Yl9wcm90ZWluX2ZzdmEpKQpgYGAKCiMjIE1ldHJpY3Mgb2YgdGhlIHdob2xlLWNlbGwgZGF0YSBzZXQKCiMjIyBPdXIgbGlicmFyaWVzCgpgYGB7ciBvdXJfd2hvbGVfbWV0cmljcywgZmlnLnNob3c9J2hpZGUnfQpvdXJfd2hvbGVfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG91cl93aG9sZV9leHB0KSkKb3VyX3dob2xlX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQob3VyX3dob2xlX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQpvdXJfd2hvbGVfbm9ybV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Mob3VyX3dob2xlX25vcm0pKQpvdXJfd2hvbGVfZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdChvdXJfd2hvbGVfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9ImZzdmEiLCBmaWx0ZXI9VFJVRSkpCm91cl93aG9sZV9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhvdXJfd2hvbGVfZnN2YSkpCmBgYAoKIyMjIFRiIGxpYnJhcmllcwoKYGBge3IgdGJfd2hvbGVfbWV0cmljcywgZmlnLnNob3c9J2hpZGUnfQp0Yl93aG9sZV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3ModGJfd2hvbGVfZXhwdCkpCnRiX3dob2xlX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQodGJfd2hvbGVfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSkpCnRiX3dob2xlX25vcm1fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHRiX3dob2xlX25vcm0pKQp0Yl93aG9sZV9mc3ZhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KHRiX3dob2xlX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJmc3ZhIiwgZmlsdGVyPVRSVUUpKQp0Yl93aG9sZV9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyh0Yl93aG9sZV9mc3ZhKSkKYGBgCgojIyBNZXRyaWNzIG9mIHRoZSBmaWx0cmF0ZSBkYXRhIHNldAoKIyMjIE91ciBsaWJyYXJpZXMKCmBgYHtyIG91cl9jZl9tZXRyaWNzLCBmaWcuc2hvdz0naGlkZSd9Cm91cl9jZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Mob3VyX2NmX2V4cHQpKQpvdXJfY2Zfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChvdXJfY2ZfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSkpCm91cl9jZl9ub3JtX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhvdXJfY2Zfbm9ybSkpCm91cl9jZl9mc3ZhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG91cl9jZl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0iZnN2YSIsIGZpbHRlcj1UUlVFKSkKb3VyX2NmX2ZzdmFfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG91cl9jZl9mc3ZhKSkKYGBgCgojIyMgVGIgbGlicmFyaWVzCgpgYGB7ciB0Yl9jZl9tZXRyaWNzLCBmaWcuc2hvdz0naGlkZSd9CnRiX2NmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyh0Yl9jZl9leHB0KSkKdGJfY2Zfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdCh0Yl9jZl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKSkKdGJfY2Zfbm9ybV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3ModGJfY2Zfbm9ybSkpCnRiX2NmX2ZzdmEgPC0gc20obm9ybWFsaXplX2V4cHQodGJfY2ZfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9ImZzdmEiLCBmaWx0ZXI9VFJVRSkpCnRiX2NmX2ZzdmFfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHRiX2NmX2ZzdmEpKQpgYGAKCiMjIHBsb3Qgc29tZSBtZXRyaWNzCgojIyMgT3VyIGxpYnJhcmllcwoKYGBge3Igb3VyX3ByaW50X21ldHJpY3MsIGV2YWw9RkFMU0V9CnBwKGltYWdlPW91cl9wcm90ZWluX21ldHJpY3MkbGlic2l6ZSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfb3VyX2xpYnNpemUucG5nIikpKQojIyBJdCBzZWVtcyB0byBtZSB0aGF0IHRoZSBzY2FsZSBvZiB0aGUgZGF0YSBpcyBhbGwgd2l0aGluIGFuIG9yZGVyIG9mIG1hZ25pdHVkZSBvciB0d28uCiMjIEkgY2Fubm90IGdldCB1c2VkIHRvIHRoZXNlIGFic3VyZGx5IGxhcmdlIG51bWJlcnMgdGhvdWdoLgpwcChpbWFnZT1vdXJfcHJvdGVpbl9ub3JtX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfb3VyX25vcm1fcGNhLnBuZyIpKSkKIyMgVGhlcmUgYXBwZWFycyB0byBiZSBhIG5pY2Ugc3BsaXQgaW4gdGhlIGRhdGEsIGhvd2V2ZXIgdGhlIHVuLWFzc2F5YWJsZSBiYXRjaAojIyBlZmZlY3QgaXMgYSBwcm9ibGVtLgpwcChpbWFnZT1vdXJfcHJvdGVpbl9mc3ZhX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfZnN2YV9wY2EucG5nIikpKQojIyBmc3ZhIHNlZW1zIHRvIGdldCBzb21lIGhhbmRsZSBvbiB0aGUgZGF0YSwgYnV0IEkgZG9uJ3QgdGhpbmsgd2Ugc2hvdWxkIHJlbHkKIyMgdXBvbiBpdC4KcHAoaW1hZ2U9b3VyX3Byb3RlaW5fbm9ybV9tZXRyaWNzJGNvcmhlYXQsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX25vcm1fY29yaGVhdC5wbmciKSkpCiMjIE9uY2UgYWdhaW4sIHRoZSB3aG9sZS1jZWxsL2N1bHR1cmUtZmlsdHJhdGUgc3BsaXQgaXMgdmVyeSBsYXJnZS4KcHAoaW1hZ2U9b3VyX3Byb3RlaW5fbWV0cmljcyRkZW5zaXR5LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9yYXdfZGVuc2l0eS5wbmciKSkpCiMjIFRoZXJlIGFyZSB0d28gb2J2aW91cyBkaXN0cmlidXRpb25zIGluIHRoZSBkYXRhLCBvbmNlIGFnYWluIHNwbGl0IGJldHdlZW4gdHlwZXMuCnBwKGltYWdlPW91cl9wcm90ZWluX21ldHJpY3MkYm94cGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfYm94cGxvdC5wbmciKSkpCiMjIFRoaXMgcmVjYXBpdHVsYXRlcyB0aGUgcHJldmlvdXMgcGxvdC4KCnBwKGltYWdlPW91cl93aG9sZV9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3dob2xlX2xpYnNpemUucG5nIikpKQpwcChpbWFnZT1vdXJfd2hvbGVfbm9ybV9tZXRyaWNzJHBjYXBsb3QsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3dob2xlX25vcm1fcGNhLnBuZyIpKSkKcHAoaW1hZ2U9b3VyX3dob2xlX2ZzdmFfbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9mc3ZhX3BjYS5wbmciKSkpCnBwKGltYWdlPW91cl93aG9sZV9ub3JtX21ldHJpY3MkY29yaGVhdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfbm9ybV9jb3JoZWF0LnBuZyIpKSkKcHAoaW1hZ2U9b3VyX3dob2xlX21ldHJpY3MkZGVuc2l0eSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfcmF3X2RlbnNpdHkucG5nIikpKQpwcChpbWFnZT1vdXJfd2hvbGVfbWV0cmljcyRib3hwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9ib3hwbG90LnBuZyIpKSkKCnBwKGltYWdlPW91cl9jZl9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX2xpYnNpemUucG5nIikpKQpwcChpbWFnZT1vdXJfY2Zfbm9ybV9tZXRyaWNzJHBjYXBsb3QsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX25vcm1fcGNhLnBuZyIpKSkKcHAoaW1hZ2U9b3VyX2NmX2ZzdmFfbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9mc3ZhX3BjYS5wbmciKSkpCnBwKGltYWdlPW91cl9jZl9ub3JtX21ldHJpY3MkY29yaGVhdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfbm9ybV9jb3JoZWF0LnBuZyIpKSkKcHAoaW1hZ2U9b3VyX2NmX21ldHJpY3MkZGVuc2l0eSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfcmF3X2RlbnNpdHkucG5nIikpKQpwcChpbWFnZT1vdXJfY2ZfbWV0cmljcyRib3hwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9ib3hwbG90LnBuZyIpKSkKYGBgCgojIyMgVGIgbGlicmFyaWVzCgpJIHRoaW5rIHRoZSBmaWd1cmUgUzEgaW50ZW5zaXRpZXMgbWF5IGNvbWUgZnJvbSB0aGVzZToKCmBgYHtyIGZpZ3VyZV9zMWF9CiMjIFJlbWluZGVyOiAgdGJfcHJvdGVpbl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3ModGJfcHJvdGVpbl9leHB0KSkKZmlndXJlX2V4cHQgPC0gc2V0X2V4cHRfc2FtcGxlbmFtZXModGJfcHJvdGVpbl9leHB0LCBwRGF0YSh0Yl9wcm90ZWluX2V4cHQpW1siZmlndXJlbmFtZSJdXSkKZmlnX3MxYSA8LSBwbG90X2xpYnNpemUoZmlndXJlX2V4cHQsIHRpdGxlPSIiLCBvcmRlcl9ieT0iY29uZGl0aW9uIiwgeV9sYWJlbD0iU3VtKGludGVuc2l0aWVzKSBieSBydW4iLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcj1jKCJ3dF93aG9sZSIsICJkZWx0YV93aG9sZSIsICJjb21wX3dob2xlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid3RfZmlsdHJhdGUiLCAiZGVsdGFfZmlsdHJhdGUiLCAiY29tcF9maWx0cmF0ZSIpKQpwcChmaWxlPSJpbWFnZXMvZmlnX3MxYS5wZGYiLCBpbWFnZT1maWdfczFhJHBsb3QpCmBgYAoKYGBge3IgdGJfcHJpbnRfbWV0cmljc30KcHAoaW1hZ2U9dGJfcHJvdGVpbl9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3RiX2xpYnNpemUucG5nIikpKQojIyBJdCBzZWVtcyB0byBtZSB0aGF0IHRoZSBzY2FsZSBvZiB0aGUgZGF0YSBpcyBhbGwgd2l0aGluIGFuIG9yZGVyIG9mIG1hZ25pdHVkZSBvciB0d28uCiMjIEkgY2Fubm90IGdldCB1c2VkIHRvIHRoZXNlIGFic3VyZGx5IGxhcmdlIG51bWJlcnMgdGhvdWdoLgpwcChpbWFnZT10Yl9wcm90ZWluX25vcm1fbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl90Yl9ub3JtX3BjYS5wbmciKSkpCiMjIFRoZXJlIGFwcGVhcnMgdG8gYmUgYSBuaWNlIHNwbGl0IGluIHRoZSBkYXRhLCBob3dldmVyIHRoZSB1bi1hc3NheWFibGUgYmF0Y2gKIyMgZWZmZWN0IGlzIGEgcHJvYmxlbS4KcHAoaW1hZ2U9dGJfcHJvdGVpbl9mc3ZhX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfZnN2YV9wY2EucG5nIikpKQojIyBmc3ZhIHNlZW1zIHRvIGdldCBzb21lIGhhbmRsZSBvbiB0aGUgZGF0YSwgYnV0IEkgZG9uJ3QgdGhpbmsgd2Ugc2hvdWxkIHJlbHkKIyMgdXBvbiBpdC4KcHAoaW1hZ2U9dGJfcHJvdGVpbl9ub3JtX21ldHJpY3MkY29yaGVhdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfbm9ybV9jb3JoZWF0LnBuZyIpKSkKIyMgT25jZSBhZ2FpbiwgdGhlIHdob2xlLWNlbGwvY3VsdHVyZS1maWx0cmF0ZSBzcGxpdCBpcyB2ZXJ5IGxhcmdlLgpwcChpbWFnZT10Yl9wcm90ZWluX21ldHJpY3MkZGVuc2l0eSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfcmF3X2RlbnNpdHkucG5nIikpKQojIyBUaGVyZSBhcmUgdHdvIG9idmlvdXMgZGlzdHJpYnV0aW9ucyBpbiB0aGUgZGF0YSwgb25jZSBhZ2FpbiBzcGxpdCBiZXR3ZWVuIHR5cGVzLgpwcChpbWFnZT10Yl9wcm90ZWluX21ldHJpY3MkYm94cGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfYm94cGxvdC5wbmciKSkpCiMjIFRoaXMgcmVjYXBpdHVsYXRlcyB0aGUgcHJldmlvdXMgcGxvdC4KCnBwKGltYWdlPXRiX3dob2xlX21ldHJpY3MkbGlic2l6ZSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfbGlic2l6ZS5wbmciKSkpCnBwKGltYWdlPXRiX3dob2xlX25vcm1fbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9ub3JtX3BjYS5wbmciKSkpCnBwKGltYWdlPXRiX3dob2xlX2ZzdmFfbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9mc3ZhX3BjYS5wbmciKSkpCnBwKGltYWdlPXRiX3dob2xlX25vcm1fbWV0cmljcyRjb3JoZWF0LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9ub3JtX2NvcmhlYXQucG5nIikpKQpwcChpbWFnZT10Yl93aG9sZV9tZXRyaWNzJGRlbnNpdHksCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3dob2xlX3Jhd19kZW5zaXR5LnBuZyIpKSkKcHAoaW1hZ2U9dGJfd2hvbGVfbWV0cmljcyRib3hwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9ib3hwbG90LnBuZyIpKSkKCnBwKGltYWdlPXRiX2NmX21ldHJpY3MkbGlic2l6ZSwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfbGlic2l6ZS5wbmciKSkpCnBwKGltYWdlPXRiX2NmX25vcm1fbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9ub3JtX3BjYS5wbmciKSkpCnBwKGltYWdlPXRiX2NmX2ZzdmFfbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9mc3ZhX3BjYS5wbmciKSkpCnBwKGltYWdlPXRiX2NmX25vcm1fbWV0cmljcyRjb3JoZWF0LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9ub3JtX2NvcmhlYXQucG5nIikpKQpwcChpbWFnZT10Yl9jZl9tZXRyaWNzJGRlbnNpdHksCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3Jhd19kZW5zaXR5LnBuZyIpKSkKcHAoaW1hZ2U9dGJfY2ZfbWV0cmljcyRib3hwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9ib3hwbG90LnBuZyIpKSkKYGBgCgojIEF0dGVtcHQgc29tZSBxdWFudGlmaWNhdGlvbiBjb21wYXJpc29ucz8KCiMjIE91ciBsaWJyYXJpZXMKCmBgYHtyIG91cl9kZV90ZXN0aW5nLCBmaWcuc2hvdz0naGlkZSd9Cm91cl9wYWlyd2lzZV9maWx0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KG91cl9wcm90ZWluX2V4cHQsIGZpbHRlcj1UUlVFKSkKb3VyX3BhaXJ3aXNlX2NvbXAgPC0gc20oYWxsX3BhaXJ3aXNlKG91cl9wYWlyd2lzZV9maWx0LCBtb2RlbF9iYXRjaD0iZnN2YSIsIGZvcmNlPVRSVUUpKQpvdXJfcGFpcndpc2Vfbm9iYXRjaCA8LSBzbShhbGxfcGFpcndpc2Uob3VyX3BhaXJ3aXNlX2ZpbHQsIG1vZGVsX2JhdGNoPUZBTFNFLCBmb3JjZT1UUlVFKSkKYGBgCgojIyBUYiBsaWJyYXJpZXMKCmBgYHtyIHRiX2RlX3Rlc3RpbmcsIGZpZy5zaG93PSdoaWRlJ30KdGJfcGFpcndpc2VfZmlsdCA8LSBzbShub3JtYWxpemVfZXhwdCh0Yl9wcm90ZWluX2V4cHQsIGZpbHRlcj1UUlVFKSkKdGJfcGFpcndpc2VfY29tcCA8LSBzbShhbGxfcGFpcndpc2UodGJfcGFpcndpc2VfZmlsdCwgbW9kZWxfYmF0Y2g9ImZzdmEiLCBmb3JjZT1UUlVFKSkKdGJfcGFpcndpc2Vfbm9iYXRjaCA8LSBzbShhbGxfcGFpcndpc2UodGJfcGFpcndpc2VfZmlsdCwgbW9kZWxfYmF0Y2g9RkFMU0UsIGZvcmNlPVRSVUUpKQpgYGAKCiMjIyBTaG93IGEgZmV3IG1ldHJpY3MgZnJvbSB0aGUgaHBnbHRvb2xzIHBhaXJ3aXNlIGNvbXBhcmlzb25zCgpgYGB7ciBzaG93X2RlX3Rlc3Rpbmd9Cm91cl9wYWlyd2lzZV9jb21wJGNvbXBhcmlzb24kaGVhdAp0Yl9wYWlyd2lzZV9jb21wJGNvbXBhcmlzb24kaGVhdApgYGAKCiMgRm9yIGVhY2ggbXNzdGF0cyBydW4sIGRvIGEgREUgdGFibGUKCiMjIHd0X2ZpbHRyYXRlIHZzIHd0X3dob2xlCgojIyMgT3VyIGxpYnJhcmllcwoKYGBge3Igb3VyX2NvbWJpbmVfd3RjZl93dHdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAid3RjZl92c193dHdob2xlIiA9IGMoInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIikpCmRyb3BwZXJzIDwtIGMoInVuZGVmaW5lZCIpCm5hbWVzKGRyb3BwZXJzKSA8LSAibG9nMmZjIgoKIyMgTWFrZSBzdXJlIHRvIHNldCB0aGUgcm93bmFtZXMgc28gaXQgd2lsbCBtZXJnZSBpbnRvIHRoZSBleGNlbCBmaWxlLgpzZXRfbmFtZSA8LSAid3RfZmlsdHJhdGVfdnNfd3Rfd2hvbGUiCnJvd25hbWVzKG91cl9yZXN1bHRzW1tzZXRfbmFtZV1dKSA8LSBvdXJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0Kd3RjZl93dHdob2xlX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAjIyBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1vdXJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2x1ZGVzPWRyb3BwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvb3VyX3d0Y2ZfdnNfd3R3aG9sZV90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQoKd3RjZl9ub2JhdGNoX3d0d2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjIG91cl9wYWlyd2lzZV9ub2JhdGNoLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PW91cl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIG91cl9wYWlyd2lzZV9ub2JhdGNoLCBrZWVwZXJzPWtlZXBlcnMsCiAgZXhjbHVkZXM9ZHJvcHBlcnMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9vdXJfd3RjZl92c193dHdob2xlX25vYmF0Y2hfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKCiMjY29tcF90YWJsZSA8LSB3dGNmX3d0d2hvbGVfdGFibGVzJGRhdGFbW3NldF9uYW1lXV0KIyNjb3IudGVzdChjb21wX3RhYmxlJGxvZzJmYywgY29tcF90YWJsZSRkZXNlcV9sb2dmYywgbWV0aG9kPSJzcGVhcm1hbiIpCgojI2NvbXBfdGFibGUgPC0gd3RjZl9ub2JhdGNoX3d0d2hvbGVfdGFibGVzJGRhdGFbW3NldF9uYW1lXV0KIyNjb3IudGVzdChjb21wX3RhYmxlJGxvZzJmYywgY29tcF90YWJsZSRkZXNlcV9sb2dmYywgbWV0aG9kPSJzcGVhcm1hbiIpCmBgYAoKIyMjIFRiIGxpYnJhcmllcwoKYGBge3IgdGJfY29tYmluZV93dGNmX3d0d2hvbGUsIGZpZy5zaG93PSdoaWRlJ30Ka2VlcGVycyA8LSBsaXN0KAogICJ3dGNmX3ZzX3d0d2hvbGUiID0gYygid3RfZmlsdHJhdGUiLCAid3Rfd2hvbGUiKSkKZHJvcHBlcnMgPC0gYygidW5kZWZpbmVkIikKbmFtZXMoZHJvcHBlcnMpIDwtICJsb2cyZmMiCgojIyBNYWtlIHN1cmUgdG8gc2V0IHRoZSByb3duYW1lcyBzbyBpdCB3aWxsIG1lcmdlIGludG8gdGhlIGV4Y2VsIGZpbGUuCnNldF9uYW1lIDwtICJ3dF9maWx0cmF0ZV92c193dF93aG9sZSIKIyMgcm93bmFtZXModGJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gdGJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0Kd3RjZl93dHdob2xlX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAjIyB0Yl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PXRiX3Jlc3VsdHNbW3NldF9uYW1lXV0sCiAgdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2x1ZGVzPWRyb3BwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvdGJfd3RjZl92c193dHdob2xlX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCgp3dGNmX25vYmF0Y2hfd3R3aG9sZV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgIyMgdGJfcGFpcndpc2Vfbm9iYXRjaCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD10Yl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIHRiX3BhaXJ3aXNlX25vYmF0Y2gsIGtlZXBlcnM9a2VlcGVycywKICBleGNsdWRlcz1kcm9wcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3RiX3d0Y2ZfdnNfd3R3aG9sZV9ub2JhdGNoX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCgojI2NvbXBfdGFibGUgPC0gd3RjZl93dHdob2xlX3RhYmxlcyRkYXRhW1tzZXRfbmFtZV1dCiMjY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZGVzZXFfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQoKIyNjb21wX3RhYmxlIDwtIHd0Y2Zfbm9iYXRjaF93dHdob2xlX3RhYmxlcyRkYXRhW1tzZXRfbmFtZV1dCiMjY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZGVzZXFfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpgYGAKCiMjIGRlbHRhX2ZpbHRyYXRlIHZzIGRlbHRhX3dob2xlCgojIyMgT3VyIGxpYnJhcmllcwoKYGBge3Igb3VyX2NvbWJpbmVfZGVsdGFjZl9kZWx0YXdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAiZGVsdGFjZl92c19kZWx0YXdob2xlIiA9IGMoImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIikpCnNldF9uYW1lIDwtICJkZWx0YV9maWx0cmF0ZV92c19kZWx0YV93aG9sZSIKIyMgcm93bmFtZXMob3VyX3Jlc3VsdHNbW3NldF9uYW1lXV0pIDwtIG91cl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQpkZWx0YWNmX2RlbHRhd2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1vdXJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvb3VyX2RlbHRhY2ZfdnNfZGVsdGF3aG9sZV90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIyBUYiBsaWJyYXJpZXMKCmBgYHtyIHRiX2NvbWJpbmVfZGVsdGFjZl9kZWx0YXdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAiZGVsdGFjZl92c19kZWx0YXdob2xlIiA9IGMoImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIikpCnNldF9uYW1lIDwtICJkZWx0YV9maWx0cmF0ZV92c19kZWx0YV93aG9sZSIKIyMgcm93bmFtZXModGJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gdGJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0KZGVsdGFjZl9kZWx0YXdob2xlX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKIyMgIHRiX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywgZXh0cmFfYW5ub3Q9dGJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICB0Yl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC90Yl9kZWx0YWNmX3ZzX2RlbHRhd2hvbGVfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBjb21wX2ZpbHRyYXRlIHZzIGNvbXBfd2hvbGUKCiMjIyBPdXIgbGlicmFyaWVzCgpgYGB7ciBvdXJfY29tYmluZV9jb21wY2ZfY29tcHdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAiY29tcGNmX3ZzX2NvbXB3aG9sZSIgPSBjKCJjb21wX2ZpbHRyYXRlIiwgImNvbXBfd2hvbGUiKSkKc2V0X25hbWUgPC0gImNvbXBfZmlsdHJhdGVfdnNfY29tcF93aG9sZSIKcm93bmFtZXMob3VyX3Jlc3VsdHNbW3NldF9uYW1lXV0pIDwtIG91cl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQpjb21wY2ZfY29tcHdob2xlX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKIyMgIG91cl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PW91cl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIG91cl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9vdXJfY29tcGNmX3ZzX2NvbXB3aG9sZV90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIyBUYiBsaWJyYXJpZXMKCmBgYHtyIHRiX2NvbWJpbmVfY29tcGNmX2NvbXB3aG9sZSwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImNvbXBjZl92c19jb21wd2hvbGUiID0gYygiY29tcF9maWx0cmF0ZSIsICJjb21wX3dob2xlIikpCnNldF9uYW1lIDwtICJjb21wX2ZpbHRyYXRlX3ZzX2NvbXBfd2hvbGUiCiMjcm93bmFtZXModGJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gdGJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0KY29tcGNmX2NvbXB3aG9sZV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiMjICB0Yl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PXRiX3Jlc3VsdHNbW3NldF9uYW1lXV0sCiAgdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvdGJfY29tcGNmX3ZzX2NvbXB3aG9sZV90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIGRlbHRhX2ZpbHRyYXRlIHZzIHd0X2ZpbHRyYXRlCgojIyMgT3VyIGxpYnJhcmllcwoKYGBge3Igb3VyX2NvbWJpbmVfZGVsdGFjZl93dGNmLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAiZGVsdGFjZl92c193dGNmIiA9IGMoImRlbHRhX2ZpbHRyYXRlIiwgInd0X2ZpbHRyYXRlIikpCnNldF9uYW1lIDwtICJkZWx0YV9maWx0cmF0ZV92c193dF9maWx0cmF0ZSIKIyNyb3duYW1lcyhvdXJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gb3VyX3Jlc3VsdHNbW3NldF9uYW1lXV1bWyJQcm90ZWluIl1dCmRlbHRhY2Zfd3RjZl90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiMjICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1vdXJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvb3VyX2RlbHRhY2ZfdnNfd3RjZl90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIyBUYiBsaWJyYXJpZXMKCmBgYHtyIHRiX2NvbWJpbmVfZGVsdGFjZl93dGNmLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAiZGVsdGFjZl92c193dGNmIiA9IGMoImRlbHRhX2ZpbHRyYXRlIiwgInd0X2ZpbHRyYXRlIikpCnNldF9uYW1lIDwtICJkZWx0YV9maWx0cmF0ZV92c193dF9maWx0cmF0ZSIKIyNyb3duYW1lcyh0Yl9yZXN1bHRzW1tzZXRfbmFtZV1dKSA8LSB0Yl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQpkZWx0YWNmX3d0Y2ZfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD10Yl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIHRiX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3RiX2RlbHRhY2ZfdnNfd3RjZl90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIGNvbXBfZmlsdHJhdGUgdnMgd3RfZmlsdHJhdGUKCiMjIyBPdXIgbGlicmFyaWVzCgpgYGB7ciBvdXJfY29tYmluZV9jb21wY2Zfd3RjZiwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImNvbXBjZl92c193dGNmIiA9IGMoImNvbXBfZmlsdHJhdGUiLCAid3RfZmlsdHJhdGUiKSkKc2V0X25hbWUgPC0gImNvbXBfZmlsdHJhdGVfdnNfd3RfZmlsdHJhdGUiCiMjcm93bmFtZXMob3VyX3Jlc3VsdHNbW3NldF9uYW1lXV0pIDwtIG91cl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQpjb21wY2Zfd3RjZl90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiMjICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1vdXJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvb3VyX2NvbXBjZl92c193dGNmX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCmBgYAoKIyMjIFRiIGxpYnJhcmllcwoKYGBge3IgdGJfY29tYmluZV9jb21wY2Zfd3RjZiwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImNvbXBjZl92c193dGNmIiA9IGMoImNvbXBfZmlsdHJhdGUiLCAid3RfZmlsdHJhdGUiKSkKc2V0X25hbWUgPC0gImNvbXBfZmlsdHJhdGVfdnNfd3RfZmlsdHJhdGUiCiMjcm93bmFtZXModGJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gdGJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0KY29tcGNmX3d0Y2ZfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjICB0Yl9wYWlyd2lzZV9jb21wLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PXRiX3Jlc3VsdHNbW3NldF9uYW1lXV0sCiAgdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvdGJfY29tcGNmX3ZzX3d0Y2ZfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBkZWx0YV93aG9sZSB2cyB3dF93aG9sZQoKIyMjIE91ciBsaWJyYXJpZXMKCmBgYHtyIG91cl9jb21iaW5lX2RlbGF3aG9sZV93dHdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAid3RjZl92c193dHdob2xlIiA9IGMoInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIikpCnNldF9uYW1lIDwtICJkZWx0YV93aG9sZV92c193dF93aG9sZSIKIyNyb3duYW1lcyhvdXJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gb3VyX3Jlc3VsdHNbW3NldF9uYW1lXV1bWyJQcm90ZWluIl1dCnd0Y2Zfd3R3aG9sZV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgIyMgb3VyX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywgZXh0cmFfYW5ub3Q9b3VyX3Jlc3VsdHNbW3NldF9uYW1lXV0sCiAgb3VyX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL291cl9kZWx0YXdob2xlX3ZzX3d0d2hvbGVfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyMgVGIgbGlicmFyaWVzCgpgYGB7ciB0Yl9jb21iaW5lX2RlbGF3aG9sZV93dHdob2xlLCBmaWcuc2hvdz0naGlkZSd9CmtlZXBlcnMgPC0gbGlzdCgKICAid3RjZl92c193dHdob2xlIiA9IGMoInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIikpCnNldF9uYW1lIDwtICJkZWx0YV93aG9sZV92c193dF93aG9sZSIKIyNyb3duYW1lcyh0Yl9yZXN1bHRzW1tzZXRfbmFtZV1dKSA8LSB0Yl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQp3dGNmX3d0d2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD10Yl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIHRiX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3RiX2RlbHRhd2hvbGVfdnNfd3R3aG9sZV90YWJsZXMtdiIsIHZlciwgIi54bHN4IikpKQpgYGAKCiMjIGNvbXBfd2hvbGUgdnMgd3Rfd2hvbGUKCiMjIyBPdXIgbGlicmFyaWVzCgpgYGB7ciBvdXJfY29tYmluZV9jb21wd2hvbGVfd3R3aG9sZSwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImNvbXB3aG9sZV92c193dHdob2xlIiA9IGMoImNvbXBfd2hvbGUiLCAid3Rfd2hvbGUiKSkKc2V0X25hbWUgPC0gImNvbXBfd2hvbGVfdnNfd3Rfd2hvbGUiCiMjcm93bmFtZXMob3VyX3Jlc3VsdHNbW3NldF9uYW1lXV0pIDwtIG91cl9yZXN1bHRzW1tzZXRfbmFtZV1dW1siUHJvdGVpbiJdXQpjb21wd2hvbGVfd3R3aG9sZV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgIyNvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1vdXJfcmVzdWx0c1tbc2V0X25hbWVdXSwKICBvdXJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvb3VyX2NvbXB3aG9sZV92c193dHdob2xlX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCmBgYAoKIyMjIFRiIGxpYnJhcmllcwoKYGBge3IgdGJfY29tYmluZV9jb21wd2hvbGVfd3R3aG9sZSwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImNvbXB3aG9sZV92c193dHdob2xlIiA9IGMoImNvbXBfd2hvbGUiLCAid3Rfd2hvbGUiKSkKc2V0X25hbWUgPC0gImNvbXBfd2hvbGVfdnNfd3Rfd2hvbGUiCiMjcm93bmFtZXModGJfcmVzdWx0c1tbc2V0X25hbWVdXSkgPC0gdGJfcmVzdWx0c1tbc2V0X25hbWVdXVtbIlByb3RlaW4iXV0KY29tcHdob2xlX3d0d2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICMjdGJfcGFpcndpc2VfY29tcCwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD10Yl9yZXN1bHRzW1tzZXRfbmFtZV1dLAogIHRiX3BhaXJ3aXNlX2NvbXAsIGtlZXBlcnM9a2VlcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3RiX2NvbXB3aG9sZV92c193dHdob2xlX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCmBgYAoKYGBge3IgY29tcGFyZV9vdXJfdGIsIGV2YWw9RkFMU0V9Cm91cl90YWJsZSA8LSBvdXJfcGFpcndpc2VfY29tcCRkZXNlcSRhbGxfdGFibGVzJHd0X3dob2xlX3ZzX3d0X2ZpbHRyYXRlCnRiX3RhYmxlIDwtIHRiX3BhaXJ3aXNlX2NvbXAkZGVzZXEkYWxsX3RhYmxlcyR3dF93aG9sZV92c193dF9maWx0cmF0ZQpvdXJfb3JkZXIgPC0gb3JkZXIob3VyX3RhYmxlW1sibGltbWFfbG9nZmMiXV0pCnJvd25hbWVzKHRiX3RhYmxlKSA8LSBnc3ViKHBhdHRlcm49Il4oLiopXy4qIiwgcmVwbGFjZW1lbnQ9IlxcMSIsIHg9cm93bmFtZXModGJfdGFibGUpKQoKdGVzdF90YWJsZSA8LSBtZXJnZShvdXJfdGFibGUsIHRiX3RhYmxlLCBieT0icm93Lm5hbWVzIikKY29yLnRlc3QodGVzdF90YWJsZSRsb2dGQy54LCB0ZXN0X3RhYmxlJGxvZ0ZDLnkpCmBgYAoKIyBSTkFTZXEgdnMgcHJvdGVvbWljcwoKVGFrZSB0aGUgYW5hbHlzaXMgcGVyZm9ybWVkIG9uIDAyX3JlbGF0aXZlX3BlX2V4cHJlc3Npb24sIHdoaWNoIHVuZm9ydHVuYXRlbHkKd2FzIG9ubHkgdXNpbmcgdGhlIEREQSBkYXRhLCBub3cgcmV1c2UgaXQgd2l0aCB0aGUgRElBIGRhdGEgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCgpgYGB7ciBwcm90X3ZzX3JuYXNlcX0KYWxsX2RlIDwtIHJlYWQudGFibGUoImV4dGVybmFsX2RhdGEvbGltbWFfcmVzdWx0LmNzdiIsIGhlYWRlcj1UUlVFLCBzZXA9Ilx0IikKCnBlX2lkcyA8LSByZWFkLnRhYmxlKCJyZWZlcmVuY2UvYW5ub3RhdGVkX3BlX2dlbmVzLnR4dCIpCmNvbG5hbWVzKHBlX2lkcykgPC0gImdlbmUiCnBlX2Fubm90YXRpb25zIDwtIG1lcmdlKHBlX2lkcywgbXRiX2Fubm90YXRpb25zLCBieS54PSJnZW5lIiwgYnkueT0iaWQiKQpjaG9zZW5fY29sbmFtZXMgPC0gYygicnZfaWQiLCAiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJ3aWR0aCIsICJzdHJhbmQiLAogICAgICAgICAgICAgICAgICAgICAic291cmNlIiwgInR5cGUiLCAic2NvcmUiLCAicGhhc2UiLCAiaWQiLCAiZ2VuZV9pZCIsCiAgICAgICAgICAgICAgICAgICAgICJkZXNjcmlwdGlvbiIsICJmdW5jdGlvbiIpCmNvbG5hbWVzKHBlX2Fubm90YXRpb25zKSA8LSBjaG9zZW5fY29sbmFtZXMKcm93bmFtZXMocGVfYW5ub3RhdGlvbnMpIDwtIHBlX2Fubm90YXRpb25zW1siaWQiXV0KCnRtcF9kZSA8LSBhbGxfZGUKY29sbmFtZXModG1wX2RlKSA8LSBjKCJpZCIsICJsb2dmYyIsICJhdmVfZXhwciIsICJhZGpwIiwgImFiYnJldl9pZCIsICJkZXNjcmlwdGlvbiIsICJnZW5lX2xlbmd0aCIsICJ0eXBlIikKY29sbmFtZXMobXRiX2Fubm90YXRpb25zKSA8LSBjaG9zZW5fY29sbmFtZXMKYWxsX2RlIDwtIG1lcmdlKHRtcF9kZSwgbXRiX2Fubm90YXRpb25zLCBieT0iaWQiKQpjb2xuYW1lcyhhbGxfZGUpIDwtIGMoImlkIiwibG9nZmMiLCAiYXZlX2V4cHIiLCAiYWRqcCIsICJhYmJyZXZfaWQiLCAiZGVzY3JpcHRpb24iLCAiZ2VuZV9sZW5ndGgiLCAidHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAicnZfaWQiLCAic3RhcnQiLCAiZW5kIiwgIndpZHRoIiwgInN0cmFuZCIsICJzb3VyY2UiLCAidHlwZSIsICJuYSIsICJhbm90aGVybmEiLAogICAgICAgICAgICAgICAgICAgICAgIm10Yl9pZCIsICJhbm90aGVyX2FiYnJldl9pZCIsICJhbm90aGVyX2Rlc2NyaXB0aW9uIiwgImh0bWxfc3RyaW5nIikKYWxsX2RlIDwtIGFsbF9kZVssIGMoMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUpXQoKcGVfZGUgPC0gbWVyZ2UocGVfYW5ub3RhdGlvbnMsIGFsbF9kZSwgYnk9ImlkIikKY29sbmFtZXMocGVfZGUpIDwtIGMoImlkIiwgInJ2X2lkIiwgImNocm9tb3NvbWUiLCAic3RhcnQiLCAiZW5kIiwgIndpZHRoIiwgInN0cmFuZCIsCiAgICAgICAgICAgICAgICAgICAgICJzb3VyY2UiLCAidHlwZSIsICJzY29yZSIsICJwaGFzZSIsICJnZW5lX2lkIiwgImRlc2NyaXB0aW9uIiwgImZ1bmN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgImxvZ2ZjIiwgImF2ZV9leHByIiwgImFkanAiLCAiYW5vdGhlcl9nZW5lIiwgImFub3RoZXJfZGVzY3JpcHRpb24iLCAiZ2VuZV9sZW5ndGgiLAogICAgICAgICAgICAgICAgICAgICAiYW5vdGhlcl90eXBlIiwgImFub3RoZXJfaWQiLCAiYW5vdGhlcl9zdGFydCIsICJhbm90aGVyX2VuZCIsICJhbm90aGVyX3dpZHRoIiwKICAgICAgICAgICAgICAgICAgICAgImFub3RoZXJfc3RyYW5kIiwgImFub3RoZXJfc291cmNlIiwgImFub3RoZXJfdHlwZSIpCnBlX2RlIDwtIHBlX2RlWywgYygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNyldCiMjIHBlX2RlX2Fubm90IDwtIG1lcmdlKHBlX2RlLCBtdGJfYW5ub3RhdGlvbnMsIGJ5PSJsb2N1c190YWciKQojIyBUaGUgY29udHJhc3QgaXMgd3JpdHRlbiBhcyB3dCAtIGRlbHRhLCBzbyBhZGQgYmFjayB0aGUgbG9nRkMgSSB0aGluawojIyBIb3BlZnVsbHkgSSBkaWQgbm90IHJldmVyc2UgdGhpcyBpbiBteSBoZWFkLgpwZV9kZSRhdmVfbWludXNfbG9nIDwtIHBlX2RlJGF2ZV9leHByIC0gcGVfZGUkbG9nZmMKYWxsX2RlJGF2ZV9taW51c19sb2cgPC0gYWxsX2RlJGF2ZV9leHByIC0gYWxsX2RlJGxvZ2ZjCnBlX2RlJHBzZXVkb19ycGttIDwtIChwZV9kZSRhdmVfbWludXNfbG9nIC8gcGVfZGUkd2lkdGgpICogMTAwMAphbGxfZGUkcHNldWRvX3Jwa20gPC0gKGFsbF9kZSRhdmVfbWludXNfbG9nIC8gYWxsX2RlJHdpZHRoKSAqIDEwMDAKCm1heGltdW1fZXhwcmVzc2lvbiA8LSBtYXgocGVfZGVbWyJwc2V1ZG9fcnBrbSJdXSkKbWF4aW11bV9hbGwgPC0gbWF4KGFsbF9kZSRwc2V1ZG9fcnBrbSkKcGVfZGVbWyJleHByc192c19tYXgiXV0gPC0gcGVfZGVbWyJwc2V1ZG9fcnBrbSJdXSAvIG1heGltdW1fZXhwcmVzc2lvbgphbGxfZGUkZXhwcnNfdnNfbWF4IDwtIGFsbF9kZSRwc2V1ZG9fcnBrbSAvIG1heGltdW1fYWxsCgp0YWJsZV9vcmRlciA8LSBvcmRlcihwZV9kZVtbImV4cHJzX3ZzX21heCJdXSwgZGVjcmVhc2luZz1UUlVFKQpwZV9kZSA8LSBwZV9kZVt0YWJsZV9vcmRlciwgXQoKa25pdHI6OmthYmxlKGhlYWQocGVfZGUsIG49NTApKQoKd3JpdGUuY3N2KHg9cGVfZGUsIGZpbGU9InBlX3JlbGF0aXZlX2V4cHJlc3Npb24uY3N2IikKCnBsb3RfaGlzdG9ncmFtKHBlX2RlJGV4cHJzX3ZzX21heCwgYmlucz0yMCkKCnByb3RfdGFibGUgPC0gdGJfcGFpcndpc2Vfbm9iYXRjaCRsaW1tYSRhbGxfdGFibGVzW1sid3Rfd2hvbGVfdnNfZGVsdGFfd2hvbGUiXV0KCmFsbF9jb21iaW5lZF90YWJsZSA8LSBtZXJnZShhbGxfZGUsIHByb3RfdGFibGUsIGJ5Lng9ImlkIiwgYnkueT0icm93Lm5hbWVzIikKY29yLnRlc3QoYWxsX2NvbWJpbmVkX3RhYmxlJGF2ZV9leHByLCBhbGxfY29tYmluZWRfdGFibGUkQXZlRXhwciwgbWV0aG9kPSJzcGVhcm1hbiIpCmFsbF90ZXN0aW5nIDwtIGFsbF9jb21iaW5lZF90YWJsZVssIGMoImF2ZV9leHByIiwgIkF2ZUV4cHIiKV0KYWxsX2NvbXBhcmlzb24gPC0gcGxvdF9saW5lYXJfc2NhdHRlcihhbGxfdGVzdGluZykKYWxsX2NvbXBhcmlzb24kc2NhdHRlcgoKcGVfY29tYmluZWRfdGFibGUgPC0gbWVyZ2UocGVfZGUsIHByb3RfdGFibGUsIGJ5Lng9ImlkIiwgYnkueT0icm93Lm5hbWVzIikKY29yLnRlc3QocGVfY29tYmluZWRfdGFibGUkYXZlX2V4cHIsIHBlX2NvbWJpbmVkX3RhYmxlJEF2ZUV4cHIsIG1ldGhvZD0ic3BlYXJtYW4iKQpwZV90ZXN0aW5nIDwtIHBlX2NvbWJpbmVkX3RhYmxlWywgYygiYXZlX2V4cHIiLCAiQXZlRXhwciIpXQpwZV9jb21wYXJpc29uIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIocGVfdGVzdGluZykKcGVfY29tcGFyaXNvbiRzY2F0dGVyCmBgYAoKYGBge3Igc2F2ZW1lfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKfQpgYGAK