1 Analyzing data from openMS and friends.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1.3 Show a series of all identifications for marker proteins

There are a few proteins for which Volker has relatively specific assumptions/expectations. Let us see what they look like and if they follow a trend which makes some sense…

The primary thing to recall, I think, is that in our previous data sets, there were a pretty large number of samples for which no identifications were made for many of these proteins. Does that remain true?

1.4 Grab annotations

## The species being downloaded is: Mycobacterium tuberculosis H37Rv
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=83332;export=tab

I will use the annotations to make finding the correct protein IDs easier.

##        gene name         description
## Rv0287 esxG esxG esat-6 like protein
## Writing the image to: images/whole_osw_esxG_intensities-v20191021.png and calling dev.off().

##        gene name                            description
## Rv0288 esxH esxH low molecular weight protein antigen 7
## Writing the image to: images/whole_osw_esxH_intensities-v20191021.png and calling dev.off().

##        gene name                          description
## Rv3763 lpqH lpqH 19 kda lipoprotein antigen precursor
## Writing the image to: images/whole_osw_lpqh_intensities-v20191021.png and calling dev.off().

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

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

##        gene name                               description
## Rv1860  apa  apa alanine and proline rich secreted protein
## Writing the image to: images/whole_osw_fap_intensities-v20191021.png and calling dev.off().

## Writing the image to: images/whole_osw_ppe1_intensities-v20191021.png and calling dev.off().
## Warning: Removed 35 rows containing non-finite values (stat_ydensity).
## Warning in min(x): no non-missing arguments to min; returning Inf
## Warning in max(x): no non-missing arguments to max; returning -Inf
## Warning: Removed 35 rows containing non-finite values (stat_ydensity).
## Warning in min(x): no non-missing arguments to min; returning Inf
## Warning in max(x): no non-missing arguments to max; returning -Inf

##         gene name                           description
## Rv1908c katG katG catalase-peroxidase-peroxynitritase T
## Writing the image to: images/whole_osw_katg_intensities-v20191021.png and calling dev.off().

##          gene  name        description
## Rv2430c PPE41 PPE41 PPE family protein
## Adding 2019_0801Briken01
## Adding 2019_0801Briken04
## Adding 2019_0801Briken07
## Adding 2019_0801Briken10
## Adding 2019_0801Briken13
## Adding 2019_0801Briken16
## Adding 2019_0709Briken01
## Adding 2019_0709Briken04
## Adding 2019_0709Briken07
## Adding 2019_0709Briken10
## Adding 2019_0709Briken13
## Adding 2019_0709Briken16
## Adding 2019_0801Briken02
## Adding 2019_0801Briken08
## Adding 2019_0801Briken11
## Adding 2019_0801Briken14
## Adding 2019_0801Briken17
## Adding 2019_0709Briken02
## Adding 2019_0709Briken05
## Adding 2019_0709Briken08
## Adding 2019_0709Briken11
## Adding 2019_0709Briken14
## Adding 2019_0709Briken17
## Adding 2019_0801Briken03
## Adding 2019_0801Briken06
## Adding 2019_0801Briken09
## Adding 2019_0801Briken12
## Adding 2019_0801Briken15
## Adding 2019_0801Briken18
## Adding 2019_0709Briken03
## Adding 2019_0709Briken06
## Adding 2019_0709Briken09
## Adding 2019_0709Briken12
## Adding 2019_0709Briken15
## Adding 2019_0709Briken18
## Writing the image to: images/PPE41_intensities-v20191021.png and calling dev.off().

##         gene name       description
## Rv2431c PE25 PE25 PE family protein
## Adding 2019_0801Briken01
## Adding 2019_0801Briken04
## Adding 2019_0801Briken07
## Adding 2019_0801Briken10
## Adding 2019_0801Briken13
## Adding 2019_0801Briken16
## Adding 2019_0709Briken01
## Adding 2019_0709Briken04
## Adding 2019_0709Briken07
## Adding 2019_0709Briken10
## Adding 2019_0709Briken13
## Adding 2019_0709Briken16
## Adding 2019_0801Briken02
## Adding 2019_0801Briken08
## Adding 2019_0801Briken11
## Adding 2019_0801Briken14
## Adding 2019_0801Briken17
## Adding 2019_0709Briken02
## Adding 2019_0709Briken05
## Adding 2019_0709Briken08
## Adding 2019_0709Briken11
## Adding 2019_0709Briken14
## Adding 2019_0709Briken17
## Adding 2019_0801Briken03
## Adding 2019_0801Briken06
## Adding 2019_0801Briken09
## Adding 2019_0801Briken12
## Adding 2019_0801Briken15
## Adding 2019_0801Briken18
## Adding 2019_0709Briken03
## Adding 2019_0709Briken06
## Adding 2019_0709Briken09
## Adding 2019_0709Briken12
## Adding 2019_0709Briken15
## Adding 2019_0709Briken18
## Writing the image to: images/PE25_intensities-v20191021.png and calling dev.off().

##        gene name       description
## Rv3477 PE31 PE31 PE family protein
## Writing the image to: images/PE31_intensities-v20191021.png and calling dev.off().

##        gene name                            description
## Rv0288 esxH esxH low molecular weight protein antigen 7
## Writing the image to: images/esxH_intensities-v20191021.png and calling dev.off().

##          gene   name          description
## Rv1748 Rv1748 Rv1748 hypothetical protein
## Writing the image to: images/Rv1748_intensities-v20191021.png and calling dev.off().
## Warning in max(data$density): no non-missing arguments to max; returning -Inf
## Warning in max(data$density): no non-missing arguments to max; returning -Inf

##        gene name                                       description
## Rv1746 pknF pknF anchored-membrane serine/threonine-protein kinase
## Writing the image to: images/pknF_intensities-v20191021.png and calling dev.off().

##         gene name                     description
## Rv0410c pknG pknG serine/threonine-protein kinase
## Writing the image to: images/pknG_intensities-v20191021.png and calling dev.off().

2 Start SWATH2stats

I want to load the data and metadata into SWATH2stats in preparation for MSstats and my own hpgltools-base analyses.

## Parsed with column specification:
## cols(
##   .default = col_double(),
##   run_id = col_character(),
##   filename = col_character(),
##   Sequence = col_character(),
##   FullPeptideName = col_character(),
##   aggr_Peak_Area = col_logical(),
##   aggr_Peak_Apex = col_logical(),
##   aggr_Fragment_Annotation = col_logical(),
##   ProteinName = col_character(),
##   align_runid = col_character(),
##   align_origfilename = col_character()
## )
## See spec(...) for full column specifications.
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   run_id = col_character(),
##   filename = col_character(),
##   Sequence = col_character(),
##   FullPeptideName = col_character(),
##   aggr_Peak_Area = col_logical(),
##   aggr_Peak_Apex = col_logical(),
##   aggr_Fragment_Annotation = col_logical(),
##   ProteinName = col_character(),
##   align_runid = col_character(),
##   align_origfilename = col_character()
## )
## See spec(...) for full column specifications.
## Parsed with column specification:
## cols(
##   .default = col_character(),
##   FigureReplicate = col_logical(),
##   `Figure Name` = col_logical(),
##   `Sample Description` = col_logical(),
##   `Replicate State` = col_logical(),
##   enzyme = col_logical(),
##   harvestdate = col_logical(),
##   prepdate = col_logical(),
##   rundate = col_logical(),
##   runinfo = col_logical(),
##   tuberculist_scored = col_logical(),
##   include_exclude = col_logical(),
##   Run_note = col_logical()
## )
## See spec(...) for full column specifications.
## Loading SWATH2stats
## Found the same mzXML files in the annotations and data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken01.mzXML has 4377 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken02.mzXML has 3590 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken03.mzXML has 4163 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken04.mzXML has 4355 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken05.mzXML has 3636 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken06.mzXML has 4003 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken07.mzXML has 4573 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken08.mzXML has 3614 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken09.mzXML has 4418 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken10.mzXML has 4960 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken11.mzXML has 5853 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken12.mzXML has 6303 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken13.mzXML has 2828 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken14.mzXML has 6987 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken15.mzXML has 4934 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken16.mzXML has 3510 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken17.mzXML has 4010 entries in the data.
## preprocessing/01mzXML/dia/20190718/2019_0709Briken18.mzXML has 6040 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken01.mzXML has 13393 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken02.mzXML has 13968 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken03.mzXML has 14417 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken04.mzXML has 11498 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken06.mzXML has 14028 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken07.mzXML has 12127 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken08.mzXML has 13509 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken09.mzXML has 13867 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken10.mzXML has 13339 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken11.mzXML has 8334 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken12.mzXML has 13904 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken13.mzXML has 12833 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken14.mzXML has 8462 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken15.mzXML has 13365 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken16.mzXML has 12468 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken17.mzXML has 8173 entries in the data.
## preprocessing/01mzXML/dia/20190801/2019_0801Briken18.mzXML has 13436 entries in the data.

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

3 SWATH2stats continued

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 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/s2s_correlation-v20191021.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/s2_correlation.png when dev.off() is called.
## png 
##   2

3.2 Perform SWATH2stats filters

I just realized something which should be added to me SWATH2stats fork: A simplified filter functions which invokes all of these so that I can make sure that there are no typeographikal errors introduced by my invocation of each of these things, one at a time.

## Number of non-decoy peptides: 17968
## Number of decoy peptides: 1413
## Decoy rate: 0.0786
## The average FDR by run on assay level is 0.01
## The average FDR by run on peptide level is 0.011
## The average FDR by run on protein level is 0.043
## Target assay FDR: 0.02
## Required overall m-score cutoff: 0.0039811
## achieving assay FDR: 0.0196
## Target protein FDR: 0.02
## Required overall m-score cutoff: 0.00079433
## achieving protein FDR: 0.019
## Original dimension: 288943, new dimension: 257900, difference: 31043.
## Peptides need to have been quantified in more conditions than: 28 in order to pass this percentage-based threshold.
## Fraction of peptides selected: 0.14
## Original dimension: 288943, new dimension: 95329, difference: 193614.
## Target protein FDR: 0.000794328234724281
## 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: 2813
## Final target proteins: 2813
## Final decoy proteins: 0
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 16178
## Final target peptides: 16178
## Final decoy peptides: 0
## Total peptides selected from:
## Total peptides: 16178
## Final target peptides: 16178
## 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: 2830
## Protein identifiers: Rv3570c, Rv2524c, Rv3908, Rv2427c, Rv1579c, Rv0913c
## Number of proteins detected that are supported by a proteotypic peptide: 2716
## Number of proteotypic peptides detected: 16060
## Number of proteins detected: 2716
## First 6 protein identifiers: Rv3570c, Rv2524c, Rv3908, Rv2427c, Rv1579c, Rv0913c
## Before filtering:
##   Number of proteins: 2716
##   Number of peptides: 16060
## 
## Percentage of peptides removed: 16.95%
## 
## After filtering:
##   Number of proteins: 2716
##   Number of peptides: 13338
## Before filtering:
##   Number of proteins: 2716
##   Number of peptides: 13338
## 
## Percentage of peptides removed: 9.18%
## 
## After filtering:
##   Number of proteins: 1845
##   Number of peptides: 12113
## Number of non-decoy peptides: 17968
## Number of decoy peptides: 1413
## Decoy rate: 0.0786
## There were 288943 observations and 4332 decoy observations.
## The average FDR by run on assay level is 0.01
## The average FDR by run on peptide level is 0.011
## The average FDR by run on protein level is 0.043
## Target assay FDR: 0.1
## Required overall m-score cutoff: 0.01
## achieving assay FDR: 0.0471
## Target protein FDR: 0.1
## Required overall m-score cutoff: 0.0031623
## achieving protein FDR: 0.094
## Starting mscore filter.
## Starting mscore filter.
## Original dimension: 288943, new dimension: 288928, difference: 15.
## Starting freqobs filter.
## Peptides need to have been quantified in more conditions than: 26.25 in order to pass this percentage-based threshold.
## Fraction of peptides selected: 0.15
## Original dimension: 288928, new dimension: 101508, difference: 187420.
## Starting fdr filter.
## Target protein FDR: 0.00316227766016838
## 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.1
## Required overall m-score cutoff: 0.01
## Achieving peptide FDR: 0
## Proteins selected: 
## Total proteins selected: 895
## Final target proteins: 895
## Final decoy proteins: 0
## Peptides mapping to these protein entries selected:
## Total mapping peptides: 2927
## Final target peptides: 2927
## Final decoy peptides: 0
## Total peptides selected from:
## Total peptides: 2927
## Final target peptides: 2927
## 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.
## Starting proteotypic filter.
## Number of proteins detected: 912
## Protein identifiers: Rv3879c, Rv0577, Rv3800c, Rv0360c, Rv1023, Rv1808
## Number of proteins detected that are supported by a proteotypic peptide: 874
## Number of proteotypic peptides detected: 2900
## Starting peptide filter.
## Number of proteins detected: 874
## First 6 protein identifiers: Rv3879c, Rv0577, Rv3800c, Rv0360c, Rv1023, Rv1808
## Starting maximum peptide filter.
## Before filtering:
##   Number of proteins: 874
##   Number of peptides: 2900
## 
## Percentage of peptides removed: 2.38%
## 
## After filtering:
##   Number of proteins: 874
##   Number of peptides: 2831
## Skipping min peptide filter.
## We went from 4159/19381 proteins/peptides to:
##              874/2831 proteins/peptides.

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

Let us reset the version back to 20190327 here.

## Protein overview matrix preprocessing/10swath2stats/20191021/protein_matrix_unfiltered.csv written to working folder.
## [1] 4159   36
## Protein overview matrix preprocessing/10swath2stats/20191021/protein_matrix_mscore.csv written to working folder.
## [1] 3072   36
## Peptide overview matrix preprocessing/10swath2stats/20191021/peptide_matrix_mscore.csv written to working folder.
## [1] 17968    36
## Protein overview matrix preprocessing/10swath2stats/20191021/protein_matrix_filtered.csv written to working folder.
## [1] 874  36
## Peptide overview matrix preprocessing/10swath2stats/20191021/peptide_matrix_filtered.csv written to working folder.
## [1] 2831   36

## The library contains 1 transitions 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.

4 Test aLFQ

I want to revisit aLFQ, I think it might provide better protein-level quantification methods. aLFQ looks promising, but I have not figured out valid parameters for using it.

4.1 MSstats

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

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

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

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 via SWATH2stats.

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.

## Reading the sample metadata.
## The sample definitions comprises: 35 rows(samples) and 20 columns(metadata fields).
## Matched 869 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## The final expressionset has 873 rows and 35 columns.
## Reading the sample metadata.
## The sample definitions comprises: 35 rows(samples) and 20 columns(metadata fields).
## Matched 2927 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## The final expressionset has 2954 rows and 35 columns.
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Warning in mode(current): NAs introduced by coercion to integer range
## Graphing a boxplot.
## 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 1759 zero count features.
## Graphing a correlation heatmap.
## Graphing a standard median correlation.
## Performing correlation.
## Graphing a distance heatmap.

## Graphing a standard median distance.
## Performing distance.
## Graphing a PCA plot.
## Graphing a T-SNE plot.
## Plotting a density plot.
## 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 1759 zero count features.
## Plotting a CV plot.
## Naively calculating coefficient of variation/dispersion with respect to condition.
## Finished calculating dispersion estimates.
## Plotting the representation of the top-n genes.
## Plotting the expression of the top-n PC loaded genes.

## Printing a color to condition legend.

## Going to write the image to: images/legend.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/density.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/box.png when dev.off() is called.
## png 
##   2
## Going to write the image to: libsize.png when dev.off() is called.
## png 
##   2
## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 0 low-count genes (873 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 102 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Graphing a boxplot.
## Graphing a correlation heatmap.
## Graphing a standard median correlation.
## Performing correlation.
## Graphing a distance heatmap.

## Graphing a standard median distance.
## Performing distance.
## Graphing a PCA plot.
## Graphing a T-SNE plot.
## Plotting a density plot.
## Plotting a CV plot.
## Naively calculating coefficient of variation/dispersion with respect to condition.
## Finished calculating dispersion estimates.
## Plotting the representation of the top-n genes.
## Plotting the expression of the top-n PC loaded genes.

## Printing a color to condition legend.

## Going to write the image to: images/cor.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/dis.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/cv.png when dev.off() is called.
## png 
##   2
## Going to write the image to: images/pca.png when dev.off() is called.
## png 
##   2
## Writing the image to: images/20191021_filtered_pca.png and calling dev.off().

## Using a subset expression.
## There were 35, now there are 17 samples.
## This function will replace the expt$expressionset slot with:
## log2(ruvg(cpm(quant(cbcb(data)))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Step 1: performing count filter with option: cbcb
## Removing 0 low-count genes (873 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 74 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with ruvg.
## Note to self:  If you get an error like 'x contains missing values' The data has too many 0's and needs a stronger low-count filter applied.
## Passing off to all_adjusters.
## batch_counts: Before batch/surrogate estimation, 14731 entries are x>1: 99%.
## batch_counts: Before batch/surrogate estimation, 74 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36 entries are 0<x<1: 0%.
## The be method chose 3 surrogate variable(s).
## Using RUVSeq and edgeR for batch correction (similar to lmfit residuals.)
## Warning in RUVSeq::RUVg(linear_mtrx, ruv_controls, k = chosen_surrogates): The expression matrix does not contain counts.
## Please, pass a matrix of counts (not logged) or set isLog to TRUE to skip the log transformation
## There are 4 (0%) elements which are < 0 after batch correction.
## Setting low elements to zero.

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

## This function will replace the expt$expressionset slot with:
## log2(cpm(quant(cbcb(data))))
## It will save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep libsizes in mind
##  when invoking limma.  The appropriate libsize is non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: performing count filter with option: cbcb
## Removing 181 low-count genes (2773 remaining).
## Step 2: normalizing the data with quant.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 6746 values equal to 0, adding 1 to the matrix.
## Step 5: not doing batch correction.

## Writing the first sheet, containing a legend and some summary data.
## Writing the raw reads.
## 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.
## Dividing work into 100 chunks...
## 
## Total:18 s
## Placing factor: condition at the beginning of the model.
## 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.
## Dividing work into 100 chunks...
## 
## Total:11 s
## Placing factor: condition at the beginning of the model.
## Writing the median reads by factor.
## Writing the first sheet, containing a legend and some summary data.
## Writing the raw reads.
## 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.
## Dividing work into 100 chunks...
## 
## Total:33 s
## Placing factor: condition at the beginning of the model.
## 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.
## Dividing work into 100 chunks...
## 
## Total:49 s
## Placing factor: condition at the beginning of the model.
## Writing the median reads by factor.
## Using a subset expression.
## There were 35, now there are 34 samples.
## Using a subset expression.
## There were 35, now there are 34 samples.
## Writing a legend of columns.
## Printing a pca plot before/after surrogates/batch estimation.
## Working on 1/9: whdt_wt which is: dt_wh/wt_wh.
## Found inverse table with wt_wh_vs_dt_wh
## The ebseq table is null.
## Working on 2/9: whcp_wt which is: cp_wh/wt_wh.
## Found inverse table with wt_wh_vs_cp_wh
## The ebseq table is null.
## Working on 3/9: whdt_cp which is: dt_wh/cp_wh.
## Found table with dt_wh_vs_cp_wh
## The ebseq table is null.
## Working on 4/9: cfdt_wt which is: dt_cf/wt_cf.
## Found inverse table with wt_cf_vs_dt_cf
## The ebseq table is null.
## Working on 5/9: cfcp_wt which is: cp_cf/wt_cf.
## Found inverse table with wt_cf_vs_cp_cf
## The ebseq table is null.
## Working on 6/9: cfdt_cp which is: dt_cf/cp_cf.
## Found table with dt_cf_vs_cp_cf
## The ebseq table is null.
## Working on 7/9: wtcf_wh which is: wt_cf/wt_wh.
## Found inverse table with wt_wh_vs_wt_cf
## The ebseq table is null.
## Working on 8/9: dtcf_wh which is: dt_cf/dt_wh.
## Found inverse table with dt_wh_vs_dt_cf
## The ebseq table is null.
## Working on 9/9: cpcf_wh which is: cp_cf/cp_wh.
## Found inverse table with cp_wh_vs_cp_cf
## The ebseq table is null.
## Adding venn plots for whdt_wt.
## Limma expression coefficients for whdt_wt; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for whdt_wt; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for whdt_wt; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for whcp_wt.
## Limma expression coefficients for whcp_wt; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for whcp_wt; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for whcp_wt; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for whdt_cp.
## Limma expression coefficients for whdt_cp; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for whdt_cp; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for whdt_cp; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for cfdt_wt.
## Limma expression coefficients for cfdt_wt; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for cfdt_wt; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for cfdt_wt; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for cfcp_wt.
## Limma expression coefficients for cfcp_wt; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for cfcp_wt; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for cfcp_wt; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for cfdt_cp.
## Limma expression coefficients for cfdt_cp; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for cfdt_cp; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for cfdt_cp; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for wtcf_wh.
## Limma expression coefficients for wtcf_wh; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for wtcf_wh; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for wtcf_wh; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for dtcf_wh.
## Limma expression coefficients for dtcf_wh; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for dtcf_wh; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for dtcf_wh; R^2: 0.69; equation: y = 0.726x + 1.64
## Adding venn plots for cpcf_wh.
## Limma expression coefficients for cpcf_wh; R^2: 0.566; equation: y = 0.634x + 3.26
## Deseq expression coefficients for cpcf_wh; R^2: 0.674; equation: y = 0.675x + 8.82
## Edger expression coefficients for cpcf_wh; R^2: 0.69; equation: y = 0.726x + 1.64
## Writing summary information, compare_plot is: TRUE.
## Performing save of excel/de_20191210_tables_v20191021.xlsx.

6 Satisfy TODO 20191105

Provide a plot of the ratio of delta(cf/whole) with respect to the ratio of wt(cf/whole)

## Warning in plot_multihistogram(df): NAs introduced by coercion

6.1 Lets see what happens if we rewrite the expressionset with NAs

## In condition wt_wh there are 264 rows which are all zero.
## In condition wt_cf there are 1377 rows which are all zero.
## In condition dt_wh there are 370 rows which are all zero.
## In condition dt_cf there are 1256 rows which are all zero.
## In condition cp_wh there are 269 rows which are all zero.
## In condition cp_cf there are 1291 rows which are all zero.
## Error in write_xls(interesting_nas, excel = "excel/testme_first.xlsx"): could not find function "write_xls"
## Error in write_xls(interesting_nas, excel = "excel/testme_first.xlsx"): could not find function "write_xls"

7 A nice subset request from Volker

Let us pull the following subset from the DE tables for Volker, it should provide a set of proteins most obviously of interest; assuming the false negatives are not too severe.

  1. lfc <= -6 for delta/wt && lfc >= -3 for comp/wt
  2. lfc >= 10 delta/wt && lfc <= 4 comp/wt

This will hopefully find things which are sufficiently different from the deletion and complement samples to be interesting.

9 Request from 20191128

Here is the text of my email:

Query 1: Given existing table of all DE proteins perform the following: a. Take the deseq_logfc for the delta(cf/wh) b. Take the deseq_logfc for the wt(cf/wh) c. Subtract a and b. d. Given c, extract the set which are negative and <= x where x is likely 0.5 at least at first.

Query 2: For the subset acquired in Query 1 do the following: a. Take the deseq_logfc for the delta(cf/wh). b. Take the deseq_logfc for the complement(cf/wh). c. Subtract a and b.

Query 3: For the results of Q1, Q2, plot them as a scatter plot. Take from this the set of genes close than some Z-value.

Focus on one stringency? start with filtered and unfiltered.

Query 4: Plot y axis: cf(delta/comp) Plot x axis: cf(delta/wt)

Query 5: Plot y axis: wh(delta/comp) Plot x axis: wh(delta/wt)

For all of the above use ggplotly (eg. hover plots).

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  -3.985  -0.335   0.030   0.013   0.377   2.842
## [1] 702
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  -4.692  -0.498  -0.071  -0.144   0.280   1.796
## Warning in plot_multihistogram(df): NAs introduced by coercion

## Warning in plot_multihistogram(df): NAs introduced by coercion

## Warning in plot_multihistogram(df): NAs introduced by coercion

## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset ca7dfe3c77056f495da05ef0c95b6208370a23f1commit!
## This is hpgltools commit: Sat Nov 23 19:41:15 2019 -0500: ca7dfe3c77056f495da05ef0c95b6208370a23f1This is hpgltools commit: Sat Nov 23 19:41:15 2019 -0500: commit!
## Saving to 03_swath2stats_20191021-v20191021.rda.xz

R version 3.6.1 (2019-07-05)

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

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

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

other attached packages: edgeR(v.3.28.0), variancePartition(v.1.16.0), ruv(v.0.9.7.1), SWATH2stats(v.1.13.5), testthat(v.2.3.1), hpgltools(v.1.0), Biobase(v.2.46.0) and BiocGenerics(v.0.32.0)

loaded via a namespace (and not attached): rappdirs(v.0.3.1), rtracklayer(v.1.46.0), R.methodsS3(v.1.7.1), tidyr(v.1.0.0), ggplot2(v.3.2.1), acepack(v.1.4.1), bit64(v.0.9-7), knitr(v.1.26), aroma.light(v.3.16.0), DelayedArray(v.0.12.0), R.utils(v.2.9.2), data.table(v.1.12.8), rpart(v.4.1-15), hwriter(v.1.3.2), RCurl(v.1.95-4.12), doParallel(v.1.0.15), GenomicFeatures(v.1.38.0), preprocessCore(v.1.48.0), callr(v.3.4.0), cowplot(v.1.0.0), usethis(v.1.5.1), RSQLite(v.2.1.4), europepmc(v.0.3), bit(v.1.1-14), enrichplot(v.1.6.0), httpuv(v.1.5.2), xml2(v.1.2.2), SummarizedExperiment(v.1.16.0), assertthat(v.0.2.1), viridis(v.0.5.1), xfun(v.0.11), hms(v.0.5.2), promises(v.1.1.0), evaluate(v.0.14), DEoptimR(v.1.0-8), fansi(v.0.4.0), progress(v.1.2.2), caTools(v.1.17.1.3), dbplyr(v.1.4.2), htmlwidgets(v.1.5.1), igraph(v.1.2.4.2), DBI(v.1.0.0), geneplotter(v.1.64.0), EDASeq(v.2.20.0), stats4(v.3.6.1), purrr(v.0.3.3), ellipsis(v.0.3.0), crosstalk(v.1.0.0), selectr(v.0.4-2), dplyr(v.0.8.3), backports(v.1.1.5), annotate(v.1.64.0), biomaRt(v.2.42.0), vctrs(v.0.2.0), remotes(v.2.1.0), BRAIN(v.1.32.0), withr(v.2.1.2), ggforce(v.0.3.1), triebeard(v.0.3.0), robustbase(v.0.93-5), checkmate(v.1.9.4), GenomicAlignments(v.1.22.1), prettyunits(v.1.0.2), cluster(v.2.1.0), DOSE(v.3.12.0), lazyeval(v.0.2.2), crayon(v.1.3.4), genefilter(v.1.68.0), pkgconfig(v.2.0.3), labeling(v.0.3), tweenr(v.1.0.1), GenomeInfoDb(v.1.22.0), nlme(v.3.1-143), PolynomF(v.2.0-2), pkgload(v.1.0.2), nnet(v.7.3-12), devtools(v.2.2.1), rlang(v.0.4.2), lifecycle(v.0.1.0), BiocFileCache(v.1.10.2), directlabels(v.2018.05.22), cellranger(v.1.1.0), rprojroot(v.1.3-2), polyclip(v.1.10-0), matrixStats(v.0.55.0), graph(v.1.64.0), Matrix(v.1.2-18), urltools(v.1.7.3), boot(v.1.3-23), base64enc(v.0.1-3), ggridges(v.0.5.1), processx(v.3.4.1), viridisLite(v.0.3.0), bitops(v.1.0-6), R.oo(v.1.23.0), KernSmooth(v.2.23-16), pander(v.0.6.3), Biostrings(v.2.54.0), blob(v.1.2.0), stringr(v.1.4.0), qvalue(v.2.18.0), ShortRead(v.1.44.0), readr(v.1.3.1), gridGraphics(v.0.4-1), S4Vectors(v.0.24.1), scales(v.1.1.0), memoise(v.1.1.0), magrittr(v.1.5), plyr(v.1.8.5), gplots(v.3.0.1.1), gdata(v.2.18.0), zlibbioc(v.1.32.0), compiler(v.3.6.1), RColorBrewer(v.1.1-2), lme4(v.1.1-21), DESeq2(v.1.26.0), Rsamtools(v.2.2.1), cli(v.2.0.0), XVector(v.0.26.0), ps(v.1.3.0), htmlTable(v.1.13.3), Formula(v.1.2-3), MASS(v.7.3-51.4), mgcv(v.1.8-31), tidyselect(v.0.2.5), stringi(v.1.4.3), yaml(v.2.2.0), GOSemSim(v.2.12.0), askpass(v.1.1), locfit(v.1.5-9.1), latticeExtra(v.0.6-28), ggrepel(v.0.8.1), grid(v.3.6.1), fastmatch(v.1.1-0), tools(v.3.6.1), rstudioapi(v.0.10), foreach(v.1.4.7), foreign(v.0.8-72), gridExtra(v.2.3), farver(v.2.0.1), Rtsne(v.0.15), ggraph(v.2.0.0), digest(v.0.6.23), rvcheck(v.0.1.7), BiocManager(v.1.30.10), shiny(v.1.4.0), quadprog(v.1.5-8), Rcpp(v.1.0.3), GenomicRanges(v.1.38.0), later(v.1.0.0), httr(v.1.4.1), AnnotationDbi(v.1.48.0), colorspace(v.1.4-1), rvest(v.0.3.5), XML(v.3.98-1.20), fs(v.1.3.1), IRanges(v.2.20.1), splines(v.3.6.1), RBGL(v.1.62.1), graphlayouts(v.0.5.0), ggplotify(v.0.0.4), plotly(v.4.9.1), sessioninfo(v.1.1.1), xtable(v.1.8-4), jsonlite(v.1.6), nloptr(v.1.2.1), tidygraph(v.1.1.2), corpcor(v.1.6.9), zeallot(v.0.1.0), Vennerable(v.3.1.0.9000), R6(v.2.4.1), Hmisc(v.4.3-0), mime(v.0.7), pillar(v.1.4.2), htmltools(v.0.4.0), fastmap(v.1.0.1), glue(v.1.3.1), minqa(v.1.2.4), clusterProfiler(v.3.14.0), BiocParallel(v.1.20.0), DESeq(v.1.38.0), RUVSeq(v.1.20.0), codetools(v.0.2-16), fgsea(v.1.12.0), pkgbuild(v.1.0.6), lattice(v.0.20-38), tibble(v.2.1.3), sva(v.3.34.0), pbkrtest(v.0.4-7), curl(v.4.3), colorRamps(v.2.3), gtools(v.3.8.1), zip(v.2.0.4), GO.db(v.3.10.0), openxlsx(v.4.1.4), openssl(v.1.4.1), survival(v.3.1-8), limma(v.3.42.0), rmarkdown(v.1.18), desc(v.1.2.0), readODS(v.1.6.7), munsell(v.0.5.0), DO.db(v.2.9), fastcluster(v.1.1.25), GenomeInfoDbData(v.1.2.2), iterators(v.1.0.12), reshape2(v.1.4.3) and gtable(v.0.3.0)

LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxOTEwMjE6IEFsbCBTYW1wbGVzIE9wZW5Td2F0aFdvcmtGbG93L1RSSUMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCIvZGF0YS9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldCh3aWR0aD0xMjAsCiAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgZWNobz1UUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplPTEwKSkKcHJldmlvdXNfZmlsZSA8LSAiMDFfYW5ub3RhdGlvbl8yMDE5MDgwMS5SbWQiCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdD0iJVklbSVkIikKdmVyIDwtICIyMDE5MDgwMSIKdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCnZlciA8LSAiMjAxOTEwMjEiCgpybWRfZmlsZSA8LSBwYXN0ZTAoIjAzX3N3YXRoMnN0YXRzXyIsIHZlciwgIi5SbWQiKQpzYXZlZmlsZSA8LSBnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IlxcLnJkYVxcLnh6IiwgeD1ybWRfZmlsZSkKYGBgCgpBbmFseXppbmcgZGF0YSBmcm9tIG9wZW5NUyBhbmQgZnJpZW5kcy4KPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIyBTV0FUSDJzdGF0cyBwcmVwcm9jZXNzaW5nCgpJIGFtIHVzaW5nIG15IHNsaWdodGx5IG1vZGlmaWVkIGNvcHkgb2YgU1dBVEgyc3RhdHMuICBUaGlzIHNlZWtzIHRvIGVuc3VyZSB0aGF0CmNoYW5nZXMgaW4gdGhlIGNhc2Ugb2YgY29sdW1ucyBpbiB0aGUgbWV0YWRhdGEgZnJvbSBvbmUgdmVyc2lvbiBvZiBPcGVuTVMgdG8KYW5vdGhlciBkbyBub3QgdHJvdWJsZSBtZS4KCiMjIyBDcmVhdGluZyBhIHN3YXRoMnN0YXRzIGV4cGVyaW1lbnQgdXNpbmcgdGhlIHR1YmVyY3VsaXN0LWRlcml2ZWQgbGlicmFyeSBkYXRhCgpUaGVyZSBpcyBvbmUgaW1wb3J0YW50IGNhdmVhdCBpbiB0aGUgZm9sbG93aW5nIGJsb2NrOiBJIHVzZWQgYSByZWdleCB0byByZW1vdmUKdGhlIHNlY29uZCBoYWxmIG9mIGdlbmVJRF9nZW5lTmFtZSBzbyB0aGF0IGxhdGVyIHdoZW4gSSBtZXJnZSBpbiB0aGUgYW5ub3RhdGlvbgpkYXRhIEkgaGF2ZSBpdCB3aWxsIG1hdGNoLgoKIyMgU29tZSBuZXcgcGxvdHMKCkluIHJlc3BvbnNlIHRvIHNvbWUgaW50ZXJlc3RpbmcgcXVlcmllcyBmcm9tIFlhbiwgSSBtYWRlIGEgZmV3IGxpdHRsZSBmdW5jdGlvbnMKd2hpY2ggcXVlcnkgYW5kIHBsb3QgZGF0YSBmcm9tIHRoZSBzY29yZWQgZGF0YSBwcm92aWRlZCBieSBvcGVuc3dhdGgvcHlwcm9waGV0LgpMZXQgdXMgbG9vayBhdCB0aGVpciByZXN1bHRzIGhlcmUuCgpgYGB7ciB0Yl9weXByb3BoZXRfcGxvdHN9CnB5cF9tZXRhZGF0YSA8LSBnbHVlOjpnbHVlKCJzYW1wbGVfc2hlZXRzL010Yl9kaWFfc2FtcGxlc197dmVyfS5vZHMiKQpweXByb3BoZXRfZnVuIDwtIHNtKGV4dHJhY3RfcHlwcm9waGV0X2RhdGEobWV0YWRhdGE9cHlwX21ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHlwcm9waGV0X2NvbHVtbj0iZGlhc2NvcmVkIikpCiMjIFZpc3VhbGl6ZSB0aGUgbWFzcyBkaXN0cmlidXRpb25zIG9mIGVhY2ggc2FtcGxlCm1hc3NfcGxvdCA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24ocHlwcm9waGV0X2Z1biwgY29sdW1uPSJtYXNzIikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2FsbF9tYXNzZXNfb2JzZXJ2ZWQtdnt2ZXJ9LnBuZyIpLAogICAgICAgICAgICAgICAgICAgaW1hZ2U9bWFzc19wbG90W1sidmlvbGluIl1dKQojIyBUaGF0IHNlY29uZCB0byBsYXN0IHNhbXBsZSBsb29rcyBwcmV0dHkgb2RkLgoKIyMgTG9vayBhdCB0aGUgZGVsdGEgcnQgdGltZXMgb2JzZXJ2ZWQuICBJIGFtIGNvbnRpbnVhbGx5IHB1enpsZWQgYXMgdG8gd2h5IHRoZXNlIG51bWJlcnMKIyMgZ2V0IHNvIGhpZ2guICBJIHN1c3BlY3QgdGhlIGFjdHVhbCByZWFzb24gaXMgdGhhdCBJIGRvIG5vdCB1bmRlcnN0YW5kIHRoaXMgY29sdW1uIGluIHRoZQojIyBkYXRhLCBidXQgZmluZGluZyByZWxpYWJsZSBkb2N1bWVudGF0aW9uIGlzIG5vbi10cml2aWFsLCBJIGp1c3QgYmxldyA0NSBtaW51dGVzIChyZSlyZWFkaW5nCiMjIGEgY291cGxlIG9mIHJldmlld3MgYW5kIHNvbWUgcGFwZXJzIGluIHdoaWNoIEkgdGhvdWdodCBJIHNhdyByZWxldmFudCBpbmZvcm1hdGlvbgojIyBhbmQgZm91bmQgbm90aGluZy4KZGVsdGFydF9wbG90X2FsbCA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24oCiAgcHlwcm9waGV0X2Z1biwgY29sdW1uPSJkZWx0YV9ydCIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy9hbGxfZHJ0X29ic2VydmVkLXZ7dmVyfS5wbmciKSwKICAgaW1hZ2U9ZGVsdGFydF9wbG90X2FsbFtbInZpb2xpbiJdXSkKCgpkZWx0YXJ0X3Bsb3RfYWxsIDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBzY2FsZT1UUlVFLAogIHB5cHJvcGhldF9mdW4sIGNvbHVtbj0iaW50ZW5zaXR5IikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2FsbF9pbnRlbnNpdGllc19vYnNlcnZlZC12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWRlbHRhcnRfcGxvdF9hbGxbWyJ2aW9saW4iXV0pCgojIyBUaGlzIHBsb3QgaXMgdGhlIHNhbWUgYXMgYWJvdmUsIGJ1dCBpbmNsdWRlcyBfb25seV8gdGhlIG5vbi1kZWNveSB2YWx1ZXMuCmRlbHRhcnRfcGxvdF9yZWFsIDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBweXByb3BoZXRfZnVuLAogIGNvbHVtbj0iZGVsdGFfcnQiLCBrZWVwX2RlY295cz1GQUxTRSkpCmRlbHRhcnRfcGxvdF9yZWFsW1sidmlvbGluIl1dCiMjIEFuZCB0aGlzIHRpbWUgd2UgaGF2ZSBfb25seV8gdGhlIGRlY295cy4gIEkgYW0gbm90IHJlYWxseSBzdXJlIHdoYXQgb25lIHNob3VsZCBleHBlY3QgaW4KIyMgdGhlc2UsIGJ1dCB0aGUgZGlmZmVyZW5jZXMgYXJlIGRlZmluaXRlbHkgaW50cmlndWluZy4KZGVsdGFydF9wbG90X2RlY295cyA8LSBzbShwbG90X3B5cHJvcGhldF9kaXN0cmlidXRpb24oCiAgcHlwcm9waGV0X2Z1biwKICBjb2x1bW49ImRlbHRhX3J0Iiwga2VlcF9yZWFsPUZBTFNFKSkKZGVsdGFydF9wbG90X2RlY295c1tbInZpb2xpbiJdXQoKZHNjb3JlX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKAogIHB5cHJvcGhldF9mdW4sCiAgY29sdW1uPSJkX3Njb3JlIikpCmRzY29yZV9wbG90W1sidmlvbGluIl1dCgpkc2NvcmVfcGxvdF9ub2RlY295IDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBweXByb3BoZXRfZnVuLCBrZWVwX2RlY295cz1GQUxTRSwKICBjb2x1bW49ImRfc2NvcmUiKSkKZHNjb3JlX3Bsb3Rfbm9kZWNveVtbInZpb2xpbiJdXQoKbXNjb3JlX3Bsb3QgPC0gc20ocGxvdF9weXByb3BoZXRfZGlzdHJpYnV0aW9uKAogIHB5cHJvcGhldF9mdW4sIGtlZXBfZGVjb3lzPUZBTFNFLAogIGNvbHVtbj0ibV9zY29yZSIpKQptc2NvcmVfcGxvdFtbInZpb2xpbiJdXQptc2NvcmVfcGxvdF9ub2RlY295IDwtIHNtKHBsb3RfcHlwcm9waGV0X2Rpc3RyaWJ1dGlvbigKICBweXByb3BoZXRfZnVuLCBrZWVwX2RlY295cz1GQUxTRSwKICBjb2x1bW49Im1fc2NvcmUiKSkKbXNjb3JlX3Bsb3Rfbm9kZWNveVtbInZpb2xpbiJdXQoKIyMgSG93IG1hbnkgaWRlbnRpZmljYXRpb25zIHdlcmUgb2JzZXJ2ZWQgaW4gZWFjaCBzYW1wbGU/CnB5cHJvcGhldF9pZGVudGlmaWNhdGlvbnMgPC0gc20ocGxvdF9weXByb3BoZXRfY291bnRzKAogIHB5cHJvcGhldF9mdW4sIGtlZXBfZGVjb3lzPUZBTFNFLAogIHR5cGU9ImNvdW50IikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2FsbF9wZXB0aWRlX2lkZW50aWZpY2F0aW9ucy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPXB5cHJvcGhldF9pZGVudGlmaWNhdGlvbnMkcGxvdCkKcHlwcm9waGV0X2lkZW50aWZpY2F0aW9ucyA8LSBzbShwbG90X3B5cHJvcGhldF9jb3VudHMoCiAgcHlwcm9waGV0X2Z1biwga2VlcF9kZWNveXM9RkFMU0UsCiAgdHlwZT0icHJvdGVpbl9jb3VudCIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy9hbGxfcHJvdGVpbl9pZGVudGlmaWNhdGlvbnMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1weXByb3BoZXRfaWRlbnRpZmljYXRpb25zJHBsb3QpCgojIyBUaGUgcmFuZ2UgaW4gdmFsdWVzIGlzIGEgbGl0dGxlIHN1cnByaXNpbmcgdG8gbWUsIGJ1dCBJIGRvIG5vdAojIyB0aGluayBpdCBpcyBjcmF6eXRvd24uCgojIyBTdW0oaW50ZW5zaXR5KSB2cy4gc3VtKGlkZW50aWZpY2F0aW9ucykuICBXZSBzYXcgaW4gYSBwcmV2aW91cyBwbG90IHRoYXQgc2FtcGxlCiMjIDE3IHdhcyBvZGQsIHNvIEkgd291bGQgc29ydCBvZiBleHBlY3QgaXQgdG8gYmUgZmFyIGF3YXkgb24gdGhpcyBwbG90PwpweXByb3BoZXRfeHkgPC0gc20ocGxvdF9weXByb3BoZXRfeHkoCiAgcHlwcm9waGV0X2Z1biwKICB4X3R5cGU9ImNvdW50IiwgeV90eXBlPSJpbnRlbnNpdHkiKSkKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvYWxsX2NvdW50c192c19pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPXB5cHJvcGhldF94eSkKIyMgaG1tIEkgZG8gbm90IHNlZSBhIHN0cm9uZyB0cmVuZAoKcHlwcm9waGV0X3h5IDwtIHNtKHBsb3RfcHlwcm9waGV0X3BvaW50cygKICBweXByb3BoZXRfZnVuLCBhbHBoYT0wLjcsIGNvbG9yX2J5PSJjb25kaXRpb24iLCBsZWdlbmQ9RkFMU0UsCiAgc2FtcGxlPWMoIjIwMTlfMDgwMUJyaWtlbjA0IiwgIjIwMTlfMDcwOUJyaWtlbjAxIiksCiAgeGF4aXM9ImRfc2NvcmUiLCB5YXhpcz0ibWFzcyIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy90d29fc2FtcGxlc193Y19jZl9kc2NvcmVfbWFzcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPXB5cHJvcGhldF94eSRwbG90KQoKcHlwcm9waGV0X3h5IDwtIHNtKHBsb3RfcHlwcm9waGV0X3BvaW50cygKICBweXByb3BoZXRfZnVuLCBhbHBoYT0wLjMsIGNvbG9yX2J5PSJjb25kaXRpb24iLCBsZWdlbmQ9RkFMU0UsCiAgc2FtcGxlPWMoIjIwMTlfMDgwMUJyaWtlbjA0IiwgIjIwMTlfMDcwOUJyaWtlbjAxIiksCiAgeGF4aXM9Im16IiwgeWF4aXM9ImxlZnR3aWR0aCIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy90d29fc2FtcGxlc19tYXNzX3J0LXZ7dmVyfS5wbmciKSwKICAgaW1hZ2U9cHlwcm9waGV0X3h5JHBsb3QpCgpweXByb3BoZXRfeHkgPC0gc20ocGxvdF9weXByb3BoZXRfcG9pbnRzKAogIHB5cHJvcGhldF9mdW4sIGFscGhhPTAuNCwgY29sb3JfYnk9ImNvbmRpdGlvbiIsIGxlZ2VuZD1GQUxTRSwKICBzYW1wbGU9YygiMjAxOV8wODAxQnJpa2VuMDQiLCAiMjAxOV8wNzA5QnJpa2VuMDEiKSwgeXNjYWxlPSJsb2cyIiwKICB4YXhpcz0ibWFzcyIsIHlheGlzPSJpbnRlbnNpdHkiKSkKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvdHdvX3NhbXBsZXNfd2NfY2ZfaW50ZW5zaXR5X21hc3Mtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1weXByb3BoZXRfeHkkcGxvdCkKCnB5cHJvcGhldF94eSA8LSBzbShwbG90X3B5cHJvcGhldF9wb2ludHMoCiAgcHlwcm9waGV0X2Z1biwgYWxwaGE9MC4zLCBjb2xvcl9ieT0iY29uZGl0aW9uIiwgbGVnZW5kPUZBTFNFLAogIHNhbXBsZT1jKCIyMDE5XzA4MDFCcmlrZW4wNCIsICIyMDE5XzA3MDlCcmlrZW4wMSIpLAogIHhheGlzPSJydCIsIHlheGlzPSJtX3Njb3JlIikpCnB5cHJvcGhldF94eSRwbG90CnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL3R3b19zYW1wbGVzX3djX2NmX3J0X21zY29yZS12e3Zlcn0ucG5nIiksCiAgIGltYWdlPXB5cHJvcGhldF94eSRwbG90KQoKcHlwcm9waGV0X3h5IDwtIHNtKHBsb3RfcHlwcm9waGV0X3BvaW50cygKICBweXByb3BoZXRfZnVuLCBhbHBoYT0wLjMsIGNvbG9yX2J5PSJjb25kaXRpb24iLCBsZWdlbmQ9RkFMU0UsCiAgc2FtcGxlPWMoIjIwMTlfMDgwMUJyaWtlbjA0IiwgIjIwMTlfMDcwOUJyaWtlbjAxIiksCiAgeGF4aXM9ImFzc2F5X3J0IiwgeWF4aXM9ImxlZnR3aWR0aCIsIHhfc2NhbGU9ImxvZzIiLCB5X3NjYWxlPSJsb2cyIikpCnB5cHJvcGhldF94eSRwbG90CnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL3R3b19zYW1wbGVzX3djX2NmX3J0X3dpZHRoLXZ7dmVyfS5wbmciKSwKICAgaW1hZ2U9cHlwcm9waGV0X3h5JHBsb3QpCgpweXByb3BoZXRfeHkgPC0gc20ocGxvdF9weXByb3BoZXRfcG9pbnRzKAogIHB5cHJvcGhldF9mdW4sIGFscGhhPTAuMywgY29sb3JfYnk9ImNvbmRpdGlvbiIsIGxlZ2VuZD1GQUxTRSwKICBzYW1wbGU9YygiMjAxOV8wODAxQnJpa2VuMDQiLCAiMjAxOV8wNzA5QnJpa2VuMDEiKSwKICB4YXhpcz0ibXoiLCB5YXhpcz0iYXNzYXlfcnQiKSkKcHlwcm9waGV0X3h5JHBsb3QKCiMjIFRoaXMgaGFzIHNvIGZhciBiZWVuIGEgcHJldHR5IHJlbGlhYmxlIHBsb3QgdG8gc2hvdyB0aGF0IHRoZSBvYnNlcnZlZCBwZWFrIHdpZHRocyBhcmUKIyMgdmVyeSBjb25zaXN0ZW50IGFjcm9zcyBzYW1wbGVzLgpweXByb3BoZXRfbHdpZHRocyA8LSBzbShwbG90X3B5cHJvcGhldF94eSgKICBweXByb3BoZXRfZnVuLAogIHhfdHlwZT0iY291bnQiLCB5X3R5cGU9ImxlZnR3aWR0aCIpKQpwcChmaWxlPSJpbWFnZXMvd2hvbGVfbHdpZHRoc192c19jb3VudHMucG5nIiwgaW1hZ2U9cHlwcm9waGV0X2x3aWR0aHMpCiMjIEluIHRoaXMgY2FzZSwgd2UgY2FuIHNlZSBzdHJvbmdseSB0aGF0IHNhbXBsZSAjMTcgaXMgc3RyYW5nZS4KYGBgCgojIyBTaG93IGEgc2VyaWVzIG9mIGFsbCBpZGVudGlmaWNhdGlvbnMgZm9yIG1hcmtlciBwcm90ZWlucwoKVGhlcmUgYXJlIGEgZmV3IHByb3RlaW5zIGZvciB3aGljaCBWb2xrZXIgaGFzIHJlbGF0aXZlbHkgc3BlY2lmaWMKYXNzdW1wdGlvbnMvZXhwZWN0YXRpb25zLiAgTGV0IHVzIHNlZSB3aGF0IHRoZXkgbG9vayBsaWtlIGFuZCBpZiB0aGV5IGZvbGxvdyBhCnRyZW5kIHdoaWNoIG1ha2VzIHNvbWUgc2Vuc2UuLi4KClRoZSBwcmltYXJ5IHRoaW5nIHRvIHJlY2FsbCwgSSB0aGluaywgaXMgdGhhdCBpbiBvdXIgcHJldmlvdXMgZGF0YSBzZXRzLCB0aGVyZQp3ZXJlIGEgcHJldHR5IGxhcmdlIG51bWJlciBvZiBzYW1wbGVzIGZvciB3aGljaCBubyBpZGVudGlmaWNhdGlvbnMgd2VyZSBtYWRlIGZvcgptYW55IG9mIHRoZXNlIHByb3RlaW5zLiAgRG9lcyB0aGF0IHJlbWFpbiB0cnVlPwoKIyMgR3JhYiBhbm5vdGF0aW9ucwoKYGBge3IgbXRiX2Fubm90YXRpb25zfQojIyBUaGUgb2xkIHdheSBvZiBnZXR0aW5nIGdlbm9tZS9hbm5vdGF0aW9uIGRhdGEKbXRiX2dmZiA8LSAicmVmZXJlbmNlL215Y29iYWN0ZXJpdW1fdHViZXJjdWxvc2lzX2gzN3J2XzIuZ2ZmLmd6IgptdGJfZ2Vub21lIDwtICJyZWZlcmVuY2UvbXR1YmVyY3Vsb3Npc19oMzdydl9nZW5iYW5rLmZhc3RhIgptdGJfY2RzIDwtICJyZWZlcmVuY2UvbXRiX2Nkcy5mYXN0YSIKCm10Yl9hbm5vdGF0aW9ucyA8LSBzbShsb2FkX2dmZl9hbm5vdGF0aW9ucyhtdGJfZ2ZmLCB0eXBlPSJnZW5lIikpCmNvbG5hbWVzKG10Yl9hbm5vdGF0aW9ucykgPC0gZ3N1YihwYXR0ZXJuPSJcXC4iLCByZXBsYWNlbWVudD0iIiwgeD1jb2xuYW1lcyhtdGJfYW5ub3RhdGlvbnMpKQptdGJfYW5ub3RhdGlvbnNbWyJkZXNjcmlwdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImRlc2NyaXB0aW9uIl1dKQptdGJfYW5ub3RhdGlvbnNbWyJmdW5jdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImZ1bmN0aW9uIl1dKQoKbXRiX21pY3JvYmVzIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfYW5ub3RhdGlvbnMoaWQ9ODMzMzIpCm10Yl9hbm5vdGF0aW9ucyA8LSBtZXJnZShtdGJfYW5ub3RhdGlvbnMsIG10Yl9taWNyb2JlcywKICAgICAgICAgICAgICAgICAgICAgICAgIGJ5Lng9IklEIiwgYnkueT0ic3lzTmFtZSIpCnJvd25hbWVzKG10Yl9hbm5vdGF0aW9ucykgPC0gbXRiX2Fubm90YXRpb25zW1siSUQiXV0KbXRiX2Fubm90YXRpb25zW1sid2lkdGgiXV0gPC0gYWJzKG10Yl9hbm5vdGF0aW9uc1tbInN0YXJ0LnkiXV0gLSBtdGJfYW5ub3RhdGlvbnNbWyJzdG9wIl1dKQpgYGAKCkkgd2lsbCB1c2UgdGhlIGFubm90YXRpb25zIHRvIG1ha2UgZmluZGluZyB0aGUgY29ycmVjdCBwcm90ZWluIElEcyBlYXNpZXIuCgpgYGB7ciBwbG90X2luZGl2aWR1YWxfcHJvdGVpbnN9CmdlbmVfeHJlZiA8LSBtdGJfYW5ub3RhdGlvbnNbLCBjKCJnZW5lIiwgIm5hbWUiLCAiZGVzY3JpcHRpb24iKV0KCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJlc3hHIiwgXQppbnRlbnNpdGllc19lc3hHIDwtIHNtKHBsb3RfcHlwcm9waGV0X3Byb3RlaW4ocHlwcm9waGV0X2Z1biwgc2NhbGU9ImxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iZXN4RyBJbnRlbnNpdGllcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MDI4NyIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy93aG9sZV9vc3dfZXN4R19pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2VzeEcpCiMjIElzIHRoaXMgYSBnb29kIG9yIHRlcnJpYmxlIHNwcmVhZCBvZiBvYnNlcnZlZCBpbnRlbnNpdGllcyBmb3IgcHJvdGVvbWljcyBkYXRhPwojIyBJZiBJIGZvdW5kIGEgcmFuZ2UgbGlrZSB0aGlzIGluIFJOQVNlcSBkYXRhLCBJIHdvdWxkIGp1c3QgdGhyb3cgaXQgYXdheSBvdXQgb2YgaGFuZC4KIyMgU2FtcGxlIDE3IGRpZCBub3QgaGF2ZSBhbnkgb2JzZXJ2YXRpb25zLCBidXQgZXZlcnl0aGluZyBlbHNlIGRpZC4KCiMjIFRoZSByYW5nZSBvZiBkUlQgdmFsdWVzLiBJIHdpc2ggdGhpcyBtZXRyaWMgbWFkZSBzZW5zZSB0byBtZSEKZHJ0X2VzeEcgPC0gc20ocGxvdF9weXByb3BoZXRfcHJvdGVpbihweXByb3BoZXRfZnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbj0iZGVsdGFfcnQiLCBwcm90ZWluPSJSdjAyODciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl9kYXRhPTEwMCwgbWF4X2RhdGE9MTAwMCkpCmRydF9lc3hHCgpnZW5lX3hyZWZbZ2VuZV94cmVmW1sibmFtZSJdXSA9PSAiZXN4SCIsIF0KaW50ZW5zaXRpZXNfZXN4SCA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKAogIHB5cHJvcGhldF9mdW4sCiAgdGl0bGU9ImVzeEggSW50ZW5zaXRpZXMiLAogIHNjYWxlPSJsb2ciLCBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MDI4OCIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy93aG9sZV9vc3dfZXN4SF9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2VzeEgpCiMjIEFsbCBzYW1wbGVzIGhhdmUgb2JzZXJ2YXRpb25zLCBidXQgYSBiaXQgc3BhcnNlci4KCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJscHFIIiwgXQppbnRlbnNpdGllc19scHFIIDwtIHNtKHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwgc2NhbGU9ImxvZyIsCiAgdGl0bGU9ImxwcUhfaW50ZW5zaXRpZXMiLCBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2Mzc2MyIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy93aG9sZV9vc3dfbHBxaF9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2xwcUgpCiMjIFZlcnkgZmV3IG9ic2VydmF0aW9ucywgYnV0IHRoZXkgYXJlIHJlbGF0aXZlbHkgY29uc2lzdGVudD8KCmludGVuc2l0aWVzX2dyb2VsMSA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKHB5cHJvcGhldF9mdW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPSJncm9FTDEgaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uPSJpbnRlbnNpdHkiLCBwcm90ZWluPSJSdjM0MTciKSkKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvd2hvbGVfb3N3X2dyb2VsMV9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2dyb2VsMSkKCmludGVuc2l0aWVzX2dyb2VsMiA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKAogIHB5cHJvcGhldF9mdW4sCiAgdGl0bGU9Imdyb0VMMiBpbnRlbnNpdGllcyIsIHNjYWxlPSJsb2ciLAogIGNvbHVtbj0iaW50ZW5zaXR5IiwgcHJvdGVpbj0iUnYwNDQwIikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL3dob2xlX29zd19ncm9lbDJfaW50ZW5zaXRpZXMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1pbnRlbnNpdGllc19ncm9lbDIpCiMjIE1hbiBJIGFtIGxvdmluZyB0aGUgZGVuc2l0eSBvZiBvYnNlcnZhdGlvbiwgYnV0IEkgd2lzaCB0aGV5IHdlcmUgbW9yZSBjb25zaXN0ZW50IQojIyBBbHNvLCBzYW1wbGUgMTcgaXMgc3BhcnNlci4KCmdlbmVfeHJlZltyb3duYW1lcyhnZW5lX3hyZWYpID09ICJSdjE4NjAiLCBdCmludGVuc2l0aWVzX2ZhcCA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKAogIHB5cHJvcGhldF9mdW4sCiAgdGl0bGU9ImZhcCBpbnRlbnNpdGllcyIsIHNjYWxlPSJsb2ciLAogIGNvbHVtbj0iaW50ZW5zaXR5IiwgcHJvdGVpbj0iUnYxODYwIikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL3dob2xlX29zd19mYXBfaW50ZW5zaXRpZXMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1pbnRlbnNpdGllc19mYXApCiMjIFNhbXBsZSAxNyBpcyBiYXNpY2FsbHkgYSBudWxsLgoKaW50ZW5zaXRpZXNfa2F0ZyA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKAogIHB5cHJvcGhldF9mdW4sCiAgdGl0bGU9IlBQRTEgKFJ2MDA5NikgaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MDA5NiIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy93aG9sZV9vc3dfcHBlMV9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2thdGcpCiMjIFdoYXQgaXMgdXAgd2l0aCB0aGF0IG9uZSwgd2VpcmRseSBsb3csIG9ic2VydmF0aW9uIGZvciBlYWNoIHNhbXBsZT8KCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJrYXRHIiwgXQppbnRlbnNpdGllc19rYXRnIDwtIHNtKHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwKICB0aXRsZT0ia2F0RyBpbnRlbnNpdGllcyIsIHNjYWxlPSJsb2ciLAogIGNvbHVtbj0iaW50ZW5zaXR5IiwgcHJvdGVpbj0iUnYxOTA4YyIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy93aG9sZV9vc3dfa2F0Z19pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWludGVuc2l0aWVzX2thdGcpCgpnZW5lX3hyZWZbZ2VuZV94cmVmW1sibmFtZSJdXSA9PSAiUFBFNDEiLCBdCnBwZTQxX2ludGVuc2l0aWVzIDwtIHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwKICB0aXRsZT0iUFBFNDEgKFJ2MjQzMGMpIGludGVuc2l0aWVzIiwgc2NhbGU9ImxvZyIsCiAgY29sdW1uPSJpbnRlbnNpdHkiLCBwcm90ZWluPSJSdjI0MzBjIikKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvUFBFNDFfaW50ZW5zaXRpZXMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1wcGU0MV9pbnRlbnNpdGllcykKCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJQRTI1IiwgXQpwZTI1X2ludGVuc2l0aWVzIDwtIHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwgc2hvd19hbGw9VFJVRSwKICB0aXRsZT0iUEUyNSAoUnYyNDMxYykgaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MjQzMWMiKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy9QRTI1X2ludGVuc2l0aWVzLXZ7dmVyfS5wbmciKSwKICAgaW1hZ2U9cGUyNV9pbnRlbnNpdGllcykKCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJQRTMxIiwgXQpwZTMxX2ludGVuc2l0aWVzIDwtIHNtKHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwKICB0aXRsZT0iUEUzMSAoUnYzNDc3KSBpbnRlbnNpdGllcyIsIHNjYWxlPSJsb2ciLAogIGNvbHVtbj0iaW50ZW5zaXR5IiwgcHJvdGVpbj0iUnYzNDc3IikpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL1BFMzFfaW50ZW5zaXRpZXMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1wZTMxX2ludGVuc2l0aWVzKQoKZ2VuZV94cmVmW2dlbmVfeHJlZltbIm5hbWUiXV0gPT0gImVzeEgiLCBdCmVzeEhfaW50ZW5zaXRpZXMgPC0gc20ocGxvdF9weXByb3BoZXRfcHJvdGVpbigKICBweXByb3BoZXRfZnVuLAogIHRpdGxlPSJlc3hIIChSdjAyODgpIGludGVuc2l0aWVzIiwgc2NhbGU9ImxvZyIsCiAgY29sdW1uPSJpbnRlbnNpdHkiLCBwcm90ZWluPSJSdjAyODgiKSkKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvZXN4SF9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWVzeEhfaW50ZW5zaXRpZXMpCgpnZW5lX3hyZWZbZ2VuZV94cmVmW1sibmFtZSJdXSA9PSAiUnYxNzQ4IiwgXQpSdjE3NDhfaW50ZW5zaXRpZXMgPC0gc20ocGxvdF9weXByb3BoZXRfcHJvdGVpbigKICBweXByb3BoZXRfZnVuLAogIHRpdGxlPSJSdjE3NDggaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MTc0OCIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy9SdjE3NDhfaW50ZW5zaXRpZXMtdnt2ZXJ9LnBuZyIpLAogICBpbWFnZT1SdjE3NDhfaW50ZW5zaXRpZXMpCgpnZW5lX3hyZWZbZ2VuZV94cmVmW1sibmFtZSJdXSA9PSAicGtuRiIsIF0KcGtuRl9pbnRlbnNpdGllcyA8LSBzbShwbG90X3B5cHJvcGhldF9wcm90ZWluKAogIHB5cHJvcGhldF9mdW4sCiAgdGl0bGU9InBrbkYgKFJ2MTc0NikgaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MTc0NiIpKQpwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy9wa25GX2ludGVuc2l0aWVzLXZ7dmVyfS5wbmciKSwKICAgaW1hZ2U9cGtuRl9pbnRlbnNpdGllcykKCmdlbmVfeHJlZltnZW5lX3hyZWZbWyJuYW1lIl1dID09ICJwa25HIiwgXQpwa25HX2ludGVuc2l0aWVzIDwtIHNtKHBsb3RfcHlwcm9waGV0X3Byb3RlaW4oCiAgcHlwcm9waGV0X2Z1biwKICB0aXRsZT0icGtuRyAoUnYwNDEwYykgaW50ZW5zaXRpZXMiLCBzY2FsZT0ibG9nIiwKICBjb2x1bW49ImludGVuc2l0eSIsIHByb3RlaW49IlJ2MDQxMGMiKSkKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvcGtuR19pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksCiAgIGltYWdlPXBrbkdfaW50ZW5zaXRpZXMpCmBgYAoKIyBTdGFydCBTV0FUSDJzdGF0cwoKSSB3YW50IHRvIGxvYWQgdGhlIGRhdGEgYW5kIG1ldGFkYXRhIGludG8gU1dBVEgyc3RhdHMgaW4gcHJlcGFyYXRpb24gZm9yIE1Tc3RhdHMKYW5kIG15IG93biBocGdsdG9vbHMtYmFzZSBhbmFseXNlcy4KCmBgYHtyIHRiX3N3YXRoMnN0YXRzX2luaXRpYWx9CmNmX3ZlcnNpb24gPC0gIjIwMTkwNzE4IgpjZl90cmljX2ZpbGUgPC0gZmlsZS5wYXRoKCJwcmVwcm9jZXNzaW5nIiwgIjA5dHJpYyIsIGNmX3ZlcnNpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIndob2xlXzhtel90dWJlcmN1bGlzdCIsICJjb21ldF9IQ0QudHN2IikKY2ZfdHJpY19kYXRhIDwtIHJlYWRyOjpyZWFkX3RzdihjZl90cmljX2ZpbGUpCmNmX3RyaWNfZGF0YVtbIlByb3RlaW5OYW1lIl1dIDwtIGdzdWIocGF0dGVybj0iXiguKilfLiokIiwgcmVwbGFjZW1lbnQ9IlxcMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD1jZl90cmljX2RhdGFbWyJQcm90ZWluTmFtZSJdXSkKd2NfdmVyc2lvbiA8LSAiMjAxOTA4MDEiCndjX3RyaWNfZmlsZSA8LSBmaWxlLnBhdGgoInByZXByb2Nlc3NpbmciLCAiMDl0cmljIiwgd2NfdmVyc2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAid2hvbGVfOG16X3R1YmVyY3VsaXN0IiwgImNvbWV0X0hDRC50c3YiKQp3Y190cmljX2RhdGEgPC0gcmVhZHI6OnJlYWRfdHN2KHdjX3RyaWNfZmlsZSkKd2NfdHJpY19kYXRhW1siUHJvdGVpbk5hbWUiXV0gPC0gZ3N1YihwYXR0ZXJuPSJeKC4qKV8uKiQiLCByZXBsYWNlbWVudD0iXFwxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PXdjX3RyaWNfZGF0YVtbIlByb3RlaW5OYW1lIl1dKQp0cmljX2RhdGEgPC0gcmJpbmQod2NfdHJpY19kYXRhLCBjZl90cmljX2RhdGEpCnNhbXBsZV9zaGVldCA8LSBmaWxlLnBhdGgoInNhbXBsZV9zaGVldHMiLCBnbHVlOjpnbHVlKCJNdGJfZGlhX3NhbXBsZXNfe3Zlcn0ub2RzIikpCnNhbXBsZV9hbm5vdCA8LSBleHRyYWN0X21ldGFkYXRhKHNhbXBsZV9zaGVldCkKIyMgQSB3ZWlyZCB0aGluZyBpcyBoYXBwZW5pbmcgd2l0aCBjb2x1bW4gbmFtZXMsIEkgd2lsbCBjaGFzZSBpdCBkb3duIGxhdGVyLgpjb2xuYW1lcyhzYW1wbGVfYW5ub3QpIDwtIGdzdWIoeD1jb2xuYW1lcyhzYW1wbGVfYW5ub3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybj0iW1s6cHVuY3Q6XV0iLCByZXBsYWNlPSIiKQprZXB0IDwtICEgZ3JlcGwoeD1yb3duYW1lcyhzYW1wbGVfYW5ub3QpLCBwYXR0ZXJuPSJec1xcLlxcLiIpCnNhbXBsZV9hbm5vdCA8LSBzYW1wbGVfYW5ub3Rba2VwdCwgXQpkZXZ0b29sczo6bG9hZF9hbGwoIn4vc2NyYXRjaC9naXQvU1dBVEgyc3RhdHNfbXlmb3JrZWQiKQpzMnNfZXhwIDwtIHNhbXBsZV9hbm5vdGF0aW9uKGRhdGE9dHJpY19kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9hbm5vdGF0aW9uPXNhbXBsZV9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxscGVwdGlkZW5hbWVfY29sdW1uPSJmdWxscGVwdGlkZW5hbWUiKQpgYGAKCk5vdyBJIGhhdmUgYSBjb3VwbGUgZGF0YSBzdHJ1Y3R1cmVzIHdoaWNoIHNob3VsZCBwcm92ZSB1c2VmdWwgZm9yIHRoZSBtZXRyaWNzCnByb3ZpZGVkIGJ5IFNXQVRIMnN0YXRzLCBNU3N0YXRzLCBhbmQgbXkgb3duIGhwZ2x0b29scy4KCiMgU1dBVEgyc3RhdHMgY29udGludWVkCgpUaGUgdmFyaW91cyBtZXRyaWNzIGFuZCBmaWx0ZXJzIHByb3ZpZGVkIGJ5IFNXQVRIMnN0YXRzIHNlZW0gcXVpdGUgcmVhc29uYWJsZSB0bwptZS4gIFRoZSBvbmx5IHRoaW5nIHRoYXQgcmVhbGx5IGJvdGhlcnMgbWUgaXMgdGhhdCB0aGV5IGFyZSBhbGwgY2FzZSBzZW5zaXRpdmUKYW5kIEkgZm91bmQgdGhhdCB0aGUgbW9zdCByZWNlbnQgdHJpYyBjaGFuZ2VkIHRoZSBjYXBpdGFsaXphdGlvbiBvZiBhIGNvbHVtbiwKY2F1c2luZyB0aGVzZSB0byBhbGwgZmFsbCBkb3duLiAgVGhlcmVmb3JlIEkgd2VudCBpbiBhbmQgbWFkZSBldmVyeXRoaW5nIGNhc2UKaW5zZW5zaXRpdmUgaW4gYSBmYXNoaW9uIHNpbWlsYXIgdG8gdGhhdCBkb25lIGJ5IE1Tc3RhdHMgKGV4Y2VwdCBJIGhhdGUgY2FwaXRhbApsZXR0ZXJzLCBzbyBJIHVzZWQgdG9sb3dlcigpIHJhdGhlciB0aGFuIHRvdXBwZXIoKSkuCgojIyBQZXJmb3JtIGZpbHRlcnMKClRoZSBmb2xsb3dpbmcgYmxvY2sgcGVyZm9ybXMgdGhlIG1ldHJpY3MgYW5kIGZpbHRlcnMgc3VnZ2VzdGVkIGJ5IHN3YXRoMnN0YXRzLgpUaGVzZSBmaXJzdCBkZWZpbmUgdGhlIGRlY295IGhpdCByYXRlIGluIHRoZSBkYXRhLCB0aGVuIGZpbHRlciB0aGUgZGF0YSBiYXNlZCBvbgp0aGF0LiAgSXQgYWxzbyBmaWx0ZXJzIG91dCBoaXRzIHdpdGggbGVzcyB0aGFuIGlkZWFsIG0tc2NvcmVzIGFuZCBwcm90ZWlucyB3aXRoCm5vbi1vcHRpbWFsIGRpc3RyaWJ1dGlvbnMgb2YgcGVwdGlkZSBoaXRzIChlaXRoZXIgZHVlIHRvIHRvbyBmZXcgcGVwdGlkZXMgb3IgYQp3ZWlyZCBkaXN0cmlidXRpb24gb2YgaW50ZW5zaXRpZXMpLgoKYGBge3IgdGJfc3dhdGgyc3RhdHNfcHJvY2Vzc2luZ30KIyMgR2V0IGNvcnJlbGF0aW9ucyBvbiBhIHNhbXBsZSBieSBzYW1wbGUgYmFzaXMKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvczJzX2NvcnJlbGF0aW9uLXZ7dmVyfS5wbmciKSkKc2FtcGxlX2NvbmRfcmVwX2NvciA8LSBwbG90X2NvcnJlbGF0aW9uX2JldHdlZW5fc2FtcGxlcygKICBzMnNfZXhwLCBzaXplPTIsCiAgY29tcGFyaXNvbj10cmFuc2l0aW9uX2dyb3VwX2lkIH4KICAgIGNvbmRpdGlvbiArIGJpb3JlcGxpY2F0ZSArIHJ1biwKICBmdW4uYWdncmVnYXRlPW1lYW4sCiAgY29sdW1uLnZhbHVlcz0iaW50ZW5zaXR5IikKZGV2Lm9mZigpCgojIyBEbyB0aGUgc2FtZSB0aGluZywgYnV0IHVzZSB0aGUgc3VtIG9mIHRoZSBpbnRlbnNpdGllcyBwZXB0aWRlL3Byb3RlaW4KIyMgaW5zdGVhZCBvZiB0aGUgbWVhbi4uLgpwcChmaWxlPSJpbWFnZXMvczJfY29ycmVsYXRpb24ucG5nIikKc2FtcGxlX2NvbmRfcmVwX2NvciA8LSBwbG90X2NvcnJlbGF0aW9uX2JldHdlZW5fc2FtcGxlcygKICBzMnNfZXhwLCBzaXplPTIsCiAgY29tcGFyaXNvbj10cmFuc2l0aW9uX2dyb3VwX2lkIH4KICAgIGNvbmRpdGlvbiArIGJpb3JlcGxpY2F0ZSArIHJ1biwKICBmdW4uYWdncmVnYXRlPXN1bSwKICBjb2x1bW4udmFsdWVzPSJpbnRlbnNpdHkiKQpkZXYub2ZmKCkKIyMgSSB3b3VsZCBsb3ZlIHRvIGtub3cgd2h5IGl0IGlzIHRoYXQgdGhlIHNwZWFybWFuIGFuZCBwZWFyc29uIGNvcnJlbGF0aW9ucwojIyBpbiB0aGlzIGRhdGEgYXJlIHNvIG9kZGx5IGRpZmZlcmVudCBjb21wYXJlIHRvIHByZXZpb3VzIGRhdGEgc2V0cy4gIElzIHRoaXMKIyMgYW4gYXJ0aWZhY3Qgb2YgdGhlIGZhY3QgdGhhdCB0aGlzIHRpbWUgSSBhbSBfb25seV8gbG9va2luZyBhdCBDRiBzYW1wbGVzPwojIyBBcmUgdGhlIGhpZ2ggaW50ZW5zaXR5IG51bWJlcnMgbWVzc2luZyB3aXRoIG5vbi1yYW5rLWJhc2VkIGNvcnJlbGF0aW9ucz8KYGBgCgojIyBQZXJmb3JtIFNXQVRIMnN0YXRzIGZpbHRlcnMKCkkganVzdCByZWFsaXplZCBzb21ldGhpbmcgd2hpY2ggc2hvdWxkIGJlIGFkZGVkIHRvIG1lIFNXQVRIMnN0YXRzIGZvcms6CkEgc2ltcGxpZmllZCBmaWx0ZXIgZnVuY3Rpb25zIHdoaWNoIGludm9rZXMgYWxsIG9mIHRoZXNlIHNvIHRoYXQgSSBjYW4gbWFrZSBzdXJlCnRoYXQgdGhlcmUgYXJlIG5vIHR5cGVvZ3JhcGhpa2FsIGVycm9ycyBpbnRyb2R1Y2VkIGJ5IG15IGludm9jYXRpb24gb2YgZWFjaCBvZgp0aGVzZSB0aGluZ3MsIG9uZSBhdCBhIHRpbWUuCgpgYGB7ciBzd2F0aDJzdGF0c19maWx0ZXJzLCBmaWcuc2hvdz0iaGlkZSJ9CmRlY295X2xpc3RzIDwtIGFzc2Vzc19kZWNveV9yYXRlKHMyc19leHApCiMjIFRoaXMgc2VlbXMgYSBiaXQgaGlnaCB0byBtZSwgeWVzbm8/CmZkcl9vdmVyYWxsIDwtIGFzc2Vzc19mZHJfb3ZlcmFsbChzMnNfZXhwLCBvdXRwdXQ9IlJjb25zb2xlIiwgcGxvdD1UUlVFKQoKYnlydW5fZmRyIDwtIGFzc2Vzc19mZHJfYnlydW4oczJzX2V4cCwgRkZUPTAuNywgcGxvdD1UUlVFLCBvdXRwdXQ9IlJjb25zb2xlIikKY2hvc2VuX21zY29yZSA8LSBtc2NvcmU0YXNzYXlmZHIoczJzX2V4cCwgRkZUPTAuNywgZmRyX3RhcmdldD0wLjAyKQpwcm90X3Njb3JlIDwtIG1zY29yZTRwcm90ZmRyKHMyc19leHAsIEZGVD0wLjcsIGZkcl90YXJnZXQ9MC4wMikKCmZpbHRlcmVkX21zIDwtIGZpbHRlcl9tc2NvcmUoczJzX2V4cCwgY2hvc2VuX21zY29yZSwgcm0uZGVjb3k9VFJVRSkKZmlsdGVyZWRfZnEgPC0gZmlsdGVyX21zY29yZV9mcmVxb2JzKHMyc19leHAsIDAuMDEsIDAuOCwgcm0uZGVjb3k9VFJVRSkKZmlsdGVyZWRfbXNfZmRyIDwtIGZpbHRlcl9tc2NvcmVfZmRyKGZpbHRlcmVkX21zLCBGRlQ9MC43LCBybS5kZWNveT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcmFsbF9wcm90ZWluX2Zkcl90YXJnZXQ9cHJvdF9zY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX292ZXJhbGxfcGVwdGlkZV9mZHJfbGltaXQ9MC4wNSkKZmlsdGVyZWRfbXNfZmRyX3ByIDwtIGZpbHRlcl9wcm90ZW90eXBpY19wZXB0aWRlcyhmaWx0ZXJlZF9tcywgcm0uZGVjb3k9VFJVRSkKZmlsdGVyZWRfbXNfZmRyX3ByX2FsbCA8LSBmaWx0ZXJfYWxsX3BlcHRpZGVzKGZpbHRlcmVkX21zX2Zkcl9wcikKZmlsdGVyZWRfbXNfZmRyX3ByX2FsbF9zdHIgPC0gZmlsdGVyX29uX21heF9wZXB0aWRlcyhkYXRhPWZpbHRlcmVkX21zX2Zkcl9wcl9hbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9wZXB0aWRlcz0xMCwgcm0uZGVjb3k9VFJVRSkKb2xkX2ZpbHRlcmVkX2FsbF9maWx0ZXJzIDwtIGZpbHRlcl9vbl9taW5fcGVwdGlkZXMoZGF0YT1maWx0ZXJlZF9tc19mZHJfcHJfYWxsX3N0ciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3BlcHRpZGVzPTMsIHJtLmRlY295PVRSVUUpCgpmaWx0ZXJlZF9hbGxfZmlsdGVycyA8LSBzMnNfYWxsX2ZpbHRlcnMoczJzX2V4cCwgdGFyZ2V0X2Zkcj0wLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2NvcmU9MC4xLCB1cHBlcl9mZHI9MC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbWluPUZBTFNFKQpgYGAKCiMjIFdyaXRlIG91dCBtYXRyaWNlcyBvZiB0aGUgcmVzdWx0cwoKc3dhdGgyc3RhdHMgcHJvdmlkZXMgYSBjb3VwbGUgb2Ygd2F5cyB0byBwcmludCBvdXQgaXRzIHJlc3VsdHMsIG9uZSBpbiBhIGZvcm1hdApzcGVjaWZpY2FsbHkgaW50ZW5kZWQgZm9yIE1Tc3RhdHMsIGFuZCBhbm90aGVyIGFzIGEgbW9yZSBjYW5vbmljYWwgbWF0cml4IG9mCnJvd3MgPSBwcm90ZWlucywgY29sdW1ucyA9IHNhbXBsZXMuCgpMZXQgdXMgcmVzZXQgdGhlIHZlcnNpb24gYmFjayB0byAyMDE5MDMyNyBoZXJlLgoKYGBge3Igc3dhdGgyc3RhdHNfbWF0cmljZXN9CiMjIEkgdGhpbmsgdGhlc2UgbWF0cml4ZXMgYXJlIHByb2JhYmx5IHNtYXJ0ZXIgdG8gdXNlIHRoYW4gdGhlIHJhdyBvdXRtYXRyaXggZnJvbSB0cmljLgojIyBCdXQgSSBhbSBub3QgYSBmYW4gb2YgcmVyd3JpdGluZyB0aGUgc2FtcGxlIGNvbHVtbiBuYW1lcy4KbWF0cml4X3ByZWZpeCA8LSBmaWxlLnBhdGgoInByZXByb2Nlc3NpbmciLCAiMTBzd2F0aDJzdGF0cyIsIHZlcikKaWYgKCFmaWxlLmV4aXN0cyhtYXRyaXhfcHJlZml4KSkgewogIGRpci5jcmVhdGUobWF0cml4X3ByZWZpeCkKfQoKIyMgSSB3YW50IHRvIHdyaXRlIGEgZmV3IGl0ZXJhdGlvbnMgb2YgdGhlIGZpbHRlcmVkIGRhdGEKIyMgU3RhcnRpbmcgd2l0aCB0aGUgcmF3IGFuZCBtb3ZpbmcgZG93biwgcGVyaGFwcyBJIHNob3VsZCBqdXN0CiMjIGFkZCB0aGlzIGxvZ2ljIHRvIG15IGZhbmN5IG5ldyBmaWx0ZXJpbmcgZnVuY3Rpb24/CnByb3RlaW5fbWF0cml4X3VuZmlsdCA8LSB3cml0ZV9tYXRyaXhfcHJvdGVpbnMoCiAgZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJyYXciXV0sIHdyaXRlLmNzdj1UUlVFLAogIGZpbGVuYW1lPWZpbGUucGF0aChtYXRyaXhfcHJlZml4LCAicHJvdGVpbl9tYXRyaXhfdW5maWx0ZXJlZC5jc3YiKSkKZGltKHByb3RlaW5fbWF0cml4X3VuZmlsdCkKcHJvdGVpbl9tYXRyaXhfbXNjb3JlIDwtIHdyaXRlX21hdHJpeF9wcm90ZWlucygKICBmaWx0ZXJlZF9hbGxfZmlsdGVyc1tbIm1zY29yZV9maWx0ZXJlZCJdXSwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJwcm90ZWluX21hdHJpeF9tc2NvcmUuY3N2IikpCmRpbShwcm90ZWluX21hdHJpeF9tc2NvcmUpCnBlcHRpZGVfbWF0cml4X21zY29yZSA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJtc2NvcmVfZmlsdGVyZWQiXV0sIHdyaXRlLmNzdj1UUlVFLAogIGZpbGVuYW1lPWZpbGUucGF0aChtYXRyaXhfcHJlZml4LCAicGVwdGlkZV9tYXRyaXhfbXNjb3JlLmNzdiIpKQpkaW0ocGVwdGlkZV9tYXRyaXhfbXNjb3JlKQpwcm90ZWluX21hdHJpeF9maWx0ZXJlZCA8LSB3cml0ZV9tYXRyaXhfcHJvdGVpbnMoCiAgZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJmaW5hbCJdXSwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJwcm90ZWluX21hdHJpeF9maWx0ZXJlZC5jc3YiKSkKZGltKHByb3RlaW5fbWF0cml4X2ZpbHRlcmVkKQpwZXB0aWRlX21hdHJpeF9maWx0ZXJlZCA8LSB3cml0ZV9tYXRyaXhfcGVwdGlkZXMoCiAgZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJmaW5hbCJdXSwgd3JpdGUuY3N2PVRSVUUsCiAgZmlsZW5hbWU9ZmlsZS5wYXRoKG1hdHJpeF9wcmVmaXgsICJwZXB0aWRlX21hdHJpeF9maWx0ZXJlZC5jc3YiKSkKZGltKHBlcHRpZGVfbWF0cml4X2ZpbHRlcmVkKQoKIyMgRG8gdGhlIGNvcnJlbGF0aW9uIG9mIHRoZSBzdW0gb2YgcGVwdGlkZXMvcHJvdGVpbgpydF9zdW1fY29yIDwtIHBsb3RfY29ycmVsYXRpb25fYmV0d2Vlbl9zYW1wbGVzKAogIGZpbHRlcmVkX2FsbF9maWx0ZXJzW1siZmluYWwiXV0sIGNvbHVtbi52YWx1ZXM9ImludGVuc2l0eSIsCiAgZnVuLmFnZ3JlZ2F0ZT1zdW0sIHNpemU9MiwKICBjb21wYXJpc29uPXRyYW5zaXRpb25fZ3JvdXBfaWQgfgogICAgY29uZGl0aW9uICsgYmlvcmVwbGljYXRlICsgcnVuKQoKIyMgQW5kIHRoZWlyIG1lYW5zCnJ0X21lYW5fY29yIDwtIHBsb3RfY29ycmVsYXRpb25fYmV0d2Vlbl9zYW1wbGVzKAogIGZpbHRlcmVkX2FsbF9maWx0ZXJzW1siZmluYWwiXV0sIGNvbHVtbi52YWx1ZXM9ImludGVuc2l0eSIsCiAgZnVuLmFnZ3JlZ2F0ZT1tZWFuLCBzaXplPTIsCiAgY29tcGFyaXNvbj10cmFuc2l0aW9uX2dyb3VwX2lkIH4KICAgIGNvbmRpdGlvbiArIGJpb3JlcGxpY2F0ZSArIHJ1bikKCmNvbHMgPC0gY29sbmFtZXMoZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJmaW5hbCJdXSkKZGlzYWdncmVnYXRlZCA8LSBkaXNhZ2dyZWdhdGUoZmlsdGVyZWRfYWxsX2ZpbHRlcnNbWyJmaW5hbCJdXSwgYWxsLmNvbHVtbnM9VFJVRSkKbXNzdGF0c19pbnB1dCA8LSBjb252ZXJ0X01Tc3RhdHMoZGlzYWdncmVnYXRlZCkKYGBgCgojIFRlc3QgYUxGUQoKSSB3YW50IHRvIHJldmlzaXQgYUxGUSwgSSB0aGluayBpdCBtaWdodCBwcm92aWRlIGJldHRlciBwcm90ZWluLWxldmVsCnF1YW50aWZpY2F0aW9uIG1ldGhvZHMuICBhTEZRIGxvb2tzIHByb21pc2luZywgYnV0IEkgaGF2ZSBub3QgZmlndXJlZCBvdXQgdmFsaWQKcGFyYW1ldGVycyBmb3IgdXNpbmcgaXQuCgpgYGB7ciBhbGZxLCBldmFsPUZBTFNFfQpzdW1tYXJ5KG1zc3RhdHNfaW5wdXQpCmRldnRvb2xzOjpsb2FkX2FsbCgifi9zY3JhdGNoL2dpdC9hTEZRIikKYWxmcV9pbnB1dCA8LSB0cmljX2RhdGFbLCBjKCJhbGlnbl9vcmlnZmlsZW5hbWUiLCAiUHJvdGVpbk5hbWUiLCAiRnVsbFBlcHRpZGVOYW1lIiwgInRyYW5zaXRpb25fZ3JvdXBfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZ1bGxQZXB0aWRlTmFtZSIsICJDaGFyZ2UiLCAiSW50ZW5zaXR5IildCmNvbG5hbWVzKGFsZnFfaW5wdXQpIDwtIGMoInJ1bl9pZCIsICJwcm90ZWluX2lkIiwgInBlcHRpZGVfaWQiLCAidHJhbnNpdGlvbl9pZCIsICJwZXB0aWRlX3NlcXVlbmNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlY3Vyc29yX2NoYXJnZSIsICJ0cmFuc2l0aW9uX2ludGVuc2l0eSIpCmFsZnFfaW5wdXRbWyJjb25jZW50cmF0aW9uIl1dIDwtICI/IgphbGZxX2luZmVyZW5jZSA8LSBhTEZROjpQcm90ZWluSW5mZXJlbmNlLmRlZmF1bHQoYWxmcV9pbnB1dCwgY29uc2Vuc3VzX3Byb3RlaW5zPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc2Vuc3VzX3BlcHRpZGVzPUZBTFNFLCB0cmFuc2l0aW9uX3N0cmljdG5lc3M9Imxvb3NlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNlbnN1c190cmFuc2l0aW9ucz1GQUxTRSkKYWxmcV9xdWFudGl0aWVzIDwtIGFMRlE6OkFic29sdXRlUXVhbnRpZmljYXRpb24uZGVmYXVsdChhbGZxX2luZmVyZW5jZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9wcm90ZWluX2NvbmNlbnRyYXRpb249MTAwKQoKYWxmcV9ub3JtIDwtIGFsZnFfcXVhbnRpdGllc1tbMl1dCmFsZnFfbWluIDwtIG1pbihhbGZxX25vcm1bWyJub3JtYWxpemVkX2NvbmNlbnRyYXRpb24iXV0pCmFsZnFfbm9ybVtbIm5vcm0iXV0gPC0gYWxmcV9ub3JtW1sibm9ybWFsaXplZF9jb25jZW50cmF0aW9uIl1dIC8gYWxmcV9taW4KIyMgSG1tIHRoYXQgZG9lcyBub3QgbG9vayByaWdodC4KYWxmcV9sb25nIDwtIGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoYWxmcV9ub3JtKQphbGZxX3dpZGUgPC0gZGF0YS50YWJsZTo6ZGNhc3QoYWxmcV9sb25nLCBwcm90ZWluX2lkIH4gcnVuX2lkLCB2YWx1ZS52YXI9Im5vcm0iKQphbGZxX210cnggPC0gYXMuZGF0YS5mcmFtZShhbGZxX3dpZGUpCnJvd25hbWVzKGFsZnFfbXRyeCkgPC0gYWxmcV9tdHJ4W1sicHJvdGVpbl9pZCJdXQphbGZxX210cnggPC0gYXMubWF0cml4KGFsZnFfbXRyeFssIC0xXSkKY29sbmFtZXMoYWxmcV9tdHJ4KSA8LSBnc3ViKHg9Y29sbmFtZXMoYWxmcV9tdHJ4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49Il4uKigyMDE5Xy4qQnJpa2VuW1s6ZGlnaXQ6XV17Mn0pLiokIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50PSJcXDEiKQpgYGAKCiMjIE1Tc3RhdHMKCm1zc3RhdHMub3JnIHNlZW1zIHRvIHByb3ZpZGUgYSBjb21wbGV0ZSBzb2x1dGlvbiBmb3IgcGVyZm9ybWluZyByZWFzb25hYmxlIG1ldHJpY3Mgb2YgdGhpcyBkYXRhLgoKSSBhbSBjdXJyZW50bHkgcmVhZGluZzogaHR0cDovL21zc3RhdHMub3JnL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE3LzAxL01Tc3RhdHNfdjMuNy4zX21hbnVhbC5wZGYKCkkgbWFkZSBzb21lIG1vZGVyYXRlbHkgaW50cnVzaXZlIGNoYW5nZXMgdG8gTVNzdGF0cyB0byBtYWtlIGl0IGNsZWFyZXIsIGFzIHdlbGwuCgpgYGB7ciB0Yl9tc3N0YXRzX3F1YW50LCBldmFsPUZBTFNFfQp0dCA8LSBzbShkZXZ0b29sczo6bG9hZF9hbGwoIn4vc2NyYXRjaC9naXQvTVNzdGF0cyIpKQoKbXNzdGF0c192ZXIgPC0gIjIwMTkxMDIxIgpjaGVja3BvaW50IDwtIHBhc3RlMCgibXNzdGF0c19kYXRhcHJvY2Vzcy12IiwgbXNzdGF0c192ZXIsICIucmRhIikKaWYgKGZpbGUuZXhpc3RzKGNoZWNrcG9pbnQpKSB7CiAgbG9hZChmaWxlPWNoZWNrcG9pbnQpCn0gZWxzZSB7CiAgbXNzdGF0c19xdWFudCA8LSBkYXRhUHJvY2Vzcyhtc3N0YXRzX2lucHV0KQogIHNhdmUoZmlsZT1jaGVja3BvaW50LCBsaXN0PWMoIm1zc3RhdHNfcXVhbnQiKSkKfQoKIyNjaGVja3BvaW50IDwtIHBhc3RlMCgibXNzdGF0c19wbG90cy12IiwgbXNzdGF0c192ZXIsICIucmRhIikKIyNpZiAoZmlsZS5leGlzdHMoY2hlY2twb2ludCkpIHsKIyMgIGxvYWQoZmlsZT1jaGVja3BvaW50KQojI30gZWxzZSB7CiMjICBtc3N0YXRzX3Bsb3RzIDwtIGRhdGFQcm9jZXNzUGxvdHMobXNzdGF0c19xdWFudCwgdHlwZT0iUUNQTE9UIikKIyMgIHNhdmUoZmlsZT1jaGVja3BvaW50LCBsaXN0PWMoIm1zc3RhdHNfcGxvdHMiKSkKIyN9CgpteV9sZXZlbHMgPC0gbGV2ZWxzKGFzLmZhY3Rvcihtc3N0YXRzX2lucHV0JGNvbmRpdGlvbikpCm15X2xldmVscwpjb21wYXJpc29ucyA8LSBtYWtlX3NpbXBsaWZpZWRfY29udHJhc3RfbWF0cml4KAogIG51bWVyYXRvcnM9YygiZHRfd2hvbGUiLCAiY3Bfd2hvbGUiKSwKICBkZW5vbWluYXRvcnM9Yygid3Rfd2hvbGUiLCAid3Rfd2hvbGUiKSkKCm1zc3RhdHNfcmVzdWx0cyA8LSBsaXN0KCkKY2hlY2twb2ludCA8LSBwYXN0ZTAoIm1zc3RhdHNfZ3JvdXAtdiIsIHZlciwgIi5yZGEiKQppZiAoZmlsZS5leGlzdHMoY2hlY2twb2ludCkpIHsKICBsb2FkKGZpbGU9Y2hlY2twb2ludCkKfSBlbHNlIHsKICBmb3IgKGMgaW4gMTpsZW5ndGgocm93bmFtZXMoY29tcGFyaXNvbnMpKSkgewogICAgbmFtZSA8LSByb3duYW1lcyhjb21wYXJpc29ucylbY10KICAgIG1lc3NhZ2UoIlN0YXJ0aW5nICIsIG5hbWUpCiAgICBjb21wIDwtIGNvbXBhcmlzb25zW2MsIF0KICAgIGNvbXAgPC0gdChhcy5tYXRyaXgoY29tcCkpCiAgICByb3duYW1lcyhjb21wKSA8LSBuYW1lCiAgICBtc3N0YXRzX3Jlc3VsdHNbW25hbWVdXSA8LSBzbShNU3N0YXRzOjpncm91cENvbXBhcmlzb24oY29udHJhc3QubWF0cml4PWNvbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1tc3N0YXRzX3F1YW50KSkKICAgIG1lc3NhZ2UoIkZpbmlzaGVkICIsIG5hbWUpCiAgfQogIHNhdmUoZmlsZT1jaGVja3BvaW50LCBsaXN0PWMoIm1zc3RhdHNfcmVzdWx0cyIpKQp9CmBgYAoKIyMjIFAvUEUgcHJvdGVpbiBRQyBwbG90cyBmb3IgWWFuCgpZYW4gYXNrZWQgZm9yIHRoZSBwL3BlIHByb3RlaW4gcWMgcGxvdHMuIG9rLiAgSSBjaGFuZ2VkIHRoZSBkYXRhUHJvY2Vzc1Bsb3RzIHRvCnJldHVybiBzb21ldGhpbmcgdXNlZnVsLCBzbyB0aGF0IHNob3VsZCBiZSBwb3NzaWJsZSBub3cuCgpgYGB7ciBwZSwgZXZhbD1GQUxTRX0KcGVfZ2VuZXMgPC0gcmVhZC50YWJsZSgicmVmZXJlbmNlL2Fubm90YXRlZF9wZV9nZW5lcy50eHQiKVtbMV1dCgojIyBVbmZvcnR1bmF0ZWx5LCB0aGUgbmFtZXMgZGlkIG5vdCBnZXQgc2V0IGluIG15IGNoYW5nZWQgdmVyc2lvbiBvZiBkYXRhUHJvY2Vzc1Bsb3RzLi4uCnBsb3Rsc3QgPC0gbXNzdGF0c19wbG90cyRRQ1BMT1QKYXZhaWxhYmxlX3Bsb3RzIDwtIGdzdWIocGF0dGVybj0iXjEvIiwgcmVwbGFjZW1lbnQ9IiIsCiAgICAgICAgICAgICAgICAgICAgICAgIHg9bGV2ZWxzKG1zc3RhdHNfcXVhbnQkUHJvY2Vzc2VkRGF0YSRQUk9URUlOKSkKbmFtZXMocGxvdGxzdCkgPC0gYXZhaWxhYmxlX3Bsb3RzCgpwZV9pbl9hdmFpbF9pZHggPC0gcGVfZ2VuZXMgJWluJSBhdmFpbGFibGVfcGxvdHMKcGVfaW5fYXZhaWwgPC0gcGVfZ2VuZXNbcGVfaW5fYXZhaWxfaWR4XQpwZV9wbG90cyA8LSBwbG90bHN0W3BlX2luX2F2YWlsXQpwZGYoZmlsZT0icGVfcWNfcGxvdHMucGRmIikKZm9yIChwIGluIDE6bGVuZ3RoKHBlX3Bsb3RzKSkgewogIHBsb3QocGVfcGxvdHNbW3BdXSkKfQpkZXYub2ZmKCkKbGVuZ3RoKHBlX3Bsb3RzKQpgYGAKCiMgQ3JlYXRlIGhwZ2x0b29scyBleHByZXNzaW9uc2V0CgpTaW5jZSBJIGFtIG5vdCBjZXJ0YWluIEkgdW5kZXJzdGFuZCB0aGVzZSBkYXRhLCBJIHdpbGwgdGFrZSB0aGUgaW50ZW5zaXRpZXMgZnJvbQpTV0FUSDJzdGF0cywgbWV0YWRhdGEsIGFuZCBhbm5vdGF0aW9uIGRhdGE7ICBhdHRlbXB0IHRvIGNyZWF0ZSBhICdub3JtYWwnCmV4cHJlc3Npb25zZXQ7IHBva2UgYXQgaXQgdG8gc2VlIHdoYXQgSSBjYW4gbGVhcm4uCgojIyBNYXNzYWdpbmcgdGhlIG1ldGFkYXRhCgpJIHdhbnQgdG8gdXNlIHRoZSBzYW1lIG1ldGFkYXRhIGFzIHdlcmUgdXNlZCBmb3IgTVNzdGF0cy4gIEl0IGhhcyBhIGZldwppbXBvcnRhbnQgZGlmZmVyZW5jZXMgZnJvbSB0aGUgcmVxdWlyZW1lbnRzIG9mIGhwZ2x0b29sczogcHJldHR5IG11Y2ggb25seSB0aGF0CkkgZG8gbm90IGFsbG93IHJvd25hbWVzL3NhbXBsZUlEcyB0byBzdGFydCB3aXRoIGEgbnVtYmVyLgoKIyMgTWFzc2FnaW5nIHRoZSBpbnRlbnNpdHkgbWF0cml4CgpJIGRvIG5vdCB3YW50IHRoZSBcMSBiZWZvcmUgdGhlIHByb3RlaW4gbmFtZXMsIEkgYWxyZWFkeSBtZXJnZWQgdGhlbSBpbnRvIG9uZQplbnRyeSBwZXIgZ2VuZSB2aWEgU1dBVEgyc3RhdHMuCgojIyMgUHlwcm9waGV0IG1hdHJpeAoKVGhlcmUgYXJlIHR3byB3YXlzIHRvIGdldCB0aGUgbWF0cml4IG9mIGludGVuc2l0aWVzLCBlaXRoZXIgZGlyZWN0bHkgZnJvbSBweXByb3BoZXQsIG9yIGZyb20KdGhlIGZpbHRlcmVkIGRhdGEgcHJvdmlkZWQgYnkgc3dhdGgyc3RhdHMuICBIZXJlIGlzIHRoZSBmb3JtZXIsIGJ1dCBJIHNob3VsZCBiZSB1c2luZyB0aGUgbGF0dGVyLgoKYGBge3IgdGJfcHJvdGVpbl9tYXRyaXgsIGV2YWw9RkFMU0V9CnByb3RfbXRyeCA8LSByZWFkLmNzdihmaWxlLnBhdGgoInByZXByb2Nlc3NpbmciLCAiMTBzd2F0aDJzdGF0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyLCAicHJvdGVpbl9tYXRyaXhfZmlsdGVyZWQuY3N2IikpCnJvd25hbWVzKHByb3RfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJeMVxcLyIsIHJlcGxhY2VtZW50PSIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeD1wcm90X210cnhbWyJwcm90ZWlubmFtZSJdXSkKcHJvdF9tdHJ4IDwtIHByb3RfbXRyeFssIC0xXQpwcm90X2tlZXBlcnMgPC0gZ3JlcGwocGF0dGVybj0iXlJ2IiwgeD1yb3duYW1lcyhwcm90X210cngpKQpwcm90X210cnggPC0gcHJvdF9tdHJ4W3Byb3Rfa2VlcGVycywgXQojIyBJbXBvcnRhbnQgcXVlc3Rpb246IERpZCBTV0FUSDJzdGF0cyByZW9yZGVyIG15IGRhdGE/CmNvbG5hbWVzKHByb3RfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJeKC4qKSgyMDE4LiopJCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudD0ic1xcMiIsIHg9Y29sbmFtZXMocHJvdF9tdHJ4KSkKCnVuZmlsdF9tdHJ4IDwtIHJlYWQuY3N2KGZpbGUucGF0aCgicHJlcHJvY2Vzc2luZyIsICIxMHN3YXRoMnN0YXRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlciwgInByb3RlaW5fbWF0cml4X3VuZmlsdGVyZWQuY3N2IikpCnJvd25hbWVzKHVuZmlsdF9tdHJ4KSA8LSBnc3ViKHBhdHRlcm49Il4xXFwvIiwgcmVwbGFjZW1lbnQ9IiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9dW5maWx0X210cnhbWyJwcm90ZWlubmFtZSJdXSkKdW5maWx0X210cnggPC0gdW5maWx0X210cnhbLCAtMV0KdW5maWx0X2tlZXBlcnMgPC0gZ3JlcGwocGF0dGVybj0iXlJ2IiwgeD1yb3duYW1lcyh1bmZpbHRfbXRyeCkpCnVuZmlsdF9tdHJ4IDwtIHVuZmlsdF9tdHJ4W3VuZmlsdF9rZWVwZXJzLCBdCiMjIEltcG9ydGFudCBxdWVzdGlvbjogRGlkIFNXQVRIMnN0YXRzIHJlb3JkZXIgbXkgZGF0YT8KY29sbmFtZXModW5maWx0X210cngpIDwtIGdzdWIocGF0dGVybj0iXiguKikoMjAxOC4qKSQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudD0ic1xcMiIsIHg9Y29sbmFtZXModW5maWx0X210cngpKQpgYGAKCiMjIyBGcm9tIFNXQVRIMnN0YXRzCgpgYGB7ciBwcm90X21hdHJpeF9zd2F0aDJzdGF0c30KcHJvdF9tdHJ4IDwtIHByb3RlaW5fbWF0cml4X2ZpbHRlcmVkCmNvbG5hbWVzKHByb3RfbXRyeCkgPC0gZ3N1Yih4PWNvbG5hbWVzKHByb3RfbXRyeCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJeKC4qKV8oMjAxOS4qKSQiLCByZXBsYWNlbWVudD0iXFwyIikKcm93bmFtZXMocHJvdF9tdHJ4KSA8LSBwcm90X210cnhbWyJwcm90ZWlubmFtZSJdXQpwcm90X210cnhbWyJwcm90ZWlubmFtZSJdXSA8LSBOVUxMCnJ2X2lkeCA8LSBncmVwbCh4PXJvd25hbWVzKHByb3RfbXRyeCksIHBhdHRlcm49Il5SdiIpCnByb3RfbXRyeCA8LSBwcm90X210cnhbcnZfaWR4LCBdCgp1bmZpbHRfbXRyeCA8LSBwcm90ZWluX21hdHJpeF91bmZpbHQKY29sbmFtZXModW5maWx0X210cngpIDwtIGdzdWIoeD1jb2xuYW1lcyh1bmZpbHRfbXRyeCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49Il4oLiopXygyMDE5LiopJCIsIHJlcGxhY2VtZW50PSJcXDIiKQpyb3duYW1lcyh1bmZpbHRfbXRyeCkgPC0gZ3N1YihwYXR0ZXJuPSJeMVxcLyIsIHJlcGxhY2VtZW50PSIiLCB4PXVuZmlsdF9tdHJ4W1sicHJvdGVpbm5hbWUiXV0pCnVuZmlsdF9tdHJ4W1sicHJvdGVpbm5hbWUiXV0gPC0gTlVMTApydl9pZHggPC0gZ3JlcGwoeD1yb3duYW1lcyh1bmZpbHRfbXRyeCksIHBhdHRlcm49Il5SdiIpCnVuZmlsdF9tdHJ4IDwtIHVuZmlsdF9tdHJ4W3J2X2lkeCwgXQpgYGAKCiMjIE1lcmdlIHRoZSBwaWVjZXMKCk5vdyB3ZSBzaG91bGQgaGF2ZSBzdWZmaWNpZW50IHBpZWNlcyB0byBtYWtlIGFuIGV4cHJlc3Npb25zZXQuCgpXaGlsZSBoZXJlLCBJIHdpbGwgYWxzbyBzcGxpdCB0aGUgZGF0YSBpbnRvIGEgY2YgYW5kIHdob2xlLWNlbGwgcGFpciBvZiBkYXRhIHN0cnVjdHVyZXMuCgpgYGB7ciB0Yl9leHB0LCBmaWcuc2hvdz0iaGlkZSJ9CiMjIERyb3AgdGhlIG1ldGFkYXRhIG5vdCBpbiB0aGUgcHJvdGVpbiBtYXRyaXg6CiMjIEFuZCBlbnN1cmUgdGhhdCB0aGV5IGFyZSB0aGUgc2FtZSBvcmRlci4KcmVvcmRlcmVkIDwtIGNvbG5hbWVzKHByb3RfbXRyeCkKbWV0YWRhdGEgPC0gc2FtcGxlX2Fubm90W3Jlb3JkZXJlZCwgXQpjb2xuYW1lcyhwcm90X210cngpIDwtIGdzdWIoeD1jb2xuYW1lcyhwcm90X210cngpLCBwYXR0ZXJuPSJeLiooMjAxOS4qJCkiLCByZXBsYWNlbWVudD0ic1xcMSIpCm10Yl9hbm5vdGF0aW9ucyA8LSBtdGJfYW5ub3RhdGlvbnNbLCAtMV0KcHJvdGVpbl9leHB0IDwtIGNyZWF0ZV9leHB0KHNhbXBsZV9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50X2RhdGFmcmFtZT1wcm90X210cngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89bXRiX2Fubm90YXRpb25zKQoKcmVvcmRlcmVkIDwtIGNvbG5hbWVzKHVuZmlsdF9tdHJ4KQptZXRhZGF0YSA8LSBzYW1wbGVfYW5ub3RbcmVvcmRlcmVkLCBdCmNvbG5hbWVzKHVuZmlsdF9tdHJ4KSA8LSBnc3ViKHg9Y29sbmFtZXModW5maWx0X210cngpLCBwYXR0ZXJuPSJeLiooMjAxOS4qJCkiLCByZXBsYWNlbWVudD0ic1xcMSIpCm10Yl9hbm5vdGF0aW9ucyA8LSBtdGJfYW5ub3RhdGlvbnNbLCAtMV0KdW5maWx0X2V4cHQgPC0gY3JlYXRlX2V4cHQoc2FtcGxlX2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudF9kYXRhZnJhbWU9dW5maWx0X210cngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1tdGJfYW5ub3RhdGlvbnMpCmBgYAoKYGBge3IgYWxsX3BjYX0KcmF3X2ZpbHQgPC0gZ3JhcGhfbWV0cmljcyhwcm90ZWluX2V4cHQpCnBwKGZpbGU9ImltYWdlcy9sZWdlbmQucG5nIikKcmF3X2ZpbHQkbGVnZW5kCmRldi5vZmYoKQoKcHAoZmlsZT0iaW1hZ2VzL2RlbnNpdHkucG5nIikKcmF3X2ZpbHQkZGVuc2l0eQpkZXYub2ZmKCkKcHAoZmlsZT0iaW1hZ2VzL2JveC5wbmciKQpyYXdfZmlsdCRib3hwbG90CmRldi5vZmYoKQpwcChmaWxlPSJsaWJzaXplLnBuZyIpCnJhd19maWx0JGxpYnNpemUKZGV2Lm9mZigpCgpmaWx0X25vcm0gPC0gbm9ybWFsaXplX2V4cHQocHJvdGVpbl9leHB0LCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCm5vcm1fZmlsdCA8LSBncmFwaF9tZXRyaWNzKGZpbHRfbm9ybSkKCnBwKGZpbGU9ImltYWdlcy9jb3IucG5nIikKbm9ybV9maWx0JGNvcmhlYXQKZGV2Lm9mZigpCgpwcChmaWxlPSJpbWFnZXMvZGlzLnBuZyIpCm5vcm1fZmlsdCRkaXNoZWF0CmRldi5vZmYoKQoKcHAoZmlsZT0iaW1hZ2VzL2N2LnBuZyIpCm5vcm1fZmlsdCRjdnBsb3QKZGV2Lm9mZigpCgpwcChmaWxlPSJpbWFnZXMvcGNhLnBuZyIpCm5vcm1fZmlsdCRwY19wbG90CmRldi5vZmYoKQoKcGx0IDwtIHBsb3RfcGNhKGZpbHRfbm9ybSkkcGxvdApwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy97dmVyfV9maWx0ZXJlZF9wY2EucG5nIiksCiAgIGltYWdlPXBsdCkKCmNmIDwtIHN1YnNldF9leHB0KHByb3RlaW5fZXhwdCwgc3Vic2V0PSJjb2xsZWN0aW9udHlwZT09J3dob2xlX2NlbGwnIikKc3ZhX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoY2YsIGZpbHRlcj1UUlVFLCBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJydXZnIikKcGx0IDwtIHBsb3RfcGNhKHN2YV9ub3JtKSRwbG90CnBsdApwcChmaWxlPWdsdWU6OmdsdWUoImltYWdlcy97dmVyfV9mc3ZhX2ZpbHRlcmVkX3BjYS5wbmciKSwKICAgaW1hZ2U9cGx0KQoKCnVuZmlsdF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHVuZmlsdF9leHB0LCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiKQpwbG90X3BjYSh1bmZpbHRfbm9ybSkkcGxvdApgYGAKCmBgYHtyIHdyaXRlX2V4cHQsIGZpZy5zaG93PSJoaWRlIn0Kd3JpdHRlbl9maWxlIDwtIGdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV9wcm90ZWluX2V4cHQtdnt2ZXJ9Lnhsc3giKQpwcm90ZWluX3dyaXRlIDwtIHdyaXRlX2V4cHQocHJvdGVpbl9leHB0LCB2aW9saW49VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJyYXciLCBleGNlbD13cml0dGVuX2ZpbGUpCgp3cml0dGVuX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgiZXhjZWwve3J1bmRhdGV9X3VuZmlsdF9wcm90ZWluX2V4cHQtdnt2ZXJ9Lnhsc3giKQp1bmZpbHRfd3JpdGUgPC0gd3JpdGVfZXhwdCh1bmZpbHRfZXhwdCwgdmlvbGluPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0icmF3IiwgZXhjZWw9d3JpdHRlbl9maWxlKQoKcHJvdGVpbl9leHB0IDwtIHN1YnNldF9leHB0KHByb3RlaW5fZXhwdCwgc3Vic2V0PSJzYW1wbGVpZCE9JzIwMTlfMDcwOUJyaWtlbjE3JyIpCnVuZmlsdF9leHB0IDwtIHN1YnNldF9leHB0KHVuZmlsdF9leHB0LCBzdWJzZXQ9InNhbXBsZWlkIT0nMjAxOV8wNzA5QnJpa2VuMTcnIikKcHJvdGVpbl9maWx0IDwtIHNtKG5vcm1hbGl6ZV9leHB0KHByb3RlaW5fZXhwdCwgZmlsdGVyPVRSVUUpKQpwcm90ZWluX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQocHJvdGVpbl9maWx0LCBub3JtPSJxdWFudCIsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBmaWx0ZXI9VFJVRSkpCgpwcm90ZWluX3VuZmlsdCA8LSBzbShub3JtYWxpemVfZXhwdCh1bmZpbHRfZXhwdCwgZmlsdGVyPVRSVUUpKQpwcm90ZWluX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShwcm90ZWluX2ZpbHQsIG1vZGVsX2JhdGNoPUZBTFNFLCBmb3JjZT1UUlVFLCBwYXJhbGxlbD1GQUxTRSkpCnVuZmlsdF9kZSA8LSBzbShhbGxfcGFpcndpc2UocHJvdGVpbl91bmZpbHQsIG1vZGVsX2JhdGNoPUZBTFNFLCBmb3JjZT1UUlVFLCBwYXJhbGxlbD1GQUxTRSkpCgprZWVwZXJzIDwtIGxpc3QoCiAgIndoZHRfd3QiID0gYygiZHRfd2giLCAid3Rfd2giKSwKICAid2hjcF93dCIgPSBjKCJjcF93aCIsICJ3dF93aCIpLAogICJ3aGR0X2NwIiA9IGMoImR0X3doIiwgImNwX3doIiksCiAgImNmZHRfd3QiID0gYygiZHRfY2YiLCAid3RfY2YiKSwKICAiY2ZjcF93dCIgPSBjKCJjcF9jZiIsICJ3dF9jZiIpLAogICJjZmR0X2NwIiA9IGMoImR0X2NmIiwgImNwX2NmIiksCiAgInd0Y2Zfd2giID0gYygid3RfY2YiLCAid3Rfd2giKSwKICAiZHRjZl93aCIgPSBjKCJkdF9jZiIsICJkdF93aCIpLAogICJjcGNmX3doIiA9IGMoImNwX2NmIiwgImNwX3doIikKKQoKcHJvdGVpbl90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgcHJvdGVpbl9kZSwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2RlX3tydW5kYXRlfV90YWJsZXNfdnt2ZXJ9Lnhsc3giKSkKdW5maWx0X3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICB1bmZpbHRfZGUsIGtlZXBlcnM9a2VlcGVycywKICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9kZV97cnVuZGF0ZX1fdW5maWx0X3RhYmxlc192e3Zlcn0ueGxzeCIpKSkKCnByb3RlaW5fc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgcHJvdGVpbl90YWJsZXMsCiAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvc2lnX3tydW5kYXRlfV90YWJsZXNfdnt2ZXJ9Lnhsc3giKSkpCnVuZmlsdF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICB1bmZpbHRfdGFibGVzLAogIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3NpZ197cnVuZGF0ZX1fdW5maWx0X3RhYmxlc192e3Zlcn0ueGxzeCIpKSkKYGBgCgojIFNhdGlzZnkgVE9ETyAyMDE5MTEwNQoKUHJvdmlkZSBhIHBsb3Qgb2YgdGhlIHJhdGlvIG9mIGRlbHRhKGNmL3dob2xlKSB3aXRoIHJlc3BlY3QgdG8gdGhlIHJhdGlvIG9mIHd0KGNmL3dob2xlKQoKYGBge3IgcmF0aW9fcGxvdHN9CnhfZGF0YSA8LSBwcm90ZWluX3RhYmxlc1tbImRhdGEiXV1bWyJkdGNmX3doIl1dWywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQp5X2RhdGEgPC0gcHJvdGVpbl90YWJsZXNbWyJkYXRhIl1dW1sid3RjZl93aCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KeHkgPC0gbWVyZ2UoeF9kYXRhLCB5X2RhdGEsIGJ5Lng9InJvdy5uYW1lcyIsIGJ5Lnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKHh5KSA8LSB4eVtbIlJvdy5uYW1lcyJdXQp4eSA8LSB4eVssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXQpjb2xuYW1lcyh4eSkgPC0gYygiZGVsdGFfcmF0aW9fY2Zfd2giLCAid3RfcmF0aW9fY2Zfd2giKQp4eV9zY2F0dGVyIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoeHkpCnh5X3NjYXR0ZXIkc2NhdHRlcgpwbG90bHk6OmdncGxvdGx5KHh5X3NjYXR0ZXIkc2NhdHRlcikKYGBgCgojIyBMZXRzIHNlZSB3aGF0IGhhcHBlbnMgaWYgd2UgcmV3cml0ZSB0aGUgZXhwcmVzc2lvbnNldCB3aXRoIE5BcwoKYGBge3IgbmFfZXhwZXJpbWVudCwgZmlnLnNob3c9ImhpZGUifQojIyBQdXQgTkFzIGludG8gdGhlIGRhdGEgZm9yIHRoZSBzZXQgb2YgcHJvdGVpbnMgZm9yIHdoaWNoIHRoZXJlIGFyZQojIyAwcyBpbiBfbm90X2FsbF8gb2YgdGhlIHNhbXBsZXMgZm9yIGVhY2ggY29uZGl0aW9uLgpwcm90ZWluX25hcyA8LSBhZGRfY29uZGl0aW9uYWxfbmFzKHVuZmlsdF9leHB0KQp1bmZpbHRfbmFzX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShwcm90ZWluX25hcywgbW9kZWxfYmF0Y2g9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFLCBkb19lYnNlcT1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdF9wY2E9RkFMU0UsIGZvcmNlPVRSVUUpKQoKdW5maWx0X25hc190YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgdW5maWx0X25hc19kZSwga2VlcGVycz1rZWVwZXJzLAogIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3tydW5kYXRlfV91bmZpbHRfbmFzX3RhYmxlc192e3Zlcn0ueGxzeCIpKSkKCm9uZV9uYXNfdGFibGUgPC0gdW5maWx0X25hc190YWJsZXNbWyJkYXRhIl1dW1siY2ZkdF93dCJdXQpvYnNlcnZhdGlvbnMgPC0gb25lX25hc190YWJsZVssIGMoInd0d2hvYnNlcnZhdGlvbnMiLCAid3RjZm9ic2VydmF0aW9ucyIsICJkdHdob2JzZXJ2YXRpb25zIiwgImR0Y2ZvYnNlcnZhdGlvbnMiKV0KaW50ZXJlc3RpbmdfaWR4IDwtIG9ic2VydmF0aW9uc1tbInd0d2hvYnNlcnZhdGlvbnMiXV0gPiA0ICYKICBvYnNlcnZhdGlvbnNbWyJ3dGNmb2JzZXJ2YXRpb25zIl1dID4gNAppbnRlcmVzdGluZ19uYXMgPC0gb25lX25hc190YWJsZVtpbnRlcmVzdGluZ19pZHgsIF0KaW50ZXJlc3Rpbmdfb3JkZXIgPC0gb3JkZXIoaW50ZXJlc3RpbmdfbmFzW1siZGVzZXFfbG9nZmMiXV0pCmludGVyZXN0aW5nX25hcyA8LSBpbnRlcmVzdGluZ19uYXNbaW50ZXJlc3Rpbmdfb3JkZXIsIF0KbG9nZmNfaWR4IDwtIGludGVyZXN0aW5nX25hc1tbImRlc2VxX2xvZ2ZjIl1dIDwgMAppbnRlcmVzdGluZ19uYXMgPC0gaW50ZXJlc3RpbmdfbmFzW2xvZ2ZjX2lkeCwgXQpwX2lkeCA8LSBpbnRlcmVzdGluZ19uYXNbWyJkZXNlcV9hZGpwIl1dIDwgMC4xCmludGVyZXN0aW5nX25hcyA8LSBpbnRlcmVzdGluZ19uYXNbcF9pZHgsIF0KdGVzdCA8LSB3cml0ZV94bHMoaW50ZXJlc3RpbmdfbmFzLCBleGNlbD0iZXhjZWwvdGVzdG1lX2ZpcnN0Lnhsc3giKQoKaW50ZXJlc3RpbmdfaWR4IDwtIG9ic2VydmF0aW9uc1tbInd0Y2ZvYnNlcnZhdGlvbnMiXV0gPiAyICYKICBvYnNlcnZhdGlvbnNbWyJkdGNmb2JzZXJ2YXRpb25zIl1dIDwgMQppbnRlcmVzdGluZ19uYXMgPC0gb25lX25hc190YWJsZVtpbnRlcmVzdGluZ19pZHgsIF0KdGVzdCA8LSB3cml0ZV94bHMoaW50ZXJlc3RpbmdfbmFzLCBleGNlbD0iZXhjZWwvdGVzdG1lX2ZpcnN0Lnhsc3giKQoKdW5maWx0X25hc19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICB1bmZpbHRfbmFzX3RhYmxlcywKICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9zaWdfe3J1bmRhdGV9X3VuZmlsdF9uYXNfdGFibGVzX3Z7dmVyfS54bHN4IikpKQpgYGAKCiMgQSBuaWNlIHN1YnNldCByZXF1ZXN0IGZyb20gVm9sa2VyCgpMZXQgdXMgcHVsbCB0aGUgZm9sbG93aW5nIHN1YnNldCBmcm9tIHRoZSBERSB0YWJsZXMgZm9yIFZvbGtlciwgaXQgc2hvdWxkCnByb3ZpZGUgYSBzZXQgb2YgcHJvdGVpbnMgbW9zdCBvYnZpb3VzbHkgb2YgaW50ZXJlc3Q7IGFzc3VtaW5nIHRoZSBmYWxzZQpuZWdhdGl2ZXMgYXJlIG5vdCB0b28gc2V2ZXJlLgoKMS4gIGxmYyA8PSAtNiBmb3IgZGVsdGEvd3QgJiYgbGZjID49IC0zIGZvciBjb21wL3d0CjIuICBsZmMgPj0gMTAgZGVsdGEvd3QgJiYgbGZjIDw9IDQgY29tcC93dAoKVGhpcyB3aWxsIGhvcGVmdWxseSBmaW5kIHRoaW5ncyB3aGljaCBhcmUgc3VmZmljaWVudGx5IGRpZmZlcmVudCBmcm9tIHRoZQpkZWxldGlvbiBhbmQgY29tcGxlbWVudCBzYW1wbGVzIHRvIGJlIGludGVyZXN0aW5nLgoKYGBge3IgaW50ZXJlc3Rpbmdfc3Vic2V0LCBldmFsPUZBTFNFfQpkdF93dCA8LSB1bmZpbHRfbmFzX3RhYmxlc1tbImRhdGEiXV1bWyJkdF93dCJdXQpjcF93dCA8LSB1bmZpbHRfbmFzX3RhYmxlc1tbImRhdGEiXV1bWyJjcF93dCJdXQpkb3duX2lkeCA8LSBkdF93dFtbImRlc2VxX2xvZ2ZjIl1dIDw9IC02ICYgY3Bfd3RbWyJkZXNlcV9sb2dmYyJdXSA+PSAtMwpkb3duX3RhYmxlIDwtIGR0X3d0W2Rvd25faWR4LCBdCnVwX2lkeCA8LSBkdF93dFtbImRlc2VxX2xvZ2ZjIl1dID49IDEwICYgY3Bfd3RbWyJkZXNlcV9sb2dmYyJdXSA8PSA0CnVwX3RhYmxlIDwtIGR0X3d0W3VwX2lkeCwgXQoKZG93bl9zdWJzZXQgPC0gd3JpdGVfeGxzKAogIGRhdGE9ZG93bl90YWJsZSwKICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9kZV97cnVuZGF0ZX1fbW9yZV9kb3duX2RlbHRhLnhsc3giKSkKdXBfc3Vic2V0IDwtIHdyaXRlX3hscygKICBkYXRhPXVwX3RhYmxlLAogIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2RlX3tydW5kYXRlfV9tb3JlX3VwX2RlbHRhLnhsc3giKSkKYGBgCgojIFBsYXlpbmcgd2l0aCBuZXcgRW5jeWNsb3BlRElBCgpgYGB7ciBsb2FkX2VuY3ljbG9wZWRpYSwgZXZhbD1GQUxTRX0KZW5jX21ldGFkYXRhIDwtIHNhbXBsZV9hbm5vdGUKbmNfbWF0cml4IDwtIHJlYWQudGFibGUoInByZXByb2Nlc3NpbmcvMDllbmN5Y2xvcGVkaWEvMjAxOTEwMDFjZl9xdWFudGl0aWVzLmVsaWIucHJvdGVpbnMudHh0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlcj1UUlVFKQplbmNfcGVwX21hdHJpeCA8LSByZWFkLnRhYmxlKCJwcmVwcm9jZXNzaW5nLzA5ZW5jeWNsb3BlZGlhLzIwMTkxMDAxY2ZfcXVhbnRpdGllcy5lbGliLnBlcHRpZGVzLnR4dCIsIGhlYWRlcj1UUlVFKQpyb3duYW1lcyhlbmNfbWF0cml4KSA8LSBlbmNfbWF0cml4W1siUHJvdGVpbiJdXQplbmNfbWF0cml4IDwtIGVuY19tYXRyaXhbLCAtMV0KZW5jX21hdHJpeCA8LSBlbmNfbWF0cml4WywgLTFdCmVuY19tYXRyaXggPC0gZW5jX21hdHJpeFssIC0xXQpjb2xuYW1lcyhlbmNfbWF0cml4KQpjb2xuYW1lcyhlbmNfbWF0cml4KSA8LSBnc3ViKHBhdHRlcm49IlgiLCByZXBsYWNlbWVudD0icyIsIHg9Y29sbmFtZXMoZW5jX21hdHJpeCkpCmNvbG5hbWVzKGVuY19tYXRyaXgpIDwtIGdzdWIocGF0dGVybj0iXFwubXpNTCIsIHJlcGxhY2VtZW50PSIiLCB4PWNvbG5hbWVzKGVuY19tYXRyaXgpKQpjb2xuYW1lcyhlbmNfbWF0cml4KSA8LSBnc3ViKHBhdHRlcm49Il5YIiwgcmVwbGFjZW1lbnQ9InMiLCB4PWNvbG5hbWVzKGVuY19tYXRyaXgpKQpjb2xuYW1lcyhlbmNfcGVwX21hdHJpeCkgPC0gZ3N1YihwYXR0ZXJuPSJYIiwgcmVwbGFjZW1lbnQ9InMiLCB4PWNvbG5hbWVzKGVuY19wZXBfbWF0cml4KSkKY29sbmFtZXMoZW5jX3BlcF9tYXRyaXgpIDwtIGdzdWIocGF0dGVybj0iXFwubXpNTCIsIHJlcGxhY2VtZW50PSIiLCB4PWNvbG5hbWVzKGVuY19wZXBfbWF0cml4KSkKY29sbmFtZXMoZW5jX3BlcF9tYXRyaXgpIDwtIGdzdWIocGF0dGVybj0iXlgiLCByZXBsYWNlbWVudD0icyIsIHg9Y29sbmFtZXMoZW5jX3BlcF9tYXRyaXgpKQoKY29sbmFtZXMoZW5jX21hdHJpeCkKcm93bmFtZXMoZW5jX21ldGFkYXRhKQoKZW5jX2V4cHQgPC0gY3JlYXRlX2V4cHQobWV0YWRhdGE9ZW5jX21ldGFkYXRhLCBjb3VudF9kYXRhZnJhbWU9ZW5jX21hdHJpeCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvPW10Yl9hbm5vdGF0aW9ucykKZW5jX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoZW5jX2V4cHQsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKGVuY19ub3JtKSRwbG90CmBgYAoKIyBSZXF1ZXN0IGZyb20gMjAxOTExMjgKCkhlcmUgaXMgdGhlIHRleHQgb2YgbXkgZW1haWw6CgpRdWVyeSAxOiAgR2l2ZW4gZXhpc3RpbmcgdGFibGUgb2YgYWxsIERFIHByb3RlaW5zIHBlcmZvcm0gdGhlIGZvbGxvd2luZzoKICBhLiBUYWtlIHRoZSBkZXNlcV9sb2dmYyBmb3IgdGhlIGRlbHRhKGNmL3doKQogIGIuIFRha2UgdGhlIGRlc2VxX2xvZ2ZjIGZvciB0aGUgd3QoY2Yvd2gpCiAgYy4gU3VidHJhY3QgYSBhbmQgYi4KICBkLiBHaXZlbiBjLCBleHRyYWN0IHRoZSBzZXQgd2hpY2ggYXJlIG5lZ2F0aXZlIGFuZCA8PSB4IHdoZXJlIHggaXMgbGlrZWx5IDAuNSBhdCBsZWFzdCBhdCBmaXJzdC4KCiBRdWVyeSAyOiBGb3IgdGhlIHN1YnNldCBhY3F1aXJlZCBpbiBRdWVyeSAxIGRvIHRoZSBmb2xsb3dpbmc6CiAgIGEuICBUYWtlIHRoZSBkZXNlcV9sb2dmYyBmb3IgdGhlIGRlbHRhKGNmL3doKS4KICAgYi4gIFRha2UgdGhlIGRlc2VxX2xvZ2ZjIGZvciB0aGUgY29tcGxlbWVudChjZi93aCkuCiAgIGMuICBTdWJ0cmFjdCBhIGFuZCBiLgoKUXVlcnkgMzogRm9yIHRoZSByZXN1bHRzIG9mIFExLCBRMiwgcGxvdCB0aGVtIGFzIGEgc2NhdHRlciBwbG90LgpUYWtlIGZyb20gdGhpcyB0aGUgc2V0IG9mIGdlbmVzIGNsb3NlIHRoYW4gc29tZSBaLXZhbHVlLgoKRm9jdXMgb24gb25lIHN0cmluZ2VuY3k/ICBzdGFydCB3aXRoIGZpbHRlcmVkIGFuZCB1bmZpbHRlcmVkLgoKUXVlcnkgNDoKUGxvdCB5IGF4aXM6IGNmKGRlbHRhL2NvbXApClBsb3QgeCBheGlzOiBjZihkZWx0YS93dCkKClF1ZXJ5IDU6ClBsb3QgeSBheGlzOiB3aChkZWx0YS9jb21wKQpQbG90IHggYXhpczogd2goZGVsdGEvd3QpCgpGb3IgYWxsIG9mIHRoZSBhYm92ZSB1c2UgZ2dwbG90bHkgKGVnLiBob3ZlciBwbG90cykuCgpgYGB7ciBxdWVyeTF9CnExYSA8LSBwcm90ZWluX3RhYmxlc1tbImRhdGEiXV1bWyJkdGNmX3doIl1dWywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQpxMWIgPC0gcHJvdGVpbl90YWJsZXNbWyJkYXRhIl1dW1sid3RjZl93aCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KdGVzdHRoYXQ6OmV4cGVjdF9lcXVhbChyb3duYW1lcyhxMWEpLCByb3duYW1lcyhxMWIpKQpxMWMgPC0gcTFhW1siZGVzZXFfbG9nZmMiXV0gLSBxMWJbWyJkZXNlcV9sb2dmYyJdXQpuYW1lcyhxMWMpIDwtIHJvd25hbWVzKHExYSkKc3VtbWFyeShxMWMpCmludGVyZXN0aW5nX2lkeCA8LSBxMWMgPD0gMC41CnN1bShpbnRlcmVzdGluZ19pZHgpCmtlcHRfaWRzIDwtIHJvd25hbWVzKHExYSlbaW50ZXJlc3RpbmdfaWR4XQpxMWQgPC0gcTFjW2ludGVyZXN0aW5nX2lkeF0KCnEyYSA8LSBwcm90ZWluX3RhYmxlc1tbImRhdGEiXV1bWyJkdGNmX3doIl1dW2ludGVyZXN0aW5nX2lkeCwgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQpxMmIgPC0gcHJvdGVpbl90YWJsZXNbWyJkYXRhIl1dW1siY3BjZl93aCJdXVtpbnRlcmVzdGluZ19pZHgsIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KcTJjIDwtIHEyYVtbImRlc2VxX2xvZ2ZjIl1dIC0gcTJiW1siZGVzZXFfbG9nZmMiXV0KbmFtZXMocTJjKSA8LSByb3duYW1lcyhxMmEpCnN1bW1hcnkocTJjKQoKcTMgPC0gYXMuZGF0YS5mcmFtZShjYmluZChxMWQsIHEyYykpCnJvd25hbWVzKHEzKSA8LSBuYW1lcyhxMmMpCmNvbG5hbWVzKHEzKSA8LSBjKCJkdF92c193dCIsICJkdF92c19jcCIpCnEzX3NjYXR0ZXIgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihxMykKcTNfc2NhdHRlciRzY2F0dGVyCnEzX3Bsb3RseSA8LSBwbG90bHk6OmdncGxvdGx5KHEzX3NjYXR0ZXIkc2NhdHRlcikKcTNfc2F2ZWQgPC0gaHRtbHdpZGdldHM6OnNhdmVXaWRnZXQocTNfcGxvdGx5LCAiMjAxOTExMjZfcXVlcnkzLmh0bWwiKQoKcTR4IDwtIHByb3RlaW5fdGFibGVzW1siZGF0YSJdXVtbImNmZHRfY3AiXV1bLCBjKCJkZXNlcV9sb2dmYyIsICJkZXNlcV9hZGpwIildCnE0eSA8LSBwcm90ZWluX3RhYmxlc1tbImRhdGEiXV1bWyJjZmR0X3d0Il1dWywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQpxNCA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHE0eFtbImRlc2VxX2xvZ2ZjIl1dLCBxNHlbWyJkZXNlcV9sb2dmYyJdXSkpCnJvd25hbWVzKHE0KSA8LSByb3duYW1lcyhxNHgpCmNvbG5hbWVzKHE0KSA8LSBjKCJjZmR0X2NwIiwgImNmZHRfd3QiKQpxNF9zY2F0dGVyIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIocTQpCnE0X3NjYXR0ZXIkc2NhdHRlcgpxNF9wbG90bHkgPC0gcGxvdGx5OjpnZ3Bsb3RseShxNF9zY2F0dGVyJHNjYXR0ZXIpCnE0X3NhdmVkIDwtIGh0bWx3aWRnZXRzOjpzYXZlV2lkZ2V0KHE0X3Bsb3RseSwgIjIwMTkxMTI2X3F1ZXJ5NC5odG1sIikKCnE1eCA8LSBwcm90ZWluX3RhYmxlc1tbImRhdGEiXV1bWyJ3aGR0X2NwIl1dWywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQpxNXkgPC0gcHJvdGVpbl90YWJsZXNbWyJkYXRhIl1dW1sid2hkdF93dCJdXVssIGMoImRlc2VxX2xvZ2ZjIiwgImRlc2VxX2FkanAiKV0KcTUgPC0gYXMuZGF0YS5mcmFtZShjYmluZChxNXhbWyJkZXNlcV9sb2dmYyJdXSwgcTV5W1siZGVzZXFfbG9nZmMiXV0pKQpyb3duYW1lcyhxNSkgPC0gcm93bmFtZXMocTV4KQpjb2xuYW1lcyhxNSkgPC0gYygid2hkdF9jcCIsICJ3aGR0X3d0IikKcTVfc2NhdHRlciA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKHE1KQpxNV9zY2F0dGVyJHNjYXR0ZXIKcTVfcGxvdGx5IDwtIHBsb3RseTo6Z2dwbG90bHkocTVfc2NhdHRlciRzY2F0dGVyKQpxNV9zYXZlZCA8LSBodG1sd2lkZ2V0czo6c2F2ZVdpZGdldChxNV9wbG90bHksICIyMDE5MTEyNl9xdWVyeTUuaHRtbCIpCmBgYAoKYGBge3Igc2F2ZW1lfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKfQpgYGAKCmBgYHtyIGxvYWRtZSwgZXZhbD1GQUxTRX0KdG1wIDwtIGxvYWRtZShmaWxlbmFtZT10aGlzX3NhdmUpCmBgYAo=