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.

2 Library sizes and nonzero genes

2.1 Human data

2.1.1 Library sizes

hs_lib <- plot_libsize(hs_macrophage)
pp(file="images/hs_macrophage_libsize.png")
hs_lib$plot
dev.off()
## png 
##   2
hs_lib$plot

hs_lib_log <- plot_libsize(hs_macrophage, yscale="log2")
hs_lib_log$plot

Potential start for a figure legend:

Library sizes of the protein coding gene counts observed per sample. The samples were mapped with hisat2 using the hg38 revision 100 human 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.

hs_non <- plot_nonzero(hs_macrophage, cutoff = 0.65)
## Scale for 'colour' is already present. Adding another scale for 'colour',
## which will replace the existing scale.
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.
pp(file="images/hs_macrophage_nonzero.png")
hs_non$plot
dev.off()
## png 
##   2
hs_non$plot

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 the putative asymptote of likely gene content; no samples were observed with fewer than 65% of the human genes included.

hs_box <- plot_boxplot(hs_macrophage)
## 177066 entries are 0.  We are on a log scale, adding 1 to the data.
pp(file="images/hs_macrophage_boxplot.png")
hs_box
dev.off()
## png 
##   2
hs_box

The distribution of observed counts / gene for all samples was plotted as a boxplot on the log2 scale. No genes were observed as explicit outliers and the range of mean coverage spanned an order of magnitude from 20-200 reads/gene. Quartile boxes were colored according to infection status and drug treatment.

filter_plot <- plot_libsize_prepost(hs_macrophage)
pp(file="images/hs_macrophage_lowgene.png")
filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.
dev.off()
## png 
##   2
filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.

pp(file="images/hs_macrophage_lowcount.png")
filter_plot$count_plot
dev.off()
## png 
##   2
filter_plot$count_plot

Numbers of low-count genes before and after filtering. The height of each bar represents the number of low-count genes (>= 2 counts) before performing a low-count filter. The lower bar represents the number of genes remaining after low-count filtering, the number inside the bar is the difference.

When the low-count filter is applied, some samples have significantly more than the cutoff number of counts/gene (2). As a result, when the number of total counts removed is plotted, that sum is ubiquitously more than twice the number of removed gene and only approaches that threshold for the samples with lowest coverage. This suggests that a coefficient of variance-based filter may be more appropriate under some circumstances.

2.2 Distribution Visualizations

The distribution of samples observed in the macrophage dataset is evocative and suggests that there are very clear distinctions between the two strains as well as the drug treatment.

2.2.1 PCA

There are a few ways we can express the sample distribution via PCA; in this instance we explicitly concatenate the infection and drug treatment status into one factor.

hs_norm <- normalize_expt(hs_macrophage, norm = "quant", transform = "log2",
                          convert = "cpm", filter = TRUE)
## Removing 10021 low-count genes (11460 remaining).
## transform_counts: Found 6 values equal to 0, adding 1 to the matrix.
hs_pca <- plot_pca(hs_norm, plot_title = "PCA of macrophage expression values",
                   plot_labels = FALSE)
pp(file="images/hs_macrophage_norm_pca.png")
hs_pca$plot
dev.off()
## png 
##   2
hs_pca$plot

hs_nb <- normalize_expt(hs_macrophage, convert = "cpm", transform = "log2",
                        filter = TRUE, batch = "svaseq")
## Removing 10021 low-count genes (11460 remaining).
## Setting 619 low elements to zero.
## transform_counts: Found 619 values equal to 0, adding 1 to the matrix.
hs_nb_pca <- plot_pca(hs_nb, plot_title = "PCA of macrophage expression values post-sva",
                      plot_labels = FALSE)
pp(file="images/hs_macrophage_nb_pca.png")
hs_nb_pca$plot
dev.off()
## png 
##   2
hs_nb_pca$plot

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 human macrophages in response to drug treatment and/or parasite infection by two strains. Each glyph represents one sample, the circular samples were not infected; green circles were not treated while yellow circles were. Zymodeme 2.2 infected samples are squares with/out antimonial (purple and green respectively). Zymodeme 2.3 infected samples are diamonds with/out antimonial treatment (pink and orange respectively). This analysis was performed following a low-count filter, cpm conversion, quantile normalization, and a log2 transformation. The second plot is identical except surrogate estimates were derived by svaseq (which estimated 3 surrogates) after normalization and those estimates were used to modify the normalized counts before log2 transformation.

Some interpretation for this figure might include:

When PCA was performed on the human macrophage transcriptome data, the first principal component coincided with drug treatment and the second with differences between zymodemes. The uninfected samples were observed to have very similar transcriptional profiles to the corresponding zymodeme 2.2 samples, suggesting that infection with zymodeme 2.2 has a relatively minimal impact on the macrophage. In contrast, the zymodeme 2.3 samples, excepting one drug treated sample, displayed a significant shift from the uninfected and z2.2. This shift was particularly evident in the non-treated samples. When sva was applied to this data, it slightly improved the observed differences between the drug treatments and zymodeme infections, but did not significantly change the relationship between z2.2 and the uninfected samples.

2.2.2 Correlation heatmaps

```{r correlation_ corheat <- plot_corheat(hs_norm, plot_title = “Correlation heatmap of macrophage expression values”) corheat$plot

corheat <- plot_corheat(hs_nb, plot_title = “Correlation heatmap of macrophage expression values”) corheat$plot

disheat <- plot_disheat(hs_norm, plot_title = “Euclidean heatmap of macrophage expression values”) disheat$plot

corheat <- plot_disheat(hs_nb, plot_title = “Euclidean heatmap of macrophage expression values”) corheat$plot

plot_sm(hs_norm)$plot


Potential start for a figure legend:

Global relationships among the human macrophage 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)
and the colors along the first column delineate infection status
(purple: z2.3, yellow: z2.2, green: uninfected).  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 11,460 normalized gene
values between two samples ranging from <= 0.9 to >= 0.98) or
the euclidean distance between two samples (dark blue to white
delineates identical to a normalized euclidean distance of >= 90).

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 drug treatment.  Secondary clades
intermingled the z2.2 and uninfected samples.  The data before svaseq
provides weak evidence for the hypothesis that sample TMRC30062 (z2.3
drug treated) is actually a z2.2 drug treated sample.  This hypothesis
was discounted by manually examining the relatively few parasite reads
in IGV and comparing the observed variant positions to other known
(not drug treated) z2.3 and z2.2 samples (in this case I compared
TMRC30062, the sample in question, to TMRC30061 (the same strain
without drug treatment), TMRC30063 (another z2.3 strain
without drug treatment) and TMRC30286 (a z2.2 (strain ID 11075) sample
which was not treated); because the drug treated sample has few reads,
it is difficult to find z2.2-specific variants; but positive matches
were readily identifiable to previously characterized z2.3-specific
variants.  Three such locations are shown in the following image
(chromosome 31, 682.4Kb, 691.5kb, 673kb):

[igv/igv_snapshot_checking_zymodeme_sample.png](igv/igv_snapshot_checking_zymodeme_sample.png)

I also wrote a scoring function which sums up all observed variant
positions by putative zymodeme status and for this sample it found 11
positions which were z2.2 specific, 119 which were z2.3 specific, 2808
positions (out of 3541: 0.793) which did not have z2.2 specific variants and
71,944 positions (out of 81,556: 0.882) which did not have z2.3 specific
variants).  The proportions of strain specific (un)observed variant
positions is interesting because it changed over time/celltype for
some people. The observed changes might just be noise in the data (we
only observed 130 specific positions out of ~80,000 in this sample,
for example), but in at least some cases it seems evocative.

## Parasite data

### Library sizes, non-zero plot, and distribution


```r
lp_lib <- plot_libsize(lp_macrophage)
pp(file="images/lp_macrophage_libsize.png")
lp_lib$plot
dev.off()
## png 
##   2
lp_lib$plot

lp_non <- plot_nonzero(lp_macrophage)
## Scale for 'colour' is already present. Adding another scale for 'colour',
## which will replace the existing scale.
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.
pp(file="images/lp_macrophage_nonzero.png")
lp_non$plot
dev.off()
## png 
##   2
lp_non$plot

lp_box <- plot_boxplot(lp_macrophage)
## 1795 entries are 0.  We are on a log scale, adding 1 to the data.
pp(file="images/lp_macrophage_boxplot.png")
lp_box
dev.off()
## png 
##   2
lp_box

filter_plot <- plot_libsize_prepost(lp_macrophage)
pp(file="images/lp_macrophage_lowgene.png")
filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.
dev.off()
## png 
##   2
filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.

pp(file="images/lp_macrophage_lowcount.png")
filter_plot$count_plot
dev.off()
## png 
##   2
filter_plot$count_plot

The parasite metrics are identical in theory to the human macrophage plots above with one relevant difference. In the box plot, the distribution of observed reads/gene follows a different distribution than what was observed in the host, this difference is due to the very different transcriptional profile of the Leishmania parasite.

2.3 Distribution Visualizations

The PCA and heatmap plots for the parasite samples are largely identical in concept to the macrophage plots above with one very important difference. Only 1 of the drug treated samples has sufficient parasite reads remaining to effectively quantify it, the other parasite samples were removed.

This lone post-drug treated samples (TMRC30248, strain 11026) had the largest parasite load before treatment by a tremendous margin (it has 268,826 SL reads compared to 72,489 in the second highest sample, the mean of the pre-drug treated samples is approximately 69,137 and median is 48,090). Thus it is perhaps not surprising that it still has a significant number of SL-containing reads following treatment (30,052 vs 14,418 in the second highest).

2.3.1 Keeping one antimonial treated sample

The following plots show the distinction between the two strains used in the experiment very clearly and suggest that, in the one case with sufficient surviving post-treatment parasites, the parasite transcriptional profile was not significantly changed by the antimonial treatment.

lp_norm <- normalize_expt(lp_macrophage, norm = "quant", transform = "log2",
                          convert = "cpm", filter = TRUE)
## Removing 188 low-count genes (8522 remaining).
## transform_counts: Found 4 values equal to 0, adding 1 to the matrix.
lp_pca <- plot_pca(lp_norm, plot_title = "PCA of macrophage expression values",
                   plot_labels = FALSE)
pp(file="images/lp_macrophage_norm_pca.png")
lp_pca$plot
dev.off()
## png 
##   2
lp_pca$plot

lp_nb <- normalize_expt(lp_macrophage, convert = "cpm", transform = "log2",
                        filter = TRUE, batch = "svaseq")
## Removing 188 low-count genes (8522 remaining).
## Setting 45 low elements to zero.
## transform_counts: Found 45 values equal to 0, adding 1 to the matrix.
lp_nb_pca <- plot_pca(lp_nb, plot_title = "PCA of macrophage expression values post-sva",
                      plot_labels = FALSE)
pp(file="images/lp_macrophage_nb_pca.png")
lp_nb_pca$plot
dev.off()
## png 
##   2
lp_nb_pca$plot

corheat <- plot_corheat(lp_norm, plot_title = "Correlation heatmap of parasite
                 expression values
")
corheat$plot

corheat <- plot_corheat(lp_nb, plot_title = "Correlation heatmap of parasite
                 expression values
")
corheat$plot

plot_sm(lp_norm)$plot
## Performing correlation.

The following repeats the parasite PCA without the peculiar post-antimonial sample.

lp_norm_nosb <- normalize_expt(lp_macrophage_nosb, norm = "quant", transform = "log2",
                          convert = "cpm", filter = TRUE)
## Removing 190 low-count genes (8520 remaining).
## transform_counts: Found 4 values equal to 0, adding 1 to the matrix.
lp_pca_nosb <- plot_pca(lp_norm_nosb, plot_title = "PCA of macrophage expression values",
                   plot_labels = FALSE)
pp(file="images/lp_macrophage_norm_nosb_pca.png")
lp_pca_nosb$plot
dev.off()
## png 
##   2
lp_pca_nosb$plot

lp_nb_nosb <- normalize_expt(lp_macrophage_nosb, convert = "cpm", transform = "log2",
                        filter = TRUE, batch = "svaseq")
## Removing 190 low-count genes (8520 remaining).
## Setting 43 low elements to zero.
## transform_counts: Found 43 values equal to 0, adding 1 to the matrix.
lp_nb_pca_nosb <- plot_pca(lp_nb_nosb, plot_title = "PCA of macrophage expression values post-sva",
                      plot_labels = FALSE)
pp(file="images/lp_macrophage_nb_nosb_pca.png")
lp_nb_pca_nosb$plot
dev.off()
## png 
##   2
lp_nb_pca_nosb$plot

corheat_nosb <- plot_corheat(lp_norm_nosb, plot_title = "Correlation heatmap of parasite
                 expression values
")
corheat_nosb$plot

corheat_nosb <- plot_corheat(lp_nb_nosb, plot_title = "Correlation heatmap of parasite
                 expression values
")
corheat_nosb$plot

if (!isTRUE(get0("skip_load"))) {
  pander::pander(sessionInfo())
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  message(paste0("Saving to ", savefile))
  tmp <- sm(saveme(filename = savefile))
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset b80a01ab8136fffc1458b8a0a80d9ce5a8d64aa5
## This is hpgltools commit: Tue Sep 13 12:24:31 2022 -0400: b80a01ab8136fffc1458b8a0a80d9ce5a8d64aa5
## Saving to tmrc2_macrophage_visualization_202209.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiTC4gcGFuYW1lbnNpcyAyMDIyMDk6IFZpc3VhbGl6aW5nIFRNUkMyIE1hY3JvcGhhZ2Ugc2FtcGxlcy4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShIZWF0cGx1cykKbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDkwLAogICAgICAgICAgICAgICAgICAgICBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGRwaSA9IDk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cyA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSAiMjAyMjA5IgpwcmV2aW91c19maWxlIDwtICIiCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdCA9ICIlWSVtJWQiKQoKIyMgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWUgPSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBwcmV2aW91c19maWxlKSkpKQpybWRfZmlsZSA8LSBnbHVlOjpnbHVlKCJ0bXJjMl9tYWNyb3BoYWdlX3Zpc3VhbGl6YXRpb25fe3Zlcn0uUm1kIikKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCmxvYWRlZCA8LSBsb2FkKGZpbGU9Z2x1ZTo6Z2x1ZSgicmRhL3RtcmMyX2RhdGFfc3RydWN0dXJlcy12e3Zlcn0ucmRhIikpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgd2lsbCB2aXN1YWxpemUgdGhlIFRNUkMyIHNhbXBsZXMgYmVmb3JlIGNvbXBsZXRpbmcgdGhlIHZhcmlvdXMgZGlmZmVyZW50aWFsCmV4cHJlc3Npb24gYW5kIHZhcmlhbnQgYW5hbHlzZXMgaW4gdGhlIGhvcGVzIG9mIGdldHRpbmcgYW4gdW5kZXJzdGFuZGluZyBvZiBob3cgdGhlIHZhcmlvdXMKc2FtcGxlcyByZWxhdGUgdG8gZWFjaCBvdGhlci4KCiMgTGlicmFyeSBzaXplcyBhbmQgbm9uemVybyBnZW5lcwoKIyMgSHVtYW4gZGF0YQoKIyMjIExpYnJhcnkgc2l6ZXMKCmBgYHtyIGh1bWFuX2xpYnNpemV9CmhzX2xpYiA8LSBwbG90X2xpYnNpemUoaHNfbWFjcm9waGFnZSkKcHAoZmlsZT0iaW1hZ2VzL2hzX21hY3JvcGhhZ2VfbGlic2l6ZS5wbmciKQpoc19saWIkcGxvdApkZXYub2ZmKCkKaHNfbGliJHBsb3QKCmhzX2xpYl9sb2cgPC0gcGxvdF9saWJzaXplKGhzX21hY3JvcGhhZ2UsIHlzY2FsZT0ibG9nMiIpCmhzX2xpYl9sb2ckcGxvdApgYGAKClBvdGVudGlhbCBzdGFydCBmb3IgYSBmaWd1cmUgbGVnZW5kOgoKTGlicmFyeSBzaXplcyBvZiB0aGUgcHJvdGVpbiBjb2RpbmcgZ2VuZSBjb3VudHMgb2JzZXJ2ZWQgcGVyIHNhbXBsZS4KVGhlIHNhbXBsZXMgd2VyZSBtYXBwZWQgd2l0aCBoaXNhdDIgdXNpbmcgdGhlIGhnMzggcmV2aXNpb24gMTAwIGh1bWFuCmdlbm9tZTsgdGhlIGFsaWdubWVudHMgd2VyZSBzb3J0ZWQsIGluZGV4ZWQsIGFuZCBjb3VudGVkIHZpYSBodHNlcQp1c2luZyB0aGUgZ2VuZSBmZWF0dXJlcyBhbmQgbm9uLXByb3RlaW4gY29kaW5nIGZlYXR1cmVzIHdlcmUgZXhjbHVkZWQuClRoZSBwZXItc2FtcGxlIHN1bXMgb2YgdGhlIHJlbWFpbmluZyBtYXRyaXggd2VyZSBwbG90dGVkIHRvIGNoZWNrIHRoYXQKdGhlIHJlbGF0aXZlIHNhbXBsZSBjb3ZlcmFnZSBpcyBzdWZmaWNpZW50IGFuZCBub3QgdG9vIGRpdmVyZ2VudAphY3Jvc3Mgc2FtcGxlcy4KCgpgYGB7ciBoc19ub256ZXJvfQpoc19ub24gPC0gcGxvdF9ub256ZXJvKGhzX21hY3JvcGhhZ2UsIGN1dG9mZiA9IDAuNjUpCnBwKGZpbGU9ImltYWdlcy9oc19tYWNyb3BoYWdlX25vbnplcm8ucG5nIikKaHNfbm9uJHBsb3QKZGV2Lm9mZigpCmhzX25vbiRwbG90CmBgYAoKRGlmZmVyZW5jZXMgaW4gcmVsYXRpdmUgZ2VuZSBjb250ZW50IHdpdGggcmVzcGVjdCB0byBzZXF1ZW5jaW5nCmNvdmVyYWdlLiAgVGhlIHBlci1zYW1wbGUgbnVtYmVyIG9mIG9ic2VydmVkIGdlbmVzIHdhcyBwbG90dGVkIHdpdGgKcmVzcGVjdCB0byB0aGUgcmVsYXRpdmUgQ1BNIGNvdmVyYWdlIGluIG9yZGVyIHRvIGNoZWNrIHRoYXQgdGhlCnNhbXBsZXMgYXJlIHN1ZmZpY2llbnRseSBhbmQgc2ltaWxhcmx5IGRpdmVyc2UuICBNYW55IHNhbXBsZXMgd2VyZQpvYnNlcnZlZCBuZWFyIHRoZSBwdXRhdGl2ZSBhc3ltcHRvdGUgb2YgbGlrZWx5IGdlbmUgY29udGVudDsgbm8Kc2FtcGxlcyB3ZXJlIG9ic2VydmVkIHdpdGggZmV3ZXIgdGhhbiA2NSUgb2YgdGhlIGh1bWFuIGdlbmVzIGluY2x1ZGVkLgoKYGBge3IgaHNfYm94cGxvdH0KaHNfYm94IDwtIHBsb3RfYm94cGxvdChoc19tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvaHNfbWFjcm9waGFnZV9ib3hwbG90LnBuZyIpCmhzX2JveApkZXYub2ZmKCkKaHNfYm94CmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZlZCBjb3VudHMgLyBnZW5lIGZvciBhbGwgc2FtcGxlcyB3YXMgcGxvdHRlZAphcyBhIGJveHBsb3Qgb24gdGhlIGxvZzIgc2NhbGUuICBObyBnZW5lcyB3ZXJlIG9ic2VydmVkIGFzIGV4cGxpY2l0Cm91dGxpZXJzIGFuZCB0aGUgcmFuZ2Ugb2YgbWVhbiBjb3ZlcmFnZSBzcGFubmVkIGFuIG9yZGVyIG9mIG1hZ25pdHVkZQpmcm9tIDIwLTIwMCByZWFkcy9nZW5lLiAgUXVhcnRpbGUgYm94ZXMgd2VyZSBjb2xvcmVkIGFjY29yZGluZyB0bwppbmZlY3Rpb24gc3RhdHVzIGFuZCBkcnVnIHRyZWF0bWVudC4KCmBgYHtyIGhzX3ByZXBvc3RfZmlsdGVyfQpmaWx0ZXJfcGxvdCA8LSBwbG90X2xpYnNpemVfcHJlcG9zdChoc19tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvaHNfbWFjcm9waGFnZV9sb3dnZW5lLnBuZyIpCmZpbHRlcl9wbG90JGxvd2dlbmVfcGxvdApkZXYub2ZmKCkKZmlsdGVyX3Bsb3QkbG93Z2VuZV9wbG90CgpwcChmaWxlPSJpbWFnZXMvaHNfbWFjcm9waGFnZV9sb3djb3VudC5wbmciKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmRldi5vZmYoKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmBgYAoKTnVtYmVycyBvZiBsb3ctY291bnQgZ2VuZXMgYmVmb3JlIGFuZCBhZnRlciBmaWx0ZXJpbmcuICBUaGUgaGVpZ2h0IG9mCmVhY2ggYmFyIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBsb3ctY291bnQgZ2VuZXMgKD49IDIgY291bnRzKSBiZWZvcmUKcGVyZm9ybWluZyBhIGxvdy1jb3VudCBmaWx0ZXIuICBUaGUgbG93ZXIgYmFyIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZgpnZW5lcyByZW1haW5pbmcgYWZ0ZXIgbG93LWNvdW50IGZpbHRlcmluZywgdGhlIG51bWJlciBpbnNpZGUgdGhlIGJhcgppcyB0aGUgZGlmZmVyZW5jZS4KCldoZW4gdGhlIGxvdy1jb3VudCBmaWx0ZXIgaXMgYXBwbGllZCwgc29tZSBzYW1wbGVzIGhhdmUgc2lnbmlmaWNhbnRseQptb3JlIHRoYW4gdGhlIGN1dG9mZiBudW1iZXIgb2YgY291bnRzL2dlbmUgKDIpLiAgQXMgYSByZXN1bHQsIHdoZW4gdGhlCm51bWJlciBvZiB0b3RhbCBjb3VudHMgcmVtb3ZlZCBpcyBwbG90dGVkLCB0aGF0IHN1bSBpcyB1YmlxdWl0b3VzbHkKbW9yZSB0aGFuIHR3aWNlIHRoZSBudW1iZXIgb2YgcmVtb3ZlZCBnZW5lIGFuZCBvbmx5IGFwcHJvYWNoZXMgdGhhdAp0aHJlc2hvbGQgZm9yIHRoZSBzYW1wbGVzIHdpdGggbG93ZXN0IGNvdmVyYWdlLiAgVGhpcyBzdWdnZXN0cyB0aGF0IGEKY29lZmZpY2llbnQgb2YgdmFyaWFuY2UtYmFzZWQgZmlsdGVyIG1heSBiZSBtb3JlIGFwcHJvcHJpYXRlIHVuZGVyCnNvbWUgY2lyY3Vtc3RhbmNlcy4KCiMjIERpc3RyaWJ1dGlvbiBWaXN1YWxpemF0aW9ucwoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGVzIG9ic2VydmVkIGluIHRoZSBtYWNyb3BoYWdlIGRhdGFzZXQgaXMKZXZvY2F0aXZlIGFuZCBzdWdnZXN0cyB0aGF0IHRoZXJlIGFyZSB2ZXJ5IGNsZWFyIGRpc3RpbmN0aW9ucyBiZXR3ZWVuCnRoZSB0d28gc3RyYWlucyBhcyB3ZWxsIGFzIHRoZSBkcnVnIHRyZWF0bWVudC4KCiMjIyBQQ0EKClRoZXJlIGFyZSBhIGZldyB3YXlzIHdlIGNhbiBleHByZXNzIHRoZSBzYW1wbGUgZGlzdHJpYnV0aW9uIHZpYSBQQ0E7CmluIHRoaXMgaW5zdGFuY2Ugd2UgZXhwbGljaXRseSBjb25jYXRlbmF0ZSB0aGUgaW5mZWN0aW9uIGFuZCBkcnVnCnRyZWF0bWVudCBzdGF0dXMgaW50byBvbmUgZmFjdG9yLgoKYGBge3IgcHJlX3F1ZXN0aW9uc30KaHNfbm9ybSA8LSBub3JtYWxpemVfZXhwdChoc19tYWNyb3BoYWdlLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkKaHNfcGNhIDwtIHBsb3RfcGNhKGhzX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZT0iaW1hZ2VzL2hzX21hY3JvcGhhZ2Vfbm9ybV9wY2EucG5nIikKaHNfcGNhJHBsb3QKZGV2Lm9mZigpCmhzX3BjYSRwbG90Cgpoc19uYiA8LSBub3JtYWxpemVfZXhwdChoc19tYWNyb3BoYWdlLCBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIikKaHNfbmJfcGNhIDwtIHBsb3RfcGNhKGhzX25iLCBwbG90X3RpdGxlID0gIlBDQSBvZiBtYWNyb3BoYWdlIGV4cHJlc3Npb24gdmFsdWVzIHBvc3Qtc3ZhIiwKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGU9ImltYWdlcy9oc19tYWNyb3BoYWdlX25iX3BjYS5wbmciKQpoc19uYl9wY2EkcGxvdApkZXYub2ZmKCkKaHNfbmJfcGNhJHBsb3QKYGBgCgpTb21lIGxpa2VseSB0ZXh0IGZvciBhIGZpZ3VyZSBsZWdlbmQgbWlnaHQgaW5jbHVkZSBzb21ldGhpbmcgbGlrZSB0aGUKZm9sbG93aW5nIChwYXJhcGhyYXNlZCBmcm9tIE5hamliJ3MgMjAxNiBkdWFsIHRyYW5zY3JpcHRvbWUgcHJvZmlsaW5nCnBhcGVyICgxMC4xMTI4L21CaW8uMDAwMjctMTYpKToKCkV4cHJlc3Npb24gcHJvZmlsZXMgb2YgdGhlIGh1bWFuIG1hY3JvcGhhZ2VzIGluIHJlc3BvbnNlIHRvIGRydWcKdHJlYXRtZW50IGFuZC9vciBwYXJhc2l0ZSBpbmZlY3Rpb24gYnkgdHdvIHN0cmFpbnMuICBFYWNoIGdseXBoCnJlcHJlc2VudHMgb25lIHNhbXBsZSwgdGhlIGNpcmN1bGFyIHNhbXBsZXMgd2VyZSBub3QgaW5mZWN0ZWQ7IGdyZWVuCmNpcmNsZXMgd2VyZSBub3QgdHJlYXRlZCB3aGlsZSB5ZWxsb3cgY2lyY2xlcyB3ZXJlLiAgWnltb2RlbWUgMi4yCmluZmVjdGVkIHNhbXBsZXMgYXJlIHNxdWFyZXMgd2l0aC9vdXQgYW50aW1vbmlhbCAocHVycGxlIGFuZCBncmVlbgpyZXNwZWN0aXZlbHkpLiAgWnltb2RlbWUgMi4zIGluZmVjdGVkIHNhbXBsZXMgYXJlIGRpYW1vbmRzIHdpdGgvb3V0CmFudGltb25pYWwgdHJlYXRtZW50IChwaW5rIGFuZCBvcmFuZ2UgcmVzcGVjdGl2ZWx5KS4gIFRoaXMgYW5hbHlzaXMKd2FzIHBlcmZvcm1lZCBmb2xsb3dpbmcgYSBsb3ctY291bnQgZmlsdGVyLCBjcG0gY29udmVyc2lvbiwgcXVhbnRpbGUKbm9ybWFsaXphdGlvbiwgYW5kIGEgbG9nMiB0cmFuc2Zvcm1hdGlvbi4gIFRoZSBzZWNvbmQgcGxvdCBpcwppZGVudGljYWwgZXhjZXB0IHN1cnJvZ2F0ZSBlc3RpbWF0ZXMgd2VyZSBkZXJpdmVkIGJ5IHN2YXNlcSAod2hpY2gKZXN0aW1hdGVkIDMgc3Vycm9nYXRlcykgYWZ0ZXIgbm9ybWFsaXphdGlvbiBhbmQgdGhvc2UgZXN0aW1hdGVzIHdlcmUKdXNlZCB0byBtb2RpZnkgdGhlIG5vcm1hbGl6ZWQgY291bnRzIGJlZm9yZSBsb2cyIHRyYW5zZm9ybWF0aW9uLgoKU29tZSBpbnRlcnByZXRhdGlvbiBmb3IgdGhpcyBmaWd1cmUgbWlnaHQgaW5jbHVkZToKCldoZW4gUENBIHdhcyBwZXJmb3JtZWQgb24gdGhlIGh1bWFuIG1hY3JvcGhhZ2UgdHJhbnNjcmlwdG9tZSBkYXRhLCB0aGUgZmlyc3QKcHJpbmNpcGFsIGNvbXBvbmVudCBjb2luY2lkZWQgd2l0aCBkcnVnIHRyZWF0bWVudCBhbmQgdGhlIHNlY29uZCB3aXRoCmRpZmZlcmVuY2VzIGJldHdlZW4genltb2RlbWVzLiBUaGUgdW5pbmZlY3RlZCBzYW1wbGVzIHdlcmUgb2JzZXJ2ZWQgdG8KaGF2ZSB2ZXJ5IHNpbWlsYXIgdHJhbnNjcmlwdGlvbmFsIHByb2ZpbGVzIHRvIHRoZSBjb3JyZXNwb25kaW5nCnp5bW9kZW1lIDIuMiBzYW1wbGVzLCBzdWdnZXN0aW5nIHRoYXQgaW5mZWN0aW9uIHdpdGggenltb2RlbWUgMi4yIGhhcwphIHJlbGF0aXZlbHkgbWluaW1hbCBpbXBhY3Qgb24gdGhlIG1hY3JvcGhhZ2UuICBJbiBjb250cmFzdCwgdGhlCnp5bW9kZW1lIDIuMyBzYW1wbGVzLCBleGNlcHRpbmcgb25lIGRydWcgdHJlYXRlZCBzYW1wbGUsIGRpc3BsYXllZCBhCnNpZ25pZmljYW50IHNoaWZ0IGZyb20gdGhlIHVuaW5mZWN0ZWQgYW5kIHoyLjIuICBUaGlzIHNoaWZ0IHdhcwpwYXJ0aWN1bGFybHkgZXZpZGVudCBpbiB0aGUgbm9uLXRyZWF0ZWQgc2FtcGxlcy4gIFdoZW4gc3ZhIHdhcyBhcHBsaWVkCnRvIHRoaXMgZGF0YSwgaXQgc2xpZ2h0bHkgaW1wcm92ZWQgdGhlIG9ic2VydmVkIGRpZmZlcmVuY2VzIGJldHdlZW4KdGhlIGRydWcgdHJlYXRtZW50cyBhbmQgenltb2RlbWUgaW5mZWN0aW9ucywgYnV0IGRpZCBub3Qgc2lnbmlmaWNhbnRseQpjaGFuZ2UgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHoyLjIgYW5kIHRoZSB1bmluZmVjdGVkIHNhbXBsZXMuCgojIyMgQ29ycmVsYXRpb24gaGVhdG1hcHMKCmBgYHtyIGNvcnJlbGF0aW9uXwpjb3JoZWF0IDwtIHBsb3RfY29yaGVhdChoc19ub3JtLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgbWFjcm9waGFnZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmNvcmhlYXQkcGxvdAoKY29yaGVhdCA8LSBwbG90X2NvcmhlYXQoaHNfbmIsIHBsb3RfdGl0bGUgPSAiQ29ycmVsYXRpb24gaGVhdG1hcCBvZiBtYWNyb3BoYWdlCiAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbiB2YWx1ZXMKIikKY29yaGVhdCRwbG90CgpkaXNoZWF0IDwtIHBsb3RfZGlzaGVhdChoc19ub3JtLCBwbG90X3RpdGxlID0gIkV1Y2xpZGVhbiBoZWF0bWFwIG9mIG1hY3JvcGhhZ2UKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpkaXNoZWF0JHBsb3QKCmNvcmhlYXQgPC0gcGxvdF9kaXNoZWF0KGhzX25iLCBwbG90X3RpdGxlID0gIkV1Y2xpZGVhbiBoZWF0bWFwIG9mIG1hY3JvcGhhZ2UKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0JHBsb3QKCnBsb3Rfc20oaHNfbm9ybSkkcGxvdApgYGAKClBvdGVudGlhbCBzdGFydCBmb3IgYSBmaWd1cmUgbGVnZW5kOgoKR2xvYmFsIHJlbGF0aW9uc2hpcHMgYW1vbmcgdGhlIGh1bWFuIG1hY3JvcGhhZ2UgdHJhbnNjcmlwdGlvbmFsCnByb2ZpbGVzLiAgUGFpcndpc2UgcGVhcnNvbiBjb3JyZWxhdGlvbnMgYW5kIEV1Y2xpZGVhbiBkaXN0YW5jZXMgd2VyZQpjYWxjdWxhdGVkIHVzaW5nIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gbWF0cmljZXMuICBDb2xvcnMgYWxvbmcgdGhlCnRvcCByb3cgZGVsaW5lYXRlIHRoZSBleHBlcmltZW50YWwgY29uZGl0aW9ucyAoc2FtZSBjb2xvcnMgYXMgdGhlIFBDQSkKYW5kIHRoZSBjb2xvcnMgYWxvbmcgdGhlIGZpcnN0IGNvbHVtbiBkZWxpbmVhdGUgaW5mZWN0aW9uIHN0YXR1cwoocHVycGxlOiB6Mi4zLCB5ZWxsb3c6IHoyLjIsIGdyZWVuOiB1bmluZmVjdGVkKS4gIFNhbXBsZXMgd2VyZQpjbHVzdGVyZWQgYnkgbmVhcmVzdCBuZWlnaGJvciBjbHVzdGVyaW5nIGFuZCBlYWNoIGNvbG9yZWQgdGlsZQpkZXNjcmliZXMgb25lIGNvcnJlbGF0aW9uIHZhbHVlIGJldHdlZW4gdHdvIHNhbXBsZXMgKHJlZCB0byB3aGl0ZQpkZWxpbmVhdGVzIHBlYXJzb24gY29ycmVsYXRpb24gdmFsdWVzIG9mIHRoZSAxMSw0NjAgbm9ybWFsaXplZCBnZW5lCnZhbHVlcyBiZXR3ZWVuIHR3byBzYW1wbGVzIHJhbmdpbmcgZnJvbSA8PSAwLjkgdG8gPj0gMC45OCkgb3IKdGhlIGV1Y2xpZGVhbiBkaXN0YW5jZSBiZXR3ZWVuIHR3byBzYW1wbGVzIChkYXJrIGJsdWUgdG8gd2hpdGUKZGVsaW5lYXRlcyBpZGVudGljYWwgdG8gYSBub3JtYWxpemVkIGV1Y2xpZGVhbiBkaXN0YW5jZSBvZiA+PSA5MCkuCgpTb21lIGludGVycHJldGF0aW9uIGZvciB0aGlzIGZpZ3VyZSBtaWdodCBpbmNsdWRlOgoKV2hlbiB0aGUgZ2xvYmFsIHJlbGF0aW9uc2hpcHMgYW1vbmcgdGhlIHNhbXBsZXMgd2VyZSBkaXN0aWxsZWQgZG93biB0bwppbmRpdmlkdWFsIGV1Y2xpZGVhbiBkaXN0YW5jZXMgb3IgcGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMKYmV0d2VlbiBwYWlycyBvZiBzYW1wbGVzLCB0aGUgcHJpbWFyeSBjbHVzdGVyaW5nIGFtb25nIHNhbXBsZXMKb2JzZXJ2ZWQgd2FzIGFjY29yZGluZyB0byBkcnVnIHRyZWF0bWVudC4gIFNlY29uZGFyeSBjbGFkZXMKaW50ZXJtaW5nbGVkIHRoZSB6Mi4yIGFuZCB1bmluZmVjdGVkIHNhbXBsZXMuICBUaGUgZGF0YSBiZWZvcmUgc3Zhc2VxCnByb3ZpZGVzIHdlYWsgZXZpZGVuY2UgZm9yIHRoZSBoeXBvdGhlc2lzIHRoYXQgc2FtcGxlIFRNUkMzMDA2MiAoejIuMwpkcnVnIHRyZWF0ZWQpIGlzIGFjdHVhbGx5IGEgejIuMiBkcnVnIHRyZWF0ZWQgc2FtcGxlLiAgVGhpcyBoeXBvdGhlc2lzCndhcyBkaXNjb3VudGVkIGJ5IG1hbnVhbGx5IGV4YW1pbmluZyB0aGUgcmVsYXRpdmVseSBmZXcgcGFyYXNpdGUgcmVhZHMKaW4gSUdWIGFuZCBjb21wYXJpbmcgdGhlIG9ic2VydmVkIHZhcmlhbnQgcG9zaXRpb25zIHRvIG90aGVyIGtub3duCihub3QgZHJ1ZyB0cmVhdGVkKSB6Mi4zIGFuZCB6Mi4yIHNhbXBsZXMgKGluIHRoaXMgY2FzZSBJIGNvbXBhcmVkClRNUkMzMDA2MiwgdGhlIHNhbXBsZSBpbiBxdWVzdGlvbiwgdG8gVE1SQzMwMDYxICh0aGUgc2FtZSBzdHJhaW4Kd2l0aG91dCBkcnVnIHRyZWF0bWVudCksIFRNUkMzMDA2MyAoYW5vdGhlciB6Mi4zIHN0cmFpbgp3aXRob3V0IGRydWcgdHJlYXRtZW50KSBhbmQgVE1SQzMwMjg2IChhIHoyLjIgKHN0cmFpbiBJRCAxMTA3NSkgc2FtcGxlCndoaWNoIHdhcyBub3QgdHJlYXRlZCk7IGJlY2F1c2UgdGhlIGRydWcgdHJlYXRlZCBzYW1wbGUgaGFzIGZldyByZWFkcywKaXQgaXMgZGlmZmljdWx0IHRvIGZpbmQgejIuMi1zcGVjaWZpYyB2YXJpYW50czsgYnV0IHBvc2l0aXZlIG1hdGNoZXMKd2VyZSByZWFkaWx5IGlkZW50aWZpYWJsZSB0byBwcmV2aW91c2x5IGNoYXJhY3Rlcml6ZWQgejIuMy1zcGVjaWZpYwp2YXJpYW50cy4gIFRocmVlIHN1Y2ggbG9jYXRpb25zIGFyZSBzaG93biBpbiB0aGUgZm9sbG93aW5nIGltYWdlCihjaHJvbW9zb21lIDMxLCA2ODIuNEtiLCA2OTEuNWtiLCA2NzNrYik6CgpbaWd2L2lndl9zbmFwc2hvdF9jaGVja2luZ196eW1vZGVtZV9zYW1wbGUucG5nXShpZ3YvaWd2X3NuYXBzaG90X2NoZWNraW5nX3p5bW9kZW1lX3NhbXBsZS5wbmcpCgpJIGFsc28gd3JvdGUgYSBzY29yaW5nIGZ1bmN0aW9uIHdoaWNoIHN1bXMgdXAgYWxsIG9ic2VydmVkIHZhcmlhbnQKcG9zaXRpb25zIGJ5IHB1dGF0aXZlIHp5bW9kZW1lIHN0YXR1cyBhbmQgZm9yIHRoaXMgc2FtcGxlIGl0IGZvdW5kIDExCnBvc2l0aW9ucyB3aGljaCB3ZXJlIHoyLjIgc3BlY2lmaWMsIDExOSB3aGljaCB3ZXJlIHoyLjMgc3BlY2lmaWMsIDI4MDgKcG9zaXRpb25zIChvdXQgb2YgMzU0MTogMC43OTMpIHdoaWNoIGRpZCBub3QgaGF2ZSB6Mi4yIHNwZWNpZmljIHZhcmlhbnRzIGFuZAo3MSw5NDQgcG9zaXRpb25zIChvdXQgb2YgODEsNTU2OiAwLjg4Mikgd2hpY2ggZGlkIG5vdCBoYXZlIHoyLjMgc3BlY2lmaWMKdmFyaWFudHMpLiAgVGhlIHByb3BvcnRpb25zIG9mIHN0cmFpbiBzcGVjaWZpYyAodW4pb2JzZXJ2ZWQgdmFyaWFudApwb3NpdGlvbnMgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBpdCBjaGFuZ2VkIG92ZXIgdGltZS9jZWxsdHlwZSBmb3IKc29tZSBwZW9wbGUuIFRoZSBvYnNlcnZlZCBjaGFuZ2VzIG1pZ2h0IGp1c3QgYmUgbm9pc2UgaW4gdGhlIGRhdGEgKHdlCm9ubHkgb2JzZXJ2ZWQgMTMwIHNwZWNpZmljIHBvc2l0aW9ucyBvdXQgb2YgfjgwLDAwMCBpbiB0aGlzIHNhbXBsZSwKZm9yIGV4YW1wbGUpLCBidXQgaW4gYXQgbGVhc3Qgc29tZSBjYXNlcyBpdCBzZWVtcyBldm9jYXRpdmUuCgojIyBQYXJhc2l0ZSBkYXRhCgojIyMgTGlicmFyeSBzaXplcywgbm9uLXplcm8gcGxvdCwgYW5kIGRpc3RyaWJ1dGlvbgoKYGBge3IgcGFyYXNpdGVfbGlic2l6ZX0KbHBfbGliIDwtIHBsb3RfbGlic2l6ZShscF9tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9saWJzaXplLnBuZyIpCmxwX2xpYiRwbG90CmRldi5vZmYoKQpscF9saWIkcGxvdAoKbHBfbm9uIDwtIHBsb3Rfbm9uemVybyhscF9tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9ub256ZXJvLnBuZyIpCmxwX25vbiRwbG90CmRldi5vZmYoKQpscF9ub24kcGxvdAoKbHBfYm94IDwtIHBsb3RfYm94cGxvdChscF9tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9ib3hwbG90LnBuZyIpCmxwX2JveApkZXYub2ZmKCkKbHBfYm94CgpmaWx0ZXJfcGxvdCA8LSBwbG90X2xpYnNpemVfcHJlcG9zdChscF9tYWNyb3BoYWdlKQpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9sb3dnZW5lLnBuZyIpCmZpbHRlcl9wbG90JGxvd2dlbmVfcGxvdApkZXYub2ZmKCkKZmlsdGVyX3Bsb3QkbG93Z2VuZV9wbG90CgpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9sb3djb3VudC5wbmciKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmRldi5vZmYoKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmBgYAoKVGhlIHBhcmFzaXRlIG1ldHJpY3MgYXJlIGlkZW50aWNhbCBpbiB0aGVvcnkgdG8gdGhlIGh1bWFuIG1hY3JvcGhhZ2UKcGxvdHMgYWJvdmUgd2l0aCBvbmUgcmVsZXZhbnQgZGlmZmVyZW5jZS4gIEluIHRoZSBib3ggcGxvdCwgdGhlCmRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZlZCByZWFkcy9nZW5lIGZvbGxvd3MgYSBkaWZmZXJlbnQgZGlzdHJpYnV0aW9uCnRoYW4gd2hhdCB3YXMgb2JzZXJ2ZWQgaW4gdGhlIGhvc3QsIHRoaXMgZGlmZmVyZW5jZSBpcyBkdWUgdG8gdGhlIHZlcnkKZGlmZmVyZW50IHRyYW5zY3JpcHRpb25hbCBwcm9maWxlIG9mIHRoZSBMZWlzaG1hbmlhIHBhcmFzaXRlLgoKIyMgRGlzdHJpYnV0aW9uIFZpc3VhbGl6YXRpb25zCgpUaGUgUENBIGFuZCBoZWF0bWFwIHBsb3RzIGZvciB0aGUgcGFyYXNpdGUgc2FtcGxlcyBhcmUgbGFyZ2VseQppZGVudGljYWwgaW4gY29uY2VwdCB0byB0aGUgbWFjcm9waGFnZSBwbG90cyBhYm92ZSB3aXRoIG9uZSB2ZXJ5CmltcG9ydGFudCBkaWZmZXJlbmNlLiAgT25seSAxIG9mIHRoZSBkcnVnIHRyZWF0ZWQgc2FtcGxlcyBoYXMKc3VmZmljaWVudCBwYXJhc2l0ZSByZWFkcyByZW1haW5pbmcgdG8gZWZmZWN0aXZlbHkgcXVhbnRpZnkgaXQsIHRoZQpvdGhlciBwYXJhc2l0ZSBzYW1wbGVzIHdlcmUgcmVtb3ZlZC4KClRoaXMgbG9uZSBwb3N0LWRydWcgdHJlYXRlZCBzYW1wbGVzIChUTVJDMzAyNDgsIHN0cmFpbiAxMTAyNikgaGFkIHRoZQpsYXJnZXN0IHBhcmFzaXRlIGxvYWQgYmVmb3JlIHRyZWF0bWVudCBieSBhIHRyZW1lbmRvdXMgbWFyZ2luIChpdCBoYXMKMjY4LDgyNiBTTCByZWFkcyBjb21wYXJlZCB0byA3Miw0ODkgaW4gdGhlIHNlY29uZCBoaWdoZXN0IHNhbXBsZSwgdGhlCm1lYW4gb2YgdGhlIHByZS1kcnVnIHRyZWF0ZWQgc2FtcGxlcyBpcyBhcHByb3hpbWF0ZWx5IDY5LDEzNyBhbmQKbWVkaWFuIGlzIDQ4LDA5MCkuICBUaHVzIGl0IGlzIHBlcmhhcHMgbm90IHN1cnByaXNpbmcgdGhhdCBpdCBzdGlsbApoYXMgYSBzaWduaWZpY2FudCBudW1iZXIgb2YgU0wtY29udGFpbmluZyByZWFkcyBmb2xsb3dpbmcgdHJlYXRtZW50CigzMCwwNTIgdnMgMTQsNDE4IGluIHRoZSBzZWNvbmQgaGlnaGVzdCkuCgojIyMgS2VlcGluZyBvbmUgYW50aW1vbmlhbCB0cmVhdGVkIHNhbXBsZQoKVGhlIGZvbGxvd2luZyBwbG90cyBzaG93IHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZSB0d28gc3RyYWlucyB1c2VkCmluIHRoZSBleHBlcmltZW50IHZlcnkgY2xlYXJseSBhbmQgc3VnZ2VzdCB0aGF0LCBpbiB0aGUgb25lIGNhc2Ugd2l0aApzdWZmaWNpZW50IHN1cnZpdmluZyBwb3N0LXRyZWF0bWVudCBwYXJhc2l0ZXMsIHRoZSBwYXJhc2l0ZQp0cmFuc2NyaXB0aW9uYWwgcHJvZmlsZSB3YXMgbm90IHNpZ25pZmljYW50bHkgY2hhbmdlZCBieSB0aGUKYW50aW1vbmlhbCB0cmVhdG1lbnQuCgpgYGB7ciBwYXJhc2l0ZV9wY2FfdjF9CmxwX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobHBfbWFjcm9waGFnZSwgbm9ybSA9ICJxdWFudCIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUpCmxwX3BjYSA8LSBwbG90X3BjYShscF9ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBtYWNyb3BoYWdlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGU9ImltYWdlcy9scF9tYWNyb3BoYWdlX25vcm1fcGNhLnBuZyIpCmxwX3BjYSRwbG90CmRldi5vZmYoKQpscF9wY2EkcGxvdAoKbHBfbmIgPC0gbm9ybWFsaXplX2V4cHQobHBfbWFjcm9waGFnZSwgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIpCmxwX25iX3BjYSA8LSBwbG90X3BjYShscF9uYiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgbWFjcm9waGFnZSBleHByZXNzaW9uIHZhbHVlcyBwb3N0LXN2YSIsCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlPSJpbWFnZXMvbHBfbWFjcm9waGFnZV9uYl9wY2EucG5nIikKbHBfbmJfcGNhJHBsb3QKZGV2Lm9mZigpCmxwX25iX3BjYSRwbG90Cgpjb3JoZWF0IDwtIHBsb3RfY29yaGVhdChscF9ub3JtLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0JHBsb3QKCmNvcmhlYXQgPC0gcGxvdF9jb3JoZWF0KGxwX25iLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0JHBsb3QKCnBsb3Rfc20obHBfbm9ybSkkcGxvdApgYGAKClRoZSBmb2xsb3dpbmcgcmVwZWF0cyB0aGUgcGFyYXNpdGUgUENBIHdpdGhvdXQgdGhlIHBlY3VsaWFyCnBvc3QtYW50aW1vbmlhbCBzYW1wbGUuCgpgYGB7ciBwYXJhc2l0ZV9wY2FfdjJ9CmxwX25vcm1fbm9zYiA8LSBub3JtYWxpemVfZXhwdChscF9tYWNyb3BoYWdlX25vc2IsIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFKQpscF9wY2Ffbm9zYiA8LSBwbG90X3BjYShscF9ub3JtX25vc2IsIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZT0iaW1hZ2VzL2xwX21hY3JvcGhhZ2Vfbm9ybV9ub3NiX3BjYS5wbmciKQpscF9wY2Ffbm9zYiRwbG90CmRldi5vZmYoKQpscF9wY2Ffbm9zYiRwbG90CgpscF9uYl9ub3NiIDwtIG5vcm1hbGl6ZV9leHB0KGxwX21hY3JvcGhhZ2Vfbm9zYiwgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIpCmxwX25iX3BjYV9ub3NiIDwtIHBsb3RfcGNhKGxwX25iX25vc2IsIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMgcG9zdC1zdmEiLAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZT0iaW1hZ2VzL2xwX21hY3JvcGhhZ2VfbmJfbm9zYl9wY2EucG5nIikKbHBfbmJfcGNhX25vc2IkcGxvdApkZXYub2ZmKCkKbHBfbmJfcGNhX25vc2IkcGxvdAoKY29yaGVhdF9ub3NiIDwtIHBsb3RfY29yaGVhdChscF9ub3JtX25vc2IsIHBsb3RfdGl0bGUgPSAiQ29ycmVsYXRpb24gaGVhdG1hcCBvZiBwYXJhc2l0ZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmNvcmhlYXRfbm9zYiRwbG90Cgpjb3JoZWF0X25vc2IgPC0gcGxvdF9jb3JoZWF0KGxwX25iX25vc2IsIHBsb3RfdGl0bGUgPSAiQ29ycmVsYXRpb24gaGVhdG1hcCBvZiBwYXJhc2l0ZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmNvcmhlYXRfbm9zYiRwbG90CmBgYAoKCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICBtZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHNhdmVmaWxlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpKQp9CmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsID0gRkFMU0V9CnRtcCA8LSBsb2FkbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==