M.tuberculosis 20180913: New samples! Analyzing data from OpenSwathWorkFlow/TRIC.

20180913

This is a copy of 20180817 but where I will further simplify to include only the wt/mutant and only the most recent technical replicate.

Therefore, the first thing I did was to copy the sample sheet and remove most of the rows, leaving behind only the 12 which comprise the 3 biological replicates for wt/mutant and the technical run dated 20180817.

Notes

  1. Remove complement.
  2. Work only with newest samples.
  3. Define intersections between limma/edger/deseq/msstats for multiple thresholds.
  4. Ontology tests

New samples!

In this copy of the worksheet, I am going to deal only with the tuberculist libraries, and only with the most recent technical replicate of the data.

This worksheet is a copy of 20180806 but this time with feeling! (or new samples) A minor caveat: I had some difficulties converting the new data to a openMS suitable format. I am not certain if I messed up a priori, or if a change in the version of the software on the spec caused the problem, but for future reference:

To properly convert the data to mzXML, make sure to use the TPP MSConvert utility and have ‘TPP’ compatibility on.

Analyzing data from openMS and friends.

SWATH2stats preprocessing

I am using my slightly modified copy of SWATH2stats. This seeks to ensure that changes in the case of columns in the metadata from one version of OpenMS to another do not trouble me.

Creating a swath2stats experiment using the tuberculist-derived library 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.

Notes 20180913

If I want to subset like this, I need to delete the pyprophet outputs for anything not included in this set and rerun feature_alignment.py.

## Loading SWATH2stats
## Not checking that the files are identical between the annotation and data.

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

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()).

Perform filters

The following block performs the metrics and filters suggested by swath2stats. These first define the decoy hit rate in the data, then filter the data based on that. It also filters out hits with less than ideal m-scores and proteins with non-optimal distributions of peptide hits (either due to too few peptides or a weird distribution of intensities).

## Going to write the image to: images/20180611_tb_swath2stats_sample_cor.png when dev.off() is called.
## png 
##   2

## Number of non-decoy peptides: 21557
## Number of decoy peptides: 939
## Decoy rate: 0.0436

## The average FDR by run on assay level is 0.009
## The average FDR by run on peptide level is 0.01
## The average FDR by run on protein level is 0.047

## Target assay FDR: 0.02
## Required overall m-score cutoff: 0.0070795
## achieving assay FDR: 0.0181
## Target protein FDR: 0.02
## Required overall m-score cutoff: 0.00089125
## achieving protein FDR: 0.0182
## Original dimension: 133447, new dimension: 128204, difference: 5243.
## Peptides need to have been quantified in more conditions than: 9.6 in order to pass this percentage-based threshold.
## Fraction of peptides selected: 0.11
## Original dimension: 135427, new dimension: 33028, difference: 102399.
## Target protein FDR: 0.000891250938133746
## 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: 2999
## Final target proteins: 2999
## Final decoy proteins: 0
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 20921
## Final target peptides: 20921
## Final decoy peptides: 0
## Total peptides selected from:
## Total peptides: 20921
## Final target peptides: 20921
## 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.
## Number of proteins detected: 3016
## Protein identifiers: Rv2524c, Rv3716c, Rv1270c, Rv0724, Rv0161, Rv2535c
## Number of proteins detected that are supported by a proteotypic peptide: 2888
## Number of proteotypic peptides detected: 20772
## Number of proteins detected: 2890
## First 6 protein identifiers: Rv2524c, Rv3716c, Rv1270c, Rv0724, Rv0161, Rv2535c
## Before filtering:
##   Number of proteins: 2888
##   Number of peptides: 20772
## 
## Percentage of peptides removed: 21.87%
## 
## After filtering:
##   Number of proteins: 2861
##   Number of peptides: 16230
## Before filtering:
##   Number of proteins: 2861
##   Number of peptides: 16230
## 
## Percentage of peptides removed: 0.04%
## 
## After filtering:
##   Number of proteins: 2603
##   Number of peptides: 16223

Write out matrices of the results

swath2stats provides a couple of ways to print out its results, one in a format specifically intended for MSstats, and another as a more canonical matrix of rows = proteins, columns = samples.

## Protein overview matrix results/swath2stats/20180913/protein_all.csv written to working folder.
## [1] 3873   13
## Protein overview matrix results/swath2stats/20180913/protein_matrix_mscore.csv written to working folder.
## [1] 2999   13
## Peptide overview matrix results/swath2stats/20180913/peptide_matrix_mscore.csv written to working folder.
## [1] 20921    13
## Protein overview matrix results/swath2stats/20180913/protein_matrix_minimum.csv written to working folder.
## [1] 2603   13
## Peptide overview matrix results/swath2stats/20180913/peptide_matrix_minimum.csv written to working folder.
## [1] 93860    13

## The library contains5transitions per precursor.
## The data table was transformed into a table containing one row per transition.
## 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.

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.

## [1] "delta_filtrate" "wt_filtrate"    "delta_whole"    "wt_whole"

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.

## Warning: Removed 90 rows containing non-finite values (stat_boxplot).
## Warning: Removed 35 rows containing non-finite values (stat_boxplot).
## Warning: Removed 60 rows containing non-finite values (stat_boxplot).
## Warning: Removed 85 rows containing non-finite values (stat_boxplot).
## Warning: Removed 55 rows containing non-finite values (stat_boxplot).
## Warning: Removed 60 rows containing non-finite values (stat_boxplot).
## Warning: Removed 50 rows containing non-finite values (stat_boxplot).
## Warning: Removed 20 rows containing non-finite values (stat_boxplot).
## Warning: Removed 90 rows containing non-finite values (stat_boxplot).
## Warning: Removed 30 rows containing non-finite values (stat_boxplot).
## Warning: Removed 55 rows containing non-finite values (stat_boxplot).
## Warning: Removed 160 rows containing non-finite values (stat_boxplot).

## Warning: Removed 160 rows containing non-finite values (stat_boxplot).
## Warning: Removed 180 rows containing non-finite values (stat_boxplot).
## Warning: Removed 95 rows containing non-finite values (stat_boxplot).
## Warning: Removed 75 rows containing non-finite values (stat_boxplot).
## Warning: Removed 55 rows containing non-finite values (stat_boxplot).
## Warning: Removed 35 rows containing non-finite values (stat_boxplot).
## Warning: Removed 70 rows containing non-finite values (stat_boxplot).
## Warning: Removed 30 rows containing non-finite values (stat_boxplot).
## Warning: Removed 35 rows containing non-finite values (stat_boxplot).
## Warning: Removed 60 rows containing non-finite values (stat_boxplot).
## Warning: Removed 55 rows containing non-finite values (stat_boxplot).

## Warning: Removed 55 rows containing non-finite values (stat_boxplot).
## Warning: Removed 65 rows containing non-finite values (stat_boxplot).
## png 
##   2
## [1] 27

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.

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.

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.

## There were 12, now there are 6 samples.
## There were 12, now there are 6 samples.
## Writing the legend.

## Writing the raw reads.
## Hey, you merged the annotation data and did not reset the column names!
## Graphing the raw reads.
## varpart sees only 1 batch, adjusting the model accordingly.
## Attempting mixed linear model with: ~  (1|condition)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 0.2 min
## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading

## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading

## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading

## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading

## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading

## Warning in serialize(data, node$con): 'package:variancePartition' may not
## be available when loading
## Placing factor: condition at the beginning of the model.
## Warning in merge.data.frame(tmp_annot, added_data, by = "row.names"):
## column name 'Row.names' is duplicated in the result
## Writing the normalized reads.
## Graphing the normalized reads.

## varpart sees only 1 batch, adjusting the model accordingly.
## Attempting mixed linear model with: ~  (1|condition)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 0.1 min
## Placing factor: condition at the beginning of the model.
## Warning in merge.data.frame(tmp_annot, added_data, by = "row.names"):
## column name 'Row.names' is duplicated in the result
## Writing the median reads by factor.
## The factor delta_filtrate has 3 rows.
## The factor delta_whole has 3 rows.
## The factor wt_filtrate has 3 rows.
## The factor wt_whole has 3 rows.

Metrics of the full data set

Generate some metrics of the full data set, later the same things will be performed using the data subsets. There is a weird caveat: sva fails under some strange circumstances for this data. It seems that if the data is cpmmed, then sva sees the resulting matrix as containing singular values. I am guessing that this means that there are a bunch of low values in the filtrate data which, when cpm(data) is performed get dropped to near 0 and therefore trip up sva. There are two likely ways around this:

  1. Do not cpm the data.
  2. Filter the data more aggressively so that there are no zero-values after cpm().

Variance partition

This is a potential argument against including only the newest technical replicate of the data; as when all the technicals were included, these metrics looked much more sensible.

## varpart sees only 1 batch, adjusting the model accordingly.
## Attempting mixed linear model with: ~  (1|condition)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 0.1 min
## Placing factor: condition at the beginning of the model.
## Warning in merge.data.frame(tmp_annot, added_data, by = "row.names"):
## column name 'Row.names' is duplicated in the result

## Naively calculating coefficient of variation/dispersion with respect to condition.
## Finished calculating dispersion estimates.

## Naively calculating coefficient of variation/dispersion with respect to genotype.
## Finished calculating dispersion estimates.
## This data will benefit from being displayed on the log scale.
## If this is not desired, set scale='raw'
## Some entries are 0.  We are on log scale, adding 1 to the data.
## Changed 11011 zero count features.

Metrics of the filtrate data set

Once again, here we have metrics of the subset data; this time of filtrate data.

## This function will replace the expt$expressionset slot with:
## hpgl(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: hpgl
## Removing 1420 low-count genes (1183 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
##  s2018_0817BrikenTrypsinDIA01 s2018_0817BrikenTrypsinDIA02
##  Min.   :0.00e+00             Min.   :0.00e+00            
##  1st Qu.:5.13e+05             1st Qu.:5.36e+05            
##  Median :2.54e+06             Median :2.50e+06            
##  Mean   :3.41e+07             Mean   :4.52e+07            
##  3rd Qu.:1.24e+07             3rd Qu.:1.12e+07            
##  Max.   :4.22e+09             Max.   :1.88e+10            
##  s2018_0817BrikenTrypsinDIA03 s2018_0817BrikenTrypsinDIA07
##  Min.   :0.00e+00             Min.   :0.00e+00            
##  1st Qu.:7.09e+05             1st Qu.:0.00e+00            
##  Median :3.82e+06             Median :8.14e+05            
##  Mean   :5.00e+07             Mean   :2.89e+07            
##  3rd Qu.:1.86e+07             3rd Qu.:4.91e+06            
##  Max.   :5.61e+09             Max.   :1.66e+10            
##  s2018_0817BrikenTrypsinDIA08 s2018_0817BrikenTrypsinDIA09
##  Min.   :0.00e+00             Min.   :0.00e+00            
##  1st Qu.:2.08e+05             1st Qu.:2.04e+05            
##  Median :1.35e+06             Median :1.47e+06            
##  Mean   :3.98e+07             Mean   :2.36e+07            
##  3rd Qu.:7.45e+06             3rd Qu.:7.13e+06            
##  Max.   :2.00e+10             Max.   :3.81e+09
## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 2055 low-count genes (548 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
## This data will benefit from being displayed on the log scale.
## If this is not desired, set scale='raw'
## Some entries are 0.  We are on log scale, setting them to 0.5.
## Changed 173 zero count features.
## This function will replace the expt$expressionset slot with:
## cbcb(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unconverted.  It is often advisable to cpm/rpkm
##  the data to normalize for sampling differences, keep in mind though that rpkm
##  has some annoying biases, and voom() by default does a cpm (though hpgl_voom()
##  will try to detect this).
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 2443 low-count genes (160 remaining).
## Step 2: not normalizing the data.
## Step 3: not converting the data.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
## This data will benefit from being displayed on the log scale.
## If this is not desired, set scale='raw'
## Some entries are 0.  We are on log scale, setting them to 0.5.
## Changed 29 zero count features.

Something fun for Najib

Plot some metrics

In the previous blocks, I generated the metrics; in this block I will print them with the assumption that some of them will end up being included in whatever publication comes from this work; with that in mind I should probably change this to sva or pdf or something not png.

## Writing the image to: images/20180913_libsize.pdf and calling dev.off().

## Going to write the image to: images/20180913_norm_pca.pdf when dev.off() is called.
## Defaulting to tiff.
## Going to write the image to: images/20180913_fsva_pca.pdfg when dev.off() is called.
## Writing the image to: images/20180913_norm_corheat.pdf and calling dev.off().
## Writing the image to: images/20180913_raw_density.pdf and calling dev.off().

## Writing the image to: images/20180913_boxplot.pdf and calling dev.off().

## Writing the image to: images/20180913_whole_libsize.pdf and calling dev.off().

## Going to write the image to: images/20180913_whole_norm_pca.pdf when dev.off() is called.
## Going to write the image to: images/20180913_whole_fsva_pca.pdf when dev.off() is called.
## Writing the image to: images/20180913_whole_norm_corheat.pdf and calling dev.off().
## Writing the image to: images/20180913_whole_raw_density.pdf and calling dev.off().

## Writing the image to: images/20180913_whole_boxplot.pdf and calling dev.off().

## Writing the image to: images/20180913_libsize.pdf and calling dev.off().

## Going to write the image to: images/20180913_norm_pca.pdf when dev.off() is called.
## Going to write the image to: images/20180913_fsva_pca.pdf when dev.off() is called.
## Writing the image to: images/20180913_norm_corheat.pdf and calling dev.off().
## Writing the image to: images/20180913_raw_density.pdf and calling dev.off().

## Writing the image to: images/20180913_boxplot.pdf and calling dev.off().

Perform hpgltools Differential Expression Analyses

Earlier MSstats was used to contrast the various conditions in this data. In this block the same will be performed using the limma/deseq/edger/ebseq/basic methods. As an aside, running all of these methods in serial takes ~ 1/5th the time of running any one step of MSstats.

Idea from Volker

Given the initial pairwise data, look at wt edgeR results ratio filtrate/culture; then set a cutoff as log2fc <= 0.75. Proteins which survive this cutoff are then used in the ratio of ratios and analyses of mutant/wt.

The survivors of this initial cutoff is the set of secreted proteins. Compare this set with the set of known secreted proteins from other papers (Cox). Also Collins, Abesol (likely same as the synthetic Mtb library).

Separate, simultaneous filter: Look at the distribution of the culture filtrate data and filter out the (relatively) low-intensity bump. Then take the surviving set and perform all analyses with it. In theory, these two filter methods should get us to a similar place.

lfc cutoff cutoff

As mentioned below, Volker had an interesting cutoff suggestion: keep only those with lfc >= 0.75 filtrate/whole

## Starting edgeR pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq. If they freak out, check the state of the count table and ensure that it is in integer counts.
## The condition+batch model failed. Does your experimental design support both condition and batch? Using only a conditional model.
## Choosing the non-intercept containing model.
## EdgeR step 1/9: Importing and normalizing data.
## EdgeR step 2/9: Estimating the common dispersion.
## EdgeR step 3/9: Estimating dispersion across genes.
## EdgeR step 4/9: Estimating GLM Common dispersion.
## EdgeR step 5/9: Estimating GLM Trended dispersion.
## EdgeR step 6/9: Estimating GLM Tagged dispersion.
## EdgeR step 7/9: Running glmFit, switch to glmQLFit by changing the argument 'edger_test'.
## EdgeR step 8/9: Making pairwise contrasts.

## Before removal, there were 2603 entries.
## Now there are 548 entries.
## Percent kept: 98.068, 98.708, 98.132, 64.816, 67.348, 67.478, 99.143, 99.085, 98.417, 67.790, 67.178, 66.334
## Percent removed: 1.932, 1.292, 1.868, 35.184, 32.652, 32.522, 0.857, 0.915, 1.583, 32.210, 32.822, 33.666
## Before removal, there were 2603 entries.
## Now there are 298 entries.
## Percent kept: 77.606, 82.261, 71.273, 15.330, 16.345, 16.731, 87.346, 89.106, 80.236, 18.102, 16.575, 14.815
## Percent removed: 22.394, 17.739, 28.727, 84.670, 83.655, 83.269, 12.654, 10.894, 19.764, 81.898, 83.425, 85.185

Show a few metrics from the hpgltools pairwise comparisons

## Writing the image to: images/de_heat.png and calling dev.off().

For each msstats run, do a DE table

wt_cf vs wt_whole

## Warning in cor.test.default(comp_table$log2fc, comp_table$deseq_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$deseq_logfc
## S = 830000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.8083
## Warning in cor.test.default(comp_table$log2fc, comp_table$limma_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$limma_logfc
## S = 1900000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.5613
## Warning in cor.test.default(comp_table$log2fc, comp_table$ebseq_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$ebseq_logfc
## S = 820000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## 0.8093

delta_cf vs wt_cf

Something is weird about this particular contrast, I keep getting negative correlations!

## Warning in cor.test.default(comp_table$log2fc, comp_table$deseq_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$deseq_logfc
## S = 7800000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##     rho 
## -0.7928
## Warning in cor.test.default(comp_table$log2fc, comp_table$limma_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$limma_logfc
## S = 6800000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##    rho 
## -0.552
## Warning in cor.test.default(comp_table$log2fc, comp_table$edger_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$edger_logfc
## S = 7800000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##     rho 
## -0.7926
## Warning in cor.test.default(comp_table$log2fc, comp_table$ebseq_logfc,
## method = "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  comp_table$log2fc and comp_table$ebseq_logfc
## S = 7800000, p-value <2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##     rho 
## -0.7952
## Could not create a linear model of the data.
## Going to perform a scatter plot without linear model.
## 
##  Pearson's product-moment correlation
## 
## data:  com_table$log2fc and com_table$deseq_logfc
## t = -21, df = 300, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.8125 -0.7191
## sample estimates:
##     cor 
## -0.7699
## Warning in plot_multihistogram(df): NAs introduced by coercion
## Used Bon Ferroni corrected t test(s) between columns.

Ok, I have been resisting this, but lets look more closely at the data for this contrast. One thing I can do to look for correctness in what I am seeing is to look at the mean numerators/denominators for this contrast and see if they agree with msstats or the others.

Venn of MSstats vs. others for wt whole/cf

Najib asked for the overlap in perceived significance.

Ontology tests

Wt CF vs Wt whole

## The species being downloaded is: Mycobacterium tuberculosis H37Rv and is being downloaded as 83332.tab.
## Using the row names of your table.
## Found 26 genes out of 63 from the sig_genes in the go_db.
## Found 61 genes out of 63 from the sig_genes in the length_db.
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/wtcf_wtwhole_up_deseq_nobatch_goseq-v20180913.xlsx.

## Using the row names of your table.
## Found 9 genes out of 11 from the sig_genes in the go_db.
## Found 11 genes out of 11 from the sig_genes in the length_db.
## Warning in pcls(G): initial point very close to some inequality constraints
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/wtcf_wtwhole_down_deseq_nobatch_goseq-v20180913.xlsx.

delta CF vs delta whole

## Using the row names of your table.
## Found 32 genes out of 85 from the sig_genes in the go_db.
## Found 82 genes out of 85 from the sig_genes in the length_db.
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltacf_deltawhole_up_deseq_nobatch_goseq-v20180913.xlsx.

## Using the row names of your table.
## Found 27 genes out of 35 from the sig_genes in the go_db.
## Found 34 genes out of 35 from the sig_genes in the length_db.
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltacf_deltawhole_down_deseq_nobatch_goseq-v20180913.xlsx.

delta filtrate vs wt filtrate

## Using the row names of your table.
## Found 4 genes out of 7 from the sig_genes in the go_db.
## Found 6 genes out of 7 from the sig_genes in the length_db.
## Warning in pcls(G): initial point very close to some inequality constraints
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltacf_wtcf_up_deseq_nobatch_goseq-v20180913.xlsx.

## Using the row names of your table.
## Found 7 genes out of 15 from the sig_genes in the go_db.
## Found 14 genes out of 15 from the sig_genes in the length_db.
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltacf_wtcf_down_deseq_nobatch_goseq-v20180913.xlsx.

delta whole vs wt whole

## Using the row names of your table.
## Found 6 genes out of 7 from the sig_genes in the go_db.
## Found 7 genes out of 7 from the sig_genes in the length_db.
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltawhole_wtwhole_up_deseq_nobatch_goseq-v20180913.xlsx.

## Using the row names of your table.
## Found 5 genes out of 11 from the sig_genes in the go_db.
## Found 10 genes out of 11 from the sig_genes in the length_db.
## Warning in pcls(G): initial point very close to some inequality constraints
## Using manually entered categories.
## Calculating the p-values...
## 'select()' returned 1:1 mapping between keys and columns
## simple_goseq(): Calculating q-values
## Using GO.db to extract terms and categories.
## simple_goseq(): There are no genes with an adj.p < 0.1 using: BH.
## simple_goseq(): Providing genes with raw pvalue < 0.1.
## simple_goseq(): Filling godata with terms, this is slow.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## simple_goseq(): Making pvalue plots for the ontologies.
## Writing data to: excel/deltawhole_wtwhole_down_deseq_nobatch_goseq-v20180913.xlsx.

## NULL

circos

## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo=TRUE)
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo=FALSE)
## Had a successful gff import with rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo=FALSE)
## Returning a df with 15 columns and 4093 rows.
## The species being downloaded is: Mycobacterium tuberculosis H37Rv
## Warning: Setting row names on a tibble is deprecated.
## This assumes you have a colors.conf in circos/colors/ and fonts.conf in circos/fonts/
## It also assumes you have conf/ideogram.conf, conf/ticks.conf, and conf/housekeeping.conf
## It will write circos/conf/mtb.conf with a reasonable first approximation config file.
## Wrote karyotype to circos/conf/ideograms/mtb.conf
## This should match the karyotype= line in mtb.conf
## Wrote ticks to circos/conf/ticks_mtb.conf
## Warning in file.symlink(from, to): cannot symlink 'conf/mtb.conf' to './
## mtb.conf', reason 'File exists'
## Wrote karyotype to circos/conf/karyotypes/mtb.conf
## This should match the karyotype= line in mtb.conf
## Writing data file: circos/data/mtb_plus_go.txt with the + strand GO data.
## Writing data file: circos/data/mtb_minus_go.txt with the - strand GO data.
## Wrote the +/- config files.  Appending their inclusion to the master file.
## Returning the inner width: 0.84.  Use it as the outer for the next ring.
## Warning in merge.data.frame(df, annot_df, by = "row.names"): column name
## 'Row.names' is duplicated in the result
## Writing data file: circos/data/mtb_wt_wholewt_whole_heatmap.txt with the wt_wholewt_whole column.
## Warning in merge.data.frame(df, annot_df, by = "row.names"): column name
## 'Row.names' is duplicated in the result
## Writing data file: circos/data/mtb_delta_wholedelta_whole_heatmap.txt with the delta_wholedelta_whole column.
## Warning in merge.data.frame(df, annot_df, by = "row.names"): column name
## 'Row.names' is duplicated in the result
## Writing data file: circos/data/mtb_wt_filtratewt_filtrate_heatmap.txt with the wt_filtratewt_filtrate column.
## Warning in merge.data.frame(df, annot_df, by = "row.names"): column name
## 'Row.names' is duplicated in the result
## Writing data file: circos/data/mtb_delta_filtratedelta_filtrate_heatmap.txt with the delta_filtratedelta_filtrate column.
## Warning in merge.data.frame(df, annot_df, by = "row.names"): column name
## 'Row.names' is duplicated in the result
## Writing data file: circos/data/mtb_delta_filtrate_heatdelta_filtrate_heatmap.txt with the delta_filtrate_heatdelta_filtrate column.

circos plot

atb abelew@gmail.com

2018-11-07

LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxODA5MTM6IE5ldyBzYW1wbGVzISBBbmFseXppbmcgZGF0YSBmcm9tIE9wZW5Td2F0aFdvcmtGbG93L1RSSUMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICBtYXgucHJpbnQ9MTIwLAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQpwcmV2aW91c19maWxlIDwtICIwMV9hbm5vdGF0aW9uXzIwMTgwOTEzLlJtZCIKdmVyIDwtICIyMDE4MDkxMyIKdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCgpybWRfZmlsZSA8LSBwYXN0ZTAoIjAyX3N3YXRoMnN0YXRzXyIsIHZlciwgIi5SbWQiKQp2ZXIgPC0gIjIwMTgwOTEzIgpgYGAKCiMgMjAxODA5MTMKClRoaXMgaXMgYSBjb3B5IG9mIDIwMTgwODE3IGJ1dCB3aGVyZSBJIHdpbGwgZnVydGhlciBzaW1wbGlmeSB0byBpbmNsdWRlIG9ubHkgdGhlCnd0L211dGFudCBhbmQgb25seSB0aGUgbW9zdCByZWNlbnQgdGVjaG5pY2FsIHJlcGxpY2F0ZS4KClRoZXJlZm9yZSwgdGhlIGZpcnN0IHRoaW5nIEkgZGlkIHdhcyB0byBjb3B5IHRoZSBzYW1wbGUgc2hlZXQgYW5kIHJlbW92ZSBtb3N0IG9mCnRoZSByb3dzLCBsZWF2aW5nIGJlaGluZCBvbmx5IHRoZSAxMiB3aGljaCBjb21wcmlzZSB0aGUgMyBiaW9sb2dpY2FsIHJlcGxpY2F0ZXMKZm9yIHd0L211dGFudCBhbmQgdGhlIHRlY2huaWNhbCBydW4gZGF0ZWQgMjAxODA4MTcuCgojIE5vdGVzCgoxLiAgUmVtb3ZlIGNvbXBsZW1lbnQuCjIuICBXb3JrIG9ubHkgd2l0aCBuZXdlc3Qgc2FtcGxlcy4KMy4gIERlZmluZSBpbnRlcnNlY3Rpb25zIGJldHdlZW4gbGltbWEvZWRnZXIvZGVzZXEvbXNzdGF0cyBmb3IgbXVsdGlwbGUgdGhyZXNob2xkcy4KNC4gIE9udG9sb2d5IHRlc3RzCgojIE5ldyBzYW1wbGVzIQoKSW4gdGhpcyBjb3B5IG9mIHRoZSB3b3Jrc2hlZXQsIEkgYW0gZ29pbmcgdG8gZGVhbCBfb25seV8gd2l0aCB0aGUgdHViZXJjdWxpc3QKbGlicmFyaWVzLCBhbmQgb25seSB3aXRoIHRoZSBtb3N0IHJlY2VudCB0ZWNobmljYWwgcmVwbGljYXRlIG9mIHRoZSBkYXRhLgoKVGhpcyB3b3Jrc2hlZXQgaXMgYSBjb3B5IG9mIDIwMTgwODA2IGJ1dCB0aGlzIHRpbWUgd2l0aCBmZWVsaW5nISAob3IgbmV3IHNhbXBsZXMpCkEgbWlub3IgY2F2ZWF0OiBJIGhhZCBzb21lIGRpZmZpY3VsdGllcyBjb252ZXJ0aW5nIHRoZSBuZXcgZGF0YSB0byBhIG9wZW5NUwpzdWl0YWJsZSBmb3JtYXQuICBJIGFtIG5vdCBjZXJ0YWluIGlmIEkgbWVzc2VkIHVwIGEgcHJpb3JpLCBvciBpZiBhIGNoYW5nZSBpbgp0aGUgdmVyc2lvbiBvZiB0aGUgc29mdHdhcmUgb24gdGhlIHNwZWMgY2F1c2VkIHRoZSBwcm9ibGVtLCBidXQgZm9yIGZ1dHVyZQpyZWZlcmVuY2U6CgpUbyBwcm9wZXJseSBjb252ZXJ0IHRoZSBkYXRhIHRvIG16WE1MLCBtYWtlIHN1cmUgdG8gdXNlIHRoZSBUUFAgTVNDb252ZXJ0CnV0aWxpdHkgYW5kIGhhdmUgJ1RQUCcgY29tcGF0aWJpbGl0eSBvbi4KCkFuYWx5emluZyBkYXRhIGZyb20gb3Blbk1TIGFuZCBmcmllbmRzLgo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMjIFNXQVRIMnN0YXRzIHByZXByb2Nlc3NpbmcKCkkgYW0gdXNpbmcgbXkgc2xpZ2h0bHkgbW9kaWZpZWQgY29weSBvZiBTV0FUSDJzdGF0cy4gIFRoaXMgc2Vla3MgdG8gZW5zdXJlIHRoYXQKY2hhbmdlcyBpbiB0aGUgY2FzZSBvZiBjb2x1bW5zIGluIHRoZSBtZXRhZGF0YSBmcm9tIG9uZSB2ZXJzaW9uIG9mIE9wZW5NUyB0bwphbm90aGVyIGRvIG5vdCB0cm91YmxlIG1lLgoKIyMjIENyZWF0aW5nIGEgc3dhdGgyc3RhdHMgZXhwZXJpbWVudCB1c2luZyB0aGUgdHViZXJjdWxpc3QtZGVyaXZlZCBsaWJyYXJ5IGRhdGEKClRoZXJlIGlzIG9uZSBpbXBvcnRhbnQgY2F2ZWF0IGluIHRoZSBmb2xsb3dpbmcgYmxvY2s6IEkgdXNlZCBhIHJlZ2V4IHRvIHJlbW92ZQp0aGUgc2Vjb25kIGhhbGYgb2YgZ2VuZUlEX2dlbmVOYW1lIHNvIHRoYXQgbGF0ZXIgd2hlbiBJIG1lcmdlIGluIHRoZSBhbm5vdGF0aW9uCmRhdGEgSSBoYXZlIGl0IHdpbGwgbWF0Y2guCgojIyBOb3RlcyAyMDE4MDkxMwoKSWYgSSB3YW50IHRvIHN1YnNldCBsaWtlIHRoaXMsIEkgbmVlZCB0byBkZWxldGUgdGhlIHB5cHJvcGhldCBvdXRwdXRzCmZvciBhbnl0aGluZyBub3QgaW5jbHVkZWQgaW4gdGhpcyBzZXQgYW5kIHJlcnVuIGZlYXR1cmVfYWxpZ25tZW50LnB5LgoKYGBge3IgdGJfc3dhdGgyc3RhdHNfaW5pdGlhbH0KdHJpY19kYXRhIDwtIHJlYWQuY3N2KAogIHBhc3RlMCgicmVzdWx0cy90cmljLyIsIHZlciwgIi93aG9sZV84bXpfdHViZXJjdWxpc3QvY29tZXRfSENELnRzdiIpLCBzZXA9Ilx0IikKdHJpY19kYXRhW1siUHJvdGVpbk5hbWUiXV0gPC0gZ3N1YihwYXR0ZXJuPSJeKC4qKV8uKiQiLCByZXBsYWNlbWVudD0iXFwxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PXRyaWNfZGF0YVtbIlByb3RlaW5OYW1lIl1dKQpzYW1wbGVfYW5ub3QgPC0gZXh0cmFjdF9tZXRhZGF0YShwYXN0ZTAoInNhbXBsZV9zaGVldHMvTXRiX2RpYV9zYW1wbGVzXyIsIHZlciwgIi54bHN4IikpCmtlcHQgPC0gISBncmVwbCh4PXJvd25hbWVzKHNhbXBsZV9hbm5vdCksIHBhdHRlcm49Il5zXFwuXFwuIikKc2FtcGxlX2Fubm90IDwtIHNhbXBsZV9hbm5vdFtrZXB0LCBdCmRldnRvb2xzOjpsb2FkX2FsbCgifi9zY3JhdGNoL2dpdC9TV0FUSDJzdGF0cyIpCnMyc19leHAgPC0gc2FtcGxlX2Fubm90YXRpb24oZGF0YT10cmljX2RhdGEsIGNoZWNrX2ZpbGVzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9hbm5vdGF0aW9uPXNhbXBsZV9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxscGVwdGlkZW5hbWVfY29sdW1uPSJmdWxscGVwdGlkZW5hbWUiKQpgYGAKCk5vdyBJIGhhdmUgYSBjb3VwbGUgZGF0YSBzdHJ1Y3R1cmVzIHdoaWNoIHNob3VsZCBwcm92ZSB1c2VmdWwgZm9yIHRoZSBtZXRyaWNzCnByb3ZpZGVkIGJ5IFNXQVRIMnN0YXRzLCBNU3N0YXRzLCBhbmQgbXkgb3duIGhwZ2x0b29scy4KCiMgU1dBVEgyc3RhdHMgY29udGludWVkCgpUaGUgdmFyaW91cyBtZXRyaWNzIGFuZCBmaWx0ZXJzIHByb3ZpZGVkIGJ5IFNXQVRIMnN0YXRzIHNlZW0gcXVpdGUgcmVhc29uYWJsZSB0bwptZS4gIFRoZSBvbmx5IHRoaW5nIHRoYXQgcmVhbGx5IGJvdGhlcnMgbWUgaXMgdGhhdCB0aGV5IGFyZSBhbGwgY2FzZSBzZW5zaXRpdmUKYW5kIEkgZm91bmQgdGhhdCB0aGUgbW9zdCByZWNlbnQgdHJpYyBjaGFuZ2VkIHRoZSBjYXBpdGFsaXphdGlvbiBvZiBhIGNvbHVtbiwKY2F1c2luZyB0aGVzZSB0byBhbGwgZmFsbCBkb3duLiAgVGhlcmVmb3JlIEkgd2VudCBpbiBhbmQgbWFkZSBldmVyeXRoaW5nIGNhc2UKaW5zZW5zaXRpdmUgaW4gYSBmYXNoaW9uIHNpbWlsYXIgdG8gdGhhdCBkb25lIGJ5IE1Tc3RhdHMgKGV4Y2VwdCBJIGhhdGUgY2FwaXRhbApsZXR0ZXJzLCBzbyBJIHVzZWQgdG9sb3dlcigpIHJhdGhlciB0aGFuIHRvdXBwZXIoKSkuCgojIyBQZXJmb3JtIGZpbHRlcnMKClRoZSBmb2xsb3dpbmcgYmxvY2sgcGVyZm9ybXMgdGhlIG1ldHJpY3MgYW5kIGZpbHRlcnMgc3VnZ2VzdGVkIGJ5IHN3YXRoMnN0YXRzLgpUaGVzZSBmaXJzdCBkZWZpbmUgdGhlIGRlY295IGhpdCByYXRlIGluIHRoZSBkYXRhLCB0aGVuIGZpbHRlciB0aGUgZGF0YSBiYXNlZCBvbgp0aGF0LiAgSXQgYWxzbyBmaWx0ZXJzIG91dCBoaXRzIHdpdGggbGVzcyB0aGFuIGlkZWFsIG0tc2NvcmVzIGFuZCBwcm90ZWlucyB3aXRoCm5vbi1vcHRpbWFsIGRpc3RyaWJ1dGlvbnMgb2YgcGVwdGlkZSBoaXRzIChlaXRoZXIgZHVlIHRvIHRvbyBmZXcgcGVwdGlkZXMgb3IgYQp3ZWlyZCBkaXN0cmlidXRpb24gb2YgaW50ZW5zaXRpZXMpLgoKYGBge3IgdGJfc3dhdGgyc3RhdHNfcHJvY2Vzc2luZ30KIyMgR2V0IGNvcnJlbGF0aW9ucyBvbiBhIHNhbXBsZSBieSBzYW1wbGUgYmFzaXMKcHAoZmlsZT0iaW1hZ2VzLzIwMTgwNjExX3RiX3N3YXRoMnN0YXRzX3NhbXBsZV9jb3IucG5nIikKc2FtcGxlX2NvciA8LSBwbG90X2NvcnJlbGF0aW9uX2JldHdlZW5fc2FtcGxlcyhzMnNfZXhwLCBzaXplPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuLmFnZ3JlZ2F0ZT1zdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnZhbHVlcz0iaW50ZW5zaXR5IikKZGV2Lm9mZigpCnNhbXBsZV9jb25kX3JlcF9jb3IgPC0gcGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXMoczJzX2V4cCwgc2l6ZT0yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBhcmlzb249dHJhbnNpdGlvbl9ncm91cF9pZCB+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb24gKyBiaW9yZXBsaWNhdGUgKyBydW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuLmFnZ3JlZ2F0ZT1zdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnZhbHVlcz0iaW50ZW5zaXR5IikKCmRlY295X2xpc3RzIDwtIGFzc2Vzc19kZWNveV9yYXRlKHMyc19leHApCiMjIFRoaXMgc2VlbXMgYSBiaXQgaGlnaCB0byBtZSwgeWVzbm8/CmZkcl9vdmVyYWxsIDwtIGFzc2Vzc19mZHJfb3ZlcmFsbChzMnNfZXhwLCBvdXRwdXQ9IlJjb25zb2xlIiwgcGxvdD1UUlVFKQoKYnlydW5fZmRyIDwtIGFzc2Vzc19mZHJfYnlydW4oczJzX2V4cCwgRkZUPTAuNywgcGxvdD1UUlVFLCBvdXRwdXQ9IlJjb25zb2xlIikKY2hvc2VuX21zY29yZSA8LSBtc2NvcmU0YXNzYXlmZHIoczJzX2V4cCwgRkZUPTAuNywgZmRyX3RhcmdldD0wLjAyKQpwcm90X3Njb3JlIDwtIG1zY29yZTRwcm90ZmRyKHMyc19leHAsIEZGVD0wLjcsIGZkcl90YXJnZXQ9MC4wMikKCm1zY29yZV9maWx0ZXJlZCA8LSBmaWx0ZXJfbXNjb3JlKHMyc19leHAsIGNob3Nlbl9tc2NvcmUpCmZyZXFfbXNjb3JlIDwtIGZpbHRlcl9tc2NvcmVfZnJlcW9icyhzMnNfZXhwLCAwLjAxLCAwLjgsIHJtLmRlY295PUZBTFNFKQpkYXRhX2ZpbHRlcmVkX2ZkciA8LSBmaWx0ZXJfbXNjb3JlX2Zkcihtc2NvcmVfZmlsdGVyZWQsIEZGVD0wLjcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJhbGxfcHJvdGVpbl9mZHJfdGFyZ2V0PXByb3Rfc2NvcmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX292ZXJhbGxfcGVwdGlkZV9mZHJfbGltaXQ9MC4wNSkKb25seV9wcm90ZW90eXBpYyA8LSBmaWx0ZXJfcHJvdGVvdHlwaWNfcGVwdGlkZXMoZGF0YV9maWx0ZXJlZF9mZHIpCmFsbF9maWx0ZXJlZCA8LSBmaWx0ZXJfYWxsX3BlcHRpZGVzKG9ubHlfcHJvdGVvdHlwaWMpCm9ubHlfc3Ryb25nIDwtIGZpbHRlcl9vbl9tYXhfcGVwdGlkZXMoZGF0YT1hbGxfZmlsdGVyZWQsIG5fcGVwdGlkZXM9MTApCm9ubHlfbWluaW11bSA8LSBmaWx0ZXJfb25fbWluX3BlcHRpZGVzKGRhdGE9b25seV9zdHJvbmcsIG5fcGVwdGlkZXM9MykKYGBgCgojIyBXcml0ZSBvdXQgbWF0cmljZXMgb2YgdGhlIHJlc3VsdHMKCnN3YXRoMnN0YXRzIHByb3ZpZGVzIGEgY291cGxlIG9mIHdheXMgdG8gcHJpbnQgb3V0IGl0cyByZXN1bHRzLCBvbmUgaW4gYSBmb3JtYXQKc3BlY2lmaWNhbGx5IGludGVuZGVkIGZvciBNU3N0YXRzLCBhbmQgYW5vdGhlciBhcyBhIG1vcmUgY2Fub25pY2FsIG1hdHJpeCBvZgpyb3dzID0gcHJvdGVpbnMsIGNvbHVtbnMgPSBzYW1wbGVzLgoKYGBge3Igc3dhdGgyc3RhdHNfbWF0cmljZXN9CiMjIEkgdGhpbmsgdGhlc2UgbWF0cml4ZXMgYXJlIHByb2JhYmx5IHNtYXJ0ZXIgdG8gdXNlIHRoYW4gdGhlIHJhdyBvdXRtYXRyaXggZnJvbSB0cmljLgojIyBCdXQgSSBhbSBub3QgYSBmYW4gb2YgcmVyd3JpdGluZyB0aGUgc2FtcGxlIGNvbHVtbiBuYW1lcy4KbWF0cml4X3ByZWZpeCA8LSBmaWxlLnBhdGgoInJlc3VsdHMiLCAic3dhdGgyc3RhdHMiLCB2ZXIpCmlmICghZmlsZS5leGlzdHMobWF0cml4X3ByZWZpeCkpIHsKICBkaXIuY3JlYXRlKG1hdHJpeF9wcmVmaXgpCn0KcHJvdGVpbl9tYXRyaXhfYWxsIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucygKICBzMnNfZXhwLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInByb3RlaW5fYWxsLmNzdiIpKQpkaW0ocHJvdGVpbl9tYXRyaXhfYWxsKQpwcm90ZWluX21hdHJpeF9tc2NvcmUgPC0gd3JpdGVfbWF0cml4X3Byb3RlaW5zKAogIG1zY29yZV9maWx0ZXJlZCwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJwcm90ZWluX21hdHJpeF9tc2NvcmUuY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9tc2NvcmUpCnBlcHRpZGVfbWF0cml4X21zY29yZSA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgbXNjb3JlX2ZpbHRlcmVkLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInBlcHRpZGVfbWF0cml4X21zY29yZS5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X21zY29yZSkKcHJvdGVpbl9tYXRyaXhfbWluaW11bSA8LSB3cml0ZV9tYXRyaXhfcHJvdGVpbnMoCiAgb25seV9taW5pbXVtLCB3cml0ZS5jc3Y9VFJVRSwKICBmaWxlbmFtZT1maWxlLnBhdGgobWF0cml4X3ByZWZpeCwgInByb3RlaW5fbWF0cml4X21pbmltdW0uY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9taW5pbXVtKQpwZXB0aWRlX21hdHJpeF9taW5pbXVtIDwtIHdyaXRlX21hdHJpeF9wZXB0aWRlcygKICBvbmx5X21pbmltdW0sIHdyaXRlLmNzdj1UUlVFLAogIGZpbGVuYW1lPWZpbGUucGF0aChtYXRyaXhfcHJlZml4LCAicGVwdGlkZV9tYXRyaXhfbWluaW11bS5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X21pbmltdW0pCgpydF9jb3IgPC0gcGxvdF9jb3JyZWxhdGlvbl9iZXR3ZWVuX3NhbXBsZXMoCiAgb25seV9taW5pbXVtLCBjb2x1bW4udmFsdWVzPSJpbnRlbnNpdHkiLCBmdW4uYWdncmVnYXRlPXN1bSwgc2l6ZT0yKQojIyBJIGhhdmUgbm8gZWZmaW5nIGNsdWUgd2hhdCB0aGlzIHBsb3QgbWVhbnMuCnZhcmlhdGlvbiA8LSBwbG90X3ZhcmlhdGlvbihvbmx5X21pbmltdW0sIGZ1bi5hZ2dyZWdhdGU9c3VtKQoKY29scyA8LSBjb2xuYW1lcyhhbGxfZmlsdGVyZWQpCmRpc2FnZ3JlZ2F0ZWQgPC0gZGlzYWdncmVnYXRlKGFsbF9maWx0ZXJlZCwgYWxsLmNvbHVtbnM9VFJVRSkKbXNzdGF0c19pbnB1dCA8LSBjb252ZXJ0X01Tc3RhdHMoZGlzYWdncmVnYXRlZCkKYGBgCgojIyBTb21lIG5ldyBwbG90cwoKSW4gcmVzcG9uc2UgdG8gc29tZSBpbnRlcmVzdGluZyBxdWVyaWVzIGZyb20gWWFuLCBJIG1hZGUgYSBmZXcgbGl0dGxlIGZ1bmN0aW9ucwp3aGljaCBxdWVyeSBhbmQgcGxvdCBkYXRhIGZyb20gdGhlIHNjb3JlZCBkYXRhIHByb3ZpZGVkIGJ5IG9wZW5zd2F0aC9weXByb3BoZXQuCkxldCB1cyBsb29rIGF0IHRoZWlyIHJlc3VsdHMgaGVyZS4KCmBgYHtyIHRiX3B5cHJvcGhldF9wbG90c30KcHlwcm9waGV0X2Z1biA8LSBzbShleHRyYWN0X3B5cHJvcGhldF9kYXRhKAogIG1ldGFkYXRhPXBhc3RlMCgic2FtcGxlX3NoZWV0cy9NdGJfZGlhX3NhbXBsZXNfIiwgdmVyLCAiLnhsc3giKSwKICBweXByb3BoZXRfY29sdW1uPSJ0dWJlcmN1bGlzdHNjb3JlZCIpKQoKbWFzc19wbG90IDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbihweXByb3BoZXRfZnVuLCBjb2x1bW49Im1hc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHRfbmFtZXM9ImZpZ3VyZW5hbWUiKSkKbWFzc19wbG90W1sidmlvbGluIl1dCgpkZWx0YXJ0X3Bsb3RfYWxsIDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBweXByb3BoZXRfZnVuLCBjb2x1bW49ImRlbHRhX3J0IiwgZXhwdF9uYW1lcz0iZmlndXJlbmFtZSIpKQpkZWx0YXJ0X3Bsb3RfYWxsW1sidmlvbGluIl1dCgpkZWx0YXJ0X3Bsb3RfcmVhbCA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24oCiAgcHlwcm9waGV0X2Z1biwgZXhwdF9uYW1lcz0iZmlndXJlbmFtZSIsCiAgY29sdW1uPSJkZWx0YV9ydCIsIGtlZXBfZGVjb3lzPUZBTFNFKSkKZGVsdGFydF9wbG90X3JlYWxbWyJ2aW9saW4iXV0KCmRlbHRhcnRfcGxvdF9kZWNveXMgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKAogIHB5cHJvcGhldF9mdW4sIGV4cHRfbmFtZXM9ImZpZ3VyZW5hbWUiLAogIGNvbHVtbj0iZGVsdGFfcnQiLCBrZWVwX3JlYWw9RkFMU0UpKQpkZWx0YXJ0X3Bsb3RfZGVjb3lzW1sidmlvbGluIl1dCmBgYAoKIyMgTVNzdGF0cwoKbXNzdGF0cy5vcmcgc2VlbXMgdG8gcHJvdmlkZSBhIGNvbXBsZXRlIHNvbHV0aW9uIGZvciBwZXJmb3JtaW5nIHJlYXNvbmFibGUgbWV0cmljcyBvZiB0aGlzIGRhdGEuCgpJIGFtIGN1cnJlbnRseSByZWFkaW5nOiBodHRwOi8vbXNzdGF0cy5vcmcvd3AtY29udGVudC91cGxvYWRzLzIwMTcvMDEvTVNzdGF0c192My43LjNfbWFudWFsLnBkZgoKSSBtYWRlIHNvbWUgbW9kZXJhdGVseSBpbnRydXNpdmUgY2hhbmdlcyB0byBNU3N0YXRzIHRvIG1ha2UgaXQgY2xlYXJlciwgYXMgd2VsbC4KCmBgYHtyIHRiX21zc3RhdHNfcXVhbnR9CnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9zY3JhdGNoL2dpdC9NU3N0YXRzIikpCmNoZWNrcG9pbnQgPC0gcGFzdGUwKCJtc3N0YXRzX2RhdGFwcm9jZXNzLXYiLCB2ZXIsICIucmRhIikKaWYgKGZpbGUuZXhpc3RzKGNoZWNrcG9pbnQpKSB7CiAgbG9hZChmaWxlPWNoZWNrcG9pbnQpCn0gZWxzZSB7CiAgbXNzdGF0c19xdWFudCA8LSBzbShkYXRhUHJvY2Vzcyhtc3N0YXRzX2lucHV0KSkKICBzYXZlKGZpbGU9Y2hlY2twb2ludCwgbGlzdD1jKCJtc3N0YXRzX3F1YW50IikpCn0KbXNzdGF0c19wbG90cyA8LSBzbShkYXRhUHJvY2Vzc1Bsb3RzKG1zc3RhdHNfcXVhbnQsIHR5cGU9IlFDUExPVCIpKQoKbXlfbGV2ZWxzIDwtIGxldmVscyhhcy5mYWN0b3IobXNzdGF0c19pbnB1dCRjb25kaXRpb24pKQpteV9sZXZlbHMKY29tcGFyaXNvbnMgPC0gbWFrZV9zaW1wbGlmaWVkX2NvbnRyYXN0X21hdHJpeCgKICBudW1lcmF0b3JzPWMoInd0X2ZpbHRyYXRlIiwgImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIiksCiAgZGVub21pbmF0b3JzPWMoInd0X3dob2xlIiwgImRlbHRhX3dob2xlIiwgInd0X2ZpbHRyYXRlIiwgInd0X3dob2xlIikpCgptc3N0YXRzX3Jlc3VsdHMgPC0gbGlzdCgpCmNoZWNrcG9pbnQgPC0gcGFzdGUwKCJtc3N0YXRzX2dyb3VwLXYiLCB2ZXIsICIucmRhIikKaWYgKGZpbGUuZXhpc3RzKGNoZWNrcG9pbnQpKSB7CiAgbG9hZChmaWxlPWNoZWNrcG9pbnQpCn0gZWxzZSB7CiAgZm9yIChjIGluIDE6bGVuZ3RoKHJvd25hbWVzKGNvbXBhcmlzb25zKSkpIHsKICAgIG5hbWUgPC0gcm93bmFtZXMoY29tcGFyaXNvbnMpW2NdCiAgICBtZXNzYWdlKCJTdGFydGluZyAiLCBuYW1lKQogICAgY29tcCA8LSBjb21wYXJpc29uc1tjLCBdCiAgICBjb21wIDwtIHQoYXMubWF0cml4KGNvbXApKQogICAgcm93bmFtZXMoY29tcCkgPC0gbmFtZQogICAgbXNzdGF0c19yZXN1bHRzW1tuYW1lXV0gPC0gc20oTVNzdGF0czo6Z3JvdXBDb21wYXJpc29uKGNvbnRyYXN0Lm1hdHJpeD1jb21wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bXNzdGF0c19xdWFudCkpCiAgICBtZXNzYWdlKCJGaW5pc2hlZCAiLCBuYW1lKQogIH0KICBzYXZlKGZpbGU9Y2hlY2twb2ludCwgbGlzdD1jKCJtc3N0YXRzX3Jlc3VsdHMiKSkKfQpgYGAKCiMjIyBQL1BFIHByb3RlaW4gUUMgcGxvdHMgZm9yIFlhbgoKWWFuIGFza2VkIGZvciB0aGUgcC9wZSBwcm90ZWluIHFjIHBsb3RzLiBvay4gIEkgY2hhbmdlZCB0aGUgZGF0YVByb2Nlc3NQbG90cyB0bwpyZXR1cm4gc29tZXRoaW5nIHVzZWZ1bCwgc28gdGhhdCBzaG91bGQgYmUgcG9zc2libGUgbm93LgoKYGBge3IgcGV9CnBlX2dlbmVzIDwtIHJlYWQudGFibGUoInJlZmVyZW5jZS9hbm5vdGF0ZWRfcGVfZ2VuZXMudHh0IilbWzFdXQoKIyMgVW5mb3J0dW5hdGVseSwgdGhlIG5hbWVzIGRpZCBub3QgZ2V0IHNldCBpbiBteSBjaGFuZ2VkIHZlcnNpb24gb2YgZGF0YVByb2Nlc3NQbG90cy4uLgpwbG90bHN0IDwtIG1zc3RhdHNfcGxvdHMkUUNQTE9UCmF2YWlsYWJsZV9wbG90cyA8LSBnc3ViKHBhdHRlcm49Il4xLyIsIHJlcGxhY2VtZW50PSIiLAogICAgICAgICAgICAgICAgICAgICAgICB4PWxldmVscyhtc3N0YXRzX3F1YW50JFByb2Nlc3NlZERhdGEkUFJPVEVJTikpCm5hbWVzKHBsb3Rsc3QpIDwtIGF2YWlsYWJsZV9wbG90cwoKcGVfaW5fYXZhaWxfaWR4IDwtIHBlX2dlbmVzICVpbiUgYXZhaWxhYmxlX3Bsb3RzCnBlX2luX2F2YWlsIDwtIHBlX2dlbmVzW3BlX2luX2F2YWlsX2lkeF0KcGVfcGxvdHMgPC0gcGxvdGxzdFtwZV9pbl9hdmFpbF0KcGRmKGZpbGU9InBlX3FjX3Bsb3RzLnBkZiIpCmZvciAocCBpbiAxOmxlbmd0aChwZV9wbG90cykpIHsKICBwbG90KHBlX3Bsb3RzW1twXV0pCn0KZGV2Lm9mZigpCmxlbmd0aChwZV9wbG90cykKYGBgCgojIENyZWF0ZSBocGdsdG9vbHMgZXhwcmVzc2lvbnNldAoKU2luY2UgSSBhbSBub3QgY2VydGFpbiBJIHVuZGVyc3RhbmQgdGhlc2UgZGF0YSwgSSB3aWxsIHRha2UgdGhlIGludGVuc2l0aWVzIGZyb20KU1dBVEgyc3RhdHMsIG1ldGFkYXRhLCBhbmQgYW5ub3RhdGlvbiBkYXRhOyAgYXR0ZW1wdCB0byBjcmVhdGUgYSAnbm9ybWFsJwpleHByZXNzaW9uc2V0OyBwb2tlIGF0IGl0IHRvIHNlZSB3aGF0IEkgY2FuIGxlYXJuLgoKIyMgTWFzc2FnaW5nIHRoZSBtZXRhZGF0YQoKSSB3YW50IHRvIHVzZSB0aGUgc2FtZSBtZXRhZGF0YSBhcyB3ZXJlIHVzZWQgZm9yIE1Tc3RhdHMuICBJdCBoYXMgYSBmZXcKaW1wb3J0YW50IGRpZmZlcmVuY2VzIGZyb20gdGhlIHJlcXVpcmVtZW50cyBvZiBocGdsdG9vbHM6IHByZXR0eSBtdWNoIG9ubHkgdGhhdApJIGRvIG5vdCBhbGxvdyByb3duYW1lcy9zYW1wbGVJRHMgdG8gc3RhcnQgd2l0aCBhIG51bWJlci4KCiMjIE1hc3NhZ2luZyB0aGUgaW50ZW5zaXR5IG1hdHJpeAoKSSBkbyBub3Qgd2FudCB0aGUgXDEgYmVmb3JlIHRoZSBwcm90ZWluIG5hbWVzLCBJIGFscmVhZHkgbWVyZ2VkIHRoZW0gaW50byBvbmUKZW50cnkgcGVyIGdlbmUgdmlhIFNXQVRIMnN0YXRzLgoKYGBge3IgdGJfcHJvdGVpbl9tYXRyaXh9CnByb3RfbXRyeCA8LSByZWFkLmNzdihmaWxlLnBhdGgoInJlc3VsdHMiLCAic3dhdGgyc3RhdHMiLCB2ZXIsICJwcm90ZWluX21hdHJpeF9taW5pbXVtLmNzdiIpKQpyb3duYW1lcyhwcm90X210cngpIDwtIGdzdWIocGF0dGVybj0iXjFcXC8iLCByZXBsYWNlbWVudD0iIiwgeD1wcm90X210cnhbWyJwcm90ZWlubmFtZSJdXSkKcHJvdF9tdHJ4IDwtIHByb3RfbXRyeFssIC0xXQojIyBJbXBvcnRhbnQgcXVlc3Rpb246IERpZCBTV0FUSDJzdGF0cyByZW9yZGVyIG15IGRhdGE/CmNvbG5hbWVzKHByb3RfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJeKC4qKSgyMDE4LiopJCIsIHJlcGxhY2VtZW50PSJzXFwyIiwgeD1jb2xuYW1lcyhwcm90X210cngpKQpgYGAKCiMjIE1lcmdlIHRoZSBwaWVjZXMKCk5vdyB3ZSBzaG91bGQgaGF2ZSBzdWZmaWNpZW50IHBpZWNlcyB0byBtYWtlIGFuIGV4cHJlc3Npb25zZXQuCgpXaGlsZSBoZXJlLCBJIHdpbGwgYWxzbyBzcGxpdCB0aGUgZGF0YSBpbnRvIGEgY2YgYW5kIHdob2xlLWNlbGwgcGFpciBvZiBkYXRhIHN0cnVjdHVyZXMuCgpgYGB7ciB0Yl9leHB0fQojIyBEcm9wIHRoZSBtZXRhZGF0YSBub3QgaW4gdGhlIHByb3RlaW4gbWF0cml4OgojIyBBbmQgZW5zdXJlIHRoYXQgdGhleSBhcmUgdGhlIHNhbWUgb3JkZXIuCnJlb3JkZXJlZCA8LSBjb2xuYW1lcyhwcm90X210cngpCm1ldGFkYXRhIDwtIHNhbXBsZV9hbm5vdFtyZW9yZGVyZWQsIF0KcHJvdGVpbl9leHB0IDwtIHNtKGNyZWF0ZV9leHB0KG1ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRfZGF0YWZyYW1lPXByb3RfbXRyeCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1tdGJfYW5ub3RhdGlvbnMpKQoKd2hvbGVfZXhwdCA8LSBzdWJzZXRfZXhwdChwcm90ZWluX2V4cHQsIHN1YnNldD0iY29sbGVjdGlvbnR5cGU9PSd3aG9sZSciKQpjZl9leHB0IDwtIHN1YnNldF9leHB0KHByb3RlaW5fZXhwdCwgc3Vic2V0PSJjb2xsZWN0aW9udHlwZT09J2ZpbHRyYXRlJyIpCnByb3RlaW5fd3JpdGUgPC0gd3JpdGVfZXhwdChwcm90ZWluX2V4cHQsIGV4cHRfbmFtZXM9ImZpZ3VyZW5hbWUiLCBwbG90X2xlZ2VuZD1GQUxTRSwgdmlvbGluPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL3Byb3RlaW5fZXhwdDItdiIsIHZlciwgIi54bHN4IikpCmBgYAoKIyMgTWV0cmljcyBvZiB0aGUgZnVsbCBkYXRhIHNldAoKR2VuZXJhdGUgc29tZSBtZXRyaWNzIG9mIHRoZSBmdWxsIGRhdGEgc2V0LCBsYXRlciB0aGUgc2FtZSB0aGluZ3Mgd2lsbCBiZQpwZXJmb3JtZWQgdXNpbmcgdGhlIGRhdGEgc3Vic2V0cy4gIFRoZXJlIGlzIGEgd2VpcmQgY2F2ZWF0OiBzdmEgZmFpbHMgdW5kZXIgc29tZQpzdHJhbmdlIGNpcmN1bXN0YW5jZXMgZm9yIHRoaXMgZGF0YS4gIEl0IHNlZW1zIHRoYXQgaWYgdGhlIGRhdGEgaXMgY3BtbWVkLCB0aGVuCnN2YSBzZWVzIHRoZSByZXN1bHRpbmcgbWF0cml4IGFzIGNvbnRhaW5pbmcgc2luZ3VsYXIgdmFsdWVzLiAgSSBhbSBndWVzc2luZyB0aGF0CnRoaXMgbWVhbnMgdGhhdCB0aGVyZSBhcmUgYSBidW5jaCBvZiBsb3cgdmFsdWVzIGluIHRoZSBmaWx0cmF0ZSBkYXRhIHdoaWNoLCB3aGVuCmNwbShkYXRhKSBpcyBwZXJmb3JtZWQgZ2V0IGRyb3BwZWQgdG8gbmVhciAwIGFuZCB0aGVyZWZvcmUgdHJpcCB1cCBzdmEuICBUaGVyZQphcmUgdHdvIGxpa2VseSB3YXlzIGFyb3VuZCB0aGlzOgoKMS4gIERvIG5vdCBjcG0gdGhlIGRhdGEuCjIuICBGaWx0ZXIgdGhlIGRhdGEgbW9yZSBhZ2dyZXNzaXZlbHkgc28gdGhhdCB0aGVyZSBhcmUgbm8gemVyby12YWx1ZXMgYWZ0ZXIgY3BtKCkuCgpgYGB7ciB0Yl9wcm90ZWluX21ldHJpY3MsIGZpZy5zaG93PSdoaWRlJ30KcHJvdGVpbl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MocHJvdGVpbl9leHB0KSkKcHJvdGVpbl9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KHByb3RlaW5fZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQpwcm90ZWluX25vcm1fbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKHByb3RlaW5fbm9ybSkpCnByb3RlaW5fZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdChwcm90ZWluX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0iZnN2YSIsIGZpbHRlcj1UUlVFKSkKcHJvdGVpbl9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhwcm90ZWluX2ZzdmEpKQpgYGAKCiMjIE1ldHJpY3Mgb2YgdGhlIHdob2xlLWNlbGwgZGF0YSBzZXQKCkhlcmUgYXJlIHNvbWUgb2YgdGhlIHByb21pc2VkIHN1YnNldCBkYXRhLgoKYGBge3IgdGJfd2hvbGVfbWV0cmljcywgZmlnLnNob3c9J2hpZGUnfQp3aG9sZV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Mod2hvbGVfZXhwdCkpCndob2xlX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQod2hvbGVfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKSkKd2hvbGVfbm9ybV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Mod2hvbGVfbm9ybSkpCndob2xlX2ZzdmEgPC0gc20obm9ybWFsaXplX2V4cHQod2hvbGVfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0iZnN2YSIsIGZpbHRlcj1UUlVFKSkKd2hvbGVfZnN2YV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3Mod2hvbGVfZnN2YSkpCmBgYAoKIyMgVmFyaWFuY2UgcGFydGl0aW9uCgpUaGlzIGlzIGEgcG90ZW50aWFsIGFyZ3VtZW50IGFnYWluc3QgaW5jbHVkaW5nIG9ubHkgdGhlIG5ld2VzdCB0ZWNobmljYWwKcmVwbGljYXRlIG9mIHRoZSBkYXRhOyBhcyB3aGVuIGFsbCB0aGUgdGVjaG5pY2FscyB3ZXJlIGluY2x1ZGVkLCB0aGVzZSBtZXRyaWNzCmxvb2tlZCBtdWNoIG1vcmUgc2Vuc2libGUuCgpgYGB7ciB0Yl92YXJpYW5jZX0Kd2hvbGVfdmFycGFydCA8LSB2YXJwYXJ0KHdob2xlX2V4cHQpCndob2xlX3ZhcnBhcnQkcGFydGl0aW9uX3Bsb3QKd2hvbGVfY3YgPC0gcGxvdF92YXJpYW5jZV9jb2VmZmljaWVudHMocHJvdGVpbl9leHB0KQp3aG9sZV9jdiRkaXNwCiMjdGJfYmF0Y2hfY3YgPC0gcGxvdF92YXJpYW5jZV9jb2VmZmljaWVudHModGJfcHJvdGVpbl9leHB0LCB4X2F4aXM9ImJhdGNoIikKIyN0Yl9iYXRjaF9jdiRkaXNwCmdlbm90eXBlX2N2IDwtIHBsb3RfdmFyaWFuY2VfY29lZmZpY2llbnRzKHByb3RlaW5fZXhwdCwgeF9heGlzPSJnZW5vdHlwZSIpCiMjZ2Vub3R5cGVfY3YkZGlzcAojI3RiX3ByZXBfY3YgPC0gcGxvdF92YXJpYW5jZV9jb2VmZmljaWVudHModGJfcHJvdGVpbl9leHB0LCB4X2F4aXM9InByZXBkYXRlIikKIyN0Yl9wcmVwX2N2JGRpc3AKCnZpbyA8LSBwbG90X2JveHBsb3QocHJvdGVpbl9leHB0LCB2aW9saW49VFJVRSkKdmlvCmBgYAoKIyMgTWV0cmljcyBvZiB0aGUgZmlsdHJhdGUgZGF0YSBzZXQKCk9uY2UgYWdhaW4sIGhlcmUgd2UgaGF2ZSBtZXRyaWNzIG9mIHRoZSBzdWJzZXQgZGF0YTsgdGhpcyB0aW1lIG9mIGZpbHRyYXRlIGRhdGEuCgpgYGB7ciB0Yl9jZl9tZXRyaWNzLCBmaWcuc2hvdz0naGlkZSd9CmNmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjZl9leHB0KSkKY2Zfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChjZl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpKQpjZl9ub3JtX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjZl9ub3JtKSkKY2ZfZnN2YSA8LSBzbShub3JtYWxpemVfZXhwdChjZl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJmc3ZhIiwgZmlsdGVyPVRSVUUpKQpjZl9mc3ZhX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjZl9mc3ZhKSkKCiMjIEdldCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmaWx0cmF0ZSBkYXRhCmNmX2ZpbHQgPC0gbm9ybWFsaXplX2V4cHQoY2ZfZXhwdCwgZmlsdGVyPVRSVUUpCnNhbXBsZV9zdW1tYXJ5IDwtIHN1bW1hcnkoZXhwcnMoY2ZfZmlsdCkpCnNhbXBsZV9zdW1tYXJ5CgpjZl9yZW1haW5pbmcgPC0gbm9ybWFsaXplX2V4cHQoY2ZfZXhwdCwgZmlsdGVyPSJjYmNiIiwgdGhyZXNoPTEwMCkKcGxvdF9kZW5zaXR5KGNmX3JlbWFpbmluZykkcGxvdAprZWVwZXJfaWRzIDwtIHJvd25hbWVzKGV4cHJzKGNmX3JlbWFpbmluZykpCmNmX3JlbWFpbmluZyA8LSBub3JtYWxpemVfZXhwdChjZl9leHB0LCBmaWx0ZXI9ImNiY2IiLCB0aHJlc2g9MTAwMCkKcGxvdF9kZW5zaXR5KGNmX3JlbWFpbmluZykkcGxvdApgYGAKCiMjIyBTb21ldGhpbmcgZnVuIGZvciBOYWppYgoKYGBge3IgcGNhM2R9CnBjYTNkIDwtIHBsb3RfcGNhKHByb3RlaW5fZnN2YSkKcGNhM2QkcGxvdApzaWxseSA8LSBtYWtlXzNkX3BjYShwY2EzZCkKc2lsbHkkcGxvdApgYGAKCiMjIFBsb3Qgc29tZSBtZXRyaWNzCgpJbiB0aGUgcHJldmlvdXMgYmxvY2tzLCBJIGdlbmVyYXRlZCB0aGUgbWV0cmljczsgaW4gdGhpcyBibG9jayBJIHdpbGwgcHJpbnQgdGhlbQp3aXRoIHRoZSBhc3N1bXB0aW9uIHRoYXQgc29tZSBvZiB0aGVtIHdpbGwgZW5kIHVwIGJlaW5nIGluY2x1ZGVkIGluIHdoYXRldmVyCnB1YmxpY2F0aW9uIGNvbWVzIGZyb20gdGhpcyB3b3JrOyB3aXRoIHRoYXQgaW4gbWluZCBJIHNob3VsZCBwcm9iYWJseSBjaGFuZ2UKdGhpcyB0byBzdmEgb3IgcGRmIG9yIHNvbWV0aGluZyBub3QgcG5nLgoKYGBge3IgdGJfcHJpbnRfbWV0cmljc30KcHAoaW1hZ2U9cHJvdGVpbl9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX2xpYnNpemUucGRmIikpKQojIyBJdCBzZWVtcyB0byBtZSB0aGF0IHRoZSBzY2FsZSBvZiB0aGUgZGF0YSBpcyBhbGwgd2l0aGluIGFuIG9yZGVyIG9mIG1hZ25pdHVkZSBvciB0d28uCiMjIEkgY2Fubm90IGdldCB1c2VkIHRvIHRoZXNlIGFic3VyZGx5IGxhcmdlIG51bWJlcnMgdGhvdWdoLgpwcChpbWFnZT1wcm90ZWluX25vcm1fbWV0cmljcyRwY2FwbG90LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9ub3JtX3BjYS5wZGYiKSkpCiMjIFRoZXJlIGFwcGVhcnMgdG8gYmUgYSBuaWNlIHNwbGl0IGluIHRoZSBkYXRhLCBob3dldmVyIHRoZSB1bi1hc3NheWFibGUgYmF0Y2gKIyMgZWZmZWN0IGlzIGEgcHJvYmxlbS4KcHAoaW1hZ2U9cHJvdGVpbl9mc3ZhX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfZnN2YV9wY2EucGRmZyIpKSkKIyMgZnN2YSBzZWVtcyB0byBnZXQgc29tZSBoYW5kbGUgb24gdGhlIGRhdGEsIGJ1dCBJIGRvbid0IHRoaW5rIHdlIHNob3VsZCByZWx5CiMjIHVwb24gaXQuCnBwKGltYWdlPXByb3RlaW5fbm9ybV9tZXRyaWNzJGNvcmhlYXQsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX25vcm1fY29yaGVhdC5wZGYiKSkpCiMjIE9uY2UgYWdhaW4sIHRoZSB3aG9sZS1jZWxsL2N1bHR1cmUtZmlsdHJhdGUgc3BsaXQgaXMgdmVyeSBsYXJnZS4KcHAoaW1hZ2U9cHJvdGVpbl9tZXRyaWNzJGRlbnNpdHksCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3Jhd19kZW5zaXR5LnBkZiIpKSkKIyMgVGhlcmUgYXJlIHR3byBvYnZpb3VzIGRpc3RyaWJ1dGlvbnMgaW4gdGhlIGRhdGEsIG9uY2UgYWdhaW4gc3BsaXQgYmV0d2VlbiB0eXBlcy4KcHAoaW1hZ2U9cHJvdGVpbl9tZXRyaWNzJGJveHBsb3QsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX2JveHBsb3QucGRmIikpKQojIyBUaGlzIHJlY2FwaXR1bGF0ZXMgdGhlIHByZXZpb3VzIHBsb3QuCgpwcChpbWFnZT13aG9sZV9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX3dob2xlX2xpYnNpemUucGRmIikpKQpwcChpbWFnZT13aG9sZV9ub3JtX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfbm9ybV9wY2EucGRmIikpKQpwcChpbWFnZT13aG9sZV9mc3ZhX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfZnN2YV9wY2EucGRmIikpKQpwcChpbWFnZT13aG9sZV9ub3JtX21ldHJpY3MkY29yaGVhdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfbm9ybV9jb3JoZWF0LnBkZiIpKSkKcHAoaW1hZ2U9d2hvbGVfbWV0cmljcyRkZW5zaXR5LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl93aG9sZV9yYXdfZGVuc2l0eS5wZGYiKSkpCnBwKGltYWdlPXdob2xlX21ldHJpY3MkYm94cGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfd2hvbGVfYm94cGxvdC5wZGYiKSkpCgpwcChpbWFnZT1jZl9tZXRyaWNzJGxpYnNpemUsCiAgIGZpbGU9ZmlsZS5wYXRoKCJpbWFnZXMiLCBwYXN0ZTAodmVyLCAiX2xpYnNpemUucGRmIikpKQpwcChpbWFnZT1jZl9ub3JtX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfbm9ybV9wY2EucGRmIikpKQpwcChpbWFnZT1jZl9mc3ZhX21ldHJpY3MkcGNhcGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfZnN2YV9wY2EucGRmIikpKQpwcChpbWFnZT1jZl9ub3JtX21ldHJpY3MkY29yaGVhdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfbm9ybV9jb3JoZWF0LnBkZiIpKSkKcHAoaW1hZ2U9Y2ZfbWV0cmljcyRkZW5zaXR5LAogICBmaWxlPWZpbGUucGF0aCgiaW1hZ2VzIiwgcGFzdGUwKHZlciwgIl9yYXdfZGVuc2l0eS5wZGYiKSkpCnBwKGltYWdlPWNmX21ldHJpY3MkYm94cGxvdCwKICAgZmlsZT1maWxlLnBhdGgoImltYWdlcyIsIHBhc3RlMCh2ZXIsICJfYm94cGxvdC5wZGYiKSkpCmBgYAoKIyBQZXJmb3JtIGhwZ2x0b29scyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNlcwoKRWFybGllciBNU3N0YXRzIHdhcyB1c2VkIHRvIGNvbnRyYXN0IHRoZSB2YXJpb3VzIGNvbmRpdGlvbnMgaW4gdGhpcyBkYXRhLiAgSW4KdGhpcyBibG9jayB0aGUgc2FtZSB3aWxsIGJlIHBlcmZvcm1lZCB1c2luZyB0aGUgbGltbWEvZGVzZXEvZWRnZXIvZWJzZXEvYmFzaWMKbWV0aG9kcy4gIEFzIGFuIGFzaWRlLCBydW5uaW5nIGFsbCBvZiB0aGVzZSBtZXRob2RzIGluIHNlcmlhbCB0YWtlcyB+IDEvNXRoIHRoZQp0aW1lIG9mIHJ1bm5pbmcgYW55IG9uZSBzdGVwIG9mIE1Tc3RhdHMuCgojIyBJZGVhIGZyb20gVm9sa2VyCgpHaXZlbiB0aGUgaW5pdGlhbCBwYWlyd2lzZSBkYXRhLCBsb29rIGF0IHd0IGVkZ2VSIHJlc3VsdHMgcmF0aW8KZmlsdHJhdGUvY3VsdHVyZTsgdGhlbiBzZXQgYSBjdXRvZmYgYXMgbG9nMmZjIDw9IDAuNzUuICBQcm90ZWlucyB3aGljaCBzdXJ2aXZlCnRoaXMgY3V0b2ZmIGFyZSB0aGVuIHVzZWQgaW4gdGhlIHJhdGlvIG9mIHJhdGlvcyBhbmQgYW5hbHlzZXMgb2YgbXV0YW50L3d0LgoKVGhlIHN1cnZpdm9ycyBvZiB0aGlzIGluaXRpYWwgY3V0b2ZmIGlzIHRoZSBzZXQgb2Ygc2VjcmV0ZWQgcHJvdGVpbnMuCkNvbXBhcmUgdGhpcyBzZXQgd2l0aCB0aGUgc2V0IG9mIGtub3duIHNlY3JldGVkIHByb3RlaW5zIGZyb20gb3RoZXIgcGFwZXJzCihDb3gpLiAgQWxzbyBDb2xsaW5zLCBBYmVzb2wgKGxpa2VseSBzYW1lIGFzIHRoZSBzeW50aGV0aWMgTXRiIGxpYnJhcnkpLgoKU2VwYXJhdGUsIHNpbXVsdGFuZW91cyBmaWx0ZXI6ICBMb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGN1bHR1cmUgZmlsdHJhdGUKZGF0YSBhbmQgZmlsdGVyIG91dCB0aGUgKHJlbGF0aXZlbHkpIGxvdy1pbnRlbnNpdHkgYnVtcC4gIFRoZW4gdGFrZSB0aGUKc3Vydml2aW5nIHNldCBhbmQgcGVyZm9ybSBhbGwgYW5hbHlzZXMgd2l0aCBpdC4gIEluIHRoZW9yeSwgdGhlc2UgdHdvIGZpbHRlcgptZXRob2RzIHNob3VsZCBnZXQgdXMgdG8gYSBzaW1pbGFyIHBsYWNlLgoKIyMgbGZjIGN1dG9mZiBjdXRvZmYKCkFzIG1lbnRpb25lZCBiZWxvdywgVm9sa2VyIGhhZCBhbiBpbnRlcmVzdGluZyBjdXRvZmYgc3VnZ2VzdGlvbjoga2VlcCBvbmx5IHRob3NlCndpdGggbGZjID49IDAuNzUgZmlsdHJhdGUvd2hvbGUKCmBgYHtyIGxmY19maWx0ZXJ9CnRlc3QgPC0gZWRnZXJfcGFpcndpc2UocHJvdGVpbl9leHB0KQpxdWVyeSA8LSB0ZXN0W1siYWxsX3RhYmxlcyJdXVtbInd0X3dob2xlX3ZzX3d0X2ZpbHRyYXRlIl1dCiMjIFRoaXMgb25lIG9mIGNvdXJzZSBwdXQgdGhlIGRlc2lyZWQgZmFjdG9yIG9uIHRoZSBib3R0b20sIHNvIEkgd2lsbCBsb29rIGZvciBsZmMgPD0gLTAuNzUKbGZjX2tlZXBlcl9pZHggPC0gcXVlcnlbWyJsb2dGQyJdXSA8PSAtMC43NQpsZmNfa2VlcGVyX2lkcyA8LSByb3duYW1lcyhxdWVyeVtsZmNfa2VlcGVyX2lkeCwgXSkKCnRlc3RfdmVubl9sc3QgPC0gbGlzdCgiY3V0b2ZmIiA9IGtlZXBlcl9pZHMsCiAgICAgICAgICAgICAgICAgICAgICAibGZjIiA9IGxmY19rZWVwZXJfaWRzKQp0ZXN0X3Zlbm4gPC0gVmVubmVyYWJsZTo6VmVubihTZXRzPXRlc3RfdmVubl9sc3QpClZlbm5lcmFibGU6OnBsb3QodGVzdF92ZW5uKQpgYGAKCmBgYHtyIGNvbXByZXNzZWRfZGUsIGZpZy5zaG93PSJoaWRlIn0KIyMgSGVyZSBJIHBlcmZvcm0gdGhlIHNhbWUgY3V0b2ZmIGFzIHNob3duIGluIHRoZSBkZW5zaXR5IHBsb3RzIGFib3ZlLgppbnB1dCA8LSBleGNsdWRlX2dlbmVzX2V4cHQocHJvdGVpbl9leHB0LCBtZXRob2Q9ImtlZXAiLCBpZHM9a2VlcGVyX2lkcykKbGZjX2lucHV0IDwtIGV4Y2x1ZGVfZ2VuZXNfZXhwdChwcm90ZWluX2V4cHQsIG1ldGhvZD0ia2VlcCIsIGlkcz1sZmNfa2VlcGVyX2lkcykKCmZpbHRlcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoCiAgaW5wdXQsIG1vZGVsX2JhdGNoPUZBTFNFLCBmb3JjZT1UUlVFLAogIGRvX2Vic2VxPVRSVUUsIHBhcmFsbGVsPUZBTFNFKSkKbGZjX2ZpbHRlcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoCiAgbGZjX2lucHV0LCBtb2RlbF9iYXRjaD1GQUxTRSwgZm9yY2U9VFJVRSwKICBkb19lYnNlcT1UUlVFLCBwYXJhbGxlbD1GQUxTRSkpCiMjIEludGVyZXN0aW5nLCB3aGVuIEkgcnVuIHRoaXMgaW50ZXJhY3RpdmVseSwgbm8gZXJyb3IsIGJ1dCBpdCBhcHBlYXJzIHRoYXQgdGhlIHJlcG9ydAojIyBoYWQgcHJvYmxlbXMgd2l0aCBpdC4KZXh0cmEgPC0gImRlbHRhX2Nmd2hvbGVfdnNfd3RfY2Z3aG9sZT0oZGVsdGFfZmlsdHJhdGUtZGVsdGFfd2hvbGUpLSh3dF9maWx0cmF0ZS13dF93aG9sZSkiCmV4dHJhX2ZpbHRlcl9kZSA8LSBzbShhbGxfcGFpcndpc2UoCiAgaW5wdXQsIG1vZGVsX2JhdGNoPUZBTFNFLCBmb3JjZT1UUlVFLAogIGRvX2Vic2VxPVRSVUUsIHBhcmFsbGVsPUZBTFNFLAogIGV4dHJhX2NvbnRyYXN0cz1leHRyYSkpCmV4dHJhX2xmY19maWx0ZXJfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKAogIGxmY19pbnB1dCwgbW9kZWxfYmF0Y2g9RkFMU0UsIGZvcmNlPVRSVUUsCiAgZG9fZWJzZXE9VFJVRSwgcGFyYWxsZWw9RkFMU0UsCiAgZXh0cmFfY29udHJhc3RzPWV4dHJhKSkKCmV4dHJhX2tlZXBlcnMgPC0gbGlzdCgKICAid3RfY2Z3aG9sZSIgPSBjKCJ3dF9maWx0cmF0ZSIsICJ3dF93aG9sZSIpLAogICJkZWx0YV9jZndob2xlIiA9IGMoImRlbHRhX2ZpbHRyYXRlIiwgImRlbHRhX3dob2xlIiksCiAgIndob2xlX2RlbHRhd3QiID0gYygiZGVsdGFfd2hvbGUiLCAid3Rfd2hvbGUiKSwKICAiY2ZfZGVsdGF3dCIgPSBjKCJkZWx0YV9maWx0cmF0ZSIsICJkZWx0YV93aG9sZSIpLAogICJyb2ZyIiA9IGMoImRlbHRhX2Nmd2hvbGUiLCAid3RfY2Z3aG9sZSIpKQpleHRyYV9maWx0ZXJfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGV4dHJhX2ZpbHRlcl9kZSwKICBrZWVwZXJzPWV4dHJhX2tlZXBlcnMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9jb21iaW5lZF9maWx0ZXJfY29udHJhc3RzLXYiLCB2ZXIsICIueGxzeCIpKSkKZXh0cmFfbGZjX2ZpbHRlcl90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgZXh0cmFfbGZjX2ZpbHRlcl9kZSwKICBrZWVwZXJzPWV4dHJhX2tlZXBlcnMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9jb21iaW5lZF9sZmNmaWx0ZXJfY29udHJhc3RzLXYiLCB2ZXIsICIueGxzeCIpKSkKCmV4dHJhX2ZpbHRlcl9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBleHRyYV9maWx0ZXJfdGFibGVzLCBhY2NvcmRpbmdfdG89ImVkZ2VyIiwKICBsZmM9MC43NSwKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3NpZ19maWx0ZXJfY29udHJhc3RzLXYiLCB2ZXIsICIueGxzeCIpKSkKZXh0cmFfbGZjX2ZpbHRlcl9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBleHRyYV9sZmNfZmlsdGVyX3RhYmxlcywgYWNjb3JkaW5nX3RvPSJlZGdlciIsCiAgbGZjPTAuNzUsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9zaWdfbGZjZmlsdGVyX2NvbnRyYXN0cy12IiwgdmVyLCAiLnhsc3giKSkpCmBgYAoKYGBge3IgcGxheV9kZSwgZXZhbD1GQUxTRX0KdGVzdF9saW1tYSA8LSBzbShsaW1tYV9wYWlyd2lzZShpbnB1dCwgbW9kZWxfYmF0Y2g9RkFMU0UsIGV4dHJhX2NvbnRyYXN0cz1leHRyYSkpCnRlc3RfZWRnZXIgPC0gc20oZWRnZXJfcGFpcndpc2UoaW5wdXQsIG1vZGVsX2JhdGNoPUZBTFNFLCBleHRyYV9jb250cmFzdHM9ZXh0cmEpKQp0ZXN0X2Rlc2VxIDwtIHNtKGRlc2VxX3BhaXJ3aXNlKGlucHV0LCBtb2RlbF9iYXRjaD1GQUxTRSwgZXh0cmFfY29udHJhc3RzPWV4dHJhLCBmb3JjZT1UUlVFKSkKdGVzdF9iYXNpYyA8LSBzbShiYXNpY19wYWlyd2lzZShpbnB1dCwgbW9kZWxfYmF0Y2g9RkFMU0UsIGV4dHJhX2NvbnRyYXN0cz1leHRyYSwgZm9yY2U9VFJVRSkpCnRlc3RfZWJzZXEgPC0gc20oZWJzZXFfcGFpcndpc2UoaW5wdXQsIG1vZGVsX2JhdGNoPUZBTFNFLCBleHRyYV9jb250cmFzdHM9ZXh0cmEsIGZvcmNlPVRSVUUpKQpgYGAKCiMjIyBTaG93IGEgZmV3IG1ldHJpY3MgZnJvbSB0aGUgaHBnbHRvb2xzIHBhaXJ3aXNlIGNvbXBhcmlzb25zCgpgYGB7ciBzaG93X2RlX3Rlc3Rpbmd9CnBwKGZpbGU9ImltYWdlcy9kZV9oZWF0LnBuZyIsIGltYWdlPWV4dHJhX2xmY19maWx0ZXJfZGUkY29tcGFyaXNvbiRoZWF0KQpleHRyYV9sZmNfZmlsdGVyX2RlJGNvbXBhcmlzb24kaGVhdApgYGAKCiMgRm9yIGVhY2ggbXNzdGF0cyBydW4sIGRvIGEgREUgdGFibGUKCiMjIHd0X2NmIHZzIHd0X3dob2xlCgpgYGB7ciB0Yl9jb21iaW5lX3d0Y2Zfd3R3aG9sZSwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgInd0Y2ZfdnNfd3R3aG9sZSIgPSBjKCJ3dF9maWx0cmF0ZSIsICJ3dF93aG9sZSIpKQptc19zZXRfbmFtZSA8LSAid3RfZmlsdHJhdGVfdnNfd3Rfd2hvbGUiCm1zc3RhdHNfcmVzdWx0IDwtIG1zc3RhdHNfcmVzdWx0c1tbbXNfc2V0X25hbWVdXVtbIkNvbXBhcmlzb25SZXN1bHQiXV0KZHJvcHBlcnMgPC0gYygidW5kZWZpbmVkIikKbmFtZXMoZHJvcHBlcnMpIDwtICJsb2cyZmMiCiMjIE1ha2Ugc3VyZSB0byBzZXQgdGhlIHJvd25hbWVzIHNvIGl0IHdpbGwgbWVyZ2UgaW50byB0aGUgZXhjZWwgZmlsZS4Kcm93bmFtZXMobXNzdGF0c19yZXN1bHQpIDwtIG1zc3RhdHNfcmVzdWx0W1siUHJvdGVpbiJdXQp3dGNmX25vYmF0Y2hfd3R3aG9sZV90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgZXh0cmFfbGZjX2ZpbHRlcl9kZSwga2VlcGVycz1rZWVwZXJzLCBleHRyYV9hbm5vdD1tc3N0YXRzX3Jlc3VsdCwKICBleGNsdWRlcz1kcm9wcGVycywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL3d0Y2ZfdnNfd3R3aG9sZV9ub2JhdGNoX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCmNvbXBfdGFibGUgPC0gd3RjZl9ub2JhdGNoX3d0d2hvbGVfdGFibGVzJGRhdGFbW25hbWVzKGtlZXBlcnMpXV0KY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZGVzZXFfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChjb21wX3RhYmxlJGxvZzJmYywgY29tcF90YWJsZSRsaW1tYV9sb2dmYywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KGNvbXBfdGFibGUkbG9nMmZjLCBjb21wX3RhYmxlJGVic2VxX2xvZ2ZjLCBtZXRob2Q9InNwZWFybWFuIikKd3RjZl9ub2JhdGNoX3d0d2hvbGVfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgd3RjZl9ub2JhdGNoX3d0d2hvbGVfdGFibGVzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvd3RjZl92c193dHdob2xlX25vYmF0Y2hfc2lnLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBkZWx0YV9jZiB2cyBkZWx0YV93aG9sZQoKYGBge3IgdGJfY29tYmluZV9kZWx0YWNmX2RlbHRhd2hvbGUsIGZpZy5zaG93PSdoaWRlJ30Ka2VlcGVycyA8LSBsaXN0KAogICJkZWx0YWNmX3ZzX2RlbHRhd2hvbGUiID0gYygiZGVsdGFfZmlsdHJhdGUiLCAiZGVsdGFfd2hvbGUiKSkKbXNfc2V0X25hbWUgPC0gImRlbHRhX2ZpbHRyYXRlX3ZzX2RlbHRhX3dob2xlIgptc3N0YXRzX3Jlc3VsdCA8LSBtc3N0YXRzX3Jlc3VsdHNbW21zX3NldF9uYW1lXV1bWyJDb21wYXJpc29uUmVzdWx0Il1dCiMjIE1ha2Ugc3VyZSB0byBzZXQgdGhlIHJvd25hbWVzIHNvIGl0IHdpbGwgbWVyZ2UgaW50byB0aGUgZXhjZWwgZmlsZS4Kcm93bmFtZXMobXNzdGF0c19yZXN1bHQpIDwtIG1zc3RhdHNfcmVzdWx0W1siUHJvdGVpbiJdXQpkZWx0YWNmX2RlbHRhd2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGV4dHJhX2xmY19maWx0ZXJfZGUsIGtlZXBlcnM9a2VlcGVycywgZXh0cmFfYW5ub3Q9bXNzdGF0c19yZXN1bHQsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9kZWx0YWNmX3ZzX2RlbHRhd2hvbGVfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKY29tcF90YWJsZSA8LSBkZWx0YWNmX2RlbHRhd2hvbGVfdGFibGVzJGRhdGFbW25hbWVzKGtlZXBlcnMpXV0KY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZGVzZXFfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQp0dCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGNvbXBfdGFibGVbLCBjKCJsb2cyZmMiLCAiZWRnZXJfbG9nZmMiKV0pCnR0JHNjYXR0ZXIKCmRlbHRhY2ZfZGVsdGF3aG9sZV9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBkZWx0YWNmX2RlbHRhd2hvbGVfdGFibGVzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvZGVsdGFjZl92c19kZWx0YXdob2xlX25vYmF0Y2hfc2lnLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgojIyBkZWx0YV9jZiB2cyB3dF9jZgoKU29tZXRoaW5nIGlzIHdlaXJkIGFib3V0IHRoaXMgcGFydGljdWxhciBjb250cmFzdCwgSSBrZWVwIGdldHRpbmcgbmVnYXRpdmUgY29ycmVsYXRpb25zIQoKYGBge3IgdGJfY29tYmluZV9kZWx0YWNmX3d0Y2YsIGZpZy5zaG93PSdoaWRlJ30Ka2VlcGVycyA8LSBsaXN0KAogICJkZWx0YWNmX3ZzX3d0Y2YiID0gYygiZGVsdGFfZmlsdHJhdGUiLCAid3RfZmlsdHJhdGUiKSkKbXNfc2V0X25hbWUgPC0gImRlbHRhX2ZpbHRyYXRlX3ZzX3d0X2ZpbHRyYXRlIgptc3N0YXRzX3Jlc3VsdCA8LSBtc3N0YXRzX3Jlc3VsdHNbW21zX3NldF9uYW1lXV1bWyJDb21wYXJpc29uUmVzdWx0Il1dCnJvd25hbWVzKG1zc3RhdHNfcmVzdWx0KSA8LSBtc3N0YXRzX3Jlc3VsdFtbIlByb3RlaW4iXV0KZGVsdGFjZl93dGNmX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICBleHRyYV9sZmNfZmlsdGVyX2RlLCBrZWVwZXJzPWtlZXBlcnMsIGV4dHJhX2Fubm90PW1zc3RhdHNfcmVzdWx0LAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvZGVsdGFjZl92c193dGNmX3RhYmxlcy12IiwgdmVyLCAiLnhsc3giKSkpCgpjb21wX3RhYmxlIDwtIGRlbHRhY2Zfd3RjZl90YWJsZXMkZGF0YVtbbmFtZXMoa2VlcGVycyldXQpjb3IudGVzdChjb21wX3RhYmxlJGxvZzJmYywgY29tcF90YWJsZSRkZXNlcV9sb2dmYywgbWV0aG9kPSJzcGVhcm1hbiIpCmNvci50ZXN0KGNvbXBfdGFibGUkbG9nMmZjLCBjb21wX3RhYmxlJGxpbW1hX2xvZ2ZjLCBtZXRob2Q9InNwZWFybWFuIikKY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZWRnZXJfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpjb3IudGVzdChjb21wX3RhYmxlJGxvZzJmYywgY29tcF90YWJsZSRlYnNlcV9sb2dmYywgbWV0aG9kPSJzcGVhcm1hbiIpCnNjYXR0ZXJfdGVzdCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGNvbXBfdGFibGVbLCBjKCJsb2cyZmMiLCAibGltbWFfbG9nZmMiKV0pCnNjYXR0ZXJfdGVzdCRzY2F0dGVyCmZpbHRlcmVkX2lkeCA8LSAhIGlzLm5hKGNvbXBfdGFibGUkbG9nMmZjKQpjb21fdGFibGUgPC0gY29tcF90YWJsZVtmaWx0ZXJlZF9pZHgsIF0KbmVnX2luZl9pZHggPC0gY29tX3RhYmxlJGxvZzJmYyA9PSAtSW5mCmNvbV90YWJsZVtuZWdfaW5mX2lkeCwgImxvZzJmYyJdIDwtIC0xMDAKcG9zX2luZl9pZHggPC0gY29tX3RhYmxlJGxvZzJmYyA9PSBJbmYKY29tX3RhYmxlW3Bvc19pbmZfaWR4LCAibG9nMmZjIl0gPC0gMTAwCmNvci50ZXN0KGNvbV90YWJsZSRsb2cyZmMsIGNvbV90YWJsZSRkZXNlcV9sb2dmYykKc2NhdHRlcl90ZXN0IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoY29tX3RhYmxlWywgYygibG9nMmZjIiwgImVkZ2VyX2xvZ2ZjIildKQoKCmRlbHRhY2Zfd3RjZl9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBkZWx0YWNmX3d0Y2ZfdGFibGVzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvZGVsdGFjZl92c193dGNmX25vYmF0Y2hfc2lnLXYiLCB2ZXIsICIueGxzeCIpKSkKYGBgCgpPaywgSSBoYXZlIGJlZW4gcmVzaXN0aW5nIHRoaXMsIGJ1dCBsZXRzIGxvb2sgbW9yZSBjbG9zZWx5IGF0IHRoZSBkYXRhIGZvciB0aGlzCmNvbnRyYXN0LgpPbmUgdGhpbmcgSSBjYW4gZG8gdG8gbG9vayBmb3IgY29ycmVjdG5lc3MgaW4gd2hhdCBJIGFtIHNlZWluZyBpcyB0byBsb29rIGF0IHRoZQptZWFuIG51bWVyYXRvcnMvZGVub21pbmF0b3JzIGZvciB0aGlzIGNvbnRyYXN0IGFuZCBzZWUgaWYgdGhleSBhZ3JlZSB3aXRoCm1zc3RhdHMgb3IgdGhlIG90aGVycy4KCiMjIGRlbHRhX3dob2xlIHZzIHd0X3dob2xlCgpgYGB7ciB0Yl9jb21iaW5lX2RlbHRhd2hvbGVfd3R3aG9sZSwgZmlnLnNob3c9J2hpZGUnfQprZWVwZXJzIDwtIGxpc3QoCiAgImRlbHRhd2hvbGVfdnNfd3R3aG9sZSIgPSBjKCJkZWx0YV93aG9sZSIsICJ3dF93aG9sZSIpKQptc19zZXRfbmFtZSA8LSAiZGVsdGFfd2hvbGVfdnNfd3Rfd2hvbGUiCm1zc3RhdHNfcmVzdWx0IDwtIG1zc3RhdHNfcmVzdWx0c1tbbXNfc2V0X25hbWVdXVtbIkNvbXBhcmlzb25SZXN1bHQiXV0Kcm93bmFtZXMobXNzdGF0c19yZXN1bHQpIDwtIG1zc3RhdHNfcmVzdWx0W1siUHJvdGVpbiJdXQpkZWx0YXdob2xlX3d0d2hvbGVfdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogIGV4dHJhX2xmY19maWx0ZXJfZGUsIGtlZXBlcnM9a2VlcGVycywgZXh0cmFfYW5ub3Q9bXNzdGF0c19yZXN1bHQsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9kZWx0YXdob2xlX3ZzX3d0d2hvbGVfdGFibGVzLXYiLCB2ZXIsICIueGxzeCIpKSkKY29tcF90YWJsZSA8LSBkZWx0YXdob2xlX3d0d2hvbGVfdGFibGVzJGRhdGFbW25hbWVzKGtlZXBlcnMpXV0KY29yLnRlc3QoY29tcF90YWJsZSRsb2cyZmMsIGNvbXBfdGFibGUkZGVzZXFfbG9nZmMsIG1ldGhvZD0ic3BlYXJtYW4iKQpkZWx0YXdob2xlX3d0d2hvbGVfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgZGVsdGF3aG9sZV93dHdob2xlX3RhYmxlcywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL2RlbHRhd2hvbGVfdnNfd3R3aG9sZV9ub2JhdGNoX3NpZy12IiwgdmVyLCAiLnhsc3giKSkpCmBgYAoKIyMgVmVubiBvZiBNU3N0YXRzIHZzLiBvdGhlcnMgZm9yIHd0IHdob2xlL2NmCgpOYWppYiBhc2tlZCBmb3IgdGhlIG92ZXJsYXAgaW4gcGVyY2VpdmVkIHNpZ25pZmljYW5jZS4KCmBgYHtyIG1zc3RhdHNfb3RoZXJfdmVubn0Kc3RhcnQgPC0gd3RjZl9ub2JhdGNoX3d0d2hvbGVfdGFibGVzW1siZGF0YSJdXVtbMV1dCm5hX2lkeCA8LSBpcy5uYShzdGFydFtbImFkanB2YWx1ZSJdXSkKc3RhcnRbbmFfaWR4LCAiYWRqcHZhbHVlIl0gPC0gMQptc19zaWdfaWR4IDwtIHN0YXJ0W1siYWRqcHZhbHVlIl1dIDw9IDAuMDUKCmRlX3NpZ19pZHggPC0gc3RhcnRbWyJkZXNlcV9hZGpwIl1dIDw9IDAuMDUKZWRfc2lnX2lkeCA8LSBzdGFydFtbImVkZ2VyX2FkanAiXV0gPD0gMC4wNQpsbV9zaWdfaWR4IDwtIHN0YXJ0W1sibGltbWFfYWRqcCJdXSA8PSAwLjA1CmViX3NpZ19pZHggPC0gc3RhcnRbWyJlYnNlcV9wcGVlIl1dIDw9IDAuMDUKCm1zX3NpZyA8LSBzdGFydFttc19zaWdfaWR4LCBdCmRlX3NpZyA8LSBzdGFydFtkZV9zaWdfaWR4LCBdCmVkX3NpZyA8LSBzdGFydFtlZF9zaWdfaWR4LCBdCmxtX3NpZyA8LSBzdGFydFtsbV9zaWdfaWR4LCBdCmViX3NpZyA8LSBzdGFydFtlYl9zaWdfaWR4LCBdCgptc19kZV9zaGFyZWQgPC0gc3VtKHJvd25hbWVzKG1zX3NpZykgJWluJSByb3duYW1lcyhkZV9zaWcpKQptc19zb2xvIDwtICEgcm93bmFtZXMobXNfc2lnKSAlaW4lIHJvd25hbWVzKGRlX3NpZykKZGVfc29sbyA8LSAhIHJvd25hbWVzKGRlX3NpZykgJWluJSByb3duYW1lcyhtc19zaWcpCm1zX2RlX3dlaWdodHMgPC0gYygwLCBzdW0obXNfc29sbyksIHN1bShkZV9zb2xvKSwgc3VtKG1zX2RlX3NoYXJlZCkpCm1zX2RlX3Zlbm4gPC0gVmVubmVyYWJsZTo6VmVubihTZXROYW1lcz1jKCJtcyIsICJkZSIpLCBXZWlnaHQ9bXNfZGVfd2VpZ2h0cykKVmVubmVyYWJsZTo6cGxvdChtc19kZV92ZW5uLCBkb1dlaWdodHM9RkFMU0UpCgptc19lZF9zaGFyZWQgPC0gc3VtKHJvd25hbWVzKG1zX3NpZykgJWluJSByb3duYW1lcyhlZF9zaWcpKQptc19zb2xvIDwtICEgcm93bmFtZXMobXNfc2lnKSAlaW4lIHJvd25hbWVzKGVkX3NpZykKZWRfc29sbyA8LSAhIHJvd25hbWVzKGVkX3NpZykgJWluJSByb3duYW1lcyhtc19zaWcpCm1zX2VkX3dlaWdodHMgPC0gYygwLCBzdW0obXNfc29sbyksIHN1bShlZF9zb2xvKSwgc3VtKG1zX2VkX3NoYXJlZCkpCm1zX2VkX3Zlbm4gPC0gVmVubmVyYWJsZTo6VmVubihTZXROYW1lcz1jKCJtcyIsICJlZCIpLCBXZWlnaHQ9bXNfZWRfd2VpZ2h0cykKVmVubmVyYWJsZTo6cGxvdChtc19lZF92ZW5uLCBkb1dlaWdodHM9RkFMU0UpCgptc19sbV9zaGFyZWQgPC0gc3VtKHJvd25hbWVzKG1zX3NpZykgJWluJSByb3duYW1lcyhsbV9zaWcpKQptc19zb2xvIDwtICEgcm93bmFtZXMobXNfc2lnKSAlaW4lIHJvd25hbWVzKGxtX3NpZykKbG1fc29sbyA8LSAhIHJvd25hbWVzKGxtX3NpZykgJWluJSByb3duYW1lcyhtc19zaWcpCm1zX2xtX3dlaWdodHMgPC0gYygwLCBzdW0obXNfc29sbyksIHN1bShsbV9zb2xvKSwgc3VtKG1zX2xtX3NoYXJlZCkpCm1zX2xtX3Zlbm4gPC0gVmVubmVyYWJsZTo6VmVubihTZXROYW1lcz1jKCJtcyIsICJsbSIpLCBXZWlnaHQ9bXNfbG1fd2VpZ2h0cykKVmVubmVyYWJsZTo6cGxvdChtc19sbV92ZW5uLCBkb1dlaWdodHM9RkFMU0UpCgptc19lYl9zaGFyZWQgPC0gc3VtKHJvd25hbWVzKG1zX3NpZykgJWluJSByb3duYW1lcyhlYl9zaWcpKQptc19zb2xvIDwtICEgcm93bmFtZXMobXNfc2lnKSAlaW4lIHJvd25hbWVzKGViX3NpZykKZWJfc29sbyA8LSAhIHJvd25hbWVzKGViX3NpZykgJWluJSByb3duYW1lcyhtc19zaWcpCm1zX2ViX3dlaWdodHMgPC0gYygwLCBzdW0obXNfc29sbyksIHN1bShlYl9zb2xvKSwgc3VtKG1zX2ViX3NoYXJlZCkpCm1zX2ViX3Zlbm4gPC0gVmVubmVyYWJsZTo6VmVubihTZXROYW1lcz1jKCJtcyIsICJlYiIpLCBXZWlnaHQ9bXNfZWJfd2VpZ2h0cykKVmVubmVyYWJsZTo6cGxvdChtc19lYl92ZW5uLCBkb1dlaWdodHM9RkFMU0UpCmBgYAoKIyBJbnRlcnNlY3Rpb25zCgpgYGB7ciBpbnRlcnNlY3R9CmNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gaW50ZXJzZWN0X3NpZ25pZmljYW50KAogIHd0Y2Zfbm9iYXRjaF93dHdob2xlX3RhYmxlcywKICBzZWxlY3RvcnM9YygibGltbWEiLCAibXNzdGF0cyIpLAogIGZjX2NvbHVtbj0ibG9nMmZjIiwgcF9jb2x1bW49ImFkanB2YWx1ZSIsCiAgZXhjZWw9ImV4Y2VsL3Rlc3RpbmdfaW50ZXJzZWN0aW9uc190d28ueGxzeCIpCmNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gaW50ZXJzZWN0X3NpZ25pZmljYW50KAogIHd0Y2Zfbm9iYXRjaF93dHdob2xlX3RhYmxlcywKICBzZWxlY3RvcnM9YygibGltbWEiLCAiZWJzZXEiLCAiZGVzZXEiKSwKICBmY19jb2x1bW49ImxvZzJmYyIsIHBfY29sdW1uPSJhZGpwdmFsdWUiLAogIGV4Y2VsPSJleGNlbC90ZXN0aW5nX2ludGVyc2VjdGlvbnNfdGhyZWUueGxzeCIpCmNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gaW50ZXJzZWN0X3NpZ25pZmljYW50KAogIHd0Y2Zfbm9iYXRjaF93dHdob2xlX3RhYmxlcywKICBzZWxlY3RvcnM9YygibGltbWEiLCAiZWJzZXEiLCAiZGVzZXEiLCAiZWRnZXIiKSwKICBmY19jb2x1bW49ImxvZzJmYyIsIHBfY29sdW1uPSJhZGpwdmFsdWUiLAogIGV4Y2VsPSJleGNlbC90ZXN0aW5nX2ludGVyc2VjdGlvbnNfZm91ci54bHN4IikKYGBgCgojIE9udG9sb2d5IHRlc3RzCgojIyBXdCBDRiB2cyBXdCB3aG9sZQoKYGBge3Igb250b2xvZ3l3dGNmd3R3aG9sZX0KbXRiX2dvIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfZ28oaWQ9ODMzMzIsIGlkX2NvbHVtbj0ic3lzTmFtZSIpCmhlYWQobXRiX2dvKQpjb2xuYW1lcyhtdGJfZ28pIDwtIGMoIklEIiwgIkdPIikKbXRiX2xlbmd0aHMgPC0gbXRiX2Fubm90YXRpb25zWywgYygiSUQiLCAid2lkdGgiKV0KCiMjIFdoYXQgc2V0cyBvZiBnZW5lcyB0byBwZXJmb3JtIGdvc2VxIG9uPwojIyBBcmJpdHJhcnkgZGVjaXNpb24gdGltZSwgbGV0cyB1c2UgZGVzZXEgZGF0YSBmb3IgZWFjaCBjb250cmFzdCwgb25jZSB3aXRob3V0IHN2YSwgb25jZSB3aXRoLgp3dGNmX3d0d2hvbGVfdXAgPC0gd3RjZl9ub2JhdGNoX3d0d2hvbGVfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQp3dGNmX3d0d2hvbGVfdXBfZ29zZXFfbmIgPC0gc2ltcGxlX2dvc2VxKAogIHNpZ19nZW5lcz13dGNmX3d0d2hvbGVfdXAsIGdvX2RiPW10Yl9nbywgbGVuZ3RoX2RiPW10Yl9sZW5ndGhzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvd3RjZl93dHdob2xlX3VwX2Rlc2VxX25vYmF0Y2hfZ29zZXEtdiIsIHZlciwgIi54bHN4IikpCnd0Y2Zfd3R3aG9sZV91cF9nb3NlcV9uYiRwdmFsdWVfcGxvdHNbWzFdXQoKd3RjZl93dHdob2xlX2Rvd24gPC0gd3RjZl9ub2JhdGNoX3d0d2hvbGVfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dCnd0Y2Zfd3R3aG9sZV9kb3duX2dvc2VxX25iIDwtIHNpbXBsZV9nb3NlcSgKICBzaWdfZ2VuZXM9d3RjZl93dHdob2xlX2Rvd24sIGdvX2RiPW10Yl9nbywgbGVuZ3RoX2RiPW10Yl9sZW5ndGhzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvd3RjZl93dHdob2xlX2Rvd25fZGVzZXFfbm9iYXRjaF9nb3NlcS12IiwgdmVyLCAiLnhsc3giKSkKd3RjZl93dHdob2xlX2Rvd25fZ29zZXFfbmIkcHZhbHVlX3Bsb3RzW1sxXV0KYGBgCgojIyBkZWx0YSBDRiB2cyBkZWx0YSB3aG9sZQoKYGBge3Igb250b2xvZ3lfZGNmX2R3aG9sZX0KZGVsdGFjZl9kZWx0YXdob2xlX3VwIDwtIGRlbHRhY2ZfZGVsdGF3aG9sZV9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dCmRlbHRhY2ZfZGVsdGF3aG9sZV91cF9nb3NlcV9uYiA8LSBzaW1wbGVfZ29zZXEoCiAgc2lnX2dlbmVzPWRlbHRhY2ZfZGVsdGF3aG9sZV91cCwgZ29fZGI9bXRiX2dvLCBsZW5ndGhfZGI9bXRiX2xlbmd0aHMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9kZWx0YWNmX2RlbHRhd2hvbGVfdXBfZGVzZXFfbm9iYXRjaF9nb3NlcS12IiwgdmVyLCAiLnhsc3giKSkKZGVsdGFjZl9kZWx0YXdob2xlX3VwX2dvc2VxX25iJHB2YWx1ZV9wbG90c1tbMV1dCgpkZWx0YWNmX2RlbHRhd2hvbGVfZG93biA8LSBkZWx0YWNmX2RlbHRhd2hvbGVfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dCmRlbHRhY2ZfZGVsdGF3aG9sZV9kb3duX2dvc2VxX25iIDwtIHNpbXBsZV9nb3NlcSgKICBzaWdfZ2VuZXM9ZGVsdGFjZl9kZWx0YXdob2xlX2Rvd24sIGdvX2RiPW10Yl9nbywgbGVuZ3RoX2RiPW10Yl9sZW5ndGhzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvZGVsdGFjZl9kZWx0YXdob2xlX2Rvd25fZGVzZXFfbm9iYXRjaF9nb3NlcS12IiwgdmVyLCAiLnhsc3giKSkKZGVsdGFjZl9kZWx0YXdob2xlX2Rvd25fZ29zZXFfbmIkcHZhbHVlX3Bsb3RzW1sxXV0KYGBgCgojIyBkZWx0YSBmaWx0cmF0ZSB2cyB3dCBmaWx0cmF0ZQoKYGBge3Igb250b2xvZ3lfZGNmX3d0Y2Z9CmRlbHRhY2Zfd3RjZl91cCA8LSBkZWx0YWNmX3d0Y2Zfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQpkZWx0YWNmX3d0Y2ZfdXBfZ29zZXFfbmIgPC0gc2ltcGxlX2dvc2VxKAogIHNpZ19nZW5lcz1kZWx0YWNmX3d0Y2ZfdXAsIGdvX2RiPW10Yl9nbywgbGVuZ3RoX2RiPW10Yl9sZW5ndGhzLAogIGV4Y2VsPXBhc3RlMCgiZXhjZWwvZGVsdGFjZl93dGNmX3VwX2Rlc2VxX25vYmF0Y2hfZ29zZXEtdiIsIHZlciwgIi54bHN4IikpCmRlbHRhY2Zfd3RjZl91cF9nb3NlcV9uYiRwdmFsdWVfcGxvdHNbWzFdXQoKZGVsdGFjZl93dGNmX2Rvd24gPC0gZGVsdGFjZl93dGNmX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXQpkZWx0YWNmX3d0Y2ZfZG93bl9nb3NlcV9uYiA8LSBzaW1wbGVfZ29zZXEoCiAgc2lnX2dlbmVzPWRlbHRhY2Zfd3RjZl9kb3duLCBnb19kYj1tdGJfZ28sIGxlbmd0aF9kYj1tdGJfbGVuZ3RocywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL2RlbHRhY2Zfd3RjZl9kb3duX2Rlc2VxX25vYmF0Y2hfZ29zZXEtdiIsIHZlciwgIi54bHN4IikpCmRlbHRhY2Zfd3RjZl9kb3duX2dvc2VxX25iJHB2YWx1ZV9wbG90c1tbMV1dCmBgYAoKIyMgZGVsdGEgd2hvbGUgdnMgd3Qgd2hvbGUKCmBgYHtyIG9udG9sb2d5X2R3aG9sZV93dHdob2xlfQpkZWx0YXdob2xlX3d0d2hvbGVfdXAgPC0gZGVsdGF3aG9sZV93dHdob2xlX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0KZGVsdGF3aG9sZV93dHdob2xlX3VwX2dvc2VxX25iIDwtIHNpbXBsZV9nb3NlcSgKICBzaWdfZ2VuZXM9ZGVsdGF3aG9sZV93dHdob2xlX3VwLCBnb19kYj1tdGJfZ28sIGxlbmd0aF9kYj1tdGJfbGVuZ3RocywKICBleGNlbD1wYXN0ZTAoImV4Y2VsL2RlbHRhd2hvbGVfd3R3aG9sZV91cF9kZXNlcV9ub2JhdGNoX2dvc2VxLXYiLCB2ZXIsICIueGxzeCIpKQpkZWx0YXdob2xlX3d0d2hvbGVfdXBfZ29zZXFfbmIkcHZhbHVlX3Bsb3RzW1sxXV0KCmRlbHRhd2hvbGVfd3R3aG9sZV9kb3duIDwtIGRlbHRhd2hvbGVfd3R3aG9sZV9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0KZGVsdGF3aG9sZV93dHdob2xlX2Rvd25fZ29zZXFfbmIgPC0gc2ltcGxlX2dvc2VxKAogIHNpZ19nZW5lcz1kZWx0YXdob2xlX3d0d2hvbGVfZG93biwgZ29fZGI9bXRiX2dvLCBsZW5ndGhfZGI9bXRiX2xlbmd0aHMsCiAgZXhjZWw9cGFzdGUwKCJleGNlbC9kZWx0YXdob2xlX3d0d2hvbGVfZG93bl9kZXNlcV9ub2JhdGNoX2dvc2VxLXYiLCB2ZXIsICIueGxzeCIpKQpkZWx0YXdob2xlX3d0d2hvbGVfZG93bl9nb3NlcV9uYiRwdmFsdWVfcGxvdHNbWzFdXQpgYGAKCiMgY2lyY29zCgpgYGB7ciBjaXJjb3N9CmdmZl9kZiA8LSBsb2FkX2dmZl9hbm5vdGF0aW9ucygicmVmZXJlbmNlL210dWJlcmN1bG9zaXNfaDM3cnYyLmdmZiIpCnJvd25hbWVzKGdmZl9kZikgPC0gbWFrZS5uYW1lcyhnZmZfZGZbWyJJRCJdXSwgdW5pcXVlPVRSVUUpCm1pY3JvYmVzX2Fubm90IDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfYW5ub3RhdGlvbnMoaWQ9ODMzMzIpCnJvd25hbWVzKG1pY3JvYmVzX2Fubm90KSA8LSBtYWtlLm5hbWVzKG1pY3JvYmVzX2Fubm90W1sic3lzTmFtZSJdXSwgdW5pcXVlPVRSVUUpCgpjb2VmZmljaWVudHMgPC0gZXh0cmFfbGZjX2ZpbHRlcl9kZSRkZXNlcSRjb2VmZmljaWVudHMKdmFsdWVzIDwtIG1lcmdlKG1pY3JvYmVzX2Fubm90LCBjb2VmZmljaWVudHMsIGJ5PSJyb3cubmFtZXMiKQoKY29nX2dyb3VwcyA8LSB2YWx1ZXNbLCBjKCJSb3cubmFtZXMiLCAic3RhcnQiLCAic3RvcCIsICJzdHJhbmQiLCAiQ09HRnVuIildCmNvbG5hbWVzKGNvZ19ncm91cHMpIDwtIGMoInNlcW5hbWVzIiwgInN0YXJ0IiwgInN0b3AiLCAic3RyYW5kIiwgIkNPR0Z1biIpCnJvd25hbWVzKGNvZ19ncm91cHMpIDwtIGNvZ19ncm91cHNbWyJzZXFuYW1lcyJdXQoKd3Rfd2hvbGUgPC0gdmFsdWVzWywgYygiUm93Lm5hbWVzIiwgInd0X3dob2xlIildCnJvd25hbWVzKHd0X3dob2xlKSA8LSB3dF93aG9sZVtbIlJvdy5uYW1lcyJdXQp3dGNmIDwtIHZhbHVlc1ssIGMoIlJvdy5uYW1lcyIsICJ3dF9maWx0cmF0ZSIpXQpyb3duYW1lcyh3dGNmKSA8LSB3dGNmW1siUm93Lm5hbWVzIl1dCmRlbHRhX3dob2xlIDwtIHZhbHVlc1ssIGMoIlJvdy5uYW1lcyIsICJkZWx0YV93aG9sZSIpXQpyb3duYW1lcyhkZWx0YV93aG9sZSkgPC0gZGVsdGFfd2hvbGVbWyJSb3cubmFtZXMiXV0KZGVsdGFfZmlsdHJhdGUgPC0gdmFsdWVzWywgYygiUm93Lm5hbWVzIiwgImRlbHRhX2ZpbHRyYXRlIildCnJvd25hbWVzKGRlbHRhX2ZpbHRyYXRlKSA8LSBkZWx0YV9maWx0cmF0ZVtbIlJvdy5uYW1lcyJdXQoKY2lyY29zX210YiA8LSBjaXJjb3NfcHJlZml4KG5hbWU9Im10YiIpCm10Yl9rYXJ5b3R5cGUgPC0gY2lyY29zX2thcnlvdHlwZSgibXRiIiwgbGVuZ3RoPTQ0MTE1MzIpCm10Yl9wbHVzIDwtIGNpcmNvc19wbHVzX21pbnVzKGNvZ19ncm91cHMsIGNpcmNvc19tdGIpCm10Yl93dHdob2xlIDwtIGNpcmNvc19oZWF0bWFwKAogIHd0X3dob2xlLCBnZmZfZGYsIGNvbG5hbWU9Ind0X3dob2xlIiwKICBjZmdvdXQ9Y2lyY29zX210YiwgYmFzZW5hbWU9Ind0X3dob2xlIiwgb3V0ZXI9bXRiX3BsdXMpCm10Yl9kZWx0YXdob2xlIDwtIGNpcmNvc19oZWF0bWFwKAogIGRlbHRhX3dob2xlLCBnZmZfZGYsIGNvbG5hbWU9ImRlbHRhX3dob2xlIiwKICBjZmdvdXQ9Y2lyY29zX210YiwgYmFzZW5hbWU9ImRlbHRhX3dob2xlIiwgb3V0ZXI9bXRiX3d0d2hvbGUpCm10Yl93dGNmIDwtIGNpcmNvc19oZWF0bWFwKAogIHd0Y2YsIGdmZl9kZiwgY29sbmFtZT0id3RfZmlsdHJhdGUiLAogIGNmZ291dD1jaXJjb3NfbXRiLCBiYXNlbmFtZT0id3RfZmlsdHJhdGUiLCBvdXRlcj1tdGJfZGVsdGF3aG9sZSkKbXRiX2RlbHRhY2YgPC0gY2lyY29zX2hlYXRtYXAoCiAgZGVsdGFfZmlsdHJhdGUsIGdmZl9kZiwgY29sbmFtZT0iZGVsdGFfZmlsdHJhdGUiLAogIGNmZ291dD1jaXJjb3NfbXRiLCBiYXNlbmFtZT0iZGVsdGFfZmlsdHJhdGUiLCBvdXRlcj1tdGJfd3RjZikKbXRiX2RlbHRhY2ZfaGVhdCA8LSBjaXJjb3NfaGVhdG1hcCgKICBkZWx0YV9maWx0cmF0ZSwgZ2ZmX2RmLCBjb2xuYW1lPSJkZWx0YV9maWx0cmF0ZSIsCiAgY2Znb3V0PWNpcmNvc19tdGIsIGJhc2VuYW1lPSJkZWx0YV9maWx0cmF0ZV9oZWF0Iiwgb3V0ZXI9bXRiX2RlbHRhY2YpCmNpcmNvc19zdWZmaXgoY2Znb3V0PWNpcmNvc19tdGIpCmNpcmNvc19tYWRlIDwtIHNtKGNpcmNvc19tYWtlKHRhcmdldD0ibXRiIikpCmBgYAoKW2NpcmNvcyBwbG90XShjaXJjb3MvbXRiLnBuZykKCiMgVE9ETwoKKiAyMDE4LTA0LTEwOiAgTWFrZSBzdXJlIG15IGludm9jYXRpb25zIG9mIFNXQVRIMnN0YXRzL01Tc3RhdHMgYXJlIGNvcnJlY3QuCgpgYGB7ciBzYXZlbWUsIGV2YWw9RkFMU0V9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIHRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCB0aGlzX3NhdmUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQp9CmBgYAoKYGBge3IgbG9hZG1lLCBldmFsPUZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkKYGBgCg==