1 Introduction

This document will visualize the TMRC2 samples before completing the various differential expression and variant analyses in the hopes of getting an understanding of how the various samples relate to each other.

1.1 Initial library size

Start off with the library sizes of the original dataset. The main thing to note is that we have quite a large variance in coverage. A few of these samples are highly likely to be removed shortly (looking at you, TMRC20001 and TMRC20095)

libsizes <- plot_libsize(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_libsize': object 'lp_expt' not found
libsizes
## Error: object 'libsizes' not found
dev <- pp("images/lp_expt_libsizes.png", width = 18, height = 9)
libsizes$plot
## Error: object 'libsizes' not found
closed <- dev.off()

Library sizes of the protein coding gene counts observed per sample. The samples were mapped with the EuPathDB revision 36 of the Leishmania (Viannia) panamensis strain MHOM/COL/81L13 genome; the alignments were sorted, indexed, and counted via htseq using the gene features, and non-protein coding features were excluded. The per-sample sums of the remaining matrix were plotted to check that the relative sample coverage is sufficient and not too divergent across samples. Bars are colored according to strain/zymodeme annotation: red: zymodeme 2.3; blue: zymodeme 2.2; Leishmania braziliensis-like strains b2904, z1.0, and z1.5: purple; zymodemes which are most similar to 2.3, comprising z2.4 is light brown; zymodemes most similar to 2.2, comprising z3.0, z2.0, z2.1, and z3.2 are light gray, dark gray, dark brown, and gray respectively.

1.2 Non-zero genes with respect to coverage

This plot is usually our primary arbiter for sample removing based on coverage. We pick a semi-arbitrary cutoff based on both coverage and genes observed. In this instance 8,600 genes seems likely?

The cutoff argument prints out samples with gene coverage < that proportion. I think we already dropped in the sample sheet the most problematic samples, so it may not actually print anything.

## I think samples 7,10 should be removed at minimum, probably also 9,11
nonzero <- plot_nonzero(lp_expt, cutoff = 0.7)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_nonzero': object 'lp_expt' not found
nonzero
## Error: object 'nonzero' not found
dev <- pp(file = "images/lp_nonzero.png", width = 9, height = 9)
nonzero$plot
## Error: object 'nonzero' not found
closed <- dev.off()

Differences in relative gene content with respect to sequencing coverage. The per-sample number of observed genes was plotted with respect to the relative CPM coverage in order to check that the samples are sufficiently and similarly diverse. Many samples were observed near or at the putative asymptote of likely gene content; no samples were observed with fewer than 65% of the Leishmania panamensis genes included. Note that the range of genes observed is quite small, 8500 <= x < 8700 genes, however this was plotted after already excluding samples with fewer than 8500 genes observed (of which there were 2) and any samples with fewer than 5 million protein coding mapped reads (there were 2 samples that had more than 8500 genes observed in less than 5 million reads).

lp_box <- plot_boxplot(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_boxplot': object 'lp_expt' not found
dev <- pp(file = "images/lp_expt_boxplot.png", width = 16, height = 9)
lp_box
## Error: object 'lp_box' not found
closed <- dev.off()
lp_box
## Error: object 'lp_box' not found

The distribution of observed counts / gene for all samples was plotted as a boxplot on the log2 (it looks like it is log10, but I checked) scale. In contrast to host transcriptome distribution, the parasite distribution of reads/gene is log-normal.

filter_plot <- plot_libsize_prepost(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_libsize': object 'lp_expt' not found
filter_plot$lowgene_plot
## Error: object 'filter_plot' not found
filter_plot$count_plot
## Error: object 'filter_plot' not found

The numbers of genes removed by low-count filtering is drastically lower in parasite samples than human. Thus, even though the range of coverage for the parasite samples is from near 0 to ~ 150 CPM, the number of genes removed by the default low-count filter ranges only from 40 to 129, and the number of reads associated with them ranges only from 100 to 3168.

table(pData(lp_expt)[["zymodemecategorical"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
table(pData(lp_expt)[["clinicalresponse"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found

1.3 Distribution Visualizations

Najib’s favorite plots are of course the PCA/TNSE. These are nice to look at in order to get a sense of the relationships between samples. They also provide a good opportunity to see what happens when one applies different normalizations, surrogate analyses, filters, etc. In addition, one may set different experimental factors as the primary ‘condition’ (usually the color of plots) and surrogate ‘batches’.

1.4 By Susceptilibity

Column ‘Q’ in the sample sheet, make a categorical version of it with these parameters:

  • 0 <= x <= 35 is resistant
  • 36 <= x <= 48 is ambiguous
  • 49 <= x is sensitive
strain_norm <- normalize_expt(lp_strain, norm = "quant", transform = "log2",
                              convert = "cpm", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_strain' not found
zymo_pca <- plot_pca(strain_norm, plot_title = "PCA of parasite expression values",
                     plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_norm' not found
zymo_pca
## Error: object 'zymo_pca' not found
dev <- pp(file = "figures/promastigote_zymocol_sensshape_z21_to_z24.pdf")
zymo_pca$plot
## Error: object 'zymo_pca' not found
closed <- dev.off()

lp_strain_known <- subset_expt(lp_strain, subset = "clinicalcategorical!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_strain' not found
strain_known_norm <- normalize_expt(lp_strain_known, norm = "quant", transform = "log2",
                                    convert = "cpm", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_strain_known' not found
zymo_known_pca <- plot_pca(strain_known_norm, plot_title = "PCA of parasite expression values",
                           plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_known_norm' not found
zymo_known_pca
## Error: object 'zymo_known_pca' not found
dev <- pp(file = "figures/promastigote_zymocol_sensshape_z21_to_z24_only_known_clinical.pdf")
zymo_known_pca$plot
## Error: object 'zymo_known_pca' not found
closed <- dev.off()

1.5 Limit to three strains: 2.1/2.2/2.3

only_three_types <- subset_expt(lp_strain, subset = "condition=='z2.1'|condition=='z2.3'|condition=='z2.2'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_strain' not found
only_three_norm <- normalize_expt(only_three_types, norm = "quant", transform = "log2",
                                  convert = "cpm", batch = FALSE, filter = TRUE) %>%
  set_expt_batches(fact = "phase")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'set_expt_batches': error in evaluating the argument 'input' in selecting a method for function 'state': object 'only_three_types' not found
onlythree_pca <- plot_pca(only_three_norm, plot_title = "PCA of z2.1, z2.2 and z2.3 parasite expression values",
                          plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'only_three_norm' not found
pp(file = "images/promastigote_threetypes_zymocol_noshape.png")
onlythree_pca$plot
## Error: object 'onlythree_pca' not found
dev.off()
## png 
##   2
onlythree_pca$plot
## Error: object 'onlythree_pca' not found

1.6 By my ML knn classifier!

I added the result from my kmer classifier to the sample sheet, let us see how that looks.

lp_strain_knn <- set_expt_conditions(lp_strain, fact = "knnv2classification")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_strain' not found
strain_norm_knn <- normalize_expt(lp_strain_knn, norm = "quant", transform = "log2",
                                  convert = "cpm", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_strain_knn' not found
zymo_pca_knn <- plot_pca(strain_norm_knn, plot_title = "PCA of parasite expression values",
                         plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_norm_knn' not found
plotly::ggplotly(zymo_pca_knn$plot)
## Error: object 'zymo_pca_knn' not found
dev <- pp(file = "images/promastigote_zymocol_sensshape_knnv2.png")
zymo_pca_knn$plot
## Error: object 'zymo_pca_knn' not found
closed <- dev.off()
zymo_pca_knn$plot
## Error: object 'zymo_pca_knn' not found
strain_nobatch <- set_expt_batches(strain_norm, fact = "sourcelab")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'set_expt_batches': object 'strain_norm' not found
zymo_pcav2 <- plot_pca(strain_nobatch, plot_title = "PCA of parasite expression values",
                       plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_nobatch' not found
dev <- pp(file = "images/promastigote_zymocol_nobatch.png")
zymo_pcav2$plot
## Error: object 'zymo_pcav2' not found
closed <- dev.off()
zymo_pcav2$plot
## Error: object 'zymo_pcav2' not found
strain_nb <- normalize_expt(lp_strain, convert = "cpm", transform = "log2",
                            filter = TRUE, batch = "svaseq")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_strain' not found
strain_nb_pca <- plot_pca(strain_nb, plot_title = "PCA of parasite expression values",
                          plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_nb' not found
dev <- pp(file = "images/clinical_nb_pca_sus_shape.png")
strain_nb_pca$plot
## Error: object 'strain_nb_pca' not found
closed <- dev.off()
strain_nb_pca
## Error: object 'strain_nb_pca' not found

Add explicit labels for a few reference strains:

  • TMRC20023: Excluded due to coverage (only 7k reads)
  • TMRC20006: This one has 19,815,673 reads, but a weirdly small number of genes and got excluded.
  • TMRC20029: This has 1,946,986 reads and so was excluded.
  • TMRC20034: Not sequenced

** NOTE ** These samples were all removed from examination in the sample_sheet in 202404 and so will not appear in this plot. Thus I am turning off the following block.

samples_to_label <- tolower(c("TMRC20023", "TMRC20006", "TMRC20029", "TMRC20007", "TMRC20034",
                              "TMRC20008", "TMRC20027", "TMRC20028", "TMRC20032", "TMRC20040"))

label_entries <- zymo_pca$table[samples_to_label, ]
zymo_pca$plot +
  geom_text(mapping = aes_string("x" = "PC1", "y" = "PC2", label = "sampleid"),
            data = label_entries)

Some likely text for a figure legend might include something like the following (paraphrased from Najib’s 2016 dual transcriptome profiling paper (10.1128/mBio.00027-16)):

Expression profiles of the promastigote samples across multiple strains. Each glyph represents one sample, colors delineate the various strains and fall into two primary clades. Red samples are zymodeme 2.3, blue samples are zymodeme 2.2. The difference between these two primary groups make up approximately 17% of the variance in the PCA. Purple samples are Leishmania braziliensis or zymodeme 1.0/1.5 samples, orange are z2.4, browns and greys are z2.1, z2.0, z3.0, and z3.2 respectively. This analysis was performed following a low-count filter, cpm conversion, quantile normalization, and a log2 transformation. No batch factor was used, nor was a surrogate variable estimation performed.

Some interpretation for this figure might include:

When PCA was performed on the promastigote samples, the dominant (but still relatively small amount of variance) component observed coincided with the two primary strain groups, zymodeme 2.2 and 2.3. With the exception of some Leishmania braziliensis samples, all promatigote samples assayed fell into one of these two categories.

When surrogate varialbe estimation was performed on the entire set of samples, it increased the apparent strain-dependent variance, but had some potentially problematic effects for a couple of samples (one z2.3 sample now lies with the other z2.2 samples); it is assumed that this is because sva attempted to estimate surrogate values for the less-represented strains with some unintended consequences for sample TMRC20095 (which, along with TMRC20008 are the two least covered samples by a significant margin); this hypothesis may be tested by excluding the braziliensis and non-z2.2/2.3 samples and repeating (when this is performed later in the document, the difference between the two primary clades increases to 49.33% of the variance and there are no odd samples).

zymo_tsne <- plot_tsne(strain_norm, plot_title = "TSNE of parasite expression values")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_norm' not found
zymo_tsne$plot
## Error: object 'zymo_tsne' not found
strain_nb_tsne <- plot_tsne(strain_nb, plot_title = "TSNE of parasite expression values")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'strain_nb' not found
strain_nb_tsne$plot
## Error: object 'strain_nb_tsne' not found
corheat <- plot_corheat(strain_norm, plot_title = "Correlation heatmap of parasite
                 expression values
")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input_data' in selecting a method for function 'plot_heatmap': object 'strain_norm' not found
corheat$plot
## Error: object 'corheat' not found
disheat <- plot_disheat(strain_norm, plot_title = "Distance heatmap of parasite
                 expression values
")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input_data' in selecting a method for function 'plot_heatmap': object 'strain_norm' not found
disheat$plot
## Error: object 'disheat' not found
plot_sm(strain_norm)$plot
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_sm': object 'strain_norm' not found

Potential start for a figure legend:

Global relationships among the promastigote transcriptional profiles. Pairwise pearson correlations and Euclidean distances were calculated using the normalized expression matrices. Colors along the top row delineate the experimental conditions (same colors as the PCA) Samples were clustered by nearest neighbor clustering and each colored tile describes one correlation value between two samples (red to white delineates pearson correlation values of the 8,710 normalized gene values between two samples ranging from <= 0.7 to >= 1.0) or the euclidean distance between two samples (dark blue to white delineates identical to a normalized euclidean distance of >= 110).

Some interpretation for this figure might include:

When the global relationships among the samples were distilled down to individual euclidean distances or pearson correlation coefficients between pairs of samples, the primary clustering among samples observed was according to strain. The primary significant outlier sample (TMRC20095) is explicitly due to low coverage. The other outlier strains are either braziliensis (purple) or a series of strains which, when viewed in IGV, appear to have genetic variants which bridge the differences between the two primary zymodemes, particularly on the known aneuploid chromosomes.

1.7 Limit to just two strains: 2.2/2.3

lp_two_strains_norm <- sm(normalize_expt(lp_zymo, norm = "quant", transform = "log2",
                                         convert = "cpm", batch = FALSE, filter = TRUE))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_zymo' not found
onlytwo_pca <- plot_pca(lp_two_strains_norm, plot_title = "PCA of z2.2 and z2.3 parasite expression values",
                        plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'lp_two_strains_norm' not found
dev <- pp(file = "figures/zymo_z2.2_z2.3_pca_sus_shape.pdf")
onlytwo_pca$plot
## Error: object 'onlytwo_pca' not found
closed <- dev.off()
onlytwo_pca$plot
## Error: object 'onlytwo_pca' not found
lp_two_strains_known <- subset_expt(lp_zymo, subset = "clinicalcategorical!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_zymo' not found
lp_two_strains_known_norm <- sm(normalize_expt(lp_two_strains_known, norm = "quant", transform = "log2",
                                               convert = "cpm", batch = FALSE, filter = TRUE))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_two_strains_known' not found
onlytwo_known_pca <- plot_pca(lp_two_strains_known_norm, plot_title = "PCA of z2.2 and z2.3 parasite expression values",
                              plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'lp_two_strains_known_norm' not found
dev <- pp(file = "figures/zymo_z2.2_z2.3_pca_sus_shape_only_known.pdf")
onlytwo_pca$plot
## Error: object 'onlytwo_pca' not found
closed <- dev.off()
onlytwo_pca$plot
## Error: object 'onlytwo_pca' not found
lp_two_strains_nb <- normalize_expt(lp_zymo, norm = "quant", transform = "log2",
                                    convert = "cpm", batch = "svaseq", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_zymo' not found
onlytwo_pca_nb <- plot_pca(lp_two_strains_nb, plot_title = "PCA of z2.2 and z2.3 parasite expression values",
                           plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'lp_two_strains_nb' not found
dev <- pp(file = "images/zymo_z2.2_z2.3_pca_sus_shape_nb.pdf")
onlytwo_pca_nb$plot
## Error: object 'onlytwo_pca_nb' not found
closed <- dev.off()
onlytwo_pca_nb$plot
## Error: object 'onlytwo_pca_nb' not found

1.8 By Cure/Fail status

This is by far the most problematic comparison, I think the only interpretation of the following images is that the parasite has little effect on the likelihood that a person will successfully end treatment. There does appear to be some variance associated with cure/fail, but only in a few samples (visible in ~10 fail samples and perhaps ~8 cure samples when sva is applied to the data).

cf_norm <- normalize_expt(lp_cf, convert = "cpm", transform = "log2",
                          norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_cf' not found
start_cf <- plot_pca(cf_norm, plot_title = "PCA of parasite expression values",
                     plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'cf_norm' not found
dev <- pp(file = "figures/cure_fail_sus_shape_all.pdf")
start_cf$plot
## Error: object 'start_cf' not found
closed <- dev.off()
start_cf
## Error: object 'start_cf' not found
lp_cf_known <- subset_expt(lp_cf, subset = "clinicalcategorical!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_cf' not found
cf_known_norm <- normalize_expt(lp_cf_known, convert = "cpm", transform = "log2",
                                norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_cf_known' not found
start_cf_known <- plot_pca(cf_known_norm, plot_title = "PCA of parasite expression values",
                           plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'cf_known_norm' not found
dev <- pp(file = "figures/cure_fail_sus_shape_known.pdf")
start_cf_known$plot
## Error: object 'start_cf_known' not found
closed <- dev.off()
start_cf_known
## Error: object 'start_cf_known' not found
only_two_cf <- set_expt_conditions(lp_zymo, fact = "clinicalcategorical") %>%
  set_expt_batches(fact = "sus_category_current") %>%
  set_expt_colors(color_choices[["cf"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'expt' in selecting a method for function 'set_expt_batches': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_zymo' not found
only_two_cf_norm <- normalize_expt(only_two_cf, norm = "quant", transform = "log2",
                                   convert = "cpm", batch = FALSE, filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'only_two_cf' not found
only_two_cf_pca <- plot_pca(only_two_cf_norm, plot_title = "PCA of z2.2 and z2.3 parasite expression values",
                            plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'only_two_cf_norm' not found
dev <- pp(file = "figures/cure_fail_sus_shape_onlyz22_z23.pdf")
only_two_cf_pca$plot
## Error: object 'only_two_cf_pca' not found
dev.off()
## png 
##   2
only_two_cf_pca
## Error: object 'only_two_cf_pca' not found
only_two_cf_known <- subset_expt(only_two_cf, subset = "condition!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'only_two_cf' not found
only_two_cf_known_norm <- normalize_expt(only_two_cf_known, norm = "quant", transform = "log2",
                                         convert = "cpm", batch = FALSE, filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'only_two_cf_known' not found
only_two_cf_known_pca <- plot_pca(only_two_cf_known_norm,
                                  plot_title = "PCA of z2.2 and z2.3 parasite expression values",
                                  plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'only_two_cf_known_norm' not found
dev <- pp(file = "figures/cure_fail_sus_shape_onlyz22_z23_known.pdf")
only_two_cf_known_pca$plot
## Error: object 'only_two_cf_known_pca' not found
dev.off()
## png 
##   2
only_two_cf_known_pca
## Error: object 'only_two_cf_known_pca' not found
cf_nb <- normalize_expt(lp_cf, convert = "cpm", transform = "log2",
                        filter = TRUE, batch = "svaseq")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_cf' not found
cf_nb_pca <- plot_pca(cf_nb, plot_title = "PCA of parasite expression values",
                      plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'cf_nb' not found
dev <- pp(file = "images/cf_sus_share_nb.png")
cf_nb_pca$plot
## Error: object 'cf_nb_pca' not found
closed <- dev.off()
cf_nb_pca
## Error: object 'cf_nb_pca' not found
cf_norm <- normalize_expt(lp_cf, transform = "log2", convert = "cpm",
                          filter = TRUE, norm = "quant")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_cf' not found
test <- pca_information(cf_norm,
                        expt_factors = c("clinicalcategorical", "zymodemecategorical",
                                         "pathogenstrain", "passagenumber"),
                        num_components = 6, plot_pcas = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'pca_information': object 'cf_norm' not found
test$anova_p
## Error: object 'test' not found
test$cor_heatmap
## Error: object 'test' not found

1.9 By Current drug sensitivity assay data

We have two competing metrics of antmonial sensitivity; one historical and one current. In both cases there is a reasonable expectation that resistant strains tend to be zymodeme 2.3 and sensitive strains tend to be zymodeme 2.2. There appear to be more exceptions to this rule of thumb in the current data than the historical.

dim(exprs(lp_susceptibility))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_susceptibility' not found
sus_norm <- normalize_expt(lp_susceptibility, transform = "log2", convert = "cpm",
                           norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_susceptibility' not found
sus_pca <- plot_pca(sus_norm, plot_title = "PCA of parasite expression values",
                    plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_norm' not found
dev <- pp(file = "figures/sus_norm_pca.svg")
sus_pca[["plot"]]
## Error: object 'sus_pca' not found
closed <- dev.off()
dev <- pp(file = "figures/sus_norm_pca.pdf")
sus_pca[["plot"]]
## Error: object 'sus_pca' not found
closed <- dev.off()
sus_pca
## Error: object 'sus_pca' not found
lp_susceptibility_known <- subset_expt(lp_susceptibility, subset = "batch!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_susceptibility' not found
sus_known_norm <- normalize_expt(lp_susceptibility_known, transform = "log2", convert = "cpm",
                                 norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_susceptibility_known' not found
sus_known_pca <- plot_pca(sus_known_norm, plot_title = "PCA of parasite expression values",
                          plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_known_norm' not found
dev <- pp(file = "figures/sus_norm_known_pca.pdf")
sus_known_pca[["plot"]]
## Error: object 'sus_known_pca' not found
closed <- dev.off()
sus_known_pca
## Error: object 'sus_known_pca' not found
lp_sus_two <- subset_expt(lp_susceptibility, subset = "zymodemecategorical!='z21'") %>%
  subset_expt(subset = "zymodemecategorical!='z24'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_susceptibility' not found
sus_two_norm <- normalize_expt(lp_sus_two, transform = "log2", convert = "cpm",
                               norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_sus_two' not found
sus_two_pca <- plot_pca(sus_two_norm, plot_title = "PCA of parasite expression values",
                        plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_two_norm' not found
dev <- pp(file = "figures/sus_norm_two_pca.pdf")
sus_two_pca[["plot"]]
## Error: object 'sus_two_pca' not found
closed <- dev.off()
sus_two_pca
## Error: object 'sus_two_pca' not found
lp_sus_two_known <- subset_expt(lp_sus_two, subset = "clinicalcategorical!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_sus_two' not found
sus_two_known_norm <- normalize_expt(lp_sus_two_known, transform = "log2", convert = "cpm",
                                     norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_sus_two_known' not found
sus_two_known_pca <- plot_pca(sus_two_known_norm, plot_title = "PCA of parasite expression values",
                              plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_two_known_norm' not found
dev <- pp(file = "figures/sus_norm_two_known_pca.pdf")
sus_two_known_pca[["plot"]]
## Error: object 'sus_two_known_pca' not found
closed <- dev.off()
sus_two_known_pca
## Error: object 'sus_two_known_pca' not found
sus_nb <- normalize_expt(lp_susceptibility, transform = "log2", convert = "cpm",
                         batch = "svaseq", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_susceptibility' not found
sus_nb_pca <- plot_pca(sus_nb, plot_title = "PCA of parasite expression values",
                       plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_nb' not found
dev <- pp(file = "images/sus_nb_pca.png")
sus_nb_pca[["plot"]]
## Error: object 'sus_nb_pca' not found
closed <- dev.off()
sus_nb_pca
## Error: object 'sus_nb_pca' not found

1.10 By Historical drug sensitivity assay data

sus_hist_norm <- normalize_expt(lp_susceptibility_historical, transform = "log2", convert = "cpm",
                                norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_susceptibility_historical' not found
sus_hist_pca <- plot_pca(sus_hist_norm, plot_title = "PCA of parasite expression values",
                         plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_hist_norm' not found
dev <- pp(file = "images/sus_hist_norm_pca.png")
sus_hist_pca[["plot"]]
## Error: object 'sus_hist_pca' not found
closed <- dev.off()
sus_hist_pca
## Error: object 'sus_hist_pca' not found
sus_hist_nb <- normalize_expt(lp_susceptibility_historical, transform = "log2", convert = "cpm",
                              batch = "svaseq", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_susceptibility_historical' not found
sus_hist_nb_pca <- plot_pca(sus_hist_nb, plot_title = "PCA of parasite expression values",
                            plot_labels = FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'sus_hist_nb' not found
dev <- pp(file = "images/sus_hist_nb_pca.png")
sus_hist_nb_pca[["plot"]]
## Error: object 'sus_hist_nb_pca' not found
closed <- dev.off()
sus_hist_nb_pca
## Error: object 'sus_hist_nb_pca' not found

1.11 Zymodeme enzyme gene IDs

Najib read me an email listing off the gene names associated with the zymodeme classification. I took those names and cross referenced them against the Leishmania panamensis gene annotations and found the following:

They are:

  1. ALAT: LPAL13_120010900 – alanine aminotransferase
  2. ASAT: LPAL13_340013000 – aspartate aminotransferase
  3. G6PD: LPAL13_000054100 – glucase-6-phosphate 1-dehydrogenase
  4. NH: LPAL13_14006100, LPAL13_180018500 – inosine-guanine nucleoside hydrolase
  5. MPI: LPAL13_320022300 (maybe) – mannose phosphate isomerase (I chose phosphomannose isomerase)

Given these 6 gene IDs (NH has two gene IDs associated with it), I can do some looking for specific differences among the various samples.

1.11.1 Expression levels of zymodeme genes

The following creates a colorspace (red to green) heatmap showing the observed expression of these genes in every sample.

my_genes <- c("LPAL13_120010900", "LPAL13_340013000", "LPAL13_000054100",
              "LPAL13_140006100", "LPAL13_180018500", "LPAL13_320022300",
              "other")
my_names <- c("ALAT", "ASAT", "G6PD", "NHv1", "NHv2", "MPI", "other")

zymo_expt <- exclude_genes_expt(strain_norm, ids = my_genes, method = "keep")
## Error in exclude_genes_expt(strain_norm, ids = my_genes, method = "keep"): could not find function "exclude_genes_expt"
zymo_heatmap <- plot_sample_heatmap(zymo_expt, row_label = my_names)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_sample_heatmap': object 'zymo_expt' not found
zymo_heatmap
## Error: object 'zymo_heatmap' not found

A recent suggestion included a query about the relationship of our amastigote TMRC2 samples which were the result of infecting a set of macrophages vs. these promastigote samples.

So far, we have kept these two experiments separate, now let us merge them.

tmrc2_macrophage_norm <- normalize_expt(lp_macrophage, transform = "log2", convert = "cpm",
                                        norm = "quant", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'lp_macrophage' not found
## Hey you, this annotation call should be made automatic for the container!
annotation(lp_expt) <- "org.Lpanamensis.MHOMCOL81L13.v46.eg.db"
## Error: object 'lp_expt' not found
annotation(lp_macrophage) <- annotation(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'annotation': object 'lp_expt' not found
all_tmrc2 <- combine_expts(lp_expt, lp_macrophage)
## Error: object 'lp_expt' not found

Before we can use the combined data, we must reconcile a few of aspects of it, notably we need to specify which samples are amastigotes and which are promastigotes.

all_nosb <- all_tmrc2
## Error: object 'all_tmrc2' not found
pData(all_nosb)[["stage"]] <- "promastigote"
## Error: object 'all_nosb' not found
na_idx <- is.na(pData(all_nosb)[["macrophagetreatment"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'all_nosb' not found
pData(all_nosb)[na_idx, "macrophagetreatment"] <- "undefined"
## Error: object 'all_nosb' not found
all_nosb <- subset_expt(all_nosb, subset = "macrophagetreatment!='inf_sb'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'all_nosb' not found
ama_idx <- pData(all_nosb)[["macrophagetreatment"]] == "inf"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'all_nosb' not found
pData(all_nosb)[ama_idx, "stage" ] <- "amastigote"
## Error: object 'all_nosb' not found
## Make sure that the zymodeme does not have the inf_ prefix.
zymodeme_char <- gsub(x = pData(all_nosb)[["condition"]], pattern = "^inf_", replacement = "")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'all_nosb' not found
pData(all_nosb)[["condition"]] <- zymodeme_char
## Error: object 'zymodeme_char' not found
pData(all_nosb)[["batch"]] <- pData(all_nosb)[["stage"]]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'all_nosb' not found
all_norm <- normalize_expt(all_nosb, convert = "cpm", norm = "quant",
                           transform = "log2", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'all_nosb' not found
pro_ama_pca <- plot_pca(all_norm)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'all_norm' not found
pro_ama_pca[["plot"]]
## Error: object 'pro_ama_pca' not found

I think the above picture is sort of the opposite of what we want to compare in a DE analysis for this set of data, e.g. we want to compare promastigotes from amastigotes?

two_nosb <- set_expt_batches(all_nosb, fact = "condition") %>%
  set_expt_conditions(fact = "stage") %>%
  subset_expt(subset = "batch=='z2.2'|batch=='z2.3'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'expt' in selecting a method for function 'set_expt_batches': object 'all_nosb' not found
two_norm <- normalize_expt(two_nosb, convert = "cpm", norm = "quant",
                           transform = "log2", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'two_nosb' not found
pro_ama_two_pca <- plot_pca(two_norm)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'two_norm' not found
pro_ama_two_pca[["plot"]]
## Error: object 'pro_ama_two_pca' not found
zy_stage_factor <- paste0(pData(two_nosb)[["batch"]], "_",
                          pData(two_nosb)[["stage"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'two_nosb' not found
pData(two_nosb)[["zystage"]] <- zy_stage_factor
## Error: object 'zy_stage_factor' not found
zystage <- set_expt_conditions(two_nosb, fact = "zystage")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'two_nosb' not found
zystage_norm <- normalize_expt(zystage, filter = TRUE, norm = "quant",
                               convert = "cpm", transform = "log2")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'state': object 'zystage' not found
plot_pca(zystage_norm)$plot
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'zystage_norm' not found
zystage_keepers <- list(
  "z2322_ama" = c("z23amastigote", "z22amastigote"),
  "z2322_pro" = c("z23promastigote", "z22promastigote"),
  "proama_z23" = c("z23amastigote", "z23promastigote"),
  "proama_z22" = c("z22amastigote", "z22promastigote"))

zystage_de <- all_pairwise(zystage, filter = TRUE, model_batch = "svaseq")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'zystage' not found
zystage_tables <- combine_de_tables(
  zystage_de, keepers = zystage_keepers,
  excel = glue("excel/zymodeme_stage_table-v{ver}.xlsx"))
## Error: object 'zystage_de' not found

2 Gene expression with respect to chromosome

I want to make a plot where the x-axis is the number of genes on a chromosome and the y-axis is the mean of the expression of those genes.

exprs_by_chr_plot <- plot_exprs_by_chromosome(lp_zymo)
## Error in plot_exprs_by_chromosome(lp_zymo): could not find function "plot_exprs_by_chromosome"
exprs_by_chr_plot[["plot"]]
## Error: object 'exprs_by_chr_plot' not found

3 SNP profiles

One potentially interesting aspect of the variant data: it may be able to help us define the zymodeme state of previous, untested samples.

In order to test this, I am loading some of the 2016 data alongside the new TMRC2 data to see if they fit together.

This is using an older dataset for which I am not sure we have permissions to include in the container, so I am turning them off for now.

old_expt <- create_expt("sample_sheets/tmrc2_samples_20191203.xlsx",
                        file_column = "tophat2file")

tt <- old_expt$expressionset
rownames(tt) <- gsub(pattern = "^exon_", replacement = "", x = rownames(tt))
rownames(tt) <- gsub(pattern = "\\.1$", replacement = "", x = rownames(tt))
old_expt$expressionset <- tt
rm(tt)

3.1 Create the SNP expressionset

One other important caveat, we have a group of new samples which have not yet run through the variant search pipeline, so I need to remove them from consideration. Though it looks like they finished overnight…

In the non-containerized version of this document, the following block combines an older dataset with the current data.

both_norm <- normalize_expt(new_snps, transform = "log2", norm = "quant") %>%
  set_expt_conditions(fact = "pathogenstrain")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'input' in selecting a method for function 'state': object 'new_snps' not found

The data structure ‘both_norm’ now contains our 2016 data along with the newer data collected since 2019.

3.2 Plot of SNP profiles for zymodemes

The following plot shows the SNP profiles of all samples (old and new) where the colors at the top show either the 2.2 strains (orange), 2.3 strains (green), the previous samples (purple), or the various lab strains (pink etc).

new_variant_heatmap <- plot_disheat(new_snps)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input_data' in selecting a method for function 'plot_heatmap': object 'new_snps' not found
dev <- pp(file = "images/raw_snp_disheat.png", height = 12, width = 12)
new_variant_heatmap$plot
## Error: object 'new_variant_heatmap' not found
closed <- dev.off()
new_variant_heatmap$plot
## Error: object 'new_variant_heatmap' not found

The function get_snp_sets() takes the provided metadata factor (in this case ‘condition’) and looks for variants which are exclusive to each element in it. In this case, this is looking for differences between 2.2 and 2.3, as well as the set shared among them.

snp_sets <- get_snp_sets(new_snps, factor = "condition")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'new_snps' not found
snp_sets
## Error: object 'snp_sets' not found
##Biobase::annotation(old_expt$expressionset) = Biobase::annotation(lp_expt$expressionset)
##both_expt <- combine_expts(lp_expt, old_expt)

snp_genes <- sm(snps_vs_genes(lp_expt, snp_sets, expt_name_col = "chromosome"))
## Error in snps_vs_genes(lp_expt, snp_sets, expt_name_col = "chromosome"): unused argument (expt_name_col = "chromosome")
snp_genes
## Error: object 'snp_genes' not found
## I think we have some metrics here we can plot...
snp_subset <- snp_subset_genes(
  lp_expt, new_snps,
  genes = c("LPAL13_120010900", "LPAL13_340013000", "LPAL13_000054100",
            "LPAL13_140006100", "LPAL13_180018500", "LPAL13_320022300"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rowData': object 'lp_expt' not found
zymo_heat <- plot_sample_heatmap(snp_subset, row_label = rownames(exprs(snp_subset)))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_sample_heatmap': object 'snp_subset' not found
zymo_heat
## Error: object 'zymo_heat' not found

3.3 Compare variants to DE genes

Najib has asked a few times about the relationship between variants and DE genes. In subsequent conversations I figured out what he really wants to learn is variants in the UTR (most likely 5’) which might affect expression of genes. The following explicitly does not help this question, but is a paralog: is there a relationship between variants in the CDS and differential expression?

3.3.1 Collect DE data

In order to do this comparison, we need to reload some of the DE results.

These blocks need to be moved to post-differential analyses

rda <- glue("rda/zymo_tables_sva-v{ver}.rda")
varname <- gsub(x = basename(rda), pattern = "\\.rda", replacement = "")
loaded <- load(file = rda)
zy_df <- get0(varname)[["data"]][["zymodeme"]]
vars_df <- data.frame(ID = names(snp_genes$summary_by_gene), variants = as.numeric(snp_genes$summary_by_gene))
vars_df[["variants"]] <- log2(vars_df[["variants"]] + 1)
vars_by_de_gene <- merge(zy_df, vars_df, by.x = "row.names", by.y = "ID")
cor.test(vars_by_de_gene$deseq_logfc, vars_by_de_gene$variants)
variants_wrt_logfc <- plot_linear_scatter(vars_by_de_gene[, c("deseq_logfc", "variants")])
variants_wrt_logfc$scatter
## It looks like there might be some genes of interest, even though this is not actually
## the question of interest.

Didn’t I create a set of densities by chromosome? Oh I think they come in from get_snp_sets()

3.4 SNPS associated with clinical response in the TMRC samples

clinical_sets <- get_snp_sets(new_snps, factor = "clinicalresponse")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'new_snps' not found
clinical_sets
## Error: object 'clinical_sets' not found
density_vec <- clinical_sets[["density"]]
## Error: object 'clinical_sets' not found
chromosome_idx <- grep(pattern = "LpaL", x = names(density_vec))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grep': object 'density_vec' not found
density_df <- as.data.frame(density_vec[chromosome_idx])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'density_vec' not found
density_df[["chr"]] <- rownames(density_df)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'density_df' not found
colnames(density_df) <- c("density_vec", "chr")
## Error: object 'density_df' not found
var_den_chr <- ggplot(density_df, aes(x = chr, y = density_vec)) +
  ggplot2::geom_col() +
  ggplot2::theme(axis.text = ggplot2::element_text(size = 10, colour = "black"),
                 axis.text.x = ggplot2::element_text(angle = 90, vjust = 0.5))
## Error: object 'density_df' not found
var_den_chr
## Error: object 'var_den_chr' not found
pp(file = "figures/variant_density_by_chromosome.pdf")
var_den_chr
## Error: object 'var_den_chr' not found
dev.off()
## png 
##   2
## oops, forgot to export write_snps...  fixed.
clinical_written <- write_snps(new_snps, output_file = "clinical_variants.aln")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'assay': object 'new_snps' not found

3.4.1 Cross reference these variants by gene

clinical_genes <- snps_vs_genes(lp_expt, clinical_sets, expt_name_col = "chromosome")
## Error in snps_vs_genes(lp_expt, clinical_sets, expt_name_col = "chromosome"): unused argument (expt_name_col = "chromosome")
snp_density <- merge(as.data.frame(clinical_genes[["summary"]]),
                     as.data.frame(fData(lp_expt)),
                     by = "row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_genes' not found
snp_density <- snp_density[, c(1, 2, 4, 15)]
## Error: object 'snp_density' not found
colnames(snp_density) <- c("name", "snps", "product", "length")
## Error: object 'snp_density' not found
snp_density[["product"]] <- tolower(snp_density[["product"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'tolower': object 'snp_density' not found
snp_density[["length"]] <- as.numeric(snp_density[["length"]])
## Error: object 'snp_density' not found
snp_density[["density"]] <- as.numeric(snp_density[["snps"]]) / snp_density[["length"]]
## Error: object 'snp_density' not found
snp_idx <- order(snp_density[["density"]], decreasing = TRUE)
## Error: object 'snp_density' not found
snp_density <- snp_density[snp_idx, ]
## Error: object 'snp_density' not found
removers <- c("amastin", "gp63", "leishmanolysin")
for (r in removers) {
  drop_idx <- grepl(pattern = r, x = snp_density[["product"]])
  snp_density <- snp_density[!drop_idx, ]
}
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': object 'snp_density' not found
## Filter these for [A|a]mastin gp63 Leishmanolysin

Let us grab out the number of variants/gene for the cure/fail samples, merge them into a dataframe, and add that to the gene annotations for the lp_expt datastructure.

clinical_snps <- snps_intersections(lp_expt, clinical_sets, chr_column = "chromosome")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rowData': object 'lp_expt' not found
fail_ref_snps <- as.data.frame(clinical_snps[["inters"]][["failure, reference strain"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
fail_ref_snps <- rbind(fail_ref_snps,
                       as.data.frame(clinical_snps[["inters"]][["failure"]]))
## Error: object 'fail_ref_snps' not found
cure_snps <- as.data.frame(clinical_snps[["inters"]][["cure"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
head(fail_ref_snps)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'head': object 'fail_ref_snps' not found
head(cure_snps)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'head': object 'cure_snps' not found
write.csv(file = "excel/cure_variants.txt", x = rownames(cure_snps))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'cure_snps' not found
write.csv(file = "excel/fail_variants.txt", x = rownames(fail_ref_snps))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'fail_ref_snps' not found
annot <- fData(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': object 'lp_expt' not found
clinical_interest_cure <- as.data.frame(clinical_snps[["gene_summaries"]][["cure"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
summary(clinical_interest_cure)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'clinical_interest_cure' not found
clinical_interest_fail <- as.data.frame(clinical_snps[["gene_summaries"]][["failure"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
summary(clinical_interest_fail)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'clinical_interest_fail' not found
clinical_interest <- merge(clinical_interest_cure,
                           clinical_interest_fail,
                           by = "row.names", all = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'clinical_interest_cure' not found
rownames(clinical_interest) <- clinical_interest[["Row.names"]]
## Error: object 'clinical_interest' not found
clinical_interest[["Row.names"]] <- NULL
## Error: object 'clinical_interest' not found
colnames(clinical_interest) <- c("cure_snps", "fail_snps")
## Error: object 'clinical_interest' not found
clinical_annot <- merge(annot, clinical_interest, by = "row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'annot' not found
rownames(annot) <- annot[["Row.names"]]
## Error: object 'annot' not found
annot[["Row.names"]] <- NULL
## Error: object 'annot' not found
dim(annot)
## Error: object 'annot' not found
dim(fData(lp_expt))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': object 'lp_expt' not found
fData(lp_expt) <- annot
## Error: object 'annot' not found

4 Zymodeme for new samples

The heatmap produced here should show the variants only for the zymodeme genes.

4.1 Hunt for snp clusters

I am thinking that if we find clusters of locations which are variant, that might provide some PCR testing possibilities.

## Drop the 2.1, 2.4, unknown, and null
pruned_snps <- subset_expt(new_snps, subset = "condition=='z2.2'|condition=='z2.3'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'new_snps' not found
new_sets <- get_snp_sets(pruned_snps, factor = "zymodemecategorical")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'pruned_snps' not found
summary(new_sets)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found
## 1000000: 2.2
## 0100000: 2.3

summary(new_sets[["intersections"]][["10"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found
write.csv(file = "excel/variants_22.csv", x = new_sets[["intersections"]][["10"]])
## Error in eval(expr, p): object 'new_sets' not found
summary(new_sets[["intersections"]][["01"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found
write.csv(file = "excel/variants_23.csv", x = new_sets[["intersections"]][["01"]])
## Error in eval(expr, p): object 'new_sets' not found

Thus we see that there are 3,553 variants associated with 2.2 and 81,589 associated with 2.3.

4.1.1 A small function for searching for potential PCR primers

The following function uses the positional data to look for sequential mismatches associated with zymodeme in the hopes that there will be some regions which would provide good potential targets for a PCR-based assay.

sequential_variants <- function(snp_sets, conditions = NULL, minimum = 3, maximum_separation = 3) {
  if (is.null(conditions)) {
    conditions <- 1
  }
  intersection_sets <- snp_sets[["intersections"]]
  intersection_names <- snp_sets[["set_names"]]
  chosen_intersection <- 1
  if (is.numeric(conditions)) {
    chosen_intersection <- conditions
  } else {
    intersection_idx <- intersection_names == conditions
    chosen_intersection <- names(intersection_names)[intersection_idx]
  }

  possible_positions <- intersection_sets[[chosen_intersection]]
  position_table <- data.frame(row.names = possible_positions)
  pat <- "^chr_(.+)_pos_(.+)_ref_.*$"
  position_table[["chr"]] <- gsub(pattern = pat, replacement = "\\1", x = rownames(position_table))
  position_table[["pos"]] <- as.numeric(gsub(pattern = pat, replacement = "\\2", x = rownames(position_table)))
  position_idx <- order(position_table[, "chr"], position_table[, "pos"])
  position_table <- position_table[position_idx, ]
  position_table[["dist"]] <- 0

  last_chr <- ""
  for (r in 1:nrow(position_table)) {
    this_chr <- position_table[r, "chr"]
    if (r == 1) {
      position_table[r, "dist"] <- position_table[r, "pos"]
      last_chr <- this_chr
      next
    }
    if (this_chr == last_chr) {
      position_table[r, "dist"] <- position_table[r, "pos"] - position_table[r - 1, "pos"]
    } else {
      position_table[r, "dist"] <- position_table[r, "pos"]
    }
    last_chr <- this_chr
  }

  ## Working interactively here.

  doubles <- position_table[["dist"]] == 1
  doubles <- position_table[doubles, ]
  write.csv(doubles, "doubles.csv")

  one_away <- position_table[["dist"]] == 2
  one_away <- position_table[one_away, ]
  write.csv(one_away, "one_away.csv")

  two_away <- position_table[["dist"]] == 3
  two_away <- position_table[two_away, ]
  write.csv(two_away, "two_away.csv")

  combined <- rbind(doubles, one_away)
  combined <- rbind(combined, two_away)
  position_idx <- order(combined[, "chr"], combined[, "pos"])
  combined <- combined[position_idx, ]

  this_chr <- ""
  for (r in 1:nrow(combined)) {
    this_chr <- combined[r, "chr"]
    if (r == 1) {
      combined[r, "dist_pair"] <- combined[r, "pos"]
      last_chr <- this_chr
      next
    }
    if (this_chr == last_chr) {
      combined[r, "dist_pair"] <- combined[r, "pos"] - combined[r - 1, "pos"]
    } else {
      combined[r, "dist_pair"] <- combined[r, "pos"]
    }
    last_chr <- this_chr
  }

  dist_pair_maximum <- 1000
  dist_pair_minimum <- 200
  dist_pair_idx <- combined[["dist_pair"]] <= dist_pair_maximum &
    combined[["dist_pair"]] >= dist_pair_minimum
  remaining <- combined[dist_pair_idx, ]
  no_weak_idx <- grepl(pattern = "ref_(G|C)", x = rownames(remaining))
  remaining <- remaining[no_weak_idx, ]

  print(head(table(position_table[["dist"]])))
  sequentials <- position_table[["dist"]] <= maximum_separation
  message("There are ", sum(sequentials), " candidate regions.")

  ## The following can tell me how many runs of each length occurred, that is not quite what I want.
  ## Now use run length encoding to find the set of sequential sequentials!
  rle_result <- rle(sequentials)
  rle_values <- rle_result[["values"]]
  ## The following line is equivalent to just leaving values alone:
  ## true_values <- rle_result[["values"]] == TRUE
  rle_lengths <- rle_result[["lengths"]]
  true_sequentials <- rle_lengths[rle_values]
  rle_idx <- cumsum(rle_lengths)[which(rle_values)]

  position_table[["last_sequential"]] <- 0
  count <- 0
  for (r in rle_idx) {
    count <- count + 1
    position_table[r, "last_sequential"] <- true_sequentials[count]
  }
  message("The maximum sequential set is: ", max(position_table[["last_sequential"]]), ".")

  wanted_idx <- position_table[["last_sequential"]] >= minimum
  wanted <- position_table[wanted_idx, c("chr", "pos")]
  return(wanted)
}

zymo22_sequentials <- sequential_variants(new_sets, conditions = "z22",
                                          minimum = 1, maximum_separation = 2)
dim(zymo22_sequentials)
## 7 candidate regions for zymodeme 2.2 -- thus I am betting that the reference strain is a 2.2
zymo23_sequentials <- sequential_variants(new_sets, conditions = "z23",
                                          minimum = 2, maximum_separation = 2)
dim(zymo23_sequentials)
## In contrast, there are lots (587) of interesting regions for 2.3!

4.1.2 Extract a promising region from the genome

The first 4 candidate regions from my set of remaining: * Chr Pos. Distance * LpaL13-15 238433 448 * LpaL13-18 142844 613 * LpaL13-29 830342 252 * LpaL13-33 1331507 843

Lets define a couple of terms: * Third: Each of the 4 above positions. * Second: Third - Distance * End: Third + PrimerLen * Start: Second - Primerlen

In each instance, these are the last positions, so we want to grab three things:

  • The entire region from End -> Start, this way we can have a quick sanity check.
  • Start -> Second.
  • (Third -> End) <- Reverse complemented
## * LpaL13-15 238433 448
first_candidate_chr <- lp_genome[["LpaL13_15"]]
primer_length <- 22
amplicon_length <- 448
first_candidate_third <- 238433
first_candidate_second <- first_candidate_third - amplicon_length
first_candidate_start <- first_candidate_second - primer_length
first_candidate_end <- first_candidate_third + primer_length
first_candidate_region <- subseq(first_candidate_chr, first_candidate_start, first_candidate_end)
first_candidate_region
first_candidate_5p <- subseq(first_candidate_chr, first_candidate_start, first_candidate_second)
as.character(first_candidate_5p)
first_candidate_3p <- spgs::reverseComplement(subseq(first_candidate_chr, first_candidate_third, first_candidate_end))
first_candidate_3p

## * LpaL13-18 142844 613
second_candidate_chr <- lp_genome[["LpaL13_18"]]
primer_length <- 22
amplicon_length <- 613
second_candidate_third <- 142844
second_candidate_second <- second_candidate_third - amplicon_length
second_candidate_start <- second_candidate_second - primer_length
second_candidate_end <- second_candidate_third + primer_length
second_candidate_region <- subseq(second_candidate_chr, second_candidate_start, second_candidate_end)
second_candidate_region
second_candidate_5p <- subseq(second_candidate_chr, second_candidate_start, second_candidate_second)
as.character(second_candidate_5p)
second_candidate_3p <- spgs::reverseComplement(subseq(second_candidate_chr, second_candidate_third, second_candidate_end))
second_candidate_3p


## * LpaL13-29 830342 252
third_candidate_chr <- lp_genome[["LpaL13_29"]]
primer_length <- 22
amplicon_length <- 252
third_candidate_third <- 830342
third_candidate_second <- third_candidate_third - amplicon_length
third_candidate_start <- third_candidate_second - primer_length
third_candidate_end <- third_candidate_third + primer_length
third_candidate_region <- subseq(third_candidate_chr, third_candidate_start, third_candidate_end)
third_candidate_region
third_candidate_5p <- subseq(third_candidate_chr, third_candidate_start, third_candidate_second)
as.character(third_candidate_5p)
third_candidate_3p <- spgs::reverseComplement(subseq(third_candidate_chr, third_candidate_third, third_candidate_end))
third_candidate_3p
## You are a garbage polypyrimidine tract.
## Which is actually interesting if the mutations mess it up.


## * LpaL13-33 1331507 843
fourth_candidate_chr <- lp_genome[["LpaL13_33"]]
primer_length <- 22
amplicon_length <- 843
fourth_candidate_third <- 1331507
fourth_candidate_second <- fourth_candidate_third - amplicon_length
fourth_candidate_start <- fourth_candidate_second - primer_length
fourth_candidate_end <- fourth_candidate_third + primer_length
fourth_candidate_region <- subseq(fourth_candidate_chr, fourth_candidate_start, fourth_candidate_end)
fourth_candidate_region
fourth_candidate_5p <- subseq(fourth_candidate_chr, fourth_candidate_start, fourth_candidate_second)
as.character(fourth_candidate_5p)
fourth_candidate_3p <- spgs::reverseComplement(subseq(fourth_candidate_chr, fourth_candidate_third, fourth_candidate_end))
fourth_candidate_3p

4.2 Go hunting for Sanger sequencing regions

I made a fun little function which should find regions which have lots of variants associated with a given experimental factor.

pheno <- subset_expt(lp_expt, subset = "condition=='z2.2'|condition=='z2.3'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_expt' not found
pheno <- subset_expt(pheno, subset = "!is.na(pData(pheno)[['bcftable']])")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'pheno' not found
pheno_snps <- count_expt_snps(pheno, annot_column = "freebayessummary", snp_column="PAIRED")
## Error in count_expt_snps(pheno, annot_column = "freebayessummary", snp_column = "PAIRED"): could not find function "count_expt_snps"
##pheno_snps <- sm(count_expt_snps(pheno, annot_column = "bcftable"))

4.3 SNP Density Primers

I cannot run the following block in the container unless/until I copy the gff into it…

fun_stuff <- snp_density_primers(
  pheno_snps,
  bsgenome = "BSGenome.Leishmania.panamensis.MHOMCOL81L13.v53",
  gff = "reference/TriTrypDB-53_LpanamensisMHOMCOL81L13.gff")
drop_scaffolds <- grepl(x = rownames(fun_stuff$favorites), pattern = "SCAF")
favorite_primer_regions <- fun_stuff[["favorites"]][!drop_scaffolds, ]
favorite_primer_regions[["bin"]] <- rownames(favorite_primer_regions)

favorite_primer_regions <- favorite_primer_regions %>%
  relocate(bin)

4.4 Combine this table with 2.2/2.3 genes

Here is my note from our meeting:

Cross reference primers to DE genes of 2.2/2.3 and/or resistance/suscpetible, add a column to the primer spreadsheet with the DE genes (in retrospect I am guessing this actually means to put the logFC as a column.

One nice thing, I did a semantic removal on the lp_expt, so the set of logFC/pvalues should not have any of the offending types; thus I should be able to automagically get rid of them in the merge.

This block needs to go after differential expression analyses.

logfc <- zy_table_sva[["data"]][["z23_vs_z22"]]
logfc_columns <- logfc[, c("deseq_logfc", "deseq_adjp")]
colnames(logfc_columns) <- c("z23_logfc", "z23_adjp")
new_table <- merge(favorite_primer_regions, logfc_columns,
                   by.x = "closest_gene_before_id", by.y = "row.names")
sus <- sus_table_sva[["data"]][["sensitive_vs_resistant"]]
sus_columns <- sus[, c("deseq_logfc", "deseq_adjp")]
colnames(sus_columns) <- c("sus_logfc", "sus_adjp")
new_table <- merge(new_table, sus_columns,
                   by.x = "closest_gene_before_id", by.y = "row.names") %>%
  relocate(bin)
written <- write_xlsx(data = new_table,
                      excel = "excel/favorite_primers_xref_zy_sus.xlsx")

4.5 Make a heatmap describing the clustering of variants

We can cross reference the variants against the zymodeme status and plot a heatmap of the results and hopefully see how they separate.

snp_genes <- sm(snps_vs_genes(lp_expt, new_sets, expt_name_col = "chromosome"))
## Error in snps_vs_genes(lp_expt, new_sets, expt_name_col = "chromosome"): unused argument (expt_name_col = "chromosome")
clinical_colors_v2 <- list(
  "z22" = "#0000cc",
  "z23" = "#cc0000")
new_zymo_norm <- normalize_expt(pruned_snps, norm = "quant") %>%
  set_expt_conditions(fact = "zymodemecategorical") %>%
  set_expt_colors(clinical_colors_v2)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'input' in selecting a method for function 'state': object 'pruned_snps' not found
zymo_heat <- plot_disheat(new_zymo_norm)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input_data' in selecting a method for function 'plot_heatmap': object 'new_zymo_norm' not found
dev <- pp(file = "images/onlyz22_z23_snp_heatmap.pdf", width = 12, height = 12)
zymo_heat[["plot"]]
## Error: object 'zymo_heat' not found
closed <- dev.off()
zymo_heat
## Error: object 'zymo_heat' not found

4.5.1 Annotated heatmap of variants

Now let us try to make a heatmap which includes some of the annotation data.

des <- pData(both_norm)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'both_norm' not found
undef_idx <- is.na(des[["pathogenstrain"]])
## Error: object 'des' not found
des[undef_idx, "pathogenstrain"] <- "unknown"
## Error: object 'des' not found
##hmcols <- colorRampPalette(c("yellow","black","darkblue"))(256)
correlations <- hpgl_cor(exprs(both_norm))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'both_norm' not found
na_idx <- is.na(correlations)
## Error: object 'correlations' not found
correlations[na_idx] <- 0
## Error: object 'correlations' not found
## Make an initial heatmap via plot_disheat, which may get used as the figure:
initial_snps <- set_expt_conditions(both_norm, fact = "zymodemereference", colors = color_choices[["strain"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'both_norm' not found
initial_disheat <- plot_disheat(both_norm)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input_data' in selecting a method for function 'plot_heatmap': object 'both_norm' not found
dev <- pp(file = "figures/initial_snp_heatmap.pdf", width = 20, height = 20)
initial_disheat[["plot"]]
## Error: object 'initial_disheat' not found
closed <- dev.off()
zymo_heat
## Error: object 'zymo_heat' not found
zymo_missing_idx <- is.na(des[["zymodemecategorical"]])
## Error: object 'des' not found
des[["zymodemecategorical"]] <- as.character(des[["zymodemecategorical"]])
## Error: object 'des' not found
des[["clinicalcategorical"]] <- as.character(des[["clinicalcategorical"]])
## Error: object 'des' not found
des[zymo_missing_idx, "zymodemecategorical"] <- "unknown"
## Error: object 'des' not found
mydendro <- list(
  "clustfun" = hclust,
  "lwd" = 2.0)
col_data <- as.data.frame(des[, c("zymodemecategorical")])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'des' not found
unknown_clinical <- is.na(des[["clinicalcategorical"]])
## Error: object 'des' not found
colnames(col_data) <- c("zymodeme")
## Error: object 'col_data' not found
row_data <- as.data.frame(des[, c("sus_category_current", "clinicalcategorical")])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'des' not found
colnames(row_data) <- c("susceptibility", "outcome")
## Error: object 'row_data' not found
row_data[unknown_clinical, "outcome"] <- "undefined"
## Error: object 'row_data' not found
myannot <- list(
  "Col" = list("data" = col_data),
  "Row" = list("data" = row_data))
## Error: object 'col_data' not found
myclust <- list("cuth" = 1.0,
                "col" = BrewerClusterCol)
mylabs <- list(
  "Row" = list("nrow" = 4),
  "Col" = list("nrow" = 4))
hmcols <- colorRampPalette(c("darkblue", "beige"))(240)
zymo_annot_heat <- annHeatmap2(
  correlations,
  dendrogram = mydendro,
  annotation = myannot,
  cluster = myclust,
  labels = mylabs,
  ## The following controls if the picture is symmetric
  scale = "none",
  col = hmcols)
## Error: object 'correlations' not found
dev <- pp(file = "images/dendro_heatmap.pdf", height = 20, width = 20)
plot(zymo_annot_heat)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'plot': object 'zymo_annot_heat' not found
closed <- dev.off()
plot(zymo_annot_heat)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'plot': object 'zymo_annot_heat' not found

Print the larger heatmap so that all the labels appear. Keep in mind that as we get more samples, this image needs to continue getting bigger.

4.5.2 CMplot karyogram of variants

I cannot run the following block until/unless I install cmplot in the container. Oh, I did! Let us run it and see what happens.

xref_prop <- table(pheno_snps[["conditions"]])
## Error: object 'pheno_snps' not found
pheno_snps$conditions
## Error: object 'pheno_snps' not found
idx_tbl <- exprs(pheno_snps) > 5
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'pheno_snps' not found
new_tbl <- data.frame(row.names = rownames(exprs(pheno_snps)))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'pheno_snps' not found
for (n in names(xref_prop)) {
  new_tbl[[n]] <- 0
  idx_cols <- which(pheno_snps[["conditions"]] == n)
  prop_col <- rowSums(idx_tbl[, idx_cols]) / xref_prop[n]
  new_tbl[n] <- prop_col
}
## Error: object 'xref_prop' not found
keepers <- grepl(x = rownames(new_tbl), pattern = "LpaL13")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'new_tbl' not found
new_tbl <- new_tbl[keepers, ]
## Error: object 'new_tbl' not found
new_tbl[["strong22"]] <- 1.001 - new_tbl[["z2.2"]]
## Error: object 'new_tbl' not found
new_tbl[["strong23"]] <- 1.001 - new_tbl[["z2.3"]]
## Error: object 'new_tbl' not found
s22_na <- new_tbl[["strong22"]] > 1
## Error: object 'new_tbl' not found
new_tbl[s22_na, "strong22"] <- 1
## Error: object 'new_tbl' not found
s23_na <- new_tbl[["strong23"]] > 1
## Error: object 'new_tbl' not found
new_tbl[s23_na, "strong23"] <- 1
## Error: object 'new_tbl' not found
new_tbl[["SNP"]] <- rownames(new_tbl)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'new_tbl' not found
new_tbl[["Chromosome"]] <- gsub(x = new_tbl[["SNP"]], pattern = "chr_(.*)_pos_.*", replacement = "\\1")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'new_tbl' not found
new_tbl[["Position"]] <- gsub(x = new_tbl[["SNP"]], pattern = ".*_pos_(\\d+)_.*", replacement = "\\1")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'new_tbl' not found
new_tbl <- new_tbl[, c("SNP", "Chromosome", "Position", "strong22", "strong23")]
## Error: object 'new_tbl' not found
simplify <- new_tbl
## Error: object 'new_tbl' not found
simplify[["strong22"]] <- NULL
## Error: object 'simplify' not found
CMplot(new_tbl, bin.size = 10000, threshold = c(0.01, 0.05), plot.type = "d",
       file.name = "variant_density_10k")
## Error: object 'new_tbl' not found
CMplot(new_tbl, bin.size = 1000, threshold = c(0.01, 0.05), plot.type = "d",
       file.name = "variant_density_1k")
## Error: object 'new_tbl' not found
CMplot(new_tbl, bin.size = 100000, threshold = c(0.01, 0.05), plot.type = "d",
       file.name = "variant_density_100k")
## Error: object 'new_tbl' not found
CMplot(new_tbl, plot.type = "m", multracks = TRUE, threshold = c(0.01, 0.05),
       threshold.lwd = c(1,1), threshold.col = c("black","grey"),
       amplify = TRUE, bin.size = 1000,
       chr.den.col = c("darkgreen", "yellow", "red"),
       signal.col = c("red", "green", "blue"),
       signal.cex = 1, file = "jpg", dpi = 300, file.output = TRUE, verbose = TRUE)
## Error: object 'new_tbl' not found
SNP Density
SNP Density

5 A different karyogram

I have been a bit frustrated with the clunkyness of cmplot, so I did some reading and found autoplot. It makes use of g/iranges to plot arbitrary data and as such has the potential to be significantly more generally useful than cmplot. I think I will be able to use it to view a lot of interesting different data types. In this instance I want to plot density of variants associated with various conditions in the data (z2.3/z2.2, cure/fail, whatever). In addition, it might be nice to have the ORFs displayed in some fashion (space permitting).

lp_entry <- get_eupath_entry(species = "MHOM/COL", metadata = meta)
## Error in get_eupath_entry(species = "MHOM/COL", metadata = meta): could not find function "get_eupath_entry"
## These lines cannot run in the container because it cannot write
##txdb_pkgname <- make_eupath_txdb(lp_entry)
##grange_name <- make_eupath_granges(lp_entry)
grange_name <- gsub(x = lp_entry[["GrangesPkg"]], pattern = "\\.rda$", replacement = "")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'lp_entry' not found
grange_filename <- file.path("build", lp_entry[["GrangesPkg"]])
## Error: object 'lp_entry' not found
if (file.exists(grange_filename)) {
  load(grange_filename)
} else {
  created <- dir.create("build/gff", recursive = TRUE)
  grange_build <- make_eupath_granges(lp_entry)
  grange_filename <- grange_build[["rda"]]
  load(grange_filename)
}
## Error: object 'grange_filename' not found
grange_data <- get0(grange_name)
## Error: object 'grange_name' not found
scaffold_idx <- grepl(x = as.character(seqnames(grange_data)), pattern = "SCAF")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': error in evaluating the argument 'x' in selecting a method for function 'seqnames': object 'grange_data' not found
no_scaffolds <- grange_data[!scaffold_idx]
## Error: object 'grange_data' not found
scaffold_idx <- grepl(x = as.character(names(seqinfo(grange_data))), pattern = "SCAF")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': error in evaluating the argument 'x' in selecting a method for function 'seqinfo': object 'grange_data' not found
chr_names <- names(seqinfo(grange_data))[!scaffold_idx]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqinfo': object 'grange_data' not found
no_scaffolds <- seqinfo(grange_data)[chr_names]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqinfo': object 'grange_data' not found
auto_tbl <- new_tbl
## Error: object 'new_tbl' not found
auto_tbl[["position2"]] <- auto_tbl[["Position"]]
## Error: object 'auto_tbl' not found
auto_tbl[["SNP"]] <- NULL
## Error: object 'auto_tbl' not found
rownames(auto_tbl) <- NULL
## Error: object 'auto_tbl' not found
tilesize <- 1000
bins_1k <- GenomicRanges::tileGenome(seqlengths(no_scaffolds), tilewidth = 1000,
                                     cut.last.tile.in.chrom = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqlengths': object 'no_scaffolds' not found
bins_5k <- GenomicRanges::tileGenome(seqlengths(no_scaffolds), tilewidth = 5000,
                                     cut.last.tile.in.chrom = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqlengths': object 'no_scaffolds' not found
bins_10k <- GenomicRanges::tileGenome(seqlengths(no_scaffolds), tilewidth = 10000,
                                  cut.last.tile.in.chrom = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqlengths': object 'no_scaffolds' not found
bins_1nt <- GenomicRanges::tileGenome(seqlengths(no_scaffolds), tilewidth = 1,
                                      cut.last.tile.in.chrom = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'seqlengths': object 'no_scaffolds' not found
auto_tbl[["strand"]] <- "+"
## Error: object 'auto_tbl' not found
## I want to calculate the number of intersecting positions between my auto_tbl and the 1k bins.
start <- auto_tbl[, c("Chromosome", "Position", "position2", "strand", "strong23")]
## Error: object 'auto_tbl' not found
colnames(start) <- c("chr", "start", "end", "strand", "z23")
## Error in `colnames<-`(`*tmp*`, value = c("chr", "start", "end", "strand", : attempt to set 'colnames' on an object with less than two dimensions
start[["chr"]] <- gsub(x = start[["chr"]], pattern = "-", replacement = "_")
## Error in (function (cond) : error in evaluating the argument 'x' in selecting a method for function 'gsub': object of type 'closure' is not subsettable
var_grange <- makeGRangesFromDataFrame(start, seqinfo = no_scaffolds, keep.extra.columns = TRUE)
## Error: object 'no_scaffolds' not found
vars_per_bin <- findOverlaps(bins_1k, var_grange)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'query' in selecting a method for function 'findOverlaps': object 'bins_1k' not found
vars_per_bin_numeric <- as.data.frame(bins_1k)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'bins_1k' not found
vars_per_bin_numeric[["bin"]] <- rownames(vars_per_bin_numeric)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'vars_per_bin_numeric' not found
count_per_bin <- as.data.frame(vars_per_bin) %>%
  group_by(queryHits) %>%
  dplyr::tally()
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'vars_per_bin' not found
colnames(count_per_bin) <- c("bin", "num")
## Error: object 'count_per_bin' not found
vars_per_bin_numeric <- merge(vars_per_bin_numeric, count_per_bin, by = "bin", all.x = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'vars_per_bin_numeric' not found
missing_idx <- is.na(vars_per_bin_numeric[["num"]])
## Error: object 'vars_per_bin_numeric' not found
vars_per_bin_numeric[missing_idx, "num"] <- 0
## Error: object 'vars_per_bin_numeric' not found
vars_per_bin <- vars_per_bin_numeric[, c("seqnames", "start", "end", "width", "strand", "num")]
## Error: object 'vars_per_bin_numeric' not found
vpb_grange <- makeGRangesFromDataFrame(vars_per_bin, seqinfo = no_scaffolds, keep.extra.columns = TRUE)
## Error: object 'vars_per_bin' not found
kary <- autoplot(vpb_grange, layout = "karyogram", aes(color = num, fill = num)) +
  scale_color_gradient(low = "blue", high = "red") +
  scale_fill_gradient(low = "blue", high = "red")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'autoplot': object 'vpb_grange' not found
## theme_bw(base_size = 10) +
pp(file = "karyogram_by_variants.pdf", height = 24, width = 18)
kary
## Error: object 'kary' not found
dev.off()
## png 
##   2
var_kary <- ggbio() +
  layout_karyogram(vpb_grange, aes(color = num, fill = num)) +
  scale_fill_gradient(low = "blue", high = "white") +
  scale_color_gradient(low = "blue", high = "white") +
  theme_bw(base_size = 10)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'layout_karyogram': object 'vpb_grange' not found
var_kary
## Error: object 'var_kary' not found

5.1 Try out MatrixEQTL

This tool looks a little opaque, but provides sample data with things that make sense to me and should be pretty easy to recapitulate in our data.

  1. covariates.txt: Columns are samples, rows are things from pData – the most likely ones of interest for our data would be zymodeme, sensitivity
  2. geneloc.txt: columns are ‘geneid’, ‘chr’, ‘left’, ‘right’. I guess I can assume left and right are start/stop; in which case this is trivially acquirable from fData.
  3. ge.txt: This appears to be a log(rpkm/cpm) table with rows as genes and columns as samples
  4. snpsloc.txt: columns are ‘snpid’, ‘chr’, ‘pos’
  5. snps.txt: columns are samples, rows are the ids from snsploc, values a 0,1,2. I assume 0 is identical and 1..12 are the various A->TGC T->AGC C->AGT G->ACT
## For this, let us use the 'new_snps' data structure.
## Caveat here: these need to be coerced to numbers.
my_covariates <- pData(new_snps)[, c("zymodemecategorical", "clinicalcategorical")]
for (col in colnames(my_covariates)) {
  my_covariates[[col]] <- as.numeric(as.factor(my_covariates[[col]]))
}
my_covariates <- t(my_covariates)

my_geneloc <- fData(lp_expt)[, c("gid", "chromosome", "start", "end")]
colnames(my_geneloc) <- c("geneid", "chr", "left", "right")

my_ge <- exprs(normalize_expt(lp_expt, transform = "log2", filter = TRUE, convert = "cpm"))
used_samples <- tolower(colnames(my_ge)) %in% colnames(exprs(new_snps))
my_ge <- my_ge[, used_samples]

my_snpsloc <- data.frame(rownames = rownames(exprs(new_snps)))
## Oh, caveat here: Because of the way I stored the data,
## I could have duplicate rows which presumably will make matrixEQTL sad
my_snpsloc[["chr"]] <- gsub(pattern = "^chr_(.+)_pos(.+)_ref_.*$", replacement = "\\1",
                            x = rownames(my_snpsloc))
my_snpsloc[["pos"]] <- gsub(pattern = "^chr_(.+)_pos(.+)_ref_.*$", replacement = "\\2",
                            x = rownames(my_snpsloc))
test <- duplicated(my_snpsloc)
## Each duplicated row would be another variant at that position;
## so in theory we would do a rle to number them I am guessing
## However, I do not have different variants so I think I can ignore this for the moment
## but will need to make my matrix either 0 or 1.
if (sum(test) > 0) {
  message("There are: ", sum(duplicated), " duplicated entries.")
  keep_idx <- ! test
  my_snpsloc <- my_snpsloc[keep_idx, ]
}

my_snps <- exprs(new_snps)
one_idx <- my_snps > 0
my_snps[one_idx] <- 1

## Ok, at this point I think I have all the pieces which this method wants...
## Oh, no I guess not; it actually wants the data as a set of filenames...
library(MatrixEQTL)
write.table(my_snps, "eqtl/snps.tsv", na = "NA", col.names = TRUE, row.names = TRUE, sep = "\t", quote = TRUE)
## readr::write_tsv(my_snps, "eqtl/snps.tsv", )
write.table(my_snpsloc, "eqtl/snpsloc.tsv", na = "NA", col.names = TRUE, row.names = TRUE, sep = "\t", quote = TRUE)
## readr::write_tsv(my_snpsloc, "eqtl/snpsloc.tsv")
write.table(as.data.frame(my_ge), "eqtl/ge.tsv", na = "NA", col.names = TRUE, row.names = TRUE, sep = "\t", quote = TRUE)
## readr::write_tsv(as.data.frame(my_ge), "eqtl/ge.tsv")
write.table(as.data.frame(my_geneloc), "eqtl/geneloc.tsv", na = "NA", col.names = TRUE, row.names = TRUE, sep = "\t", quote = TRUE)
## readr::write_tsv(as.data.frame(my_geneloc), "eqtl/geneloc.tsv")
write.table(as.data.frame(my_covariates), "eqtl/covariates.tsv", na = "NA", col.names = TRUE, row.names = TRUE, sep = "\t", quote = TRUE)
## readr::write_tsv(as.data.frame(my_covariates), "eqtl/covariates.tsv")

useModel = modelLINEAR # modelANOVA, modelLINEAR, or modelLINEAR_CROSS

# Genotype file name
SNP_file_name = "eqtl/snps.tsv"
snps_location_file_name = "eqtl/snpsloc.tsv"
expression_file_name = "eqtl/ge.tsv"
gene_location_file_name = "eqtl/geneloc.tsv"
covariates_file_name = "eqtl/covariates.tsv"
# Output file name
output_file_name_cis = tempfile()
output_file_name_tra = tempfile()
# Only associations significant at this level will be saved
pvOutputThreshold_cis = 0.1
pvOutputThreshold_tra = 0.1
# Error covariance matrix
# Set to numeric() for identity.
errorCovariance = numeric()
# errorCovariance = read.table("Sample_Data/errorCovariance.txt");
# Distance for local gene-SNP pairs
cisDist = 1e6
## Load genotype data
snps = SlicedData$new()
snps$fileDelimiter = "\t"      # the TAB character
snps$fileOmitCharacters = "NA" # denote missing values;
snps$fileSkipRows = 1          # one row of column labels
snps$fileSkipColumns = 1       # one column of row labels
snps$fileSliceSize = 2000      # read file in slices of 2,000 rows
snps$LoadFile(SNP_file_name)
## Load gene expression data
gene = SlicedData$new()
gene$fileDelimiter = "\t"      # the TAB character
gene$fileOmitCharacters = "NA" # denote missing values;
gene$fileSkipRows = 1          # one row of column labels
gene$fileSkipColumns = 1       # one column of row labels
gene$fileSliceSize = 2000      # read file in slices of 2,000 rows
gene$LoadFile(expression_file_name)
## Load covariates
cvrt = SlicedData$new()
cvrt$fileDelimiter = "\t"      # the TAB character
cvrt$fileOmitCharacters = "NA" # denote missing values;
cvrt$fileSkipRows = 1          # one row of column labels
cvrt$fileSkipColumns = 1       # one column of row labels
if(length(covariates_file_name) > 0) {
  cvrt$LoadFile(covariates_file_name)
}
## Run the analysis
snpspos = read.table(snps_location_file_name, header = TRUE, stringsAsFactors = FALSE)
genepos = read.table(gene_location_file_name, header = TRUE, stringsAsFactors = FALSE)

me = Matrix_eQTL_main(
  snps = snps,
  gene = gene,
  cvrt = cvrt,
  output_file_name = output_file_name_tra,
  pvOutputThreshold = pvOutputThreshold_tra,
  useModel = useModel,
  errorCovariance = errorCovariance,
  verbose = TRUE,
  output_file_name.cis = output_file_name_cis,
  pvOutputThreshold.cis = pvOutputThreshold_cis,
  snpspos = snpspos,
  genepos = genepos,
  cisDist = cisDist,
  pvalue.hist = "qqplot",
  min.pv.by.genesnp = FALSE,
  noFDRsaveMemory = FALSE);
pander::pander(sessionInfo())
## Warning: Your system is mis-configured: '/etc/localtime' is not a symlink
## Warning: It is strongly recommended to set envionment variable TZ to
## 'America/New_York' (or equivalent)

R version 4.5.0 (2025-04-11)

Platform: x86_64-pc-linux-gnu

locale: C

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

other attached packages: ggbio(v.1.56.1), GenomicRanges(v.1.60.0), GenomeInfoDb(v.1.44.2), IRanges(v.2.42.0), S4Vectors(v.0.46.0), BiocGenerics(v.0.54.0), generics(v.0.1.4), glue(v.1.8.0), CMplot(v.4.5.1), dplyr(v.1.1.4), ggplot2(v.4.0.0), hpgltools(v.1.2) and Heatplus(v.3.16.0)

loaded via a namespace (and not attached): splines(v.4.5.0), later(v.1.4.3), BiocIO(v.1.18.0), bitops(v.1.0-9), filelock(v.1.0.3), tibble(v.3.3.0), R.oo(v.1.27.1), graph(v.1.86.0), XML(v.3.99-0.19), rpart(v.4.1.24), lifecycle(v.1.0.4), httr2(v.1.2.1), lattice(v.0.22-7), ensembldb(v.2.32.0), OrganismDbi(v.1.50.0), backports(v.1.5.0), magrittr(v.2.0.4), openxlsx(v.4.2.8), Hmisc(v.5.2-4), plotly(v.4.11.0), sass(v.0.4.10), rmarkdown(v.2.29), jquerylib(v.0.1.4), yaml(v.2.3.10), httpuv(v.1.6.16), zip(v.2.3.3), cowplot(v.1.2.0), DBI(v.1.2.3), RColorBrewer(v.1.1-3), abind(v.1.4-8), purrr(v.1.1.0), R.utils(v.2.13.0), AnnotationFilter(v.1.32.0), biovizBase(v.1.56.0), RCurl(v.1.98-1.17), yulab.utils(v.0.2.1), nnet(v.7.3-20), VariantAnnotation(v.1.54.1), rappdirs(v.0.3.3), GenomeInfoDbData(v.1.2.14), annotate(v.1.86.1), codetools(v.0.2-20), DelayedArray(v.0.34.1), DOSE(v.4.2.0), xml2(v.1.4.0), tidyselect(v.1.2.1), UCSC.utils(v.1.4.0), farver(v.2.1.2), matrixStats(v.1.5.0), BiocFileCache(v.2.16.1), base64enc(v.0.1-3), GenomicAlignments(v.1.44.0), jsonlite(v.2.0.0), Formula(v.1.2-5), iterators(v.1.0.14), foreach(v.1.5.2), tools(v.4.5.0), progress(v.1.2.3), Rcpp(v.1.1.0), gridExtra(v.2.3), SparseArray(v.1.8.1), xfun(v.0.53), qvalue(v.2.40.0), MatrixGenerics(v.1.20.0), withr(v.3.0.2), BiocManager(v.1.30.26), fastmap(v.1.2.0), GGally(v.2.4.0), digest(v.0.6.37), R6(v.2.6.1), mime(v.0.13), colorspace(v.2.1-2), GO.db(v.3.21.0), dichromat(v.2.0-0.1), biomaRt(v.2.64.0), RSQLite(v.2.4.3), R.methodsS3(v.1.8.2), tidyr(v.1.3.1), data.table(v.1.17.8), rtracklayer(v.1.68.0), prettyunits(v.1.2.0), httr(v.1.4.7), htmlwidgets(v.1.6.4), S4Arrays(v.1.8.1), ggstats(v.0.11.0), pkgconfig(v.2.0.3), gtable(v.0.3.6), blob(v.1.2.4), S7(v.0.2.0), XVector(v.0.48.0), htmltools(v.0.5.8.1), fgsea(v.1.34.2), RBGL(v.1.84.0), GSEABase(v.1.70.0), ProtGenerics(v.1.40.0), scales(v.1.4.0), Biobase(v.2.68.0), png(v.0.1-8), knitr(v.1.50), rstudioapi(v.0.17.1), reshape2(v.1.4.4), rjson(v.0.2.23), checkmate(v.2.3.3), curl(v.7.0.0), cachem(v.1.1.0), stringr(v.1.5.1), parallel(v.4.5.0), foreign(v.0.8-90), AnnotationDbi(v.1.70.0), restfulr(v.0.0.16), pillar(v.1.11.0), grid(v.4.5.0), vctrs(v.0.6.5), promises(v.1.3.3), dbplyr(v.2.5.0), xtable(v.1.8-4), cluster(v.2.1.8.1), htmlTable(v.2.4.3), evaluate(v.1.0.4), GenomicFeatures(v.1.60.0), cli(v.3.6.5), compiler(v.4.5.0), Rsamtools(v.2.24.0), rlang(v.1.1.6), crayon(v.1.5.3), plyr(v.1.8.9), fs(v.1.6.6), pander(v.0.6.6), stringi(v.1.8.7), viridisLite(v.0.4.2), BiocParallel(v.1.42.1), txdbmaker(v.1.4.2), Biostrings(v.2.76.0), lazyeval(v.0.2.2), GOSemSim(v.2.34.0), Matrix(v.1.7-3), BSgenome(v.1.76.0), hms(v.1.1.3), bit64(v.4.6.0-1), KEGGREST(v.1.48.1), shiny(v.1.11.1), SummarizedExperiment(v.1.38.1), broom(v.1.0.10), memoise(v.2.0.1), bslib(v.0.9.0), fastmatch(v.1.1-6) and bit(v.4.6.0)

message(paste0("This is hpgltools commit: ", get_git_commit()))
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 5043179aa73cd71040a7ba82276b0cf26cc661bd
## This is hpgltools commit: Mon Oct 6 12:01:25 2025 -0400: 5043179aa73cd71040a7ba82276b0cf26cc661bd
##message(paste0("Saving to ", savefile))
## tmp <- sm(saveme(filename = savefile))
tmp <- loame(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzIgYHIgU3lzLmdldGVudignVkVSU0lPTicpYDogVmlzdWFsaXppbmcgQW5hbHlzZXMgYmVmb3JlIERFL3ZhcmlhbnQgYW5hbHlzZXMiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCmJpYmxpb2dyYXBoeTogYXRiLmJpYgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDkKICAgIGZpZ193aWR0aDogOQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHkgLm1haW4tY29udGFpbmVyIHsKICBtYXgtd2lkdGg6IDE2MDBweDsKfQpib2R5LCB0ZCB7CiAgZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDE2cHg7Cn0KcHJlIHsKICBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShIZWF0cGx1cykKbGlicmFyeShocGdsdG9vbHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShDTXBsb3QpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShHZW5vbWljUmFuZ2VzKQpsaWJyYXJ5KGdnYmlvKQpsaWJyYXJ5KGdncGxvdDIpCgprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcyA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFLCB3aWR0aCA9IDkwLCBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVycm9yID0gVFJVRSwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDksIGZpZy5yZXRpbmEgPSAyLAogIG91dC53aWR0aCA9ICIxMDAlIiwgZGV2ID0gInBuZyIsCiAgZGV2LmFyZ3MgPSBsaXN0KHBuZyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzID0gNCwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gU3lzLmdldGVudigiVkVSU0lPTiIpCnByZXZpb3VzX2ZpbGUgPC0gIiIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gIiVZJW0lZCIpCgojIyB0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZSA9IGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHByZXZpb3VzX2ZpbGUpKSkpCnJtZF9maWxlIDwtICIwMnByZV92aXN1YWxpemF0aW9uLlJtZCIKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCmxvYWRlZCA8LSBsb2FkKGZpbGUgPSBnbHVlKCJyZGEvdG1yYzJfZGF0YV9zdHJ1Y3R1cmVzLXZ7dmVyfS5yZGEiKSkKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBkb2N1bWVudCB3aWxsIHZpc3VhbGl6ZSB0aGUgVE1SQzIgc2FtcGxlcyBiZWZvcmUgY29tcGxldGluZyB0aGUgdmFyaW91cyBkaWZmZXJlbnRpYWwKZXhwcmVzc2lvbiBhbmQgdmFyaWFudCBhbmFseXNlcyBpbiB0aGUgaG9wZXMgb2YgZ2V0dGluZyBhbiB1bmRlcnN0YW5kaW5nIG9mIGhvdyB0aGUgdmFyaW91cwpzYW1wbGVzIHJlbGF0ZSB0byBlYWNoIG90aGVyLgoKIyMgSW5pdGlhbCBsaWJyYXJ5IHNpemUKClN0YXJ0IG9mZiB3aXRoIHRoZSBsaWJyYXJ5IHNpemVzIG9mIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiAgVGhlIG1haW4KdGhpbmcgdG8gbm90ZSBpcyB0aGF0IHdlIGhhdmUgcXVpdGUgYSBsYXJnZSB2YXJpYW5jZSBpbiBjb3ZlcmFnZS4gIEEKZmV3IG9mIHRoZXNlIHNhbXBsZXMgYXJlIGhpZ2hseSBsaWtlbHkgdG8gYmUgcmVtb3ZlZCBzaG9ydGx5IChsb29raW5nCmF0IHlvdSwgVE1SQzIwMDAxIGFuZCBUTVJDMjAwOTUpCgpgYGB7cn0KbGlic2l6ZXMgPC0gcGxvdF9saWJzaXplKGxwX2V4cHQpCmxpYnNpemVzCmRldiA8LSBwcCgiaW1hZ2VzL2xwX2V4cHRfbGlic2l6ZXMucG5nIiwgd2lkdGggPSAxOCwgaGVpZ2h0ID0gOSkKbGlic2l6ZXMkcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCmBgYAoKTGlicmFyeSBzaXplcyBvZiB0aGUgcHJvdGVpbiBjb2RpbmcgZ2VuZSBjb3VudHMgb2JzZXJ2ZWQgcGVyIHNhbXBsZS4KVGhlIHNhbXBsZXMgd2VyZSBtYXBwZWQgd2l0aCB0aGUgRXVQYXRoREIgcmV2aXNpb24gMzYgb2YgdGhlCkxlaXNobWFuaWEgKFZpYW5uaWEpIHBhbmFtZW5zaXMgc3RyYWluIE1IT00vQ09MLzgxTDEzIGdlbm9tZTsgdGhlCmFsaWdubWVudHMgd2VyZSBzb3J0ZWQsIGluZGV4ZWQsIGFuZCBjb3VudGVkIHZpYSBodHNlcSB1c2luZyB0aGUgZ2VuZQpmZWF0dXJlcywgYW5kIG5vbi1wcm90ZWluIGNvZGluZyBmZWF0dXJlcyB3ZXJlIGV4Y2x1ZGVkLgpUaGUgcGVyLXNhbXBsZSBzdW1zIG9mIHRoZSByZW1haW5pbmcgbWF0cml4IHdlcmUgcGxvdHRlZCB0byBjaGVjayB0aGF0CnRoZSByZWxhdGl2ZSBzYW1wbGUgY292ZXJhZ2UgaXMgc3VmZmljaWVudCBhbmQgbm90IHRvbyBkaXZlcmdlbnQKYWNyb3NzIHNhbXBsZXMuICBCYXJzIGFyZSBjb2xvcmVkIGFjY29yZGluZyB0byBzdHJhaW4venltb2RlbWUKYW5ub3RhdGlvbjogcmVkOiB6eW1vZGVtZSAyLjM7IGJsdWU6IHp5bW9kZW1lIDIuMjsgTGVpc2htYW5pYQpicmF6aWxpZW5zaXMtbGlrZSBzdHJhaW5zIGIyOTA0LCB6MS4wLCBhbmQgejEuNTogcHVycGxlOyB6eW1vZGVtZXMKd2hpY2ggYXJlIG1vc3Qgc2ltaWxhciB0byAyLjMsIGNvbXByaXNpbmcgejIuNCBpcyBsaWdodCBicm93bjsKenltb2RlbWVzIG1vc3Qgc2ltaWxhciB0byAyLjIsIGNvbXByaXNpbmcgejMuMCwgejIuMCwgejIuMSwgYW5kIHozLjIKYXJlIGxpZ2h0IGdyYXksIGRhcmsgZ3JheSwgZGFyayBicm93biwgYW5kIGdyYXkgcmVzcGVjdGl2ZWx5LgoKIyMgTm9uLXplcm8gZ2VuZXMgd2l0aCByZXNwZWN0IHRvIGNvdmVyYWdlCgpUaGlzIHBsb3QgaXMgdXN1YWxseSBvdXIgcHJpbWFyeSBhcmJpdGVyIGZvciBzYW1wbGUgcmVtb3ZpbmcgYmFzZWQgb24KY292ZXJhZ2UuICBXZSBwaWNrIGEgc2VtaS1hcmJpdHJhcnkgY3V0b2ZmIGJhc2VkIG9uIGJvdGggY292ZXJhZ2UgYW5kCmdlbmVzIG9ic2VydmVkLiAgSW4gdGhpcyBpbnN0YW5jZSA4LDYwMCBnZW5lcyBzZWVtcyBsaWtlbHk/CgpUaGUgY3V0b2ZmIGFyZ3VtZW50IHByaW50cyBvdXQgc2FtcGxlcyB3aXRoIGdlbmUgY292ZXJhZ2UgPCB0aGF0CnByb3BvcnRpb24uICBJIHRoaW5rIHdlIGFscmVhZHkgZHJvcHBlZCBpbiB0aGUgc2FtcGxlIHNoZWV0IHRoZSBtb3N0CnByb2JsZW1hdGljIHNhbXBsZXMsIHNvIGl0IG1heSBub3QgYWN0dWFsbHkgcHJpbnQgYW55dGhpbmcuCgpgYGB7cn0KIyMgSSB0aGluayBzYW1wbGVzIDcsMTAgc2hvdWxkIGJlIHJlbW92ZWQgYXQgbWluaW11bSwgcHJvYmFibHkgYWxzbyA5LDExCm5vbnplcm8gPC0gcGxvdF9ub256ZXJvKGxwX2V4cHQsIGN1dG9mZiA9IDAuNykKbm9uemVybwpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvbHBfbm9uemVyby5wbmciLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCm5vbnplcm8kcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCmBgYAoKRGlmZmVyZW5jZXMgaW4gcmVsYXRpdmUgZ2VuZSBjb250ZW50IHdpdGggcmVzcGVjdCB0byBzZXF1ZW5jaW5nCmNvdmVyYWdlLiAgVGhlIHBlci1zYW1wbGUgbnVtYmVyIG9mIG9ic2VydmVkIGdlbmVzIHdhcyBwbG90dGVkIHdpdGgKcmVzcGVjdCB0byB0aGUgcmVsYXRpdmUgQ1BNIGNvdmVyYWdlIGluIG9yZGVyIHRvIGNoZWNrIHRoYXQgdGhlCnNhbXBsZXMgYXJlIHN1ZmZpY2llbnRseSBhbmQgc2ltaWxhcmx5IGRpdmVyc2UuICBNYW55IHNhbXBsZXMgd2VyZQpvYnNlcnZlZCBuZWFyIG9yIGF0IHRoZSBwdXRhdGl2ZSBhc3ltcHRvdGUgb2YgbGlrZWx5IGdlbmUgY29udGVudDsgbm8Kc2FtcGxlcyB3ZXJlIG9ic2VydmVkIHdpdGggZmV3ZXIgdGhhbiA2NSUgb2YgdGhlIExlaXNobWFuaWEgcGFuYW1lbnNpcwpnZW5lcyBpbmNsdWRlZC4gIE5vdGUgdGhhdCB0aGUgcmFuZ2Ugb2YgZ2VuZXMgb2JzZXJ2ZWQgaXMgcXVpdGUgc21hbGwsCjg1MDAgPD0geCA8IDg3MDAgZ2VuZXMsIGhvd2V2ZXIgdGhpcyB3YXMgcGxvdHRlZCBhZnRlciBhbHJlYWR5CmV4Y2x1ZGluZyBzYW1wbGVzIHdpdGggZmV3ZXIgdGhhbiA4NTAwIGdlbmVzIG9ic2VydmVkIChvZiB3aGljaCB0aGVyZQp3ZXJlIDIpIGFuZCBhbnkgc2FtcGxlcyB3aXRoIGZld2VyIHRoYW4gNSBtaWxsaW9uIHByb3RlaW4gY29kaW5nCm1hcHBlZCByZWFkcyAodGhlcmUgd2VyZSAyIHNhbXBsZXMgdGhhdCBoYWQgbW9yZSB0aGFuIDg1MDAgZ2VuZXMKb2JzZXJ2ZWQgaW4gbGVzcyB0aGFuIDUgbWlsbGlvbiByZWFkcykuCgpgYGB7cn0KbHBfYm94IDwtIHBsb3RfYm94cGxvdChscF9leHB0KQpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvbHBfZXhwdF9ib3hwbG90LnBuZyIsIHdpZHRoID0gMTYsIGhlaWdodCA9IDkpCmxwX2JveApjbG9zZWQgPC0gZGV2Lm9mZigpCmxwX2JveApgYGAKClRoZSBkaXN0cmlidXRpb24gb2Ygb2JzZXJ2ZWQgY291bnRzIC8gZ2VuZSBmb3IgYWxsIHNhbXBsZXMgd2FzIHBsb3R0ZWQKYXMgYSBib3hwbG90IG9uIHRoZSBsb2cyIChpdCBsb29rcyBsaWtlIGl0IGlzIGxvZzEwLCBidXQgSSBjaGVja2VkKQpzY2FsZS4gIEluIGNvbnRyYXN0IHRvIGhvc3QgdHJhbnNjcmlwdG9tZSBkaXN0cmlidXRpb24sIHRoZSBwYXJhc2l0ZQpkaXN0cmlidXRpb24gb2YgcmVhZHMvZ2VuZSBpcyBsb2ctbm9ybWFsLgoKYGBge3J9CmZpbHRlcl9wbG90IDwtIHBsb3RfbGlic2l6ZV9wcmVwb3N0KGxwX2V4cHQpCmZpbHRlcl9wbG90JGxvd2dlbmVfcGxvdApmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmBgYAoKVGhlIG51bWJlcnMgb2YgZ2VuZXMgcmVtb3ZlZCBieSBsb3ctY291bnQgZmlsdGVyaW5nIGlzIGRyYXN0aWNhbGx5Cmxvd2VyIGluIHBhcmFzaXRlIHNhbXBsZXMgdGhhbiBodW1hbi4gIFRodXMsIGV2ZW4gdGhvdWdoIHRoZSByYW5nZSBvZgpjb3ZlcmFnZSBmb3IgdGhlIHBhcmFzaXRlIHNhbXBsZXMgaXMgZnJvbSBuZWFyIDAgdG8gfiAxNTAgQ1BNLCB0aGUKbnVtYmVyIG9mIGdlbmVzIHJlbW92ZWQgYnkgdGhlIGRlZmF1bHQgbG93LWNvdW50IGZpbHRlciByYW5nZXMgb25seQpmcm9tIDQwIHRvIDEyOSwgYW5kIHRoZSBudW1iZXIgb2YgcmVhZHMgYXNzb2NpYXRlZCB3aXRoIHRoZW0gcmFuZ2VzCm9ubHkgZnJvbSAxMDAgdG8gMzE2OC4KCmBgYHtyfQp0YWJsZShwRGF0YShscF9leHB0KVtbInp5bW9kZW1lY2F0ZWdvcmljYWwiXV0pCnRhYmxlKHBEYXRhKGxwX2V4cHQpW1siY2xpbmljYWxyZXNwb25zZSJdXSkKYGBgCgojIyBEaXN0cmlidXRpb24gVmlzdWFsaXphdGlvbnMKCk5hamliJ3MgZmF2b3JpdGUgcGxvdHMgYXJlIG9mIGNvdXJzZSB0aGUgUENBL1ROU0UuICBUaGVzZSBhcmUgbmljZSB0byBsb29rIGF0IGluCm9yZGVyIHRvIGdldCBhIHNlbnNlIG9mIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gc2FtcGxlcy4gIFRoZXkgYWxzbyBwcm92aWRlIGEKZ29vZCBvcHBvcnR1bml0eSB0byBzZWUgd2hhdCBoYXBwZW5zIHdoZW4gb25lIGFwcGxpZXMgZGlmZmVyZW50IG5vcm1hbGl6YXRpb25zLApzdXJyb2dhdGUgYW5hbHlzZXMsIGZpbHRlcnMsIGV0Yy4gIEluIGFkZGl0aW9uLCBvbmUgbWF5IHNldCBkaWZmZXJlbnQKZXhwZXJpbWVudGFsIGZhY3RvcnMgYXMgdGhlIHByaW1hcnkgJ2NvbmRpdGlvbicgKHVzdWFsbHkgdGhlIGNvbG9yIG9mIHBsb3RzKSBhbmQKc3Vycm9nYXRlICdiYXRjaGVzJy4KCiMjIEJ5IFN1c2NlcHRpbGliaXR5CgpDb2x1bW4gJ1EnIGluIHRoZSBzYW1wbGUgc2hlZXQsIG1ha2UgYSBjYXRlZ29yaWNhbCB2ZXJzaW9uIG9mIGl0IHdpdGggdGhlc2UgcGFyYW1ldGVyczoKCiogMCA8PSB4IDw9IDM1IGlzIHJlc2lzdGFudAoqIDM2IDw9IHggPD0gNDggaXMgYW1iaWd1b3VzCiogNDkgPD0geCBpcyBzZW5zaXRpdmUKCmBgYHtyfQpzdHJhaW5fbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9zdHJhaW4sIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkKenltb19wY2EgPC0gcGxvdF9wY2Eoc3RyYWluX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKenltb19wY2EKZGV2IDwtIHBwKGZpbGUgPSAiZmlndXJlcy9wcm9tYXN0aWdvdGVfenltb2NvbF9zZW5zc2hhcGVfejIxX3RvX3oyNC5wZGYiKQp6eW1vX3BjYSRwbG90CmNsb3NlZCA8LSBkZXYub2ZmKCkKCmxwX3N0cmFpbl9rbm93biA8LSBzdWJzZXRfZXhwdChscF9zdHJhaW4sIHN1YnNldCA9ICJjbGluaWNhbGNhdGVnb3JpY2FsIT0ndW5rbm93biciKQpzdHJhaW5fa25vd25fbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9zdHJhaW5fa25vd24sIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkKenltb19rbm93bl9wY2EgPC0gcGxvdF9wY2Eoc3RyYWluX2tub3duX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKenltb19rbm93bl9wY2EKZGV2IDwtIHBwKGZpbGUgPSAiZmlndXJlcy9wcm9tYXN0aWdvdGVfenltb2NvbF9zZW5zc2hhcGVfejIxX3RvX3oyNF9vbmx5X2tub3duX2NsaW5pY2FsLnBkZiIpCnp5bW9fa25vd25fcGNhJHBsb3QKY2xvc2VkIDwtIGRldi5vZmYoKQpgYGAKCiMjIExpbWl0IHRvIHRocmVlIHN0cmFpbnM6IDIuMS8yLjIvMi4zCgpgYGB7cn0Kb25seV90aHJlZV90eXBlcyA8LSBzdWJzZXRfZXhwdChscF9zdHJhaW4sIHN1YnNldCA9ICJjb25kaXRpb249PSd6Mi4xJ3xjb25kaXRpb249PSd6Mi4zJ3xjb25kaXRpb249PSd6Mi4yJyIpCm9ubHlfdGhyZWVfbm9ybSA8LSBub3JtYWxpemVfZXhwdChvbmx5X3RocmVlX3R5cGVzLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAicGhhc2UiKQpvbmx5dGhyZWVfcGNhIDwtIHBsb3RfcGNhKG9ubHlfdGhyZWVfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgejIuMSwgejIuMiBhbmQgejIuMyBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvcHJvbWFzdGlnb3RlX3RocmVldHlwZXNfenltb2NvbF9ub3NoYXBlLnBuZyIpCm9ubHl0aHJlZV9wY2EkcGxvdApkZXYub2ZmKCkKb25seXRocmVlX3BjYSRwbG90CmBgYAoKIyMgQnkgbXkgTUwga25uIGNsYXNzaWZpZXIhCgpJIGFkZGVkIHRoZSByZXN1bHQgZnJvbSBteSBrbWVyIGNsYXNzaWZpZXIgdG8gdGhlIHNhbXBsZSBzaGVldCwgbGV0IHVzCnNlZSBob3cgdGhhdCBsb29rcy4KCmBgYHtyfQpscF9zdHJhaW5fa25uIDwtIHNldF9leHB0X2NvbmRpdGlvbnMobHBfc3RyYWluLCBmYWN0ID0gImtubnYyY2xhc3NpZmljYXRpb24iKQpzdHJhaW5fbm9ybV9rbm4gPC0gbm9ybWFsaXplX2V4cHQobHBfc3RyYWluX2tubiwgbm9ybSA9ICJxdWFudCIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkKenltb19wY2Ffa25uIDwtIHBsb3RfcGNhKHN0cmFpbl9ub3JtX2tubiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcGxvdGx5OjpnZ3Bsb3RseSh6eW1vX3BjYV9rbm4kcGxvdCkKZGV2IDwtIHBwKGZpbGUgPSAiaW1hZ2VzL3Byb21hc3RpZ290ZV96eW1vY29sX3NlbnNzaGFwZV9rbm52Mi5wbmciKQp6eW1vX3BjYV9rbm4kcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCnp5bW9fcGNhX2tubiRwbG90CgpzdHJhaW5fbm9iYXRjaCA8LSBzZXRfZXhwdF9iYXRjaGVzKHN0cmFpbl9ub3JtLCBmYWN0ID0gInNvdXJjZWxhYiIpCnp5bW9fcGNhdjIgPC0gcGxvdF9wY2Eoc3RyYWluX25vYmF0Y2gsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvcHJvbWFzdGlnb3RlX3p5bW9jb2xfbm9iYXRjaC5wbmciKQp6eW1vX3BjYXYyJHBsb3QKY2xvc2VkIDwtIGRldi5vZmYoKQp6eW1vX3BjYXYyJHBsb3QKCnN0cmFpbl9uYiA8LSBub3JtYWxpemVfZXhwdChscF9zdHJhaW4sIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIikKc3RyYWluX25iX3BjYSA8LSBwbG90X3BjYShzdHJhaW5fbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvY2xpbmljYWxfbmJfcGNhX3N1c19zaGFwZS5wbmciKQpzdHJhaW5fbmJfcGNhJHBsb3QKY2xvc2VkIDwtIGRldi5vZmYoKQpzdHJhaW5fbmJfcGNhCmBgYAoKQWRkIGV4cGxpY2l0IGxhYmVscyBmb3IgYSBmZXcgcmVmZXJlbmNlIHN0cmFpbnM6CgoqIFRNUkMyMDAyMzogRXhjbHVkZWQgZHVlIHRvIGNvdmVyYWdlIChvbmx5IDdrIHJlYWRzKQoqIFRNUkMyMDAwNjogVGhpcyBvbmUgaGFzIDE5LDgxNSw2NzMgcmVhZHMsIGJ1dCBhIHdlaXJkbHkgc21hbGwgbnVtYmVyIG9mIGdlbmVzIGFuZCBnb3QgZXhjbHVkZWQuCiogVE1SQzIwMDI5OiBUaGlzIGhhcyAxLDk0Niw5ODYgcmVhZHMgYW5kIHNvIHdhcyBleGNsdWRlZC4KKiBUTVJDMjAwMzQ6IE5vdCBzZXF1ZW5jZWQKCioqIE5PVEUgKiogVGhlc2Ugc2FtcGxlcyB3ZXJlIGFsbCByZW1vdmVkIGZyb20gZXhhbWluYXRpb24gaW4gdGhlCl9zYW1wbGVfc2hlZXRfIGluIDIwMjQwNCBhbmQgc28gd2lsbCBub3QgYXBwZWFyIGluIHRoaXMgcGxvdC4gIFRodXMgSQphbSB0dXJuaW5nIG9mZiB0aGUgZm9sbG93aW5nIGJsb2NrLgoKYGBge3IsIGV2YWw9RkFMU0V9CnNhbXBsZXNfdG9fbGFiZWwgPC0gdG9sb3dlcihjKCJUTVJDMjAwMjMiLCAiVE1SQzIwMDA2IiwgIlRNUkMyMDAyOSIsICJUTVJDMjAwMDciLCAiVE1SQzIwMDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRNUkMyMDAwOCIsICJUTVJDMjAwMjciLCAiVE1SQzIwMDI4IiwgIlRNUkMyMDAzMiIsICJUTVJDMjAwNDAiKSkKCmxhYmVsX2VudHJpZXMgPC0genltb19wY2EkdGFibGVbc2FtcGxlc190b19sYWJlbCwgXQp6eW1vX3BjYSRwbG90ICsKICBnZW9tX3RleHQobWFwcGluZyA9IGFlc19zdHJpbmcoIngiID0gIlBDMSIsICJ5IiA9ICJQQzIiLCBsYWJlbCA9ICJzYW1wbGVpZCIpLAogICAgICAgICAgICBkYXRhID0gbGFiZWxfZW50cmllcykKYGBgCgpTb21lIGxpa2VseSB0ZXh0IGZvciBhIGZpZ3VyZSBsZWdlbmQgbWlnaHQgaW5jbHVkZSBzb21ldGhpbmcgbGlrZSB0aGUKZm9sbG93aW5nIChwYXJhcGhyYXNlZCBmcm9tIE5hamliJ3MgMjAxNiBkdWFsIHRyYW5zY3JpcHRvbWUgcHJvZmlsaW5nCnBhcGVyICgxMC4xMTI4L21CaW8uMDAwMjctMTYpKToKCkV4cHJlc3Npb24gcHJvZmlsZXMgb2YgdGhlIHByb21hc3RpZ290ZSBzYW1wbGVzIGFjcm9zcyBtdWx0aXBsZQpzdHJhaW5zLiBFYWNoIGdseXBoIHJlcHJlc2VudHMgb25lIHNhbXBsZSwgY29sb3JzIGRlbGluZWF0ZSB0aGUKdmFyaW91cyBzdHJhaW5zIGFuZCBmYWxsIGludG8gdHdvIHByaW1hcnkgY2xhZGVzLiAgUmVkIHNhbXBsZXMgYXJlCnp5bW9kZW1lIDIuMywgYmx1ZSBzYW1wbGVzIGFyZSB6eW1vZGVtZSAyLjIuICBUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuCnRoZXNlIHR3byBwcmltYXJ5IGdyb3VwcyBtYWtlIHVwIGFwcHJveGltYXRlbHkgMTclIG9mIHRoZSB2YXJpYW5jZSBpbgp0aGUgUENBLiAgUHVycGxlIHNhbXBsZXMgYXJlIExlaXNobWFuaWEgYnJhemlsaWVuc2lzIG9yIHp5bW9kZW1lCjEuMC8xLjUgc2FtcGxlcywgb3JhbmdlIGFyZSB6Mi40LCBicm93bnMgYW5kIGdyZXlzIGFyZSB6Mi4xLCB6Mi4wLAp6My4wLCBhbmQgejMuMiByZXNwZWN0aXZlbHkuICBUaGlzIGFuYWx5c2lzIHdhcyBwZXJmb3JtZWQgZm9sbG93aW5nIGEKbG93LWNvdW50IGZpbHRlciwgY3BtIGNvbnZlcnNpb24sIHF1YW50aWxlIG5vcm1hbGl6YXRpb24sIGFuZCBhIGxvZzIKdHJhbnNmb3JtYXRpb24uICBObyBiYXRjaCBmYWN0b3Igd2FzIHVzZWQsIG5vciB3YXMgYSBzdXJyb2dhdGUKdmFyaWFibGUgZXN0aW1hdGlvbiBwZXJmb3JtZWQuCgpTb21lIGludGVycHJldGF0aW9uIGZvciB0aGlzIGZpZ3VyZSBtaWdodCBpbmNsdWRlOgoKV2hlbiBQQ0Egd2FzIHBlcmZvcm1lZCBvbiB0aGUgcHJvbWFzdGlnb3RlIHNhbXBsZXMsIHRoZSBkb21pbmFudCAoYnV0CnN0aWxsIHJlbGF0aXZlbHkgc21hbGwgYW1vdW50IG9mIHZhcmlhbmNlKSBjb21wb25lbnQgb2JzZXJ2ZWQKY29pbmNpZGVkIHdpdGggdGhlIHR3byBwcmltYXJ5IHN0cmFpbiBncm91cHMsIHp5bW9kZW1lIDIuMiBhbmQgMi4zLgpXaXRoIHRoZSBleGNlcHRpb24gb2Ygc29tZSBMZWlzaG1hbmlhIGJyYXppbGllbnNpcyBzYW1wbGVzLCBhbGwKcHJvbWF0aWdvdGUgc2FtcGxlcyBhc3NheWVkIGZlbGwgaW50byBvbmUgb2YgdGhlc2UgdHdvIGNhdGVnb3JpZXMuCgpXaGVuIHN1cnJvZ2F0ZSB2YXJpYWxiZSBlc3RpbWF0aW9uIHdhcyBwZXJmb3JtZWQgb24gdGhlIGVudGlyZSBzZXQgb2YKc2FtcGxlcywgaXQgaW5jcmVhc2VkIHRoZSBhcHBhcmVudCBzdHJhaW4tZGVwZW5kZW50IHZhcmlhbmNlLCBidXQgaGFkCnNvbWUgcG90ZW50aWFsbHkgcHJvYmxlbWF0aWMgZWZmZWN0cyBmb3IgYSBjb3VwbGUgb2Ygc2FtcGxlcyAob25lIHoyLjMKc2FtcGxlIG5vdyBsaWVzIHdpdGggdGhlIG90aGVyIHoyLjIgc2FtcGxlcyk7IGl0IGlzIGFzc3VtZWQgdGhhdCB0aGlzCmlzIGJlY2F1c2Ugc3ZhIGF0dGVtcHRlZCB0byBlc3RpbWF0ZSBzdXJyb2dhdGUgdmFsdWVzIGZvciB0aGUKbGVzcy1yZXByZXNlbnRlZCBzdHJhaW5zIHdpdGggc29tZSB1bmludGVuZGVkIGNvbnNlcXVlbmNlcyBmb3Igc2FtcGxlClRNUkMyMDA5NSAod2hpY2gsIGFsb25nIHdpdGggVE1SQzIwMDA4IGFyZSB0aGUgdHdvIGxlYXN0IGNvdmVyZWQKc2FtcGxlcyBieSBhIHNpZ25pZmljYW50IG1hcmdpbik7IHRoaXMgaHlwb3RoZXNpcyBtYXkgYmUgdGVzdGVkIGJ5CmV4Y2x1ZGluZyB0aGUgYnJhemlsaWVuc2lzIGFuZCBub24tejIuMi8yLjMgc2FtcGxlcyBhbmQgcmVwZWF0aW5nCih3aGVuIHRoaXMgaXMgcGVyZm9ybWVkIGxhdGVyIGluIHRoZSBkb2N1bWVudCwgdGhlIGRpZmZlcmVuY2UgYmV0d2Vlbgp0aGUgdHdvIHByaW1hcnkgY2xhZGVzIGluY3JlYXNlcyB0byA0OS4zMyUgb2YgdGhlIHZhcmlhbmNlIGFuZCB0aGVyZQphcmUgbm8gb2RkIHNhbXBsZXMpLgoKYGBge3J9Cnp5bW9fdHNuZSA8LSBwbG90X3RzbmUoc3RyYWluX25vcm0sIHBsb3RfdGl0bGUgPSAiVFNORSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIpCnp5bW9fdHNuZSRwbG90CgpzdHJhaW5fbmJfdHNuZSA8LSBwbG90X3RzbmUoc3RyYWluX25iLCBwbG90X3RpdGxlID0gIlRTTkUgb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiKQpzdHJhaW5fbmJfdHNuZSRwbG90Cgpjb3JoZWF0IDwtIHBsb3RfY29yaGVhdChzdHJhaW5fbm9ybSwgcGxvdF90aXRsZSA9ICJDb3JyZWxhdGlvbiBoZWF0bWFwIG9mIHBhcmFzaXRlCiAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbiB2YWx1ZXMKIikKY29yaGVhdCRwbG90CgpkaXNoZWF0IDwtIHBsb3RfZGlzaGVhdChzdHJhaW5fbm9ybSwgcGxvdF90aXRsZSA9ICJEaXN0YW5jZSBoZWF0bWFwIG9mIHBhcmFzaXRlCiAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbiB2YWx1ZXMKIikKZGlzaGVhdCRwbG90CgpwbG90X3NtKHN0cmFpbl9ub3JtKSRwbG90CmBgYAoKUG90ZW50aWFsIHN0YXJ0IGZvciBhIGZpZ3VyZSBsZWdlbmQ6CgpHbG9iYWwgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgcHJvbWFzdGlnb3RlIHRyYW5zY3JpcHRpb25hbApwcm9maWxlcy4gIFBhaXJ3aXNlIHBlYXJzb24gY29ycmVsYXRpb25zIGFuZCBFdWNsaWRlYW4gZGlzdGFuY2VzIHdlcmUKY2FsY3VsYXRlZCB1c2luZyB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIG1hdHJpY2VzLiAgQ29sb3JzIGFsb25nIHRoZQp0b3Agcm93IGRlbGluZWF0ZSB0aGUgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMgKHNhbWUgY29sb3JzIGFzIHRoZSBQQ0EpClNhbXBsZXMgd2VyZSBjbHVzdGVyZWQgYnkgbmVhcmVzdCBuZWlnaGJvciBjbHVzdGVyaW5nIGFuZCBlYWNoIGNvbG9yZWQKdGlsZSBkZXNjcmliZXMgb25lIGNvcnJlbGF0aW9uIHZhbHVlIGJldHdlZW4gdHdvIHNhbXBsZXMgKHJlZCB0byB3aGl0ZQpkZWxpbmVhdGVzIHBlYXJzb24gY29ycmVsYXRpb24gdmFsdWVzIG9mIHRoZSA4LDcxMCBub3JtYWxpemVkIGdlbmUKdmFsdWVzIGJldHdlZW4gdHdvIHNhbXBsZXMgcmFuZ2luZyBmcm9tIDw9IDAuNyB0byA+PSAxLjApIG9yCnRoZSBldWNsaWRlYW4gZGlzdGFuY2UgYmV0d2VlbiB0d28gc2FtcGxlcyAoZGFyayBibHVlIHRvIHdoaXRlCmRlbGluZWF0ZXMgaWRlbnRpY2FsIHRvIGEgbm9ybWFsaXplZCBldWNsaWRlYW4gZGlzdGFuY2Ugb2YgPj0gMTEwKS4KClNvbWUgaW50ZXJwcmV0YXRpb24gZm9yIHRoaXMgZmlndXJlIG1pZ2h0IGluY2x1ZGU6CgpXaGVuIHRoZSBnbG9iYWwgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgc2FtcGxlcyB3ZXJlIGRpc3RpbGxlZCBkb3duIHRvCmluZGl2aWR1YWwgZXVjbGlkZWFuIGRpc3RhbmNlcyBvciBwZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cwpiZXR3ZWVuIHBhaXJzIG9mIHNhbXBsZXMsIHRoZSBwcmltYXJ5IGNsdXN0ZXJpbmcgYW1vbmcgc2FtcGxlcwpvYnNlcnZlZCB3YXMgYWNjb3JkaW5nIHRvIHN0cmFpbi4gIFRoZSBwcmltYXJ5IHNpZ25pZmljYW50IG91dGxpZXIKc2FtcGxlIChUTVJDMjAwOTUpIGlzIGV4cGxpY2l0bHkgZHVlIHRvIGxvdyBjb3ZlcmFnZS4gIFRoZSBvdGhlcgpvdXRsaWVyIHN0cmFpbnMgYXJlIGVpdGhlciBicmF6aWxpZW5zaXMgKHB1cnBsZSkgb3IgYSBzZXJpZXMgb2YKc3RyYWlucyB3aGljaCwgd2hlbiB2aWV3ZWQgaW4gSUdWLCBhcHBlYXIgdG8gaGF2ZSBnZW5ldGljIHZhcmlhbnRzCndoaWNoIGJyaWRnZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvIHByaW1hcnkgenltb2RlbWVzLApwYXJ0aWN1bGFybHkgb24gdGhlIGtub3duIGFuZXVwbG9pZCBjaHJvbW9zb21lcy4KCiMjIExpbWl0IHRvIGp1c3QgdHdvIHN0cmFpbnM6IDIuMi8yLjMKCmBgYHtyfQpscF90d29fc3RyYWluc19ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGxwX3p5bW8sIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKb25seXR3b19wY2EgPC0gcGxvdF9wY2EobHBfdHdvX3N0cmFpbnNfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgejIuMiBhbmQgejIuMyBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCmRldiA8LSBwcChmaWxlID0gImZpZ3VyZXMvenltb196Mi4yX3oyLjNfcGNhX3N1c19zaGFwZS5wZGYiKQpvbmx5dHdvX3BjYSRwbG90CmNsb3NlZCA8LSBkZXYub2ZmKCkKb25seXR3b19wY2EkcGxvdAoKbHBfdHdvX3N0cmFpbnNfa25vd24gPC0gc3Vic2V0X2V4cHQobHBfenltbywgc3Vic2V0ID0gImNsaW5pY2FsY2F0ZWdvcmljYWwhPSd1bmtub3duJyIpCmxwX3R3b19zdHJhaW5zX2tub3duX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobHBfdHdvX3N0cmFpbnNfa25vd24sIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKb25seXR3b19rbm93bl9wY2EgPC0gcGxvdF9wY2EobHBfdHdvX3N0cmFpbnNfa25vd25fbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgejIuMiBhbmQgejIuMyBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCmRldiA8LSBwcChmaWxlID0gImZpZ3VyZXMvenltb196Mi4yX3oyLjNfcGNhX3N1c19zaGFwZV9vbmx5X2tub3duLnBkZiIpCm9ubHl0d29fcGNhJHBsb3QKY2xvc2VkIDwtIGRldi5vZmYoKQpvbmx5dHdvX3BjYSRwbG90CgpscF90d29fc3RyYWluc19uYiA8LSBub3JtYWxpemVfZXhwdChscF96eW1vLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIGJhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCm9ubHl0d29fcGNhX25iIDwtIHBsb3RfcGNhKGxwX3R3b19zdHJhaW5zX25iLCBwbG90X3RpdGxlID0gIlBDQSBvZiB6Mi4yIGFuZCB6Mi4zIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKZGV2IDwtIHBwKGZpbGUgPSAiaW1hZ2VzL3p5bW9fejIuMl96Mi4zX3BjYV9zdXNfc2hhcGVfbmIucGRmIikKb25seXR3b19wY2FfbmIkcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCm9ubHl0d29fcGNhX25iJHBsb3QKYGBgCgojIyBCeSBDdXJlL0ZhaWwgc3RhdHVzCgpUaGlzIGlzIGJ5IGZhciB0aGUgbW9zdCBwcm9ibGVtYXRpYyBjb21wYXJpc29uLCBJIHRoaW5rIHRoZSBvbmx5CmludGVycHJldGF0aW9uIG9mIHRoZSBmb2xsb3dpbmcgaW1hZ2VzIGlzIHRoYXQgdGhlIHBhcmFzaXRlIGhhcyBsaXR0bGUKZWZmZWN0IG9uIHRoZSBsaWtlbGlob29kIHRoYXQgYSBwZXJzb24gd2lsbCBzdWNjZXNzZnVsbHkgZW5kCnRyZWF0bWVudC4gIFRoZXJlIGRvZXMgYXBwZWFyIHRvIGJlIHNvbWUgdmFyaWFuY2UgYXNzb2NpYXRlZCB3aXRoCmN1cmUvZmFpbCwgYnV0IG9ubHkgaW4gYSBmZXcgc2FtcGxlcyAodmlzaWJsZSBpbiB+MTAgZmFpbCBzYW1wbGVzIGFuZApwZXJoYXBzIH44IGN1cmUgc2FtcGxlcyB3aGVuIHN2YSBpcyBhcHBsaWVkIHRvIHRoZSBkYXRhKS4KCmBgYHtyfQpjZl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGxwX2NmLCBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSkKc3RhcnRfY2YgPC0gcGxvdF9wY2EoY2Zfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJmaWd1cmVzL2N1cmVfZmFpbF9zdXNfc2hhcGVfYWxsLnBkZiIpCnN0YXJ0X2NmJHBsb3QKY2xvc2VkIDwtIGRldi5vZmYoKQpzdGFydF9jZgoKbHBfY2Zfa25vd24gPC0gc3Vic2V0X2V4cHQobHBfY2YsIHN1YnNldCA9ICJjbGluaWNhbGNhdGVnb3JpY2FsIT0ndW5rbm93biciKQpjZl9rbm93bl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGxwX2NmX2tub3duLCBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSkKc3RhcnRfY2Zfa25vd24gPC0gcGxvdF9wY2EoY2Zfa25vd25fbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJmaWd1cmVzL2N1cmVfZmFpbF9zdXNfc2hhcGVfa25vd24ucGRmIikKc3RhcnRfY2Zfa25vd24kcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCnN0YXJ0X2NmX2tub3duCgpvbmx5X3R3b19jZiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGxwX3p5bW8sIGZhY3QgPSAiY2xpbmljYWxjYXRlZ29yaWNhbCIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJzdXNfY2F0ZWdvcnlfY3VycmVudCIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcl9jaG9pY2VzW1siY2YiXV0pCgpvbmx5X3R3b19jZl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KG9ubHlfdHdvX2NmLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkKb25seV90d29fY2ZfcGNhIDwtIHBsb3RfcGNhKG9ubHlfdHdvX2NmX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHoyLjIgYW5kIHoyLjMgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKZGV2IDwtIHBwKGZpbGUgPSAiZmlndXJlcy9jdXJlX2ZhaWxfc3VzX3NoYXBlX29ubHl6MjJfejIzLnBkZiIpCm9ubHlfdHdvX2NmX3BjYSRwbG90CmRldi5vZmYoKQpvbmx5X3R3b19jZl9wY2EKCm9ubHlfdHdvX2NmX2tub3duIDwtIHN1YnNldF9leHB0KG9ubHlfdHdvX2NmLCBzdWJzZXQgPSAiY29uZGl0aW9uIT0ndW5rbm93biciKQpvbmx5X3R3b19jZl9rbm93bl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KG9ubHlfdHdvX2NmX2tub3duLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkKb25seV90d29fY2Zfa25vd25fcGNhIDwtIHBsb3RfcGNhKG9ubHlfdHdvX2NmX2tub3duX25vcm0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBDQSBvZiB6Mi4yIGFuZCB6Mi4zIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCmRldiA8LSBwcChmaWxlID0gImZpZ3VyZXMvY3VyZV9mYWlsX3N1c19zaGFwZV9vbmx5ejIyX3oyM19rbm93bi5wZGYiKQpvbmx5X3R3b19jZl9rbm93bl9wY2EkcGxvdApkZXYub2ZmKCkKb25seV90d29fY2Zfa25vd25fcGNhCgpjZl9uYiA8LSBub3JtYWxpemVfZXhwdChscF9jZiwgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIpCmNmX25iX3BjYSA8LSBwbG90X3BjYShjZl9uYiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKZGV2IDwtIHBwKGZpbGUgPSAiaW1hZ2VzL2NmX3N1c19zaGFyZV9uYi5wbmciKQpjZl9uYl9wY2EkcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCmNmX25iX3BjYQoKY2Zfbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9jZiwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCnRlc3QgPC0gcGNhX2luZm9ybWF0aW9uKGNmX25vcm0sCiAgICAgICAgICAgICAgICAgICAgICAgIGV4cHRfZmFjdG9ycyA9IGMoImNsaW5pY2FsY2F0ZWdvcmljYWwiLCAienltb2RlbWVjYXRlZ29yaWNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBhdGhvZ2Vuc3RyYWluIiwgInBhc3NhZ2VudW1iZXIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgbnVtX2NvbXBvbmVudHMgPSA2LCBwbG90X3BjYXMgPSBUUlVFKQp0ZXN0JGFub3ZhX3AKdGVzdCRjb3JfaGVhdG1hcApgYGAKCiMjIEJ5IEN1cnJlbnQgZHJ1ZyBzZW5zaXRpdml0eSBhc3NheSBkYXRhCgpXZSBoYXZlIHR3byBjb21wZXRpbmcgbWV0cmljcyBvZiBhbnRtb25pYWwgc2Vuc2l0aXZpdHk7IG9uZSBoaXN0b3JpY2FsCmFuZCBvbmUgY3VycmVudC4gIEluIGJvdGggY2FzZXMgdGhlcmUgaXMgYSByZWFzb25hYmxlIGV4cGVjdGF0aW9uIHRoYXQKcmVzaXN0YW50IHN0cmFpbnMgdGVuZCB0byBiZSB6eW1vZGVtZSAyLjMgYW5kIHNlbnNpdGl2ZSBzdHJhaW5zIHRlbmQKdG8gYmUgenltb2RlbWUgMi4yLiAgVGhlcmUgYXBwZWFyIHRvIGJlIG1vcmUgZXhjZXB0aW9ucyB0byB0aGlzIHJ1bGUKb2YgdGh1bWIgaW4gdGhlIGN1cnJlbnQgZGF0YSB0aGFuIHRoZSBoaXN0b3JpY2FsLgoKYGBge3J9CmRpbShleHBycyhscF9zdXNjZXB0aWJpbGl0eSkpCnN1c19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGxwX3N1c2NlcHRpYmlsaXR5LCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnN1c19wY2EgPC0gcGxvdF9wY2Eoc3VzX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJmaWd1cmVzL3N1c19ub3JtX3BjYS5zdmciKQpzdXNfcGNhW1sicGxvdCJdXQpjbG9zZWQgPC0gZGV2Lm9mZigpCmRldiA8LSBwcChmaWxlID0gImZpZ3VyZXMvc3VzX25vcm1fcGNhLnBkZiIpCnN1c19wY2FbWyJwbG90Il1dCmNsb3NlZCA8LSBkZXYub2ZmKCkKc3VzX3BjYQoKbHBfc3VzY2VwdGliaWxpdHlfa25vd24gPC0gc3Vic2V0X2V4cHQobHBfc3VzY2VwdGliaWxpdHksIHN1YnNldCA9ICJiYXRjaCE9J3Vua25vd24nIikKc3VzX2tub3duX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobHBfc3VzY2VwdGliaWxpdHlfa25vd24sIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSkKc3VzX2tub3duX3BjYSA8LSBwbG90X3BjYShzdXNfa25vd25fbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCmRldiA8LSBwcChmaWxlID0gImZpZ3VyZXMvc3VzX25vcm1fa25vd25fcGNhLnBkZiIpCnN1c19rbm93bl9wY2FbWyJwbG90Il1dCmNsb3NlZCA8LSBkZXYub2ZmKCkKc3VzX2tub3duX3BjYQoKbHBfc3VzX3R3byA8LSBzdWJzZXRfZXhwdChscF9zdXNjZXB0aWJpbGl0eSwgc3Vic2V0ID0gInp5bW9kZW1lY2F0ZWdvcmljYWwhPSd6MjEnIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0ID0gInp5bW9kZW1lY2F0ZWdvcmljYWwhPSd6MjQnIikKc3VzX3R3b19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGxwX3N1c190d28sIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnN1c190d29fcGNhIDwtIHBsb3RfcGNhKHN1c190d29fbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJmaWd1cmVzL3N1c19ub3JtX3R3b19wY2EucGRmIikKc3VzX3R3b19wY2FbWyJwbG90Il1dCmNsb3NlZCA8LSBkZXYub2ZmKCkKc3VzX3R3b19wY2EKCmxwX3N1c190d29fa25vd24gPC0gc3Vic2V0X2V4cHQobHBfc3VzX3R3bywgc3Vic2V0ID0gImNsaW5pY2FsY2F0ZWdvcmljYWwhPSd1bmtub3duJyIpCnN1c190d29fa25vd25fbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9zdXNfdHdvX2tub3duLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpzdXNfdHdvX2tub3duX3BjYSA8LSBwbG90X3BjYShzdXNfdHdvX2tub3duX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKZGV2IDwtIHBwKGZpbGUgPSAiZmlndXJlcy9zdXNfbm9ybV90d29fa25vd25fcGNhLnBkZiIpCnN1c190d29fa25vd25fcGNhW1sicGxvdCJdXQpjbG9zZWQgPC0gZGV2Lm9mZigpCnN1c190d29fa25vd25fcGNhCgpzdXNfbmIgPC0gbm9ybWFsaXplX2V4cHQobHBfc3VzY2VwdGliaWxpdHksIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKc3VzX25iX3BjYSA8LSBwbG90X3BjYShzdXNfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvc3VzX25iX3BjYS5wbmciKQpzdXNfbmJfcGNhW1sicGxvdCJdXQpjbG9zZWQgPC0gZGV2Lm9mZigpCnN1c19uYl9wY2EKYGBgCgojIyBCeSBIaXN0b3JpY2FsIGRydWcgc2Vuc2l0aXZpdHkgYXNzYXkgZGF0YQoKYGBge3J9CnN1c19oaXN0X25vcm0gPC0gbm9ybWFsaXplX2V4cHQobHBfc3VzY2VwdGliaWxpdHlfaGlzdG9yaWNhbCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnN1c19oaXN0X3BjYSA8LSBwbG90X3BjYShzdXNfaGlzdF9ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvc3VzX2hpc3Rfbm9ybV9wY2EucG5nIikKc3VzX2hpc3RfcGNhW1sicGxvdCJdXQpjbG9zZWQgPC0gZGV2Lm9mZigpCnN1c19oaXN0X3BjYQoKc3VzX2hpc3RfbmIgPC0gbm9ybWFsaXplX2V4cHQobHBfc3VzY2VwdGliaWxpdHlfaGlzdG9yaWNhbCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCnN1c19oaXN0X25iX3BjYSA8LSBwbG90X3BjYShzdXNfaGlzdF9uYiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKZGV2IDwtIHBwKGZpbGUgPSAiaW1hZ2VzL3N1c19oaXN0X25iX3BjYS5wbmciKQpzdXNfaGlzdF9uYl9wY2FbWyJwbG90Il1dCmNsb3NlZCA8LSBkZXYub2ZmKCkKc3VzX2hpc3RfbmJfcGNhCmBgYAoKIyMgWnltb2RlbWUgZW56eW1lIGdlbmUgSURzCgpOYWppYiByZWFkIG1lIGFuIGVtYWlsIGxpc3Rpbmcgb2ZmIHRoZSBnZW5lIG5hbWVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgenltb2RlbWUKY2xhc3NpZmljYXRpb24uICBJIHRvb2sgdGhvc2UgbmFtZXMgYW5kIGNyb3NzIHJlZmVyZW5jZWQgdGhlbSBhZ2FpbnN0IHRoZQpMZWlzaG1hbmlhIHBhbmFtZW5zaXMgZ2VuZSBhbm5vdGF0aW9ucyBhbmQgZm91bmQgdGhlIGZvbGxvd2luZzoKClRoZXkgYXJlOgoKMS4gQUxBVDogTFBBTDEzXzEyMDAxMDkwMCAtLSBhbGFuaW5lIGFtaW5vdHJhbnNmZXJhc2UKMi4gQVNBVDogTFBBTDEzXzM0MDAxMzAwMCAtLSBhc3BhcnRhdGUgYW1pbm90cmFuc2ZlcmFzZQozLiBHNlBEOiBMUEFMMTNfMDAwMDU0MTAwIC0tIGdsdWNhc2UtNi1waG9zcGhhdGUgMS1kZWh5ZHJvZ2VuYXNlCjQuIE5IOiBMUEFMMTNfMTQwMDYxMDAsIExQQUwxM18xODAwMTg1MDAgLS0gaW5vc2luZS1ndWFuaW5lIG51Y2xlb3NpZGUgaHlkcm9sYXNlCjUuIE1QSTogTFBBTDEzXzMyMDAyMjMwMCAobWF5YmUpIC0tIG1hbm5vc2UgcGhvc3BoYXRlIGlzb21lcmFzZSAoSSBjaG9zZSBwaG9zcGhvbWFubm9zZSBpc29tZXJhc2UpCgpHaXZlbiB0aGVzZSA2IGdlbmUgSURzIChOSCBoYXMgdHdvIGdlbmUgSURzIGFzc29jaWF0ZWQgd2l0aCBpdCksIEkgY2FuIGRvIHNvbWUKbG9va2luZyBmb3Igc3BlY2lmaWMgZGlmZmVyZW5jZXMgYW1vbmcgdGhlIHZhcmlvdXMgc2FtcGxlcy4KCiMjIyBFeHByZXNzaW9uIGxldmVscyBvZiB6eW1vZGVtZSBnZW5lcwoKVGhlIGZvbGxvd2luZyBjcmVhdGVzIGEgY29sb3JzcGFjZSAocmVkIHRvIGdyZWVuKSBoZWF0bWFwIHNob3dpbmcgdGhlIG9ic2VydmVkCmV4cHJlc3Npb24gb2YgdGhlc2UgZ2VuZXMgaW4gZXZlcnkgc2FtcGxlLgoKYGBge3J9Cm15X2dlbmVzIDwtIGMoIkxQQUwxM18xMjAwMTA5MDAiLCAiTFBBTDEzXzM0MDAxMzAwMCIsICJMUEFMMTNfMDAwMDU0MTAwIiwKICAgICAgICAgICAgICAiTFBBTDEzXzE0MDAwNjEwMCIsICJMUEFMMTNfMTgwMDE4NTAwIiwgIkxQQUwxM18zMjAwMjIzMDAiLAogICAgICAgICAgICAgICJvdGhlciIpCm15X25hbWVzIDwtIGMoIkFMQVQiLCAiQVNBVCIsICJHNlBEIiwgIk5IdjEiLCAiTkh2MiIsICJNUEkiLCAib3RoZXIiKQoKenltb19leHB0IDwtIGV4Y2x1ZGVfZ2VuZXNfZXhwdChzdHJhaW5fbm9ybSwgaWRzID0gbXlfZ2VuZXMsIG1ldGhvZCA9ICJrZWVwIikKenltb19oZWF0bWFwIDwtIHBsb3Rfc2FtcGxlX2hlYXRtYXAoenltb19leHB0LCByb3dfbGFiZWwgPSBteV9uYW1lcykKenltb19oZWF0bWFwCmBgYAoKQSByZWNlbnQgc3VnZ2VzdGlvbiBpbmNsdWRlZCBhIHF1ZXJ5IGFib3V0IHRoZSByZWxhdGlvbnNoaXAgb2Ygb3VyCmFtYXN0aWdvdGUgVE1SQzIgc2FtcGxlcyB3aGljaCB3ZXJlIHRoZSByZXN1bHQgb2YgaW5mZWN0aW5nIGEgc2V0IG9mCm1hY3JvcGhhZ2VzIHZzLiB0aGVzZSBwcm9tYXN0aWdvdGUgc2FtcGxlcy4KClNvIGZhciwgd2UgaGF2ZSBrZXB0IHRoZXNlIHR3byBleHBlcmltZW50cyBzZXBhcmF0ZSwgbm93IGxldCB1cyBtZXJnZSB0aGVtLgoKYGBge3J9CnRtcmMyX21hY3JvcGhhZ2Vfbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9tYWNyb3BoYWdlLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQoKIyMgSGV5IHlvdSwgdGhpcyBhbm5vdGF0aW9uIGNhbGwgc2hvdWxkIGJlIG1hZGUgYXV0b21hdGljIGZvciB0aGUgY29udGFpbmVyIQphbm5vdGF0aW9uKGxwX2V4cHQpIDwtICJvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYiIKYW5ub3RhdGlvbihscF9tYWNyb3BoYWdlKSA8LSBhbm5vdGF0aW9uKGxwX2V4cHQpCmFsbF90bXJjMiA8LSBjb21iaW5lX2V4cHRzKGxwX2V4cHQsIGxwX21hY3JvcGhhZ2UpCmBgYAoKQmVmb3JlIHdlIGNhbiB1c2UgdGhlIGNvbWJpbmVkIGRhdGEsIHdlIG11c3QgcmVjb25jaWxlIGEgZmV3IG9mCmFzcGVjdHMgb2YgaXQsIG5vdGFibHkgd2UgbmVlZCB0byBzcGVjaWZ5IHdoaWNoIHNhbXBsZXMgYXJlCmFtYXN0aWdvdGVzIGFuZCB3aGljaCBhcmUgcHJvbWFzdGlnb3Rlcy4KCmBgYHtyfQphbGxfbm9zYiA8LSBhbGxfdG1yYzIKcERhdGEoYWxsX25vc2IpW1sic3RhZ2UiXV0gPC0gInByb21hc3RpZ290ZSIKbmFfaWR4IDwtIGlzLm5hKHBEYXRhKGFsbF9ub3NiKVtbIm1hY3JvcGhhZ2V0cmVhdG1lbnQiXV0pCnBEYXRhKGFsbF9ub3NiKVtuYV9pZHgsICJtYWNyb3BoYWdldHJlYXRtZW50Il0gPC0gInVuZGVmaW5lZCIKYWxsX25vc2IgPC0gc3Vic2V0X2V4cHQoYWxsX25vc2IsIHN1YnNldCA9ICJtYWNyb3BoYWdldHJlYXRtZW50IT0naW5mX3NiJyIpCmFtYV9pZHggPC0gcERhdGEoYWxsX25vc2IpW1sibWFjcm9waGFnZXRyZWF0bWVudCJdXSA9PSAiaW5mIgpwRGF0YShhbGxfbm9zYilbYW1hX2lkeCwgInN0YWdlIiBdIDwtICJhbWFzdGlnb3RlIgoKIyMgTWFrZSBzdXJlIHRoYXQgdGhlIHp5bW9kZW1lIGRvZXMgbm90IGhhdmUgdGhlIGluZl8gcHJlZml4Lgp6eW1vZGVtZV9jaGFyIDwtIGdzdWIoeCA9IHBEYXRhKGFsbF9ub3NiKVtbImNvbmRpdGlvbiJdXSwgcGF0dGVybiA9ICJeaW5mXyIsIHJlcGxhY2VtZW50ID0gIiIpCnBEYXRhKGFsbF9ub3NiKVtbImNvbmRpdGlvbiJdXSA8LSB6eW1vZGVtZV9jaGFyCgpwRGF0YShhbGxfbm9zYilbWyJiYXRjaCJdXSA8LSBwRGF0YShhbGxfbm9zYilbWyJzdGFnZSJdXQphbGxfbm9ybSA8LSBub3JtYWxpemVfZXhwdChhbGxfbm9zYiwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBmaWx0ZXIgPSBUUlVFKQpwcm9fYW1hX3BjYSA8LSBwbG90X3BjYShhbGxfbm9ybSkKcHJvX2FtYV9wY2FbWyJwbG90Il1dCmBgYAoKSSB0aGluayB0aGUgYWJvdmUgcGljdHVyZSBpcyBzb3J0IG9mIHRoZSBvcHBvc2l0ZSBvZiB3aGF0IHdlIHdhbnQgdG8KY29tcGFyZSBpbiBhIERFIGFuYWx5c2lzIGZvciB0aGlzIHNldCBvZiBkYXRhLCBlLmcuIHdlIHdhbnQgdG8gY29tcGFyZQpwcm9tYXN0aWdvdGVzIGZyb20gYW1hc3RpZ290ZXM/CgpgYGB7cn0KdHdvX25vc2IgPC0gc2V0X2V4cHRfYmF0Y2hlcyhhbGxfbm9zYiwgZmFjdCA9ICJjb25kaXRpb24iKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAic3RhZ2UiKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQgPSAiYmF0Y2g9PSd6Mi4yJ3xiYXRjaD09J3oyLjMnIikKCnR3b19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHR3b19ub3NiLCBjb252ZXJ0ID0gImNwbSIsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGZpbHRlciA9IFRSVUUpCnByb19hbWFfdHdvX3BjYSA8LSBwbG90X3BjYSh0d29fbm9ybSkKcHJvX2FtYV90d29fcGNhW1sicGxvdCJdXQoKenlfc3RhZ2VfZmFjdG9yIDwtIHBhc3RlMChwRGF0YSh0d29fbm9zYilbWyJiYXRjaCJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBEYXRhKHR3b19ub3NiKVtbInN0YWdlIl1dKQpwRGF0YSh0d29fbm9zYilbWyJ6eXN0YWdlIl1dIDwtIHp5X3N0YWdlX2ZhY3Rvcgp6eXN0YWdlIDwtIHNldF9leHB0X2NvbmRpdGlvbnModHdvX25vc2IsIGZhY3QgPSAienlzdGFnZSIpCgp6eXN0YWdlX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoenlzdGFnZSwgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIikKcGxvdF9wY2EoenlzdGFnZV9ub3JtKSRwbG90Cgp6eXN0YWdlX2tlZXBlcnMgPC0gbGlzdCgKICAiejIzMjJfYW1hIiA9IGMoInoyM2FtYXN0aWdvdGUiLCAiejIyYW1hc3RpZ290ZSIpLAogICJ6MjMyMl9wcm8iID0gYygiejIzcHJvbWFzdGlnb3RlIiwgInoyMnByb21hc3RpZ290ZSIpLAogICJwcm9hbWFfejIzIiA9IGMoInoyM2FtYXN0aWdvdGUiLCAiejIzcHJvbWFzdGlnb3RlIiksCiAgInByb2FtYV96MjIiID0gYygiejIyYW1hc3RpZ290ZSIsICJ6MjJwcm9tYXN0aWdvdGUiKSkKCnp5c3RhZ2VfZGUgPC0gYWxsX3BhaXJ3aXNlKHp5c3RhZ2UsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpCgp6eXN0YWdlX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICB6eXN0YWdlX2RlLCBrZWVwZXJzID0genlzdGFnZV9rZWVwZXJzLAogIGV4Y2VsID0gZ2x1ZSgiZXhjZWwvenltb2RlbWVfc3RhZ2VfdGFibGUtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIEdlbmUgZXhwcmVzc2lvbiB3aXRoIHJlc3BlY3QgdG8gY2hyb21vc29tZQoKSSB3YW50IHRvIG1ha2UgYSBwbG90IHdoZXJlIHRoZSB4LWF4aXMgaXMgdGhlIG51bWJlciBvZiBnZW5lcyBvbiBhIGNocm9tb3NvbWUgYW5kIHRoZQp5LWF4aXMgaXMgdGhlIG1lYW4gb2YgdGhlIGV4cHJlc3Npb24gb2YgdGhvc2UgZ2VuZXMuCgpgYGB7cn0KZXhwcnNfYnlfY2hyX3Bsb3QgPC0gcGxvdF9leHByc19ieV9jaHJvbW9zb21lKGxwX3p5bW8pCmV4cHJzX2J5X2Nocl9wbG90W1sicGxvdCJdXQpgYGAKCiMgU05QIHByb2ZpbGVzCgpPbmUgcG90ZW50aWFsbHkgaW50ZXJlc3RpbmcgYXNwZWN0IG9mIHRoZSB2YXJpYW50IGRhdGE6IGl0IG1heSBiZSBhYmxlCnRvIGhlbHAgdXMgZGVmaW5lIHRoZSB6eW1vZGVtZSBzdGF0ZSBvZiBwcmV2aW91cywgdW50ZXN0ZWQgc2FtcGxlcy4KCkluIG9yZGVyIHRvIHRlc3QgdGhpcywgSSBhbSBsb2FkaW5nIHNvbWUgb2YgdGhlIDIwMTYgZGF0YSBhbG9uZ3NpZGUKdGhlIG5ldyBUTVJDMiBkYXRhIHRvIHNlZSBpZiB0aGV5IGZpdCB0b2dldGhlci4KClRoaXMgaXMgdXNpbmcgYW4gb2xkZXIgZGF0YXNldCBmb3Igd2hpY2ggSSBhbSBub3Qgc3VyZSB3ZSBoYXZlCnBlcm1pc3Npb25zIHRvIGluY2x1ZGUgaW4gdGhlIGNvbnRhaW5lciwgc28gSSBhbSB0dXJuaW5nIHRoZW0gb2ZmIGZvcgpub3cuCgpgYGB7ciwgZXZhbD1GQUxTRX0Kb2xkX2V4cHQgPC0gY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvdG1yYzJfc2FtcGxlc18yMDE5MTIwMy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidG9waGF0MmZpbGUiKQoKdHQgPC0gb2xkX2V4cHQkZXhwcmVzc2lvbnNldApyb3duYW1lcyh0dCkgPC0gZ3N1YihwYXR0ZXJuID0gIl5leG9uXyIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSByb3duYW1lcyh0dCkpCnJvd25hbWVzKHR0KSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuMSQiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gcm93bmFtZXModHQpKQpvbGRfZXhwdCRleHByZXNzaW9uc2V0IDwtIHR0CnJtKHR0KQpgYGAKCiMjIENyZWF0ZSB0aGUgU05QIGV4cHJlc3Npb25zZXQKCk9uZSBvdGhlciBpbXBvcnRhbnQgY2F2ZWF0LCB3ZSBoYXZlIGEgZ3JvdXAgb2YgbmV3IHNhbXBsZXMgd2hpY2ggaGF2ZQpub3QgeWV0IHJ1biB0aHJvdWdoIHRoZSB2YXJpYW50IHNlYXJjaCBwaXBlbGluZSwgc28gSSBuZWVkIHRvIHJlbW92ZQp0aGVtIGZyb20gY29uc2lkZXJhdGlvbi4gIFRob3VnaCBpdCBsb29rcyBsaWtlIHRoZXkgZmluaXNoZWQgb3Zlcm5pZ2h0Li4uCgpJbiB0aGUgbm9uLWNvbnRhaW5lcml6ZWQgdmVyc2lvbiBvZiB0aGlzIGRvY3VtZW50LCB0aGUgZm9sbG93aW5nIGJsb2NrCmNvbWJpbmVzIGFuIG9sZGVyIGRhdGFzZXQgd2l0aCB0aGUgY3VycmVudCBkYXRhLgoKYGBge3J9CmJvdGhfbm9ybSA8LSBub3JtYWxpemVfZXhwdChuZXdfc25wcywgdHJhbnNmb3JtID0gImxvZzIiLCBub3JtID0gInF1YW50IikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gInBhdGhvZ2Vuc3RyYWluIikKYGBgCgpUaGUgZGF0YSBzdHJ1Y3R1cmUgJ2JvdGhfbm9ybScgbm93IGNvbnRhaW5zIG91ciAyMDE2IGRhdGEgYWxvbmcgd2l0aAp0aGUgbmV3ZXIgZGF0YSBjb2xsZWN0ZWQgc2luY2UgMjAxOS4KCiMjIFBsb3Qgb2YgU05QIHByb2ZpbGVzIGZvciB6eW1vZGVtZXMKClRoZSBmb2xsb3dpbmcgcGxvdCBzaG93cyB0aGUgU05QIHByb2ZpbGVzIG9mIGFsbCBzYW1wbGVzIChvbGQgYW5kIG5ldykgd2hlcmUgdGhlCmNvbG9ycyBhdCB0aGUgdG9wIHNob3cgZWl0aGVyIHRoZSAyLjIgc3RyYWlucyAob3JhbmdlKSwgMi4zIHN0cmFpbnMgKGdyZWVuKSwgdGhlCnByZXZpb3VzIHNhbXBsZXMgKHB1cnBsZSksIG9yIHRoZSB2YXJpb3VzIGxhYiBzdHJhaW5zIChwaW5rIGV0YykuCgpgYGB7cn0KbmV3X3ZhcmlhbnRfaGVhdG1hcCA8LSBwbG90X2Rpc2hlYXQobmV3X3NucHMpCmRldiA8LSBwcChmaWxlID0gImltYWdlcy9yYXdfc25wX2Rpc2hlYXQucG5nIiwgaGVpZ2h0ID0gMTIsIHdpZHRoID0gMTIpCm5ld192YXJpYW50X2hlYXRtYXAkcGxvdApjbG9zZWQgPC0gZGV2Lm9mZigpCm5ld192YXJpYW50X2hlYXRtYXAkcGxvdApgYGAKClRoZSBmdW5jdGlvbiBnZXRfc25wX3NldHMoKSB0YWtlcyB0aGUgcHJvdmlkZWQgbWV0YWRhdGEgZmFjdG9yIChpbgp0aGlzIGNhc2UgJ2NvbmRpdGlvbicpIGFuZCBsb29rcyBmb3IgdmFyaWFudHMgd2hpY2ggYXJlIGV4Y2x1c2l2ZSB0bwplYWNoIGVsZW1lbnQgaW4gaXQuICBJbiB0aGlzIGNhc2UsIHRoaXMgaXMgbG9va2luZyBmb3IgZGlmZmVyZW5jZXMKYmV0d2VlbiAyLjIgYW5kIDIuMywgYXMgd2VsbCBhcyB0aGUgc2V0IHNoYXJlZCBhbW9uZyB0aGVtLgoKYGBge3J9CnNucF9zZXRzIDwtIGdldF9zbnBfc2V0cyhuZXdfc25wcywgZmFjdG9yID0gImNvbmRpdGlvbiIpCnNucF9zZXRzCiMjQmlvYmFzZTo6YW5ub3RhdGlvbihvbGRfZXhwdCRleHByZXNzaW9uc2V0KSA9IEJpb2Jhc2U6OmFubm90YXRpb24obHBfZXhwdCRleHByZXNzaW9uc2V0KQojI2JvdGhfZXhwdCA8LSBjb21iaW5lX2V4cHRzKGxwX2V4cHQsIG9sZF9leHB0KQoKc25wX2dlbmVzIDwtIHNtKHNucHNfdnNfZ2VuZXMobHBfZXhwdCwgc25wX3NldHMsIGV4cHRfbmFtZV9jb2wgPSAiY2hyb21vc29tZSIpKQpzbnBfZ2VuZXMKIyMgSSB0aGluayB3ZSBoYXZlIHNvbWUgbWV0cmljcyBoZXJlIHdlIGNhbiBwbG90Li4uCnNucF9zdWJzZXQgPC0gc25wX3N1YnNldF9nZW5lcygKICBscF9leHB0LCBuZXdfc25wcywKICBnZW5lcyA9IGMoIkxQQUwxM18xMjAwMTA5MDAiLCAiTFBBTDEzXzM0MDAxMzAwMCIsICJMUEFMMTNfMDAwMDU0MTAwIiwKICAgICAgICAgICAgIkxQQUwxM18xNDAwMDYxMDAiLCAiTFBBTDEzXzE4MDAxODUwMCIsICJMUEFMMTNfMzIwMDIyMzAwIikpCnp5bW9faGVhdCA8LSBwbG90X3NhbXBsZV9oZWF0bWFwKHNucF9zdWJzZXQsIHJvd19sYWJlbCA9IHJvd25hbWVzKGV4cHJzKHNucF9zdWJzZXQpKSkKenltb19oZWF0CmBgYAoKIyMgQ29tcGFyZSB2YXJpYW50cyB0byBERSBnZW5lcwoKTmFqaWIgaGFzIGFza2VkIGEgZmV3IHRpbWVzIGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYW50cwphbmQgREUgZ2VuZXMuICBJbiBzdWJzZXF1ZW50IGNvbnZlcnNhdGlvbnMgSSBmaWd1cmVkIG91dCB3aGF0IGhlCnJlYWxseSB3YW50cyB0byBsZWFybiBpcyB2YXJpYW50cyBpbiB0aGUgVVRSIChtb3N0IGxpa2VseSA1Jykgd2hpY2gKbWlnaHQgYWZmZWN0IGV4cHJlc3Npb24gb2YgZ2VuZXMuICBUaGUgZm9sbG93aW5nIGV4cGxpY2l0bHkgZG9lcyBub3QKaGVscCB0aGlzIHF1ZXN0aW9uLCBidXQgaXMgYSBwYXJhbG9nOiBpcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuCnZhcmlhbnRzIGluIHRoZSBDRFMgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uPwoKIyMjIENvbGxlY3QgREUgZGF0YQoKSW4gb3JkZXIgdG8gZG8gdGhpcyBjb21wYXJpc29uLCB3ZSBuZWVkIHRvIHJlbG9hZCBzb21lIG9mIHRoZSBERSByZXN1bHRzLgoKVGhlc2UgYmxvY2tzIG5lZWQgdG8gYmUgbW92ZWQgdG8gcG9zdC1kaWZmZXJlbnRpYWwgYW5hbHlzZXMKCmBgYHtyIHJlbG9hZF9kZV9yZXN1bHRzLCBldmFsPUZBTFNFfQpyZGEgPC0gZ2x1ZSgicmRhL3p5bW9fdGFibGVzX3N2YS12e3Zlcn0ucmRhIikKdmFybmFtZSA8LSBnc3ViKHggPSBiYXNlbmFtZShyZGEpLCBwYXR0ZXJuID0gIlxcLnJkYSIsIHJlcGxhY2VtZW50ID0gIiIpCmxvYWRlZCA8LSBsb2FkKGZpbGUgPSByZGEpCnp5X2RmIDwtIGdldDAodmFybmFtZSlbWyJkYXRhIl1dW1sienltb2RlbWUiXV0KYGBgCgpgYGB7ciB2YXJpYW50c192c19kZSwgZXZhbD1GQUxTRX0KdmFyc19kZiA8LSBkYXRhLmZyYW1lKElEID0gbmFtZXMoc25wX2dlbmVzJHN1bW1hcnlfYnlfZ2VuZSksIHZhcmlhbnRzID0gYXMubnVtZXJpYyhzbnBfZ2VuZXMkc3VtbWFyeV9ieV9nZW5lKSkKdmFyc19kZltbInZhcmlhbnRzIl1dIDwtIGxvZzIodmFyc19kZltbInZhcmlhbnRzIl1dICsgMSkKdmFyc19ieV9kZV9nZW5lIDwtIG1lcmdlKHp5X2RmLCB2YXJzX2RmLCBieS54ID0gInJvdy5uYW1lcyIsIGJ5LnkgPSAiSUQiKQpjb3IudGVzdCh2YXJzX2J5X2RlX2dlbmUkZGVzZXFfbG9nZmMsIHZhcnNfYnlfZGVfZ2VuZSR2YXJpYW50cykKdmFyaWFudHNfd3J0X2xvZ2ZjIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIodmFyc19ieV9kZV9nZW5lWywgYygiZGVzZXFfbG9nZmMiLCAidmFyaWFudHMiKV0pCnZhcmlhbnRzX3dydF9sb2dmYyRzY2F0dGVyCiMjIEl0IGxvb2tzIGxpa2UgdGhlcmUgbWlnaHQgYmUgc29tZSBnZW5lcyBvZiBpbnRlcmVzdCwgZXZlbiB0aG91Z2ggdGhpcyBpcyBub3QgYWN0dWFsbHkKIyMgdGhlIHF1ZXN0aW9uIG9mIGludGVyZXN0LgpgYGAKCkRpZG4ndCBJIGNyZWF0ZSBhIHNldCBvZiBkZW5zaXRpZXMgYnkgY2hyb21vc29tZT8KT2ggSSB0aGluayB0aGV5IGNvbWUgaW4gZnJvbSBnZXRfc25wX3NldHMoKQoKIyMgU05QUyBhc3NvY2lhdGVkIHdpdGggY2xpbmljYWwgcmVzcG9uc2UgaW4gdGhlIFRNUkMgc2FtcGxlcwoKYGBge3J9CmNsaW5pY2FsX3NldHMgPC0gZ2V0X3NucF9zZXRzKG5ld19zbnBzLCBmYWN0b3IgPSAiY2xpbmljYWxyZXNwb25zZSIpCmNsaW5pY2FsX3NldHMKCmRlbnNpdHlfdmVjIDwtIGNsaW5pY2FsX3NldHNbWyJkZW5zaXR5Il1dCmNocm9tb3NvbWVfaWR4IDwtIGdyZXAocGF0dGVybiA9ICJMcGFMIiwgeCA9IG5hbWVzKGRlbnNpdHlfdmVjKSkKZGVuc2l0eV9kZiA8LSBhcy5kYXRhLmZyYW1lKGRlbnNpdHlfdmVjW2Nocm9tb3NvbWVfaWR4XSkKZGVuc2l0eV9kZltbImNociJdXSA8LSByb3duYW1lcyhkZW5zaXR5X2RmKQpjb2xuYW1lcyhkZW5zaXR5X2RmKSA8LSBjKCJkZW5zaXR5X3ZlYyIsICJjaHIiKQp2YXJfZGVuX2NociA8LSBnZ3Bsb3QoZGVuc2l0eV9kZiwgYWVzKHggPSBjaHIsIHkgPSBkZW5zaXR5X3ZlYykpICsKICBnZ3Bsb3QyOjpnZW9tX2NvbCgpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkpCnZhcl9kZW5fY2hyCnBwKGZpbGUgPSAiZmlndXJlcy92YXJpYW50X2RlbnNpdHlfYnlfY2hyb21vc29tZS5wZGYiKQp2YXJfZGVuX2NocgpkZXYub2ZmKCkKIyMgb29wcywgZm9yZ290IHRvIGV4cG9ydCB3cml0ZV9zbnBzLi4uICBmaXhlZC4KY2xpbmljYWxfd3JpdHRlbiA8LSB3cml0ZV9zbnBzKG5ld19zbnBzLCBvdXRwdXRfZmlsZSA9ICJjbGluaWNhbF92YXJpYW50cy5hbG4iKQpgYGAKCiMjIyBDcm9zcyByZWZlcmVuY2UgdGhlc2UgdmFyaWFudHMgYnkgZ2VuZQoKYGBge3J9CmNsaW5pY2FsX2dlbmVzIDwtIHNucHNfdnNfZ2VuZXMobHBfZXhwdCwgY2xpbmljYWxfc2V0cywgZXhwdF9uYW1lX2NvbCA9ICJjaHJvbW9zb21lIikKCnNucF9kZW5zaXR5IDwtIG1lcmdlKGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfZ2VuZXNbWyJzdW1tYXJ5Il1dKSwKICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShmRGF0YShscF9leHB0KSksCiAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIpCnNucF9kZW5zaXR5IDwtIHNucF9kZW5zaXR5WywgYygxLCAyLCA0LCAxNSldCmNvbG5hbWVzKHNucF9kZW5zaXR5KSA8LSBjKCJuYW1lIiwgInNucHMiLCAicHJvZHVjdCIsICJsZW5ndGgiKQpzbnBfZGVuc2l0eVtbInByb2R1Y3QiXV0gPC0gdG9sb3dlcihzbnBfZGVuc2l0eVtbInByb2R1Y3QiXV0pCnNucF9kZW5zaXR5W1sibGVuZ3RoIl1dIDwtIGFzLm51bWVyaWMoc25wX2RlbnNpdHlbWyJsZW5ndGgiXV0pCnNucF9kZW5zaXR5W1siZGVuc2l0eSJdXSA8LSBhcy5udW1lcmljKHNucF9kZW5zaXR5W1sic25wcyJdXSkgLyBzbnBfZGVuc2l0eVtbImxlbmd0aCJdXQpzbnBfaWR4IDwtIG9yZGVyKHNucF9kZW5zaXR5W1siZGVuc2l0eSJdXSwgZGVjcmVhc2luZyA9IFRSVUUpCnNucF9kZW5zaXR5IDwtIHNucF9kZW5zaXR5W3NucF9pZHgsIF0KCnJlbW92ZXJzIDwtIGMoImFtYXN0aW4iLCAiZ3A2MyIsICJsZWlzaG1hbm9seXNpbiIpCmZvciAociBpbiByZW1vdmVycykgewogIGRyb3BfaWR4IDwtIGdyZXBsKHBhdHRlcm4gPSByLCB4ID0gc25wX2RlbnNpdHlbWyJwcm9kdWN0Il1dKQogIHNucF9kZW5zaXR5IDwtIHNucF9kZW5zaXR5WyFkcm9wX2lkeCwgXQp9CiMjIEZpbHRlciB0aGVzZSBmb3IgW0F8YV1tYXN0aW4gZ3A2MyBMZWlzaG1hbm9seXNpbgpgYGAKCkxldCB1cyBncmFiIG91dCB0aGUgbnVtYmVyIG9mIHZhcmlhbnRzL2dlbmUgZm9yIHRoZSBjdXJlL2ZhaWwgc2FtcGxlcywKbWVyZ2UgdGhlbSBpbnRvIGEgZGF0YWZyYW1lLCBhbmQgYWRkIHRoYXQgdG8gdGhlIGdlbmUgYW5ub3RhdGlvbnMgZm9yCnRoZSBscF9leHB0IGRhdGFzdHJ1Y3R1cmUuCgpgYGB7cn0KY2xpbmljYWxfc25wcyA8LSBzbnBzX2ludGVyc2VjdGlvbnMobHBfZXhwdCwgY2xpbmljYWxfc2V0cywgY2hyX2NvbHVtbiA9ICJjaHJvbW9zb21lIikKCmZhaWxfcmVmX3NucHMgPC0gYXMuZGF0YS5mcmFtZShjbGluaWNhbF9zbnBzW1siaW50ZXJzIl1dW1siZmFpbHVyZSwgcmVmZXJlbmNlIHN0cmFpbiJdXSkKZmFpbF9yZWZfc25wcyA8LSByYmluZChmYWlsX3JlZl9zbnBzLAogICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfc25wc1tbImludGVycyJdXVtbImZhaWx1cmUiXV0pKQpjdXJlX3NucHMgPC0gYXMuZGF0YS5mcmFtZShjbGluaWNhbF9zbnBzW1siaW50ZXJzIl1dW1siY3VyZSJdXSkKCmhlYWQoZmFpbF9yZWZfc25wcykKaGVhZChjdXJlX3NucHMpCndyaXRlLmNzdihmaWxlID0gImV4Y2VsL2N1cmVfdmFyaWFudHMudHh0IiwgeCA9IHJvd25hbWVzKGN1cmVfc25wcykpCndyaXRlLmNzdihmaWxlID0gImV4Y2VsL2ZhaWxfdmFyaWFudHMudHh0IiwgeCA9IHJvd25hbWVzKGZhaWxfcmVmX3NucHMpKQoKYW5ub3QgPC0gZkRhdGEobHBfZXhwdCkKY2xpbmljYWxfaW50ZXJlc3RfY3VyZSA8LSBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJnZW5lX3N1bW1hcmllcyJdXVtbImN1cmUiXV0pCnN1bW1hcnkoY2xpbmljYWxfaW50ZXJlc3RfY3VyZSkKY2xpbmljYWxfaW50ZXJlc3RfZmFpbCA8LSBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJnZW5lX3N1bW1hcmllcyJdXVtbImZhaWx1cmUiXV0pCnN1bW1hcnkoY2xpbmljYWxfaW50ZXJlc3RfZmFpbCkKCmNsaW5pY2FsX2ludGVyZXN0IDwtIG1lcmdlKGNsaW5pY2FsX2ludGVyZXN0X2N1cmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsaW5pY2FsX2ludGVyZXN0X2ZhaWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIsIGFsbCA9IFRSVUUpCgpyb3duYW1lcyhjbGluaWNhbF9pbnRlcmVzdCkgPC0gY2xpbmljYWxfaW50ZXJlc3RbWyJSb3cubmFtZXMiXV0KY2xpbmljYWxfaW50ZXJlc3RbWyJSb3cubmFtZXMiXV0gPC0gTlVMTApjb2xuYW1lcyhjbGluaWNhbF9pbnRlcmVzdCkgPC0gYygiY3VyZV9zbnBzIiwgImZhaWxfc25wcyIpCmNsaW5pY2FsX2Fubm90IDwtIG1lcmdlKGFubm90LCBjbGluaWNhbF9pbnRlcmVzdCwgYnkgPSAicm93Lm5hbWVzIikKcm93bmFtZXMoYW5ub3QpIDwtIGFubm90W1siUm93Lm5hbWVzIl1dCmFubm90W1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKZGltKGFubm90KQpkaW0oZkRhdGEobHBfZXhwdCkpCmZEYXRhKGxwX2V4cHQpIDwtIGFubm90CmBgYAoKIyBaeW1vZGVtZSBmb3IgbmV3IHNhbXBsZXMKClRoZSBoZWF0bWFwIHByb2R1Y2VkIGhlcmUgc2hvdWxkIHNob3cgdGhlIHZhcmlhbnRzIG9ubHkgZm9yIHRoZSB6eW1vZGVtZSBnZW5lcy4KCiMjIEh1bnQgZm9yIHNucCBjbHVzdGVycwoKSSBhbSB0aGlua2luZyB0aGF0IGlmIHdlIGZpbmQgY2x1c3RlcnMgb2YgbG9jYXRpb25zIHdoaWNoIGFyZSB2YXJpYW50LCB0aGF0Cm1pZ2h0IHByb3ZpZGUgc29tZSBQQ1IgdGVzdGluZyBwb3NzaWJpbGl0aWVzLgoKYGBge3J9CiMjIERyb3AgdGhlIDIuMSwgMi40LCB1bmtub3duLCBhbmQgbnVsbApwcnVuZWRfc25wcyA8LSBzdWJzZXRfZXhwdChuZXdfc25wcywgc3Vic2V0ID0gImNvbmRpdGlvbj09J3oyLjInfGNvbmRpdGlvbj09J3oyLjMnIikKbmV3X3NldHMgPC0gZ2V0X3NucF9zZXRzKHBydW5lZF9zbnBzLCBmYWN0b3IgPSAienltb2RlbWVjYXRlZ29yaWNhbCIpCnN1bW1hcnkobmV3X3NldHMpCiMjIDEwMDAwMDA6IDIuMgojIyAwMTAwMDAwOiAyLjMKCnN1bW1hcnkobmV3X3NldHNbWyJpbnRlcnNlY3Rpb25zIl1dW1siMTAiXV0pCndyaXRlLmNzdihmaWxlID0gImV4Y2VsL3ZhcmlhbnRzXzIyLmNzdiIsIHggPSBuZXdfc2V0c1tbImludGVyc2VjdGlvbnMiXV1bWyIxMCJdXSkKc3VtbWFyeShuZXdfc2V0c1tbImludGVyc2VjdGlvbnMiXV1bWyIwMSJdXSkKd3JpdGUuY3N2KGZpbGUgPSAiZXhjZWwvdmFyaWFudHNfMjMuY3N2IiwgeCA9IG5ld19zZXRzW1siaW50ZXJzZWN0aW9ucyJdXVtbIjAxIl1dKQpgYGAKClRodXMgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIDMsNTUzIHZhcmlhbnRzIGFzc29jaWF0ZWQgd2l0aCAyLjIgYW5kCjgxLDU4OSBhc3NvY2lhdGVkIHdpdGggMi4zLgoKIyMjIEEgc21hbGwgZnVuY3Rpb24gZm9yIHNlYXJjaGluZyBmb3IgcG90ZW50aWFsIFBDUiBwcmltZXJzCgpUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIHVzZXMgdGhlIHBvc2l0aW9uYWwgZGF0YSB0byBsb29rIGZvciBzZXF1ZW50aWFsCm1pc21hdGNoZXMgYXNzb2NpYXRlZCB3aXRoIHp5bW9kZW1lIGluIHRoZSBob3BlcyB0aGF0IHRoZXJlIHdpbGwgYmUKc29tZSByZWdpb25zIHdoaWNoIHdvdWxkIHByb3ZpZGUgZ29vZCBwb3RlbnRpYWwgdGFyZ2V0cyBmb3IgYQpQQ1ItYmFzZWQgYXNzYXkuCgpgYGB7ciBzZXF1ZW50aWFsX3NlYXJjaCwgZXZhbD1GQUxTRX0Kc2VxdWVudGlhbF92YXJpYW50cyA8LSBmdW5jdGlvbihzbnBfc2V0cywgY29uZGl0aW9ucyA9IE5VTEwsIG1pbmltdW0gPSAzLCBtYXhpbXVtX3NlcGFyYXRpb24gPSAzKSB7CiAgaWYgKGlzLm51bGwoY29uZGl0aW9ucykpIHsKICAgIGNvbmRpdGlvbnMgPC0gMQogIH0KICBpbnRlcnNlY3Rpb25fc2V0cyA8LSBzbnBfc2V0c1tbImludGVyc2VjdGlvbnMiXV0KICBpbnRlcnNlY3Rpb25fbmFtZXMgPC0gc25wX3NldHNbWyJzZXRfbmFtZXMiXV0KICBjaG9zZW5faW50ZXJzZWN0aW9uIDwtIDEKICBpZiAoaXMubnVtZXJpYyhjb25kaXRpb25zKSkgewogICAgY2hvc2VuX2ludGVyc2VjdGlvbiA8LSBjb25kaXRpb25zCiAgfSBlbHNlIHsKICAgIGludGVyc2VjdGlvbl9pZHggPC0gaW50ZXJzZWN0aW9uX25hbWVzID09IGNvbmRpdGlvbnMKICAgIGNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gbmFtZXMoaW50ZXJzZWN0aW9uX25hbWVzKVtpbnRlcnNlY3Rpb25faWR4XQogIH0KCiAgcG9zc2libGVfcG9zaXRpb25zIDwtIGludGVyc2VjdGlvbl9zZXRzW1tjaG9zZW5faW50ZXJzZWN0aW9uXV0KICBwb3NpdGlvbl90YWJsZSA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHBvc3NpYmxlX3Bvc2l0aW9ucykKICBwYXQgPC0gIl5jaHJfKC4rKV9wb3NfKC4rKV9yZWZfLiokIgogIHBvc2l0aW9uX3RhYmxlW1siY2hyIl1dIDwtIGdzdWIocGF0dGVybiA9IHBhdCwgcmVwbGFjZW1lbnQgPSAiXFwxIiwgeCA9IHJvd25hbWVzKHBvc2l0aW9uX3RhYmxlKSkKICBwb3NpdGlvbl90YWJsZVtbInBvcyJdXSA8LSBhcy5udW1lcmljKGdzdWIocGF0dGVybiA9IHBhdCwgcmVwbGFjZW1lbnQgPSAiXFwyIiwgeCA9IHJvd25hbWVzKHBvc2l0aW9uX3RhYmxlKSkpCiAgcG9zaXRpb25faWR4IDwtIG9yZGVyKHBvc2l0aW9uX3RhYmxlWywgImNociJdLCBwb3NpdGlvbl90YWJsZVssICJwb3MiXSkKICBwb3NpdGlvbl90YWJsZSA8LSBwb3NpdGlvbl90YWJsZVtwb3NpdGlvbl9pZHgsIF0KICBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPC0gMAoKICBsYXN0X2NociA8LSAiIgogIGZvciAociBpbiAxOm5yb3cocG9zaXRpb25fdGFibGUpKSB7CiAgICB0aGlzX2NociA8LSBwb3NpdGlvbl90YWJsZVtyLCAiY2hyIl0KICAgIGlmIChyID09IDEpIHsKICAgICAgcG9zaXRpb25fdGFibGVbciwgImRpc3QiXSA8LSBwb3NpdGlvbl90YWJsZVtyLCAicG9zIl0KICAgICAgbGFzdF9jaHIgPC0gdGhpc19jaHIKICAgICAgbmV4dAogICAgfQogICAgaWYgKHRoaXNfY2hyID09IGxhc3RfY2hyKSB7CiAgICAgIHBvc2l0aW9uX3RhYmxlW3IsICJkaXN0Il0gPC0gcG9zaXRpb25fdGFibGVbciwgInBvcyJdIC0gcG9zaXRpb25fdGFibGVbciAtIDEsICJwb3MiXQogICAgfSBlbHNlIHsKICAgICAgcG9zaXRpb25fdGFibGVbciwgImRpc3QiXSA8LSBwb3NpdGlvbl90YWJsZVtyLCAicG9zIl0KICAgIH0KICAgIGxhc3RfY2hyIDwtIHRoaXNfY2hyCiAgfQoKICAjIyBXb3JraW5nIGludGVyYWN0aXZlbHkgaGVyZS4KCiAgZG91YmxlcyA8LSBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPT0gMQogIGRvdWJsZXMgPC0gcG9zaXRpb25fdGFibGVbZG91YmxlcywgXQogIHdyaXRlLmNzdihkb3VibGVzLCAiZG91Ymxlcy5jc3YiKQoKICBvbmVfYXdheSA8LSBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPT0gMgogIG9uZV9hd2F5IDwtIHBvc2l0aW9uX3RhYmxlW29uZV9hd2F5LCBdCiAgd3JpdGUuY3N2KG9uZV9hd2F5LCAib25lX2F3YXkuY3N2IikKCiAgdHdvX2F3YXkgPC0gcG9zaXRpb25fdGFibGVbWyJkaXN0Il1dID09IDMKICB0d29fYXdheSA8LSBwb3NpdGlvbl90YWJsZVt0d29fYXdheSwgXQogIHdyaXRlLmNzdih0d29fYXdheSwgInR3b19hd2F5LmNzdiIpCgogIGNvbWJpbmVkIDwtIHJiaW5kKGRvdWJsZXMsIG9uZV9hd2F5KQogIGNvbWJpbmVkIDwtIHJiaW5kKGNvbWJpbmVkLCB0d29fYXdheSkKICBwb3NpdGlvbl9pZHggPC0gb3JkZXIoY29tYmluZWRbLCAiY2hyIl0sIGNvbWJpbmVkWywgInBvcyJdKQogIGNvbWJpbmVkIDwtIGNvbWJpbmVkW3Bvc2l0aW9uX2lkeCwgXQoKICB0aGlzX2NociA8LSAiIgogIGZvciAociBpbiAxOm5yb3coY29tYmluZWQpKSB7CiAgICB0aGlzX2NociA8LSBjb21iaW5lZFtyLCAiY2hyIl0KICAgIGlmIChyID09IDEpIHsKICAgICAgY29tYmluZWRbciwgImRpc3RfcGFpciJdIDwtIGNvbWJpbmVkW3IsICJwb3MiXQogICAgICBsYXN0X2NociA8LSB0aGlzX2NocgogICAgICBuZXh0CiAgICB9CiAgICBpZiAodGhpc19jaHIgPT0gbGFzdF9jaHIpIHsKICAgICAgY29tYmluZWRbciwgImRpc3RfcGFpciJdIDwtIGNvbWJpbmVkW3IsICJwb3MiXSAtIGNvbWJpbmVkW3IgLSAxLCAicG9zIl0KICAgIH0gZWxzZSB7CiAgICAgIGNvbWJpbmVkW3IsICJkaXN0X3BhaXIiXSA8LSBjb21iaW5lZFtyLCAicG9zIl0KICAgIH0KICAgIGxhc3RfY2hyIDwtIHRoaXNfY2hyCiAgfQoKICBkaXN0X3BhaXJfbWF4aW11bSA8LSAxMDAwCiAgZGlzdF9wYWlyX21pbmltdW0gPC0gMjAwCiAgZGlzdF9wYWlyX2lkeCA8LSBjb21iaW5lZFtbImRpc3RfcGFpciJdXSA8PSBkaXN0X3BhaXJfbWF4aW11bSAmCiAgICBjb21iaW5lZFtbImRpc3RfcGFpciJdXSA+PSBkaXN0X3BhaXJfbWluaW11bQogIHJlbWFpbmluZyA8LSBjb21iaW5lZFtkaXN0X3BhaXJfaWR4LCBdCiAgbm9fd2Vha19pZHggPC0gZ3JlcGwocGF0dGVybiA9ICJyZWZfKEd8QykiLCB4ID0gcm93bmFtZXMocmVtYWluaW5nKSkKICByZW1haW5pbmcgPC0gcmVtYWluaW5nW25vX3dlYWtfaWR4LCBdCgogIHByaW50KGhlYWQodGFibGUocG9zaXRpb25fdGFibGVbWyJkaXN0Il1dKSkpCiAgc2VxdWVudGlhbHMgPC0gcG9zaXRpb25fdGFibGVbWyJkaXN0Il1dIDw9IG1heGltdW1fc2VwYXJhdGlvbgogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBzdW0oc2VxdWVudGlhbHMpLCAiIGNhbmRpZGF0ZSByZWdpb25zLiIpCgogICMjIFRoZSBmb2xsb3dpbmcgY2FuIHRlbGwgbWUgaG93IG1hbnkgcnVucyBvZiBlYWNoIGxlbmd0aCBvY2N1cnJlZCwgdGhhdCBpcyBub3QgcXVpdGUgd2hhdCBJIHdhbnQuCiAgIyMgTm93IHVzZSBydW4gbGVuZ3RoIGVuY29kaW5nIHRvIGZpbmQgdGhlIHNldCBvZiBzZXF1ZW50aWFsIHNlcXVlbnRpYWxzIQogIHJsZV9yZXN1bHQgPC0gcmxlKHNlcXVlbnRpYWxzKQogIHJsZV92YWx1ZXMgPC0gcmxlX3Jlc3VsdFtbInZhbHVlcyJdXQogICMjIFRoZSBmb2xsb3dpbmcgbGluZSBpcyBlcXVpdmFsZW50IHRvIGp1c3QgbGVhdmluZyB2YWx1ZXMgYWxvbmU6CiAgIyMgdHJ1ZV92YWx1ZXMgPC0gcmxlX3Jlc3VsdFtbInZhbHVlcyJdXSA9PSBUUlVFCiAgcmxlX2xlbmd0aHMgPC0gcmxlX3Jlc3VsdFtbImxlbmd0aHMiXV0KICB0cnVlX3NlcXVlbnRpYWxzIDwtIHJsZV9sZW5ndGhzW3JsZV92YWx1ZXNdCiAgcmxlX2lkeCA8LSBjdW1zdW0ocmxlX2xlbmd0aHMpW3doaWNoKHJsZV92YWx1ZXMpXQoKICBwb3NpdGlvbl90YWJsZVtbImxhc3Rfc2VxdWVudGlhbCJdXSA8LSAwCiAgY291bnQgPC0gMAogIGZvciAociBpbiBybGVfaWR4KSB7CiAgICBjb3VudCA8LSBjb3VudCArIDEKICAgIHBvc2l0aW9uX3RhYmxlW3IsICJsYXN0X3NlcXVlbnRpYWwiXSA8LSB0cnVlX3NlcXVlbnRpYWxzW2NvdW50XQogIH0KICBtZXNzYWdlKCJUaGUgbWF4aW11bSBzZXF1ZW50aWFsIHNldCBpczogIiwgbWF4KHBvc2l0aW9uX3RhYmxlW1sibGFzdF9zZXF1ZW50aWFsIl1dKSwgIi4iKQoKICB3YW50ZWRfaWR4IDwtIHBvc2l0aW9uX3RhYmxlW1sibGFzdF9zZXF1ZW50aWFsIl1dID49IG1pbmltdW0KICB3YW50ZWQgPC0gcG9zaXRpb25fdGFibGVbd2FudGVkX2lkeCwgYygiY2hyIiwgInBvcyIpXQogIHJldHVybih3YW50ZWQpCn0KCnp5bW8yMl9zZXF1ZW50aWFscyA8LSBzZXF1ZW50aWFsX3ZhcmlhbnRzKG5ld19zZXRzLCBjb25kaXRpb25zID0gInoyMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW0gPSAxLCBtYXhpbXVtX3NlcGFyYXRpb24gPSAyKQpkaW0oenltbzIyX3NlcXVlbnRpYWxzKQojIyA3IGNhbmRpZGF0ZSByZWdpb25zIGZvciB6eW1vZGVtZSAyLjIgLS0gdGh1cyBJIGFtIGJldHRpbmcgdGhhdCB0aGUgcmVmZXJlbmNlIHN0cmFpbiBpcyBhIDIuMgp6eW1vMjNfc2VxdWVudGlhbHMgPC0gc2VxdWVudGlhbF92YXJpYW50cyhuZXdfc2V0cywgY29uZGl0aW9ucyA9ICJ6MjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtID0gMiwgbWF4aW11bV9zZXBhcmF0aW9uID0gMikKZGltKHp5bW8yM19zZXF1ZW50aWFscykKIyMgSW4gY29udHJhc3QsIHRoZXJlIGFyZSBsb3RzICg1ODcpIG9mIGludGVyZXN0aW5nIHJlZ2lvbnMgZm9yIDIuMyEKYGBgCgojIyMgRXh0cmFjdCBhIHByb21pc2luZyByZWdpb24gZnJvbSB0aGUgZ2Vub21lCgpUaGUgZmlyc3QgNCBjYW5kaWRhdGUgcmVnaW9ucyBmcm9tIG15IHNldCBvZiByZW1haW5pbmc6CiogQ2hyICAgICAgIFBvcy4gICBEaXN0YW5jZQoqIExwYUwxMy0xNSAyMzg0MzMgNDQ4CiogTHBhTDEzLTE4IDE0Mjg0NCA2MTMKKiBMcGFMMTMtMjkgODMwMzQyIDI1MgoqIExwYUwxMy0zMyAxMzMxNTA3IDg0MwoKTGV0cyBkZWZpbmUgYSBjb3VwbGUgb2YgdGVybXM6CiogVGhpcmQ6IEVhY2ggb2YgdGhlIDQgYWJvdmUgcG9zaXRpb25zLgoqIFNlY29uZDogVGhpcmQgLSBEaXN0YW5jZQoqIEVuZDogVGhpcmQgKyBQcmltZXJMZW4KKiBTdGFydDogU2Vjb25kIC0gUHJpbWVybGVuCgpJbiBlYWNoIGluc3RhbmNlLCB0aGVzZSBhcmUgdGhlIGxhc3QgcG9zaXRpb25zLCBzbyB3ZSB3YW50IHRvIGdyYWIgdGhyZWUgdGhpbmdzOgoKKiBUaGUgZW50aXJlIHJlZ2lvbiBmcm9tIEVuZCAtPiBTdGFydCwgdGhpcyB3YXkgd2UgY2FuIGhhdmUgYSBxdWljayBzYW5pdHkgY2hlY2suCiogU3RhcnQgLT4gU2Vjb25kLgoqIChUaGlyZCAtPiBFbmQpIDwtIFJldmVyc2UgY29tcGxlbWVudGVkCgpgYGB7ciBleHRyYWN0X2JzZ2Vub21lLCBldmFsPUZBTFNFfQojIyAqIExwYUwxMy0xNSAyMzg0MzMgNDQ4CmZpcnN0X2NhbmRpZGF0ZV9jaHIgPC0gbHBfZ2Vub21lW1siTHBhTDEzXzE1Il1dCnByaW1lcl9sZW5ndGggPC0gMjIKYW1wbGljb25fbGVuZ3RoIDwtIDQ0OApmaXJzdF9jYW5kaWRhdGVfdGhpcmQgPC0gMjM4NDMzCmZpcnN0X2NhbmRpZGF0ZV9zZWNvbmQgPC0gZmlyc3RfY2FuZGlkYXRlX3RoaXJkIC0gYW1wbGljb25fbGVuZ3RoCmZpcnN0X2NhbmRpZGF0ZV9zdGFydCA8LSBmaXJzdF9jYW5kaWRhdGVfc2Vjb25kIC0gcHJpbWVyX2xlbmd0aApmaXJzdF9jYW5kaWRhdGVfZW5kIDwtIGZpcnN0X2NhbmRpZGF0ZV90aGlyZCArIHByaW1lcl9sZW5ndGgKZmlyc3RfY2FuZGlkYXRlX3JlZ2lvbiA8LSBzdWJzZXEoZmlyc3RfY2FuZGlkYXRlX2NociwgZmlyc3RfY2FuZGlkYXRlX3N0YXJ0LCBmaXJzdF9jYW5kaWRhdGVfZW5kKQpmaXJzdF9jYW5kaWRhdGVfcmVnaW9uCmZpcnN0X2NhbmRpZGF0ZV81cCA8LSBzdWJzZXEoZmlyc3RfY2FuZGlkYXRlX2NociwgZmlyc3RfY2FuZGlkYXRlX3N0YXJ0LCBmaXJzdF9jYW5kaWRhdGVfc2Vjb25kKQphcy5jaGFyYWN0ZXIoZmlyc3RfY2FuZGlkYXRlXzVwKQpmaXJzdF9jYW5kaWRhdGVfM3AgPC0gc3Bnczo6cmV2ZXJzZUNvbXBsZW1lbnQoc3Vic2VxKGZpcnN0X2NhbmRpZGF0ZV9jaHIsIGZpcnN0X2NhbmRpZGF0ZV90aGlyZCwgZmlyc3RfY2FuZGlkYXRlX2VuZCkpCmZpcnN0X2NhbmRpZGF0ZV8zcAoKIyMgKiBMcGFMMTMtMTggMTQyODQ0IDYxMwpzZWNvbmRfY2FuZGlkYXRlX2NociA8LSBscF9nZW5vbWVbWyJMcGFMMTNfMTgiXV0KcHJpbWVyX2xlbmd0aCA8LSAyMgphbXBsaWNvbl9sZW5ndGggPC0gNjEzCnNlY29uZF9jYW5kaWRhdGVfdGhpcmQgPC0gMTQyODQ0CnNlY29uZF9jYW5kaWRhdGVfc2Vjb25kIDwtIHNlY29uZF9jYW5kaWRhdGVfdGhpcmQgLSBhbXBsaWNvbl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9zdGFydCA8LSBzZWNvbmRfY2FuZGlkYXRlX3NlY29uZCAtIHByaW1lcl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9lbmQgPC0gc2Vjb25kX2NhbmRpZGF0ZV90aGlyZCArIHByaW1lcl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9yZWdpb24gPC0gc3Vic2VxKHNlY29uZF9jYW5kaWRhdGVfY2hyLCBzZWNvbmRfY2FuZGlkYXRlX3N0YXJ0LCBzZWNvbmRfY2FuZGlkYXRlX2VuZCkKc2Vjb25kX2NhbmRpZGF0ZV9yZWdpb24Kc2Vjb25kX2NhbmRpZGF0ZV81cCA8LSBzdWJzZXEoc2Vjb25kX2NhbmRpZGF0ZV9jaHIsIHNlY29uZF9jYW5kaWRhdGVfc3RhcnQsIHNlY29uZF9jYW5kaWRhdGVfc2Vjb25kKQphcy5jaGFyYWN0ZXIoc2Vjb25kX2NhbmRpZGF0ZV81cCkKc2Vjb25kX2NhbmRpZGF0ZV8zcCA8LSBzcGdzOjpyZXZlcnNlQ29tcGxlbWVudChzdWJzZXEoc2Vjb25kX2NhbmRpZGF0ZV9jaHIsIHNlY29uZF9jYW5kaWRhdGVfdGhpcmQsIHNlY29uZF9jYW5kaWRhdGVfZW5kKSkKc2Vjb25kX2NhbmRpZGF0ZV8zcAoKCiMjICogTHBhTDEzLTI5IDgzMDM0MiAyNTIKdGhpcmRfY2FuZGlkYXRlX2NociA8LSBscF9nZW5vbWVbWyJMcGFMMTNfMjkiXV0KcHJpbWVyX2xlbmd0aCA8LSAyMgphbXBsaWNvbl9sZW5ndGggPC0gMjUyCnRoaXJkX2NhbmRpZGF0ZV90aGlyZCA8LSA4MzAzNDIKdGhpcmRfY2FuZGlkYXRlX3NlY29uZCA8LSB0aGlyZF9jYW5kaWRhdGVfdGhpcmQgLSBhbXBsaWNvbl9sZW5ndGgKdGhpcmRfY2FuZGlkYXRlX3N0YXJ0IDwtIHRoaXJkX2NhbmRpZGF0ZV9zZWNvbmQgLSBwcmltZXJfbGVuZ3RoCnRoaXJkX2NhbmRpZGF0ZV9lbmQgPC0gdGhpcmRfY2FuZGlkYXRlX3RoaXJkICsgcHJpbWVyX2xlbmd0aAp0aGlyZF9jYW5kaWRhdGVfcmVnaW9uIDwtIHN1YnNlcSh0aGlyZF9jYW5kaWRhdGVfY2hyLCB0aGlyZF9jYW5kaWRhdGVfc3RhcnQsIHRoaXJkX2NhbmRpZGF0ZV9lbmQpCnRoaXJkX2NhbmRpZGF0ZV9yZWdpb24KdGhpcmRfY2FuZGlkYXRlXzVwIDwtIHN1YnNlcSh0aGlyZF9jYW5kaWRhdGVfY2hyLCB0aGlyZF9jYW5kaWRhdGVfc3RhcnQsIHRoaXJkX2NhbmRpZGF0ZV9zZWNvbmQpCmFzLmNoYXJhY3Rlcih0aGlyZF9jYW5kaWRhdGVfNXApCnRoaXJkX2NhbmRpZGF0ZV8zcCA8LSBzcGdzOjpyZXZlcnNlQ29tcGxlbWVudChzdWJzZXEodGhpcmRfY2FuZGlkYXRlX2NociwgdGhpcmRfY2FuZGlkYXRlX3RoaXJkLCB0aGlyZF9jYW5kaWRhdGVfZW5kKSkKdGhpcmRfY2FuZGlkYXRlXzNwCiMjIFlvdSBhcmUgYSBnYXJiYWdlIHBvbHlweXJpbWlkaW5lIHRyYWN0LgojIyBXaGljaCBpcyBhY3R1YWxseSBpbnRlcmVzdGluZyBpZiB0aGUgbXV0YXRpb25zIG1lc3MgaXQgdXAuCgoKIyMgKiBMcGFMMTMtMzMgMTMzMTUwNyA4NDMKZm91cnRoX2NhbmRpZGF0ZV9jaHIgPC0gbHBfZ2Vub21lW1siTHBhTDEzXzMzIl1dCnByaW1lcl9sZW5ndGggPC0gMjIKYW1wbGljb25fbGVuZ3RoIDwtIDg0Mwpmb3VydGhfY2FuZGlkYXRlX3RoaXJkIDwtIDEzMzE1MDcKZm91cnRoX2NhbmRpZGF0ZV9zZWNvbmQgPC0gZm91cnRoX2NhbmRpZGF0ZV90aGlyZCAtIGFtcGxpY29uX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX3N0YXJ0IDwtIGZvdXJ0aF9jYW5kaWRhdGVfc2Vjb25kIC0gcHJpbWVyX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX2VuZCA8LSBmb3VydGhfY2FuZGlkYXRlX3RoaXJkICsgcHJpbWVyX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX3JlZ2lvbiA8LSBzdWJzZXEoZm91cnRoX2NhbmRpZGF0ZV9jaHIsIGZvdXJ0aF9jYW5kaWRhdGVfc3RhcnQsIGZvdXJ0aF9jYW5kaWRhdGVfZW5kKQpmb3VydGhfY2FuZGlkYXRlX3JlZ2lvbgpmb3VydGhfY2FuZGlkYXRlXzVwIDwtIHN1YnNlcShmb3VydGhfY2FuZGlkYXRlX2NociwgZm91cnRoX2NhbmRpZGF0ZV9zdGFydCwgZm91cnRoX2NhbmRpZGF0ZV9zZWNvbmQpCmFzLmNoYXJhY3Rlcihmb3VydGhfY2FuZGlkYXRlXzVwKQpmb3VydGhfY2FuZGlkYXRlXzNwIDwtIHNwZ3M6OnJldmVyc2VDb21wbGVtZW50KHN1YnNlcShmb3VydGhfY2FuZGlkYXRlX2NociwgZm91cnRoX2NhbmRpZGF0ZV90aGlyZCwgZm91cnRoX2NhbmRpZGF0ZV9lbmQpKQpmb3VydGhfY2FuZGlkYXRlXzNwCmBgYAoKIyMgR28gaHVudGluZyBmb3IgU2FuZ2VyIHNlcXVlbmNpbmcgcmVnaW9ucwoKSSBtYWRlIGEgZnVuIGxpdHRsZSBmdW5jdGlvbiB3aGljaCBzaG91bGQgZmluZCByZWdpb25zIHdoaWNoIGhhdmUgbG90cyBvZiB2YXJpYW50cwphc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBleHBlcmltZW50YWwgZmFjdG9yLgoKYGBge3J9CnBoZW5vIDwtIHN1YnNldF9leHB0KGxwX2V4cHQsIHN1YnNldCA9ICJjb25kaXRpb249PSd6Mi4yJ3xjb25kaXRpb249PSd6Mi4zJyIpCnBoZW5vIDwtIHN1YnNldF9leHB0KHBoZW5vLCBzdWJzZXQgPSAiIWlzLm5hKHBEYXRhKHBoZW5vKVtbJ2JjZnRhYmxlJ11dKSIpCnBoZW5vX3NucHMgPC0gY291bnRfZXhwdF9zbnBzKHBoZW5vLCBhbm5vdF9jb2x1bW4gPSAiZnJlZWJheWVzc3VtbWFyeSIsIHNucF9jb2x1bW49IlBBSVJFRCIpCiMjcGhlbm9fc25wcyA8LSBzbShjb3VudF9leHB0X3NucHMocGhlbm8sIGFubm90X2NvbHVtbiA9ICJiY2Z0YWJsZSIpKQpgYGAKCiMjIFNOUCBEZW5zaXR5IFByaW1lcnMKCkkgY2Fubm90IHJ1biB0aGUgZm9sbG93aW5nIGJsb2NrIGluIHRoZSBjb250YWluZXIgdW5sZXNzL3VudGlsIEkgY29weQp0aGUgZ2ZmIGludG8gaXQuLi4KCmBgYHtyLCBldmFsPUZBTFNFfQpmdW5fc3R1ZmYgPC0gc25wX2RlbnNpdHlfcHJpbWVycygKICBwaGVub19zbnBzLAogIGJzZ2Vub21lID0gIkJTR2Vub21lLkxlaXNobWFuaWEucGFuYW1lbnNpcy5NSE9NQ09MODFMMTMudjUzIiwKICBnZmYgPSAicmVmZXJlbmNlL1RyaVRyeXBEQi01M19McGFuYW1lbnNpc01IT01DT0w4MUwxMy5nZmYiKQpkcm9wX3NjYWZmb2xkcyA8LSBncmVwbCh4ID0gcm93bmFtZXMoZnVuX3N0dWZmJGZhdm9yaXRlcyksIHBhdHRlcm4gPSAiU0NBRiIpCmZhdm9yaXRlX3ByaW1lcl9yZWdpb25zIDwtIGZ1bl9zdHVmZltbImZhdm9yaXRlcyJdXVshZHJvcF9zY2FmZm9sZHMsIF0KZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnNbWyJiaW4iXV0gPC0gcm93bmFtZXMoZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnMpCgpmYXZvcml0ZV9wcmltZXJfcmVnaW9ucyA8LSBmYXZvcml0ZV9wcmltZXJfcmVnaW9ucyAlPiUKICByZWxvY2F0ZShiaW4pCmBgYAoKIyMgQ29tYmluZSB0aGlzIHRhYmxlIHdpdGggMi4yLzIuMyBnZW5lcwoKSGVyZSBpcyBteSBub3RlIGZyb20gb3VyIG1lZXRpbmc6CgpDcm9zcyByZWZlcmVuY2UgcHJpbWVycyB0byBERSBnZW5lcyBvZiAyLjIvMi4zIGFuZC9vciByZXNpc3RhbmNlL3N1c2NwZXRpYmxlLAphZGQgYSBjb2x1bW4gdG8gdGhlIHByaW1lciBzcHJlYWRzaGVldCB3aXRoIHRoZSBERSBnZW5lcyAoaW4gcmV0cm9zcGVjdCBJIGFtIGd1ZXNzaW5nCnRoaXMgYWN0dWFsbHkgbWVhbnMgdG8gcHV0IHRoZSBsb2dGQyBhcyBhIGNvbHVtbi4KCk9uZSBuaWNlIHRoaW5nLCBJIGRpZCBhIHNlbWFudGljIHJlbW92YWwgb24gdGhlIGxwX2V4cHQsIHNvIHRoZSBzZXQgb2YgbG9nRkMvcHZhbHVlcwpzaG91bGQgbm90IGhhdmUgYW55IG9mIHRoZSBvZmZlbmRpbmcgdHlwZXM7IHRodXMgSSBzaG91bGQgYmUgYWJsZSB0byBhdXRvbWFnaWNhbGx5CmdldCByaWQgb2YgdGhlbSBpbiB0aGUgbWVyZ2UuCgpUaGlzIGJsb2NrIG5lZWRzIHRvIGdvIGFmdGVyIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2VzLgoKYGBge3IsIGV2YWw9RkFMU0V9CmxvZ2ZjIDwtIHp5X3RhYmxlX3N2YVtbImRhdGEiXV1bWyJ6MjNfdnNfejIyIl1dCmxvZ2ZjX2NvbHVtbnMgPC0gbG9nZmNbLCBjKCJkZXNlcV9sb2dmYyIsICJkZXNlcV9hZGpwIildCmNvbG5hbWVzKGxvZ2ZjX2NvbHVtbnMpIDwtIGMoInoyM19sb2dmYyIsICJ6MjNfYWRqcCIpCm5ld190YWJsZSA8LSBtZXJnZShmYXZvcml0ZV9wcmltZXJfcmVnaW9ucywgbG9nZmNfY29sdW1ucywKICAgICAgICAgICAgICAgICAgIGJ5LnggPSAiY2xvc2VzdF9nZW5lX2JlZm9yZV9pZCIsIGJ5LnkgPSAicm93Lm5hbWVzIikKc3VzIDwtIHN1c190YWJsZV9zdmFbWyJkYXRhIl1dW1sic2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCJdXQpzdXNfY29sdW1ucyA8LSBzdXNbLCBjKCJkZXNlcV9sb2dmYyIsICJkZXNlcV9hZGpwIildCmNvbG5hbWVzKHN1c19jb2x1bW5zKSA8LSBjKCJzdXNfbG9nZmMiLCAic3VzX2FkanAiKQpuZXdfdGFibGUgPC0gbWVyZ2UobmV3X3RhYmxlLCBzdXNfY29sdW1ucywKICAgICAgICAgICAgICAgICAgIGJ5LnggPSAiY2xvc2VzdF9nZW5lX2JlZm9yZV9pZCIsIGJ5LnkgPSAicm93Lm5hbWVzIikgJT4lCiAgcmVsb2NhdGUoYmluKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG5ld190YWJsZSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gImV4Y2VsL2Zhdm9yaXRlX3ByaW1lcnNfeHJlZl96eV9zdXMueGxzeCIpCmBgYAoKCiMjIE1ha2UgYSBoZWF0bWFwIGRlc2NyaWJpbmcgdGhlIGNsdXN0ZXJpbmcgb2YgdmFyaWFudHMKCldlIGNhbiBjcm9zcyByZWZlcmVuY2UgdGhlIHZhcmlhbnRzIGFnYWluc3QgdGhlIHp5bW9kZW1lIHN0YXR1cyBhbmQKcGxvdCBhIGhlYXRtYXAgb2YgdGhlIHJlc3VsdHMgYW5kIGhvcGVmdWxseSBzZWUgaG93IHRoZXkgc2VwYXJhdGUuCgpgYGB7cn0Kc25wX2dlbmVzIDwtIHNtKHNucHNfdnNfZ2VuZXMobHBfZXhwdCwgbmV3X3NldHMsIGV4cHRfbmFtZV9jb2wgPSAiY2hyb21vc29tZSIpKQoKY2xpbmljYWxfY29sb3JzX3YyIDwtIGxpc3QoCiAgInoyMiIgPSAiIzAwMDBjYyIsCiAgInoyMyIgPSAiI2NjMDAwMCIpCm5ld196eW1vX25vcm0gPC0gbm9ybWFsaXplX2V4cHQocHJ1bmVkX3NucHMsIG5vcm0gPSAicXVhbnQiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAienltb2RlbWVjYXRlZ29yaWNhbCIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjbGluaWNhbF9jb2xvcnNfdjIpCgp6eW1vX2hlYXQgPC0gcGxvdF9kaXNoZWF0KG5ld196eW1vX25vcm0pCmRldiA8LSBwcChmaWxlID0gImltYWdlcy9vbmx5ejIyX3oyM19zbnBfaGVhdG1hcC5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKenltb19oZWF0W1sicGxvdCJdXQpjbG9zZWQgPC0gZGV2Lm9mZigpCnp5bW9faGVhdApgYGAKCiMjIyBBbm5vdGF0ZWQgaGVhdG1hcCBvZiB2YXJpYW50cwoKTm93IGxldCB1cyB0cnkgdG8gbWFrZSBhIGhlYXRtYXAgd2hpY2ggaW5jbHVkZXMgc29tZSBvZiB0aGUgYW5ub3RhdGlvbiBkYXRhLgoKYGBge3J9CmRlcyA8LSBwRGF0YShib3RoX25vcm0pCnVuZGVmX2lkeCA8LSBpcy5uYShkZXNbWyJwYXRob2dlbnN0cmFpbiJdXSkKZGVzW3VuZGVmX2lkeCwgInBhdGhvZ2Vuc3RyYWluIl0gPC0gInVua25vd24iCgojI2htY29scyA8LSBjb2xvclJhbXBQYWxldHRlKGMoInllbGxvdyIsImJsYWNrIiwiZGFya2JsdWUiKSkoMjU2KQpjb3JyZWxhdGlvbnMgPC0gaHBnbF9jb3IoZXhwcnMoYm90aF9ub3JtKSkKbmFfaWR4IDwtIGlzLm5hKGNvcnJlbGF0aW9ucykKY29ycmVsYXRpb25zW25hX2lkeF0gPC0gMAoKIyMgTWFrZSBhbiBpbml0aWFsIGhlYXRtYXAgdmlhIHBsb3RfZGlzaGVhdCwgd2hpY2ggbWF5IGdldCB1c2VkIGFzIHRoZSBmaWd1cmU6CmluaXRpYWxfc25wcyA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGJvdGhfbm9ybSwgZmFjdCA9ICJ6eW1vZGVtZXJlZmVyZW5jZSIsIGNvbG9ycyA9IGNvbG9yX2Nob2ljZXNbWyJzdHJhaW4iXV0pCmluaXRpYWxfZGlzaGVhdCA8LSBwbG90X2Rpc2hlYXQoYm90aF9ub3JtKQpkZXYgPC0gcHAoZmlsZSA9ICJmaWd1cmVzL2luaXRpYWxfc25wX2hlYXRtYXAucGRmIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMjApCmluaXRpYWxfZGlzaGVhdFtbInBsb3QiXV0KY2xvc2VkIDwtIGRldi5vZmYoKQp6eW1vX2hlYXQKCnp5bW9fbWlzc2luZ19pZHggPC0gaXMubmEoZGVzW1sienltb2RlbWVjYXRlZ29yaWNhbCJdXSkKZGVzW1sienltb2RlbWVjYXRlZ29yaWNhbCJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1sienltb2RlbWVjYXRlZ29yaWNhbCJdXSkKZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSkKZGVzW3p5bW9fbWlzc2luZ19pZHgsICJ6eW1vZGVtZWNhdGVnb3JpY2FsIl0gPC0gInVua25vd24iCm15ZGVuZHJvIDwtIGxpc3QoCiAgImNsdXN0ZnVuIiA9IGhjbHVzdCwKICAibHdkIiA9IDIuMCkKY29sX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShkZXNbLCBjKCJ6eW1vZGVtZWNhdGVnb3JpY2FsIildKQp1bmtub3duX2NsaW5pY2FsIDwtIGlzLm5hKGRlc1tbImNsaW5pY2FsY2F0ZWdvcmljYWwiXV0pCmNvbG5hbWVzKGNvbF9kYXRhKSA8LSBjKCJ6eW1vZGVtZSIpCgpyb3dfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKGRlc1ssIGMoInN1c19jYXRlZ29yeV9jdXJyZW50IiwgImNsaW5pY2FsY2F0ZWdvcmljYWwiKV0pCmNvbG5hbWVzKHJvd19kYXRhKSA8LSBjKCJzdXNjZXB0aWJpbGl0eSIsICJvdXRjb21lIikKcm93X2RhdGFbdW5rbm93bl9jbGluaWNhbCwgIm91dGNvbWUiXSA8LSAidW5kZWZpbmVkIgoKbXlhbm5vdCA8LSBsaXN0KAogICJDb2wiID0gbGlzdCgiZGF0YSIgPSBjb2xfZGF0YSksCiAgIlJvdyIgPSBsaXN0KCJkYXRhIiA9IHJvd19kYXRhKSkKbXljbHVzdCA8LSBsaXN0KCJjdXRoIiA9IDEuMCwKICAgICAgICAgICAgICAgICJjb2wiID0gQnJld2VyQ2x1c3RlckNvbCkKbXlsYWJzIDwtIGxpc3QoCiAgIlJvdyIgPSBsaXN0KCJucm93IiA9IDQpLAogICJDb2wiID0gbGlzdCgibnJvdyIgPSA0KSkKaG1jb2xzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiZGFya2JsdWUiLCAiYmVpZ2UiKSkoMjQwKQp6eW1vX2Fubm90X2hlYXQgPC0gYW5uSGVhdG1hcDIoCiAgY29ycmVsYXRpb25zLAogIGRlbmRyb2dyYW0gPSBteWRlbmRybywKICBhbm5vdGF0aW9uID0gbXlhbm5vdCwKICBjbHVzdGVyID0gbXljbHVzdCwKICBsYWJlbHMgPSBteWxhYnMsCiAgIyMgVGhlIGZvbGxvd2luZyBjb250cm9scyBpZiB0aGUgcGljdHVyZSBpcyBzeW1tZXRyaWMKICBzY2FsZSA9ICJub25lIiwKICBjb2wgPSBobWNvbHMpCgpkZXYgPC0gcHAoZmlsZSA9ICJpbWFnZXMvZGVuZHJvX2hlYXRtYXAucGRmIiwgaGVpZ2h0ID0gMjAsIHdpZHRoID0gMjApCnBsb3Qoenltb19hbm5vdF9oZWF0KQpjbG9zZWQgPC0gZGV2Lm9mZigpCnBsb3Qoenltb19hbm5vdF9oZWF0KQpgYGAKClByaW50IHRoZSBsYXJnZXIgaGVhdG1hcCBzbyB0aGF0IGFsbCB0aGUgbGFiZWxzIGFwcGVhci4gIEtlZXAgaW4gbWluZAp0aGF0IGFzIHdlIGdldCBtb3JlIHNhbXBsZXMsIHRoaXMgaW1hZ2UgbmVlZHMgdG8gY29udGludWUgZ2V0dGluZwpiaWdnZXIuCgojIyMgQ01wbG90IGthcnlvZ3JhbSBvZiB2YXJpYW50cwoKSSBjYW5ub3QgcnVuIHRoZSBmb2xsb3dpbmcgYmxvY2sgdW50aWwvdW5sZXNzIEkgaW5zdGFsbCBjbXBsb3QgaW4gdGhlCmNvbnRhaW5lci4gIE9oLCBJIGRpZCEgIExldCB1cyBydW4gaXQgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCgpgYGB7cn0KeHJlZl9wcm9wIDwtIHRhYmxlKHBoZW5vX3NucHNbWyJjb25kaXRpb25zIl1dKQpwaGVub19zbnBzJGNvbmRpdGlvbnMKaWR4X3RibCA8LSBleHBycyhwaGVub19zbnBzKSA+IDUKbmV3X3RibCA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHJvd25hbWVzKGV4cHJzKHBoZW5vX3NucHMpKSkKZm9yIChuIGluIG5hbWVzKHhyZWZfcHJvcCkpIHsKICBuZXdfdGJsW1tuXV0gPC0gMAogIGlkeF9jb2xzIDwtIHdoaWNoKHBoZW5vX3NucHNbWyJjb25kaXRpb25zIl1dID09IG4pCiAgcHJvcF9jb2wgPC0gcm93U3VtcyhpZHhfdGJsWywgaWR4X2NvbHNdKSAvIHhyZWZfcHJvcFtuXQogIG5ld190Ymxbbl0gPC0gcHJvcF9jb2wKfQprZWVwZXJzIDwtIGdyZXBsKHggPSByb3duYW1lcyhuZXdfdGJsKSwgcGF0dGVybiA9ICJMcGFMMTMiKQpuZXdfdGJsIDwtIG5ld190Ymxba2VlcGVycywgXQpuZXdfdGJsW1sic3Ryb25nMjIiXV0gPC0gMS4wMDEgLSBuZXdfdGJsW1siejIuMiJdXQpuZXdfdGJsW1sic3Ryb25nMjMiXV0gPC0gMS4wMDEgLSBuZXdfdGJsW1siejIuMyJdXQpzMjJfbmEgPC0gbmV3X3RibFtbInN0cm9uZzIyIl1dID4gMQpuZXdfdGJsW3MyMl9uYSwgInN0cm9uZzIyIl0gPC0gMQpzMjNfbmEgPC0gbmV3X3RibFtbInN0cm9uZzIzIl1dID4gMQpuZXdfdGJsW3MyM19uYSwgInN0cm9uZzIzIl0gPC0gMQoKbmV3X3RibFtbIlNOUCJdXSA8LSByb3duYW1lcyhuZXdfdGJsKQpuZXdfdGJsW1siQ2hyb21vc29tZSJdXSA8LSBnc3ViKHggPSBuZXdfdGJsW1siU05QIl1dLCBwYXR0ZXJuID0gImNocl8oLiopX3Bvc18uKiIsIHJlcGxhY2VtZW50ID0gIlxcMSIpCm5ld190YmxbWyJQb3NpdGlvbiJdXSA8LSBnc3ViKHggPSBuZXdfdGJsW1siU05QIl1dLCBwYXR0ZXJuID0gIi4qX3Bvc18oXFxkKylfLioiLCByZXBsYWNlbWVudCA9ICJcXDEiKQpuZXdfdGJsIDwtIG5ld190YmxbLCBjKCJTTlAiLCAiQ2hyb21vc29tZSIsICJQb3NpdGlvbiIsICJzdHJvbmcyMiIsICJzdHJvbmcyMyIpXQoKc2ltcGxpZnkgPC0gbmV3X3RibApzaW1wbGlmeVtbInN0cm9uZzIyIl1dIDwtIE5VTEwKCkNNcGxvdChuZXdfdGJsLCBiaW4uc2l6ZSA9IDEwMDAwLCB0aHJlc2hvbGQgPSBjKDAuMDEsIDAuMDUpLCBwbG90LnR5cGUgPSAiZCIsCiAgICAgICBmaWxlLm5hbWUgPSAidmFyaWFudF9kZW5zaXR5XzEwayIpCkNNcGxvdChuZXdfdGJsLCBiaW4uc2l6ZSA9IDEwMDAsIHRocmVzaG9sZCA9IGMoMC4wMSwgMC4wNSksIHBsb3QudHlwZSA9ICJkIiwKICAgICAgIGZpbGUubmFtZSA9ICJ2YXJpYW50X2RlbnNpdHlfMWsiKQpDTXBsb3QobmV3X3RibCwgYmluLnNpemUgPSAxMDAwMDAsIHRocmVzaG9sZCA9IGMoMC4wMSwgMC4wNSksIHBsb3QudHlwZSA9ICJkIiwKICAgICAgIGZpbGUubmFtZSA9ICJ2YXJpYW50X2RlbnNpdHlfMTAwayIpCgpDTXBsb3QobmV3X3RibCwgcGxvdC50eXBlID0gIm0iLCBtdWx0cmFja3MgPSBUUlVFLCB0aHJlc2hvbGQgPSBjKDAuMDEsIDAuMDUpLAogICAgICAgdGhyZXNob2xkLmx3ZCA9IGMoMSwxKSwgdGhyZXNob2xkLmNvbCA9IGMoImJsYWNrIiwiZ3JleSIpLAogICAgICAgYW1wbGlmeSA9IFRSVUUsIGJpbi5zaXplID0gMTAwMCwKICAgICAgIGNoci5kZW4uY29sID0gYygiZGFya2dyZWVuIiwgInllbGxvdyIsICJyZWQiKSwKICAgICAgIHNpZ25hbC5jb2wgPSBjKCJyZWQiLCAiZ3JlZW4iLCAiYmx1ZSIpLAogICAgICAgc2lnbmFsLmNleCA9IDEsIGZpbGUgPSAianBnIiwgZHBpID0gMzAwLCBmaWxlLm91dHB1dCA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFKQpgYGAKCiFbU05QIERlbnNpdHldKE1hcmtlcl9EZW5zaXR5LnZhcmlhbnRfZGVuc2l0eV8xMGsuanBnKQoKIyBBIGRpZmZlcmVudCBrYXJ5b2dyYW0KCkkgaGF2ZSBiZWVuIGEgYml0IGZydXN0cmF0ZWQgd2l0aCB0aGUgY2x1bmt5bmVzcyBvZiBjbXBsb3QsIHNvIEkgZGlkCnNvbWUgcmVhZGluZyBhbmQgZm91bmQgYXV0b3Bsb3QuICBJdCBtYWtlcyB1c2Ugb2YgZy9pcmFuZ2VzIHRvIHBsb3QKYXJiaXRyYXJ5IGRhdGEgYW5kIGFzIHN1Y2ggaGFzIHRoZSBwb3RlbnRpYWwgdG8gYmUgc2lnbmlmaWNhbnRseSBtb3JlCmdlbmVyYWxseSB1c2VmdWwgdGhhbiBjbXBsb3QuICBJIHRoaW5rIEkgd2lsbCBiZSBhYmxlIHRvIHVzZSBpdCB0bwp2aWV3IGEgbG90IG9mIGludGVyZXN0aW5nIGRpZmZlcmVudCBkYXRhIHR5cGVzLiAgSW4gdGhpcyBpbnN0YW5jZSBJCndhbnQgdG8gcGxvdCBkZW5zaXR5IG9mIHZhcmlhbnRzIGFzc29jaWF0ZWQgd2l0aCB2YXJpb3VzIGNvbmRpdGlvbnMgaW4KdGhlIGRhdGEgKHoyLjMvejIuMiwgY3VyZS9mYWlsLCB3aGF0ZXZlcikuICBJbiBhZGRpdGlvbiwgaXQgbWlnaHQgYmUKbmljZSB0byBoYXZlIHRoZSBPUkZzIGRpc3BsYXllZCBpbiBzb21lIGZhc2hpb24gKHNwYWNlIHBlcm1pdHRpbmcpLgoKYGBge3J9CmxwX2VudHJ5IDwtIGdldF9ldXBhdGhfZW50cnkoc3BlY2llcyA9ICJNSE9NL0NPTCIsIG1ldGFkYXRhID0gbWV0YSkKCiMjIFRoZXNlIGxpbmVzIGNhbm5vdCBydW4gaW4gdGhlIGNvbnRhaW5lciBiZWNhdXNlIGl0IGNhbm5vdCB3cml0ZQojI3R4ZGJfcGtnbmFtZSA8LSBtYWtlX2V1cGF0aF90eGRiKGxwX2VudHJ5KQojI2dyYW5nZV9uYW1lIDwtIG1ha2VfZXVwYXRoX2dyYW5nZXMobHBfZW50cnkpCmdyYW5nZV9uYW1lIDwtIGdzdWIoeCA9IGxwX2VudHJ5W1siR3Jhbmdlc1BrZyJdXSwgcGF0dGVybiA9ICJcXC5yZGEkIiwgcmVwbGFjZW1lbnQgPSAiIikKZ3JhbmdlX2ZpbGVuYW1lIDwtIGZpbGUucGF0aCgiYnVpbGQiLCBscF9lbnRyeVtbIkdyYW5nZXNQa2ciXV0pCmlmIChmaWxlLmV4aXN0cyhncmFuZ2VfZmlsZW5hbWUpKSB7CiAgbG9hZChncmFuZ2VfZmlsZW5hbWUpCn0gZWxzZSB7CiAgY3JlYXRlZCA8LSBkaXIuY3JlYXRlKCJidWlsZC9nZmYiLCByZWN1cnNpdmUgPSBUUlVFKQogIGdyYW5nZV9idWlsZCA8LSBtYWtlX2V1cGF0aF9ncmFuZ2VzKGxwX2VudHJ5KQogIGdyYW5nZV9maWxlbmFtZSA8LSBncmFuZ2VfYnVpbGRbWyJyZGEiXV0KICBsb2FkKGdyYW5nZV9maWxlbmFtZSkKfQpncmFuZ2VfZGF0YSA8LSBnZXQwKGdyYW5nZV9uYW1lKQoKc2NhZmZvbGRfaWR4IDwtIGdyZXBsKHggPSBhcy5jaGFyYWN0ZXIoc2VxbmFtZXMoZ3JhbmdlX2RhdGEpKSwgcGF0dGVybiA9ICJTQ0FGIikKbm9fc2NhZmZvbGRzIDwtIGdyYW5nZV9kYXRhWyFzY2FmZm9sZF9pZHhdCnNjYWZmb2xkX2lkeCA8LSBncmVwbCh4ID0gYXMuY2hhcmFjdGVyKG5hbWVzKHNlcWluZm8oZ3JhbmdlX2RhdGEpKSksIHBhdHRlcm4gPSAiU0NBRiIpCmNocl9uYW1lcyA8LSBuYW1lcyhzZXFpbmZvKGdyYW5nZV9kYXRhKSlbIXNjYWZmb2xkX2lkeF0Kbm9fc2NhZmZvbGRzIDwtIHNlcWluZm8oZ3JhbmdlX2RhdGEpW2Nocl9uYW1lc10KCmF1dG9fdGJsIDwtIG5ld190YmwKYXV0b190YmxbWyJwb3NpdGlvbjIiXV0gPC0gYXV0b190YmxbWyJQb3NpdGlvbiJdXQphdXRvX3RibFtbIlNOUCJdXSA8LSBOVUxMCnJvd25hbWVzKGF1dG9fdGJsKSA8LSBOVUxMCgp0aWxlc2l6ZSA8LSAxMDAwCmJpbnNfMWsgPC0gR2Vub21pY1Jhbmdlczo6dGlsZUdlbm9tZShzZXFsZW5ndGhzKG5vX3NjYWZmb2xkcyksIHRpbGV3aWR0aCA9IDEwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXQubGFzdC50aWxlLmluLmNocm9tID0gVFJVRSkKYmluc181ayA8LSBHZW5vbWljUmFuZ2VzOjp0aWxlR2Vub21lKHNlcWxlbmd0aHMobm9fc2NhZmZvbGRzKSwgdGlsZXdpZHRoID0gNTAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1dC5sYXN0LnRpbGUuaW4uY2hyb20gPSBUUlVFKQpiaW5zXzEwayA8LSBHZW5vbWljUmFuZ2VzOjp0aWxlR2Vub21lKHNlcWxlbmd0aHMobm9fc2NhZmZvbGRzKSwgdGlsZXdpZHRoID0gMTAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXQubGFzdC50aWxlLmluLmNocm9tID0gVFJVRSkKYmluc18xbnQgPC0gR2Vub21pY1Jhbmdlczo6dGlsZUdlbm9tZShzZXFsZW5ndGhzKG5vX3NjYWZmb2xkcyksIHRpbGV3aWR0aCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0Lmxhc3QudGlsZS5pbi5jaHJvbSA9IFRSVUUpCmF1dG9fdGJsW1sic3RyYW5kIl1dIDwtICIrIgojIyBJIHdhbnQgdG8gY2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgaW50ZXJzZWN0aW5nIHBvc2l0aW9ucyBiZXR3ZWVuIG15IGF1dG9fdGJsIGFuZCB0aGUgMWsgYmlucy4Kc3RhcnQgPC0gYXV0b190YmxbLCBjKCJDaHJvbW9zb21lIiwgIlBvc2l0aW9uIiwgInBvc2l0aW9uMiIsICJzdHJhbmQiLCAic3Ryb25nMjMiKV0KY29sbmFtZXMoc3RhcnQpIDwtIGMoImNociIsICJzdGFydCIsICJlbmQiLCAic3RyYW5kIiwgInoyMyIpCnN0YXJ0W1siY2hyIl1dIDwtIGdzdWIoeCA9IHN0YXJ0W1siY2hyIl1dLCBwYXR0ZXJuID0gIi0iLCByZXBsYWNlbWVudCA9ICJfIikKdmFyX2dyYW5nZSA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUoc3RhcnQsIHNlcWluZm8gPSBub19zY2FmZm9sZHMsIGtlZXAuZXh0cmEuY29sdW1ucyA9IFRSVUUpCnZhcnNfcGVyX2JpbiA8LSBmaW5kT3ZlcmxhcHMoYmluc18xaywgdmFyX2dyYW5nZSkKdmFyc19wZXJfYmluX251bWVyaWMgPC0gYXMuZGF0YS5mcmFtZShiaW5zXzFrKQp2YXJzX3Blcl9iaW5fbnVtZXJpY1tbImJpbiJdXSA8LSByb3duYW1lcyh2YXJzX3Blcl9iaW5fbnVtZXJpYykKCmNvdW50X3Blcl9iaW4gPC0gYXMuZGF0YS5mcmFtZSh2YXJzX3Blcl9iaW4pICU+JQogIGdyb3VwX2J5KHF1ZXJ5SGl0cykgJT4lCiAgZHBseXI6OnRhbGx5KCkKY29sbmFtZXMoY291bnRfcGVyX2JpbikgPC0gYygiYmluIiwgIm51bSIpCnZhcnNfcGVyX2Jpbl9udW1lcmljIDwtIG1lcmdlKHZhcnNfcGVyX2Jpbl9udW1lcmljLCBjb3VudF9wZXJfYmluLCBieSA9ICJiaW4iLCBhbGwueCA9IFRSVUUpCm1pc3NpbmdfaWR4IDwtIGlzLm5hKHZhcnNfcGVyX2Jpbl9udW1lcmljW1sibnVtIl1dKQp2YXJzX3Blcl9iaW5fbnVtZXJpY1ttaXNzaW5nX2lkeCwgIm51bSJdIDwtIDAKdmFyc19wZXJfYmluIDwtIHZhcnNfcGVyX2Jpbl9udW1lcmljWywgYygic2VxbmFtZXMiLCAic3RhcnQiLCAiZW5kIiwgIndpZHRoIiwgInN0cmFuZCIsICJudW0iKV0KdnBiX2dyYW5nZSA8LSBtYWtlR1Jhbmdlc0Zyb21EYXRhRnJhbWUodmFyc19wZXJfYmluLCBzZXFpbmZvID0gbm9fc2NhZmZvbGRzLCBrZWVwLmV4dHJhLmNvbHVtbnMgPSBUUlVFKQoKa2FyeSA8LSBhdXRvcGxvdCh2cGJfZ3JhbmdlLCBsYXlvdXQgPSAia2FyeW9ncmFtIiwgYWVzKGNvbG9yID0gbnVtLCBmaWxsID0gbnVtKSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikKIyMgdGhlbWVfYncoYmFzZV9zaXplID0gMTApICsKcHAoZmlsZSA9ICJrYXJ5b2dyYW1fYnlfdmFyaWFudHMucGRmIiwgaGVpZ2h0ID0gMjQsIHdpZHRoID0gMTgpCmthcnkKZGV2Lm9mZigpCgp2YXJfa2FyeSA8LSBnZ2JpbygpICsKICBsYXlvdXRfa2FyeW9ncmFtKHZwYl9ncmFuZ2UsIGFlcyhjb2xvciA9IG51bSwgZmlsbCA9IG51bSkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJibHVlIiwgaGlnaCA9ICJ3aGl0ZSIpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAid2hpdGUiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTApCnZhcl9rYXJ5CmBgYAoKCjwhLS0tCiFbU05QIERlbnNpdHldKFNOUC1EZW5zaXR5LnJhdGlvLmpwZykKIVtDaXJjdWxhciBNYW5oYXR0YW5dKENpcmN1bGFyLU1hbmhhdHRhbi5yYXRpby5qcGcpCiFbUmVjdGFuZ3VsYXIgTWFuaGF0dGFuXShSZWN0YW5ndWxhci1NYW5oYXR0YW4ucmF0aW8uanBnKQohW1FRXShRUXBsb3QucmF0aW8uanBnKQotLS0+CgojIyBUcnkgb3V0IE1hdHJpeEVRVEwKClRoaXMgdG9vbCBsb29rcyBhIGxpdHRsZSBvcGFxdWUsIGJ1dCBwcm92aWRlcyBzYW1wbGUgZGF0YSB3aXRoIHRoaW5ncwp0aGF0IG1ha2Ugc2Vuc2UgdG8gbWUgYW5kIHNob3VsZCBiZSBwcmV0dHkgZWFzeSB0byByZWNhcGl0dWxhdGUgaW4gb3VyCmRhdGEuCgoxLiAgY292YXJpYXRlcy50eHQ6IENvbHVtbnMgYXJlIHNhbXBsZXMsIHJvd3MgYXJlIHRoaW5ncyBmcm9tIHBEYXRhIC0tIHRoZQptb3N0IGxpa2VseSBvbmVzIG9mIGludGVyZXN0IGZvciBvdXIgZGF0YSB3b3VsZCBiZSB6eW1vZGVtZSwKc2Vuc2l0aXZpdHkKMi4gIGdlbmVsb2MudHh0OiBjb2x1bW5zIGFyZSAnZ2VuZWlkJywgJ2NocicsICdsZWZ0JywgJ3JpZ2h0Jy4gIEkKZ3Vlc3MgSSBjYW4gYXNzdW1lIGxlZnQgYW5kIHJpZ2h0IGFyZSBzdGFydC9zdG9wOyBpbiB3aGljaCBjYXNlCnRoaXMgaXMgdHJpdmlhbGx5IGFjcXVpcmFibGUgZnJvbSBmRGF0YS4KMy4gIGdlLnR4dDogVGhpcyBhcHBlYXJzIHRvIGJlIGEgbG9nKHJwa20vY3BtKSB0YWJsZSB3aXRoIHJvd3MgYXMgZ2VuZXMgYW5kCmNvbHVtbnMgYXMgc2FtcGxlcwo0LiAgc25wc2xvYy50eHQ6IGNvbHVtbnMgYXJlICdzbnBpZCcsICdjaHInLCAncG9zJwo1LiAgc25wcy50eHQ6IGNvbHVtbnMgYXJlIHNhbXBsZXMsIHJvd3MgYXJlIHRoZSBpZHMgZnJvbSBzbnNwbG9jLAp2YWx1ZXMgYSAwLDEsMi4gIEkgYXNzdW1lIDAgaXMgaWRlbnRpY2FsIGFuZCAxLi4xMiBhcmUgdGhlIHZhcmlvdXMKQS0+VEdDIFQtPkFHQyBDLT5BR1QgRy0+QUNUCgpgYGB7ciBtYXRyaXhlcXRsLCBldmFsPUZBTFNFfQojIyBGb3IgdGhpcywgbGV0IHVzIHVzZSB0aGUgJ25ld19zbnBzJyBkYXRhIHN0cnVjdHVyZS4KIyMgQ2F2ZWF0IGhlcmU6IHRoZXNlIG5lZWQgdG8gYmUgY29lcmNlZCB0byBudW1iZXJzLgpteV9jb3ZhcmlhdGVzIDwtIHBEYXRhKG5ld19zbnBzKVssIGMoInp5bW9kZW1lY2F0ZWdvcmljYWwiLCAiY2xpbmljYWxjYXRlZ29yaWNhbCIpXQpmb3IgKGNvbCBpbiBjb2xuYW1lcyhteV9jb3ZhcmlhdGVzKSkgewogIG15X2NvdmFyaWF0ZXNbW2NvbF1dIDwtIGFzLm51bWVyaWMoYXMuZmFjdG9yKG15X2NvdmFyaWF0ZXNbW2NvbF1dKSkKfQpteV9jb3ZhcmlhdGVzIDwtIHQobXlfY292YXJpYXRlcykKCm15X2dlbmVsb2MgPC0gZkRhdGEobHBfZXhwdClbLCBjKCJnaWQiLCAiY2hyb21vc29tZSIsICJzdGFydCIsICJlbmQiKV0KY29sbmFtZXMobXlfZ2VuZWxvYykgPC0gYygiZ2VuZWlkIiwgImNociIsICJsZWZ0IiwgInJpZ2h0IikKCm15X2dlIDwtIGV4cHJzKG5vcm1hbGl6ZV9leHB0KGxwX2V4cHQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iKSkKdXNlZF9zYW1wbGVzIDwtIHRvbG93ZXIoY29sbmFtZXMobXlfZ2UpKSAlaW4lIGNvbG5hbWVzKGV4cHJzKG5ld19zbnBzKSkKbXlfZ2UgPC0gbXlfZ2VbLCB1c2VkX3NhbXBsZXNdCgpteV9zbnBzbG9jIDwtIGRhdGEuZnJhbWUocm93bmFtZXMgPSByb3duYW1lcyhleHBycyhuZXdfc25wcykpKQojIyBPaCwgY2F2ZWF0IGhlcmU6IEJlY2F1c2Ugb2YgdGhlIHdheSBJIHN0b3JlZCB0aGUgZGF0YSwKIyMgSSBjb3VsZCBoYXZlIGR1cGxpY2F0ZSByb3dzIHdoaWNoIHByZXN1bWFibHkgd2lsbCBtYWtlIG1hdHJpeEVRVEwgc2FkCm15X3NucHNsb2NbWyJjaHIiXV0gPC0gZ3N1YihwYXR0ZXJuID0gIl5jaHJfKC4rKV9wb3MoLispX3JlZl8uKiQiLCByZXBsYWNlbWVudCA9ICJcXDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHJvd25hbWVzKG15X3NucHNsb2MpKQpteV9zbnBzbG9jW1sicG9zIl1dIDwtIGdzdWIocGF0dGVybiA9ICJeY2hyXyguKylfcG9zKC4rKV9yZWZfLiokIiwgcmVwbGFjZW1lbnQgPSAiXFwyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSByb3duYW1lcyhteV9zbnBzbG9jKSkKdGVzdCA8LSBkdXBsaWNhdGVkKG15X3NucHNsb2MpCiMjIEVhY2ggZHVwbGljYXRlZCByb3cgd291bGQgYmUgYW5vdGhlciB2YXJpYW50IGF0IHRoYXQgcG9zaXRpb247CiMjIHNvIGluIHRoZW9yeSB3ZSB3b3VsZCBkbyBhIHJsZSB0byBudW1iZXIgdGhlbSBJIGFtIGd1ZXNzaW5nCiMjIEhvd2V2ZXIsIEkgZG8gbm90IGhhdmUgZGlmZmVyZW50IHZhcmlhbnRzIHNvIEkgdGhpbmsgSSBjYW4gaWdub3JlIHRoaXMgZm9yIHRoZSBtb21lbnQKIyMgYnV0IHdpbGwgbmVlZCB0byBtYWtlIG15IG1hdHJpeCBlaXRoZXIgMCBvciAxLgppZiAoc3VtKHRlc3QpID4gMCkgewogIG1lc3NhZ2UoIlRoZXJlIGFyZTogIiwgc3VtKGR1cGxpY2F0ZWQpLCAiIGR1cGxpY2F0ZWQgZW50cmllcy4iKQogIGtlZXBfaWR4IDwtICEgdGVzdAogIG15X3NucHNsb2MgPC0gbXlfc25wc2xvY1trZWVwX2lkeCwgXQp9CgpteV9zbnBzIDwtIGV4cHJzKG5ld19zbnBzKQpvbmVfaWR4IDwtIG15X3NucHMgPiAwCm15X3NucHNbb25lX2lkeF0gPC0gMQoKIyMgT2ssIGF0IHRoaXMgcG9pbnQgSSB0aGluayBJIGhhdmUgYWxsIHRoZSBwaWVjZXMgd2hpY2ggdGhpcyBtZXRob2Qgd2FudHMuLi4KIyMgT2gsIG5vIEkgZ3Vlc3Mgbm90OyBpdCBhY3R1YWxseSB3YW50cyB0aGUgZGF0YSBhcyBhIHNldCBvZiBmaWxlbmFtZXMuLi4KbGlicmFyeShNYXRyaXhFUVRMKQp3cml0ZS50YWJsZShteV9zbnBzLCAiZXF0bC9zbnBzLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KG15X3NucHMsICJlcXRsL3NucHMudHN2IiwgKQp3cml0ZS50YWJsZShteV9zbnBzbG9jLCAiZXF0bC9zbnBzbG9jLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KG15X3NucHNsb2MsICJlcXRsL3NucHNsb2MudHN2IikKd3JpdGUudGFibGUoYXMuZGF0YS5mcmFtZShteV9nZSksICJlcXRsL2dlLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KGFzLmRhdGEuZnJhbWUobXlfZ2UpLCAiZXF0bC9nZS50c3YiKQp3cml0ZS50YWJsZShhcy5kYXRhLmZyYW1lKG15X2dlbmVsb2MpLCAiZXF0bC9nZW5lbG9jLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KGFzLmRhdGEuZnJhbWUobXlfZ2VuZWxvYyksICJlcXRsL2dlbmVsb2MudHN2IikKd3JpdGUudGFibGUoYXMuZGF0YS5mcmFtZShteV9jb3ZhcmlhdGVzKSwgImVxdGwvY292YXJpYXRlcy50c3YiLCBuYSA9ICJOQSIsIGNvbC5uYW1lcyA9IFRSVUUsIHJvdy5uYW1lcyA9IFRSVUUsIHNlcCA9ICJcdCIsIHF1b3RlID0gVFJVRSkKIyMgcmVhZHI6OndyaXRlX3Rzdihhcy5kYXRhLmZyYW1lKG15X2NvdmFyaWF0ZXMpLCAiZXF0bC9jb3ZhcmlhdGVzLnRzdiIpCgp1c2VNb2RlbCA9IG1vZGVsTElORUFSICMgbW9kZWxBTk9WQSwgbW9kZWxMSU5FQVIsIG9yIG1vZGVsTElORUFSX0NST1NTCgojIEdlbm90eXBlIGZpbGUgbmFtZQpTTlBfZmlsZV9uYW1lID0gImVxdGwvc25wcy50c3YiCnNucHNfbG9jYXRpb25fZmlsZV9uYW1lID0gImVxdGwvc25wc2xvYy50c3YiCmV4cHJlc3Npb25fZmlsZV9uYW1lID0gImVxdGwvZ2UudHN2IgpnZW5lX2xvY2F0aW9uX2ZpbGVfbmFtZSA9ICJlcXRsL2dlbmVsb2MudHN2Igpjb3ZhcmlhdGVzX2ZpbGVfbmFtZSA9ICJlcXRsL2NvdmFyaWF0ZXMudHN2IgojIE91dHB1dCBmaWxlIG5hbWUKb3V0cHV0X2ZpbGVfbmFtZV9jaXMgPSB0ZW1wZmlsZSgpCm91dHB1dF9maWxlX25hbWVfdHJhID0gdGVtcGZpbGUoKQojIE9ubHkgYXNzb2NpYXRpb25zIHNpZ25pZmljYW50IGF0IHRoaXMgbGV2ZWwgd2lsbCBiZSBzYXZlZApwdk91dHB1dFRocmVzaG9sZF9jaXMgPSAwLjEKcHZPdXRwdXRUaHJlc2hvbGRfdHJhID0gMC4xCiMgRXJyb3IgY292YXJpYW5jZSBtYXRyaXgKIyBTZXQgdG8gbnVtZXJpYygpIGZvciBpZGVudGl0eS4KZXJyb3JDb3ZhcmlhbmNlID0gbnVtZXJpYygpCiMgZXJyb3JDb3ZhcmlhbmNlID0gcmVhZC50YWJsZSgiU2FtcGxlX0RhdGEvZXJyb3JDb3ZhcmlhbmNlLnR4dCIpOwojIERpc3RhbmNlIGZvciBsb2NhbCBnZW5lLVNOUCBwYWlycwpjaXNEaXN0ID0gMWU2CiMjIExvYWQgZ2Vub3R5cGUgZGF0YQpzbnBzID0gU2xpY2VkRGF0YSRuZXcoKQpzbnBzJGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpzbnBzJGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CnNucHMkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpzbnBzJGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKc25wcyRmaWxlU2xpY2VTaXplID0gMjAwMCAgICAgICMgcmVhZCBmaWxlIGluIHNsaWNlcyBvZiAyLDAwMCByb3dzCnNucHMkTG9hZEZpbGUoU05QX2ZpbGVfbmFtZSkKIyMgTG9hZCBnZW5lIGV4cHJlc3Npb24gZGF0YQpnZW5lID0gU2xpY2VkRGF0YSRuZXcoKQpnZW5lJGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpnZW5lJGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CmdlbmUkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpnZW5lJGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKZ2VuZSRmaWxlU2xpY2VTaXplID0gMjAwMCAgICAgICMgcmVhZCBmaWxlIGluIHNsaWNlcyBvZiAyLDAwMCByb3dzCmdlbmUkTG9hZEZpbGUoZXhwcmVzc2lvbl9maWxlX25hbWUpCiMjIExvYWQgY292YXJpYXRlcwpjdnJ0ID0gU2xpY2VkRGF0YSRuZXcoKQpjdnJ0JGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpjdnJ0JGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CmN2cnQkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpjdnJ0JGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKaWYobGVuZ3RoKGNvdmFyaWF0ZXNfZmlsZV9uYW1lKSA+IDApIHsKICBjdnJ0JExvYWRGaWxlKGNvdmFyaWF0ZXNfZmlsZV9uYW1lKQp9CiMjIFJ1biB0aGUgYW5hbHlzaXMKc25wc3BvcyA9IHJlYWQudGFibGUoc25wc19sb2NhdGlvbl9maWxlX25hbWUsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKZ2VuZXBvcyA9IHJlYWQudGFibGUoZ2VuZV9sb2NhdGlvbl9maWxlX25hbWUsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCm1lID0gTWF0cml4X2VRVExfbWFpbigKICBzbnBzID0gc25wcywKICBnZW5lID0gZ2VuZSwKICBjdnJ0ID0gY3ZydCwKICBvdXRwdXRfZmlsZV9uYW1lID0gb3V0cHV0X2ZpbGVfbmFtZV90cmEsCiAgcHZPdXRwdXRUaHJlc2hvbGQgPSBwdk91dHB1dFRocmVzaG9sZF90cmEsCiAgdXNlTW9kZWwgPSB1c2VNb2RlbCwKICBlcnJvckNvdmFyaWFuY2UgPSBlcnJvckNvdmFyaWFuY2UsCiAgdmVyYm9zZSA9IFRSVUUsCiAgb3V0cHV0X2ZpbGVfbmFtZS5jaXMgPSBvdXRwdXRfZmlsZV9uYW1lX2NpcywKICBwdk91dHB1dFRocmVzaG9sZC5jaXMgPSBwdk91dHB1dFRocmVzaG9sZF9jaXMsCiAgc25wc3BvcyA9IHNucHNwb3MsCiAgZ2VuZXBvcyA9IGdlbmVwb3MsCiAgY2lzRGlzdCA9IGNpc0Rpc3QsCiAgcHZhbHVlLmhpc3QgPSAicXFwbG90IiwKICBtaW4ucHYuYnkuZ2VuZXNucCA9IEZBTFNFLAogIG5vRkRSc2F2ZU1lbW9yeSA9IEZBTFNFKTsKYGBgCgpgYGB7ciBzYXZlbWV9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQojI21lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQojIyB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpKQpgYGAKCmBgYHtyIGxvYWRtZV9hZnRlciwgZXZhbCA9IEZBTFNFfQp0bXAgPC0gbG9hbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==