sample_sheet <- glue::glue("sample_sheets/tmrc2_samples_20210610.xlsx")

1 Introduction

This document is intended to provide a general overview of the TMRC2 samples which have thus far been sequenced. In some cases, this includes only those samples starting in 2019; in other instances I am including our previous (2015-2016) samples.

In all cases the processing performed was:

  1. Default trimming was performed.
  2. Hisat2 was used to map the remaining reads against the Leishmania panamensis genome revision 36.
  3. The alignments from hisat2 were used to count reads/gene against the revision 36 annotations with htseq.
  4. These alignments were also passed to the pileup functionality of samtools and the vcf/bcf utilities in order to make a matrix of all observed differences between each sample with respect to the reference.

The analyses in this document use the matrices of counts/gene from #3 and variants/position from #4 in order to provide some images and metrics describing the samples we have sequenced so far.

2 Annotations

Everything which follows depends on the Existing TriTrypDB annotations revision 46, circa 2019. The following block loads a database of these annotations and turns it into a matrix where the rows are genes and columns are all the annotation types provided by TriTrypDB.

The same database was used to create a matrix of orthologous genes between L.panamensis and all of the other species in the TriTrypDB.

tt <- sm(library(EuPathDB))
tt <- sm(library(org.Lpanamensis.MHOMCOL81L13.v46.eg.db))
pan_db <- org.Lpanamensis.MHOMCOL81L13.v46.eg.db
all_fields <- columns(pan_db)

all_lp_annot <- sm(load_orgdb_annotations(
    pan_db,
    keytype = "gid",
    fields = c("annot_gene_entrez_id", "annot_gene_name",
               "annot_strand", "annot_chromosome", "annot_cds_length",
               "annot_gene_product")))$genes

lp_go <- sm(load_orgdb_go(pan_db))
lp_lengths <- all_lp_annot[, c("gid", "annot_cds_length")]
colnames(lp_lengths)  <- c("ID", "length")
all_lp_annot[["annot_gene_product"]] <- tolower(all_lp_annot[["annot_gene_product"]])
orthos <- sm(EuPathDB::extract_eupath_orthologs(db = pan_db))

hisat_annot <- all_lp_annot
## rownames(hisat_annot) <- paste0("exon_", rownames(hisat_annot), ".E1")

3 TODO:

Resequence samples: TMRC20002, TMRC20006, TMRC20004 (maybe TMRC20008 and TMRC20029)

4 Generate Expressionsets and Sample Estimation

The process of sample estimation takes two primary inputs:

  1. The sample sheet, which contains all the metadata we currently have on hand, including filenames for the outputs of #3 and #4 above.
  2. The gene annotations.

An expressionset is a data structure used in R to examine RNASeq data. It is comprised of annotations, metadata, and expression data. In the case of our processing pipeline, the location of the expression data is provided by the filenames in the metadata.

The first lines of the following block create the Expressionset. All of the following lines perform various normalizations and generate plots from it.

4.1 Notes

The following samples are much lower coverage:

  • TMRC20002
  • TMRC20006
  • TMRC20007
  • TMRC20008

20210610: I made some manual changes to the sample sheet which I downloaded, filling in some zymodeme with ‘unknown’

4.2 TODO:

  1. Do the multi-gene family removal right here instead of way down at the bottom
  2. Add zymodeme snps to the annotation later.
  3. Start phylogenetic analysis of variant table.
sanitize_columns <- c("passagenumber", "clinicalresponse", "clinicalcategorical",
                      "zymodemecategorical", "phenotypiccharacteristics")
lp_expt <- sm(create_expt(sample_sheet,
                          gene_info = hisat_annot,
                          id_column = "hpglidentifier",
                          file_column = "lpanamensisv36hisatfile")) %>%
  set_expt_conditions(fact = "zymodemecategorical") %>%
  subset_expt(nonzero = 8600) %>%
  semantic_expt_filter(semantic = c("amastin", "gp63", "leishmanolysin"),
                       semantic_column = "annot_gene_product") %>%
  sanitize_expt_metadata(columns = sanitize_columns) %>%
  set_expt_factors(columns = sanitize_columns, class = "factor")
## The samples (and read coverage) removed when filtering 8600 non-zero genes are:
## TMRC20002 TMRC20004 TMRC20006 TMRC20029 TMRC20008 
##  11681227    564812   6670348   1658096   6249790
## subset_expt(): There were 68, now there are 63 samples.
## semantic_expt_filter(): Removed 68 genes.
libsizes <- plot_libsize(lp_expt)
pp(file = "images/lp_expt_libsizes.png", image = libsizes$plot, width = 12, height = 9)

## I think samples 7,10 should be removed at minimum, probably also 9,11
nonzero <- plot_nonzero(lp_expt)
nonzero$plot
## Warning: ggrepel: 37 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

lp_box <- plot_boxplot(lp_expt)
## 4524 entries are 0.  We are on a log scale, adding 1 to the data.
pp(file = "images/lp_expt_boxplot.png", image = lp_box, width = 12, height = 9)

filter_plot <- plot_libsize_prepost(lp_expt)
filter_plot$lowgene_plot
## Warning: Using alpha for a discrete variable is not advised.

filter_plot$count_plot

4.3 Distribution Visualization

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

4.4 By Susceptilibity

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

  • 0 <= x <= 35 is resistant
  • 36 <= x <= 48 is ambiguous
  • 49 <= x is sensitive
starting <- as.numeric(pData(lp_expt)[["susceptibilityinfectionreduction32ugmlsbvhistoricaldata"]])
sus_categorical <- starting
na_idx <- is.na(starting)
sus_categorical[na_idx] <- "unknown"

resist_idx <- starting <= 0.35
sus_categorical[resist_idx] <- "resistant"
indeterminant_idx <- starting >= 0.36 & starting <= 0.48
sus_categorical[indeterminant_idx] <- "ambiguous"
susceptible_idx <- starting >= 0.49
sus_categorical[susceptible_idx] <- "sensitive"

pData(lp_expt$expressionset)[["sus_category"]] <- sus_categorical
clinical_samples <- lp_expt %>%
  set_expt_batches(fact = sus_categorical)

clinical_norm <- sm(normalize_expt(clinical_samples, norm = "quant", transform = "log2",
                                   convert = "cpm", batch = FALSE, filter = TRUE))
zymo_pca <- plot_pca(clinical_norm, plot_title = "PCA of parasite expression values")
pp(file = "images/zymo_pca_sus_shape.png", image = zymo_pca$plot)

zymo_3dpca <- plot_3d_pca(zymo_pca)
zymo_3dpca$plot
clinical_n <- sm(normalize_expt(clinical_samples, transform = "log2",
                                convert = "cpm", batch = FALSE, filter = TRUE))
zymo_tsne <- plot_tsne(clinical_n, plot_title = "TSNE of parasite expression values")
zymo_tsne$plot

clinical_nb <- normalize_expt(clinical_samples, convert = "cpm", transform = "log2",
                         filter = TRUE, batch = "svaseq")
## Removing 144 low-count genes (8566 remaining).
## batch_counts: Before batch/surrogate estimation, 827 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 2903 entries are 0<x<1: 1%.
## Setting 277 low elements to zero.
## transform_counts: Found 277 values equal to 0, adding 1 to the matrix.
clinical_nb_pca <- plot_pca(clinical_nb, plot_title = "PCA of parasite expression values")
pp(file = "images/clinical_nb_pca_sus_shape.png", image = clinical_nb_pca$plot)

clinical_nb_tsne <- plot_tsne(clinical_nb, plot_title = "TSNE of parasite expression values")
clinical_nb_tsne$plot

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

plot_sm(clinical_norm)$plot
## Performing correlation.

4.5 By Cure/Fail status

cf_expt <- set_expt_conditions(lp_expt, fact = "clinicalcategorical") %>%
  set_expt_batches(fact = sus_categorical)

cf_norm <- normalize_expt(cf_expt, convert = "cpm", transform = "log2",
                          norm = "quant", filter = TRUE)
## Removing 144 low-count genes (8566 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
start_cf <- plot_pca(cf_norm, plot_title = "PCA of parasite expression values")
pp(file = "images/cf_sus_shape.png", image = start_cf$plot)

cf_nb <- normalize_expt(cf_expt, convert = "cpm", transform = "log2",
                        norm = "quant", filter = TRUE, batch = "svaseq")
## Warning in normalize_expt(cf_expt, convert = "cpm", transform = "log2", :
## Quantile normalization and sva do not always play well together.
## Removing 144 low-count genes (8566 remaining).
## batch_counts: Before batch/surrogate estimation, 2 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 3534 entries are 0<x<1: 1%.
## Setting 134 low elements to zero.
## transform_counts: Found 134 values equal to 0, adding 1 to the matrix.
cf_nb_pca <- plot_pca(cf_nb, plot_title = "PCA of parasite expression values")
pp(file = "images/cf_sus_share_nb.png", image = cf_nb_pca$plot)

cf_norm <- normalize_expt(cf_expt, transform = "log2", convert = "cpm",
                          filter = TRUE, norm = "quant")
## Removing 144 low-count genes (8566 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
test <- pca_information(cf_norm,
                        expt_factors = c("clinicalcategorical", "zymodemecategorical",
                                         "pathogenstrain", "passagenumber"),
                        num_components = 6, plot_pcas = TRUE)
test$anova_p
##                           PC1       PC2       PC3    PC4     PC5     PC6
## clinicalcategorical 7.056e-02 4.047e-01 2.052e-02 0.1541 0.48989 0.46854
## zymodemecategorical 8.474e-06 6.051e-01 2.480e-02 0.8261 0.31641 0.31532
## pathogenstrain      4.381e-01 4.212e-01 1.353e-05 0.6289 0.02871 0.70783
## passagenumber       5.646e-01 4.494e-05 1.468e-01 0.1060 0.16486 0.08373
test$cor_heatmap

sus_expt <- set_expt_conditions(lp_expt, fact = "sus_category") %>%
  set_expt_batches(fact = "zymodemecategorical")

sus_norm <- normalize_expt(sus_expt, transform = "log2", convert = "cpm",
                           norm = "quant", filter = TRUE)
## Removing 144 low-count genes (8566 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
sus_pca <- plot_pca(sus_norm, plot_title = "PCA of parasite expression values")
sus_pca$plot

sus_nb <- normalize_expt(sus_expt, transform = "log2", convert = "cpm",
                         batch = "svaseq", filter = TRUE)
## Removing 144 low-count genes (8566 remaining).
## batch_counts: Before batch/surrogate estimation, 827 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 2903 entries are 0<x<1: 1%.
## Setting 166 low elements to zero.
## transform_counts: Found 166 values equal to 0, adding 1 to the matrix.
sus_nb_pca <- plot_pca(sus_nb, plot_title = "PCA of parasite expression values")
pp(file = "images/sus_nb_pca.png", image = sus_nb_pca$plot)
## Warning: ggrepel: 16 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 20 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

At this time, we do not have very many samples, so the set of metrics/plots is fairly limited. There is really only one factor in the metadata which we can use for performing differential expression analyses, the ‘zymodeme’.

5 Zymodeme analyses

The following sections perform a series of analyses which seek to elucidate differences between the zymodemes 2.2 and 2.3 either through differential expression or variant profiles.

5.1 Differential expression

5.1.1 With respect to zymodeme attribution

TODO: Do this with and without sva and compare the results.

zy_expt <- subset_expt(lp_expt, subset = "condition=='z2.2'|condition=='z2.3'")
## subset_expt(): There were 63, now there are 29 samples.
zy_norm <- normalize_expt(zy_expt, filter = TRUE, convert = "cpm", norm = "quant")
## Removing 166 low-count genes (8544 remaining).
zy_de_nobatch <- sm(all_pairwise(zy_expt, filter = TRUE, model_batch = "svaseq"))
zy_de <- sm(all_pairwise(zy_expt, filter = TRUE, model_batch = "svaseq"))
zy_table <- sm(combine_de_tables(zy_de, excel = glue::glue("excel/zy_tables-v{ver}.xlsx")))
zy_sig <- sm(extract_significant_genes(zy_table, excel = glue::glue("excel/zy_sig-v{ver}.xlsx")))

5.1.2 Images of zymodeme DE

zy_table[["plots"]][["z23_vs_z22"]][["deseq_ma_plots"]][["plot"]]

5.2 With respect to cure/failure

In contrast, we can search for genes which are differentially expressed with respect to cure/failure status.

cf_de <- sm(all_pairwise(cf_expt, filter = TRUE, model_batch = "svaseq"))
cf_table <- sm(combine_de_tables(cf_de, excel = glue::glue("excel/cf_tables-v{ver}.xlsx")))
cf_sig <- sm(extract_significant_genes(cf_table, excel = glue::glue("excel/cf_sig-v{ver}.xlsx")))

5.3 With respect to susceptibility

Finally, we can use our category of susceptibility and look for genes which change from sensitive to resistant. Keep in mind, though, that for the moment we have a lot of ambiguous and unknown strains.

sus_de <- sm(all_pairwise(sus_expt, filter = TRUE, model_batch = "svaseq"))
sus_table <- sm(combine_de_tables(sus_de, excel = glue::glue("excel/sus_tables-v{ver}.xlsx")))
sus_sig <- sm(extract_significant_genes(sus_table, excel = glue::glue("excel/sus_sig-v{ver}.xlsx")))
knitr::kable(head(sus_sig$deseq$ups$sensitive_vs_resistant, n = 20))
gid annotgeneproduct annotgenetype chromosome start end strand annotgeneentrezid annotgenename annotstrand annotchromosome annotcdslength length deseq_logfc deseq_adjp edger_logfc edger_adjp limma_logfc limma_adjp basic_nummed basic_denmed basic_numvar basic_denvar basic_logfc basic_t basic_p basic_adjp deseq_basemean deseq_lfcse deseq_stat deseq_p ebseq_fc ebseq_logfc ebseq_c1mean ebseq_c2mean ebseq_mean ebseq_var ebseq_postfc ebseq_ppee ebseq_ppde ebseq_adjp edger_logcpm edger_lr edger_p limma_ave limma_t limma_b limma_p limma_adjp_ihw deseq_adjp_ihw edger_adjp_ihw ebseq_adjp_ihw basic_adjp_ihw lfc_meta lfc_var lfc_varbymed p_meta p_var
LPAL13_000044900 LPAL13_000044900 actin-related protein 2, putative protein coding LPAL13_SCAF000645 507 1685 - reverse Not Assigned 1179.0 1178 28.010 0.0000 13.380 0.0000 8.2610 0.3530 3.6410 -4.2250 18.173 0.1055 7.865 8.404 0.0000 0.0000 870.40 1.3260 21.120 0e+00 120487.21 16.878 0.0000 1204.862 816.197 5.866e+05 296.832 1.0000 0e+00 1.0000 4.9370 48.24 0e+00 1.1310 1.3320 -4.511 0.1877 4.045e-01 4.406e-95 6.316e-09 0.000e+00 6.311e-06 13.800 8.923e+00 6.466e-01 6.257e-02 1.174e-02
LPAL13_000035800 LPAL13_000035800 hypothetical protein protein coding LPAL13_SCAF000500 737 1006 - reverse Not Assigned 270.0 269 14.540 0.0000 13.800 0.0000 9.8980 0.3753 4.7850 -3.9610 16.123 0.4540 8.746 9.699 0.0000 0.0000 2548.00 1.2930 11.250 0e+00 21845.10 14.415 0.1641 3803.389 2576.542 1.302e+07 946.975 0.0000 0e+00 0.0000 6.4810 73.28 0e+00 1.9270 1.2800 -4.547 0.2053 5.017e-01 1.134e-25 6.169e-14 0.000e+00 1.067e-06 15.610 7.949e+00 5.093e-01 6.843e-02 1.405e-02
LPAL13_320026300 LPAL13_320026300 hypothetical protein, conserved protein coding LpaL13_32 754268 755485 - reverse 32 1218.0 1217 13.980 0.0000 13.200 0.0000 9.1380 0.4066 4.4360 -4.0340 21.011 0.7598 8.469 8.163 0.0000 0.0000 1558.00 1.2680 11.020 0e+00 14426.16 13.816 0.1534 2357.791 1597.263 2.438e+06 561.074 0.0000 0e+00 0.0000 5.7730 63.40 0e+00 1.7870 1.2060 -4.600 0.2325 4.633e-01 8.686e-25 4.207e-12 0.000e+00 5.982e-06 11.990 9.684e-02 8.075e-03 7.750e-02 1.802e-02
LPAL13_000053200 LPAL13_000053200 hypothetical protein protein coding LPAL13_SCAF000804 5037 5249 - reverse Not Assigned 213.0 212 8.660 0.0000 10.060 0.0000 5.2360 0.0907 0.6563 -4.2250 10.158 0.1055 4.881 6.943 0.0000 0.0000 73.21 1.2520 6.916 0e+00 11962.59 13.546 0.0000 119.616 81.030 7.350e+03 30.186 1.0000 0e+00 1.0000 1.4230 39.59 0e+00 -1.1420 2.2900 -3.625 0.0255 1.234e-01 3.513e-09 1.142e-07 0.000e+00 3.370e-05 7.953 1.106e-01 1.391e-02 8.497e-03 2.166e-04
LPAL13_000051300 LPAL13_000051300 hypothetical protein, conserved protein coding LPAL13_SCAF000772 11 2344 + forward Not Assigned 2334.0 2333 8.421 0.0000 9.051 0.0000 2.9220 0.4366 -0.0057 -4.0020 11.186 0.6120 3.996 5.186 0.0000 0.0006 140.30 1.4020 6.004 0e+00 1405.97 10.457 0.1125 172.174 116.671 7.380e+04 47.638 0.0000 0e+00 0.0000 2.3610 26.08 0e+00 -1.2640 1.1420 -4.640 0.2578 4.942e-01 4.447e-07 2.656e-05 0.000e+00 5.676e-04 6.422 3.951e+00 6.152e-01 8.593e-02 2.215e-02
LPAL13_300029400 LPAL13_300029400 hypothetical protein, conserved protein coding LpaL13_30 853953 854150 - reverse 30 198.0 197 6.350 0.0000 6.260 0.0000 4.9050 0.0096 1.6480 -2.4720 1.706 1.8110 4.120 8.045 0.0000 0.0000 91.71 0.8385 7.573 0e+00 70.71 6.144 1.8871 134.139 91.477 1.183e+04 23.273 0.0000 0e+00 0.0000 1.6890 41.62 0e+00 -0.0924 3.4720 -1.678 0.0010 1.085e-02 3.899e-11 8.495e-08 0.000e+00 2.466e-05 5.921 3.575e-01 6.038e-02 3.172e-04 3.018e-07
LPAL13_000017600 LPAL13_000017600 hypothetical protein, conserved protein coding LPAL13_SCAF000146 359 586 + forward Not Assigned 228.0 227 6.343 0.0000 6.329 0.0000 5.7160 0.1190 4.2350 -0.9343 4.891 2.3477 5.170 7.560 0.0000 0.0000 615.40 0.7654 8.287 0e+00 67.17 6.070 14.2982 961.055 655.649 4.213e+05 53.926 0.0000 1e+00 0.0000 4.4350 43.58 0e+00 2.2210 2.1230 -3.643 0.0378 1.639e-01 4.969e-13 4.327e-08 1.000e+00 9.841e-06 6.530 2.115e+00 3.239e-01 1.261e-02 4.768e-04
LPAL13_000040700 LPAL13_000040700 hypothetical protein, conserved protein coding LPAL13_SCAF000598 54 1067 + forward Not Assigned 1014.0 1013 6.086 0.0002 7.545 0.0001 2.2580 0.2699 -1.5860 -4.2250 7.064 0.1055 2.639 4.480 0.0002 0.0024 21.07 1.3450 4.526 0e+00 2462.97 11.266 0.0000 24.620 16.678 4.281e+02 6.722 1.0000 0e+00 1.0000 -0.1668 22.03 0e+00 -2.5800 1.5540 -4.342 0.1254 3.637e-01 1.656e-04 1.006e-04 0.000e+00 2.020e-03 5.070 2.889e+00 5.697e-01 4.180e-02 5.241e-03
LPAL13_080010600 LPAL13_080010600 hypothetical protein, conserved protein coding LpaL13_08 195555 195749 - reverse 8 195.0 194 5.761 0.0002 7.165 0.0001 1.9980 0.1654 -2.1240 -4.2250 5.295 0.1055 2.101 4.099 0.0005 0.0045 10.31 1.2670 4.549 0e+00 1874.51 10.872 0.0000 18.735 12.691 5.733e+02 5.646 1.0000 0e+00 1.0000 -1.0520 21.83 0e+00 -3.3450 1.9120 -4.054 0.0606 1.910e-01 2.170e-04 1.080e-04 0.000e+00 3.759e-03 4.548 3.206e+00 7.050e-01 2.020e-02 1.224e-03
LPAL13_000011700 LPAL13_000011700 hypothetical protein protein coding LPAL13_SCAF000076 101 364 - reverse Not Assigned 264.0 263 5.750 0.0012 7.244 0.0003 2.5290 0.1359 -1.6090 -4.2250 7.713 0.1055 2.615 4.255 0.0003 0.0036 14.55 1.4560 3.949 1e-04 2510.78 11.294 0.0000 25.098 17.002 5.103e+02 6.951 1.0000 0e+00 1.0000 -0.6106 19.16 0e+00 -3.0780 2.0420 -3.913 0.0454 1.568e-01 1.191e-03 4.100e-04 0.000e+00 3.650e-03 4.970 1.691e+00 3.403e-01 1.517e-02 6.860e-04
LPAL13_040019400 LPAL13_040019400 hypothetical protein protein coding LpaL13_04 440768 441127 - reverse 4 360.0 359 5.537 0.0000 5.376 0.0000 3.6830 0.0383 -0.3080 -3.4550 1.856 1.2917 3.147 6.746 0.0000 0.0001 38.43 1.0170 5.443 0e+00 48.48 5.599 0.8221 40.331 27.586 2.402e+03 8.993 0.0000 0e+00 0.0000 0.4513 25.47 0e+00 -1.6730 2.7650 -3.064 0.0075 4.461e-02 4.997e-06 2.600e-05 0.000e+00 4.499e-05 4.932 1.457e-01 2.954e-02 2.501e-03 1.875e-05
LPAL13_350011800 LPAL13_350011800 hypothetical protein, conserved protein coding LpaL13_35 171009 171242 + forward 35 234.0 233 5.073 0.0000 5.050 0.0000 4.2060 0.0165 2.7180 -0.8548 2.746 0.1697 3.573 9.297 0.0000 0.0000 176.30 0.6435 7.884 0e+00 32.10 5.004 9.6863 311.202 213.939 7.486e+04 23.658 0.0000 1e+00 0.0000 2.6270 44.16 0e+00 1.0650 3.2010 -1.704 0.0022 2.243e-02 4.770e-12 3.061e-08 9.654e-01 1.067e-06 4.875 6.786e-01 1.392e-01 7.233e-04 1.570e-06
LPAL13_170014500 LPAL13_170014500 hypothetical protein, conserved protein coding LpaL13_17 361708 362040 + forward 17 333.0 332 4.837 0.0003 4.724 0.0027 2.1550 0.1443 -1.0540 -3.1350 7.247 1.7316 2.081 2.890 0.0072 0.0313 19.12 1.1180 4.326 0e+00 32.96 5.043 1.2101 40.206 27.627 1.665e+03 8.351 0.0000 0e+00 0.0000 -0.4863 13.64 2e-04 -2.6780 2.0050 -3.918 0.0494 1.662e-01 4.988e-04 2.706e-03 0.000e+00 3.142e-02 3.710 7.737e-01 2.086e-01 1.655e-02 8.096e-04
LPAL13_080010800 LPAL13_080010800 hypothetical protein protein coding LpaL13_08 199409 199792 - reverse 8 384.0 383 4.734 0.0014 6.247 0.0004 1.4160 0.3958 -2.3890 -4.2250 4.791 0.1055 1.836 3.757 0.0011 0.0084 11.62 1.2100 3.911 1e-04 1177.41 10.201 0.0000 11.764 7.969 1.362e+02 3.580 1.0000 0e+00 1.0000 -0.8327 18.69 0e+00 -3.1550 1.2300 -4.565 0.2233 4.546e-01 1.351e-03 4.919e-04 0.000e+00 9.317e-03 3.666 2.812e+00 7.671e-01 7.447e-02 1.661e-02
LPAL13_200050100 LPAL13_200050100 hypothetical protein protein coding LpaL13_20.1 1627529 1627717 + forward 20.1 189.0 188 4.612 0.0000 4.582 0.0000 4.7730 0.0082 2.4290 -2.0220 1.076 2.6699 4.452 7.891 0.0000 0.0001 121.70 0.6825 6.758 0e+00 25.40 4.667 8.1538 207.323 143.075 2.629e+04 17.527 0.0000 0e+00 0.0000 2.1250 33.62 0e+00 0.7007 3.5480 -1.353 0.0007 1.100e-02 1.324e-08 1.116e-06 0.000e+00 1.433e-04 4.649 1.629e+00 3.504e-01 2.497e-04 1.870e-07
LPAL13_000011800 LPAL13_000011800 hypothetical protein, conserved protein coding LPAL13_SCAF000076 446 640 - reverse Not Assigned 195.0 194 4.323 0.0034 4.677 0.0051 0.6508 0.6867 -2.5750 -3.9900 4.063 0.6650 1.416 2.776 0.0096 0.0385 12.47 1.1990 3.604 3e-04 51.35 5.682 0.1807 9.781 6.684 8.693e+01 2.840 0.9994 6e-04 0.9994 -0.8096 12.06 5e-04 -3.1110 0.6322 -4.846 0.5296 7.726e-01 3.336e-03 6.549e-03 1.369e-02 3.854e-02 2.849 3.412e+00 1.198e+00 1.768e-01 9.335e-02
LPAL13_000035500 LPAL13_000035500 hypothetical protein, conserved protein coding LPAL13_SCAF000492 7045 7410 + forward Not Assigned 366.0 365 4.245 0.0000 4.234 0.0000 3.8840 0.0982 4.4620 0.7273 2.742 0.4752 3.735 8.851 0.0000 0.0000 522.10 0.6605 6.427 0e+00 21.24 4.409 45.2429 961.289 665.790 4.244e+05 20.247 0.0000 1e+00 0.0000 4.2070 31.17 0e+00 2.6740 2.2390 -3.501 0.0288 1.141e-01 4.845e-08 3.871e-06 9.654e-01 6.768e-07 4.227 9.038e-01 2.138e-01 9.597e-03 2.763e-04
LPAL13_000014000 LPAL13_000014000 hypothetical protein protein coding LPAL13_SCAF000119 655 942 + forward Not Assigned 288.0 287 4.081 0.0000 4.066 0.0000 3.4080 0.0504 2.3010 -0.9661 1.686 1.4648 3.268 6.862 0.0000 0.0001 129.20 0.5882 6.937 0e+00 16.85 4.074 11.5358 194.496 135.477 1.427e+04 12.824 0.0000 1e+00 0.0000 2.2120 37.32 0e+00 1.0250 2.6200 -2.833 0.0111 5.709e-02 3.426e-09 2.680e-07 9.374e-01 8.178e-05 4.060 7.553e-01 1.860e-01 3.683e-03 4.070e-05
LPAL13_000026500 LPAL13_000026500 hypothetical protein protein coding LPAL13_SCAF000301 144 494 - reverse Not Assigned 351.0 350 3.991 0.0002 3.931 0.0008 1.8810 0.3831 -0.0450 -2.3340 6.192 2.0999 2.289 3.222 0.0033 0.0179 47.30 0.8778 4.546 0e+00 18.72 4.227 3.0706 57.668 40.056 1.815e+03 8.614 0.0000 0e+00 0.0000 0.8996 16.58 0e+00 -0.9806 1.2610 -4.595 0.2121 5.126e-01 1.558e-04 8.214e-04 0.000e+00 1.797e-02 3.084 3.055e-01 9.906e-02 7.072e-02 1.499e-02
LPAL13_220019500 LPAL13_220019500 hypothetical protein protein coding LpaL13_22 578260 578538 + forward 22 279.0 278 3.728 0.0000 3.718 0.0000 3.0580 0.1006 3.4430 0.4137 2.469 0.5415 3.029 7.310 0.0000 0.0000 293.40 0.5593 6.666 0e+00 14.01 3.808 32.1428 450.373 315.460 8.620e+04 12.863 0.0000 1e+00 0.0000 3.3810 35.24 0e+00 2.2920 2.2240 -3.505 0.0298 1.381e-01 1.324e-08 8.333e-07 9.374e-01 5.624e-06 3.660 5.323e-01 1.454e-01 9.943e-03 2.966e-04
knitr::kable(head(sus_sig$deseq$downs$sensitive_vs_resistant, n = 20))
gid annotgeneproduct annotgenetype chromosome start end strand annotgeneentrezid annotgenename annotstrand annotchromosome annotcdslength length deseq_logfc deseq_adjp edger_logfc edger_adjp limma_logfc limma_adjp basic_nummed basic_denmed basic_numvar basic_denvar basic_logfc basic_t basic_p basic_adjp deseq_basemean deseq_lfcse deseq_stat deseq_p ebseq_fc ebseq_logfc ebseq_c1mean ebseq_c2mean ebseq_mean ebseq_var ebseq_postfc ebseq_ppee ebseq_ppde ebseq_adjp edger_logcpm edger_lr edger_p limma_ave limma_t limma_b limma_p limma_adjp_ihw deseq_adjp_ihw edger_adjp_ihw ebseq_adjp_ihw basic_adjp_ihw lfc_meta lfc_var lfc_varbymed p_meta p_var
LPAL13_000033300 LPAL13_000033300 hypothetical protein, conserved protein coding LPAL13_SCAF000463 551 811 + forward Not Assigned 261.0 260 -4.504 0.0070 -4.456 0.0091 -5.418 0.0008 -3.3890 3.4650 11.9880 0.0692 -6.854 -9.018 0e+00 0.0000 145.00 1.3510 -3.334 0.0009 0.1473 -2.763 334.10 49.211 141.11 2.626e+04 0.1572 0.0000 0.0000 0.0000 2.3450 10.580 0.0011 -0.8790 -4.596 1.8400 0.0000 8.912e-04 7.024e-03 9.134e-03 0.000e+00 2.773e-06 -4.793 0.000e+00 0.000e+00 6.730e-04 3.382e-07
LPAL13_350063000 LPAL13_350063000 hypothetical protein protein coding LpaL13_35 1964328 1964543 - reverse 35 216.0 215 -2.512 0.0000 -2.508 0.0000 -3.193 0.0000 -2.1690 1.1700 1.8625 0.2316 -3.339 -9.984 0e+00 0.0000 22.70 0.5013 -5.011 0.0000 0.1525 -2.713 57.00 8.684 24.27 6.867e+02 0.1773 0.0000 1.0000 0.0000 -0.3296 24.650 0.0000 -1.4050 -5.953 4.9380 0.0000 5.034e-05 2.800e-05 3.518e-05 9.654e-01 3.167e-07 -2.765 4.934e-03 -1.784e-03 4.554e-07 8.173e-14
LPAL13_000038400 LPAL13_000038400 expression-site associated gene (esag3), putative protein coding LPAL13_SCAF000573 101 1360 + forward Not Assigned 1260.0 1259 -2.423 0.0004 -2.436 0.0003 -3.096 0.0009 4.8300 8.2430 3.4691 0.0311 -3.413 -8.320 0e+00 0.0000 4056.00 0.5625 -4.308 0.0000 0.1984 -2.333 9497.20 1884.665 4340.32 1.809e+07 0.2036 0.0041 0.9959 0.0041 7.1510 19.200 0.0000 5.9840 -4.556 2.2780 0.0000 8.078e-04 3.599e-04 2.776e-04 1.000e+00 5.556e-06 -2.668 7.259e-04 -2.720e-04 1.785e-05 4.702e-11
LPAL13_140019300 LPAL13_140019300 bt1 family, putative protein coding LpaL13_14 530784 531350 + forward 14 567.0 566 -2.404 0.0000 -2.412 0.0000 -2.304 0.0001 4.7300 7.1060 0.5266 1.2139 -2.377 -6.210 0e+00 0.0007 2043.00 0.4233 -5.680 0.0000 0.1739 -2.524 5153.16 896.019 2269.29 6.616e+06 0.1790 0.0000 1.0000 0.0000 6.1610 36.940 0.0000 5.4500 -5.675 6.2410 0.0000 6.916e-05 2.037e-06 2.981e-07 9.721e-01 6.951e-04 -2.426 1.344e-01 -5.541e-02 1.382e-07 5.141e-14
LPAL13_310039200 LPAL13_310039200 hypothetical protein protein coding LpaL13_31 1301745 1301972 - reverse 31 228.0 227 -2.365 0.0000 -2.374 0.0000 -2.221 0.0009 1.2770 3.6780 1.5657 0.1132 -2.401 -8.193 0e+00 0.0000 206.20 0.4475 -5.286 0.0000 0.2907 -1.782 388.76 113.020 201.97 3.130e+04 0.3039 0.6977 0.3023 0.6977 2.8640 30.930 0.0000 2.0860 -4.529 2.3810 0.0000 1.047e-03 1.525e-05 3.270e-06 3.606e-01 2.773e-06 -2.358 1.602e-01 -6.795e-02 9.304e-06 2.555e-10
LPAL13_000012000 LPAL13_000012000 hypothetical protein protein coding LPAL13_SCAF000080 710 1159 - reverse Not Assigned 450.0 449 -2.230 0.0045 -2.239 0.0024 -2.507 0.0229 0.5477 3.9890 7.6848 0.1885 -3.441 -5.548 0e+00 0.0004 233.40 0.6365 -3.504 0.0005 0.2564 -1.964 497.60 127.578 246.94 5.850e+04 0.2678 0.2261 0.7739 0.2261 3.0330 13.970 0.0002 1.6770 -3.036 -1.8890 0.0035 2.624e-02 4.497e-03 3.182e-03 7.867e-01 3.726e-04 -2.325 4.070e-02 -1.750e-02 1.385e-03 3.406e-06
LPAL13_310031000 LPAL13_310031000 hypothetical protein, conserved protein coding LpaL13_31 1075172 1075459 - reverse 31 288.0 287 -2.130 0.0001 -2.318 0.0000 -2.622 0.0005 -1.6880 0.9482 3.1681 0.5642 -2.637 -5.791 0e+00 0.0001 28.86 0.4397 -4.843 0.0000 0.3251 -1.621 57.85 18.798 31.40 1.200e+03 0.3516 0.6385 0.3615 0.6385 0.0980 27.610 0.0000 -1.0560 -4.824 2.2340 0.0000 6.313e-04 5.455e-05 1.116e-05 3.844e-01 1.199e-04 -2.347 2.712e-02 -1.155e-02 3.690e-06 2.689e-11
LPAL13_140019100 LPAL13_140019100 bt1 family, putative protein coding LpaL13_14 525164 525514 + forward 14 351.0 350 -1.931 0.0000 -1.938 0.0000 -1.988 0.0000 3.8960 6.0140 0.4121 0.6077 -2.118 -7.470 0e+00 0.0001 942.10 0.3337 -5.788 0.0000 0.2279 -2.133 2123.48 484.016 1012.87 8.904e+05 0.2321 0.0000 1.0000 0.0000 5.0450 40.060 0.0000 4.6010 -6.309 8.6430 0.0000 2.849e-05 1.111e-06 1.031e-07 9.669e-01 8.680e-05 -1.980 1.012e-01 -5.111e-02 1.384e-08 3.207e-16
LPAL13_000012100 LPAL13_000012100 hypothetical protein protein coding LPAL13_SCAF000080 1637 1894 - reverse Not Assigned 258.0 257 -1.915 0.0334 -1.922 0.0324 -2.822 0.0053 -1.9250 1.1810 6.1476 0.7484 -3.106 -5.123 0e+00 0.0005 34.08 0.7101 -2.697 0.0070 0.3103 -1.688 70.75 21.945 37.69 2.259e+03 0.3428 0.1419 0.8581 0.1419 0.2875 7.434 0.0064 -1.2630 -3.757 -0.4155 0.0004 5.953e-03 3.345e-02 3.191e-02 8.560e-01 5.444e-04 -2.232 2.045e-02 -9.161e-03 4.594e-03 1.338e-05
LPAL13_340039600 LPAL13_340039600 hypothetical protein protein coding LpaL13_34 1247554 1247757 - reverse 34 204.0 203 -1.888 0.0022 -1.898 0.0012 -2.235 0.0084 1.4450 4.2360 3.3827 0.0499 -2.791 -6.848 0e+00 0.0000 245.70 0.5037 -3.749 0.0002 0.2426 -2.043 569.47 138.142 277.28 5.427e+04 0.2480 0.0000 1.0000 0.0000 3.0980 15.690 0.0001 2.1550 -3.532 -0.6309 0.0008 9.586e-03 2.198e-03 1.165e-03 9.654e-01 4.562e-05 -2.034 1.216e-02 -5.979e-03 3.468e-04 1.487e-07
LPAL13_310031300 LPAL13_310031300 hypothetical protein, conserved protein coding LpaL13_31 1084772 1085059 - reverse 31 288.0 287 -1.740 0.0189 -1.745 0.0185 -2.897 0.0034 -1.0220 1.9180 4.2414 0.5013 -2.940 -5.855 0e+00 0.0001 64.63 0.5905 -2.947 0.0032 0.3268 -1.613 114.26 37.337 62.15 3.847e+03 0.3505 0.3354 0.6646 0.3354 1.2040 8.861 0.0029 -0.2008 -3.946 0.2801 0.0002 3.931e-03 2.683e-02 2.372e-02 6.860e-01 1.203e-04 -2.098 1.102e-01 -5.252e-02 2.111e-03 2.743e-06
LPAL13_050005000 LPAL13_050005000 hypothetical protein protein coding LpaL13_05 3394 3612 - reverse 5 219.0 218 -1.729 0.0368 -1.738 0.0286 -2.611 0.0027 0.1637 2.6120 2.4370 0.1404 -2.448 -6.788 0e+00 0.0000 96.84 0.6522 -2.650 0.0080 0.3127 -1.677 180.74 56.508 96.58 6.519e+03 0.3232 0.0055 0.9945 0.0055 1.7580 7.761 0.0053 0.4879 -4.068 0.8488 0.0001 3.099e-03 3.679e-02 3.807e-02 9.791e-01 3.283e-05 -1.980 2.139e-02 -1.080e-02 4.505e-03 1.613e-05
LPAL13_340039700 LPAL13_340039700 snare domain containing protein, putative protein coding LpaL13_34 1248192 1248947 - reverse 34 756.0 755 -1.557 0.0001 -1.566 0.0000 -1.742 0.0001 4.6900 6.6660 0.7805 0.0554 -1.977 -9.565 0e+00 0.0000 1492.00 0.3243 -4.802 0.0000 0.3017 -1.729 3050.36 920.141 1607.31 1.346e+06 0.3058 0.0001 0.9999 0.0001 5.7080 27.180 0.0000 5.3190 -5.454 5.4250 0.0000 1.000e-04 6.443e-05 1.300e-05 9.506e-01 5.982e-07 -1.665 1.815e-02 -1.090e-02 8.951e-07 4.816e-13
LPAL13_040007800 LPAL13_040007800 hypothetical protein, conserved protein coding LpaL13_04 77524 78306 + forward 4 783.0 782 -1.472 0.0000 -1.481 0.0000 -1.327 0.0001 6.4970 7.7730 0.1173 0.4170 -1.275 -5.865 1e-04 0.0014 4344.00 0.2563 -5.745 0.0000 0.3607 -1.471 7519.30 2712.403 4263.02 9.689e+06 0.3659 0.0002 0.9998 0.0002 7.2500 41.510 0.0000 7.0160 -5.559 5.7890 0.0000 8.891e-05 1.403e-06 8.301e-08 1.000e+00 1.713e-03 -1.475 9.708e-02 -6.583e-02 2.102e-07 1.267e-13
LPAL13_170015400 LPAL13_170015400 hypothetical protein, conserved protein coding LpaL13_17 395975 396307 + forward 17 333.0 332 -1.471 0.0001 -1.480 0.0001 -1.588 0.0024 1.3290 3.1710 1.0588 0.0350 -1.842 -7.933 0e+00 0.0000 162.10 0.3162 -4.652 0.0000 0.3712 -1.430 264.81 98.292 152.01 1.093e+04 0.3763 0.0000 1.0000 0.0000 2.5070 21.670 0.0000 2.1060 -4.114 1.0820 0.0001 2.769e-03 1.792e-04 1.151e-04 9.374e-01 5.982e-06 -1.579 1.517e-02 -9.610e-03 4.128e-05 4.334e-09
LPAL13_350073400 LPAL13_350073400 hypothetical protein protein coding LpaL13_35 2342701 2342883 + forward 35 183.0 182 -1.422 0.0237 -1.428 0.0286 -2.011 0.0031 -0.0868 1.8030 1.0264 0.9772 -1.890 -4.936 1e-04 0.0015 51.13 0.4994 -2.847 0.0044 0.3131 -1.675 124.94 39.114 66.80 8.632e+03 0.3400 0.0019 0.9981 0.0019 0.7997 7.760 0.0053 -0.0785 -3.994 0.5267 0.0002 3.520e-03 3.385e-02 2.831e-02 1.000e+00 1.541e-03 -1.627 5.880e-04 -3.615e-04 3.309e-03 7.577e-06
LPAL13_340016200 LPAL13_340016200 nadh-dependent fumarate reductase, putative protein coding LpaL13_34 396984 398009 + forward 34 1026.0 1025 -1.392 0.0000 -1.399 0.0000 -1.468 0.0000 4.5730 5.9380 0.2396 0.2268 -1.365 -7.391 0e+00 0.0000 1000.00 0.2302 -6.048 0.0000 0.3960 -1.337 1890.93 748.759 1117.20 5.033e+05 0.3998 0.0000 1.0000 0.0000 5.1310 39.150 0.0000 4.8980 -6.903 10.8900 0.0000 8.385e-06 5.056e-07 1.808e-07 9.489e-01 3.350e-05 -1.498 1.307e-02 -8.722e-03 1.710e-09 2.123e-18
LPAL13_320038700 LPAL13_320038700 hypothetical protein, conserved protein coding LpaL13_32 1175024 1175257 + forward 32 234.0 233 -1.389 0.0000 -1.398 0.0000 -1.403 0.0002 2.5630 3.9230 0.4803 0.1093 -1.361 -7.402 0e+00 0.0000 277.00 0.2560 -5.425 0.0000 0.4313 -1.213 459.38 198.144 282.41 2.456e+04 0.4357 0.0073 0.9927 0.0073 3.2820 30.670 0.0000 3.0340 -5.189 4.6000 0.0000 2.364e-04 7.194e-06 3.557e-06 9.634e-01 5.822e-06 -1.425 2.173e-02 -1.526e-02 8.675e-07 2.033e-12
LPAL13_230021300 LPAL13_230021300 hypothetical protein, conserved protein coding LpaL13_23 513359 513691 + forward 23 333.0 332 -1.364 0.0046 -1.367 0.0030 -1.623 0.0228 0.9943 2.5460 0.5807 0.3004 -1.551 -6.459 0e+00 0.0001 143.40 0.3898 -3.498 0.0005 0.4141 -1.272 173.67 71.917 104.74 5.745e+03 0.4215 0.0000 1.0000 0.0000 2.3520 13.340 0.0003 1.7190 -3.040 -1.8510 0.0035 2.610e-02 4.558e-03 3.927e-03 9.374e-01 4.499e-05 -1.455 8.533e-05 -5.863e-05 1.402e-03 3.238e-06
LPAL13_140019200 LPAL13_140019200 inositol-3-phosphate synthase protein coding LpaL13_14 527711 529291 + INO1 forward 14 1581.0 1580 -1.356 0.0001 -1.365 0.0000 -1.426 0.0001 8.8430 10.4600 0.1893 0.4665 -1.619 -6.861 0e+00 0.0004 20630.00 0.2895 -4.684 0.0000 0.3429 -1.544 40652.04 13937.657 22555.20 2.313e+08 0.3457 0.0000 1.0000 0.0000 9.4970 32.430 0.0000 9.2670 -5.524 5.7440 0.0000 9.605e-05 9.872e-05 1.943e-06 1.000e+00 3.611e-04 -1.383 8.392e-03 -6.066e-03 1.178e-06 2.124e-12
sus_ma <- sus_table[["plots"]][["sensitive_vs_resistant"]][["deseq_ma_plots"]][["plot"]]
pp(file = "images/sus_ma.png", image = sus_ma)

## test <- ggplt(sus_ma)

5.4 Ontology searches

Now let us look for ontology categories which are increased in the 2.3 samples followed by the 2.2 samples.

## Gene categories more represented in the 2.3 group.
zy_go_up <- sm(simple_goseq(sig_genes = zy_sig[["deseq"]][["ups"]][[1]],
                            go_db = lp_go, length_db = lp_lengths))

## Gene categories more represented in the 2.2 group.
zy_go_down <- sm(simple_goseq(sig_genes = zy_sig[["deseq"]][["downs"]][[1]],
                              go_db = lp_go, length_db = lp_lengths))

5.4.1 A couple plots from the differential expression

5.4.1.1 Number of genes in agreement among DE methods, 2.3 more than 2.2

In the function ‘combined_de_tables()’ above, one of the tasks performed is to look at the agreement among DESeq2, limma, and edgeR. The following show a couple of these for the set of genes observed with a fold-change >= |2| and adjusted p-value <= 0.05.

zy_table[["venns"]][[1]][["p_lfc1"]][["up_noweight"]]

5.4.1.2 Number of genes in agreement among DE methods, 2.2 more than 2.3

zy_table[["venns"]][[1]][["p_lfc1"]][["down_noweight"]]

5.4.1.3 goseq ontology plots of groups of genes, 2.3 more than 2.2

zy_go_up$pvalue_plots$bpp_plot_over

5.4.1.4 goseq ontology plots of groups of genes, 2.2 more than 2.3

zy_go_down$pvalue_plots$bpp_plot_over

5.5 Look for agreement between sensitivity and zymodemes

Remind myself, the data structures are (zy|sus)_(de|table|sig).

zy_df <- zy_table[["data"]][["z23_vs_z22"]]
sus_df <- sus_table[["data"]][["sensitive_vs_resistant"]]

both_df <- merge(zy_df, sus_df, by = "row.names")
plot_df <- both_df[, c("deseq_logfc.x", "deseq_logfc.y")]
rownames(plot_df) <- both_df[["Row.names"]]
colnames(plot_df) <- c("z23_vs_z22", "sensitive_vs_resistant")

compare <- plot_linear_scatter(plot_df)
## Warning in plot_multihistogram(df): NAs introduced by coercion
pp(file = "images/compare_sus_zy.png", image = compare$scatter)

compare$cor
## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = -174, df = 8542, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.8881 -0.8788
## sample estimates:
##     cor 
## -0.8836

5.6 Zymodeme enzyme gene IDs

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

They are:

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

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

5.6.1 Expression levels of zymodeme genes

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

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

zymo_expt <- exclude_genes_expt(zy_norm, ids = my_genes, method = "keep")
## Before removal, there were 8544 genes, now there are 6.
## There are 29 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.1309    0.1246    0.1318    0.1057    0.1298    0.1099    0.1127    0.1162 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.1152    0.1178    0.1145    0.1134    0.1097    0.1058    0.1100    0.1204 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20021 TMRC20022 TMRC20053 TMRC20052 
##    0.1203    0.1062    0.1088    0.1144    0.1060    0.1304    0.1180    0.1103 
## TMRC20064 TMRC20051 TMRC20050 TMRC20062 TMRC20054 
##    0.1137    0.1279    0.1151    0.1282    0.1275
zymo_heatmap <- plot_sample_heatmap(zymo_expt, row_label = my_names)
zymo_heatmap

5.7 Empirically observed Zymodeme genes from differential expression analysis

In contrast, the following plots take the set of genes which are shared among all differential expression methods (|lfc| >= 1.0 and adjp <= 0.05) and use them to make categories of genes which are increased in 2.3 or 2.2.

shared_zymo <- intersect_significant(zy_table)
## Deleting the file excel/intersect_significant.xlsx before writing the tables.
up_shared <- shared_zymo[["ups"]][[1]][["data"]][["all"]]
rownames(up_shared)
##  [1] "LPAL13_000033300" "LPAL13_000012000" "LPAL13_310031300" "LPAL13_000038400"
##  [5] "LPAL13_000038500" "LPAL13_000012100" "LPAL13_340039600" "LPAL13_050005000"
##  [9] "LPAL13_310031000" "LPAL13_310039200" "LPAL13_210015500" "LPAL13_350063000"
## [13] "LPAL13_140019300" "LPAL13_270034100" "LPAL13_340039700" "LPAL13_180013900"
## [17] "LPAL13_170015400" "LPAL13_350013200" "LPAL13_140019100" "LPAL13_330021800"
## [21] "LPAL13_240009700" "LPAL13_140019200" "LPAL13_330021900" "LPAL13_250025700"
## [25] "LPAL13_320038700" "LPAL13_210005000" "LPAL13_000052700" "LPAL13_350073200"
## [29] "LPAL13_230011400" "LPAL13_310028500" "LPAL13_230011200" "LPAL13_310032500"
## [33] "LPAL13_230011500" "LPAL13_040007800" "LPAL13_300031600" "LPAL13_230011300"
## [37] "LPAL13_000010600" "LPAL13_110015700" "LPAL13_230011600"
upshared_expt <- exclude_genes_expt(zy_norm, ids = rownames(up_shared), method = "keep")
## Before removal, there were 8544 genes, now there are 39.
## There are 29 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.3545    0.4356    0.1178    0.4012    0.1655    0.4374    0.5572    0.3396 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.3829    0.1645    0.4265    0.1429    0.4065    0.3056    0.1531    0.1272 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20021 TMRC20022 TMRC20053 TMRC20052 
##    0.3744    0.1659    0.1624    0.3562    0.3943    0.1420    0.1856    0.4531 
## TMRC20064 TMRC20051 TMRC20050 TMRC20062 TMRC20054 
##    0.4197    0.6309    0.1624    0.6503    0.5515

We can plot a quick heatmap to get a sense of the differences observed between the genes which are different between the two zymodemes.

5.7.1 Heatmap of zymodeme gene expression increased in 2.3 vs. 2.2

high_23_heatmap <- plot_sample_heatmap(upshared_expt, row_label = rownames(up_shared))
high_23_heatmap

5.7.2 Heatmap of zymodeme gene expression increased in 2.2 vs. 2.3

down_shared <- shared_zymo[["downs"]][[1]][["data"]][["all"]]
downshared_expt <- exclude_genes_expt(zy_norm, ids = rownames(down_shared), method = "keep")
## Before removal, there were 8544 genes, now there are 68.
## There are 29 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.1901    0.1825    0.6478    0.2105    0.6455    0.1951    0.1864    0.2296 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.1877    0.6764    0.1808    0.6169    0.1643    0.2087    0.5629    0.5490 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20021 TMRC20022 TMRC20053 TMRC20052 
##    0.1598    0.6316    0.6411    0.1508    0.1488    0.6381    0.5372    0.1660 
## TMRC20064 TMRC20051 TMRC20050 TMRC20062 TMRC20054 
##    0.1832    0.1744    0.5981    0.1720    0.1829
high_22_heatmap <- plot_sample_heatmap(downshared_expt, row_label = rownames(down_shared))
high_22_heatmap

6 SNP profiles

Now I will combine our previous samples and our new samples in the hopes of finding variant positions which help elucidate currently unknown aspects of either group via their clustering to known samples from the other group. In other words, we do not know the zymodeme annotations for the old samples nor the strain identities (or the shortcut ‘chronic vs. self-healing’) for the new samples. I hope to make educated guesses given the variant profiles. There are some differences in how the previous and current data sets were analyzed (though I have since redone the old samples so it should be trivial to remove those differences now).

I added our 2016 data to a specific TMRC2 sample sheet, dated 20191203. Thus I will load the data here. That previous data was mapped using tophat, so I will also need to make some changes to the gene names to accomodate the two mappings.

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

tt <- lp_expt[["expressionset"]]
rownames(tt) <- gsub(pattern = "^exon_", replacement = "", x = rownames(tt))
rownames(tt) <- gsub(pattern = "\\.E1$", replacement = "", x = rownames(tt))
lp_expt$expressionset <- tt

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

6.1 Create the SNP expressionset

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

## The next line drops the samples which are missing the SNP pipeline.
lp_snp <- subset_expt(lp_expt, subset="!is.na(pData(lp_expt)[['bcftable']])")
## subset_expt(): There were 63, now there are 46 samples.
new_snps <- sm(count_expt_snps(lp_snp, annot_column = "bcftable"))
old_snps <- sm(count_expt_snps(old_expt, annot_column = "bcftable", snp_column = 2))

both_snps <- combine_expts(new_snps, old_snps)
both_norm <- sm(normalize_expt(both_snps, transform = "log2", convert = "cpm", filter = TRUE))

## strains <- both_norm[["design"]][["strain"]]
both_strain <- set_expt_conditions(both_norm, fact = "strain")

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

6.2 Plot of SNP profiles for zymodemes

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

old_new_variant_heatmap <- plot_disheat(both_norm)
pp(file = "images/raw_snp_disheat.png", image = old_new_variant_heatmap,
   height = 12, width = 12)

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

snp_sets <- get_snp_sets(both_snps, factor = "condition")
## The factor z2.3 has 14 rows.
## The factor z2.2 has 11 rows.
## The factor unknown has 21 rows.
## The factor sh has 13 rows.
## The factor chr has 14 rows.
## The factor inf has 6 rows.
## Iterating over 727 elements.
both_expt <- combine_expts(lp_expt, old_expt)

snp_genes <- sm(snps_vs_genes(both_expt, snp_sets, expt_name_col = "chromosome"))
## I think we have some metrics here we can plot...
snp_subset <- sm(snp_subset_genes(
  both_expt, both_snps,
  genes = c("LPAL13_120010900", "LPAL13_340013000", "LPAL13_000054100",
            "LPAL13_140006100", "LPAL13_180018500", "LPAL13_320022300")))
zymo_heat <- plot_sample_heatmap(snp_subset, row_label = rownames(exprs(snp_subset)))
zymo_heat

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

6.3 SNPS associated with clinical response in the TMRC samples

clinical_sets <- get_snp_sets(new_snps, factor = "clinicalresponse")
## The factor cure has 17 rows.
## The factor failure has 15 rows.
## The factor laboratory line has only 1 row.
## The factor nd has 3 rows.
## The factor reference strain has 3 rows.
## The factor unknown has 7 rows.
## Iterating over 693 elements.
density_vec <- clinical_sets[["density"]]
chromosome_idx <- grep(pattern = "LpaL", x = names(density_vec))
density_df <- as.data.frame(density_vec[chromosome_idx])
density_df[["chr"]] <- rownames(density_df)
colnames(density_df) <- c("density_vec", "chr")
ggplot(density_df, aes_string(x = "chr", y = "density_vec")) +
  ggplot2::geom_col() +
  ggplot2::theme(axis.text = ggplot2::element_text(size = 10, colour = "black"),
                 axis.text.x = ggplot2::element_text(angle = 90, vjust = 0.5))

## clinical_written <- write_variants(new_snps)

6.3.1 Cross reference these variants by gene

clinical_genes <- sm(snps_vs_genes(lp_expt, clinical_sets, expt_name_col = "chromosome"))

snp_density <- merge(as.data.frame(clinical_genes[["summary_by_gene"]]),
                     as.data.frame(fData(lp_expt)),
                     by = "row.names")
snp_density <- snp_density[, c(1, 2, 4, 15)]
colnames(snp_density) <- c("name", "snps", "product", "length")
snp_density[["product"]] <- tolower(snp_density[["product"]])
snp_density[["length"]] <- as.numeric(snp_density[["length"]])
snp_density[["density"]] <- snp_density[["snps"]] / snp_density[["length"]]
snp_idx <- order(snp_density[["density"]], decreasing = TRUE)
snp_density <- snp_density[snp_idx, ]

removers <- c("amastin", "gp63", "leishmanolysin")
for (r in removers) {
  drop_idx <- grepl(pattern = r, x = snp_density[["product"]])
  snp_density <- snp_density[!drop_idx, ]
}
## Filter these for [A|a]mastin gp63 Leishmanolysin
clinical_snps <- snps_intersections(lp_expt, clinical_sets, chr_column = "chromosome")

fail_ref_snps <- as.data.frame(clinical_snps[["inters"]][["failure, reference strain"]])
cure_snps <- as.data.frame(clinical_snps[["inters"]][["cure"]])

head(fail_ref_snps)
##                                       seqnames  start    end width strand
## chr_LpaL13-10_pos_233490_ref_C_alt_G LpaL13-10 233490 233491     2      +
## chr_LpaL13-15_pos_42885_ref_A_alt_G  LpaL13-15  42885  42886     2      +
## chr_LpaL13-24_pos_163196_ref_C_alt_A LpaL13-24 163196 163197     2      +
## chr_LpaL13-31_pos_852703_ref_C_alt_A LpaL13-31 852703 852704     2      +
head(cure_snps)
##                                       seqnames  start    end width strand
## chr_LpaL13-01_pos_169299_ref_A_alt_G LpaL13-01 169299 169300     2      +
## chr_LpaL13-08_pos_184791_ref_T_alt_A LpaL13-08 184791 184792     2      +
## chr_LpaL13-10_pos_347757_ref_A_alt_C LpaL13-10 347757 347758     2      +
## chr_LpaL13-11_pos_433123_ref_C_alt_T LpaL13-11 433123 433124     2      +
## chr_LpaL13-15_pos_47170_ref_G_alt_C  LpaL13-15  47170  47171     2      +
## chr_LpaL13-16_pos_456493_ref_A_alt_G LpaL13-16 456493 456494     2      +
annot <- fData(lp_expt)
clinical_interest <- as.data.frame(clinical_snps[["gene_summaries"]][["cure"]])
clinical_interest <- merge(clinical_interest,
                           as.data.frame(clinical_snps[["gene_summaries"]][["failure, reference strain"]]),
                           by = "row.names")
rownames(clinical_interest) <- clinical_interest[["Row.names"]]
clinical_interest[["Row.names"]] <- NULL
colnames(clinical_interest) <- c("cure_snps","fail_snps")
annot <- merge(annot, clinical_interest, by = "row.names")
rownames(annot) <- annot[["Row.names"]]
annot[["Row.names"]] <- NULL
fData(lp_expt$expressionset) <- annot

7 Zymodeme for new samples

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

7.1 Hunt for snp clusters

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

new_sets <- get_snp_sets(new_snps, factor = "phenotypiccharacteristics")
## The factor 22 has 11 rows.
## The factor 23 has 14 rows.
## The factor laboratory line has only 1 row.
## The factor notapplicable has 17 rows.
## The factor reference strain has 3 rows.
## Iterating over 693 elements.
summary(new_sets)
##               Length Class      Mode     
## medians         6    data.frame list     
## possibilities   5    -none-     character
## intersections  31    -none-     list     
## chr_data      693    -none-     list     
## set_names      32    -none-     list     
## invert_names   32    -none-     list     
## density       693    -none-     numeric
## 1000000: 2.2
## 0100000: 2.3

summary(new_sets[["intersections"]][["10000"]])
##    Length     Class      Mode 
##       511 character character
summary(new_sets[["intersections"]][["01000"]])
##    Length     Class      Mode 
##     49790 character character

Thus we see that there are 511 variants associated with 2.2 and 49,790 associated with 2.3.

7.1.1 A small function for searching for potential PCR primers

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

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

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

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

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

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

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

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

zymo22_sequentials <- sequential_variants(new_sets, conditions = "22")
## There are 75 candidate regions.
## The maximum sequential set is: 3.
dim(zymo22_sequentials)
## [1] 7 2
## 7 candidate regions for zymodeme 2.2 -- thus I am betting that the reference strain is a 2.2
zymo23_sequentials <- sequential_variants(new_sets, conditions = "23",
                                          minimum = 1, maximum_separation = 3)
## There are 587 candidate regions.
## The maximum sequential set is: 1.
dim(zymo23_sequentials)
## [1] 587   2
## In contrast, there are lots (587) of interesting regions for 2.3!

7.2 Make a heatmap describing the clustering of variants

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

snp_genes <- sm(snps_vs_genes(lp_expt, new_sets, expt_name_col = "chromosome"))
new_zymo_norm  <- normalize_expt(new_snps, filter = TRUE, convert = "cpm", norm = "quant", transform = TRUE)
## Removing 0 low-count genes (558524 remaining).
## transform_counts: Found 11978651 values equal to 0, adding 1 to the matrix.
new_zymo_norm <- set_expt_conditions(new_zymo_norm, fact = "phenotypiccharacteristics")

zymo_heat <- plot_disheat(new_zymo_norm)
zymo_heat[["plot"]]

7.2.1 Annotated heatmap of variants

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

des <- both_norm[["design"]]
undef_idx <- is.na(des[["strain"]])
des[undef_idx, "strain"] <- "unknown"

##hmcols <- colorRampPalette(c("yellow","black","darkblue"))(256)
correlations <- hpgl_cor(exprs(both_norm))

zymo_missing_idx <- is.na(des[["phenotypiccharacteristics"]])
des[["phenotypiccharacteristics"]] <- as.character(des[["phenotypiccharacteristics"]])
des[["clinicalcategorical"]] <- as.character(des[["clinicalcategorical"]])
des[zymo_missing_idx, "phenotypiccharacteristics"] <- "unknown"
mydendro <- list(
  "clustfun" = hclust,
  "lwd" = 2.0)
col_data <- as.data.frame(des[, c("phenotypiccharacteristics", "clinicalcategorical")])

unknown_clinical <- is.na(col_data[["clinicalcategorical"]])
row_data <- as.data.frame(des[, c("strain")])
colnames(col_data) <- c("zymodeme", "outcome")
col_data[unknown_clinical, "outcome"] <- "undefined"

colnames(row_data) <- c("strain")
myannot <- list(
  "Col" = list("data" = col_data),
  "Row" = list("data" = row_data))
myclust <- list("cuth" = 1.0,
                "col" = BrewerClusterCol)
mylabs <- list(
  "Row" = list("nrow" = 4),
  "Col" = list("nrow" = 4))
hmcols <- colorRampPalette(c("darkblue", "beige"))(240)
map1 <- annHeatmap2(
  correlations,
  dendrogram = mydendro,
  annotation = myannot,
  cluster = myclust,
  labels = mylabs,
  ## The following controls if the picture is symmetric
  scale = "none",
  col = hmcols)
## Warning in breakColors(breaks, col): more colors than classes: ignoring 29 last
## colors
pp(file = "images/dendro_heatmap.png", image = map1, height = 20, width = 20)
## annotated Heatmap
## 
## Rows: 'dendrogram' with 2 branches and 79 members total, at height 5.258 
##   11  annotation variable(s)
## Cols: 'dendrogram' with 2 branches and 79 members total, at height 5.258 
##   10  annotation variable(s)

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

big heatmap

pheno <- subset_expt(lp_expt, subset = "condition=='z2.2'|condition=='z2.3'")
## subset_expt(): There were 63, now there are 29 samples.
pheno <- subset_expt(pheno, subset="!is.na(pData(pheno)[['bcftable']])")
## subset_expt(): There were 29, now there are 25 samples.
pheno_snps <- sm(count_expt_snps(pheno, annot_column = "bcftable"))

xref_prop <- table(pheno_snps[["conditions"]])
pheno_snps$conditions
##  [1] "z2.3" "z2.2" "z2.2" "z2.3" "z2.3" "z2.2" "z2.3" "z2.2" "z2.3" "z2.3"
## [11] "z2.2" "z2.2" "z2.3" "z2.2" "z2.2" "z2.3" "z2.3" "z2.2" "z2.2" "z2.3"
## [21] "z2.3" "z2.3" "z2.2" "z2.3" "z2.3"
idx_tbl <- exprs(pheno_snps) > 5
new_tbl <- data.frame(row.names = rownames(exprs(pheno_snps)))
for (n in names(xref_prop)) {
  new_tbl[[n]] <- 0
  idx_cols <- which(pheno_snps[["conditions"]] == n)
  prop_col <- rowSums(idx_tbl[, idx_cols]) / xref_prop[n]
  new_tbl[n] <- prop_col
}
keepers <- grepl(x = rownames(new_tbl), pattern = "LpaL13")
new_tbl <- new_tbl[keepers, ]
new_tbl[["strong22"]] <- 1.001 - new_tbl[["z2.2"]]
new_tbl[["strong23"]] <- 1.001 - new_tbl[["z2.3"]]
s22_na <- new_tbl[["strong22"]] > 1
new_tbl[s22_na, "strong22"] <- 1
s23_na <- new_tbl[["strong23"]] > 1
new_tbl[s23_na, "strong23"] <- 1

new_tbl[["SNP"]] <- rownames(new_tbl)
new_tbl[["Chromosome"]] <- gsub(x = new_tbl[["SNP"]], pattern = "chr_(.*)_pos_.*", replacement = "\\1")
new_tbl[["Position"]] <- gsub(x = new_tbl[["SNP"]], pattern = ".*_pos_(\\d+)_.*", replacement = "\\1")
new_tbl <- new_tbl[, c("SNP", "Chromosome", "Position", "strong22", "strong23")]


library(CMplot)
## Much appreciate for using CMplot.
## Full description, Bug report, Suggestion and the latest codes:
## https://github.com/YinLiLin/CMplot
CMplot(new_tbl, bin.size = 100000)
##  SNP-Density Plotting.
##  Circular-Manhattan Plotting strong22.
##  Circular-Manhattan Plotting strong23.
##  Rectangular-Manhattan Plotting strong22.
##  Rectangular-Manhattan Plotting strong23.
##  QQ Plotting strong22.
##  QQ Plotting strong23.
##  Plots are stored in: /mnt/cbcb/fs01_abelew/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019
CMplot(new_tbl, plot.type="m", multracks=TRUE, threshold = c(0.01, 0.05),
       threshold.lwd=c(1,1), threshold.col=c("black","grey"),
       amplify=TRUE, bin.size=1e5,
       chr.den.col=c("darkgreen", "yellow", "red"),
       signal.col=c("red", "green", "blue"),
       signal.cex=1, file="jpg", memo="", dpi=300, file.output=TRUE, verbose=TRUE)
##  Multracks-Manhattan Plotting strong22.
##  Multracks-Manhattan Plotting strong23.
##  Multraits-Rectangular Plotting...(finished 78%)
 Multraits-Rectangular Plotting...(finished 79%)
 Multraits-Rectangular Plotting...(finished 80%)
 Multraits-Rectangular Plotting...(finished 81%)
 Multraits-Rectangular Plotting...(finished 82%)
 Multraits-Rectangular Plotting...(finished 83%)
 Multraits-Rectangular Plotting...(finished 84%)
 Multraits-Rectangular Plotting...(finished 85%)
 Multraits-Rectangular Plotting...(finished 86%)
 Multraits-Rectangular Plotting...(finished 87%)
 Multraits-Rectangular Plotting...(finished 88%)
 Multraits-Rectangular Plotting...(finished 89%)
 Multraits-Rectangular Plotting...(finished 90%)
 Multraits-Rectangular Plotting...(finished 91%)
 Multraits-Rectangular Plotting...(finished 92%)
 Multraits-Rectangular Plotting...(finished 93%)
 Multraits-Rectangular Plotting...(finished 94%)
 Multraits-Rectangular Plotting...(finished 95%)
 Multraits-Rectangular Plotting...(finished 96%)
 Multraits-Rectangular Plotting...(finished 97%)
 Multraits-Rectangular Plotting...(finished 98%)
 Multraits-Rectangular Plotting...(finished 99%)
 Multraits-Rectangular Plotting...(finished 100%)
##  Plots are stored in: /mnt/cbcb/fs01_abelew/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019

SNP Density Circular Manhattan Rectangular Manhattan QQ

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 72947fcc6afe09da22d71967059edd84e3063341
## This is hpgltools commit: Tue Jun 1 15:57:56 2021 -0400: 72947fcc6afe09da22d71967059edd84e3063341
## Saving to tmrc2_02sample_estimation_v202106.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzIgQ29tcHJlaGVuc2l2ZSBEYXRhIEFuYWx5c2lzOiAyMDIxMDYiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSA5MCwKICAgICAgICAgICAgICAgICAgICAgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA4LAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjEwNiIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gIiVZJW0lZCIpCgojIyB0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZSA9IGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHByZXZpb3VzX2ZpbGUpKSkpCnJtZF9maWxlIDwtIGdsdWU6OmdsdWUoInRtcmMyXzAyc2FtcGxlX2VzdGltYXRpb25fdnt2ZXJ9LlJtZCIpCnNhdmVmaWxlIDwtIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHJtZF9maWxlKQoKbGlicmFyeShIZWF0cGx1cykKYGBgCgpgYGB7ciBjdXJyZW50X3NhbXBsZXNoZWV0fQpzYW1wbGVfc2hlZXQgPC0gZ2x1ZTo6Z2x1ZSgic2FtcGxlX3NoZWV0cy90bXJjMl9zYW1wbGVzXzIwMjEwNjEwLnhsc3giKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IGlzIGludGVuZGVkIHRvIHByb3ZpZGUgYSBnZW5lcmFsIG92ZXJ2aWV3IG9mIHRoZSBUTVJDMiBzYW1wbGVzCndoaWNoIGhhdmUgdGh1cyBmYXIgYmVlbiBzZXF1ZW5jZWQuICBJbiBzb21lIGNhc2VzLCB0aGlzIGluY2x1ZGVzIG9ubHkgdGhvc2UKc2FtcGxlcyBzdGFydGluZyBpbiAyMDE5OyBpbiBvdGhlciBpbnN0YW5jZXMgSSBhbSBpbmNsdWRpbmcgb3VyIHByZXZpb3VzCigyMDE1LTIwMTYpIHNhbXBsZXMuCgpJbiBhbGwgY2FzZXMgdGhlIHByb2Nlc3NpbmcgcGVyZm9ybWVkIHdhczoKCjEuICBEZWZhdWx0IHRyaW1taW5nIHdhcyBwZXJmb3JtZWQuCjIuICBIaXNhdDIgd2FzIHVzZWQgdG8gbWFwIHRoZSByZW1haW5pbmcgcmVhZHMgYWdhaW5zdCB0aGUgTGVpc2htYW5pYQogICAgcGFuYW1lbnNpcyBnZW5vbWUgcmV2aXNpb24gMzYuCjMuICBUaGUgYWxpZ25tZW50cyBmcm9tIGhpc2F0MiB3ZXJlIHVzZWQgdG8gY291bnQgcmVhZHMvZ2VuZSBhZ2FpbnN0IHRoZQogICAgcmV2aXNpb24gMzYgYW5ub3RhdGlvbnMgd2l0aCBodHNlcS4KNC4gIFRoZXNlIGFsaWdubWVudHMgd2VyZSBhbHNvIHBhc3NlZCB0byB0aGUgcGlsZXVwIGZ1bmN0aW9uYWxpdHkgb2Ygc2FtdG9vbHMKICAgIGFuZCB0aGUgdmNmL2JjZiB1dGlsaXRpZXMgaW4gb3JkZXIgdG8gbWFrZSBhIG1hdHJpeCBvZiBhbGwgb2JzZXJ2ZWQKICAgIGRpZmZlcmVuY2VzIGJldHdlZW4gZWFjaCBzYW1wbGUgd2l0aCByZXNwZWN0IHRvIHRoZSByZWZlcmVuY2UuCgpUaGUgYW5hbHlzZXMgaW4gdGhpcyBkb2N1bWVudCB1c2UgdGhlIG1hdHJpY2VzIG9mIGNvdW50cy9nZW5lIGZyb20gIzMgYW5kCnZhcmlhbnRzL3Bvc2l0aW9uIGZyb20gIzQgaW4gb3JkZXIgdG8gcHJvdmlkZSBzb21lIGltYWdlcyBhbmQgbWV0cmljcyBkZXNjcmliaW5nCnRoZSBzYW1wbGVzIHdlIGhhdmUgc2VxdWVuY2VkIHNvIGZhci4KCiMgQW5ub3RhdGlvbnMKCkV2ZXJ5dGhpbmcgd2hpY2ggZm9sbG93cyBkZXBlbmRzIG9uIHRoZSBFeGlzdGluZyBUcmlUcnlwREIgYW5ub3RhdGlvbnMgcmV2aXNpb24KNDYsIGNpcmNhIDIwMTkuICBUaGUgZm9sbG93aW5nIGJsb2NrIGxvYWRzIGEgZGF0YWJhc2Ugb2YgdGhlc2UgYW5ub3RhdGlvbnMgYW5kCnR1cm5zIGl0IGludG8gYSBtYXRyaXggd2hlcmUgdGhlIHJvd3MgYXJlIGdlbmVzIGFuZCBjb2x1bW5zIGFyZSBhbGwgdGhlCmFubm90YXRpb24gdHlwZXMgcHJvdmlkZWQgYnkgVHJpVHJ5cERCLgoKVGhlIHNhbWUgZGF0YWJhc2Ugd2FzIHVzZWQgdG8gY3JlYXRlIGEgbWF0cml4IG9mIG9ydGhvbG9nb3VzIGdlbmVzIGJldHdlZW4KTC5wYW5hbWVuc2lzIGFuZCBhbGwgb2YgdGhlIG90aGVyIHNwZWNpZXMgaW4gdGhlIFRyaVRyeXBEQi4KCmBgYHtyIGFubm90fQp0dCA8LSBzbShsaWJyYXJ5KEV1UGF0aERCKSkKdHQgPC0gc20obGlicmFyeShvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYikpCnBhbl9kYiA8LSBvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYgphbGxfZmllbGRzIDwtIGNvbHVtbnMocGFuX2RiKQoKYWxsX2xwX2Fubm90IDwtIHNtKGxvYWRfb3JnZGJfYW5ub3RhdGlvbnMoCiAgICBwYW5fZGIsCiAgICBrZXl0eXBlID0gImdpZCIsCiAgICBmaWVsZHMgPSBjKCJhbm5vdF9nZW5lX2VudHJlel9pZCIsICJhbm5vdF9nZW5lX25hbWUiLAogICAgICAgICAgICAgICAiYW5ub3Rfc3RyYW5kIiwgImFubm90X2Nocm9tb3NvbWUiLCAiYW5ub3RfY2RzX2xlbmd0aCIsCiAgICAgICAgICAgICAgICJhbm5vdF9nZW5lX3Byb2R1Y3QiKSkpJGdlbmVzCgpscF9nbyA8LSBzbShsb2FkX29yZ2RiX2dvKHBhbl9kYikpCmxwX2xlbmd0aHMgPC0gYWxsX2xwX2Fubm90WywgYygiZ2lkIiwgImFubm90X2Nkc19sZW5ndGgiKV0KY29sbmFtZXMobHBfbGVuZ3RocykgIDwtIGMoIklEIiwgImxlbmd0aCIpCmFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSA8LSB0b2xvd2VyKGFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSkKb3J0aG9zIDwtIHNtKEV1UGF0aERCOjpleHRyYWN0X2V1cGF0aF9vcnRob2xvZ3MoZGIgPSBwYW5fZGIpKQoKaGlzYXRfYW5ub3QgPC0gYWxsX2xwX2Fubm90CiMjIHJvd25hbWVzKGhpc2F0X2Fubm90KSA8LSBwYXN0ZTAoImV4b25fIiwgcm93bmFtZXMoaGlzYXRfYW5ub3QpLCAiLkUxIikKYGBgCgojIFRPRE86CgpSZXNlcXVlbmNlIHNhbXBsZXM6IFRNUkMyMDAwMiwgVE1SQzIwMDA2LCBUTVJDMjAwMDQgKG1heWJlIFRNUkMyMDAwOCBhbmQgVE1SQzIwMDI5KQoKIyBHZW5lcmF0ZSBFeHByZXNzaW9uc2V0cyBhbmQgU2FtcGxlIEVzdGltYXRpb24KClRoZSBwcm9jZXNzIG9mIHNhbXBsZSBlc3RpbWF0aW9uIHRha2VzIHR3byBwcmltYXJ5IGlucHV0czoKCjEuICBUaGUgc2FtcGxlIHNoZWV0LCB3aGljaCBjb250YWlucyBhbGwgdGhlIG1ldGFkYXRhIHdlIGN1cnJlbnRseSBoYXZlIG9uIGhhbmQsCiAgICBpbmNsdWRpbmcgZmlsZW5hbWVzIGZvciB0aGUgb3V0cHV0cyBvZiAjMyBhbmQgIzQgYWJvdmUuCjIuICBUaGUgZ2VuZSBhbm5vdGF0aW9ucy4KCkFuIGV4cHJlc3Npb25zZXQgaXMgYSBkYXRhIHN0cnVjdHVyZSB1c2VkIGluIFIgdG8gZXhhbWluZSBSTkFTZXEgZGF0YS4gIEl0CmlzIGNvbXByaXNlZCBvZiBhbm5vdGF0aW9ucywgbWV0YWRhdGEsIGFuZCBleHByZXNzaW9uIGRhdGEuICBJbiB0aGUgY2FzZSBvZiBvdXIKcHJvY2Vzc2luZyBwaXBlbGluZSwgdGhlIGxvY2F0aW9uIG9mIHRoZSBleHByZXNzaW9uIGRhdGEgaXMgcHJvdmlkZWQgYnkgdGhlCmZpbGVuYW1lcyBpbiB0aGUgbWV0YWRhdGEuCgpUaGUgZmlyc3QgbGluZXMgb2YgdGhlIGZvbGxvd2luZyBibG9jayBjcmVhdGUgdGhlIEV4cHJlc3Npb25zZXQuICBBbGwgb2YgdGhlCmZvbGxvd2luZyBsaW5lcyBwZXJmb3JtIHZhcmlvdXMgbm9ybWFsaXphdGlvbnMgYW5kIGdlbmVyYXRlIHBsb3RzIGZyb20gaXQuCgojIyBOb3RlcwoKVGhlIGZvbGxvd2luZyBzYW1wbGVzIGFyZSBtdWNoIGxvd2VyIGNvdmVyYWdlOgoKKiBUTVJDMjAwMDIKKiBUTVJDMjAwMDYKKiBUTVJDMjAwMDcKKiBUTVJDMjAwMDgKCjIwMjEwNjEwOiBJIG1hZGUgc29tZSBtYW51YWwgY2hhbmdlcyB0byB0aGUgc2FtcGxlIHNoZWV0IHdoaWNoIEkKZG93bmxvYWRlZCwgZmlsbGluZyBpbiBzb21lIHp5bW9kZW1lIHdpdGggJ3Vua25vd24nCgojIyBUT0RPOgoKMS4gIERvIHRoZSBtdWx0aS1nZW5lIGZhbWlseSByZW1vdmFsIHJpZ2h0IGhlcmUgaW5zdGVhZCBvZiB3YXkgZG93biBhdCB0aGUgYm90dG9tCjIuICBBZGQgenltb2RlbWUgc25wcyB0byB0aGUgYW5ub3RhdGlvbiBsYXRlci4KMy4gIFN0YXJ0IHBoeWxvZ2VuZXRpYyBhbmFseXNpcyBvZiB2YXJpYW50IHRhYmxlLgoKCmBgYHtyIG5ld19zYW1wbGVzX2hpc2F0fQpzYW5pdGl6ZV9jb2x1bW5zIDwtIGMoInBhc3NhZ2VudW1iZXIiLCAiY2xpbmljYWxyZXNwb25zZSIsICJjbGluaWNhbGNhdGVnb3JpY2FsIiwKICAgICAgICAgICAgICAgICAgICAgICJ6eW1vZGVtZWNhdGVnb3JpY2FsIiwgInBoZW5vdHlwaWNjaGFyYWN0ZXJpc3RpY3MiKQpscF9leHB0IDwtIHNtKGNyZWF0ZV9leHB0KHNhbXBsZV9zaGVldCwKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm8gPSBoaXNhdF9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZF9jb2x1bW4gPSAiaHBnbGlkZW50aWZpZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gImxwYW5hbWVuc2lzdjM2aGlzYXRmaWxlIikpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJ6eW1vZGVtZWNhdGVnb3JpY2FsIikgJT4lCiAgc3Vic2V0X2V4cHQobm9uemVybyA9IDg2MDApICU+JQogIHNlbWFudGljX2V4cHRfZmlsdGVyKHNlbWFudGljID0gYygiYW1hc3RpbiIsICJncDYzIiwgImxlaXNobWFub2x5c2luIiksCiAgICAgICAgICAgICAgICAgICAgICAgc2VtYW50aWNfY29sdW1uID0gImFubm90X2dlbmVfcHJvZHVjdCIpICU+JQogIHNhbml0aXplX2V4cHRfbWV0YWRhdGEoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMpICU+JQogIHNldF9leHB0X2ZhY3RvcnMoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMsIGNsYXNzID0gImZhY3RvciIpCgpsaWJzaXplcyA8LSBwbG90X2xpYnNpemUobHBfZXhwdCkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfZXhwdF9saWJzaXplcy5wbmciLCBpbWFnZSA9IGxpYnNpemVzJHBsb3QsIHdpZHRoID0gMTIsIGhlaWdodCA9IDkpCiMjIEkgdGhpbmsgc2FtcGxlcyA3LDEwIHNob3VsZCBiZSByZW1vdmVkIGF0IG1pbmltdW0sIHByb2JhYmx5IGFsc28gOSwxMQpub256ZXJvIDwtIHBsb3Rfbm9uemVybyhscF9leHB0KQpub256ZXJvJHBsb3QKCmxwX2JveCA8LSBwbG90X2JveHBsb3QobHBfZXhwdCkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfZXhwdF9ib3hwbG90LnBuZyIsIGltYWdlID0gbHBfYm94LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA5KQoKZmlsdGVyX3Bsb3QgPC0gcGxvdF9saWJzaXplX3ByZXBvc3QobHBfZXhwdCkKZmlsdGVyX3Bsb3QkbG93Z2VuZV9wbG90CmZpbHRlcl9wbG90JGNvdW50X3Bsb3QKYGBgCgojIyBEaXN0cmlidXRpb24gVmlzdWFsaXphdGlvbgoKTmFqaWIncyBmYXZvcml0ZSBwbG90cyBhcmUgb2YgY291cnNlIHRoZSBQQ0EvVE5TRS4gIFRoZXNlIGFyZSBuaWNlIHRvIGxvb2sgYXQgaW4Kb3JkZXIgdG8gZ2V0IGEgc2Vuc2Ugb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzYW1wbGVzLiAgVGhleSBhbHNvIHByb3ZpZGUgYQpnb29kIG9wcG9ydHVuaXR5IHRvIHNlZSB3aGF0IGhhcHBlbnMgd2hlbiBvbmUgYXBwbGllcyBkaWZmZXJlbnQgbm9ybWFsaXphdGlvbnMsCnN1cnJvZ2F0ZSBhbmFseXNlcywgZmlsdGVycywgZXRjLiAgSW4gYWRkaXRpb24sIG9uZSBtYXkgc2V0IGRpZmZlcmVudApleHBlcmltZW50YWwgZmFjdG9ycyBhcyB0aGUgcHJpbWFyeSAnY29uZGl0aW9uJyAodXN1YWxseSB0aGUgY29sb3Igb2YgcGxvdHMpIGFuZApzdXJyb2dhdGUgJ2JhdGNoZXMnLgoKIyMgQnkgU3VzY2VwdGlsaWJpdHkKCkNvbHVtbiAnUScgaW4gdGhlIHNhbXBsZSBzaGVldCwgbWFrZSBhIGNhdGVnb3JpY2FsIHZlcnNpb24gb2YgaXQgd2l0aCB0aGVzZSBwYXJhbWV0ZXJzOgoKKiAwIDw9IHggPD0gMzUgaXMgcmVzaXN0YW50CiogMzYgPD0geCA8PSA0OCBpcyBhbWJpZ3VvdXMKKiA0OSA8PSB4IGlzIHNlbnNpdGl2ZQoKYGBge3Igc3VzY2VwdGliaWxpdHl9CnN0YXJ0aW5nIDwtIGFzLm51bWVyaWMocERhdGEobHBfZXhwdClbWyJzdXNjZXB0aWJpbGl0eWluZmVjdGlvbnJlZHVjdGlvbjMydWdtbHNidmhpc3RvcmljYWxkYXRhIl1dKQpzdXNfY2F0ZWdvcmljYWwgPC0gc3RhcnRpbmcKbmFfaWR4IDwtIGlzLm5hKHN0YXJ0aW5nKQpzdXNfY2F0ZWdvcmljYWxbbmFfaWR4XSA8LSAidW5rbm93biIKCnJlc2lzdF9pZHggPC0gc3RhcnRpbmcgPD0gMC4zNQpzdXNfY2F0ZWdvcmljYWxbcmVzaXN0X2lkeF0gPC0gInJlc2lzdGFudCIKaW5kZXRlcm1pbmFudF9pZHggPC0gc3RhcnRpbmcgPj0gMC4zNiAmIHN0YXJ0aW5nIDw9IDAuNDgKc3VzX2NhdGVnb3JpY2FsW2luZGV0ZXJtaW5hbnRfaWR4XSA8LSAiYW1iaWd1b3VzIgpzdXNjZXB0aWJsZV9pZHggPC0gc3RhcnRpbmcgPj0gMC40OQpzdXNfY2F0ZWdvcmljYWxbc3VzY2VwdGlibGVfaWR4XSA8LSAic2Vuc2l0aXZlIgoKcERhdGEobHBfZXhwdCRleHByZXNzaW9uc2V0KVtbInN1c19jYXRlZ29yeSJdXSA8LSBzdXNfY2F0ZWdvcmljYWwKYGBgCgpgYGB7ciBwcmVfcXVlc3Rpb25zfQpjbGluaWNhbF9zYW1wbGVzIDwtIGxwX2V4cHQgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gc3VzX2NhdGVnb3JpY2FsKQoKY2xpbmljYWxfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChjbGluaWNhbF9zYW1wbGVzLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkpCnp5bW9fcGNhIDwtIHBsb3RfcGNhKGNsaW5pY2FsX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIikKcHAoZmlsZSA9ICJpbWFnZXMvenltb19wY2Ffc3VzX3NoYXBlLnBuZyIsIGltYWdlID0genltb19wY2EkcGxvdCkKCnp5bW9fM2RwY2EgPC0gcGxvdF8zZF9wY2Eoenltb19wY2EpCnp5bW9fM2RwY2EkcGxvdAoKY2xpbmljYWxfbiA8LSBzbShub3JtYWxpemVfZXhwdChjbGluaWNhbF9zYW1wbGVzLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKenltb190c25lIDwtIHBsb3RfdHNuZShjbGluaWNhbF9uLCBwbG90X3RpdGxlID0gIlRTTkUgb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiKQp6eW1vX3RzbmUkcGxvdAoKY2xpbmljYWxfbmIgPC0gbm9ybWFsaXplX2V4cHQoY2xpbmljYWxfc2FtcGxlcywgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKQpjbGluaWNhbF9uYl9wY2EgPC0gcGxvdF9wY2EoY2xpbmljYWxfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIikKcHAoZmlsZSA9ICJpbWFnZXMvY2xpbmljYWxfbmJfcGNhX3N1c19zaGFwZS5wbmciLCBpbWFnZSA9IGNsaW5pY2FsX25iX3BjYSRwbG90KQoKY2xpbmljYWxfbmJfdHNuZSA8LSBwbG90X3RzbmUoY2xpbmljYWxfbmIsIHBsb3RfdGl0bGUgPSAiVFNORSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIpCmNsaW5pY2FsX25iX3RzbmUkcGxvdAoKY29yaGVhdCA8LSBwbG90X2NvcmhlYXQoY2xpbmljYWxfbm9ybSwgcGxvdF90aXRsZSA9ICJDb3JyZWxhdGlvbiBoZWF0bWFwIG9mIHBhcmFzaXRlCiAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbiB2YWx1ZXMKIikKY29yaGVhdCRwbG90CgpwbG90X3NtKGNsaW5pY2FsX25vcm0pJHBsb3QKYGBgCgojIyBCeSBDdXJlL0ZhaWwgc3RhdHVzCgpgYGB7ciBjZl9zdGF0dXN9CmNmX2V4cHQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhscF9leHB0LCBmYWN0ID0gImNsaW5pY2FsY2F0ZWdvcmljYWwiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSBzdXNfY2F0ZWdvcmljYWwpCgpjZl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGNmX2V4cHQsIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpzdGFydF9jZiA8LSBwbG90X3BjYShjZl9ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIpCnBwKGZpbGUgPSAiaW1hZ2VzL2NmX3N1c19zaGFwZS5wbmciLCBpbWFnZSA9IHN0YXJ0X2NmJHBsb3QpCgpjZl9uYiA8LSBub3JtYWxpemVfZXhwdChjZl9leHB0LCBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIpCmNmX25iX3BjYSA8LSBwbG90X3BjYShjZl9uYiwgcGxvdF90aXRsZSA9ICJQQ0Egb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiKQpwcChmaWxlID0gImltYWdlcy9jZl9zdXNfc2hhcmVfbmIucG5nIiwgaW1hZ2UgPSBjZl9uYl9wY2EkcGxvdCkKCmNmX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoY2ZfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCgp0ZXN0IDwtIHBjYV9pbmZvcm1hdGlvbihjZl9ub3JtLAogICAgICAgICAgICAgICAgICAgICAgICBleHB0X2ZhY3RvcnMgPSBjKCJjbGluaWNhbGNhdGVnb3JpY2FsIiwgInp5bW9kZW1lY2F0ZWdvcmljYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYXRob2dlbnN0cmFpbiIsICJwYXNzYWdlbnVtYmVyIiksCiAgICAgICAgICAgICAgICAgICAgICAgIG51bV9jb21wb25lbnRzID0gNiwgcGxvdF9wY2FzID0gVFJVRSkKdGVzdCRhbm92YV9wCnRlc3QkY29yX2hlYXRtYXAKYGBgCgpgYGB7ciBzdXNjZXB0aWJpbGl0eV9wY2F9CnN1c19leHB0IDwtIHNldF9leHB0X2NvbmRpdGlvbnMobHBfZXhwdCwgZmFjdCA9ICJzdXNfY2F0ZWdvcnkiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAienltb2RlbWVjYXRlZ29yaWNhbCIpCgpzdXNfbm9ybSA8LSBub3JtYWxpemVfZXhwdChzdXNfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpzdXNfcGNhIDwtIHBsb3RfcGNhKHN1c19ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIpCnN1c19wY2EkcGxvdAoKc3VzX25iIDwtIG5vcm1hbGl6ZV9leHB0KHN1c19leHB0LCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCnN1c19uYl9wY2EgPC0gcGxvdF9wY2Eoc3VzX25iLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIpCnBwKGZpbGUgPSAiaW1hZ2VzL3N1c19uYl9wY2EucG5nIiwgaW1hZ2UgPSBzdXNfbmJfcGNhJHBsb3QpCmBgYAoKQXQgdGhpcyB0aW1lLCB3ZSBkbyBub3QgaGF2ZSB2ZXJ5IG1hbnkgc2FtcGxlcywgc28gdGhlIHNldCBvZiBtZXRyaWNzL3Bsb3RzIGlzCmZhaXJseSBsaW1pdGVkLiAgVGhlcmUgaXMgcmVhbGx5IG9ubHkgb25lIGZhY3RvciBpbiB0aGUgbWV0YWRhdGEgd2hpY2ggd2UgY2FuCnVzZSBmb3IgcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNlcywgdGhlICd6eW1vZGVtZScuCgojIFp5bW9kZW1lIGFuYWx5c2VzCgpUaGUgZm9sbG93aW5nIHNlY3Rpb25zIHBlcmZvcm0gYSBzZXJpZXMgb2YgYW5hbHlzZXMgd2hpY2ggc2VlayB0byBlbHVjaWRhdGUKZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgenltb2RlbWVzIDIuMiBhbmQgMi4zIGVpdGhlciB0aHJvdWdoIGRpZmZlcmVudGlhbApleHByZXNzaW9uIG9yIHZhcmlhbnQgcHJvZmlsZXMuCgojIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKIyMjIFdpdGggcmVzcGVjdCB0byB6eW1vZGVtZSBhdHRyaWJ1dGlvbgoKVE9ETzogRG8gdGhpcyB3aXRoIGFuZCB3aXRob3V0IHN2YSBhbmQgY29tcGFyZSB0aGUgcmVzdWx0cy4KCmBgYHtyIHp5bW9fZGUsIGZpZy5zaG93ID0gImhpZGUifQp6eV9leHB0IDwtIHN1YnNldF9leHB0KGxwX2V4cHQsIHN1YnNldCA9ICJjb25kaXRpb249PSd6Mi4yJ3xjb25kaXRpb249PSd6Mi4zJyIpCnp5X25vcm0gPC0gbm9ybWFsaXplX2V4cHQoenlfZXhwdCwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IikKenlfZGVfbm9iYXRjaCA8LSBzbShhbGxfcGFpcndpc2UoenlfZXhwdCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikpCnp5X2RlIDwtIHNtKGFsbF9wYWlyd2lzZSh6eV9leHB0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKSkKenlfdGFibGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoenlfZGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvenlfdGFibGVzLXZ7dmVyfS54bHN4IikpKQp6eV9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyh6eV90YWJsZSwgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC96eV9zaWctdnt2ZXJ9Lnhsc3giKSkpCmBgYAoKIyMjIEltYWdlcyBvZiB6eW1vZGVtZSBERQoKYGBge3Igenltb2RfZGVfcGljdHVyZXN9Cnp5X3RhYmxlW1sicGxvdHMiXV1bWyJ6MjNfdnNfejIyIl1dW1siZGVzZXFfbWFfcGxvdHMiXV1bWyJwbG90Il1dCmBgYAoKIyMgV2l0aCByZXNwZWN0IHRvIGN1cmUvZmFpbHVyZQoKSW4gY29udHJhc3QsIHdlIGNhbiBzZWFyY2ggZm9yIGdlbmVzIHdoaWNoIGFyZSBkaWZmZXJlbnRpYWxseQpleHByZXNzZWQgd2l0aCByZXNwZWN0IHRvIGN1cmUvZmFpbHVyZSBzdGF0dXMuCgpgYGB7ciBjdXJlZmFpbF9kZSwgZmlnLnNob3cgPSAiaGlkZSJ9CmNmX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShjZl9leHB0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKSkKY2ZfdGFibGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoY2ZfZGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvY2ZfdGFibGVzLXZ7dmVyfS54bHN4IikpKQpjZl9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhjZl90YWJsZSwgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9jZl9zaWctdnt2ZXJ9Lnhsc3giKSkpCmBgYAoKIyMgV2l0aCByZXNwZWN0IHRvIHN1c2NlcHRpYmlsaXR5CgpGaW5hbGx5LCB3ZSBjYW4gdXNlIG91ciBjYXRlZ29yeSBvZiBzdXNjZXB0aWJpbGl0eSBhbmQgbG9vayBmb3IgZ2VuZXMKd2hpY2ggY2hhbmdlIGZyb20gc2Vuc2l0aXZlIHRvIHJlc2lzdGFudC4gIEtlZXAgaW4gbWluZCwgdGhvdWdoLCB0aGF0CmZvciB0aGUgbW9tZW50IHdlIGhhdmUgYSBsb3Qgb2YgYW1iaWd1b3VzIGFuZCB1bmtub3duIHN0cmFpbnMuCgpgYGB7ciBjdXJlZmFpbF9kZSwgZmlnLnNob3cgPSAiaGlkZSJ9CnN1c19kZSA8LSBzbShhbGxfcGFpcndpc2Uoc3VzX2V4cHQsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpKQpzdXNfdGFibGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoc3VzX2RlLCBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3N1c190YWJsZXMtdnt2ZXJ9Lnhsc3giKSkpCnN1c19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhzdXNfdGFibGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvc3VzX3NpZy12e3Zlcn0ueGxzeCIpKSkKYGBgCgpgYGB7ciB6eW1vZF9kZV9waWN0dXJlc30Ka25pdHI6OmthYmxlKGhlYWQoc3VzX3NpZyRkZXNlcSR1cHMkc2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCwgbiA9IDIwKSkKCmtuaXRyOjprYWJsZShoZWFkKHN1c19zaWckZGVzZXEkZG93bnMkc2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCwgbiA9IDIwKSkKCnN1c19tYSA8LSBzdXNfdGFibGVbWyJwbG90cyJdXVtbInNlbnNpdGl2ZV92c19yZXNpc3RhbnQiXV1bWyJkZXNlcV9tYV9wbG90cyJdXVtbInBsb3QiXV0KcHAoZmlsZSA9ICJpbWFnZXMvc3VzX21hLnBuZyIsIGltYWdlID0gc3VzX21hKQoKIyMgdGVzdCA8LSBnZ3BsdChzdXNfbWEpCmBgYAoKCiMjIE9udG9sb2d5IHNlYXJjaGVzCgpOb3cgbGV0IHVzIGxvb2sgZm9yIG9udG9sb2d5IGNhdGVnb3JpZXMgd2hpY2ggYXJlIGluY3JlYXNlZCBpbiB0aGUgMi4zCnNhbXBsZXMgZm9sbG93ZWQgYnkgdGhlIDIuMiBzYW1wbGVzLgoKYGBge3IgZ28sIHNpZy5zaG93ID0gImhpZGUifQojIyBHZW5lIGNhdGVnb3JpZXMgbW9yZSByZXByZXNlbnRlZCBpbiB0aGUgMi4zIGdyb3VwLgp6eV9nb191cCA8LSBzbShzaW1wbGVfZ29zZXEoc2lnX2dlbmVzID0genlfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2RiID0gbHBfZ28sIGxlbmd0aF9kYiA9IGxwX2xlbmd0aHMpKQoKIyMgR2VuZSBjYXRlZ29yaWVzIG1vcmUgcmVwcmVzZW50ZWQgaW4gdGhlIDIuMiBncm91cC4KenlfZ29fZG93biA8LSBzbShzaW1wbGVfZ29zZXEoc2lnX2dlbmVzID0genlfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19kYiA9IGxwX2dvLCBsZW5ndGhfZGIgPSBscF9sZW5ndGhzKSkKYGBgCgojIyMgQSBjb3VwbGUgcGxvdHMgZnJvbSB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24KCiMjIyMgTnVtYmVyIG9mIGdlbmVzIGluIGFncmVlbWVudCBhbW9uZyBERSBtZXRob2RzLCAyLjMgbW9yZSB0aGFuIDIuMgoKSW4gdGhlIGZ1bmN0aW9uICdjb21iaW5lZF9kZV90YWJsZXMoKScgYWJvdmUsIG9uZSBvZiB0aGUgdGFza3MKcGVyZm9ybWVkIGlzIHRvIGxvb2sgYXQgdGhlIGFncmVlbWVudCBhbW9uZyBERVNlcTIsIGxpbW1hLCBhbmQgZWRnZVIuClRoZSBmb2xsb3dpbmcgc2hvdyBhIGNvdXBsZSBvZiB0aGVzZSBmb3IgdGhlIHNldCBvZiBnZW5lcyBvYnNlcnZlZAp3aXRoIGEgZm9sZC1jaGFuZ2UgPj0gfDJ8IGFuZCBhZGp1c3RlZCBwLXZhbHVlIDw9IDAuMDUuCgpgYGB7ciBkZV9wbG90c30KenlfdGFibGVbWyJ2ZW5ucyJdXVtbMV1dW1sicF9sZmMxIl1dW1sidXBfbm93ZWlnaHQiXV0KYGBgCgojIyMjIE51bWJlciBvZiBnZW5lcyBpbiBhZ3JlZW1lbnQgYW1vbmcgREUgbWV0aG9kcywgMi4yIG1vcmUgdGhhbiAyLjMKCmBgYHtyIGRlX3Bsb3RzfQp6eV90YWJsZVtbInZlbm5zIl1dW1sxXV1bWyJwX2xmYzEiXV1bWyJkb3duX25vd2VpZ2h0Il1dCmBgYAoKIyMjIyBnb3NlcSBvbnRvbG9neSBwbG90cyBvZiBncm91cHMgb2YgZ2VuZXMsIDIuMyBtb3JlIHRoYW4gMi4yCgpgYGB7ciBnb3NlcV91cH0KenlfZ29fdXAkcHZhbHVlX3Bsb3RzJGJwcF9wbG90X292ZXIKYGBgCgojIyMjIGdvc2VxIG9udG9sb2d5IHBsb3RzIG9mIGdyb3VwcyBvZiBnZW5lcywgMi4yIG1vcmUgdGhhbiAyLjMKCmBgYHtyIGdvc2VxX2Rvd259Cnp5X2dvX2Rvd24kcHZhbHVlX3Bsb3RzJGJwcF9wbG90X292ZXIKYGBgCgojIyBMb29rIGZvciBhZ3JlZW1lbnQgYmV0d2VlbiBzZW5zaXRpdml0eSBhbmQgenltb2RlbWVzCgpSZW1pbmQgbXlzZWxmLCB0aGUgZGF0YSBzdHJ1Y3R1cmVzIGFyZSAoenl8c3VzKV8oZGV8dGFibGV8c2lnKS4KCmBgYHtyIHNlbnNpdGl2ZV92c196eW1vfQp6eV9kZiA8LSB6eV90YWJsZVtbImRhdGEiXV1bWyJ6MjNfdnNfejIyIl1dCnN1c19kZiA8LSBzdXNfdGFibGVbWyJkYXRhIl1dW1sic2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCJdXQoKYm90aF9kZiA8LSBtZXJnZSh6eV9kZiwgc3VzX2RmLCBieSA9ICJyb3cubmFtZXMiKQpwbG90X2RmIDwtIGJvdGhfZGZbLCBjKCJkZXNlcV9sb2dmYy54IiwgImRlc2VxX2xvZ2ZjLnkiKV0Kcm93bmFtZXMocGxvdF9kZikgPC0gYm90aF9kZltbIlJvdy5uYW1lcyJdXQpjb2xuYW1lcyhwbG90X2RmKSA8LSBjKCJ6MjNfdnNfejIyIiwgInNlbnNpdGl2ZV92c19yZXNpc3RhbnQiKQoKY29tcGFyZSA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKHBsb3RfZGYpCnBwKGZpbGUgPSAiaW1hZ2VzL2NvbXBhcmVfc3VzX3p5LnBuZyIsIGltYWdlID0gY29tcGFyZSRzY2F0dGVyKQpjb21wYXJlJGNvcgpgYGAKCiMjIFp5bW9kZW1lIGVuenltZSBnZW5lIElEcwoKTmFqaWIgcmVhZCBtZSBhbiBlbWFpbCBsaXN0aW5nIG9mZiB0aGUgZ2VuZSBuYW1lcyBhc3NvY2lhdGVkIHdpdGggdGhlIHp5bW9kZW1lCmNsYXNzaWZpY2F0aW9uLiAgSSB0b29rIHRob3NlIG5hbWVzIGFuZCBjcm9zcyByZWZlcmVuY2VkIHRoZW0gYWdhaW5zdCB0aGUKTGVpc2htYW5pYSBwYW5hbWVuc2lzIGdlbmUgYW5ub3RhdGlvbnMgYW5kIGZvdW5kIHRoZSBmb2xsb3dpbmc6CgpUaGV5IGFyZToKCjEuIEFMQVQ6IExQQUwxM18xMjAwMTA5MDAgLS0gYWxhbmluZSBhbWlub3RyYW5zZmVyYXNlCjIuIEFTQVQ6IExQQUwxM18zNDAwMTMwMDAgLS0gYXNwYXJ0YXRlIGFtaW5vdHJhbnNmZXJhc2UKMy4gRzZQRDogTFBBTDEzXzAwMDA1NDEwMCAtLSBnbHVjYXNlLTYtcGhvc3BoYXRlIDEtZGVoeWRyb2dlbmFzZQo0LiBOSDogTFBBTDEzXzE0MDA2MTAwLCBMUEFMMTNfMTgwMDE4NTAwIC0tIGlub3NpbmUtZ3VhbmluZSBudWNsZW9zaWRlIGh5ZHJvbGFzZQo1LiBNUEk6IExQQUwxM18zMjAwMjIzMDAgKG1heWJlKSAtLSBtYW5ub3NlIHBob3NwaGF0ZSBpc29tZXJhc2UgKEkgY2hvc2UgcGhvc3Bob21hbm5vc2UgaXNvbWVyYXNlKQoKR2l2ZW4gdGhlc2UgNiBnZW5lIElEcyAoTkggaGFzIHR3byBnZW5lIElEcyBhc3NvY2lhdGVkIHdpdGggaXQpLCBJIGNhbiBkbyBzb21lCmxvb2tpbmcgZm9yIHNwZWNpZmljIGRpZmZlcmVuY2VzIGFtb25nIHRoZSB2YXJpb3VzIHNhbXBsZXMuCgojIyMgRXhwcmVzc2lvbiBsZXZlbHMgb2Ygenltb2RlbWUgZ2VuZXMKClRoZSBmb2xsb3dpbmcgY3JlYXRlcyBhIGNvbG9yc3BhY2UgKHJlZCB0byBncmVlbikgaGVhdG1hcCBzaG93aW5nIHRoZSBvYnNlcnZlZApleHByZXNzaW9uIG9mIHRoZXNlIGdlbmVzIGluIGV2ZXJ5IHNhbXBsZS4KCmBgYHtyIHp5bW9kZW1lc30KbXlfZ2VuZXMgPC0gYygiTFBBTDEzXzEyMDAxMDkwMCIsICJMUEFMMTNfMzQwMDEzMDAwIiwgIkxQQUwxM18wMDAwNTQxMDAiLAogICAgICAgICAgICAgICJMUEFMMTNfMTQwMDA2MTAwIiwgIkxQQUwxM18xODAwMTg1MDAiLCAiTFBBTDEzXzMyMDAyMjMwMCIsCiAgICAgICAgICAgICAgIm90aGVyIikKbXlfbmFtZXMgPC0gYygiQUxBVCIsICJBU0FUIiwgIkc2UEQiLCAiTkh2MSIsICJOSHYyIiwgIk1QSSIsICJvdGhlciIpCgp6eW1vX2V4cHQgPC0gZXhjbHVkZV9nZW5lc19leHB0KHp5X25vcm0sIGlkcyA9IG15X2dlbmVzLCBtZXRob2QgPSAia2VlcCIpCnp5bW9faGVhdG1hcCA8LSBwbG90X3NhbXBsZV9oZWF0bWFwKHp5bW9fZXhwdCwgcm93X2xhYmVsID0gbXlfbmFtZXMpCnp5bW9faGVhdG1hcApgYGAKCiMjIEVtcGlyaWNhbGx5IG9ic2VydmVkIFp5bW9kZW1lIGdlbmVzIGZyb20gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMKCkluIGNvbnRyYXN0LCB0aGUgZm9sbG93aW5nIHBsb3RzIHRha2UgdGhlIHNldCBvZiBnZW5lcyB3aGljaCBhcmUgc2hhcmVkIGFtb25nCmFsbCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBtZXRob2RzICh8bGZjfCA+PSAxLjAgYW5kIGFkanAgPD0gMC4wNSkgYW5kIHVzZSB0aGVtCnRvIG1ha2UgY2F0ZWdvcmllcyBvZiBnZW5lcyB3aGljaCBhcmUgaW5jcmVhc2VkIGluIDIuMyBvciAyLjIuCgpgYGB7ciB6eW1vZGVtZV9nZW5lc19lbXBpcmljYWx9CnNoYXJlZF96eW1vIDwtIGludGVyc2VjdF9zaWduaWZpY2FudCh6eV90YWJsZSkKdXBfc2hhcmVkIDwtIHNoYXJlZF96eW1vW1sidXBzIl1dW1sxXV1bWyJkYXRhIl1dW1siYWxsIl1dCnJvd25hbWVzKHVwX3NoYXJlZCkKdXBzaGFyZWRfZXhwdCA8LSBleGNsdWRlX2dlbmVzX2V4cHQoenlfbm9ybSwgaWRzID0gcm93bmFtZXModXBfc2hhcmVkKSwgbWV0aG9kID0gImtlZXAiKQpgYGAKCldlIGNhbiBwbG90IGEgcXVpY2sgaGVhdG1hcCB0byBnZXQgYSBzZW5zZSBvZiB0aGUgZGlmZmVyZW5jZXMgb2JzZXJ2ZWQKYmV0d2VlbiB0aGUgZ2VuZXMgd2hpY2ggYXJlIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSB0d28genltb2RlbWVzLgoKIyMjIEhlYXRtYXAgb2Ygenltb2RlbWUgZ2VuZSBleHByZXNzaW9uIGluY3JlYXNlZCBpbiAyLjMgdnMuIDIuMgoKYGBge3Igenltb2VtcHVwfQpoaWdoXzIzX2hlYXRtYXAgPC0gcGxvdF9zYW1wbGVfaGVhdG1hcCh1cHNoYXJlZF9leHB0LCByb3dfbGFiZWwgPSByb3duYW1lcyh1cF9zaGFyZWQpKQpoaWdoXzIzX2hlYXRtYXAKYGBgCgojIyMgSGVhdG1hcCBvZiB6eW1vZGVtZSBnZW5lIGV4cHJlc3Npb24gaW5jcmVhc2VkIGluIDIuMiB2cy4gMi4zCgpgYGB7ciB6eW1vZW1kb3dufQpkb3duX3NoYXJlZCA8LSBzaGFyZWRfenltb1tbImRvd25zIl1dW1sxXV1bWyJkYXRhIl1dW1siYWxsIl1dCmRvd25zaGFyZWRfZXhwdCA8LSBleGNsdWRlX2dlbmVzX2V4cHQoenlfbm9ybSwgaWRzID0gcm93bmFtZXMoZG93bl9zaGFyZWQpLCBtZXRob2QgPSAia2VlcCIpCmhpZ2hfMjJfaGVhdG1hcCA8LSBwbG90X3NhbXBsZV9oZWF0bWFwKGRvd25zaGFyZWRfZXhwdCwgcm93X2xhYmVsID0gcm93bmFtZXMoZG93bl9zaGFyZWQpKQpoaWdoXzIyX2hlYXRtYXAKYGBgCgojIFNOUCBwcm9maWxlcwoKTm93IEkgd2lsbCBjb21iaW5lIG91ciBwcmV2aW91cyBzYW1wbGVzIGFuZCBvdXIgbmV3IHNhbXBsZXMgaW4gdGhlCmhvcGVzIG9mIGZpbmRpbmcgdmFyaWFudCBwb3NpdGlvbnMgd2hpY2ggaGVscCBlbHVjaWRhdGUgY3VycmVudGx5CnVua25vd24gYXNwZWN0cyBvZiBlaXRoZXIgZ3JvdXAgdmlhIHRoZWlyIGNsdXN0ZXJpbmcgdG8ga25vd24gc2FtcGxlcwpmcm9tIHRoZSBvdGhlciBncm91cC4gSW4gb3RoZXIgd29yZHMsIHdlIGRvIG5vdCBrbm93IHRoZSB6eW1vZGVtZQphbm5vdGF0aW9ucyBmb3IgdGhlIG9sZCBzYW1wbGVzIG5vciB0aGUgc3RyYWluIGlkZW50aXRpZXMgKG9yIHRoZQpzaG9ydGN1dCAnY2hyb25pYyB2cy4gc2VsZi1oZWFsaW5nJykgZm9yIHRoZSBuZXcgc2FtcGxlcy4gSSBob3BlIHRvCm1ha2UgZWR1Y2F0ZWQgZ3Vlc3NlcyBnaXZlbiB0aGUgdmFyaWFudCBwcm9maWxlcy4gVGhlcmUgYXJlIHNvbWUKZGlmZmVyZW5jZXMgaW4gaG93IHRoZSBwcmV2aW91cyBhbmQgY3VycmVudCBkYXRhIHNldHMgd2VyZSBhbmFseXplZAoodGhvdWdoIEkgaGF2ZSBzaW5jZSByZWRvbmUgdGhlIG9sZCBzYW1wbGVzIHNvIGl0IHNob3VsZCBiZSB0cml2aWFsIHRvCnJlbW92ZSB0aG9zZSBkaWZmZXJlbmNlcyBub3cpLgoKSSBhZGRlZCBvdXIgMjAxNiBkYXRhIHRvIGEgc3BlY2lmaWMgVE1SQzIgc2FtcGxlIHNoZWV0LApkYXRlZCAyMDE5MTIwMy4gIFRodXMgSSB3aWxsIGxvYWQgdGhlIGRhdGEgaGVyZS4gIFRoYXQgcHJldmlvdXMgZGF0YQp3YXMgbWFwcGVkIHVzaW5nIHRvcGhhdCwgc28gSSB3aWxsIGFsc28gbmVlZCB0byBtYWtlIHNvbWUgY2hhbmdlcyB0bwp0aGUgZ2VuZSBuYW1lcyB0byBhY2NvbW9kYXRlIHRoZSB0d28gbWFwcGluZ3MuCgpgYGB7ciBvbGRuZXdfdmFyaWFudHN9Cm9sZF9leHB0IDwtIHNtKGNyZWF0ZV9leHB0KCJzYW1wbGVfc2hlZXRzL3RtcmMyX3NhbXBsZXNfMjAxOTEyMDMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gInRvcGhhdDJmaWxlIikpCgp0dCA8LSBscF9leHB0W1siZXhwcmVzc2lvbnNldCJdXQpyb3duYW1lcyh0dCkgPC0gZ3N1YihwYXR0ZXJuID0gIl5leG9uXyIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSByb3duYW1lcyh0dCkpCnJvd25hbWVzKHR0KSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuRTEkIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJvd25hbWVzKHR0KSkKbHBfZXhwdCRleHByZXNzaW9uc2V0IDwtIHR0Cgp0dCA8LSBvbGRfZXhwdCRleHByZXNzaW9uc2V0CnJvd25hbWVzKHR0KSA8LSBnc3ViKHBhdHRlcm4gPSAiXmV4b25fIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJvd25hbWVzKHR0KSkKcm93bmFtZXModHQpIDwtIGdzdWIocGF0dGVybiA9ICJcXC4xJCIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSByb3duYW1lcyh0dCkpCm9sZF9leHB0JGV4cHJlc3Npb25zZXQgPC0gdHQKcm0odHQpCmBgYAoKIyMgQ3JlYXRlIHRoZSBTTlAgZXhwcmVzc2lvbnNldAoKT25lIG90aGVyIGltcG9ydGFudCBjYXZlYXQsIHdlIGhhdmUgYSBncm91cCBvZiBuZXcgc2FtcGxlcyB3aGljaCBoYXZlCm5vdCB5ZXQgcnVuIHRocm91Z2ggdGhlIHZhcmlhbnQgc2VhcmNoIHBpcGVsaW5lLCBzbyBJIG5lZWQgdG8gcmVtb3ZlCnRoZW0gZnJvbSBjb25zaWRlcmF0aW9uLiAgVGhvdWdoIGl0IGxvb2tzIGxpa2UgdGhleSBmaW5pc2hlZCBvdmVybmlnaHQuLi4KCmBgYHtyIGNvdW50X2V4cHRfb2xkX25ld30KIyMgVGhlIG5leHQgbGluZSBkcm9wcyB0aGUgc2FtcGxlcyB3aGljaCBhcmUgbWlzc2luZyB0aGUgU05QIHBpcGVsaW5lLgpscF9zbnAgPC0gc3Vic2V0X2V4cHQobHBfZXhwdCwgc3Vic2V0PSIhaXMubmEocERhdGEobHBfZXhwdClbWydiY2Z0YWJsZSddXSkiKQpuZXdfc25wcyA8LSBzbShjb3VudF9leHB0X3NucHMobHBfc25wLCBhbm5vdF9jb2x1bW4gPSAiYmNmdGFibGUiKSkKb2xkX3NucHMgPC0gc20oY291bnRfZXhwdF9zbnBzKG9sZF9leHB0LCBhbm5vdF9jb2x1bW4gPSAiYmNmdGFibGUiLCBzbnBfY29sdW1uID0gMikpCgpib3RoX3NucHMgPC0gY29tYmluZV9leHB0cyhuZXdfc25wcywgb2xkX3NucHMpCmJvdGhfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChib3RoX3NucHMsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFKSkKCiMjIHN0cmFpbnMgPC0gYm90aF9ub3JtW1siZGVzaWduIl1dW1sic3RyYWluIl1dCmJvdGhfc3RyYWluIDwtIHNldF9leHB0X2NvbmRpdGlvbnMoYm90aF9ub3JtLCBmYWN0ID0gInN0cmFpbiIpCmBgYAoKVGhlIGRhdGEgc3RydWN0dXJlICdib3RoX25vcm0nIG5vdyBjb250YWlucyBvdXIgMjAxNiBkYXRhIGFsb25nIHdpdGgKdGhlIG5ld2VyIGRhdGEgY29sbGVjdGVkIHNpbmNlIDIwMTkuCgojIyBQbG90IG9mIFNOUCBwcm9maWxlcyBmb3Igenltb2RlbWVzCgpUaGUgZm9sbG93aW5nIHBsb3Qgc2hvd3MgdGhlIFNOUCBwcm9maWxlcyBvZiBhbGwgc2FtcGxlcyAob2xkIGFuZCBuZXcpIHdoZXJlIHRoZQpjb2xvcnMgYXQgdGhlIHRvcCBzaG93IGVpdGhlciB0aGUgMi4yIHN0cmFpbnMgKG9yYW5nZSksIDIuMyBzdHJhaW5zIChncmVlbiksIHRoZQpwcmV2aW91cyBzYW1wbGVzIChwdXJwbGUpLCBvciB0aGUgdmFyaW91cyBsYWIgc3RyYWlucyAocGluayBldGMpLgoKYGBge3IgcGxvdHRpbmdfdmFyaWFudHN9Cm9sZF9uZXdfdmFyaWFudF9oZWF0bWFwIDwtIHBsb3RfZGlzaGVhdChib3RoX25vcm0pCnBwKGZpbGUgPSAiaW1hZ2VzL3Jhd19zbnBfZGlzaGVhdC5wbmciLCBpbWFnZSA9IG9sZF9uZXdfdmFyaWFudF9oZWF0bWFwLAogICBoZWlnaHQgPSAxMiwgd2lkdGggPSAxMikKYGBgCgpUaGUgZnVuY3Rpb24gZ2V0X3NucF9zZXRzKCkgdGFrZXMgdGhlIHByb3ZpZGVkIG1ldGFkYXRhIGZhY3RvciAoaW4KdGhpcyBjYXNlICdjb25kaXRpb24nKSBhbmQgbG9va3MgZm9yIHZhcmlhbnRzIHdoaWNoIGFyZSBleGNsdXNpdmUgdG8KZWFjaCBlbGVtZW50IGluIGl0LiAgSW4gdGhpcyBjYXNlLCB0aGlzIGlzIGxvb2tpbmcgZm9yIGRpZmZlcmVuY2VzCmJldHdlZW4gMi4yIGFuZCAyLjMsIGFzIHdlbGwgYXMgdGhlIHNldCBzaGFyZWQgYW1vbmcgdGhlbS4KCmBgYHtyIGdldF9zbnBfc2V0czF9CnNucF9zZXRzIDwtIGdldF9zbnBfc2V0cyhib3RoX3NucHMsIGZhY3RvciA9ICJjb25kaXRpb24iKQpib3RoX2V4cHQgPC0gY29tYmluZV9leHB0cyhscF9leHB0LCBvbGRfZXhwdCkKCnNucF9nZW5lcyA8LSBzbShzbnBzX3ZzX2dlbmVzKGJvdGhfZXhwdCwgc25wX3NldHMsIGV4cHRfbmFtZV9jb2wgPSAiY2hyb21vc29tZSIpKQojIyBJIHRoaW5rIHdlIGhhdmUgc29tZSBtZXRyaWNzIGhlcmUgd2UgY2FuIHBsb3QuLi4Kc25wX3N1YnNldCA8LSBzbShzbnBfc3Vic2V0X2dlbmVzKAogIGJvdGhfZXhwdCwgYm90aF9zbnBzLAogIGdlbmVzID0gYygiTFBBTDEzXzEyMDAxMDkwMCIsICJMUEFMMTNfMzQwMDEzMDAwIiwgIkxQQUwxM18wMDAwNTQxMDAiLAogICAgICAgICAgICAiTFBBTDEzXzE0MDAwNjEwMCIsICJMUEFMMTNfMTgwMDE4NTAwIiwgIkxQQUwxM18zMjAwMjIzMDAiKSkpCnp5bW9faGVhdCA8LSBwbG90X3NhbXBsZV9oZWF0bWFwKHNucF9zdWJzZXQsIHJvd19sYWJlbCA9IHJvd25hbWVzKGV4cHJzKHNucF9zdWJzZXQpKSkKenltb19oZWF0CmBgYAoKRGlkbid0IEkgY3JlYXRlIGEgc2V0IG9mIGRlbnNpdGllcyBieSBjaHJvbW9zb21lPwpPaCBJIHRoaW5rIHRoZXkgY29tZSBpbiBmcm9tIGdldF9zbnBfc2V0cygpCgojIyBTTlBTIGFzc29jaWF0ZWQgd2l0aCBjbGluaWNhbCByZXNwb25zZSBpbiB0aGUgVE1SQyBzYW1wbGVzCgpgYGB7ciBzbnBfY2xpbmljYWx9CmNsaW5pY2FsX3NldHMgPC0gZ2V0X3NucF9zZXRzKG5ld19zbnBzLCBmYWN0b3IgPSAiY2xpbmljYWxyZXNwb25zZSIpCgpkZW5zaXR5X3ZlYyA8LSBjbGluaWNhbF9zZXRzW1siZGVuc2l0eSJdXQpjaHJvbW9zb21lX2lkeCA8LSBncmVwKHBhdHRlcm4gPSAiTHBhTCIsIHggPSBuYW1lcyhkZW5zaXR5X3ZlYykpCmRlbnNpdHlfZGYgPC0gYXMuZGF0YS5mcmFtZShkZW5zaXR5X3ZlY1tjaHJvbW9zb21lX2lkeF0pCmRlbnNpdHlfZGZbWyJjaHIiXV0gPC0gcm93bmFtZXMoZGVuc2l0eV9kZikKY29sbmFtZXMoZGVuc2l0eV9kZikgPC0gYygiZGVuc2l0eV92ZWMiLCAiY2hyIikKZ2dwbG90KGRlbnNpdHlfZGYsIGFlc19zdHJpbmcoeCA9ICJjaHIiLCB5ID0gImRlbnNpdHlfdmVjIikpICsKICBnZ3Bsb3QyOjpnZW9tX2NvbCgpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkpCgojIyBjbGluaWNhbF93cml0dGVuIDwtIHdyaXRlX3ZhcmlhbnRzKG5ld19zbnBzKQpgYGAKCiMjIyBDcm9zcyByZWZlcmVuY2UgdGhlc2UgdmFyaWFudHMgYnkgZ2VuZQoKYGBge3Igc25wX2NsYXNzaWZpY2F0aW9uc30KY2xpbmljYWxfZ2VuZXMgPC0gc20oc25wc192c19nZW5lcyhscF9leHB0LCBjbGluaWNhbF9zZXRzLCBleHB0X25hbWVfY29sID0gImNocm9tb3NvbWUiKSkKCnNucF9kZW5zaXR5IDwtIG1lcmdlKGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfZ2VuZXNbWyJzdW1tYXJ5X2J5X2dlbmUiXV0pLAogICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGZEYXRhKGxwX2V4cHQpKSwKICAgICAgICAgICAgICAgICAgICAgYnkgPSAicm93Lm5hbWVzIikKc25wX2RlbnNpdHkgPC0gc25wX2RlbnNpdHlbLCBjKDEsIDIsIDQsIDE1KV0KY29sbmFtZXMoc25wX2RlbnNpdHkpIDwtIGMoIm5hbWUiLCAic25wcyIsICJwcm9kdWN0IiwgImxlbmd0aCIpCnNucF9kZW5zaXR5W1sicHJvZHVjdCJdXSA8LSB0b2xvd2VyKHNucF9kZW5zaXR5W1sicHJvZHVjdCJdXSkKc25wX2RlbnNpdHlbWyJsZW5ndGgiXV0gPC0gYXMubnVtZXJpYyhzbnBfZGVuc2l0eVtbImxlbmd0aCJdXSkKc25wX2RlbnNpdHlbWyJkZW5zaXR5Il1dIDwtIHNucF9kZW5zaXR5W1sic25wcyJdXSAvIHNucF9kZW5zaXR5W1sibGVuZ3RoIl1dCnNucF9pZHggPC0gb3JkZXIoc25wX2RlbnNpdHlbWyJkZW5zaXR5Il1dLCBkZWNyZWFzaW5nID0gVFJVRSkKc25wX2RlbnNpdHkgPC0gc25wX2RlbnNpdHlbc25wX2lkeCwgXQoKcmVtb3ZlcnMgPC0gYygiYW1hc3RpbiIsICJncDYzIiwgImxlaXNobWFub2x5c2luIikKZm9yIChyIGluIHJlbW92ZXJzKSB7CiAgZHJvcF9pZHggPC0gZ3JlcGwocGF0dGVybiA9IHIsIHggPSBzbnBfZGVuc2l0eVtbInByb2R1Y3QiXV0pCiAgc25wX2RlbnNpdHkgPC0gc25wX2RlbnNpdHlbIWRyb3BfaWR4LCBdCn0KIyMgRmlsdGVyIHRoZXNlIGZvciBbQXxhXW1hc3RpbiBncDYzIExlaXNobWFub2x5c2luCmBgYAoKCmBgYHtyIHNucF9pbnRlcnNlY3Rpb25zfQpjbGluaWNhbF9zbnBzIDwtIHNucHNfaW50ZXJzZWN0aW9ucyhscF9leHB0LCBjbGluaWNhbF9zZXRzLCBjaHJfY29sdW1uID0gImNocm9tb3NvbWUiKQoKZmFpbF9yZWZfc25wcyA8LSBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJpbnRlcnMiXV1bWyJmYWlsdXJlLCByZWZlcmVuY2Ugc3RyYWluIl1dKQpjdXJlX3NucHMgPC0gYXMuZGF0YS5mcmFtZShjbGluaWNhbF9zbnBzW1siaW50ZXJzIl1dW1siY3VyZSJdXSkKCmhlYWQoZmFpbF9yZWZfc25wcykKaGVhZChjdXJlX3NucHMpCgphbm5vdCA8LSBmRGF0YShscF9leHB0KQpjbGluaWNhbF9pbnRlcmVzdCA8LSBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJnZW5lX3N1bW1hcmllcyJdXVtbImN1cmUiXV0pCmNsaW5pY2FsX2ludGVyZXN0IDwtIG1lcmdlKGNsaW5pY2FsX2ludGVyZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJnZW5lX3N1bW1hcmllcyJdXVtbImZhaWx1cmUsIHJlZmVyZW5jZSBzdHJhaW4iXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJyb3cubmFtZXMiKQpyb3duYW1lcyhjbGluaWNhbF9pbnRlcmVzdCkgPC0gY2xpbmljYWxfaW50ZXJlc3RbWyJSb3cubmFtZXMiXV0KY2xpbmljYWxfaW50ZXJlc3RbWyJSb3cubmFtZXMiXV0gPC0gTlVMTApjb2xuYW1lcyhjbGluaWNhbF9pbnRlcmVzdCkgPC0gYygiY3VyZV9zbnBzIiwiZmFpbF9zbnBzIikKYW5ub3QgPC0gbWVyZ2UoYW5ub3QsIGNsaW5pY2FsX2ludGVyZXN0LCBieSA9ICJyb3cubmFtZXMiKQpyb3duYW1lcyhhbm5vdCkgPC0gYW5ub3RbWyJSb3cubmFtZXMiXV0KYW5ub3RbWyJSb3cubmFtZXMiXV0gPC0gTlVMTApmRGF0YShscF9leHB0JGV4cHJlc3Npb25zZXQpIDwtIGFubm90CmBgYAoKIyBaeW1vZGVtZSBmb3IgbmV3IHNhbXBsZXMKClRoZSBoZWF0bWFwIHByb2R1Y2VkIGhlcmUgc2hvdWxkIHNob3cgdGhlIHZhcmlhbnRzIG9ubHkgZm9yIHRoZSB6eW1vZGVtZSBnZW5lcy4KCiMjIEh1bnQgZm9yIHNucCBjbHVzdGVycwoKSSBhbSB0aGlua2luZyB0aGF0IGlmIHdlIGZpbmQgY2x1c3RlcnMgb2YgbG9jYXRpb25zIHdoaWNoIGFyZSB2YXJpYW50LCB0aGF0Cm1pZ2h0IHByb3ZpZGUgc29tZSBQQ1IgdGVzdGluZyBwb3NzaWJpbGl0aWVzLgoKYGBge3IgbmV3X3p5bW99Cm5ld19zZXRzIDwtIGdldF9zbnBfc2V0cyhuZXdfc25wcywgZmFjdG9yID0gInBoZW5vdHlwaWNjaGFyYWN0ZXJpc3RpY3MiKQpzdW1tYXJ5KG5ld19zZXRzKQojIyAxMDAwMDAwOiAyLjIKIyMgMDEwMDAwMDogMi4zCgpzdW1tYXJ5KG5ld19zZXRzW1siaW50ZXJzZWN0aW9ucyJdXVtbIjEwMDAwIl1dKQpzdW1tYXJ5KG5ld19zZXRzW1siaW50ZXJzZWN0aW9ucyJdXVtbIjAxMDAwIl1dKQpgYGAKClRodXMgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIDUxMSB2YXJpYW50cyBhc3NvY2lhdGVkIHdpdGggMi4yIGFuZCA0OSw3OTAgYXNzb2NpYXRlZCB3aXRoIDIuMy4KCiMjIyBBIHNtYWxsIGZ1bmN0aW9uIGZvciBzZWFyY2hpbmcgZm9yIHBvdGVudGlhbCBQQ1IgcHJpbWVycwoKVGhlIGZvbGxvd2luZyBmdW5jdGlvbiB1c2VzIHRoZSBwb3NpdGlvbmFsIGRhdGEgdG8gbG9vayBmb3Igc2VxdWVudGlhbAptaXNtYXRjaGVzIGFzc29jaWF0ZWQgd2l0aCB6eW1vZGVtZSBpbiB0aGUgaG9wZXMgdGhhdCB0aGVyZSB3aWxsIGJlCnNvbWUgcmVnaW9ucyB3aGljaCB3b3VsZCBwcm92aWRlIGdvb2QgcG90ZW50aWFsIHRhcmdldHMgZm9yIGEKUENSLWJhc2VkIGFzc2F5LgoKYGBge3Igc2VxdWVudGlhbF9zZWFyY2h9CnNlcXVlbnRpYWxfdmFyaWFudHMgPC0gZnVuY3Rpb24oc25wX3NldHMsIGNvbmRpdGlvbnMgPSBOVUxMLCBtaW5pbXVtID0gMywgbWF4aW11bV9zZXBhcmF0aW9uID0gMykgewogIGlmIChpcy5udWxsKGNvbmRpdGlvbnMpKSB7CiAgICBjb25kaXRpb25zIDwtIDEKICB9CiAgaW50ZXJzZWN0aW9uX3NldHMgPC0gc25wX3NldHNbWyJpbnRlcnNlY3Rpb25zIl1dCiAgaW50ZXJzZWN0aW9uX25hbWVzIDwtIHNucF9zZXRzW1sic2V0X25hbWVzIl1dCiAgY2hvc2VuX2ludGVyc2VjdGlvbiA8LSAxCiAgaWYgKGlzLm51bWVyaWMoY29uZGl0aW9ucykpIHsKICAgIGNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gY29uZGl0aW9ucwogIH0gZWxzZSB7CiAgICBpbnRlcnNlY3Rpb25faWR4IDwtIGludGVyc2VjdGlvbl9uYW1lcyA9PSBjb25kaXRpb25zCiAgICBjaG9zZW5faW50ZXJzZWN0aW9uIDwtIG5hbWVzKGludGVyc2VjdGlvbl9uYW1lcylbaW50ZXJzZWN0aW9uX2lkeF0KICB9CgogIHBvc3NpYmxlX3Bvc2l0aW9ucyA8LSBpbnRlcnNlY3Rpb25fc2V0c1tbY2hvc2VuX2ludGVyc2VjdGlvbl1dCiAgcG9zaXRpb25fdGFibGUgPC0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBwb3NzaWJsZV9wb3NpdGlvbnMpCiAgcGF0IDwtICJeY2hyXyguKylfcG9zXyguKylfcmVmXy4qJCIKICBwb3NpdGlvbl90YWJsZVtbImNociJdXSA8LSBnc3ViKHBhdHRlcm4gPSBwYXQsIHJlcGxhY2VtZW50ID0gIlxcMSIsIHggPSByb3duYW1lcyhwb3NpdGlvbl90YWJsZSkpCiAgcG9zaXRpb25fdGFibGVbWyJwb3MiXV0gPC0gYXMubnVtZXJpYyhnc3ViKHBhdHRlcm4gPSBwYXQsIHJlcGxhY2VtZW50ID0gIlxcMiIsIHggPSByb3duYW1lcyhwb3NpdGlvbl90YWJsZSkpKQogIHBvc2l0aW9uX2lkeCA8LSBvcmRlcihwb3NpdGlvbl90YWJsZVssICJjaHIiXSwgcG9zaXRpb25fdGFibGVbLCAicG9zIl0pCiAgcG9zaXRpb25fdGFibGUgPC0gcG9zaXRpb25fdGFibGVbcG9zaXRpb25faWR4LCBdCiAgcG9zaXRpb25fdGFibGVbWyJkaXN0Il1dIDwtIDAKCiAgbGFzdF9jaHIgPC0gIiIKICBmb3IgKHIgaW4gMTpucm93KHBvc2l0aW9uX3RhYmxlKSkgewogICAgdGhpc19jaHIgPC0gcG9zaXRpb25fdGFibGVbciwgImNociJdCiAgICBpZiAociA9PSAxKSB7CiAgICAgIHBvc2l0aW9uX3RhYmxlW3IsICJkaXN0Il0gPC0gcG9zaXRpb25fdGFibGVbciwgInBvcyJdCiAgICAgIGxhc3RfY2hyIDwtIHRoaXNfY2hyCiAgICAgIG5leHQKICAgIH0KICAgIGlmICh0aGlzX2NociA9PSBsYXN0X2NocikgewogICAgICBwb3NpdGlvbl90YWJsZVtyLCAiZGlzdCJdIDwtIHBvc2l0aW9uX3RhYmxlW3IsICJwb3MiXSAtIHBvc2l0aW9uX3RhYmxlW3IgLSAxLCAicG9zIl0KICAgIH0gZWxzZSB7CiAgICAgIHBvc2l0aW9uX3RhYmxlW3IsICJkaXN0Il0gPC0gcG9zaXRpb25fdGFibGVbciwgInBvcyJdCiAgICB9CiAgICBsYXN0X2NociA8LSB0aGlzX2NocgogIH0KCiAgc2VxdWVudGlhbHMgPC0gcG9zaXRpb25fdGFibGVbWyJkaXN0Il1dIDw9IG1heGltdW1fc2VwYXJhdGlvbgogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBzdW0oc2VxdWVudGlhbHMpLCAiIGNhbmRpZGF0ZSByZWdpb25zLiIpCgogICMjIFRoZSBmb2xsb3dpbmcgY2FuIHRlbGwgbWUgaG93IG1hbnkgcnVucyBvZiBlYWNoIGxlbmd0aCBvY2N1cnJlZCwgdGhhdCBpcyBub3QgcXVpdGUgd2hhdCBJIHdhbnQuCiAgIyMgTm93IHVzZSBydW4gbGVuZ3RoIGVuY29kaW5nIHRvIGZpbmQgdGhlIHNldCBvZiBzZXF1ZW50aWFsIHNlcXVlbnRpYWxzIQogIHJsZV9yZXN1bHQgPC0gcmxlKHNlcXVlbnRpYWxzKQogIHJsZV92YWx1ZXMgPC0gcmxlX3Jlc3VsdFtbInZhbHVlcyJdXQogICMjIFRoZSBmb2xsb3dpbmcgbGluZSBpcyBlcXVpdmFsZW50IHRvIGp1c3QgbGVhdmluZyB2YWx1ZXMgYWxvbmU6CiAgIyMgdHJ1ZV92YWx1ZXMgPC0gcmxlX3Jlc3VsdFtbInZhbHVlcyJdXSA9PSBUUlVFCiAgcmxlX2xlbmd0aHMgPC0gcmxlX3Jlc3VsdFtbImxlbmd0aHMiXV0KICB0cnVlX3NlcXVlbnRpYWxzIDwtIHJsZV9sZW5ndGhzW3JsZV92YWx1ZXNdCiAgcmxlX2lkeCA8LSBjdW1zdW0ocmxlX2xlbmd0aHMpW3doaWNoKHJsZV92YWx1ZXMpXQoKICBwb3NpdGlvbl90YWJsZVtbImxhc3Rfc2VxdWVudGlhbCJdXSA8LSAwCiAgY291bnQgPC0gMAogIGZvciAociBpbiBybGVfaWR4KSB7CiAgICBjb3VudCA8LSBjb3VudCArIDEKICAgIHBvc2l0aW9uX3RhYmxlW3IsICJsYXN0X3NlcXVlbnRpYWwiXSA8LSB0cnVlX3NlcXVlbnRpYWxzW2NvdW50XQogIH0KICBtZXNzYWdlKCJUaGUgbWF4aW11bSBzZXF1ZW50aWFsIHNldCBpczogIiwgbWF4KHBvc2l0aW9uX3RhYmxlW1sibGFzdF9zZXF1ZW50aWFsIl1dKSwgIi4iKQoKICB3YW50ZWRfaWR4IDwtIHBvc2l0aW9uX3RhYmxlW1sibGFzdF9zZXF1ZW50aWFsIl1dID49IG1pbmltdW0KICB3YW50ZWQgPC0gcG9zaXRpb25fdGFibGVbd2FudGVkX2lkeCwgYygiY2hyIiwgInBvcyIpXQogIHJldHVybih3YW50ZWQpCn0KCnp5bW8yMl9zZXF1ZW50aWFscyA8LSBzZXF1ZW50aWFsX3ZhcmlhbnRzKG5ld19zZXRzLCBjb25kaXRpb25zID0gIjIyIikKZGltKHp5bW8yMl9zZXF1ZW50aWFscykKIyMgNyBjYW5kaWRhdGUgcmVnaW9ucyBmb3Igenltb2RlbWUgMi4yIC0tIHRodXMgSSBhbSBiZXR0aW5nIHRoYXQgdGhlIHJlZmVyZW5jZSBzdHJhaW4gaXMgYSAyLjIKenltbzIzX3NlcXVlbnRpYWxzIDwtIHNlcXVlbnRpYWxfdmFyaWFudHMobmV3X3NldHMsIGNvbmRpdGlvbnMgPSAiMjMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5pbXVtID0gMSwgbWF4aW11bV9zZXBhcmF0aW9uID0gMykKZGltKHp5bW8yM19zZXF1ZW50aWFscykKIyMgSW4gY29udHJhc3QsIHRoZXJlIGFyZSBsb3RzICg1ODcpIG9mIGludGVyZXN0aW5nIHJlZ2lvbnMgZm9yIDIuMyEKYGBgCgojIyBNYWtlIGEgaGVhdG1hcCBkZXNjcmliaW5nIHRoZSBjbHVzdGVyaW5nIG9mIHZhcmlhbnRzCgpXZSBjYW4gY3Jvc3MgcmVmZXJlbmNlIHRoZSB2YXJpYW50cyBhZ2FpbnN0IHRoZSB6eW1vZGVtZSBzdGF0dXMgYW5kCnBsb3QgYSBoZWF0bWFwIG9mIHRoZSByZXN1bHRzIGFuZCBob3BlZnVsbHkgc2VlIGhvdyB0aGV5IHNlcGFyYXRlLgoKYGBge3Igenltb19oZWF0bWFwc30Kc25wX2dlbmVzIDwtIHNtKHNucHNfdnNfZ2VuZXMobHBfZXhwdCwgbmV3X3NldHMsIGV4cHRfbmFtZV9jb2wgPSAiY2hyb21vc29tZSIpKQpuZXdfenltb19ub3JtICA8LSBub3JtYWxpemVfZXhwdChuZXdfc25wcywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gVFJVRSkKbmV3X3p5bW9fbm9ybSA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG5ld196eW1vX25vcm0sIGZhY3QgPSAicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyIpCgp6eW1vX2hlYXQgPC0gcGxvdF9kaXNoZWF0KG5ld196eW1vX25vcm0pCnp5bW9faGVhdFtbInBsb3QiXV0KYGBgCgojIyMgQW5ub3RhdGVkIGhlYXRtYXAgb2YgdmFyaWFudHMKCk5vdyBsZXQgdXMgdHJ5IHRvIG1ha2UgYSBoZWF0bWFwIHdoaWNoIGluY2x1ZGVzIHNvbWUgb2YgdGhlIGFubm90YXRpb24gZGF0YS4KCmBgYHtyIHp5bW9faGVhdF9wYW5lbF9nZW5lc30KZGVzIDwtIGJvdGhfbm9ybVtbImRlc2lnbiJdXQp1bmRlZl9pZHggPC0gaXMubmEoZGVzW1sic3RyYWluIl1dKQpkZXNbdW5kZWZfaWR4LCAic3RyYWluIl0gPC0gInVua25vd24iCgojI2htY29scyA8LSBjb2xvclJhbXBQYWxldHRlKGMoInllbGxvdyIsImJsYWNrIiwiZGFya2JsdWUiKSkoMjU2KQpjb3JyZWxhdGlvbnMgPC0gaHBnbF9jb3IoZXhwcnMoYm90aF9ub3JtKSkKCnp5bW9fbWlzc2luZ19pZHggPC0gaXMubmEoZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSkKZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSkKZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSkKZGVzW3p5bW9fbWlzc2luZ19pZHgsICJwaGVub3R5cGljY2hhcmFjdGVyaXN0aWNzIl0gPC0gInVua25vd24iCm15ZGVuZHJvIDwtIGxpc3QoCiAgImNsdXN0ZnVuIiA9IGhjbHVzdCwKICAibHdkIiA9IDIuMCkKY29sX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShkZXNbLCBjKCJwaGVub3R5cGljY2hhcmFjdGVyaXN0aWNzIiwgImNsaW5pY2FsY2F0ZWdvcmljYWwiKV0pCgp1bmtub3duX2NsaW5pY2FsIDwtIGlzLm5hKGNvbF9kYXRhW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSkKcm93X2RhdGEgPC0gYXMuZGF0YS5mcmFtZShkZXNbLCBjKCJzdHJhaW4iKV0pCmNvbG5hbWVzKGNvbF9kYXRhKSA8LSBjKCJ6eW1vZGVtZSIsICJvdXRjb21lIikKY29sX2RhdGFbdW5rbm93bl9jbGluaWNhbCwgIm91dGNvbWUiXSA8LSAidW5kZWZpbmVkIgoKY29sbmFtZXMocm93X2RhdGEpIDwtIGMoInN0cmFpbiIpCm15YW5ub3QgPC0gbGlzdCgKICAiQ29sIiA9IGxpc3QoImRhdGEiID0gY29sX2RhdGEpLAogICJSb3ciID0gbGlzdCgiZGF0YSIgPSByb3dfZGF0YSkpCm15Y2x1c3QgPC0gbGlzdCgiY3V0aCIgPSAxLjAsCiAgICAgICAgICAgICAgICAiY29sIiA9IEJyZXdlckNsdXN0ZXJDb2wpCm15bGFicyA8LSBsaXN0KAogICJSb3ciID0gbGlzdCgibnJvdyIgPSA0KSwKICAiQ29sIiA9IGxpc3QoIm5yb3ciID0gNCkpCmhtY29scyA8LSBjb2xvclJhbXBQYWxldHRlKGMoImRhcmtibHVlIiwgImJlaWdlIikpKDI0MCkKbWFwMSA8LSBhbm5IZWF0bWFwMigKICBjb3JyZWxhdGlvbnMsCiAgZGVuZHJvZ3JhbSA9IG15ZGVuZHJvLAogIGFubm90YXRpb24gPSBteWFubm90LAogIGNsdXN0ZXIgPSBteWNsdXN0LAogIGxhYmVscyA9IG15bGFicywKICAjIyBUaGUgZm9sbG93aW5nIGNvbnRyb2xzIGlmIHRoZSBwaWN0dXJlIGlzIHN5bW1ldHJpYwogIHNjYWxlID0gIm5vbmUiLAogIGNvbCA9IGhtY29scykKcHAoZmlsZSA9ICJpbWFnZXMvZGVuZHJvX2hlYXRtYXAucG5nIiwgaW1hZ2UgPSBtYXAxLCBoZWlnaHQgPSAyMCwgd2lkdGggPSAyMCkKYGBgCgpQcmludCB0aGUgbGFyZ2VyIGhlYXRtYXAgc28gdGhhdCBhbGwgdGhlIGxhYmVscyBhcHBlYXIuICBLZWVwIGluIG1pbmQKdGhhdCBhcyB3ZSBnZXQgbW9yZSBzYW1wbGVzLCB0aGlzIGltYWdlIG5lZWRzIHRvIGNvbnRpbnVlIGdldHRpbmcKYmlnZ2VyLgoKIVtiaWcgaGVhdG1hcF0oaW1hZ2VzL2RlbmRyb19oZWF0bWFwLnBuZykKCgpgYGB7ciB0aGVyZXNhX2lkZWF9CnBoZW5vIDwtIHN1YnNldF9leHB0KGxwX2V4cHQsIHN1YnNldCA9ICJjb25kaXRpb249PSd6Mi4yJ3xjb25kaXRpb249PSd6Mi4zJyIpCnBoZW5vIDwtIHN1YnNldF9leHB0KHBoZW5vLCBzdWJzZXQ9IiFpcy5uYShwRGF0YShwaGVubylbWydiY2Z0YWJsZSddXSkiKQpwaGVub19zbnBzIDwtIHNtKGNvdW50X2V4cHRfc25wcyhwaGVubywgYW5ub3RfY29sdW1uID0gImJjZnRhYmxlIikpCgp4cmVmX3Byb3AgPC0gdGFibGUocGhlbm9fc25wc1tbImNvbmRpdGlvbnMiXV0pCnBoZW5vX3NucHMkY29uZGl0aW9ucwppZHhfdGJsIDwtIGV4cHJzKHBoZW5vX3NucHMpID4gNQpuZXdfdGJsIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzID0gcm93bmFtZXMoZXhwcnMocGhlbm9fc25wcykpKQpmb3IgKG4gaW4gbmFtZXMoeHJlZl9wcm9wKSkgewogIG5ld190YmxbW25dXSA8LSAwCiAgaWR4X2NvbHMgPC0gd2hpY2gocGhlbm9fc25wc1tbImNvbmRpdGlvbnMiXV0gPT0gbikKICBwcm9wX2NvbCA8LSByb3dTdW1zKGlkeF90YmxbLCBpZHhfY29sc10pIC8geHJlZl9wcm9wW25dCiAgbmV3X3RibFtuXSA8LSBwcm9wX2NvbAp9CmtlZXBlcnMgPC0gZ3JlcGwoeCA9IHJvd25hbWVzKG5ld190YmwpLCBwYXR0ZXJuID0gIkxwYUwxMyIpCm5ld190YmwgPC0gbmV3X3RibFtrZWVwZXJzLCBdCm5ld190YmxbWyJzdHJvbmcyMiJdXSA8LSAxLjAwMSAtIG5ld190YmxbWyJ6Mi4yIl1dCm5ld190YmxbWyJzdHJvbmcyMyJdXSA8LSAxLjAwMSAtIG5ld190YmxbWyJ6Mi4zIl1dCnMyMl9uYSA8LSBuZXdfdGJsW1sic3Ryb25nMjIiXV0gPiAxCm5ld190YmxbczIyX25hLCAic3Ryb25nMjIiXSA8LSAxCnMyM19uYSA8LSBuZXdfdGJsW1sic3Ryb25nMjMiXV0gPiAxCm5ld190YmxbczIzX25hLCAic3Ryb25nMjMiXSA8LSAxCgpuZXdfdGJsW1siU05QIl1dIDwtIHJvd25hbWVzKG5ld190YmwpCm5ld190YmxbWyJDaHJvbW9zb21lIl1dIDwtIGdzdWIoeCA9IG5ld190YmxbWyJTTlAiXV0sIHBhdHRlcm4gPSAiY2hyXyguKilfcG9zXy4qIiwgcmVwbGFjZW1lbnQgPSAiXFwxIikKbmV3X3RibFtbIlBvc2l0aW9uIl1dIDwtIGdzdWIoeCA9IG5ld190YmxbWyJTTlAiXV0sIHBhdHRlcm4gPSAiLipfcG9zXyhcXGQrKV8uKiIsIHJlcGxhY2VtZW50ID0gIlxcMSIpCm5ld190YmwgPC0gbmV3X3RibFssIGMoIlNOUCIsICJDaHJvbW9zb21lIiwgIlBvc2l0aW9uIiwgInN0cm9uZzIyIiwgInN0cm9uZzIzIildCgoKbGlicmFyeShDTXBsb3QpCkNNcGxvdChuZXdfdGJsLCBiaW4uc2l6ZSA9IDEwMDAwMCkKCkNNcGxvdChuZXdfdGJsLCBwbG90LnR5cGU9Im0iLCBtdWx0cmFja3M9VFJVRSwgdGhyZXNob2xkID0gYygwLjAxLCAwLjA1KSwKICAgICAgIHRocmVzaG9sZC5sd2Q9YygxLDEpLCB0aHJlc2hvbGQuY29sPWMoImJsYWNrIiwiZ3JleSIpLAogICAgICAgYW1wbGlmeT1UUlVFLCBiaW4uc2l6ZT0xZTUsCiAgICAgICBjaHIuZGVuLmNvbD1jKCJkYXJrZ3JlZW4iLCAieWVsbG93IiwgInJlZCIpLAogICAgICAgc2lnbmFsLmNvbD1jKCJyZWQiLCAiZ3JlZW4iLCAiYmx1ZSIpLAogICAgICAgc2lnbmFsLmNleD0xLCBmaWxlPSJqcGciLCBtZW1vPSIiLCBkcGk9MzAwLCBmaWxlLm91dHB1dD1UUlVFLCB2ZXJib3NlPVRSVUUpCmBgYAoKIVtTTlAgRGVuc2l0eV0oU05QLURlbnNpdHkucmF0aW8uanBnKQohW0NpcmN1bGFyIE1hbmhhdHRhbl0oQ2lyY3VsYXItTWFuaGF0dGFuLnJhdGlvLmpwZykKIVtSZWN0YW5ndWxhciBNYW5oYXR0YW5dKFJlY3Rhbmd1bGFyLU1hbmhhdHRhbi5yYXRpby5qcGcpCiFbUVFdKFFRcGxvdC5yYXRpby5qcGcpCgoKCgpgYGB7ciBzYXZlbWV9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIHBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCiAgbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCBzYXZlZmlsZSkpCiAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKfQpgYGAKCmBgYHtyIGxvYWRtZV9hZnRlciwgZXZhbCA9IEZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=