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

This is really comprised of two datasets, one which is purely the comparison of the various parasite strains, and another which is derived from an experiment performed at CIDEIM which compares human macrophages as well as U937 cells following a infection and/or treatment with the antimonial. With that in mind, the next few plots are of this experiment.

2.1.1 Library sizes

Showing this plot twice in order to make explicit that our range of coverage really is pretty extraordinary.

hs_lib <- plot_libsize(hs_macrophage, yscale = "log2")
pp(file = glue("images/hs_macrophage_libsize-v{ver}.svg"), width = 15, height = 9)
hs_lib$plot
dev.off()
## png 
##   2
hs_lib$plot

hs_lib_log <- plot_libsize(hs_macrophage)
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 = glue("images/hs_macrophage_nonzero-v{ver}.svg"))
hs_non$plot
## Warning: ggrepel: 54 unlabeled data points (too many overlaps). Consider increasing
## max.overlaps
dev.off()
## png 
##   2
hs_non$plot
## Warning: ggrepel: 51 unlabeled data points (too many overlaps). Consider increasing
## max.overlaps

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)
## 449491 entries are 0.  We are on a log scale, adding 1 to the data.
pp(file = "images/hs_macrophage_boxplot.svg")
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.svg")
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.svg")
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.

As of 202212, we now have a set of samples from two different cell types: macrophages and U937. Thus the first order of business is to observe their similarities/differences.

type_batch <- set_expt_batches(hs_macrophage, fact="typeofcells")
## 
## Macrophages        U937 
##          54          14
type_batch_norm <- normalize_expt(type_batch, norm = "quant", transform = "log2",
                                  convert = "cpm", filter = TRUE)
## Removing 9198 low-count genes (12283 remaining).
## transform_counts: Found 846 values equal to 0, adding 1 to the matrix.
type_batch_pca <- plot_pca(type_batch_norm, plot_title = "PCA of macrophage expression values",
                           plot_alpha = 0.6, plot_labels = FALSE)
pp(file = glue("images/type_batch_macrophage_norm_pca-v{ver}.svg"))
type_batch_pca$plot
dev.off()
## png 
##   2
type_batch_pca$plot

The differences, as expected are stark. Thus, let us consider the macrophage and U937 samples separately. In addition, consider the samples behind the lense of sample date, strain, infection status, etc.

hs_macr <- subset_expt(hs_macrophage, subset = "typeofcells=='Macrophages'")
## subset_expt(): There were 68, now there are 54 samples.
writen <- write_expt(
  hs_macr,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/hs_macr-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/202304/read_counts/hs_macr-v202304.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## 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.
## 353608 entries are 0.  We are on a log scale, adding 1 to the data.
## 
## Using expt method.
## 
## Performing correlation.
## 
## Using expt method.
## 
## Performing distance.
## 
## Changed 353608 zero count features.
## 
## Naively calculating coefficient of variation/dispersion with respect to condition.
## 
## Finished calculating dispersion estimates.
## 
## `geom_smooth()` using formula = 'y ~ x'
## Error in checkModelStatus(fit, showWarnings = showWarnings, colinearityCutoff = colinearityCutoff,  : 
##   The variables specified in this model are redundant,
## so the design matrix is not full rank
## Retrying with only condition in the model.
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following object is masked from 'package:S4Vectors':
## 
##     expand
## 
## 
## Total:109 s
## `geom_smooth()` using formula = 'y ~ x'
## Error in checkModelStatus(fit, showWarnings = showWarnings, colinearityCutoff = colinearityCutoff,  : 
##   The variables specified in this model are redundant,
## so the design matrix is not full rank
## Retrying with only condition in the model.
## 
## Total:77 s
macr_norm <- normalize_expt(hs_macr, norm = "quant", transform = "log2",
                            convert = "cpm", filter = TRUE)
## Removing 9725 low-count genes (11756 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
macr_pca <- plot_pca(macr_norm, plot_title = "PCA of macrophage expression values",
                     plot_alpha = 0.6, plot_labels = FALSE)
pp(file = glue("images/macr_norm_pca-v{ver}.svg"))
macr_pca$plot
dev.off()
## png 
##   2
macr_pca$plot

hs_macr_datebatch <- set_expt_batches(hs_macr, fact = "oldnew")
## 
##  current previous 
##       27       27
macr_date_norm <- normalize_expt(hs_macr_datebatch, norm = "quant", transform = "log2",
                                 convert = "cpm", filter = TRUE)
## Removing 9725 low-count genes (11756 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
macr_date_pca <- plot_pca(macr_date_norm, plot_title = "PCA of macrophage expression values, date batch",
                     plot_alpha = 0.6, plot_labels = FALSE)
pp(file = glue("images/macr_norm_date_pca-v{ver}.svg"))
macr_date_pca$plot
dev.off()
## png 
##   2
macr_date_pca$plot

Some of the same questions/observations are interesting for the U937 samples.

hs_u937 <- subset_expt(hs_macrophage, subset = "typeofcells!='Macrophages'")
## subset_expt(): There were 68, now there are 14 samples.
u937_norm <- normalize_expt(hs_u937, norm = "quant", transform = "log2",
                            convert = "cpm", filter = TRUE)
## Removing 10730 low-count genes (10751 remaining).
u937_pca <- plot_pca(u937_norm, plot_title = "PCA of U937 expression values",
                     plot_alpha = 0.6, plot_labels = FALSE)
pp(file = glue("images/u937_norm_pca-v{ver}.svg"))
u937_pca$plot
dev.off()
## png 
##   2
u937_pca$plot

Having taken some views of the samples, repeat with sva.

hs_nb <- normalize_expt(hs_macr, convert = "cpm", transform = "log2",
                        filter = TRUE, batch = "svaseq")
## Removing 9725 low-count genes (11756 remaining).
## Setting 1746 low elements to zero.
## transform_counts: Found 1746 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_alpha = 0.6, plot_labels = FALSE)
pp(file = "images/hs_macr_nb_pca.svg")
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

corheat <- plot_corheat(macr_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(macr_norm, plot_title = "Euclidean heatmap of macrophage
                 expression values
")
disheat$plot

disheat_nb <- plot_disheat(hs_nb, plot_title = "Euclidean heatmap of macrophage
                 expression values
")
disheat_nb$plot

plot_sm(macr_norm)$plot
## Using expt method.
## Performing correlation.

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

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.

3 Sources of variance

One thing I did not realize until this very moment, weird combinations of donor/drug/treatment/zymodeme are confounded. Drug and treatment are confounded by definition, but it looks like donor and treatment are, too. This limits the ability to run variancePartition slightly.

3.1 Donor, drug, zymodeme

Let us first run variancePartition in the order donor,drug,zymodeme; which, as Theresa noted, should bias the results in that order.

Oddly, when I did this, it appears to not change the results at all, let us look a little more closely.

table(pData(hs_macr)[["donor"]])
## 
## d01 d02 d09 d81 
##  13  14  13  14
table(pData(hs_macr)[["drug"]])
## 
## antimony     none 
##       27       27
table(pData(hs_macr)[["macrophagezymodeme"]])
## 
## none  z22  z23 
##    8   23   23
table(pData(hs_macr)[["rnaextractiondate"]])
## 
## 20200113 20210831 20211118 20211221 20220829 20220919 
##       13       11        1        2       14       13
table(pData(hs_macr)[["oldnew"]])
## 
##  current previous 
##       27       27
donor_drug_zymo_varpart <- simple_varpart(
    hs_macr,
    factors = c("donor", "drug", "macrophagezymodeme"))
## 
## Total:162 s
donor_drug_zymo_varpart$partition_plot

by_donor <- replot_varpart_percent(donor_drug_zymo_varpart, column = "donor")
by_donor$plot

by_zymo <- replot_varpart_percent(donor_drug_zymo_varpart, column = "macrophagezymodeme")
by_zymo$plot

top_ids <- gsub(x = head(rownames(by_zymo[["resorted"]]), n = 100),
                pattern = "^gene:", replacement = "")
tt <- simple_gprofiler(top_ids)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
tt$pvalue_plots$MF

tt$pvalue_plots$REAC

tt$pvalue_plots$WP

tt$pvalue_plots$BP

by_drug <- replot_varpart_percent(donor_drug_zymo_varpart, column = "drug")
by_drug$plot

top_ids <- gsub(x = head(rownames(by_drug[["resorted"]]), n = 100),
                pattern = "^gene:", replacement = "")
tt <- simple_gprofiler(top_ids)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
tt$pvalue_plots$MF

tt$pvalue_plots$REAC

tt$pvalue_plots$BP

time_drug_zymo_varpart <- simple_varpart(
    hs_macr,
    factors = c("oldnew", "drug", "macrophagezymodeme"))
## 
## Total:154 s
time_drug_zymo_varpart$partition_plot

3.2 Drug zymodeme donor

drug_zymo_donor_varpart <- simple_varpart(
    hs_macr,
    factors = c("drug", "macrophagezymodeme", "donor"))
## 
## Total:159 s
donor_drug_zymo_varpart$partition_plot

donor_drug_zymo_varpart$model_used
## ~donor + drug + macrophagezymodeme
## <environment: 0x5573c4ffd460>
drug_zymo_donor_varpart$partition_plot

drug_zymo_donor_varpart$model_used
## ~drug + macrophagezymodeme + donor
## <environment: 0x55737bd1f0d0>

I think the above shows that the order of elements used in the model do not affect the results.

4 Examine Donors

4.1 Donor comparison

hs_donors <- set_expt_conditions(hs_macr, fact = "donor")
## 
## d01 d02 d09 d81 
##  13  14  13  14
donor_norm <- normalize_expt(hs_donors, filter = TRUE, norm = "quant",
                             convert = "cpm", transform = "log2")
## Removing 9725 low-count genes (11756 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
pp(file = "images/tmrc2_macrophages_donors.svg")
plot_pca(donor_norm, plot_labels = FALSE)$plot
dev.off()
## png 
##   2
donor_nb <- normalize_expt(hs_donors, filter = TRUE, norm = "quant",
                           convert = "cpm", transform = "log2", batch = "svaseq")
## Warning in normalize_expt(hs_donors, filter = TRUE, norm = "quant", convert = "cpm", :
## Quantile normalization and sva do not always play well together.
## Removing 9725 low-count genes (11756 remaining).
## Setting 1456 low elements to zero.
## transform_counts: Found 1456 values equal to 0, adding 1 to the matrix.
pp(file = "images/tmrc2_macrophages_donors_sva.svg")
plot_pca(donor_nb, plot_labels = FALSE)$plot
dev.off()
## png 
##   2

4.2 Drug comparison

hs_drug <- set_expt_conditions(hs_macr, fact = "drug")
## 
## antimony     none 
##       27       27
drug_norm <- normalize_expt(hs_drug, filter = TRUE, norm = "quant",
                             convert = "cpm", transform = "log2")
## Removing 9725 low-count genes (11756 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
pp(file = "images/tmrc2_macrophages_drugs.svg")
plot_pca(drug_norm, plot_labels = FALSE)$plot
dev.off()
## png 
##   2
drug_nb <- normalize_expt(hs_drug, filter = TRUE, norm = "quant",
                           convert = "cpm", transform = "log2", batch = "svaseq")
## Warning in normalize_expt(hs_drug, filter = TRUE, norm = "quant", convert = "cpm", : Quantile
## normalization and sva do not always play well together.
## Removing 9725 low-count genes (11756 remaining).
## Setting 1120 low elements to zero.
## transform_counts: Found 1120 values equal to 0, adding 1 to the matrix.
pp(file = "images/tmrc2_macrophages_drugs_sva.svg")
plot_pca(drug_nb, plot_labels = FALSE)$plot
dev.off()
## png 
##   2

4.3 Parasite data

4.3.1 Library sizes, non-zero plot, and distribution

lp_write <- write_expt(
  lp_macrophage,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/lp_macrophage_reads-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/202304/read_counts/lp_macrophage_reads-v202304.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## 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.
## 3510 entries are 0.  We are on a log scale, adding 1 to the data.
## 
## Using expt method.
## 
## Performing correlation.
## 
## Using expt method.
## 
## Performing distance.
## 
## Changed 3510 zero count features.
## 
## Naively calculating coefficient of variation/dispersion with respect to condition.
## 
## Finished calculating dispersion estimates.
## 
## `geom_smooth()` using formula = 'y ~ x'
## 
## Total:69 s
## 
## `geom_smooth()` using formula = 'y ~ x'
## 
## Total:70 s
lp_nosb_write <- write_expt(
  lp_macrophage_nosb,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/lp_macrophage_nosb_reads-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/202304/read_counts/lp_macrophage_nosb_reads-v202304.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## 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.3148 entries are 0.  We are on a log scale, adding 1 to the data.
## Using expt method.
## Performing correlation.
## Using expt method.
## Performing distance.
## Changed 3148 zero count features.
## Naively calculating coefficient of variation/dispersion with respect to condition.
## Finished calculating dispersion estimates.
## `geom_smooth()` using formula = 'y ~ x'varpart sees only 1 batch, adjusting the model accordingly.
## Error in .fitExtractVarPartModel(exprObj, formula, data, REML = REML,  : 
##   Variable in formula not found in data: condition
## Retrying with only condition in the model.
## 
## Total:52 s
## `geom_smooth()` using formula = 'y ~ x'varpart sees only 1 batch, adjusting the model accordingly.
## Error in .fitExtractVarPartModel(exprObj, formula, data, REML = REML,  : 
##   Variable in formula not found in data: condition
## Retrying with only condition in the model.
## 
## Total:63 s
lp_lib <- plot_libsize(lp_macrophage)
pp(file = "images/lp_macrophage_libsize.svg")
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.svg")
lp_non$plot
dev.off()
## png 
##   2
lp_non$plot

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

filter_plot <- plot_libsize_prepost(lp_macrophage)
pp(file = "images/lp_macrophage_lowgene.svg")
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.svg")
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.

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

4.4.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 169 low-count genes (8541 remaining).
## transform_counts: Found 23 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.svg")
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 169 low-count genes (8541 remaining).
## Setting 134 low elements to zero.
## transform_counts: Found 134 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.svg")
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
## Using expt method.
## 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 171 low-count genes (8539 remaining).
## transform_counts: Found 23 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.svg")
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 171 low-count genes (8539 remaining).
## Setting 110 low elements to zero.
## transform_counts: Found 110 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.svg")
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("This is hpgltools commit: ", get_git_commit())
  message("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 bbc75e24b763faa635cb62c86fc51c0efb3424a1
## This is hpgltools commit: Fri Apr 21 14:33:16 2023 -0400: bbc75e24b763faa635cb62c86fc51c0efb3424a1
## Saving to tmrc2_macrophage_visualization_202304.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzIgMjAyMzAxOiBWaXN1YWxpemluZyBNYWNyb3BoYWdlIHNhbXBsZXMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogIGNvZGVfZG93bmxvYWQ6IHRydWUKICBjb2RlX2ZvbGRpbmc6IHNob3cKICBmaWdfY2FwdGlvbjogdHJ1ZQogIGZpZ19oZWlnaHQ6IDcKICBmaWdfd2lkdGg6IDcKICBoaWdobGlnaHQ6IGRlZmF1bHQKICBrZWVwX21kOiBmYWxzZQogIG1vZGU6IHNlbGZjb250YWluZWQKICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogIHRoZW1lOiByZWFkYWJsZQogIHRvYzogdHJ1ZQogIHRvY19mbG9hdDoKICAgY29sbGFwc2VkOiBmYWxzZQogICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKICB9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoSGVhdHBsdXMpCmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KGdsdWUpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDkwLAogICAgICAgICAgICAgICAgICAgICBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGRwaSA9IDk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cyA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSAiMjAyMzA0IgpwcmV2aW91c19maWxlIDwtICIiCnJ1bmRhdGUgPC0gZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdCA9ICIlWSVtJWQiKQoKIyMgdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWUgPSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBwcmV2aW91c19maWxlKSkpKQpybWRfZmlsZSA8LSBnbHVlKCJ0bXJjMl9tYWNyb3BoYWdlX3Zpc3VhbGl6YXRpb25fe3Zlcn0uUm1kIikKbG9hZGVkIDwtIGxvYWQoZmlsZT1nbHVlKCJyZGEvdG1yYzJfZGF0YV9zdHJ1Y3R1cmVzLXZ7dmVyfS5yZGEiKSkKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgd2lsbCB2aXN1YWxpemUgdGhlIFRNUkMyIHNhbXBsZXMgYmVmb3JlIGNvbXBsZXRpbmcgdGhlIHZhcmlvdXMgZGlmZmVyZW50aWFsCmV4cHJlc3Npb24gYW5kIHZhcmlhbnQgYW5hbHlzZXMgaW4gdGhlIGhvcGVzIG9mIGdldHRpbmcgYW4gdW5kZXJzdGFuZGluZyBvZiBob3cgdGhlIHZhcmlvdXMKc2FtcGxlcyByZWxhdGUgdG8gZWFjaCBvdGhlci4KCiMgTGlicmFyeSBzaXplcyBhbmQgbm9uemVybyBnZW5lcwoKIyMgSHVtYW4gZGF0YQoKVGhpcyBpcyByZWFsbHkgY29tcHJpc2VkIG9mIHR3byBkYXRhc2V0cywgb25lIHdoaWNoIGlzIHB1cmVseSB0aGUKY29tcGFyaXNvbiBvZiB0aGUgdmFyaW91cyBwYXJhc2l0ZSBzdHJhaW5zLCBhbmQgYW5vdGhlciB3aGljaCBpcwpkZXJpdmVkIGZyb20gYW4gZXhwZXJpbWVudCBwZXJmb3JtZWQgYXQgQ0lERUlNIHdoaWNoIGNvbXBhcmVzIGh1bWFuCm1hY3JvcGhhZ2VzIGFzIHdlbGwgYXMgVTkzNyBjZWxscyBmb2xsb3dpbmcgYSBpbmZlY3Rpb24gYW5kL29yCnRyZWF0bWVudCB3aXRoIHRoZSBhbnRpbW9uaWFsLiAgV2l0aCB0aGF0IGluIG1pbmQsIHRoZSBuZXh0IGZldyBwbG90cwphcmUgb2YgdGhpcyBleHBlcmltZW50LgoKIyMjIExpYnJhcnkgc2l6ZXMKClNob3dpbmcgdGhpcyBwbG90IHR3aWNlIGluIG9yZGVyIHRvIG1ha2UgZXhwbGljaXQgdGhhdCBvdXIgcmFuZ2Ugb2YKY292ZXJhZ2UgcmVhbGx5IGlzIHByZXR0eSBleHRyYW9yZGluYXJ5LgoKYGBge3IgaHVtYW5fbGlic2l6ZX0KaHNfbGliIDwtIHBsb3RfbGlic2l6ZShoc19tYWNyb3BoYWdlLCB5c2NhbGUgPSAibG9nMiIpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvaHNfbWFjcm9waGFnZV9saWJzaXplLXZ7dmVyfS5zdmciKSwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gOSkKaHNfbGliJHBsb3QKZGV2Lm9mZigpCmhzX2xpYiRwbG90Cgpoc19saWJfbG9nIDwtIHBsb3RfbGlic2l6ZShoc19tYWNyb3BoYWdlKQpoc19saWJfbG9nJHBsb3QKYGBgCgpQb3RlbnRpYWwgc3RhcnQgZm9yIGEgZmlndXJlIGxlZ2VuZDoKCkxpYnJhcnkgc2l6ZXMgb2YgdGhlIHByb3RlaW4gY29kaW5nIGdlbmUgY291bnRzIG9ic2VydmVkIHBlciBzYW1wbGUuClRoZSBzYW1wbGVzIHdlcmUgbWFwcGVkIHdpdGggaGlzYXQyIHVzaW5nIHRoZSBoZzM4IHJldmlzaW9uIDEwMCBodW1hbgpnZW5vbWU7IHRoZSBhbGlnbm1lbnRzIHdlcmUgc29ydGVkLCBpbmRleGVkLCBhbmQgY291bnRlZCB2aWEgaHRzZXEKdXNpbmcgdGhlIGdlbmUgZmVhdHVyZXMgYW5kIG5vbi1wcm90ZWluIGNvZGluZyBmZWF0dXJlcyB3ZXJlIGV4Y2x1ZGVkLgpUaGUgcGVyLXNhbXBsZSBzdW1zIG9mIHRoZSByZW1haW5pbmcgbWF0cml4IHdlcmUgcGxvdHRlZCB0byBjaGVjayB0aGF0CnRoZSByZWxhdGl2ZSBzYW1wbGUgY292ZXJhZ2UgaXMgc3VmZmljaWVudCBhbmQgbm90IHRvbyBkaXZlcmdlbnQKYWNyb3NzIHNhbXBsZXMuCgpgYGB7ciBoc19ub256ZXJvfQpoc19ub24gPC0gcGxvdF9ub256ZXJvKGhzX21hY3JvcGhhZ2UsIGN1dG9mZiA9IDAuNjUpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvaHNfbWFjcm9waGFnZV9ub256ZXJvLXZ7dmVyfS5zdmciKSkKaHNfbm9uJHBsb3QKZGV2Lm9mZigpCmhzX25vbiRwbG90CmBgYAoKRGlmZmVyZW5jZXMgaW4gcmVsYXRpdmUgZ2VuZSBjb250ZW50IHdpdGggcmVzcGVjdCB0byBzZXF1ZW5jaW5nCmNvdmVyYWdlLiAgVGhlIHBlci1zYW1wbGUgbnVtYmVyIG9mIG9ic2VydmVkIGdlbmVzIHdhcyBwbG90dGVkIHdpdGgKcmVzcGVjdCB0byB0aGUgcmVsYXRpdmUgQ1BNIGNvdmVyYWdlIGluIG9yZGVyIHRvIGNoZWNrIHRoYXQgdGhlCnNhbXBsZXMgYXJlIHN1ZmZpY2llbnRseSBhbmQgc2ltaWxhcmx5IGRpdmVyc2UuICBNYW55IHNhbXBsZXMgd2VyZQpvYnNlcnZlZCBuZWFyIHRoZSBwdXRhdGl2ZSBhc3ltcHRvdGUgb2YgbGlrZWx5IGdlbmUgY29udGVudDsgbm8Kc2FtcGxlcyB3ZXJlIG9ic2VydmVkIHdpdGggZmV3ZXIgdGhhbiA2NSUgb2YgdGhlIGh1bWFuIGdlbmVzIGluY2x1ZGVkLgoKYGBge3IgaHNfYm94cGxvdH0KaHNfYm94IDwtIHBsb3RfYm94cGxvdChoc19tYWNyb3BoYWdlKQpwcChmaWxlID0gImltYWdlcy9oc19tYWNyb3BoYWdlX2JveHBsb3Quc3ZnIikKaHNfYm94CmRldi5vZmYoKQpoc19ib3gKYGBgCgpUaGUgZGlzdHJpYnV0aW9uIG9mIG9ic2VydmVkIGNvdW50cyAvIGdlbmUgZm9yIGFsbCBzYW1wbGVzIHdhcyBwbG90dGVkCmFzIGEgYm94cGxvdCBvbiB0aGUgbG9nMiBzY2FsZS4gIE5vIGdlbmVzIHdlcmUgb2JzZXJ2ZWQgYXMgZXhwbGljaXQKb3V0bGllcnMgYW5kIHRoZSByYW5nZSBvZiBtZWFuIGNvdmVyYWdlIHNwYW5uZWQgYW4gb3JkZXIgb2YgbWFnbml0dWRlCmZyb20gMjAtMjAwIHJlYWRzL2dlbmUuICBRdWFydGlsZSBib3hlcyB3ZXJlIGNvbG9yZWQgYWNjb3JkaW5nIHRvCmluZmVjdGlvbiBzdGF0dXMgYW5kIGRydWcgdHJlYXRtZW50LgoKYGBge3IgaHNfcHJlcG9zdF9maWx0ZXJ9CmZpbHRlcl9wbG90IDwtIHBsb3RfbGlic2l6ZV9wcmVwb3N0KGhzX21hY3JvcGhhZ2UpCnBwKGZpbGUgPSAiaW1hZ2VzL2hzX21hY3JvcGhhZ2VfbG93Z2VuZS5zdmciKQpmaWx0ZXJfcGxvdCRsb3dnZW5lX3Bsb3QKZGV2Lm9mZigpCmZpbHRlcl9wbG90JGxvd2dlbmVfcGxvdAoKcHAoZmlsZSA9ICJpbWFnZXMvaHNfbWFjcm9waGFnZV9sb3djb3VudC5zdmciKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmRldi5vZmYoKQpmaWx0ZXJfcGxvdCRjb3VudF9wbG90CmBgYAoKTnVtYmVycyBvZiBsb3ctY291bnQgZ2VuZXMgYmVmb3JlIGFuZCBhZnRlciBmaWx0ZXJpbmcuICBUaGUgaGVpZ2h0IG9mCmVhY2ggYmFyIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBsb3ctY291bnQgZ2VuZXMgKD49IDIgY291bnRzKSBiZWZvcmUKcGVyZm9ybWluZyBhIGxvdy1jb3VudCBmaWx0ZXIuICBUaGUgbG93ZXIgYmFyIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZgpnZW5lcyByZW1haW5pbmcgYWZ0ZXIgbG93LWNvdW50IGZpbHRlcmluZywgdGhlIG51bWJlciBpbnNpZGUgdGhlIGJhcgppcyB0aGUgZGlmZmVyZW5jZS4KCldoZW4gdGhlIGxvdy1jb3VudCBmaWx0ZXIgaXMgYXBwbGllZCwgc29tZSBzYW1wbGVzIGhhdmUgc2lnbmlmaWNhbnRseQptb3JlIHRoYW4gdGhlIGN1dG9mZiBudW1iZXIgb2YgY291bnRzL2dlbmUgKDIpLiAgQXMgYSByZXN1bHQsIHdoZW4gdGhlCm51bWJlciBvZiB0b3RhbCBjb3VudHMgcmVtb3ZlZCBpcyBwbG90dGVkLCB0aGF0IHN1bSBpcyB1YmlxdWl0b3VzbHkKbW9yZSB0aGFuIHR3aWNlIHRoZSBudW1iZXIgb2YgcmVtb3ZlZCBnZW5lIGFuZCBvbmx5IGFwcHJvYWNoZXMgdGhhdAp0aHJlc2hvbGQgZm9yIHRoZSBzYW1wbGVzIHdpdGggbG93ZXN0IGNvdmVyYWdlLiAgVGhpcyBzdWdnZXN0cyB0aGF0IGEKY29lZmZpY2llbnQgb2YgdmFyaWFuY2UtYmFzZWQgZmlsdGVyIG1heSBiZSBtb3JlIGFwcHJvcHJpYXRlIHVuZGVyCnNvbWUgY2lyY3Vtc3RhbmNlcy4KCiMjIERpc3RyaWJ1dGlvbiBWaXN1YWxpemF0aW9ucwoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGVzIG9ic2VydmVkIGluIHRoZSBtYWNyb3BoYWdlIGRhdGFzZXQgaXMKZXZvY2F0aXZlIGFuZCBzdWdnZXN0cyB0aGF0IHRoZXJlIGFyZSB2ZXJ5IGNsZWFyIGRpc3RpbmN0aW9ucyBiZXR3ZWVuCnRoZSB0d28gc3RyYWlucyBhcyB3ZWxsIGFzIHRoZSBkcnVnIHRyZWF0bWVudC4KCiMjIyBQQ0EKClRoZXJlIGFyZSBhIGZldyB3YXlzIHdlIGNhbiBleHByZXNzIHRoZSBzYW1wbGUgZGlzdHJpYnV0aW9uIHZpYSBQQ0E7CmluIHRoaXMgaW5zdGFuY2Ugd2UgZXhwbGljaXRseSBjb25jYXRlbmF0ZSB0aGUgaW5mZWN0aW9uIGFuZCBkcnVnCnRyZWF0bWVudCBzdGF0dXMgaW50byBvbmUgZmFjdG9yLgoKQXMgb2YgMjAyMjEyLCB3ZSBub3cgaGF2ZSBhIHNldCBvZiBzYW1wbGVzIGZyb20gdHdvIGRpZmZlcmVudCBjZWxsCnR5cGVzOiBtYWNyb3BoYWdlcyBhbmQgVTkzNy4gIFRodXMgdGhlIGZpcnN0IG9yZGVyIG9mIGJ1c2luZXNzIGlzIHRvCm9ic2VydmUgdGhlaXIgc2ltaWxhcml0aWVzL2RpZmZlcmVuY2VzLgoKYGBge3IgcHJlX3F1ZXN0aW9uc30KdHlwZV9iYXRjaCA8LSBzZXRfZXhwdF9iYXRjaGVzKGhzX21hY3JvcGhhZ2UsIGZhY3Q9InR5cGVvZmNlbGxzIikKdHlwZV9iYXRjaF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHR5cGVfYmF0Y2gsIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUpCnR5cGVfYmF0Y2hfcGNhIDwtIHBsb3RfcGNhKHR5cGVfYmF0Y2hfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgbWFjcm9waGFnZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfYWxwaGEgPSAwLjYsIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvdHlwZV9iYXRjaF9tYWNyb3BoYWdlX25vcm1fcGNhLXZ7dmVyfS5zdmciKSkKdHlwZV9iYXRjaF9wY2EkcGxvdApkZXYub2ZmKCkKdHlwZV9iYXRjaF9wY2EkcGxvdApgYGAKClRoZSBkaWZmZXJlbmNlcywgYXMgZXhwZWN0ZWQgYXJlIHN0YXJrLiAgVGh1cywgbGV0IHVzIGNvbnNpZGVyIHRoZQptYWNyb3BoYWdlIGFuZCBVOTM3IHNhbXBsZXMgc2VwYXJhdGVseS4gIEluIGFkZGl0aW9uLCBjb25zaWRlciB0aGUKc2FtcGxlcyBiZWhpbmQgdGhlIGxlbnNlIG9mIHNhbXBsZSBkYXRlLCBzdHJhaW4sIGluZmVjdGlvbiBzdGF0dXMsIGV0Yy4KCmBgYHtyIG1hY3JvX29ubHl9CmhzX21hY3IgPC0gc3Vic2V0X2V4cHQoaHNfbWFjcm9waGFnZSwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nTWFjcm9waGFnZXMnIikKd3JpdGVuIDwtIHdyaXRlX2V4cHQoCiAgaHNfbWFjciwKICBleGNlbCA9IGdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUve3Zlcn0vcmVhZF9jb3VudHMvaHNfbWFjci12e3Zlcn0ueGxzeCIpKQoKbWFjcl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGhzX21hY3IsIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUpCm1hY3JfcGNhIDwtIHBsb3RfcGNhKG1hY3Jfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgbWFjcm9waGFnZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgIHBsb3RfYWxwaGEgPSAwLjYsIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvbWFjcl9ub3JtX3BjYS12e3Zlcn0uc3ZnIikpCm1hY3JfcGNhJHBsb3QKZGV2Lm9mZigpCm1hY3JfcGNhJHBsb3QKCmhzX21hY3JfZGF0ZWJhdGNoIDwtIHNldF9leHB0X2JhdGNoZXMoaHNfbWFjciwgZmFjdCA9ICJvbGRuZXciKQptYWNyX2RhdGVfbm9ybSA8LSBub3JtYWxpemVfZXhwdChoc19tYWNyX2RhdGViYXRjaCwgbm9ybSA9ICJxdWFudCIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFKQptYWNyX2RhdGVfcGNhIDwtIHBsb3RfcGNhKG1hY3JfZGF0ZV9ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBtYWNyb3BoYWdlIGV4cHJlc3Npb24gdmFsdWVzLCBkYXRlIGJhdGNoIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9hbHBoYSA9IDAuNiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9tYWNyX25vcm1fZGF0ZV9wY2Etdnt2ZXJ9LnN2ZyIpKQptYWNyX2RhdGVfcGNhJHBsb3QKZGV2Lm9mZigpCm1hY3JfZGF0ZV9wY2EkcGxvdApgYGAKClNvbWUgb2YgdGhlIHNhbWUgcXVlc3Rpb25zL29ic2VydmF0aW9ucyBhcmUgaW50ZXJlc3RpbmcgZm9yIHRoZSBVOTM3IHNhbXBsZXMuCgpgYGB7ciB1OTM3X29ubHl9CmhzX3U5MzcgPC0gc3Vic2V0X2V4cHQoaHNfbWFjcm9waGFnZSwgc3Vic2V0ID0gInR5cGVvZmNlbGxzIT0nTWFjcm9waGFnZXMnIikKdTkzN19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGhzX3U5MzcsIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUpCnU5MzdfcGNhIDwtIHBsb3RfcGNhKHU5Mzdfbm9ybSwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgVTkzNyBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgIHBsb3RfYWxwaGEgPSAwLjYsIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvdTkzN19ub3JtX3BjYS12e3Zlcn0uc3ZnIikpCnU5MzdfcGNhJHBsb3QKZGV2Lm9mZigpCnU5MzdfcGNhJHBsb3QKYGBgCgpIYXZpbmcgdGFrZW4gc29tZSB2aWV3cyBvZiB0aGUgc2FtcGxlcywgcmVwZWF0IHdpdGggc3ZhLgoKYGBge3IgbWFjcm9waGFnZV9zdmF9CmhzX25iIDwtIG5vcm1hbGl6ZV9leHB0KGhzX21hY3IsIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKQpoc19uYl9wY2EgPC0gcGxvdF9wY2EoaHNfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMgcG9zdC1zdmEiLAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9hbHBoYSA9IDAuNiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvaHNfbWFjcl9uYl9wY2Euc3ZnIikKaHNfbmJfcGNhJHBsb3QKZGV2Lm9mZigpCmhzX25iX3BjYSRwbG90CmBgYAoKU29tZSBsaWtlbHkgdGV4dCBmb3IgYSBmaWd1cmUgbGVnZW5kIG1pZ2h0IGluY2x1ZGUgc29tZXRoaW5nIGxpa2UgdGhlCmZvbGxvd2luZyAocGFyYXBocmFzZWQgZnJvbSBOYWppYidzIDIwMTYgZHVhbCB0cmFuc2NyaXB0b21lIHByb2ZpbGluZwpwYXBlciAoMTAuMTEyOC9tQmlvLjAwMDI3LTE2KSk6CgpFeHByZXNzaW9uIHByb2ZpbGVzIG9mIHRoZSBodW1hbiBtYWNyb3BoYWdlcyBpbiByZXNwb25zZSB0byBkcnVnCnRyZWF0bWVudCBhbmQvb3IgcGFyYXNpdGUgaW5mZWN0aW9uIGJ5IHR3byBzdHJhaW5zLiAgRWFjaCBnbHlwaApyZXByZXNlbnRzIG9uZSBzYW1wbGUsIHRoZSBjaXJjdWxhciBzYW1wbGVzIHdlcmUgbm90IGluZmVjdGVkOyBncmVlbgpjaXJjbGVzIHdlcmUgbm90IHRyZWF0ZWQgd2hpbGUgeWVsbG93IGNpcmNsZXMgd2VyZS4gIFp5bW9kZW1lIDIuMgppbmZlY3RlZCBzYW1wbGVzIGFyZSBzcXVhcmVzIHdpdGgvb3V0IGFudGltb25pYWwgKHB1cnBsZSBhbmQgZ3JlZW4KcmVzcGVjdGl2ZWx5KS4gIFp5bW9kZW1lIDIuMyBpbmZlY3RlZCBzYW1wbGVzIGFyZSBkaWFtb25kcyB3aXRoL291dAphbnRpbW9uaWFsIHRyZWF0bWVudCAocGluayBhbmQgb3JhbmdlIHJlc3BlY3RpdmVseSkuICBUaGlzIGFuYWx5c2lzCndhcyBwZXJmb3JtZWQgZm9sbG93aW5nIGEgbG93LWNvdW50IGZpbHRlciwgY3BtIGNvbnZlcnNpb24sIHF1YW50aWxlCm5vcm1hbGl6YXRpb24sIGFuZCBhIGxvZzIgdHJhbnNmb3JtYXRpb24uICBUaGUgc2Vjb25kIHBsb3QgaXMKaWRlbnRpY2FsIGV4Y2VwdCBzdXJyb2dhdGUgZXN0aW1hdGVzIHdlcmUgZGVyaXZlZCBieSBzdmFzZXEgKHdoaWNoCmVzdGltYXRlZCAzIHN1cnJvZ2F0ZXMpIGFmdGVyIG5vcm1hbGl6YXRpb24gYW5kIHRob3NlIGVzdGltYXRlcyB3ZXJlCnVzZWQgdG8gbW9kaWZ5IHRoZSBub3JtYWxpemVkIGNvdW50cyBiZWZvcmUgbG9nMiB0cmFuc2Zvcm1hdGlvbi4KClNvbWUgaW50ZXJwcmV0YXRpb24gZm9yIHRoaXMgZmlndXJlIG1pZ2h0IGluY2x1ZGU6CgpXaGVuIFBDQSB3YXMgcGVyZm9ybWVkIG9uIHRoZSBodW1hbiBtYWNyb3BoYWdlIHRyYW5zY3JpcHRvbWUgZGF0YSwgdGhlIGZpcnN0CnByaW5jaXBhbCBjb21wb25lbnQgY29pbmNpZGVkIHdpdGggZHJ1ZyB0cmVhdG1lbnQgYW5kIHRoZSBzZWNvbmQgd2l0aApkaWZmZXJlbmNlcyBiZXR3ZWVuIHp5bW9kZW1lcy4gVGhlIHVuaW5mZWN0ZWQgc2FtcGxlcyB3ZXJlIG9ic2VydmVkIHRvCmhhdmUgdmVyeSBzaW1pbGFyIHRyYW5zY3JpcHRpb25hbCBwcm9maWxlcyB0byB0aGUgY29ycmVzcG9uZGluZwp6eW1vZGVtZSAyLjIgc2FtcGxlcywgc3VnZ2VzdGluZyB0aGF0IGluZmVjdGlvbiB3aXRoIHp5bW9kZW1lIDIuMiBoYXMKYSByZWxhdGl2ZWx5IG1pbmltYWwgaW1wYWN0IG9uIHRoZSBtYWNyb3BoYWdlLiAgSW4gY29udHJhc3QsIHRoZQp6eW1vZGVtZSAyLjMgc2FtcGxlcywgZXhjZXB0aW5nIG9uZSBkcnVnIHRyZWF0ZWQgc2FtcGxlLCBkaXNwbGF5ZWQgYQpzaWduaWZpY2FudCBzaGlmdCBmcm9tIHRoZSB1bmluZmVjdGVkIGFuZCB6Mi4yLiAgVGhpcyBzaGlmdCB3YXMKcGFydGljdWxhcmx5IGV2aWRlbnQgaW4gdGhlIG5vbi10cmVhdGVkIHNhbXBsZXMuICBXaGVuIHN2YSB3YXMgYXBwbGllZAp0byB0aGlzIGRhdGEsIGl0IHNsaWdodGx5IGltcHJvdmVkIHRoZSBvYnNlcnZlZCBkaWZmZXJlbmNlcyBiZXR3ZWVuCnRoZSBkcnVnIHRyZWF0bWVudHMgYW5kIHp5bW9kZW1lIGluZmVjdGlvbnMsIGJ1dCBkaWQgbm90IHNpZ25pZmljYW50bHkKY2hhbmdlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB6Mi4yIGFuZCB0aGUgdW5pbmZlY3RlZCBzYW1wbGVzLgoKIyMjIENvcnJlbGF0aW9uIGhlYXRtYXBzCgpgYGB7ciBjb3JyZWxhdGlvbl9oZWF0bWFwc30KY29yaGVhdCA8LSBwbG90X2NvcmhlYXQobWFjcl9ub3JtLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgbWFjcm9waGFnZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmNvcmhlYXQkcGxvdAoKY29yaGVhdCA8LSBwbG90X2NvcmhlYXQoaHNfbmIsIHBsb3RfdGl0bGUgPSAiQ29ycmVsYXRpb24gaGVhdG1hcCBvZiBtYWNyb3BoYWdlCiAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbiB2YWx1ZXMKIikKY29yaGVhdCRwbG90CgpkaXNoZWF0IDwtIHBsb3RfZGlzaGVhdChtYWNyX25vcm0sIHBsb3RfdGl0bGUgPSAiRXVjbGlkZWFuIGhlYXRtYXAgb2YgbWFjcm9waGFnZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmRpc2hlYXQkcGxvdAoKZGlzaGVhdF9uYiA8LSBwbG90X2Rpc2hlYXQoaHNfbmIsIHBsb3RfdGl0bGUgPSAiRXVjbGlkZWFuIGhlYXRtYXAgb2YgbWFjcm9waGFnZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmRpc2hlYXRfbmIkcGxvdAoKcGxvdF9zbShtYWNyX25vcm0pJHBsb3QKYGBgCgpQb3RlbnRpYWwgc3RhcnQgZm9yIGEgZmlndXJlIGxlZ2VuZDoKCkdsb2JhbCByZWxhdGlvbnNoaXBzIGFtb25nIHRoZSBodW1hbiBtYWNyb3BoYWdlIHRyYW5zY3JpcHRpb25hbApwcm9maWxlcy4gIFBhaXJ3aXNlIHBlYXJzb24gY29ycmVsYXRpb25zIGFuZCBFdWNsaWRlYW4gZGlzdGFuY2VzIHdlcmUKY2FsY3VsYXRlZCB1c2luZyB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIG1hdHJpY2VzLiAgQ29sb3JzIGFsb25nIHRoZQp0b3Agcm93IGRlbGluZWF0ZSB0aGUgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMgKHNhbWUgY29sb3JzIGFzIHRoZSBQQ0EpCmFuZCB0aGUgY29sb3JzIGFsb25nIHRoZSBmaXJzdCBjb2x1bW4gZGVsaW5lYXRlIGluZmVjdGlvbiBzdGF0dXMKKHB1cnBsZTogejIuMywgeWVsbG93OiB6Mi4yLCBncmVlbjogdW5pbmZlY3RlZCkuICBTYW1wbGVzIHdlcmUKY2x1c3RlcmVkIGJ5IG5lYXJlc3QgbmVpZ2hib3IgY2x1c3RlcmluZyBhbmQgZWFjaCBjb2xvcmVkIHRpbGUKZGVzY3JpYmVzIG9uZSBjb3JyZWxhdGlvbiB2YWx1ZSBiZXR3ZWVuIHR3byBzYW1wbGVzIChyZWQgdG8gd2hpdGUKZGVsaW5lYXRlcyBwZWFyc29uIGNvcnJlbGF0aW9uIHZhbHVlcyBvZiB0aGUgMTEsNDYwIG5vcm1hbGl6ZWQgZ2VuZQp2YWx1ZXMgYmV0d2VlbiB0d28gc2FtcGxlcyByYW5naW5nIGZyb20gPD0gMC45IHRvID49IDAuOTgpIG9yCnRoZSBldWNsaWRlYW4gZGlzdGFuY2UgYmV0d2VlbiB0d28gc2FtcGxlcyAoZGFyayBibHVlIHRvIHdoaXRlCmRlbGluZWF0ZXMgaWRlbnRpY2FsIHRvIGEgbm9ybWFsaXplZCBldWNsaWRlYW4gZGlzdGFuY2Ugb2YgPj0gOTApLgoKU29tZSBpbnRlcnByZXRhdGlvbiBmb3IgdGhpcyBmaWd1cmUgbWlnaHQgaW5jbHVkZToKCldoZW4gdGhlIGdsb2JhbCByZWxhdGlvbnNoaXBzIGFtb25nIHRoZSBzYW1wbGVzIHdlcmUgZGlzdGlsbGVkIGRvd24gdG8KaW5kaXZpZHVhbCBldWNsaWRlYW4gZGlzdGFuY2VzIG9yIHBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzCmJldHdlZW4gcGFpcnMgb2Ygc2FtcGxlcywgdGhlIHByaW1hcnkgY2x1c3RlcmluZyBhbW9uZyBzYW1wbGVzCm9ic2VydmVkIHdhcyBhY2NvcmRpbmcgdG8gZHJ1ZyB0cmVhdG1lbnQuICBTZWNvbmRhcnkgY2xhZGVzCmludGVybWluZ2xlZCB0aGUgejIuMiBhbmQgdW5pbmZlY3RlZCBzYW1wbGVzLiAgVGhlIGRhdGEgYmVmb3JlIHN2YXNlcQpwcm92aWRlcyB3ZWFrIGV2aWRlbmNlIGZvciB0aGUgaHlwb3RoZXNpcyB0aGF0IHNhbXBsZSBUTVJDMzAwNjIgKHoyLjMKZHJ1ZyB0cmVhdGVkKSBpcyBhY3R1YWxseSBhIHoyLjIgZHJ1ZyB0cmVhdGVkIHNhbXBsZS4gIFRoaXMgaHlwb3RoZXNpcwp3YXMgZGlzY291bnRlZCBieSBtYW51YWxseSBleGFtaW5pbmcgdGhlIHJlbGF0aXZlbHkgZmV3IHBhcmFzaXRlIHJlYWRzCmluIElHViBhbmQgY29tcGFyaW5nIHRoZSBvYnNlcnZlZCB2YXJpYW50IHBvc2l0aW9ucyB0byBvdGhlciBrbm93bgoobm90IGRydWcgdHJlYXRlZCkgejIuMyBhbmQgejIuMiBzYW1wbGVzIChpbiB0aGlzIGNhc2UgSSBjb21wYXJlZApUTVJDMzAwNjIsIHRoZSBzYW1wbGUgaW4gcXVlc3Rpb24sIHRvIFRNUkMzMDA2MSAodGhlIHNhbWUgc3RyYWluCndpdGhvdXQgZHJ1ZyB0cmVhdG1lbnQpLCBUTVJDMzAwNjMgKGFub3RoZXIgejIuMyBzdHJhaW4Kd2l0aG91dCBkcnVnIHRyZWF0bWVudCkgYW5kIFRNUkMzMDI4NiAoYSB6Mi4yIChzdHJhaW4gSUQgMTEwNzUpIHNhbXBsZQp3aGljaCB3YXMgbm90IHRyZWF0ZWQpOyBiZWNhdXNlIHRoZSBkcnVnIHRyZWF0ZWQgc2FtcGxlIGhhcyBmZXcgcmVhZHMsCml0IGlzIGRpZmZpY3VsdCB0byBmaW5kIHoyLjItc3BlY2lmaWMgdmFyaWFudHM7IGJ1dCBwb3NpdGl2ZSBtYXRjaGVzCndlcmUgcmVhZGlseSBpZGVudGlmaWFibGUgdG8gcHJldmlvdXNseSBjaGFyYWN0ZXJpemVkIHoyLjMtc3BlY2lmaWMKdmFyaWFudHMuICBUaHJlZSBzdWNoIGxvY2F0aW9ucyBhcmUgc2hvd24gaW4gdGhlIGZvbGxvd2luZyBpbWFnZQooY2hyb21vc29tZSAzMSwgNjgyLjRLYiwgNjkxLjVrYiwgNjcza2IpOgoKW2lndi9pZ3Zfc25hcHNob3RfY2hlY2tpbmdfenltb2RlbWVfc2FtcGxlLnN2Z10oaWd2L2lndl9zbmFwc2hvdF9jaGVja2luZ196eW1vZGVtZV9zYW1wbGUuc3ZnKQoKSSBhbHNvIHdyb3RlIGEgc2NvcmluZyBmdW5jdGlvbiB3aGljaCBzdW1zIHVwIGFsbCBvYnNlcnZlZCB2YXJpYW50CnBvc2l0aW9ucyBieSBwdXRhdGl2ZSB6eW1vZGVtZSBzdGF0dXMgYW5kIGZvciB0aGlzIHNhbXBsZSBpdCBmb3VuZCAxMQpwb3NpdGlvbnMgd2hpY2ggd2VyZSB6Mi4yIHNwZWNpZmljLCAxMTkgd2hpY2ggd2VyZSB6Mi4zIHNwZWNpZmljLCAyODA4CnBvc2l0aW9ucyAob3V0IG9mIDM1NDE6IDAuNzkzKSB3aGljaCBkaWQgbm90IGhhdmUgejIuMiBzcGVjaWZpYyB2YXJpYW50cyBhbmQKNzEsOTQ0IHBvc2l0aW9ucyAob3V0IG9mIDgxLDU1NjogMC44ODIpIHdoaWNoIGRpZCBub3QgaGF2ZSB6Mi4zIHNwZWNpZmljCnZhcmlhbnRzKS4gIFRoZSBwcm9wb3J0aW9ucyBvZiBzdHJhaW4gc3BlY2lmaWMgKHVuKW9ic2VydmVkIHZhcmlhbnQKcG9zaXRpb25zIGlzIGludGVyZXN0aW5nIGJlY2F1c2UgaXQgY2hhbmdlZCBvdmVyIHRpbWUvY2VsbHR5cGUgZm9yCnNvbWUgcGVvcGxlLiBUaGUgb2JzZXJ2ZWQgY2hhbmdlcyBtaWdodCBqdXN0IGJlIG5vaXNlIGluIHRoZSBkYXRhICh3ZQpvbmx5IG9ic2VydmVkIDEzMCBzcGVjaWZpYyBwb3NpdGlvbnMgb3V0IG9mIH44MCwwMDAgaW4gdGhpcyBzYW1wbGUsCmZvciBleGFtcGxlKSwgYnV0IGluIGF0IGxlYXN0IHNvbWUgY2FzZXMgaXQgc2VlbXMgZXZvY2F0aXZlLgoKIyBTb3VyY2VzIG9mIHZhcmlhbmNlCgpPbmUgdGhpbmcgSSBkaWQgbm90IHJlYWxpemUgdW50aWwgdGhpcyB2ZXJ5IG1vbWVudCwgd2VpcmQgY29tYmluYXRpb25zCm9mIGRvbm9yL2RydWcvdHJlYXRtZW50L3p5bW9kZW1lIGFyZSBjb25mb3VuZGVkLiAgRHJ1ZyBhbmQgdHJlYXRtZW50CmFyZSBjb25mb3VuZGVkIGJ5IGRlZmluaXRpb24sIGJ1dCBpdCBsb29rcyBsaWtlIGRvbm9yIGFuZCB0cmVhdG1lbnQKYXJlLCB0b28uICBUaGlzIGxpbWl0cyB0aGUgYWJpbGl0eSB0byBydW4gdmFyaWFuY2VQYXJ0aXRpb24gc2xpZ2h0bHkuCgojIyBEb25vciwgZHJ1Zywgenltb2RlbWUKCkxldCB1cyBmaXJzdCBydW4gdmFyaWFuY2VQYXJ0aXRpb24gaW4gdGhlIG9yZGVyIGRvbm9yLGRydWcsenltb2RlbWU7CndoaWNoLCBhcyBUaGVyZXNhIG5vdGVkLCBzaG91bGQgYmlhcyB0aGUgcmVzdWx0cyBpbiB0aGF0IG9yZGVyLgoKT2RkbHksIHdoZW4gSSBkaWQgdGhpcywgaXQgYXBwZWFycyB0byBub3QgY2hhbmdlIHRoZSByZXN1bHRzIGF0IGFsbCwKbGV0IHVzIGxvb2sgYSBsaXR0bGUgbW9yZSBjbG9zZWx5LgoKYGBge3IgdmFyaWFuY2VQYXJ0aXRpb259CnRhYmxlKHBEYXRhKGhzX21hY3IpW1siZG9ub3IiXV0pCnRhYmxlKHBEYXRhKGhzX21hY3IpW1siZHJ1ZyJdXSkKdGFibGUocERhdGEoaHNfbWFjcilbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCnRhYmxlKHBEYXRhKGhzX21hY3IpW1sicm5hZXh0cmFjdGlvbmRhdGUiXV0pCnRhYmxlKHBEYXRhKGhzX21hY3IpW1sib2xkbmV3Il1dKQoKZG9ub3JfZHJ1Z196eW1vX3ZhcnBhcnQgPC0gc2ltcGxlX3ZhcnBhcnQoCiAgICBoc19tYWNyLAogICAgZmFjdG9ycyA9IGMoImRvbm9yIiwgImRydWciLCAibWFjcm9waGFnZXp5bW9kZW1lIikpCmRvbm9yX2RydWdfenltb192YXJwYXJ0JHBhcnRpdGlvbl9wbG90CgpieV9kb25vciA8LSByZXBsb3RfdmFycGFydF9wZXJjZW50KGRvbm9yX2RydWdfenltb192YXJwYXJ0LCBjb2x1bW4gPSAiZG9ub3IiKQpieV9kb25vciRwbG90CgpieV96eW1vIDwtIHJlcGxvdF92YXJwYXJ0X3BlcmNlbnQoZG9ub3JfZHJ1Z196eW1vX3ZhcnBhcnQsIGNvbHVtbiA9ICJtYWNyb3BoYWdlenltb2RlbWUiKQpieV96eW1vJHBsb3QKdG9wX2lkcyA8LSBnc3ViKHggPSBoZWFkKHJvd25hbWVzKGJ5X3p5bW9bWyJyZXNvcnRlZCJdXSksIG4gPSAxMDApLAogICAgICAgICAgICAgICAgcGF0dGVybiA9ICJeZ2VuZToiLCByZXBsYWNlbWVudCA9ICIiKQp0dCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHRvcF9pZHMpCgp0dCRwdmFsdWVfcGxvdHMkTUYKdHQkcHZhbHVlX3Bsb3RzJFJFQUMKdHQkcHZhbHVlX3Bsb3RzJFdQCnR0JHB2YWx1ZV9wbG90cyRCUAoKYnlfZHJ1ZyA8LSByZXBsb3RfdmFycGFydF9wZXJjZW50KGRvbm9yX2RydWdfenltb192YXJwYXJ0LCBjb2x1bW4gPSAiZHJ1ZyIpCmJ5X2RydWckcGxvdAp0b3BfaWRzIDwtIGdzdWIoeCA9IGhlYWQocm93bmFtZXMoYnlfZHJ1Z1tbInJlc29ydGVkIl1dKSwgbiA9IDEwMCksCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl5nZW5lOiIsIHJlcGxhY2VtZW50ID0gIiIpCnR0IDwtIHNpbXBsZV9ncHJvZmlsZXIodG9wX2lkcykKdHQkcHZhbHVlX3Bsb3RzJE1GCnR0JHB2YWx1ZV9wbG90cyRSRUFDCnR0JHB2YWx1ZV9wbG90cyRCUAoKdGltZV9kcnVnX3p5bW9fdmFycGFydCA8LSBzaW1wbGVfdmFycGFydCgKICAgIGhzX21hY3IsCiAgICBmYWN0b3JzID0gYygib2xkbmV3IiwgImRydWciLCAibWFjcm9waGFnZXp5bW9kZW1lIikpCnRpbWVfZHJ1Z196eW1vX3ZhcnBhcnQkcGFydGl0aW9uX3Bsb3QKYGBgCgojIyBEcnVnIHp5bW9kZW1lIGRvbm9yCgpgYGB7ciB2YXJpYW5jZVBhcnRpdGlvbn0KZHJ1Z196eW1vX2Rvbm9yX3ZhcnBhcnQgPC0gc2ltcGxlX3ZhcnBhcnQoCiAgICBoc19tYWNyLAogICAgZmFjdG9ycyA9IGMoImRydWciLCAibWFjcm9waGFnZXp5bW9kZW1lIiwgImRvbm9yIikpCgpkb25vcl9kcnVnX3p5bW9fdmFycGFydCRwYXJ0aXRpb25fcGxvdApkb25vcl9kcnVnX3p5bW9fdmFycGFydCRtb2RlbF91c2VkCmRydWdfenltb19kb25vcl92YXJwYXJ0JHBhcnRpdGlvbl9wbG90CmRydWdfenltb19kb25vcl92YXJwYXJ0JG1vZGVsX3VzZWQKYGBgCgpJIHRoaW5rIHRoZSBhYm92ZSBzaG93cyB0aGF0IHRoZSBvcmRlciBvZiBlbGVtZW50cyB1c2VkIGluIHRoZSBtb2RlbApkbyBub3QgYWZmZWN0IHRoZSByZXN1bHRzLgoKIyBFeGFtaW5lIERvbm9ycwoKCiMjIERvbm9yIGNvbXBhcmlzb24KCmBgYHtyIG1hY3JvX2Rvbm9yczAxfQpoc19kb25vcnMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhoc19tYWNyLCBmYWN0ID0gImRvbm9yIikKCmRvbm9yX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoaHNfZG9ub3JzLCBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIikKCnBwKGZpbGUgPSAiaW1hZ2VzL3RtcmMyX21hY3JvcGhhZ2VzX2Rvbm9ycy5zdmciKQpwbG90X3BjYShkb25vcl9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CmRldi5vZmYoKQoKZG9ub3JfbmIgPC0gbm9ybWFsaXplX2V4cHQoaHNfZG9ub3JzLCBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCnBwKGZpbGUgPSAiaW1hZ2VzL3RtcmMyX21hY3JvcGhhZ2VzX2Rvbm9yc19zdmEuc3ZnIikKcGxvdF9wY2EoZG9ub3JfbmIsIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKZGV2Lm9mZigpCmBgYAoKIyMgRHJ1ZyBjb21wYXJpc29uCgpgYGB7ciBkcnVnX3Zpc3VhbGl6YXRpb259CmhzX2RydWcgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhoc19tYWNyLCBmYWN0ID0gImRydWciKQoKZHJ1Z19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGhzX2RydWcsIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiKQpwcChmaWxlID0gImltYWdlcy90bXJjMl9tYWNyb3BoYWdlc19kcnVncy5zdmciKQpwbG90X3BjYShkcnVnX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKZGV2Lm9mZigpCgpkcnVnX25iIDwtIG5vcm1hbGl6ZV9leHB0KGhzX2RydWcsIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKcHAoZmlsZSA9ICJpbWFnZXMvdG1yYzJfbWFjcm9waGFnZXNfZHJ1Z3Nfc3ZhLnN2ZyIpCnBsb3RfcGNhKGRydWdfbmIsIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKZGV2Lm9mZigpCmBgYAoKIyMgUGFyYXNpdGUgZGF0YQoKIyMjIExpYnJhcnkgc2l6ZXMsIG5vbi16ZXJvIHBsb3QsIGFuZCBkaXN0cmlidXRpb24KCmBgYHtyIHBhcmFzaXRlX2xpYnNpemV9CmxwX3dyaXRlIDwtIHdyaXRlX2V4cHQoCiAgbHBfbWFjcm9waGFnZSwKICBleGNlbCA9IGdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUve3Zlcn0vcmVhZF9jb3VudHMvbHBfbWFjcm9waGFnZV9yZWFkcy12e3Zlcn0ueGxzeCIpKQpscF9ub3NiX3dyaXRlIDwtIHdyaXRlX2V4cHQoCiAgbHBfbWFjcm9waGFnZV9ub3NiLAogIGV4Y2VsID0gZ2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS97dmVyfS9yZWFkX2NvdW50cy9scF9tYWNyb3BoYWdlX25vc2JfcmVhZHMtdnt2ZXJ9Lnhsc3giKSkKCmxwX2xpYiA8LSBwbG90X2xpYnNpemUobHBfbWFjcm9waGFnZSkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbWFjcm9waGFnZV9saWJzaXplLnN2ZyIpCmxwX2xpYiRwbG90CmRldi5vZmYoKQpscF9saWIkcGxvdAoKbHBfbm9uIDwtIHBsb3Rfbm9uemVybyhscF9tYWNyb3BoYWdlKQpwcChmaWxlID0gImltYWdlcy9scF9tYWNyb3BoYWdlX25vbnplcm8uc3ZnIikKbHBfbm9uJHBsb3QKZGV2Lm9mZigpCmxwX25vbiRwbG90CgpscF9ib3ggPC0gcGxvdF9ib3hwbG90KGxwX21hY3JvcGhhZ2UpCnBwKGZpbGUgPSAiaW1hZ2VzL2xwX21hY3JvcGhhZ2VfYm94cGxvdC5zdmciKQpscF9ib3gKZGV2Lm9mZigpCmxwX2JveAoKZmlsdGVyX3Bsb3QgPC0gcGxvdF9saWJzaXplX3ByZXBvc3QobHBfbWFjcm9waGFnZSkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbWFjcm9waGFnZV9sb3dnZW5lLnN2ZyIpCmZpbHRlcl9wbG90JGxvd2dlbmVfcGxvdApkZXYub2ZmKCkKZmlsdGVyX3Bsb3QkbG93Z2VuZV9wbG90CgpwcChmaWxlID0gImltYWdlcy9scF9tYWNyb3BoYWdlX2xvd2NvdW50LnN2ZyIpCmZpbHRlcl9wbG90JGNvdW50X3Bsb3QKZGV2Lm9mZigpCmZpbHRlcl9wbG90JGNvdW50X3Bsb3QKYGBgCgpUaGUgcGFyYXNpdGUgbWV0cmljcyBhcmUgaWRlbnRpY2FsIGluIHRoZW9yeSB0byB0aGUgaHVtYW4gbWFjcm9waGFnZQpwbG90cyBhYm92ZSB3aXRoIG9uZSByZWxldmFudCBkaWZmZXJlbmNlLiAgSW4gdGhlIGJveCBwbG90LCB0aGUKZGlzdHJpYnV0aW9uIG9mIG9ic2VydmVkIHJlYWRzL2dlbmUgZm9sbG93cyBhIGRpZmZlcmVudCBkaXN0cmlidXRpb24KdGhhbiB3aGF0IHdhcyBvYnNlcnZlZCBpbiB0aGUgaG9zdCwgdGhpcyBkaWZmZXJlbmNlIGlzIGR1ZSB0byB0aGUgdmVyeQpkaWZmZXJlbnQgdHJhbnNjcmlwdGlvbmFsIHByb2ZpbGUgb2YgdGhlIExlaXNobWFuaWEgcGFyYXNpdGUuCgojIyBEaXN0cmlidXRpb24gVmlzdWFsaXphdGlvbnMKClRoZSBQQ0EgYW5kIGhlYXRtYXAgcGxvdHMgZm9yIHRoZSBwYXJhc2l0ZSBzYW1wbGVzIGFyZSBsYXJnZWx5CmlkZW50aWNhbCBpbiBjb25jZXB0IHRvIHRoZSBtYWNyb3BoYWdlIHBsb3RzIGFib3ZlIHdpdGggb25lIHZlcnkKaW1wb3J0YW50IGRpZmZlcmVuY2UuICBPbmx5IDEgb2YgdGhlIGRydWcgdHJlYXRlZCBzYW1wbGVzIGhhcwpzdWZmaWNpZW50IHBhcmFzaXRlIHJlYWRzIHJlbWFpbmluZyB0byBlZmZlY3RpdmVseSBxdWFudGlmeSBpdCwgdGhlCm90aGVyIHBhcmFzaXRlIHNhbXBsZXMgd2VyZSByZW1vdmVkLgoKVGhpcyBsb25lIHBvc3QtZHJ1ZyB0cmVhdGVkIHNhbXBsZXMgKFRNUkMzMDI0OCwgc3RyYWluIDExMDI2KSBoYWQgdGhlCmxhcmdlc3QgcGFyYXNpdGUgbG9hZCBiZWZvcmUgdHJlYXRtZW50IGJ5IGEgdHJlbWVuZG91cyBtYXJnaW4gKGl0IGhhcwoyNjgsODI2IFNMIHJlYWRzIGNvbXBhcmVkIHRvIDcyLDQ4OSBpbiB0aGUgc2Vjb25kIGhpZ2hlc3Qgc2FtcGxlLCB0aGUKbWVhbiBvZiB0aGUgcHJlLWRydWcgdHJlYXRlZCBzYW1wbGVzIGlzIGFwcHJveGltYXRlbHkgNjksMTM3IGFuZAptZWRpYW4gaXMgNDgsMDkwKS4gIFRodXMgaXQgaXMgcGVyaGFwcyBub3Qgc3VycHJpc2luZyB0aGF0IGl0IHN0aWxsCmhhcyBhIHNpZ25pZmljYW50IG51bWJlciBvZiBTTC1jb250YWluaW5nIHJlYWRzIGZvbGxvd2luZyB0cmVhdG1lbnQKKDMwLDA1MiB2cyAxNCw0MTggaW4gdGhlIHNlY29uZCBoaWdoZXN0KS4KCiMjIyBLZWVwaW5nIG9uZSBhbnRpbW9uaWFsIHRyZWF0ZWQgc2FtcGxlCgpUaGUgZm9sbG93aW5nIHBsb3RzIHNob3cgdGhlIGRpc3RpbmN0aW9uIGJldHdlZW4gdGhlIHR3byBzdHJhaW5zIHVzZWQKaW4gdGhlIGV4cGVyaW1lbnQgdmVyeSBjbGVhcmx5IGFuZCBzdWdnZXN0IHRoYXQsIGluIHRoZSBvbmUgY2FzZSB3aXRoCnN1ZmZpY2llbnQgc3Vydml2aW5nIHBvc3QtdHJlYXRtZW50IHBhcmFzaXRlcywgdGhlIHBhcmFzaXRlCnRyYW5zY3JpcHRpb25hbCBwcm9maWxlIHdhcyBub3Qgc2lnbmlmaWNhbnRseSBjaGFuZ2VkIGJ5IHRoZQphbnRpbW9uaWFsIHRyZWF0bWVudC4KCmBgYHtyIHBhcmFzaXRlX3BjYV92MX0KbHBfbm9ybSA8LSBub3JtYWxpemVfZXhwdChscF9tYWNyb3BoYWdlLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkKbHBfcGNhIDwtIHBsb3RfcGNhKGxwX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbWFjcm9waGFnZV9ub3JtX3BjYS5zdmciKQpscF9wY2EkcGxvdApkZXYub2ZmKCkKbHBfcGNhJHBsb3QKCmxwX25iIDwtIG5vcm1hbGl6ZV9leHB0KGxwX21hY3JvcGhhZ2UsIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKQpscF9uYl9wY2EgPC0gcGxvdF9wY2EobHBfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMgcG9zdC1zdmEiLAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbWFjcm9waGFnZV9uYl9wY2Euc3ZnIikKbHBfbmJfcGNhJHBsb3QKZGV2Lm9mZigpCmxwX25iX3BjYSRwbG90Cgpjb3JoZWF0IDwtIHBsb3RfY29yaGVhdChscF9ub3JtLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0JHBsb3QKCmNvcmhlYXQgPC0gcGxvdF9jb3JoZWF0KGxwX25iLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0JHBsb3QKCnBsb3Rfc20obHBfbm9ybSkkcGxvdApgYGAKClRoZSBmb2xsb3dpbmcgcmVwZWF0cyB0aGUgcGFyYXNpdGUgUENBIHdpdGhvdXQgdGhlIHBlY3VsaWFyCnBvc3QtYW50aW1vbmlhbCBzYW1wbGUuCgpgYGB7ciBwYXJhc2l0ZV9wY2FfdjJ9CmxwX25vcm1fbm9zYiA8LSBub3JtYWxpemVfZXhwdChscF9tYWNyb3BoYWdlX25vc2IsIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFKQpscF9wY2Ffbm9zYiA8LSBwbG90X3BjYShscF9ub3JtX25vc2IsIHBsb3RfdGl0bGUgPSAiUENBIG9mIG1hY3JvcGhhZ2UgZXhwcmVzc2lvbiB2YWx1ZXMiLAogICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbWFjcm9waGFnZV9ub3JtX25vc2JfcGNhLnN2ZyIpCmxwX3BjYV9ub3NiJHBsb3QKZGV2Lm9mZigpCmxwX3BjYV9ub3NiJHBsb3QKCmxwX25iX25vc2IgPC0gbm9ybWFsaXplX2V4cHQobHBfbWFjcm9waGFnZV9ub3NiLCBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIikKbHBfbmJfcGNhX25vc2IgPC0gcGxvdF9wY2EobHBfbmJfbm9zYiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgbWFjcm9waGFnZSBleHByZXNzaW9uIHZhbHVlcyBwb3N0LXN2YSIsCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy9scF9tYWNyb3BoYWdlX25iX25vc2JfcGNhLnN2ZyIpCmxwX25iX3BjYV9ub3NiJHBsb3QKZGV2Lm9mZigpCmxwX25iX3BjYV9ub3NiJHBsb3QKCmNvcmhlYXRfbm9zYiA8LSBwbG90X2NvcmhlYXQobHBfbm9ybV9ub3NiLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0X25vc2IkcGxvdAoKY29yaGVhdF9ub3NiIDwtIHBsb3RfY29yaGVhdChscF9uYl9ub3NiLCBwbG90X3RpdGxlID0gIkNvcnJlbGF0aW9uIGhlYXRtYXAgb2YgcGFyYXNpdGUKICAgICAgICAgICAgICAgICBleHByZXNzaW9uIHZhbHVlcwoiKQpjb3JoZWF0X25vc2IkcGxvdApgYGAKCgpgYGB7ciBzYXZlbWV9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIHBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCiAgbWVzc2FnZSgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKQogIG1lc3NhZ2UoIlNhdmluZyB0byAiLCBzYXZlZmlsZSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpKQp9CmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsID0gRkFMU0V9CnRtcCA8LSBsb2FkbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==