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

1 Introduction

This is mostly just a run of this worksheet to reacquaint myself with it.

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 Load a genome

meta <- EuPathDB::download_eupath_metadata(webservice="tritrypdb")
## Unable to find species names for 2 species.
## Leishmania sp. Ghana MHOM/GH/2012/GH5, Leishmania sp. Namibia MPRO/NA/1975/252/LV425
## Appending to an existing file: EuPathDB/metadata/biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/GRanges_biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/OrgDb_biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/TxDb_biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/OrganismDbi_biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/BSgenome_biocv3.14_tritrypdbv55_metadata.csv
## Appending to an existing file: EuPathDB/metadata/biocv3.14_tritrypdbv55_invalid_metadata.csv
## Appending to an existing file: EuPathDB/metadata/GRanges_biocv3.14_tritrypdbv55_invalid_metadata.csv
## Appending to an existing file: EuPathDB/metadata/OrgDb_biocv3.14_tritrypdbv55_invalid_metadata.csv
## Appending to an existing file: EuPathDB/metadata/TxDb_biocv3.14_tritrypdbv55_invalid_metadata.csv
## Appending to an existing file: EuPathDB/metadata/OrganismDbi_biocv3.14_tritrypdbv55_invalid_metadata.csv
## Appending to an existing file: EuPathDB/metadata/BSgenome_biocv3.14_tritrypdbv55_invalid_metadata.csv
lp_entry <- EuPathDB::get_eupath_entry(species="Leishmania panamensis", metadata=meta)
## Found the following hits: Leishmania panamensis MHOM/COL/81/L13, Leishmania panamensis strain MHOM/PA/94/PSC-1, choosing the first.
## Using: Leishmania panamensis MHOM/COL/81/L13.
colnames(lp_entry)
##  [1] "AnnotationVersion"  "AnnotationSource"   "BiocVersion"       
##  [4] "DataProvider"       "Genome"             "GenomeSource"      
##  [7] "GenomeVersion"      "NumArrayGene"       "NumChipChipGene"   
## [10] "NumChromosome"      "NumCodingGene"      "NumCommunity"      
## [13] "NumContig"          "NumEC"              "NumEST"            
## [16] "NumGene"            "NumGO"              "NumOrtholog"       
## [19] "NumOtherGene"       "NumPopSet"          "NumProteomics"     
## [22] "NumPseudogene"      "NumRNASeq"          "NumRTPCR"          
## [25] "NumSNP"             "NumTFBS"            "Organellar"        
## [28] "ReferenceStrain"    "MegaBP"             "PrimaryKey"        
## [31] "ProjectID"          "RecordClassName"    "SourceID"          
## [34] "SourceVersion"      "TaxonomyID"         "TaxonomyName"      
## [37] "URLGenome"          "URLGFF"             "URLProtein"        
## [40] "Coordinate_1_based" "Maintainer"         "SourceUrl"         
## [43] "Tags"               "BsgenomePkg"        "GrangesPkg"        
## [46] "OrganismdbiPkg"     "OrgdbPkg"           "TxdbPkg"           
## [49] "Taxon"              "Genus"              "Species"           
## [52] "Strain"             "BsgenomeFile"       "GrangesFile"       
## [55] "OrganismdbiFile"    "OrgdbFile"          "TxdbFile"          
## [58] "GenusSpecies"       "TaxonUnmodified"    "TaxonCanonical"    
## [61] "TaxonXref"
testing_panamensis <- "BSGenome.Leishmania.panamensis.MHOMCOL81L13.v53"
## testing_panamensis <- EuPathDB::make_eupath_bsgenome(entry=lp_entry, eu_version="v46")
library(as.character(testing_panamensis), character.only=TRUE)
## Loading required package: BSgenome
## Loading required package: Biostrings
## Loading required package: XVector
## 
## Attaching package: 'Biostrings'
## The following object is masked from 'package:base':
## 
##     strsplit
## Loading required package: rtracklayer
genome <- get0(as.character(testing_panamensis))

4 TODO:

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

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

5.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’

5.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 = 8550) %>%
  subset_expt(coverage = 5000000) %>%
  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 8550 non-zero genes are:
## TMRC20002 TMRC20006 
##  11681227   6670348
## subset_expt(): There were 75, now there are 73 samples.
## The samples removed (and read coverage) when filtering samples with less than 5e+06 reads are:
## TMRC20004 TMRC20029 
##    564812   1658096
## subset_expt(): There were 73, now there are 71 samples.
## semantic_expt_filter(): Removed 68 genes.
libsizes <- plot_libsize(lp_expt)
pp(file = "images/lp_expt_libsizes.png", image = libsizes$plot, width = 14, height = 9)

## I think samples 7,10 should be removed at minimum, probably also 9,11
nonzero <- plot_nonzero(lp_expt)
pp(file = "images/lp_nonzero.png", image = nonzero$plot, width = 9, height = 9)
## Warning: ggrepel: 50 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 53 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

lp_box <- plot_boxplot(lp_expt)
## 5364 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

5.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’.

5.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_colors <- list(
    "z2.1" = "#0000cc",
    "z2.3" = "#874400",
    "z2.2" = "#df7000",
    "z2.4" = "#cc0000",
    "unknown" = "#cbcbcb",
    "null" = "#000000")
clinical_samples <- lp_expt %>%
  set_expt_batches(fact = sus_categorical) %>%
  set_expt_colors(clinical_colors)

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",
                     plot_labels = FALSE)
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
## Warning: ggrepel: 13 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

clinical_nb <- normalize_expt(clinical_samples, convert = "cpm", transform = "log2",
                         filter = TRUE, batch = "svaseq")
## Removing 142 low-count genes (8568 remaining).
## batch_counts: Before batch/surrogate estimation, 1008 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 3380 entries are 0<x<1: 1%.
## Setting 324 low elements to zero.
## transform_counts: Found 324 values equal to 0, adding 1 to the matrix.
clinical_nb_pca <- plot_pca(clinical_nb, plot_title = "PCA of parasite expression values",
                            plot_labels = FALSE)
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
## Warning: ggrepel: 52 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

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

plot_sm(clinical_norm)$plot
## Performing correlation.

5.5 By Cure/Fail status

cf_colors <- list(
    "cure" = "#006f00",
    "fail" = "#9dffa0",
    "unknown" = "#cbcbcb",
    "notapplicable" = "#000000")
cf_expt <- set_expt_conditions(lp_expt, fact = "clinicalcategorical") %>%
  set_expt_batches(fact = sus_categorical) %>%
  set_expt_colors(cf_colors)
## Warning in set_expt_colors(., cf_colors): Colors for the following categories
## are not being used: notapplicable.
cf_norm <- normalize_expt(cf_expt, convert = "cpm", transform = "log2",
                          norm = "quant", filter = TRUE)
## Removing 142 low-count genes (8568 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",
                     plot_labels = FALSE)
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 142 low-count genes (8568 remaining).
## batch_counts: Before batch/surrogate estimation, 2 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 4130 entries are 0<x<1: 1%.
## Setting 154 low elements to zero.
## transform_counts: Found 154 values equal to 0, adding 1 to the matrix.
cf_nb_pca <- plot_pca(cf_nb, plot_title = "PCA of parasite expression values",
                      plot_labels = FALSE)
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 142 low-count genes (8568 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 2.850e-01 0.331134 0.47800 1.728e-03 0.69347 0.42085
## zymodemecategorical 6.720e-06 0.005922 0.70766 3.336e-02 0.01269 0.09026
## pathogenstrain      7.092e-01 0.776303 0.84356 4.512e-06 0.01811 0.56192
## passagenumber       8.896e-01 0.237729 0.04096 2.795e-02 0.22294 0.41299
test$cor_heatmap

sus_colors <- list(
    "resistant" = "#8563a7",
    "sensitive" = "#8d0000",
    "ambiguous" = "#cbcbcb",
    "unknown" = "#000000")
sus_expt <- set_expt_conditions(lp_expt, fact = "sus_category") %>%
  set_expt_batches(fact = "zymodemecategorical") %>%
  set_expt_colors(colors = sus_colors)

sus_norm <- normalize_expt(sus_expt, transform = "log2", convert = "cpm",
                           norm = "quant", filter = TRUE)
## Removing 142 low-count genes (8568 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",
                    plot_labels = FALSE)
pp(file = "images/sus_norm_pca.png", image = sus_pca[["plot"]])

sus_nb <- normalize_expt(sus_expt, transform = "log2", convert = "cpm",
                         batch = "svaseq", filter = TRUE)
## Removing 142 low-count genes (8568 remaining).
## batch_counts: Before batch/surrogate estimation, 1008 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 3380 entries are 0<x<1: 1%.
## Setting 229 low elements to zero.
## transform_counts: Found 229 values equal to 0, adding 1 to the matrix.
sus_nb_pca <- plot_pca(sus_nb, plot_title = "PCA of parasite expression values",
                       plot_labels = FALSE)
pp(file = "images/sus_nb_pca.png", image = sus_nb_pca[["plot"]])

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

6.1 Differential expression

6.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 71, now there are 55 samples.
zy_norm <- normalize_expt(zy_expt, filter = TRUE, convert = "cpm", norm = "quant")
## Removing 160 low-count genes (8550 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")))

6.1.2 Images of zymodeme DE

pp(file = "images/zymo_ma.png", image = zy_table[["plots"]][["z23_vs_z22"]][["deseq_ma_plots"]][["plot"]])

6.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")))

6.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 29.300 0e+00 13.430 0e+00 9.0070 0.2369 3.9690 -4.1880 15.756 0.1172 8.157 10.200 0.0000 0.0000 841.70 1.1550 25.370 0 115812.91 16.821 0.0000 1158.119 782.513 4.955e+05 356.464 1.0000 0.0000 1.0000 4.9800 60.02 0 1.3620 1.619 -4.2760 0.1099 2.370e-01 4.861e-138 1.647e-11 0.000e+00 5.941e-08 14.280 1.013e+01 7.092e-01 3.663e-02 4.026e-03
LPAL13_000035800 LPAL13_000035800 hypothetical protein protein coding LPAL13_SCAF000500 737 1006 - reverse Not Assigned 270.0 269 14.910 0e+00 14.080 0e+00 10.4500 0.2580 5.3190 -3.9740 15.252 0.3680 9.293 11.610 0.0000 0.0000 2880.00 1.1430 13.040 0 31670.08 14.951 0.1254 4287.362 2896.907 1.341e+07 1311.656 0.0000 0.0000 0.0000 6.7500 86.47 0 2.2850 1.554 -4.3360 0.1248 2.577e-01 2.908e-35 1.154e-16 0.000e+00 7.479e-09 16.200 9.099e+00 5.616e-01 4.160e-02 5.192e-03
LPAL13_320026300 LPAL13_320026300 hypothetical protein, conserved protein coding LpaL13_32 754268 755485 - reverse 32 1218.0 1217 14.210 0e+00 13.330 0e+00 9.8160 0.2961 4.7860 -4.0330 18.222 0.6163 8.819 9.984 0.0000 0.0000 1521.00 1.1160 12.740 0 17750.55 14.116 0.1173 2258.771 1526.235 2.020e+06 672.288 0.0000 0.0000 0.0000 5.8310 77.84 0 2.0190 1.445 -4.4300 0.1531 2.965e-01 1.034e-33 5.258e-15 0.000e+00 4.003e-08 12.360 9.588e-02 7.757e-03 5.103e-02 7.813e-03
LPAL13_000053200 LPAL13_000053200 hypothetical protein protein coding LPAL13_SCAF000804 5037 5249 - reverse Not Assigned 213.0 212 8.774 0e+00 10.180 0e+00 5.8300 0.0288 1.0040 -4.1880 9.040 0.1172 5.193 8.521 0.0000 0.0000 75.03 1.0880 8.064 0 12533.34 13.614 0.0000 125.323 84.678 7.766e+03 39.301 1.0000 0.0000 1.0000 1.5420 52.91 0 -0.9226 2.861 -2.8140 0.0056 3.481e-02 4.408e-13 2.647e-10 0.000e+00 7.765e-07 8.168 4.425e-02 5.417e-03 1.866e-03 1.045e-05
LPAL13_000051300 LPAL13_000051300 hypothetical protein, conserved protein coding LPAL13_SCAF000772 11 2344 + forward Not Assigned 2334.0 2333 8.477 0e+00 9.468 0e+00 3.7190 0.2694 0.2373 -4.0070 10.238 0.5216 4.244 6.306 0.0000 0.0000 135.60 1.2650 6.701 0 1753.26 10.776 0.0861 168.514 113.889 6.534e+04 56.718 0.0000 0.0000 0.0000 2.4020 32.16 0 -1.1240 1.520 -4.3650 0.1330 2.690e-01 4.676e-09 1.618e-06 0.000e+00 2.766e-05 6.999 2.573e+00 3.676e-01 4.433e-02 5.896e-03
LPAL13_000040700 LPAL13_000040700 hypothetical protein, conserved protein coding LPAL13_SCAF000598 54 1067 + forward Not Assigned 1014.0 1013 7.671 0e+00 6.800 0e+00 2.8180 0.1002 -1.2510 -3.9900 6.479 0.5345 2.740 4.971 0.0000 0.0004 20.16 1.1500 6.669 0 186.50 7.543 0.1278 25.699 17.405 3.919e+02 8.201 0.0000 0.0000 0.0000 -0.1417 25.17 0 -2.3660 2.188 -3.7130 0.0321 1.004e-01 5.117e-09 2.694e-05 0.000e+00 3.968e-04 5.586 1.673e+00 2.996e-01 1.069e-02 3.430e-04
LPAL13_000017600 LPAL13_000017600 hypothetical protein, conserved protein coding LPAL13_SCAF000146 359 586 + forward Not Assigned 228.0 227 6.599 0e+00 6.582 0e+00 5.9140 0.0594 4.4470 -1.1540 4.361 2.6176 5.601 8.940 0.0000 0.0000 615.90 0.6798 9.707 0 80.79 6.336 11.8247 956.082 649.836 3.876e+05 64.957 0.0000 1.0000 0.0000 4.5290 58.28 0 2.3410 2.483 -3.0470 0.0155 5.934e-02 5.443e-19 3.255e-11 9.676e-01 2.057e-07 6.658 2.129e+00 3.198e-01 5.160e-03 7.988e-05
LPAL13_300029400 LPAL13_300029400 hypothetical protein, conserved protein coding LpaL13_30 853953 854150 - reverse 30 198.0 197 6.334 0e+00 6.254 0e+00 4.9430 0.0024 1.7270 -2.5570 1.492 1.9180 4.284 9.143 0.0000 0.0000 89.08 0.7409 8.549 0 64.90 6.020 1.8983 123.831 84.285 8.962e+03 24.716 0.0000 1.0000 0.0000 1.7340 54.93 0 0.0165 3.995 -0.5115 0.0002 2.361e-03 1.330e-14 1.268e-10 9.650e-01 1.550e-06 5.915 5.901e-01 9.977e-02 5.337e-05 8.544e-09
LPAL13_080010600 LPAL13_080010600 hypothetical protein, conserved protein coding LpaL13_08 195555 195749 - reverse 8 195.0 194 5.937 0e+00 7.435 0e+00 2.3330 0.0513 -1.8840 -4.1880 4.892 0.1172 2.304 5.084 0.0000 0.0004 10.97 1.1490 5.165 0 1825.43 10.834 0.0000 18.244 12.327 4.601e+02 6.571 1.0000 0.0000 1.0000 -0.9372 26.93 0 -3.1350 2.562 -3.3070 0.0126 6.156e-02 9.050e-06 1.393e-05 0.000e+00 4.302e-04 4.938 4.273e+00 8.653e-01 4.200e-03 5.292e-05
LPAL13_000011700 LPAL13_000011700 hypothetical protein protein coding LPAL13_SCAF000076 101 364 - reverse Not Assigned 264.0 263 5.837 0e+00 7.381 0e+00 2.6660 0.0452 -1.3950 -4.1880 6.725 0.1172 2.793 5.291 0.0000 0.0003 13.83 1.1890 4.910 0 2415.59 11.238 0.0000 24.146 16.315 4.529e+02 8.171 1.0000 0.0000 1.0000 -0.6026 24.80 0 -2.9340 2.632 -3.1710 0.0105 4.521e-02 2.898e-05 3.232e-05 0.000e+00 3.013e-04 5.108 1.611e+00 3.154e-01 3.494e-03 3.660e-05
LPAL13_040019400 LPAL13_040019400 hypothetical protein protein coding LpaL13_04 440768 441127 - reverse 4 360.0 359 5.467 0e+00 5.338 0e+00 3.4590 0.0204 -0.4395 -3.3620 1.762 1.1875 2.922 7.098 0.0000 0.0000 33.36 0.8746 6.251 0 43.94 5.457 0.7564 33.666 22.992 1.721e+03 9.142 0.0000 0.0000 0.0000 0.3743 31.59 0 -1.6880 3.026 -2.5930 0.0035 2.038e-02 5.815e-08 1.928e-06 0.000e+00 8.066e-06 4.777 1.077e-01 2.254e-02 1.161e-03 4.046e-06
LPAL13_170014500 LPAL13_170014500 hypothetical protein, conserved protein coding LpaL13_17 361708 362040 + forward 17 333.0 332 5.167 0e+00 4.916 3e-04 2.7620 0.0290 -0.6550 -3.2950 6.983 1.4800 2.640 4.161 0.0002 0.0020 21.04 0.9833 5.255 0 46.88 5.551 0.9255 43.850 29.929 1.585e+03 11.208 0.0000 0.0000 0.0000 -0.2718 18.70 0 -2.4250 2.857 -2.7770 0.0057 2.911e-02 6.836e-06 3.877e-04 0.000e+00 1.994e-03 4.197 2.010e-01 4.790e-02 1.892e-03 1.065e-05
LPAL13_350011800 LPAL13_350011800 hypothetical protein, conserved protein coding LpaL13_35 171009 171242 + forward 35 234.0 233 5.163 0e+00 5.148 0e+00 4.6090 0.0026 2.8750 -1.1550 2.429 1.1467 4.030 9.181 0.0000 0.0000 174.70 0.5695 9.066 0 34.83 5.122 8.5427 297.854 204.023 5.757e+04 26.123 0.0000 1.0000 0.0000 2.7050 58.33 0 1.1580 3.938 -0.0230 0.0002 2.642e-03 2.111e-16 3.255e-11 9.650e-01 6.496e-08 4.958 6.883e-01 1.388e-01 6.487e-05 1.262e-08
LPAL13_200050100 LPAL13_200050100 hypothetical protein protein coding LpaL13_20.1 1627529 1627717 + forward 20.1 189.0 188 5.114 0e+00 5.083 0e+00 4.6430 0.0017 2.4570 -1.8560 1.010 2.3968 4.313 8.802 0.0000 0.0000 116.30 0.5978 8.555 0 25.75 4.686 7.4499 192.056 132.184 2.099e+04 18.447 0.0000 1.0000 0.0000 2.1490 51.00 0 0.7904 4.129 0.0911 0.0001 2.041e-03 1.305e-14 5.942e-10 9.676e-01 9.799e-06 5.002 1.092e+00 2.183e-01 3.370e-05 3.407e-09
LPAL13_080010800 LPAL13_080010800 hypothetical protein protein coding LpaL13_08 199409 199792 - reverse 8 384.0 383 5.065 1e-04 6.542 0e+00 1.6980 0.2085 -2.3590 -4.1880 4.126 0.1172 1.829 4.375 0.0002 0.0018 10.25 1.0820 4.681 0 1036.53 10.018 0.0000 10.355 6.997 1.037e+02 3.870 1.0000 0.0000 1.0000 -0.8838 24.72 0 -3.1090 1.714 -4.2060 0.0910 2.089e-01 7.164e-05 3.308e-05 0.000e+00 1.773e-03 3.916 3.049e+00 7.785e-01 3.034e-02 2.762e-03
LPAL13_000011800 LPAL13_000011800 hypothetical protein, conserved protein coding LPAL13_SCAF000076 446 640 - reverse Not Assigned 195.0 194 4.744 2e-04 5.365 3e-04 0.9541 0.4747 -2.5010 -3.9920 3.638 0.5576 1.491 3.404 0.0017 0.0102 11.03 1.0720 4.424 0 61.09 5.933 0.1379 9.026 6.143 7.072e+01 3.201 0.9990 0.0010 0.9990 -0.8584 18.80 0 -3.0600 1.029 -4.6930 0.3073 4.744e-01 1.774e-04 3.603e-04 1.773e-02 1.023e-02 3.320 3.640e+00 1.096e+00 1.024e-01 3.148e-02
LPAL13_000014000 LPAL13_000014000 hypothetical protein protein coding LPAL13_SCAF000119 655 942 + forward Not Assigned 288.0 287 4.278 0e+00 4.268 0e+00 3.9120 0.0114 2.4330 -1.1070 1.521 1.9542 3.540 7.486 0.0000 0.0000 128.20 0.5257 8.137 0 17.50 4.129 10.8620 190.207 132.041 1.264e+04 13.784 0.0000 1.0000 0.0000 2.2850 49.29 0 1.0980 3.311 -1.4520 0.0015 1.136e-02 3.161e-13 1.293e-09 9.609e-01 1.616e-05 4.339 9.720e-01 2.240e-01 4.953e-04 7.361e-07
LPAL13_000035500 LPAL13_000035500 hypothetical protein, conserved protein coding LPAL13_SCAF000492 7045 7410 + forward Not Assigned 366.0 365 4.244 0e+00 4.247 0e+00 3.8130 0.0290 4.5240 0.8016 2.358 0.5645 3.722 9.900 0.0000 0.0000 509.00 0.5882 7.214 0 19.25 4.267 45.7435 880.950 610.072 3.355e+05 18.528 0.0000 1.0000 0.0000 4.2590 38.49 0 2.8070 2.857 -2.2370 0.0057 3.509e-02 2.215e-10 1.077e-07 9.650e-01 8.739e-09 4.278 9.389e-01 2.195e-01 1.886e-03 1.067e-05
LPAL13_000026500 LPAL13_000026500 hypothetical protein protein coding LPAL13_SCAF000301 144 494 - reverse Not Assigned 351.0 350 4.099 0e+00 4.058 1e-04 2.4050 0.1735 0.1342 -2.3950 5.419 1.9803 2.529 4.092 0.0003 0.0025 43.82 0.7856 5.218 0 20.01 4.323 2.7286 54.802 37.913 1.498e+03 9.648 0.0002 0.9998 0.0002 0.8896 22.05 0 -0.8872 1.840 -4.0380 0.0701 1.737e-01 7.827e-06 8.662e-05 9.676e-01 2.483e-03 3.298 2.748e-01 8.333e-02 2.337e-02 1.638e-03
LPAL13_220019500 LPAL13_220019500 hypothetical protein protein coding LpaL13_22 578260 578538 + forward 22 279.0 278 3.766 0e+00 3.767 0e+00 3.0520 0.0282 3.5420 0.3451 2.128 0.8014 3.196 8.201 0.0000 0.0000 284.60 0.4888 7.703 0 14.41 3.849 29.3640 423.356 295.575 6.945e+04 13.320 0.0000 1.0000 0.0000 3.4280 45.31 0 2.3620 2.872 -2.2080 0.0054 2.827e-02 6.678e-12 6.457e-09 9.650e-01 2.914e-07 3.738 3.673e-01 9.825e-02 1.809e-03 9.817e-06
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 -5.470 0.0003 -5.372 0.0007 -5.948 0.0000 -3.7270 3.4570 10.5693 0.0607 -7.184 -10.980 0 0e+00 128.700 1.2590 -4.344 0.0000 0.1257 -2.992 303.97 38.190 124.390 2.181e+04 0.1338 0.0000 0.0000 0.0000 2.2660 16.67 0.0000 -1.0450 -5.584 4.7710 0e+00 3.750e-05 2.310e-04 8.774e-04 0.000e+00 2.320e-08 -5.597 0.000e+00 0.000e+00 1.964e-05 5.091e-10
LPAL13_000038400 LPAL13_000038400 expression-site associated gene (esag3), putative protein coding LPAL13_SCAF000573 101 1360 + forward Not Assigned 1260.0 1259 -2.890 0.0000 -2.883 0.0000 -3.228 0.0001 4.6320 8.2100 3.1208 0.0361 -3.578 -10.010 0 0e+00 3613.000 0.5417 -5.335 0.0000 0.1769 -2.499 8563.68 1514.852 3800.959 1.502e+07 0.1810 0.0000 0.0000 0.0000 7.0710 32.07 0.0000 5.8030 -5.353 5.2830 0e+00 7.083e-05 4.901e-06 1.316e-06 0.000e+00 6.552e-08 -2.980 2.311e-02 -7.757e-03 3.978e-07 3.538e-13
LPAL13_350063000 LPAL13_350063000 hypothetical protein protein coding LpaL13_35 1964328 1964543 - reverse 35 216.0 215 -2.787 0.0000 -2.760 0.0000 -3.430 0.0000 -2.3360 1.1760 2.1326 0.2175 -3.511 -10.920 0 0e+00 20.820 0.4834 -5.767 0.0000 0.1430 -2.806 52.76 7.535 22.203 6.022e+02 0.1650 0.0000 1.0000 0.0000 -0.3551 32.28 0.0000 -1.4490 -6.980 8.1370 0e+00 9.781e-07 6.585e-07 1.463e-06 9.609e-01 5.752e-09 -3.009 2.562e-03 -8.513e-04 7.635e-09 3.534e-17
LPAL13_140019300 LPAL13_140019300 bt1 family, putative protein coding LpaL13_14 530784 531350 + forward 14 567.0 566 -2.647 0.0000 -2.642 0.0000 -2.524 0.0000 4.6450 7.1000 0.4797 1.0258 -2.455 -7.588 0 0e+00 1850.000 0.3812 -6.943 0.0000 0.1690 -2.565 4590.02 775.713 2012.785 5.149e+06 0.1732 0.0000 1.0000 0.0000 6.1060 54.17 0.0000 5.3900 -6.983 11.6400 0e+00 9.781e-07 1.215e-09 1.268e-10 9.956e-01 3.706e-05 -2.637 1.599e-01 -6.065e-02 4.897e-10 7.135e-19
LPAL13_000012000 LPAL13_000012000 hypothetical protein protein coding LPAL13_SCAF000080 710 1159 - reverse Not Assigned 450.0 449 -2.597 0.0006 -2.588 0.0003 -3.018 0.0033 0.0920 3.9390 7.6668 0.1677 -3.847 -6.794 0 0e+00 204.300 0.6316 -4.113 0.0000 0.2273 -2.137 439.13 99.824 209.870 4.713e+04 0.2373 0.1104 0.8896 0.1104 2.9350 18.91 0.0000 1.3490 -3.853 0.3639 3e-04 3.273e-03 5.777e-04 3.565e-04 8.804e-01 1.427e-05 -2.699 3.322e-02 -1.231e-02 1.041e-04 1.825e-08
LPAL13_310039200 LPAL13_310039200 hypothetical protein protein coding LpaL13_31 1301745 1301972 - reverse 31 228.0 227 -2.424 0.0000 -2.419 0.0000 -2.442 0.0000 1.2180 3.7480 1.3520 0.2102 -2.530 -9.456 0 0e+00 189.000 0.4028 -6.018 0.0000 0.2518 -1.990 382.33 96.248 189.031 3.283e+04 0.2618 0.3602 0.6398 0.3602 2.8250 39.27 0.0000 1.9810 -5.653 6.3710 0e+00 3.272e-05 1.888e-07 8.181e-08 6.661e-01 1.829e-08 -2.505 9.974e-02 -3.981e-02 1.114e-07 3.655e-14
LPAL13_310035500 LPAL13_310035500 hypothetical protein protein coding LpaL13_31 1198439 1198957 - reverse 31 519.0 518 -2.381 0.0059 -2.284 0.0045 -3.219 0.0000 -4.1820 -0.4332 4.0735 0.4619 -3.749 -8.353 0 0e+00 6.986 0.7064 -3.370 0.0008 0.3087 -1.696 17.33 5.343 9.229 3.055e+02 0.3627 0.0000 0.0000 0.0000 -1.9240 12.08 0.0005 -3.1420 -7.026 5.9880 0e+00 9.518e-07 5.431e-03 6.168e-03 0.000e+00 2.057e-07 -2.637 1.925e-03 -7.302e-04 4.202e-04 1.469e-07
LPAL13_340039600 LPAL13_340039600 hypothetical protein protein coding LpaL13_34 1247554 1247757 - reverse 34 204.0 203 -2.226 0.0002 -2.222 0.0001 -2.731 0.0005 1.2470 4.2710 3.6166 0.1032 -3.024 -7.724 0 0e+00 225.900 0.5086 -4.377 0.0000 0.2131 -2.230 541.90 115.473 253.773 5.388e+04 0.2179 0.0000 1.0000 0.0000 3.0670 20.97 0.0000 1.9970 -4.581 2.6640 0e+00 6.390e-04 2.224e-04 1.488e-04 9.609e-01 2.350e-06 -2.435 8.498e-03 -3.489e-03 1.227e-05 5.938e-11
LPAL13_310031000 LPAL13_310031000 hypothetical protein, conserved protein coding LpaL13_31 1075172 1075459 - reverse 31 288.0 287 -2.225 0.0000 -2.203 0.0000 -2.878 0.0000 -2.0110 0.9902 3.4994 0.5164 -3.001 -7.015 0 0e+00 26.070 0.4422 -5.032 0.0000 0.2783 -1.845 53.53 14.891 27.423 9.837e+02 0.3026 0.1041 0.8959 0.1041 0.0442 25.63 0.0000 -1.1600 -6.196 6.2140 0e+00 7.298e-06 1.793e-05 2.417e-05 8.856e-01 2.953e-06 -2.435 0.000e+00 0.000e+00 3.120e-07 5.784e-14
LPAL13_000012100 LPAL13_000012100 hypothetical protein protein coding LPAL13_SCAF000080 1637 1894 - reverse Not Assigned 258.0 257 -2.194 0.0093 -2.179 0.0075 -3.393 0.0003 -2.2170 1.1630 6.2496 0.6344 -3.380 -6.141 0 0e+00 30.040 0.6857 -3.200 0.0014 0.2868 -1.802 62.47 17.913 32.365 1.713e+03 0.3159 0.0526 0.9474 0.0526 0.2151 10.88 0.0010 -1.4100 -4.876 2.4920 0e+00 3.045e-04 9.270e-03 8.836e-03 9.356e-01 2.741e-05 -2.573 1.242e-01 -4.826e-02 7.845e-04 4.935e-07
LPAL13_310031300 LPAL13_310031300 hypothetical protein, conserved protein coding LpaL13_31 1084772 1085059 - reverse 31 288.0 287 -2.134 0.0024 -2.122 0.0016 -3.169 0.0002 -1.0760 2.1610 3.9624 0.7670 -3.237 -6.863 0 0e+00 62.920 0.5806 -3.676 0.0002 0.2357 -2.085 134.87 31.779 65.216 6.123e+03 0.2525 0.0099 0.9901 0.0099 1.2360 14.58 0.0001 -0.2025 -4.969 3.2940 0e+00 2.022e-04 2.379e-03 2.121e-03 9.584e-01 3.680e-06 -2.423 2.657e-02 -1.097e-02 1.253e-04 1.350e-08
LPAL13_140019100 LPAL13_140019100 bt1 family, putative protein coding LpaL13_14 525164 525514 + forward 14 351.0 350 -2.003 0.0000 -1.998 0.0000 -2.040 0.0000 3.9170 6.0240 0.3510 0.5070 -2.107 -8.882 0 0e+00 869.900 0.2988 -6.703 0.0000 0.2312 -2.113 1932.12 446.698 928.457 7.009e+05 0.2344 0.0000 1.0000 0.0000 5.0180 52.46 0.0000 4.5850 -7.335 13.0600 0e+00 5.447e-07 4.676e-09 2.970e-10 9.609e-01 2.897e-06 -2.057 4.177e-02 -2.031e-02 1.192e-10 3.558e-20
LPAL13_050005000 LPAL13_050005000 hypothetical protein protein coding LpaL13_05 3394 3612 - reverse 5 219.0 218 -1.993 0.0056 -1.986 0.0035 -2.736 0.0002 0.1994 2.6790 2.0375 0.1572 -2.480 -8.063 0 0e+00 88.780 0.5888 -3.384 0.0007 0.2837 -1.817 174.87 49.604 90.231 6.026e+03 0.2922 0.0002 0.9998 0.0002 1.7250 12.71 0.0004 0.4855 -4.996 3.8090 0e+00 2.276e-04 5.662e-03 4.140e-03 9.609e-01 5.395e-07 -2.217 1.753e-02 -7.908e-03 3.606e-04 1.258e-07
LPAL13_000038500 LPAL13_000038500 hypothetical protein protein coding LPAL13_SCAF000575 39 251 + forward Not Assigned 213.0 212 -1.978 0.0067 -1.963 0.0097 -3.314 0.0000 -1.9410 1.3660 4.6543 0.6628 -3.307 -6.731 0 0e+00 31.090 0.5964 -3.317 0.0009 0.2989 -1.742 72.58 21.686 38.191 2.293e+03 0.3243 0.1752 0.8248 0.1752 0.2162 10.24 0.0014 -1.2950 -5.590 4.5350 0e+00 4.344e-05 6.321e-03 1.256e-02 8.291e-01 5.673e-06 -2.298 2.433e-01 -1.059e-01 7.605e-04 4.864e-07
LPAL13_340039700 LPAL13_340039700 snare domain containing protein, putative protein coding LpaL13_34 1248192 1248947 - reverse 34 756.0 755 -1.798 0.0000 -1.794 0.0000 -1.930 0.0000 4.6130 6.7130 0.6868 0.0937 -2.100 -11.180 0 0e+00 1390.000 0.3094 -5.810 0.0000 0.2704 -1.887 2937.42 794.360 1489.406 1.369e+06 0.2739 0.0000 1.0000 0.0000 5.6930 38.61 0.0000 5.2760 -6.469 9.5800 0e+00 3.701e-06 5.447e-07 8.727e-08 9.487e-01 2.029e-09 -1.790 3.196e-02 -1.786e-02 6.333e-09 3.442e-17
LPAL13_170015400 LPAL13_170015400 hypothetical protein, conserved protein coding LpaL13_17 395975 396307 + forward 17 333.0 332 -1.715 0.0000 -1.708 0.0000 -1.699 0.0001 1.2420 3.2650 0.9481 0.1241 -2.023 -9.210 0 0e+00 148.900 0.2814 -6.095 0.0000 0.3164 -1.660 265.43 83.965 142.820 1.263e+04 0.3213 0.0000 1.0000 0.0000 2.4750 37.57 0.0000 1.9960 -5.333 5.1870 0e+00 7.409e-05 1.166e-07 1.322e-07 9.609e-01 3.537e-08 -1.702 4.225e-02 -2.482e-02 3.903e-07 4.548e-13
LPAL13_210015500 LPAL13_210015500 core histone h2a/h2b/h3/h4, putative protein coding LpaL13_21 326108 326506 + forward 21 399.0 398 -1.415 0.0015 -1.404 0.0004 -1.438 0.0045 4.9010 6.6470 2.6083 0.2832 -1.746 -4.882 0 4e-04 2143.000 0.3701 -3.822 0.0001 0.4722 -1.082 2956.62 1396.232 1902.304 2.503e+06 0.4907 0.9914 0.0086 0.9914 6.3210 18.04 0.0000 5.6650 -3.716 -0.3655 4e-04 4.497e-03 1.522e-03 3.184e-04 4.523e-02 4.434e-04 -1.498 2.465e-02 -1.646e-02 1.874e-04 3.965e-08
LPAL13_140019200 LPAL13_140019200 inositol-3-phosphate synthase protein coding LpaL13_14 527711 529291 + INO1 forward 14 1581.0 1580 -1.414 0.0000 -1.409 0.0000 -1.490 0.0000 8.8260 10.4100 0.1715 0.4377 -1.580 -7.588 0 0e+00 19060.000 0.2377 -5.946 0.0000 0.3502 -1.514 36500.63 12780.792 20473.713 1.790e+08 0.3525 0.0000 1.0000 0.0000 9.4720 41.49 0.0000 9.2510 -6.301 8.9390 0e+00 5.648e-06 2.763e-07 2.036e-08 1.000e+00 4.852e-05 -1.522 1.763e-02 -1.158e-02 9.103e-09 1.784e-16
LPAL13_320038700 LPAL13_320038700 hypothetical protein, conserved protein coding LpaL13_32 1175024 1175257 + forward 32 234.0 233 -1.413 0.0000 -1.406 0.0000 -1.442 0.0000 2.5490 3.9280 0.4267 0.1122 -1.379 -8.484 0 0e+00 255.300 0.2271 -6.222 0.0000 0.4234 -1.240 421.88 178.602 257.503 2.064e+04 0.4270 0.0009 0.9991 0.0009 3.2540 40.65 0.0000 3.0110 -5.952 7.5730 0e+00 1.437e-05 6.640e-08 4.747e-08 9.609e-01 1.169e-07 -1.490 2.028e-02 -1.361e-02 3.376e-08 3.351e-15
LPAL13_040007800 LPAL13_040007800 hypothetical protein, conserved protein coding LpaL13_04 77524 78306 + forward 4 783.0 782 -1.378 0.0000 -1.373 0.0000 -1.246 0.0000 6.5520 7.7350 0.1432 0.3718 -1.183 -6.174 0 3e-04 4021.000 0.2295 -6.007 0.0000 0.3941 -1.343 6683.93 2634.211 3947.634 7.264e+06 0.3986 0.0001 0.9999 0.0001 7.2270 44.53 0.0000 7.0050 -5.829 7.0500 0e+00 2.049e-05 2.015e-07 7.246e-09 9.679e-01 3.080e-04 -1.364 6.839e-02 -5.014e-02 5.564e-08 8.971e-15
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)

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

6.4.1 A couple plots from the differential expression

6.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"]]

6.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"]]

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

zy_go_up$pvalue_plots$bpp_plot_over

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

zy_go_down$pvalue_plots$bpp_plot_over

6.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 = -193, df = 8548, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.9060 -0.8981
## sample estimates:
##     cor 
## -0.9021

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

6.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 8550 genes, now there are 6.
## There are 55 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.1312    0.1249    0.1320    0.1060    0.1300    0.1102    0.1130    0.1165 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.1157    0.1181    0.1149    0.1137    0.1101    0.1062    0.1104    0.1208 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20019 TMRC20070 TMRC20020 TMRC20021 
##    0.1207    0.1066    0.1092    0.1147    0.1224    0.1127    0.1102    0.1063 
## TMRC20022 TMRC20024 TMRC20036 TMRC20069 TMRC20033 TMRC20031 TMRC20055 TMRC20079 
##    0.1307    0.1126    0.1202    0.1163    0.1128    0.1005    0.1346    0.1268 
## TMRC20071 TMRC20078 TMRC20058 TMRC20072 TMRC20059 TMRC20048 TMRC20060 TMRC20077 
##    0.1234    0.1340    0.1181    0.1430    0.1104    0.1033    0.1087    0.1220 
## TMRC20074 TMRC20063 TMRC20053 TMRC20052 TMRC20064 TMRC20075 TMRC20051 TMRC20050 
##    0.1208    0.1167    0.1182    0.1105    0.1140    0.1113    0.1283    0.1154 
## TMRC20049 TMRC20062 TMRC20080 TMRC20043 TMRC20054 TMRC20046 TMRC20044 
##    0.1393    0.1285    0.1154    0.1137    0.1278    0.1367    0.1337
zymo_heatmap <- plot_sample_heatmap(zymo_expt, row_label = my_names)
zymo_heatmap

6.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_000038500" "LPAL13_000012100"
##  [5] "LPAL13_310031300" "LPAL13_000038400" "LPAL13_050005000" "LPAL13_340039600"
##  [9] "LPAL13_310031000" "LPAL13_310039200" "LPAL13_350063000" "LPAL13_180013900"
## [13] "LPAL13_140019300" "LPAL13_210015500" "LPAL13_350013200" "LPAL13_340039700"
## [17] "LPAL13_350073400" "LPAL13_250006300" "LPAL13_170015400" "LPAL13_330024000"
## [21] "LPAL13_140019100" "LPAL13_320038700" "LPAL13_000052700" "LPAL13_140019200"
## [25] "LPAL13_210005000" "LPAL13_230011200" "LPAL13_330021800" "LPAL13_240009700"
## [29] "LPAL13_160014500" "LPAL13_350073200" "LPAL13_050009600" "LPAL13_250025700"
## [33] "LPAL13_230011500" "LPAL13_160014100" "LPAL13_230011400" "LPAL13_040007800"
## [37] "LPAL13_230011300" "LPAL13_020006700" "LPAL13_310032500" "LPAL13_310028500"
upshared_expt <- exclude_genes_expt(zy_norm, ids = rownames(up_shared), method = "keep")
## Before removal, there were 8550 genes, now there are 40.
## There are 55 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.3322    0.4156    0.1039    0.3671    0.1512    0.3873    0.5153    0.3105 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.3625    0.1575    0.4002    0.1335    0.3897    0.2896    0.1460    0.1261 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20019 TMRC20070 TMRC20020 TMRC20021 
##    0.3401    0.1453    0.1548    0.3148    0.1255    0.3827    0.1178    0.3447 
## TMRC20022 TMRC20024 TMRC20036 TMRC20069 TMRC20033 TMRC20031 TMRC20055 TMRC20079 
##    0.1226    0.1371    0.1805    0.1545    0.1339    0.1099    0.1670    0.5184 
## TMRC20071 TMRC20078 TMRC20058 TMRC20072 TMRC20059 TMRC20048 TMRC20060 TMRC20077 
##    0.4733    0.1748    0.5681    0.1654    0.2709    0.2979    0.1251    0.1243 
## TMRC20074 TMRC20063 TMRC20053 TMRC20052 TMRC20064 TMRC20075 TMRC20051 TMRC20050 
##    0.1484    0.1369    0.1613    0.4133    0.3801    0.3249    0.5661    0.1338 
## TMRC20049 TMRC20062 TMRC20080 TMRC20043 TMRC20054 TMRC20046 TMRC20044 
##    0.1526    0.5845    0.4227    0.3880    0.5060    0.1546    0.1557

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

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

6.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 8550 genes, now there are 68.
## There are 55 samples which kept less than 90 percent counts.
## TMRC20001 TMRC20065 TMRC20005 TMRC20066 TMRC20039 TMRC20037 TMRC20038 TMRC20067 
##    0.2203    0.1878    0.6713    0.2263    0.6575    0.2105    0.2015    0.2387 
## TMRC20068 TMRC20041 TMRC20015 TMRC20009 TMRC20010 TMRC20016 TMRC20011 TMRC20012 
##    0.2024    0.6894    0.1877    0.6366    0.1683    0.2077    0.5678    0.5511 
## TMRC20013 TMRC20017 TMRC20014 TMRC20018 TMRC20019 TMRC20070 TMRC20020 TMRC20021 
##    0.1656    0.6549    0.6493    0.1597    0.6529    0.1858    0.6854    0.1538 
## TMRC20022 TMRC20024 TMRC20036 TMRC20069 TMRC20033 TMRC20031 TMRC20055 TMRC20079 
##    0.6762    0.7158    0.6760    0.6975    0.7211    0.6116    0.7106    0.1868 
## TMRC20071 TMRC20078 TMRC20058 TMRC20072 TMRC20059 TMRC20048 TMRC20060 TMRC20077 
##    0.1697    0.5313    0.2196    0.5354    0.1380    0.1543    0.7607    0.5706 
## TMRC20074 TMRC20063 TMRC20053 TMRC20052 TMRC20064 TMRC20075 TMRC20051 TMRC20050 
##    0.6620    0.6333    0.5715    0.1784    0.1946    0.1804    0.1904    0.6151 
## TMRC20049 TMRC20062 TMRC20080 TMRC20043 TMRC20054 TMRC20046 TMRC20044 
##    0.6976    0.1887    0.1547    0.1729    0.2026    0.6344    0.6226
high_22_heatmap <- plot_sample_heatmap(downshared_expt, row_label = rownames(down_shared))
high_22_heatmap

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

7.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 71, now there are 67 samples.
new_snps <- sm(count_expt_snps(lp_snp, annot_column = "bcftable"))
## Error : 'preprocessing/TMRC20080/outputs/vcfutils_lpanamensis_v36/r1_trimmed_lpanamensis_v36_count.txt' does not exist in current working directory ('/mnt/cbcb/fs01_abelew/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019').
## Error : 'preprocessing/TMRC20080/outputs/vcfutils_lpanamensis_v36/r1_trimmed_lpanamensis_v36_count.txt' does not exist in current working directory ('/mnt/cbcb/fs01_abelew/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019').
## Error in Biobase::`sampleNames<-`(`*tmp*`, value = colnames(snp_exprs)): number of new names (66) should equal number of rows in AnnotatedDataFrame (67)
old_snps <- sm(count_expt_snps(old_expt, annot_column = "bcftable", snp_column = 2))

both_snps <- combine_expts(new_snps, old_snps)
## Error in combine_expts(new_snps, old_snps): object 'new_snps' not found
both_norm <- sm(normalize_expt(both_snps, transform = "log2", convert = "cpm", filter = TRUE))
## Error in normalize_expt(both_snps, transform = "log2", convert = "cpm", : object 'both_snps' not found
## strains <- both_norm[["design"]][["strain"]]
both_strain <- set_expt_conditions(both_norm, fact = "strain")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'both_norm' not found

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

7.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)
## Error in plot_heatmap(expt_data, expt_colors = expt_colors, expt_design = expt_design, : object 'both_norm' not found
pp(file = "images/raw_snp_disheat.png", image = old_new_variant_heatmap,
   height = 12, width = 12)
## Error in pp(file = "images/raw_snp_disheat.png", image = old_new_variant_heatmap, : object 'old_new_variant_heatmap' not found

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

snp_sets <- get_snp_sets(both_snps, factor = "condition")
## Error in get_snp_sets(both_snps, factor = "condition"): object 'both_snps' not found
both_expt <- combine_expts(lp_expt, old_expt)

snp_genes <- sm(snps_vs_genes(both_expt, snp_sets, expt_name_col = "chromosome"))
## Error in snps_vs_genes(both_expt, snp_sets, expt_name_col = "chromosome"): object 'snp_sets' not found
## 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")))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': object 'both_snps' not found
zymo_heat <- plot_sample_heatmap(snp_subset, row_label = rownames(exprs(snp_subset)))
## Error in plot_sample_heatmap(snp_subset, row_label = rownames(exprs(snp_subset))): object 'snp_subset' not found
zymo_heat
## Error in eval(expr, envir, enclos): object 'zymo_heat' not found

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

7.3 SNPS associated with clinical response in the TMRC samples

clinical_sets <- get_snp_sets(new_snps, factor = "clinicalresponse")
## Error in get_snp_sets(new_snps, factor = "clinicalresponse"): object 'new_snps' not found
density_vec <- clinical_sets[["density"]]
## Error in eval(expr, envir, enclos): object 'clinical_sets' not found
chromosome_idx <- grep(pattern = "LpaL", x = names(density_vec))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grep': object 'density_vec' not found
density_df <- as.data.frame(density_vec[chromosome_idx])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'density_vec' not found
density_df[["chr"]] <- rownames(density_df)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'density_df' not found
colnames(density_df) <- c("density_vec", "chr")
## Error in colnames(density_df) <- c("density_vec", "chr"): object 'density_df' not found
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))
## Error in ggplot(density_df, aes_string(x = "chr", y = "density_vec")): object 'density_df' not found
## clinical_written <- write_variants(new_snps)

7.3.1 Cross reference these variants by gene

clinical_genes <- sm(snps_vs_genes(lp_expt, clinical_sets, expt_name_col = "chromosome"))
## Error in snps_vs_genes(lp_expt, clinical_sets, expt_name_col = "chromosome"): object 'clinical_sets' not found
snp_density <- merge(as.data.frame(clinical_genes[["summary_by_gene"]]),
                     as.data.frame(fData(lp_expt)),
                     by = "row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_genes' not found
snp_density <- snp_density[, c(1, 2, 4, 15)]
## Error in eval(expr, envir, enclos): object 'snp_density' not found
colnames(snp_density) <- c("name", "snps", "product", "length")
## Error in colnames(snp_density) <- c("name", "snps", "product", "length"): object 'snp_density' not found
snp_density[["product"]] <- tolower(snp_density[["product"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'tolower': object 'snp_density' not found
snp_density[["length"]] <- as.numeric(snp_density[["length"]])
## Error in eval(expr, envir, enclos): object 'snp_density' not found
snp_density[["density"]] <- snp_density[["snps"]] / snp_density[["length"]]
## Error in eval(expr, envir, enclos): object 'snp_density' not found
snp_idx <- order(snp_density[["density"]], decreasing = TRUE)
## Error in eval(quote(list(...)), env): object 'snp_density' not found
snp_density <- snp_density[snp_idx, ]
## Error in eval(expr, envir, enclos): object 'snp_density' not found
removers <- c("amastin", "gp63", "leishmanolysin")
for (r in removers) {
  drop_idx <- grepl(pattern = r, x = snp_density[["product"]])
  snp_density <- snp_density[!drop_idx, ]
}
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': object 'snp_density' not found
## Filter these for [A|a]mastin gp63 Leishmanolysin
clinical_snps <- snps_intersections(lp_expt, clinical_sets, chr_column = "chromosome")
## Error in snps_intersections(lp_expt, clinical_sets, chr_column = "chromosome"): object 'clinical_sets' not found
fail_ref_snps <- as.data.frame(clinical_snps[["inters"]][["failure, reference strain"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
cure_snps <- as.data.frame(clinical_snps[["inters"]][["cure"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
head(fail_ref_snps)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'head': object 'fail_ref_snps' not found
head(cure_snps)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'head': object 'cure_snps' not found
annot <- fData(lp_expt)
clinical_interest <- as.data.frame(clinical_snps[["gene_summaries"]][["cure"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'clinical_snps' not found
clinical_interest <- merge(clinical_interest,
                           as.data.frame(clinical_snps[["gene_summaries"]][["failure, reference strain"]]),
                           by = "row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'merge': object 'clinical_interest' not found
rownames(clinical_interest) <- clinical_interest[["Row.names"]]
## Error in eval(expr, envir, enclos): object 'clinical_interest' not found
clinical_interest[["Row.names"]] <- NULL
## Error in clinical_interest[["Row.names"]] <- NULL: object 'clinical_interest' not found
colnames(clinical_interest) <- c("cure_snps","fail_snps")
## Error in colnames(clinical_interest) <- c("cure_snps", "fail_snps"): object 'clinical_interest' not found
annot <- merge(annot, clinical_interest, by = "row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'y' in selecting a method for function 'merge': object 'clinical_interest' not found
rownames(annot) <- annot[["Row.names"]]
annot[["Row.names"]] <- NULL
fData(lp_expt$expressionset) <- annot

8 Zymodeme for new samples

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

8.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")
## Error in get_snp_sets(new_snps, factor = "phenotypiccharacteristics"): object 'new_snps' not found
summary(new_sets)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found
## 1000000: 2.2
## 0100000: 2.3

summary(new_sets[["intersections"]][["10000"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found
summary(new_sets[["intersections"]][["01000"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'new_sets' not found

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

8.1.1 A small function for searching for potential PCR primers

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

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

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

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

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

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

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

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

  dist_pair_maximum <- 1000
  dist_pair_minimum <- 200
  dist_pair_idx <- combined[["dist_pair"]] <= dist_pair_maximum &
    combined[["dist_pair"]] >= dist_pair_minimum
  remaining <- combined[dist_pair_idx, ]
  no_weak_idx <- grepl(pattern="ref_(G|C)", x=rownames(remaining))
  remaining <- remaining[no_weak_idx, ]
  
  print(head(table(position_table[["dist"]])))
  sequentials <- position_table[["dist"]] <= maximum_separation
  message("There are ", sum(sequentials), " candidate regions.")

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

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

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

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

8.1.2 Extract a promising region from the genome

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

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

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

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


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


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


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

8.2 Go hunting for Sanger sequencing regions

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

pheno <- subset_expt(lp_expt, subset = "condition=='z2.2'|condition=='z2.3'")
pheno <- subset_expt(pheno, subset = "!is.na(pData(pheno)[['bcftable']])")
pheno_snps <- sm(count_expt_snps(pheno, annot_column = "bcftable"))

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

8.3 Combine this table with 2.2/2.3 genes

Here is my note from our meeting:

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

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

logfc <- zy_table[["data"]][["z23_vs_z22"]]
logfc_columns <- logfc[, c("deseq_logfc", "deseq_adjp")]
colnames(logfc_columns) <- c("z23_logfc", "z23_adjp")
new_table <- merge(favorite_primer_regions, logfc_columns,
                   by.x = "closest_gene_before_id", by.y = "row.names")
sus <- sus_table[["data"]][["sensitive_vs_resistant"]]
sus_columns <- sus[, c("deseq_logfc", "deseq_adjp")]
colnames(sus_columns) <- c("sus_logfc", "sus_adjp")
new_table <- merge(new_table, sus_columns,
                   by.x = "closest_gene_before_id", by.y = "row.names") %>%
  relocate(bin)
written <- write_xlsx(data=new_table,
                      excel="excel/favorite_primers_xref_zy_sus.
## Error: <text>:13:29: unexpected INCOMPLETE_STRING
## 12: written <- write_xlsx(data=new_table,
## 13:                       excel="excel/favorite_primers_xref_zy_sus.
##                                 ^

8.4 Make a heatmap describing the clustering of variants

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

snp_genes <- sm(snps_vs_genes(lp_expt, new_sets, expt_name_col = "chromosome"))
## Error in snps_vs_genes(lp_expt, new_sets, expt_name_col = "chromosome"): object 'new_sets' not found
new_zymo_norm <- normalize_expt(new_snps, filter = TRUE, convert = "cpm", norm = "quant", transform = TRUE)
## Error in normalize_expt(new_snps, filter = TRUE, convert = "cpm", norm = "quant", : object 'new_snps' not found
new_zymo_norm <- set_expt_conditions(new_zymo_norm, fact = "phenotypiccharacteristics")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'new_zymo_norm' not found
zymo_heat <- plot_disheat(new_zymo_norm)
## Error in plot_heatmap(expt_data, expt_colors = expt_colors, expt_design = expt_design, : object 'new_zymo_norm' not found
zymo_heat[["plot"]]
## Error in eval(expr, envir, enclos): object 'zymo_heat' not found

8.4.1 Annotated heatmap of variants

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

des <- both_norm[["design"]]
## Error in eval(expr, envir, enclos): object 'both_norm' not found
undef_idx <- is.na(des[["strain"]])
## Error in eval(expr, envir, enclos): object 'des' not found
des[undef_idx, "strain"] <- "unknown"
## Error in des[undef_idx, "strain"] <- "unknown": object 'des' not found
##hmcols <- colorRampPalette(c("yellow","black","darkblue"))(256)
correlations <- hpgl_cor(exprs(both_norm))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'both_norm' not found
zymo_missing_idx <- is.na(des[["phenotypiccharacteristics"]])
## Error in eval(expr, envir, enclos): object 'des' not found
des[["phenotypiccharacteristics"]] <- as.character(des[["phenotypiccharacteristics"]])
## Error in eval(expr, envir, enclos): object 'des' not found
des[["clinicalcategorical"]] <- as.character(des[["clinicalcategorical"]])
## Error in eval(expr, envir, enclos): object 'des' not found
des[zymo_missing_idx, "phenotypiccharacteristics"] <- "unknown"
## Error in des[zymo_missing_idx, "phenotypiccharacteristics"] <- "unknown": object 'des' not found
mydendro <- list(
  "clustfun" = hclust,
  "lwd" = 2.0)
col_data <- as.data.frame(des[, c("phenotypiccharacteristics", "clinicalcategorical")])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'des' not found
unknown_clinical <- is.na(col_data[["clinicalcategorical"]])
## Error in eval(expr, envir, enclos): object 'col_data' not found
row_data <- as.data.frame(des[, c("strain")])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'des' not found
colnames(col_data) <- c("zymodeme", "outcome")
## Error in colnames(col_data) <- c("zymodeme", "outcome"): object 'col_data' not found
col_data[unknown_clinical, "outcome"] <- "undefined"
## Error in col_data[unknown_clinical, "outcome"] <- "undefined": object 'col_data' not found
colnames(row_data) <- c("strain")
## Error in colnames(row_data) <- c("strain"): object 'row_data' not found
myannot <- list(
  "Col" = list("data" = col_data),
  "Row" = list("data" = row_data))
## Error in eval(expr, envir, enclos): object 'col_data' not found
myclust <- list("cuth" = 1.0,
                "col" = BrewerClusterCol)
mylabs <- list(
  "Row" = list("nrow" = 4),
  "Col" = list("nrow" = 4))
hmcols <- colorRampPalette(c("darkblue", "beige"))(240)
map1 <- annHeatmap2(
  correlations,
  dendrogram = mydendro,
  annotation = myannot,
  cluster = myclust,
  labels = mylabs,
  ## The following controls if the picture is symmetric
  scale = "none",
  col = hmcols)
## Error in annHeatmap2(correlations, dendrogram = mydendro, annotation = myannot, : object 'correlations' not found
pp(file = "images/dendro_heatmap.png", image = map1, height = 20, width = 20)
## Error in pp(file = "images/dendro_heatmap.png", image = map1, height = 20, : object 'map1' not found

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

big heatmap

xref_prop <- table(pheno_snps[["conditions"]])
## Error in eval(quote(list(...)), env): object 'pheno_snps' not found
pheno_snps$conditions
## Error in eval(expr, envir, enclos): object 'pheno_snps' not found
idx_tbl <- exprs(pheno_snps) > 5
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'pheno_snps' not found
new_tbl <- data.frame(row.names = rownames(exprs(pheno_snps)))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'pheno_snps' not found
for (n in names(xref_prop)) {
  new_tbl[[n]] <- 0
  idx_cols <- which(pheno_snps[["conditions"]] == n)
  prop_col <- rowSums(idx_tbl[, idx_cols]) / xref_prop[n]
  new_tbl[n] <- prop_col
}
## Error in eval(expr, envir, enclos): object 'xref_prop' not found
keepers <- grepl(x = rownames(new_tbl), pattern = "LpaL13")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'new_tbl' not found
new_tbl <- new_tbl[keepers, ]
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
new_tbl[["strong22"]] <- 1.001 - new_tbl[["z2.2"]]
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
new_tbl[["strong23"]] <- 1.001 - new_tbl[["z2.3"]]
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
s22_na <- new_tbl[["strong22"]] > 1
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
new_tbl[s22_na, "strong22"] <- 1
## Error in new_tbl[s22_na, "strong22"] <- 1: object 'new_tbl' not found
s23_na <- new_tbl[["strong23"]] > 1
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
new_tbl[s23_na, "strong23"] <- 1
## Error in new_tbl[s23_na, "strong23"] <- 1: object 'new_tbl' not found
new_tbl[["SNP"]] <- rownames(new_tbl)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'new_tbl' not found
new_tbl[["Chromosome"]] <- gsub(x = new_tbl[["SNP"]], pattern = "chr_(.*)_pos_.*", replacement = "\\1")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'new_tbl' not found
new_tbl[["Position"]] <- gsub(x = new_tbl[["SNP"]], pattern = ".*_pos_(\\d+)_.*", replacement = "\\1")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'new_tbl' not found
new_tbl <- new_tbl[, c("SNP", "Chromosome", "Position", "strong22", "strong23")]
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
library(CMplot)
## Much appreciate for using CMplot.
## Full description, Bug report, Suggestion and the latest codes:
## https://github.com/YinLiLin/CMplot
simplify <- new_tbl
## Error in eval(expr, envir, enclos): object 'new_tbl' not found
simplify[["strong22"]] <- NULL
## Error in simplify[["strong22"]] <- NULL: object 'simplify' not found
CMplot(simplify, bin.size = 100000)
## Error in is.data.frame(x): object 'simplify' not found
CMplot(new_tbl, plot.type="m", multracks=TRUE, threshold = c(0.01, 0.05),
       threshold.lwd=c(1,1), threshold.col=c("black","grey"),
       amplify=TRUE, bin.size=10000,
       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)
## Error in is.data.frame(x): object 'new_tbl' not found

SNP Density Circular Manhattan Rectangular Manhattan QQ

8.5 Try out MatrixEQTL

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

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

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

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

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

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

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

useModel = modelLINEAR # modelANOVA, modelLINEAR, or modelLINEAR_CROSS

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

me = Matrix_eQTL_main(
    snps = snps,
    gene = gene,
    cvrt = cvrt,
    output_file_name = output_file_name_tra,
    pvOutputThreshold = pvOutputThreshold_tra,
    useModel = useModel,
    errorCovariance = errorCovariance,
    verbose = TRUE,
    output_file_name.cis = output_file_name_cis,
    pvOutputThreshold.cis = pvOutputThreshold_cis,
    snpspos = snpspos,
    genepos = genepos,
    cisDist = cisDist,
    pvalue.hist = "qqplot",
    min.pv.by.genesnp = FALSE,
    noFDRsaveMemory = FALSE);
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 b006f25aaf505e4650ed89d020b1cb7e4b46f6a0
## This is hpgltools commit: Mon Dec 13 14:13:47 2021 -0500: b006f25aaf505e4650ed89d020b1cb7e4b46f6a0
## Saving to tmrc2_02sample_estimation_v202201.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzIgQ29tcHJlaGVuc2l2ZSBEYXRhIEFuYWx5c2lzOiAyMDIyMDEiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSA5MCwKICAgICAgICAgICAgICAgICAgICAgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA4LAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjIwMSIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gIiVZJW0lZCIpCgojIyB0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZSA9IGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHByZXZpb3VzX2ZpbGUpKSkpCnJtZF9maWxlIDwtIGdsdWU6OmdsdWUoInRtcmMyXzAyc2FtcGxlX2VzdGltYXRpb25fdnt2ZXJ9LlJtZCIpCnNhdmVmaWxlIDwtIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHJtZF9maWxlKQoKbGlicmFyeShIZWF0cGx1cykKYGBgCgpgYGB7ciBjdXJyZW50X3NhbXBsZXNoZWV0fQpzYW1wbGVfc2hlZXQgPC0gZ2x1ZTo6Z2x1ZSgic2FtcGxlX3NoZWV0cy90bXJjMl9zYW1wbGVzXzIwMjIwMTA2Lnhsc3giKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGlzIG1vc3RseSBqdXN0IGEgcnVuIG9mIHRoaXMgd29ya3NoZWV0IHRvIHJlYWNxdWFpbnQgbXlzZWxmIHdpdGggaXQuCgpUaGlzIGRvY3VtZW50IGlzIGludGVuZGVkIHRvIHByb3ZpZGUgYSBnZW5lcmFsIG92ZXJ2aWV3IG9mIHRoZSBUTVJDMiBzYW1wbGVzCndoaWNoIGhhdmUgdGh1cyBmYXIgYmVlbiBzZXF1ZW5jZWQuICBJbiBzb21lIGNhc2VzLCB0aGlzIGluY2x1ZGVzIG9ubHkgdGhvc2UKc2FtcGxlcyBzdGFydGluZyBpbiAyMDE5OyBpbiBvdGhlciBpbnN0YW5jZXMgSSBhbSBpbmNsdWRpbmcgb3VyIHByZXZpb3VzCigyMDE1LTIwMTYpIHNhbXBsZXMuCgpJbiBhbGwgY2FzZXMgdGhlIHByb2Nlc3NpbmcgcGVyZm9ybWVkIHdhczoKCjEuICBEZWZhdWx0IHRyaW1taW5nIHdhcyBwZXJmb3JtZWQuCjIuICBIaXNhdDIgd2FzIHVzZWQgdG8gbWFwIHRoZSByZW1haW5pbmcgcmVhZHMgYWdhaW5zdCB0aGUgTGVpc2htYW5pYQogICAgcGFuYW1lbnNpcyBnZW5vbWUgcmV2aXNpb24gMzYuCjMuICBUaGUgYWxpZ25tZW50cyBmcm9tIGhpc2F0MiB3ZXJlIHVzZWQgdG8gY291bnQgcmVhZHMvZ2VuZSBhZ2FpbnN0IHRoZQogICAgcmV2aXNpb24gMzYgYW5ub3RhdGlvbnMgd2l0aCBodHNlcS4KNC4gIFRoZXNlIGFsaWdubWVudHMgd2VyZSBhbHNvIHBhc3NlZCB0byB0aGUgcGlsZXVwIGZ1bmN0aW9uYWxpdHkgb2Ygc2FtdG9vbHMKICAgIGFuZCB0aGUgdmNmL2JjZiB1dGlsaXRpZXMgaW4gb3JkZXIgdG8gbWFrZSBhIG1hdHJpeCBvZiBhbGwgb2JzZXJ2ZWQKICAgIGRpZmZlcmVuY2VzIGJldHdlZW4gZWFjaCBzYW1wbGUgd2l0aCByZXNwZWN0IHRvIHRoZSByZWZlcmVuY2UuCgpUaGUgYW5hbHlzZXMgaW4gdGhpcyBkb2N1bWVudCB1c2UgdGhlIG1hdHJpY2VzIG9mIGNvdW50cy9nZW5lIGZyb20gIzMgYW5kCnZhcmlhbnRzL3Bvc2l0aW9uIGZyb20gIzQgaW4gb3JkZXIgdG8gcHJvdmlkZSBzb21lIGltYWdlcyBhbmQgbWV0cmljcyBkZXNjcmliaW5nCnRoZSBzYW1wbGVzIHdlIGhhdmUgc2VxdWVuY2VkIHNvIGZhci4KCiMgQW5ub3RhdGlvbnMKCkV2ZXJ5dGhpbmcgd2hpY2ggZm9sbG93cyBkZXBlbmRzIG9uIHRoZSBFeGlzdGluZyBUcmlUcnlwREIgYW5ub3RhdGlvbnMgcmV2aXNpb24KNDYsIGNpcmNhIDIwMTkuICBUaGUgZm9sbG93aW5nIGJsb2NrIGxvYWRzIGEgZGF0YWJhc2Ugb2YgdGhlc2UgYW5ub3RhdGlvbnMgYW5kCnR1cm5zIGl0IGludG8gYSBtYXRyaXggd2hlcmUgdGhlIHJvd3MgYXJlIGdlbmVzIGFuZCBjb2x1bW5zIGFyZSBhbGwgdGhlCmFubm90YXRpb24gdHlwZXMgcHJvdmlkZWQgYnkgVHJpVHJ5cERCLgoKVGhlIHNhbWUgZGF0YWJhc2Ugd2FzIHVzZWQgdG8gY3JlYXRlIGEgbWF0cml4IG9mIG9ydGhvbG9nb3VzIGdlbmVzIGJldHdlZW4KTC5wYW5hbWVuc2lzIGFuZCBhbGwgb2YgdGhlIG90aGVyIHNwZWNpZXMgaW4gdGhlIFRyaVRyeXBEQi4KCmBgYHtyIGFubm90fQp0dCA8LSBzbShsaWJyYXJ5KEV1UGF0aERCKSkKdHQgPC0gc20obGlicmFyeShvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYikpCnBhbl9kYiA8LSBvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYgphbGxfZmllbGRzIDwtIGNvbHVtbnMocGFuX2RiKQoKYWxsX2xwX2Fubm90IDwtIHNtKGxvYWRfb3JnZGJfYW5ub3RhdGlvbnMoCiAgICBwYW5fZGIsCiAgICBrZXl0eXBlID0gImdpZCIsCiAgICBmaWVsZHMgPSBjKCJhbm5vdF9nZW5lX2VudHJlel9pZCIsICJhbm5vdF9nZW5lX25hbWUiLAogICAgICAgICAgICAgICAiYW5ub3Rfc3RyYW5kIiwgImFubm90X2Nocm9tb3NvbWUiLCAiYW5ub3RfY2RzX2xlbmd0aCIsCiAgICAgICAgICAgICAgICJhbm5vdF9nZW5lX3Byb2R1Y3QiKSkpJGdlbmVzCgpscF9nbyA8LSBzbShsb2FkX29yZ2RiX2dvKHBhbl9kYikpCmxwX2xlbmd0aHMgPC0gYWxsX2xwX2Fubm90WywgYygiZ2lkIiwgImFubm90X2Nkc19sZW5ndGgiKV0KY29sbmFtZXMobHBfbGVuZ3RocykgIDwtIGMoIklEIiwgImxlbmd0aCIpCmFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSA8LSB0b2xvd2VyKGFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSkKb3J0aG9zIDwtIHNtKEV1UGF0aERCOjpleHRyYWN0X2V1cGF0aF9vcnRob2xvZ3MoZGIgPSBwYW5fZGIpKQoKaGlzYXRfYW5ub3QgPC0gYWxsX2xwX2Fubm90CiMjIHJvd25hbWVzKGhpc2F0X2Fubm90KSA8LSBwYXN0ZTAoImV4b25fIiwgcm93bmFtZXMoaGlzYXRfYW5ub3QpLCAiLkUxIikKYGBgCgojIExvYWQgYSBnZW5vbWUKCmBgYHtyIGdlbm9tZX0KbWV0YSA8LSBFdVBhdGhEQjo6ZG93bmxvYWRfZXVwYXRoX21ldGFkYXRhKHdlYnNlcnZpY2U9InRyaXRyeXBkYiIpCmxwX2VudHJ5IDwtIEV1UGF0aERCOjpnZXRfZXVwYXRoX2VudHJ5KHNwZWNpZXM9IkxlaXNobWFuaWEgcGFuYW1lbnNpcyIsIG1ldGFkYXRhPW1ldGEpCmNvbG5hbWVzKGxwX2VudHJ5KQp0ZXN0aW5nX3BhbmFtZW5zaXMgPC0gIkJTR2Vub21lLkxlaXNobWFuaWEucGFuYW1lbnNpcy5NSE9NQ09MODFMMTMudjUzIgojIyB0ZXN0aW5nX3BhbmFtZW5zaXMgPC0gRXVQYXRoREI6Om1ha2VfZXVwYXRoX2JzZ2Vub21lKGVudHJ5PWxwX2VudHJ5LCBldV92ZXJzaW9uPSJ2NDYiKQpsaWJyYXJ5KGFzLmNoYXJhY3Rlcih0ZXN0aW5nX3BhbmFtZW5zaXMpLCBjaGFyYWN0ZXIub25seT1UUlVFKQpnZW5vbWUgPC0gZ2V0MChhcy5jaGFyYWN0ZXIodGVzdGluZ19wYW5hbWVuc2lzKSkKYGBgCgojIFRPRE86CgpSZXNlcXVlbmNlIHNhbXBsZXM6IFRNUkMyMDAwMiwgVE1SQzIwMDA2LCBUTVJDMjAwMDQgKG1heWJlIFRNUkMyMDAwOCBhbmQgVE1SQzIwMDI5KQoKIyBHZW5lcmF0ZSBFeHByZXNzaW9uc2V0cyBhbmQgU2FtcGxlIEVzdGltYXRpb24KClRoZSBwcm9jZXNzIG9mIHNhbXBsZSBlc3RpbWF0aW9uIHRha2VzIHR3byBwcmltYXJ5IGlucHV0czoKCjEuICBUaGUgc2FtcGxlIHNoZWV0LCB3aGljaCBjb250YWlucyBhbGwgdGhlIG1ldGFkYXRhIHdlIGN1cnJlbnRseSBoYXZlIG9uIGhhbmQsCiAgICBpbmNsdWRpbmcgZmlsZW5hbWVzIGZvciB0aGUgb3V0cHV0cyBvZiAjMyBhbmQgIzQgYWJvdmUuCjIuICBUaGUgZ2VuZSBhbm5vdGF0aW9ucy4KCkFuIGV4cHJlc3Npb25zZXQgaXMgYSBkYXRhIHN0cnVjdHVyZSB1c2VkIGluIFIgdG8gZXhhbWluZSBSTkFTZXEgZGF0YS4gIEl0CmlzIGNvbXByaXNlZCBvZiBhbm5vdGF0aW9ucywgbWV0YWRhdGEsIGFuZCBleHByZXNzaW9uIGRhdGEuICBJbiB0aGUgY2FzZSBvZiBvdXIKcHJvY2Vzc2luZyBwaXBlbGluZSwgdGhlIGxvY2F0aW9uIG9mIHRoZSBleHByZXNzaW9uIGRhdGEgaXMgcHJvdmlkZWQgYnkgdGhlCmZpbGVuYW1lcyBpbiB0aGUgbWV0YWRhdGEuCgpUaGUgZmlyc3QgbGluZXMgb2YgdGhlIGZvbGxvd2luZyBibG9jayBjcmVhdGUgdGhlIEV4cHJlc3Npb25zZXQuICBBbGwgb2YgdGhlCmZvbGxvd2luZyBsaW5lcyBwZXJmb3JtIHZhcmlvdXMgbm9ybWFsaXphdGlvbnMgYW5kIGdlbmVyYXRlIHBsb3RzIGZyb20gaXQuCgojIyBOb3RlcwoKVGhlIGZvbGxvd2luZyBzYW1wbGVzIGFyZSBtdWNoIGxvd2VyIGNvdmVyYWdlOgoKKiBUTVJDMjAwMDIKKiBUTVJDMjAwMDYKKiBUTVJDMjAwMDcKKiBUTVJDMjAwMDgKCjIwMjEwNjEwOiBJIG1hZGUgc29tZSBtYW51YWwgY2hhbmdlcyB0byB0aGUgc2FtcGxlIHNoZWV0IHdoaWNoIEkKZG93bmxvYWRlZCwgZmlsbGluZyBpbiBzb21lIHp5bW9kZW1lIHdpdGggJ3Vua25vd24nCgojIyBUT0RPOgoKMS4gIERvIHRoZSBtdWx0aS1nZW5lIGZhbWlseSByZW1vdmFsIHJpZ2h0IGhlcmUgaW5zdGVhZCBvZiB3YXkgZG93biBhdCB0aGUgYm90dG9tCjIuICBBZGQgenltb2RlbWUgc25wcyB0byB0aGUgYW5ub3RhdGlvbiBsYXRlci4KMy4gIFN0YXJ0IHBoeWxvZ2VuZXRpYyBhbmFseXNpcyBvZiB2YXJpYW50IHRhYmxlLgoKYGBge3IgbmV3X3NhbXBsZXNfaGlzYXR9CnNhbml0aXplX2NvbHVtbnMgPC0gYygicGFzc2FnZW51bWJlciIsICJjbGluaWNhbHJlc3BvbnNlIiwgImNsaW5pY2FsY2F0ZWdvcmljYWwiLAogICAgICAgICAgICAgICAgICAgICAgInp5bW9kZW1lY2F0ZWdvcmljYWwiLCAicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyIpCmxwX2V4cHQgPC0gc20oY3JlYXRlX2V4cHQoc2FtcGxlX3NoZWV0LAogICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGhpc2F0X2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgIGlkX2NvbHVtbiA9ICJocGdsaWRlbnRpZmllciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAibHBhbmFtZW5zaXN2MzZoaXNhdGZpbGUiKSkgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gInp5bW9kZW1lY2F0ZWdvcmljYWwiKSAlPiUKICBzdWJzZXRfZXhwdChub256ZXJvID0gODU1MCkgJT4lCiAgc3Vic2V0X2V4cHQoY292ZXJhZ2UgPSA1MDAwMDAwKSAlPiUKICBzZW1hbnRpY19leHB0X2ZpbHRlcihzZW1hbnRpYyA9IGMoImFtYXN0aW4iLCAiZ3A2MyIsICJsZWlzaG1hbm9seXNpbiIpLAogICAgICAgICAgICAgICAgICAgICAgIHNlbWFudGljX2NvbHVtbiA9ICJhbm5vdF9nZW5lX3Byb2R1Y3QiKSAlPiUKICBzYW5pdGl6ZV9leHB0X21ldGFkYXRhKGNvbHVtbnMgPSBzYW5pdGl6ZV9jb2x1bW5zKSAlPiUKICBzZXRfZXhwdF9mYWN0b3JzKGNvbHVtbnMgPSBzYW5pdGl6ZV9jb2x1bW5zLCBjbGFzcyA9ICJmYWN0b3IiKQoKbGlic2l6ZXMgPC0gcGxvdF9saWJzaXplKGxwX2V4cHQpCnBwKGZpbGUgPSAiaW1hZ2VzL2xwX2V4cHRfbGlic2l6ZXMucG5nIiwgaW1hZ2UgPSBsaWJzaXplcyRwbG90LCB3aWR0aCA9IDE0LCBoZWlnaHQgPSA5KQojIyBJIHRoaW5rIHNhbXBsZXMgNywxMCBzaG91bGQgYmUgcmVtb3ZlZCBhdCBtaW5pbXVtLCBwcm9iYWJseSBhbHNvIDksMTEKbm9uemVybyA8LSBwbG90X25vbnplcm8obHBfZXhwdCkKcHAoZmlsZSA9ICJpbWFnZXMvbHBfbm9uemVyby5wbmciLCBpbWFnZSA9IG5vbnplcm8kcGxvdCwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQoKbHBfYm94IDwtIHBsb3RfYm94cGxvdChscF9leHB0KQpwcChmaWxlID0gImltYWdlcy9scF9leHB0X2JveHBsb3QucG5nIiwgaW1hZ2UgPSBscF9ib3gsIHdpZHRoID0gMTIsIGhlaWdodCA9IDkpCgpmaWx0ZXJfcGxvdCA8LSBwbG90X2xpYnNpemVfcHJlcG9zdChscF9leHB0KQpmaWx0ZXJfcGxvdCRsb3dnZW5lX3Bsb3QKZmlsdGVyX3Bsb3QkY291bnRfcGxvdApgYGAKCiMjIERpc3RyaWJ1dGlvbiBWaXN1YWxpemF0aW9uCgpOYWppYidzIGZhdm9yaXRlIHBsb3RzIGFyZSBvZiBjb3Vyc2UgdGhlIFBDQS9UTlNFLiAgVGhlc2UgYXJlIG5pY2UgdG8gbG9vayBhdCBpbgpvcmRlciB0byBnZXQgYSBzZW5zZSBvZiB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHNhbXBsZXMuICBUaGV5IGFsc28gcHJvdmlkZSBhCmdvb2Qgb3Bwb3J0dW5pdHkgdG8gc2VlIHdoYXQgaGFwcGVucyB3aGVuIG9uZSBhcHBsaWVzIGRpZmZlcmVudCBub3JtYWxpemF0aW9ucywKc3Vycm9nYXRlIGFuYWx5c2VzLCBmaWx0ZXJzLCBldGMuICBJbiBhZGRpdGlvbiwgb25lIG1heSBzZXQgZGlmZmVyZW50CmV4cGVyaW1lbnRhbCBmYWN0b3JzIGFzIHRoZSBwcmltYXJ5ICdjb25kaXRpb24nICh1c3VhbGx5IHRoZSBjb2xvciBvZiBwbG90cykgYW5kCnN1cnJvZ2F0ZSAnYmF0Y2hlcycuCgojIyBCeSBTdXNjZXB0aWxpYml0eQoKQ29sdW1uICdRJyBpbiB0aGUgc2FtcGxlIHNoZWV0LCBtYWtlIGEgY2F0ZWdvcmljYWwgdmVyc2lvbiBvZiBpdCB3aXRoIHRoZXNlIHBhcmFtZXRlcnM6CgoqIDAgPD0geCA8PSAzNSBpcyByZXNpc3RhbnQKKiAzNiA8PSB4IDw9IDQ4IGlzIGFtYmlndW91cwoqIDQ5IDw9IHggaXMgc2Vuc2l0aXZlCgpgYGB7ciBzdXNjZXB0aWJpbGl0eX0Kc3RhcnRpbmcgPC0gYXMubnVtZXJpYyhwRGF0YShscF9leHB0KVtbInN1c2NlcHRpYmlsaXR5aW5mZWN0aW9ucmVkdWN0aW9uMzJ1Z21sc2J2aGlzdG9yaWNhbGRhdGEiXV0pCnN1c19jYXRlZ29yaWNhbCA8LSBzdGFydGluZwpuYV9pZHggPC0gaXMubmEoc3RhcnRpbmcpCnN1c19jYXRlZ29yaWNhbFtuYV9pZHhdIDwtICJ1bmtub3duIgoKcmVzaXN0X2lkeCA8LSBzdGFydGluZyA8PSAwLjM1CnN1c19jYXRlZ29yaWNhbFtyZXNpc3RfaWR4XSA8LSAicmVzaXN0YW50IgppbmRldGVybWluYW50X2lkeCA8LSBzdGFydGluZyA+PSAwLjM2ICYgc3RhcnRpbmcgPD0gMC40OApzdXNfY2F0ZWdvcmljYWxbaW5kZXRlcm1pbmFudF9pZHhdIDwtICJhbWJpZ3VvdXMiCnN1c2NlcHRpYmxlX2lkeCA8LSBzdGFydGluZyA+PSAwLjQ5CnN1c19jYXRlZ29yaWNhbFtzdXNjZXB0aWJsZV9pZHhdIDwtICJzZW5zaXRpdmUiCgpwRGF0YShscF9leHB0JGV4cHJlc3Npb25zZXQpW1sic3VzX2NhdGVnb3J5Il1dIDwtIHN1c19jYXRlZ29yaWNhbApgYGAKCmBgYHtyIHByZV9xdWVzdGlvbnN9CmNsaW5pY2FsX2NvbG9ycyA8LSBsaXN0KAogICAgInoyLjEiID0gIiMwMDAwY2MiLAogICAgInoyLjMiID0gIiM4NzQ0MDAiLAogICAgInoyLjIiID0gIiNkZjcwMDAiLAogICAgInoyLjQiID0gIiNjYzAwMDAiLAogICAgInVua25vd24iID0gIiNjYmNiY2IiLAogICAgIm51bGwiID0gIiMwMDAwMDAiKQpjbGluaWNhbF9zYW1wbGVzIDwtIGxwX2V4cHQgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gc3VzX2NhdGVnb3JpY2FsKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY2xpbmljYWxfY29sb3JzKQoKY2xpbmljYWxfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChjbGluaWNhbF9zYW1wbGVzLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkpCnp5bW9fcGNhIDwtIHBsb3RfcGNhKGNsaW5pY2FsX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvenltb19wY2Ffc3VzX3NoYXBlLnBuZyIsIGltYWdlID0genltb19wY2EkcGxvdCkKCnp5bW9fM2RwY2EgPC0gcGxvdF8zZF9wY2Eoenltb19wY2EpCnp5bW9fM2RwY2EkcGxvdAoKY2xpbmljYWxfbiA8LSBzbShub3JtYWxpemVfZXhwdChjbGluaWNhbF9zYW1wbGVzLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKenltb190c25lIDwtIHBsb3RfdHNuZShjbGluaWNhbF9uLCBwbG90X3RpdGxlID0gIlRTTkUgb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiKQp6eW1vX3RzbmUkcGxvdAoKY2xpbmljYWxfbmIgPC0gbm9ybWFsaXplX2V4cHQoY2xpbmljYWxfc2FtcGxlcywgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKQpjbGluaWNhbF9uYl9wY2EgPC0gcGxvdF9wY2EoY2xpbmljYWxfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGUgPSAiaW1hZ2VzL2NsaW5pY2FsX25iX3BjYV9zdXNfc2hhcGUucG5nIiwgaW1hZ2UgPSBjbGluaWNhbF9uYl9wY2EkcGxvdCkKCmNsaW5pY2FsX25iX3RzbmUgPC0gcGxvdF90c25lKGNsaW5pY2FsX25iLCBwbG90X3RpdGxlID0gIlRTTkUgb2YgcGFyYXNpdGUgZXhwcmVzc2lvbiB2YWx1ZXMiKQpjbGluaWNhbF9uYl90c25lJHBsb3QKCmNvcmhlYXQgPC0gcGxvdF9jb3JoZWF0KGNsaW5pY2FsX25vcm0sIHBsb3RfdGl0bGUgPSAiQ29ycmVsYXRpb24gaGVhdG1hcCBvZiBwYXJhc2l0ZQogICAgICAgICAgICAgICAgIGV4cHJlc3Npb24gdmFsdWVzCiIpCmNvcmhlYXQkcGxvdAoKcGxvdF9zbShjbGluaWNhbF9ub3JtKSRwbG90CmBgYAoKIyMgQnkgQ3VyZS9GYWlsIHN0YXR1cwoKYGBge3IgY2Zfc3RhdHVzfQpjZl9jb2xvcnMgPC0gbGlzdCgKICAgICJjdXJlIiA9ICIjMDA2ZjAwIiwKICAgICJmYWlsIiA9ICIjOWRmZmEwIiwKICAgICJ1bmtub3duIiA9ICIjY2JjYmNiIiwKICAgICJub3RhcHBsaWNhYmxlIiA9ICIjMDAwMDAwIikKY2ZfZXhwdCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGxwX2V4cHQsIGZhY3QgPSAiY2xpbmljYWxjYXRlZ29yaWNhbCIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9IHN1c19jYXRlZ29yaWNhbCkgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNmX2NvbG9ycykKCmNmX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoY2ZfZXhwdCwgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnN0YXJ0X2NmIDwtIHBsb3RfcGNhKGNmX25vcm0sIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvY2Zfc3VzX3NoYXBlLnBuZyIsIGltYWdlID0gc3RhcnRfY2YkcGxvdCkKCmNmX25iIDwtIG5vcm1hbGl6ZV9leHB0KGNmX2V4cHQsIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIikKY2ZfbmJfcGNhIDwtIHBsb3RfcGNhKGNmX25iLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy9jZl9zdXNfc2hhcmVfbmIucG5nIiwgaW1hZ2UgPSBjZl9uYl9wY2EkcGxvdCkKCmNmX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoY2ZfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCgp0ZXN0IDwtIHBjYV9pbmZvcm1hdGlvbihjZl9ub3JtLAogICAgICAgICAgICAgICAgICAgICAgICBleHB0X2ZhY3RvcnMgPSBjKCJjbGluaWNhbGNhdGVnb3JpY2FsIiwgInp5bW9kZW1lY2F0ZWdvcmljYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYXRob2dlbnN0cmFpbiIsICJwYXNzYWdlbnVtYmVyIiksCiAgICAgICAgICAgICAgICAgICAgICAgIG51bV9jb21wb25lbnRzID0gNiwgcGxvdF9wY2FzID0gVFJVRSkKdGVzdCRhbm92YV9wCnRlc3QkY29yX2hlYXRtYXAKYGBgCgpgYGB7ciBzdXNjZXB0aWJpbGl0eV9wY2F9CnN1c19jb2xvcnMgPC0gbGlzdCgKICAgICJyZXNpc3RhbnQiID0gIiM4NTYzYTciLAogICAgInNlbnNpdGl2ZSIgPSAiIzhkMDAwMCIsCiAgICAiYW1iaWd1b3VzIiA9ICIjY2JjYmNiIiwKICAgICJ1bmtub3duIiA9ICIjMDAwMDAwIikKc3VzX2V4cHQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhscF9leHB0LCBmYWN0ID0gInN1c19jYXRlZ29yeSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ6eW1vZGVtZWNhdGVnb3JpY2FsIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycyA9IHN1c19jb2xvcnMpCgpzdXNfbm9ybSA8LSBub3JtYWxpemVfZXhwdChzdXNfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpzdXNfcGNhIDwtIHBsb3RfcGNhKHN1c19ub3JtLCBwbG90X3RpdGxlID0gIlBDQSBvZiBwYXJhc2l0ZSBleHByZXNzaW9uIHZhbHVlcyIsCiAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJpbWFnZXMvc3VzX25vcm1fcGNhLnBuZyIsIGltYWdlID0gc3VzX3BjYVtbInBsb3QiXV0pCgpzdXNfbmIgPC0gbm9ybWFsaXplX2V4cHQoc3VzX2V4cHQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKc3VzX25iX3BjYSA8LSBwbG90X3BjYShzdXNfbmIsIHBsb3RfdGl0bGUgPSAiUENBIG9mIHBhcmFzaXRlIGV4cHJlc3Npb24gdmFsdWVzIiwKICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy9zdXNfbmJfcGNhLnBuZyIsIGltYWdlID0gc3VzX25iX3BjYVtbInBsb3QiXV0pCmBgYAoKIyBaeW1vZGVtZSBhbmFseXNlcwoKVGhlIGZvbGxvd2luZyBzZWN0aW9ucyBwZXJmb3JtIGEgc2VyaWVzIG9mIGFuYWx5c2VzIHdoaWNoIHNlZWsgdG8gZWx1Y2lkYXRlCmRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHp5bW9kZW1lcyAyLjIgYW5kIDIuMyBlaXRoZXIgdGhyb3VnaCBkaWZmZXJlbnRpYWwKZXhwcmVzc2lvbiBvciB2YXJpYW50IHByb2ZpbGVzLgoKIyMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24KCiMjIyBXaXRoIHJlc3BlY3QgdG8genltb2RlbWUgYXR0cmlidXRpb24KClRPRE86IERvIHRoaXMgd2l0aCBhbmQgd2l0aG91dCBzdmEgYW5kIGNvbXBhcmUgdGhlIHJlc3VsdHMuCgpgYGB7ciB6eW1vX2RlLCBmaWcuc2hvdyA9ICJoaWRlIn0KenlfZXhwdCA8LSBzdWJzZXRfZXhwdChscF9leHB0LCBzdWJzZXQgPSAiY29uZGl0aW9uPT0nejIuMid8Y29uZGl0aW9uPT0nejIuMyciKQp6eV9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHp5X2V4cHQsIGZpbHRlciA9IFRSVUUsIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIpCnp5X2RlX25vYmF0Y2ggPC0gc20oYWxsX3BhaXJ3aXNlKHp5X2V4cHQsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpKQp6eV9kZSA8LSBzbShhbGxfcGFpcndpc2UoenlfZXhwdCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikpCnp5X3RhYmxlIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKHp5X2RlLCBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL3p5X3RhYmxlcy12e3Zlcn0ueGxzeCIpKSkKenlfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoenlfdGFibGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvenlfc2lnLXZ7dmVyfS54bHN4IikpKQpgYGAKCiMjIyBJbWFnZXMgb2Ygenltb2RlbWUgREUKCmBgYHtyIHp5bW9kX2RlX3BpY3R1cmVzfQpwcChmaWxlID0gImltYWdlcy96eW1vX21hLnBuZyIsIGltYWdlID0genlfdGFibGVbWyJwbG90cyJdXVtbInoyM192c196MjIiXV1bWyJkZXNlcV9tYV9wbG90cyJdXVtbInBsb3QiXV0pCmBgYAoKIyMgV2l0aCByZXNwZWN0IHRvIGN1cmUvZmFpbHVyZQoKSW4gY29udHJhc3QsIHdlIGNhbiBzZWFyY2ggZm9yIGdlbmVzIHdoaWNoIGFyZSBkaWZmZXJlbnRpYWxseQpleHByZXNzZWQgd2l0aCByZXNwZWN0IHRvIGN1cmUvZmFpbHVyZSBzdGF0dXMuCgpgYGB7ciBjdXJlZmFpbF9kZSwgZmlnLnNob3cgPSAiaGlkZSJ9CmNmX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShjZl9leHB0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKSkKY2ZfdGFibGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoY2ZfZGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvY2ZfdGFibGVzLXZ7dmVyfS54bHN4IikpKQpjZl9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhjZl90YWJsZSwgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9jZl9zaWctdnt2ZXJ9Lnhsc3giKSkpCmBgYAoKIyMgV2l0aCByZXNwZWN0IHRvIHN1c2NlcHRpYmlsaXR5CgpGaW5hbGx5LCB3ZSBjYW4gdXNlIG91ciBjYXRlZ29yeSBvZiBzdXNjZXB0aWJpbGl0eSBhbmQgbG9vayBmb3IgZ2VuZXMKd2hpY2ggY2hhbmdlIGZyb20gc2Vuc2l0aXZlIHRvIHJlc2lzdGFudC4gIEtlZXAgaW4gbWluZCwgdGhvdWdoLCB0aGF0CmZvciB0aGUgbW9tZW50IHdlIGhhdmUgYSBsb3Qgb2YgYW1iaWd1b3VzIGFuZCB1bmtub3duIHN0cmFpbnMuCgpgYGB7ciBjdXJlZmFpbF9kZTAyLCBmaWcuc2hvdyA9ICJoaWRlIn0Kc3VzX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShzdXNfZXhwdCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikpCnN1c190YWJsZSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcyhzdXNfZGUsIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvc3VzX3RhYmxlcy12e3Zlcn0ueGxzeCIpKSkKc3VzX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKHN1c190YWJsZSwgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9zdXNfc2lnLXZ7dmVyfS54bHN4IikpKQpgYGAKCmBgYHtyIHp5bW9kX2RlX3BpY3R1cmVzMDF9CmtuaXRyOjprYWJsZShoZWFkKHN1c19zaWckZGVzZXEkdXBzJHNlbnNpdGl2ZV92c19yZXNpc3RhbnQsIG4gPSAyMCkpCgprbml0cjo6a2FibGUoaGVhZChzdXNfc2lnJGRlc2VxJGRvd25zJHNlbnNpdGl2ZV92c19yZXNpc3RhbnQsIG4gPSAyMCkpCgpzdXNfbWEgPC0gc3VzX3RhYmxlW1sicGxvdHMiXV1bWyJzZW5zaXRpdmVfdnNfcmVzaXN0YW50Il1dW1siZGVzZXFfbWFfcGxvdHMiXV1bWyJwbG90Il1dCnBwKGZpbGUgPSAiaW1hZ2VzL3N1c19tYS5wbmciLCBpbWFnZSA9IHN1c19tYSkKCiMjIHRlc3QgPC0gZ2dwbHQoc3VzX21hKQpgYGAKCiMjIE9udG9sb2d5IHNlYXJjaGVzCgpOb3cgbGV0IHVzIGxvb2sgZm9yIG9udG9sb2d5IGNhdGVnb3JpZXMgd2hpY2ggYXJlIGluY3JlYXNlZCBpbiB0aGUgMi4zCnNhbXBsZXMgZm9sbG93ZWQgYnkgdGhlIDIuMiBzYW1wbGVzLgoKYGBge3IgZ28sIHNpZy5zaG93ID0gImhpZGUifQojIyBHZW5lIGNhdGVnb3JpZXMgbW9yZSByZXByZXNlbnRlZCBpbiB0aGUgMi4zIGdyb3VwLgp6eV9nb191cCA8LSBzbShzaW1wbGVfZ29zZXEoc2lnX2dlbmVzID0genlfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2RiID0gbHBfZ28sIGxlbmd0aF9kYiA9IGxwX2xlbmd0aHMpKQoKIyMgR2VuZSBjYXRlZ29yaWVzIG1vcmUgcmVwcmVzZW50ZWQgaW4gdGhlIDIuMiBncm91cC4KenlfZ29fZG93biA8LSBzbShzaW1wbGVfZ29zZXEoc2lnX2dlbmVzID0genlfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19kYiA9IGxwX2dvLCBsZW5ndGhfZGIgPSBscF9sZW5ndGhzKSkKYGBgCgojIyMgQSBjb3VwbGUgcGxvdHMgZnJvbSB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24KCiMjIyMgTnVtYmVyIG9mIGdlbmVzIGluIGFncmVlbWVudCBhbW9uZyBERSBtZXRob2RzLCAyLjMgbW9yZSB0aGFuIDIuMgoKSW4gdGhlIGZ1bmN0aW9uICdjb21iaW5lZF9kZV90YWJsZXMoKScgYWJvdmUsIG9uZSBvZiB0aGUgdGFza3MKcGVyZm9ybWVkIGlzIHRvIGxvb2sgYXQgdGhlIGFncmVlbWVudCBhbW9uZyBERVNlcTIsIGxpbW1hLCBhbmQgZWRnZVIuClRoZSBmb2xsb3dpbmcgc2hvdyBhIGNvdXBsZSBvZiB0aGVzZSBmb3IgdGhlIHNldCBvZiBnZW5lcyBvYnNlcnZlZAp3aXRoIGEgZm9sZC1jaGFuZ2UgPj0gfDJ8IGFuZCBhZGp1c3RlZCBwLXZhbHVlIDw9IDAuMDUuCgpgYGB7ciBkZV9wbG90c30KenlfdGFibGVbWyJ2ZW5ucyJdXVtbMV1dW1sicF9sZmMxIl1dW1sidXBfbm93ZWlnaHQiXV0KYGBgCgojIyMjIE51bWJlciBvZiBnZW5lcyBpbiBhZ3JlZW1lbnQgYW1vbmcgREUgbWV0aG9kcywgMi4yIG1vcmUgdGhhbiAyLjMKCmBgYHtyIGRlX3Bsb3RzMDF9Cnp5X3RhYmxlW1sidmVubnMiXV1bWzFdXVtbInBfbGZjMSJdXVtbImRvd25fbm93ZWlnaHQiXV0KYGBgCgojIyMjIGdvc2VxIG9udG9sb2d5IHBsb3RzIG9mIGdyb3VwcyBvZiBnZW5lcywgMi4zIG1vcmUgdGhhbiAyLjIKCmBgYHtyIGdvc2VxX3VwfQp6eV9nb191cCRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3ZlcgpgYGAKCiMjIyMgZ29zZXEgb250b2xvZ3kgcGxvdHMgb2YgZ3JvdXBzIG9mIGdlbmVzLCAyLjIgbW9yZSB0aGFuIDIuMwoKYGBge3IgZ29zZXFfZG93bn0KenlfZ29fZG93biRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3ZlcgpgYGAKCiMjIExvb2sgZm9yIGFncmVlbWVudCBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCB6eW1vZGVtZXMKClJlbWluZCBteXNlbGYsIHRoZSBkYXRhIHN0cnVjdHVyZXMgYXJlICh6eXxzdXMpXyhkZXx0YWJsZXxzaWcpLgoKYGBge3Igc2Vuc2l0aXZlX3ZzX3p5bW99Cnp5X2RmIDwtIHp5X3RhYmxlW1siZGF0YSJdXVtbInoyM192c196MjIiXV0Kc3VzX2RmIDwtIHN1c190YWJsZVtbImRhdGEiXV1bWyJzZW5zaXRpdmVfdnNfcmVzaXN0YW50Il1dCgpib3RoX2RmIDwtIG1lcmdlKHp5X2RmLCBzdXNfZGYsIGJ5ID0gInJvdy5uYW1lcyIpCnBsb3RfZGYgPC0gYm90aF9kZlssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXQpyb3duYW1lcyhwbG90X2RmKSA8LSBib3RoX2RmW1siUm93Lm5hbWVzIl1dCmNvbG5hbWVzKHBsb3RfZGYpIDwtIGMoInoyM192c196MjIiLCAic2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCIpCgpjb21wYXJlIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIocGxvdF9kZikKcHAoZmlsZSA9ICJpbWFnZXMvY29tcGFyZV9zdXNfenkucG5nIiwgaW1hZ2UgPSBjb21wYXJlJHNjYXR0ZXIpCmNvbXBhcmUkY29yCmBgYAoKIyMgWnltb2RlbWUgZW56eW1lIGdlbmUgSURzCgpOYWppYiByZWFkIG1lIGFuIGVtYWlsIGxpc3Rpbmcgb2ZmIHRoZSBnZW5lIG5hbWVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgenltb2RlbWUKY2xhc3NpZmljYXRpb24uICBJIHRvb2sgdGhvc2UgbmFtZXMgYW5kIGNyb3NzIHJlZmVyZW5jZWQgdGhlbSBhZ2FpbnN0IHRoZQpMZWlzaG1hbmlhIHBhbmFtZW5zaXMgZ2VuZSBhbm5vdGF0aW9ucyBhbmQgZm91bmQgdGhlIGZvbGxvd2luZzoKClRoZXkgYXJlOgoKMS4gQUxBVDogTFBBTDEzXzEyMDAxMDkwMCAtLSBhbGFuaW5lIGFtaW5vdHJhbnNmZXJhc2UKMi4gQVNBVDogTFBBTDEzXzM0MDAxMzAwMCAtLSBhc3BhcnRhdGUgYW1pbm90cmFuc2ZlcmFzZQozLiBHNlBEOiBMUEFMMTNfMDAwMDU0MTAwIC0tIGdsdWNhc2UtNi1waG9zcGhhdGUgMS1kZWh5ZHJvZ2VuYXNlCjQuIE5IOiBMUEFMMTNfMTQwMDYxMDAsIExQQUwxM18xODAwMTg1MDAgLS0gaW5vc2luZS1ndWFuaW5lIG51Y2xlb3NpZGUgaHlkcm9sYXNlCjUuIE1QSTogTFBBTDEzXzMyMDAyMjMwMCAobWF5YmUpIC0tIG1hbm5vc2UgcGhvc3BoYXRlIGlzb21lcmFzZSAoSSBjaG9zZSBwaG9zcGhvbWFubm9zZSBpc29tZXJhc2UpCgpHaXZlbiB0aGVzZSA2IGdlbmUgSURzIChOSCBoYXMgdHdvIGdlbmUgSURzIGFzc29jaWF0ZWQgd2l0aCBpdCksIEkgY2FuIGRvIHNvbWUKbG9va2luZyBmb3Igc3BlY2lmaWMgZGlmZmVyZW5jZXMgYW1vbmcgdGhlIHZhcmlvdXMgc2FtcGxlcy4KCiMjIyBFeHByZXNzaW9uIGxldmVscyBvZiB6eW1vZGVtZSBnZW5lcwoKVGhlIGZvbGxvd2luZyBjcmVhdGVzIGEgY29sb3JzcGFjZSAocmVkIHRvIGdyZWVuKSBoZWF0bWFwIHNob3dpbmcgdGhlIG9ic2VydmVkCmV4cHJlc3Npb24gb2YgdGhlc2UgZ2VuZXMgaW4gZXZlcnkgc2FtcGxlLgoKYGBge3Igenltb2RlbWVzfQpteV9nZW5lcyA8LSBjKCJMUEFMMTNfMTIwMDEwOTAwIiwgIkxQQUwxM18zNDAwMTMwMDAiLCAiTFBBTDEzXzAwMDA1NDEwMCIsCiAgICAgICAgICAgICAgIkxQQUwxM18xNDAwMDYxMDAiLCAiTFBBTDEzXzE4MDAxODUwMCIsICJMUEFMMTNfMzIwMDIyMzAwIiwKICAgICAgICAgICAgICAib3RoZXIiKQpteV9uYW1lcyA8LSBjKCJBTEFUIiwgIkFTQVQiLCAiRzZQRCIsICJOSHYxIiwgIk5IdjIiLCAiTVBJIiwgIm90aGVyIikKCnp5bW9fZXhwdCA8LSBleGNsdWRlX2dlbmVzX2V4cHQoenlfbm9ybSwgaWRzID0gbXlfZ2VuZXMsIG1ldGhvZCA9ICJrZWVwIikKenltb19oZWF0bWFwIDwtIHBsb3Rfc2FtcGxlX2hlYXRtYXAoenltb19leHB0LCByb3dfbGFiZWwgPSBteV9uYW1lcykKenltb19oZWF0bWFwCmBgYAoKIyMgRW1waXJpY2FsbHkgb2JzZXJ2ZWQgWnltb2RlbWUgZ2VuZXMgZnJvbSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwoKSW4gY29udHJhc3QsIHRoZSBmb2xsb3dpbmcgcGxvdHMgdGFrZSB0aGUgc2V0IG9mIGdlbmVzIHdoaWNoIGFyZSBzaGFyZWQgYW1vbmcKYWxsIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIG1ldGhvZHMgKHxsZmN8ID49IDEuMCBhbmQgYWRqcCA8PSAwLjA1KSBhbmQgdXNlIHRoZW0KdG8gbWFrZSBjYXRlZ29yaWVzIG9mIGdlbmVzIHdoaWNoIGFyZSBpbmNyZWFzZWQgaW4gMi4zIG9yIDIuMi4KCmBgYHtyIHp5bW9kZW1lX2dlbmVzX2VtcGlyaWNhbH0Kc2hhcmVkX3p5bW8gPC0gaW50ZXJzZWN0X3NpZ25pZmljYW50KHp5X3RhYmxlKQp1cF9zaGFyZWQgPC0gc2hhcmVkX3p5bW9bWyJ1cHMiXV1bWzFdXVtbImRhdGEiXV1bWyJhbGwiXV0Kcm93bmFtZXModXBfc2hhcmVkKQp1cHNoYXJlZF9leHB0IDwtIGV4Y2x1ZGVfZ2VuZXNfZXhwdCh6eV9ub3JtLCBpZHMgPSByb3duYW1lcyh1cF9zaGFyZWQpLCBtZXRob2QgPSAia2VlcCIpCmBgYAoKV2UgY2FuIHBsb3QgYSBxdWljayBoZWF0bWFwIHRvIGdldCBhIHNlbnNlIG9mIHRoZSBkaWZmZXJlbmNlcyBvYnNlcnZlZApiZXR3ZWVuIHRoZSBnZW5lcyB3aGljaCBhcmUgZGlmZmVyZW50IGJldHdlZW4gdGhlIHR3byB6eW1vZGVtZXMuCgojIyMgSGVhdG1hcCBvZiB6eW1vZGVtZSBnZW5lIGV4cHJlc3Npb24gaW5jcmVhc2VkIGluIDIuMyB2cy4gMi4yCgpgYGB7ciB6eW1vZW1wdXB9CmhpZ2hfMjNfaGVhdG1hcCA8LSBwbG90X3NhbXBsZV9oZWF0bWFwKHVwc2hhcmVkX2V4cHQsIHJvd19sYWJlbCA9IHJvd25hbWVzKHVwX3NoYXJlZCkpCmhpZ2hfMjNfaGVhdG1hcApgYGAKCiMjIyBIZWF0bWFwIG9mIHp5bW9kZW1lIGdlbmUgZXhwcmVzc2lvbiBpbmNyZWFzZWQgaW4gMi4yIHZzLiAyLjMKCmBgYHtyIHp5bW9lbWRvd259CmRvd25fc2hhcmVkIDwtIHNoYXJlZF96eW1vW1siZG93bnMiXV1bWzFdXVtbImRhdGEiXV1bWyJhbGwiXV0KZG93bnNoYXJlZF9leHB0IDwtIGV4Y2x1ZGVfZ2VuZXNfZXhwdCh6eV9ub3JtLCBpZHMgPSByb3duYW1lcyhkb3duX3NoYXJlZCksIG1ldGhvZCA9ICJrZWVwIikKaGlnaF8yMl9oZWF0bWFwIDwtIHBsb3Rfc2FtcGxlX2hlYXRtYXAoZG93bnNoYXJlZF9leHB0LCByb3dfbGFiZWwgPSByb3duYW1lcyhkb3duX3NoYXJlZCkpCmhpZ2hfMjJfaGVhdG1hcApgYGAKCiMgU05QIHByb2ZpbGVzCgpOb3cgSSB3aWxsIGNvbWJpbmUgb3VyIHByZXZpb3VzIHNhbXBsZXMgYW5kIG91ciBuZXcgc2FtcGxlcyBpbiB0aGUKaG9wZXMgb2YgZmluZGluZyB2YXJpYW50IHBvc2l0aW9ucyB3aGljaCBoZWxwIGVsdWNpZGF0ZSBjdXJyZW50bHkKdW5rbm93biBhc3BlY3RzIG9mIGVpdGhlciBncm91cCB2aWEgdGhlaXIgY2x1c3RlcmluZyB0byBrbm93biBzYW1wbGVzCmZyb20gdGhlIG90aGVyIGdyb3VwLiBJbiBvdGhlciB3b3Jkcywgd2UgZG8gbm90IGtub3cgdGhlIHp5bW9kZW1lCmFubm90YXRpb25zIGZvciB0aGUgb2xkIHNhbXBsZXMgbm9yIHRoZSBzdHJhaW4gaWRlbnRpdGllcyAob3IgdGhlCnNob3J0Y3V0ICdjaHJvbmljIHZzLiBzZWxmLWhlYWxpbmcnKSBmb3IgdGhlIG5ldyBzYW1wbGVzLiBJIGhvcGUgdG8KbWFrZSBlZHVjYXRlZCBndWVzc2VzIGdpdmVuIHRoZSB2YXJpYW50IHByb2ZpbGVzLiBUaGVyZSBhcmUgc29tZQpkaWZmZXJlbmNlcyBpbiBob3cgdGhlIHByZXZpb3VzIGFuZCBjdXJyZW50IGRhdGEgc2V0cyB3ZXJlIGFuYWx5emVkCih0aG91Z2ggSSBoYXZlIHNpbmNlIHJlZG9uZSB0aGUgb2xkIHNhbXBsZXMgc28gaXQgc2hvdWxkIGJlIHRyaXZpYWwgdG8KcmVtb3ZlIHRob3NlIGRpZmZlcmVuY2VzIG5vdykuCgpJIGFkZGVkIG91ciAyMDE2IGRhdGEgdG8gYSBzcGVjaWZpYyBUTVJDMiBzYW1wbGUgc2hlZXQsCmRhdGVkIDIwMTkxMjAzLiAgVGh1cyBJIHdpbGwgbG9hZCB0aGUgZGF0YSBoZXJlLiAgVGhhdCBwcmV2aW91cyBkYXRhCndhcyBtYXBwZWQgdXNpbmcgdG9waGF0LCBzbyBJIHdpbGwgYWxzbyBuZWVkIHRvIG1ha2Ugc29tZSBjaGFuZ2VzIHRvCnRoZSBnZW5lIG5hbWVzIHRvIGFjY29tb2RhdGUgdGhlIHR3byBtYXBwaW5ncy4KCmBgYHtyIG9sZG5ld192YXJpYW50c30Kb2xkX2V4cHQgPC0gc20oY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvdG1yYzJfc2FtcGxlc18yMDE5MTIwMy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidG9waGF0MmZpbGUiKSkKCnR0IDwtIGxwX2V4cHRbWyJleHByZXNzaW9uc2V0Il1dCnJvd25hbWVzKHR0KSA8LSBnc3ViKHBhdHRlcm4gPSAiXmV4b25fIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJvd25hbWVzKHR0KSkKcm93bmFtZXModHQpIDwtIGdzdWIocGF0dGVybiA9ICJcXC5FMSQiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gcm93bmFtZXModHQpKQpscF9leHB0JGV4cHJlc3Npb25zZXQgPC0gdHQKCnR0IDwtIG9sZF9leHB0JGV4cHJlc3Npb25zZXQKcm93bmFtZXModHQpIDwtIGdzdWIocGF0dGVybiA9ICJeZXhvbl8iLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gcm93bmFtZXModHQpKQpyb3duYW1lcyh0dCkgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLjEkIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJvd25hbWVzKHR0KSkKb2xkX2V4cHQkZXhwcmVzc2lvbnNldCA8LSB0dApybSh0dCkKYGBgCgojIyBDcmVhdGUgdGhlIFNOUCBleHByZXNzaW9uc2V0CgpPbmUgb3RoZXIgaW1wb3J0YW50IGNhdmVhdCwgd2UgaGF2ZSBhIGdyb3VwIG9mIG5ldyBzYW1wbGVzIHdoaWNoIGhhdmUKbm90IHlldCBydW4gdGhyb3VnaCB0aGUgdmFyaWFudCBzZWFyY2ggcGlwZWxpbmUsIHNvIEkgbmVlZCB0byByZW1vdmUKdGhlbSBmcm9tIGNvbnNpZGVyYXRpb24uICBUaG91Z2ggaXQgbG9va3MgbGlrZSB0aGV5IGZpbmlzaGVkIG92ZXJuaWdodC4uLgoKYGBge3IgY291bnRfZXhwdF9vbGRfbmV3fQojIyBUaGUgbmV4dCBsaW5lIGRyb3BzIHRoZSBzYW1wbGVzIHdoaWNoIGFyZSBtaXNzaW5nIHRoZSBTTlAgcGlwZWxpbmUuCmxwX3NucCA8LSBzdWJzZXRfZXhwdChscF9leHB0LCBzdWJzZXQ9IiFpcy5uYShwRGF0YShscF9leHB0KVtbJ2JjZnRhYmxlJ11dKSIpCm5ld19zbnBzIDwtIHNtKGNvdW50X2V4cHRfc25wcyhscF9zbnAsIGFubm90X2NvbHVtbiA9ICJiY2Z0YWJsZSIpKQpvbGRfc25wcyA8LSBzbShjb3VudF9leHB0X3NucHMob2xkX2V4cHQsIGFubm90X2NvbHVtbiA9ICJiY2Z0YWJsZSIsIHNucF9jb2x1bW4gPSAyKSkKCmJvdGhfc25wcyA8LSBjb21iaW5lX2V4cHRzKG5ld19zbnBzLCBvbGRfc25wcykKYm90aF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGJvdGhfc25wcywgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUpKQoKIyMgc3RyYWlucyA8LSBib3RoX25vcm1bWyJkZXNpZ24iXV1bWyJzdHJhaW4iXV0KYm90aF9zdHJhaW4gPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhib3RoX25vcm0sIGZhY3QgPSAic3RyYWluIikKYGBgCgpUaGUgZGF0YSBzdHJ1Y3R1cmUgJ2JvdGhfbm9ybScgbm93IGNvbnRhaW5zIG91ciAyMDE2IGRhdGEgYWxvbmcgd2l0aAp0aGUgbmV3ZXIgZGF0YSBjb2xsZWN0ZWQgc2luY2UgMjAxOS4KCiMjIFBsb3Qgb2YgU05QIHByb2ZpbGVzIGZvciB6eW1vZGVtZXMKClRoZSBmb2xsb3dpbmcgcGxvdCBzaG93cyB0aGUgU05QIHByb2ZpbGVzIG9mIGFsbCBzYW1wbGVzIChvbGQgYW5kIG5ldykgd2hlcmUgdGhlCmNvbG9ycyBhdCB0aGUgdG9wIHNob3cgZWl0aGVyIHRoZSAyLjIgc3RyYWlucyAob3JhbmdlKSwgMi4zIHN0cmFpbnMgKGdyZWVuKSwgdGhlCnByZXZpb3VzIHNhbXBsZXMgKHB1cnBsZSksIG9yIHRoZSB2YXJpb3VzIGxhYiBzdHJhaW5zIChwaW5rIGV0YykuCgpgYGB7ciBwbG90dGluZ192YXJpYW50c30Kb2xkX25ld192YXJpYW50X2hlYXRtYXAgPC0gcGxvdF9kaXNoZWF0KGJvdGhfbm9ybSkKcHAoZmlsZSA9ICJpbWFnZXMvcmF3X3NucF9kaXNoZWF0LnBuZyIsIGltYWdlID0gb2xkX25ld192YXJpYW50X2hlYXRtYXAsCiAgIGhlaWdodCA9IDEyLCB3aWR0aCA9IDEyKQpgYGAKClRoZSBmdW5jdGlvbiBnZXRfc25wX3NldHMoKSB0YWtlcyB0aGUgcHJvdmlkZWQgbWV0YWRhdGEgZmFjdG9yIChpbgp0aGlzIGNhc2UgJ2NvbmRpdGlvbicpIGFuZCBsb29rcyBmb3IgdmFyaWFudHMgd2hpY2ggYXJlIGV4Y2x1c2l2ZSB0bwplYWNoIGVsZW1lbnQgaW4gaXQuICBJbiB0aGlzIGNhc2UsIHRoaXMgaXMgbG9va2luZyBmb3IgZGlmZmVyZW5jZXMKYmV0d2VlbiAyLjIgYW5kIDIuMywgYXMgd2VsbCBhcyB0aGUgc2V0IHNoYXJlZCBhbW9uZyB0aGVtLgoKYGBge3IgZ2V0X3NucF9zZXRzMX0Kc25wX3NldHMgPC0gZ2V0X3NucF9zZXRzKGJvdGhfc25wcywgZmFjdG9yID0gImNvbmRpdGlvbiIpCmJvdGhfZXhwdCA8LSBjb21iaW5lX2V4cHRzKGxwX2V4cHQsIG9sZF9leHB0KQoKc25wX2dlbmVzIDwtIHNtKHNucHNfdnNfZ2VuZXMoYm90aF9leHB0LCBzbnBfc2V0cywgZXhwdF9uYW1lX2NvbCA9ICJjaHJvbW9zb21lIikpCiMjIEkgdGhpbmsgd2UgaGF2ZSBzb21lIG1ldHJpY3MgaGVyZSB3ZSBjYW4gcGxvdC4uLgpzbnBfc3Vic2V0IDwtIHNtKHNucF9zdWJzZXRfZ2VuZXMoCiAgYm90aF9leHB0LCBib3RoX3NucHMsCiAgZ2VuZXMgPSBjKCJMUEFMMTNfMTIwMDEwOTAwIiwgIkxQQUwxM18zNDAwMTMwMDAiLCAiTFBBTDEzXzAwMDA1NDEwMCIsCiAgICAgICAgICAgICJMUEFMMTNfMTQwMDA2MTAwIiwgIkxQQUwxM18xODAwMTg1MDAiLCAiTFBBTDEzXzMyMDAyMjMwMCIpKSkKenltb19oZWF0IDwtIHBsb3Rfc2FtcGxlX2hlYXRtYXAoc25wX3N1YnNldCwgcm93X2xhYmVsID0gcm93bmFtZXMoZXhwcnMoc25wX3N1YnNldCkpKQp6eW1vX2hlYXQKYGBgCgpEaWRuJ3QgSSBjcmVhdGUgYSBzZXQgb2YgZGVuc2l0aWVzIGJ5IGNocm9tb3NvbWU/Ck9oIEkgdGhpbmsgdGhleSBjb21lIGluIGZyb20gZ2V0X3NucF9zZXRzKCkKCiMjIFNOUFMgYXNzb2NpYXRlZCB3aXRoIGNsaW5pY2FsIHJlc3BvbnNlIGluIHRoZSBUTVJDIHNhbXBsZXMKCmBgYHtyIHNucF9jbGluaWNhbH0KY2xpbmljYWxfc2V0cyA8LSBnZXRfc25wX3NldHMobmV3X3NucHMsIGZhY3RvciA9ICJjbGluaWNhbHJlc3BvbnNlIikKCmRlbnNpdHlfdmVjIDwtIGNsaW5pY2FsX3NldHNbWyJkZW5zaXR5Il1dCmNocm9tb3NvbWVfaWR4IDwtIGdyZXAocGF0dGVybiA9ICJMcGFMIiwgeCA9IG5hbWVzKGRlbnNpdHlfdmVjKSkKZGVuc2l0eV9kZiA8LSBhcy5kYXRhLmZyYW1lKGRlbnNpdHlfdmVjW2Nocm9tb3NvbWVfaWR4XSkKZGVuc2l0eV9kZltbImNociJdXSA8LSByb3duYW1lcyhkZW5zaXR5X2RmKQpjb2xuYW1lcyhkZW5zaXR5X2RmKSA8LSBjKCJkZW5zaXR5X3ZlYyIsICJjaHIiKQpnZ3Bsb3QoZGVuc2l0eV9kZiwgYWVzX3N0cmluZyh4ID0gImNociIsIHkgPSAiZGVuc2l0eV92ZWMiKSkgKwogIGdncGxvdDI6Omdlb21fY29sKCkgKwogIGdncGxvdDI6OnRoZW1lKGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSkKCiMjIGNsaW5pY2FsX3dyaXR0ZW4gPC0gd3JpdGVfdmFyaWFudHMobmV3X3NucHMpCmBgYAoKIyMjIENyb3NzIHJlZmVyZW5jZSB0aGVzZSB2YXJpYW50cyBieSBnZW5lCgpgYGB7ciBzbnBfY2xhc3NpZmljYXRpb25zfQpjbGluaWNhbF9nZW5lcyA8LSBzbShzbnBzX3ZzX2dlbmVzKGxwX2V4cHQsIGNsaW5pY2FsX3NldHMsIGV4cHRfbmFtZV9jb2wgPSAiY2hyb21vc29tZSIpKQoKc25wX2RlbnNpdHkgPC0gbWVyZ2UoYXMuZGF0YS5mcmFtZShjbGluaWNhbF9nZW5lc1tbInN1bW1hcnlfYnlfZ2VuZSJdXSksCiAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoZkRhdGEobHBfZXhwdCkpLAogICAgICAgICAgICAgICAgICAgICBieSA9ICJyb3cubmFtZXMiKQpzbnBfZGVuc2l0eSA8LSBzbnBfZGVuc2l0eVssIGMoMSwgMiwgNCwgMTUpXQpjb2xuYW1lcyhzbnBfZGVuc2l0eSkgPC0gYygibmFtZSIsICJzbnBzIiwgInByb2R1Y3QiLCAibGVuZ3RoIikKc25wX2RlbnNpdHlbWyJwcm9kdWN0Il1dIDwtIHRvbG93ZXIoc25wX2RlbnNpdHlbWyJwcm9kdWN0Il1dKQpzbnBfZGVuc2l0eVtbImxlbmd0aCJdXSA8LSBhcy5udW1lcmljKHNucF9kZW5zaXR5W1sibGVuZ3RoIl1dKQpzbnBfZGVuc2l0eVtbImRlbnNpdHkiXV0gPC0gc25wX2RlbnNpdHlbWyJzbnBzIl1dIC8gc25wX2RlbnNpdHlbWyJsZW5ndGgiXV0Kc25wX2lkeCA8LSBvcmRlcihzbnBfZGVuc2l0eVtbImRlbnNpdHkiXV0sIGRlY3JlYXNpbmcgPSBUUlVFKQpzbnBfZGVuc2l0eSA8LSBzbnBfZGVuc2l0eVtzbnBfaWR4LCBdCgpyZW1vdmVycyA8LSBjKCJhbWFzdGluIiwgImdwNjMiLCAibGVpc2htYW5vbHlzaW4iKQpmb3IgKHIgaW4gcmVtb3ZlcnMpIHsKICBkcm9wX2lkeCA8LSBncmVwbChwYXR0ZXJuID0gciwgeCA9IHNucF9kZW5zaXR5W1sicHJvZHVjdCJdXSkKICBzbnBfZGVuc2l0eSA8LSBzbnBfZGVuc2l0eVshZHJvcF9pZHgsIF0KfQojIyBGaWx0ZXIgdGhlc2UgZm9yIFtBfGFdbWFzdGluIGdwNjMgTGVpc2htYW5vbHlzaW4KYGBgCgoKYGBge3Igc25wX2ludGVyc2VjdGlvbnN9CmNsaW5pY2FsX3NucHMgPC0gc25wc19pbnRlcnNlY3Rpb25zKGxwX2V4cHQsIGNsaW5pY2FsX3NldHMsIGNocl9jb2x1bW4gPSAiY2hyb21vc29tZSIpCgpmYWlsX3JlZl9zbnBzIDwtIGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfc25wc1tbImludGVycyJdXVtbImZhaWx1cmUsIHJlZmVyZW5jZSBzdHJhaW4iXV0pCmN1cmVfc25wcyA8LSBhcy5kYXRhLmZyYW1lKGNsaW5pY2FsX3NucHNbWyJpbnRlcnMiXV1bWyJjdXJlIl1dKQoKaGVhZChmYWlsX3JlZl9zbnBzKQpoZWFkKGN1cmVfc25wcykKCmFubm90IDwtIGZEYXRhKGxwX2V4cHQpCmNsaW5pY2FsX2ludGVyZXN0IDwtIGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfc25wc1tbImdlbmVfc3VtbWFyaWVzIl1dW1siY3VyZSJdXSkKY2xpbmljYWxfaW50ZXJlc3QgPC0gbWVyZ2UoY2xpbmljYWxfaW50ZXJlc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY2xpbmljYWxfc25wc1tbImdlbmVfc3VtbWFyaWVzIl1dW1siZmFpbHVyZSwgcmVmZXJlbmNlIHN0cmFpbiJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIpCnJvd25hbWVzKGNsaW5pY2FsX2ludGVyZXN0KSA8LSBjbGluaWNhbF9pbnRlcmVzdFtbIlJvdy5uYW1lcyJdXQpjbGluaWNhbF9pbnRlcmVzdFtbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCmNvbG5hbWVzKGNsaW5pY2FsX2ludGVyZXN0KSA8LSBjKCJjdXJlX3NucHMiLCJmYWlsX3NucHMiKQphbm5vdCA8LSBtZXJnZShhbm5vdCwgY2xpbmljYWxfaW50ZXJlc3QsIGJ5ID0gInJvdy5uYW1lcyIpCnJvd25hbWVzKGFubm90KSA8LSBhbm5vdFtbIlJvdy5uYW1lcyJdXQphbm5vdFtbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCmZEYXRhKGxwX2V4cHQkZXhwcmVzc2lvbnNldCkgPC0gYW5ub3QKYGBgCgojIFp5bW9kZW1lIGZvciBuZXcgc2FtcGxlcwoKVGhlIGhlYXRtYXAgcHJvZHVjZWQgaGVyZSBzaG91bGQgc2hvdyB0aGUgdmFyaWFudHMgb25seSBmb3IgdGhlIHp5bW9kZW1lIGdlbmVzLgoKIyMgSHVudCBmb3Igc25wIGNsdXN0ZXJzCgpJIGFtIHRoaW5raW5nIHRoYXQgaWYgd2UgZmluZCBjbHVzdGVycyBvZiBsb2NhdGlvbnMgd2hpY2ggYXJlIHZhcmlhbnQsIHRoYXQKbWlnaHQgcHJvdmlkZSBzb21lIFBDUiB0ZXN0aW5nIHBvc3NpYmlsaXRpZXMuCgpgYGB7ciBuZXdfenltb30KbmV3X3NldHMgPC0gZ2V0X3NucF9zZXRzKG5ld19zbnBzLCBmYWN0b3IgPSAicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyIpCnN1bW1hcnkobmV3X3NldHMpCiMjIDEwMDAwMDA6IDIuMgojIyAwMTAwMDAwOiAyLjMKCnN1bW1hcnkobmV3X3NldHNbWyJpbnRlcnNlY3Rpb25zIl1dW1siMTAwMDAiXV0pCnN1bW1hcnkobmV3X3NldHNbWyJpbnRlcnNlY3Rpb25zIl1dW1siMDEwMDAiXV0pCmBgYAoKVGh1cyB3ZSBzZWUgdGhhdCB0aGVyZSBhcmUgNTExIHZhcmlhbnRzIGFzc29jaWF0ZWQgd2l0aCAyLjIgYW5kIDQ5LDc5MCBhc3NvY2lhdGVkIHdpdGggMi4zLgoKIyMjIEEgc21hbGwgZnVuY3Rpb24gZm9yIHNlYXJjaGluZyBmb3IgcG90ZW50aWFsIFBDUiBwcmltZXJzCgpUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIHVzZXMgdGhlIHBvc2l0aW9uYWwgZGF0YSB0byBsb29rIGZvciBzZXF1ZW50aWFsCm1pc21hdGNoZXMgYXNzb2NpYXRlZCB3aXRoIHp5bW9kZW1lIGluIHRoZSBob3BlcyB0aGF0IHRoZXJlIHdpbGwgYmUKc29tZSByZWdpb25zIHdoaWNoIHdvdWxkIHByb3ZpZGUgZ29vZCBwb3RlbnRpYWwgdGFyZ2V0cyBmb3IgYQpQQ1ItYmFzZWQgYXNzYXkuCgpgYGB7ciBzZXF1ZW50aWFsX3NlYXJjaCwgZXZhbD1GQUxTRX0Kc2VxdWVudGlhbF92YXJpYW50cyA8LSBmdW5jdGlvbihzbnBfc2V0cywgY29uZGl0aW9ucyA9IE5VTEwsIG1pbmltdW0gPSAzLCBtYXhpbXVtX3NlcGFyYXRpb24gPSAzKSB7CiAgaWYgKGlzLm51bGwoY29uZGl0aW9ucykpIHsKICAgIGNvbmRpdGlvbnMgPC0gMQogIH0KICBpbnRlcnNlY3Rpb25fc2V0cyA8LSBzbnBfc2V0c1tbImludGVyc2VjdGlvbnMiXV0KICBpbnRlcnNlY3Rpb25fbmFtZXMgPC0gc25wX3NldHNbWyJzZXRfbmFtZXMiXV0KICBjaG9zZW5faW50ZXJzZWN0aW9uIDwtIDEKICBpZiAoaXMubnVtZXJpYyhjb25kaXRpb25zKSkgewogICAgY2hvc2VuX2ludGVyc2VjdGlvbiA8LSBjb25kaXRpb25zCiAgfSBlbHNlIHsKICAgIGludGVyc2VjdGlvbl9pZHggPC0gaW50ZXJzZWN0aW9uX25hbWVzID09IGNvbmRpdGlvbnMKICAgIGNob3Nlbl9pbnRlcnNlY3Rpb24gPC0gbmFtZXMoaW50ZXJzZWN0aW9uX25hbWVzKVtpbnRlcnNlY3Rpb25faWR4XQogIH0KCiAgcG9zc2libGVfcG9zaXRpb25zIDwtIGludGVyc2VjdGlvbl9zZXRzW1tjaG9zZW5faW50ZXJzZWN0aW9uXV0KICBwb3NpdGlvbl90YWJsZSA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IHBvc3NpYmxlX3Bvc2l0aW9ucykKICBwYXQgPC0gIl5jaHJfKC4rKV9wb3NfKC4rKV9yZWZfLiokIgogIHBvc2l0aW9uX3RhYmxlW1siY2hyIl1dIDwtIGdzdWIocGF0dGVybiA9IHBhdCwgcmVwbGFjZW1lbnQgPSAiXFwxIiwgeCA9IHJvd25hbWVzKHBvc2l0aW9uX3RhYmxlKSkKICBwb3NpdGlvbl90YWJsZVtbInBvcyJdXSA8LSBhcy5udW1lcmljKGdzdWIocGF0dGVybiA9IHBhdCwgcmVwbGFjZW1lbnQgPSAiXFwyIiwgeCA9IHJvd25hbWVzKHBvc2l0aW9uX3RhYmxlKSkpCiAgcG9zaXRpb25faWR4IDwtIG9yZGVyKHBvc2l0aW9uX3RhYmxlWywgImNociJdLCBwb3NpdGlvbl90YWJsZVssICJwb3MiXSkKICBwb3NpdGlvbl90YWJsZSA8LSBwb3NpdGlvbl90YWJsZVtwb3NpdGlvbl9pZHgsIF0KICBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPC0gMAoKICBsYXN0X2NociA8LSAiIgogIGZvciAociBpbiAxOm5yb3cocG9zaXRpb25fdGFibGUpKSB7CiAgICB0aGlzX2NociA8LSBwb3NpdGlvbl90YWJsZVtyLCAiY2hyIl0KICAgIGlmIChyID09IDEpIHsKICAgICAgcG9zaXRpb25fdGFibGVbciwgImRpc3QiXSA8LSBwb3NpdGlvbl90YWJsZVtyLCAicG9zIl0KICAgICAgbGFzdF9jaHIgPC0gdGhpc19jaHIKICAgICAgbmV4dAogICAgfQogICAgaWYgKHRoaXNfY2hyID09IGxhc3RfY2hyKSB7CiAgICAgIHBvc2l0aW9uX3RhYmxlW3IsICJkaXN0Il0gPC0gcG9zaXRpb25fdGFibGVbciwgInBvcyJdIC0gcG9zaXRpb25fdGFibGVbciAtIDEsICJwb3MiXQogICAgfSBlbHNlIHsKICAgICAgcG9zaXRpb25fdGFibGVbciwgImRpc3QiXSA8LSBwb3NpdGlvbl90YWJsZVtyLCAicG9zIl0KICAgIH0KICAgIGxhc3RfY2hyIDwtIHRoaXNfY2hyCiAgfQoKICAjIyBXb3JraW5nIGludGVyYWN0aXZlbHkgaGVyZS4KICAKICBkb3VibGVzIDwtIHBvc2l0aW9uX3RhYmxlW1siZGlzdCJdXSA9PSAxCiAgZG91YmxlcyA8LSBwb3NpdGlvbl90YWJsZVtkb3VibGVzLCBdCiAgd3JpdGUuY3N2KGRvdWJsZXMsICJkb3VibGVzLmNzdiIpCgogIG9uZV9hd2F5IDwtIHBvc2l0aW9uX3RhYmxlW1siZGlzdCJdXSA9PSAyCiAgb25lX2F3YXkgPC0gcG9zaXRpb25fdGFibGVbb25lX2F3YXksIF0KICB3cml0ZS5jc3Yob25lX2F3YXksICJvbmVfYXdheS5jc3YiKQoKICB0d29fYXdheSA8LSBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPT0gMwogIHR3b19hd2F5IDwtIHBvc2l0aW9uX3RhYmxlW3R3b19hd2F5LCBdCiAgd3JpdGUuY3N2KHR3b19hd2F5LCAidHdvX2F3YXkuY3N2IikKCiAgY29tYmluZWQgPC0gcmJpbmQoZG91Ymxlcywgb25lX2F3YXkpCiAgY29tYmluZWQgPC0gcmJpbmQoY29tYmluZWQsIHR3b19hd2F5KQogIHBvc2l0aW9uX2lkeCA8LSBvcmRlcihjb21iaW5lZFssICJjaHIiXSwgY29tYmluZWRbLCAicG9zIl0pCiAgY29tYmluZWQgPC0gY29tYmluZWRbcG9zaXRpb25faWR4LCBdCiAgCiAgdGhpc19jaHIgPC0gIiIKICBmb3IgKHIgaW4gMTpucm93KGNvbWJpbmVkKSkgewogICAgdGhpc19jaHIgPC0gY29tYmluZWRbciwgImNociJdCiAgICBpZiAociA9PSAxKSB7CiAgICAgIGNvbWJpbmVkW3IsICJkaXN0X3BhaXIiXSA8LSBjb21iaW5lZFtyLCAicG9zIl0KICAgICAgbGFzdF9jaHIgPC0gdGhpc19jaHIKICAgICAgbmV4dAogICAgfQogICAgaWYgKHRoaXNfY2hyID09IGxhc3RfY2hyKSB7CiAgICAgIGNvbWJpbmVkW3IsICJkaXN0X3BhaXIiXSA8LSBjb21iaW5lZFtyLCAicG9zIl0gLSBjb21iaW5lZFtyIC0gMSwgInBvcyJdCiAgICB9IGVsc2UgewogICAgICBjb21iaW5lZFtyLCAiZGlzdF9wYWlyIl0gPC0gY29tYmluZWRbciwgInBvcyJdCiAgICB9CiAgICBsYXN0X2NociA8LSB0aGlzX2NocgogIH0KCiAgZGlzdF9wYWlyX21heGltdW0gPC0gMTAwMAogIGRpc3RfcGFpcl9taW5pbXVtIDwtIDIwMAogIGRpc3RfcGFpcl9pZHggPC0gY29tYmluZWRbWyJkaXN0X3BhaXIiXV0gPD0gZGlzdF9wYWlyX21heGltdW0gJgogICAgY29tYmluZWRbWyJkaXN0X3BhaXIiXV0gPj0gZGlzdF9wYWlyX21pbmltdW0KICByZW1haW5pbmcgPC0gY29tYmluZWRbZGlzdF9wYWlyX2lkeCwgXQogIG5vX3dlYWtfaWR4IDwtIGdyZXBsKHBhdHRlcm49InJlZl8oR3xDKSIsIHg9cm93bmFtZXMocmVtYWluaW5nKSkKICByZW1haW5pbmcgPC0gcmVtYWluaW5nW25vX3dlYWtfaWR4LCBdCiAgCiAgcHJpbnQoaGVhZCh0YWJsZShwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0pKSkKICBzZXF1ZW50aWFscyA8LSBwb3NpdGlvbl90YWJsZVtbImRpc3QiXV0gPD0gbWF4aW11bV9zZXBhcmF0aW9uCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIHN1bShzZXF1ZW50aWFscyksICIgY2FuZGlkYXRlIHJlZ2lvbnMuIikKCiAgIyMgVGhlIGZvbGxvd2luZyBjYW4gdGVsbCBtZSBob3cgbWFueSBydW5zIG9mIGVhY2ggbGVuZ3RoIG9jY3VycmVkLCB0aGF0IGlzIG5vdCBxdWl0ZSB3aGF0IEkgd2FudC4KICAjIyBOb3cgdXNlIHJ1biBsZW5ndGggZW5jb2RpbmcgdG8gZmluZCB0aGUgc2V0IG9mIHNlcXVlbnRpYWwgc2VxdWVudGlhbHMhCiAgcmxlX3Jlc3VsdCA8LSBybGUoc2VxdWVudGlhbHMpCiAgcmxlX3ZhbHVlcyA8LSBybGVfcmVzdWx0W1sidmFsdWVzIl1dCiAgIyMgVGhlIGZvbGxvd2luZyBsaW5lIGlzIGVxdWl2YWxlbnQgdG8ganVzdCBsZWF2aW5nIHZhbHVlcyBhbG9uZToKICAjIyB0cnVlX3ZhbHVlcyA8LSBybGVfcmVzdWx0W1sidmFsdWVzIl1dID09IFRSVUUKICBybGVfbGVuZ3RocyA8LSBybGVfcmVzdWx0W1sibGVuZ3RocyJdXQogIHRydWVfc2VxdWVudGlhbHMgPC0gcmxlX2xlbmd0aHNbcmxlX3ZhbHVlc10KICBybGVfaWR4IDwtIGN1bXN1bShybGVfbGVuZ3Rocylbd2hpY2gocmxlX3ZhbHVlcyldCgogIHBvc2l0aW9uX3RhYmxlW1sibGFzdF9zZXF1ZW50aWFsIl1dIDwtIDAKICBjb3VudCA8LSAwCiAgZm9yIChyIGluIHJsZV9pZHgpIHsKICAgIGNvdW50IDwtIGNvdW50ICsgMQogICAgcG9zaXRpb25fdGFibGVbciwgImxhc3Rfc2VxdWVudGlhbCJdIDwtIHRydWVfc2VxdWVudGlhbHNbY291bnRdCiAgfQogIG1lc3NhZ2UoIlRoZSBtYXhpbXVtIHNlcXVlbnRpYWwgc2V0IGlzOiAiLCBtYXgocG9zaXRpb25fdGFibGVbWyJsYXN0X3NlcXVlbnRpYWwiXV0pLCAiLiIpCgogIHdhbnRlZF9pZHggPC0gcG9zaXRpb25fdGFibGVbWyJsYXN0X3NlcXVlbnRpYWwiXV0gPj0gbWluaW11bQogIHdhbnRlZCA8LSBwb3NpdGlvbl90YWJsZVt3YW50ZWRfaWR4LCBjKCJjaHIiLCAicG9zIildCiAgcmV0dXJuKHdhbnRlZCkKfQoKenltbzIyX3NlcXVlbnRpYWxzIDwtIHNlcXVlbnRpYWxfdmFyaWFudHMobmV3X3NldHMsIGNvbmRpdGlvbnMgPSAiMjIiLCBtaW5pbXVtPTEsIG1heGltdW1fc2VwYXJhdGlvbj0yKQpkaW0oenltbzIyX3NlcXVlbnRpYWxzKQojIyA3IGNhbmRpZGF0ZSByZWdpb25zIGZvciB6eW1vZGVtZSAyLjIgLS0gdGh1cyBJIGFtIGJldHRpbmcgdGhhdCB0aGUgcmVmZXJlbmNlIHN0cmFpbiBpcyBhIDIuMgp6eW1vMjNfc2VxdWVudGlhbHMgPC0gc2VxdWVudGlhbF92YXJpYW50cyhuZXdfc2V0cywgY29uZGl0aW9ucyA9ICIyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmltdW0gPSAyLCBtYXhpbXVtX3NlcGFyYXRpb24gPSAyKQpkaW0oenltbzIzX3NlcXVlbnRpYWxzKQojIyBJbiBjb250cmFzdCwgdGhlcmUgYXJlIGxvdHMgKDU4Nykgb2YgaW50ZXJlc3RpbmcgcmVnaW9ucyBmb3IgMi4zIQpgYGAKCiMjIyBFeHRyYWN0IGEgcHJvbWlzaW5nIHJlZ2lvbiBmcm9tIHRoZSBnZW5vbWUKClRoZSBmaXJzdCA0IGNhbmRpZGF0ZSByZWdpb25zIGZyb20gbXkgc2V0IG9mIHJlbWFpbmluZzoKKiBDaHIgICAgICAgUG9zLiAgIERpc3RhbmNlCiogTHBhTDEzLTE1IDIzODQzMyA0NDgKKiBMcGFMMTMtMTggMTQyODQ0IDYxMwoqIExwYUwxMy0yOSA4MzAzNDIgMjUyCiogTHBhTDEzLTMzIDEzMzE1MDcgODQzCgpMZXRzIGRlZmluZSBhIGNvdXBsZSBvZiB0ZXJtczoKKiBUaGlyZDogRWFjaCBvZiB0aGUgNCBhYm92ZSBwb3NpdGlvbnMuCiogU2Vjb25kOiBUaGlyZCAtIERpc3RhbmNlCiogRW5kOiBUaGlyZCArIFByaW1lckxlbgoqIFN0YXJ0OiBTZWNvbmQgLSBQcmltZXJsZW4KCkluIGVhY2ggaW5zdGFuY2UsIHRoZXNlIGFyZSB0aGUgbGFzdCBwb3NpdGlvbnMsIHNvIHdlIHdhbnQgdG8gZ3JhYiB0aHJlZSB0aGluZ3M6CgoqIFRoZSBlbnRpcmUgcmVnaW9uIGZyb20gRW5kIC0+IFN0YXJ0LCB0aGlzIHdheSB3ZSBjYW4gaGF2ZSBhIHF1aWNrIHNhbml0eSBjaGVjay4KKiBTdGFydCAtPiBTZWNvbmQuCiogKFRoaXJkIC0+IEVuZCkgPC0gUmV2ZXJzZSBjb21wbGVtZW50ZWQKCmBgYHtyIGV4dHJhY3RfYnNnZW5vbWUsIGV2YWw9RkFMU0V9CiMjICogTHBhTDEzLTE1IDIzODQzMyA0NDgKZmlyc3RfY2FuZGlkYXRlX2NociA8LSBnZW5vbWVbWyJMcGFMMTNfMTUiXV0KcHJpbWVyX2xlbmd0aCA8LSAyMgphbXBsaWNvbl9sZW5ndGggPC0gNDQ4CmZpcnN0X2NhbmRpZGF0ZV90aGlyZCA8LSAyMzg0MzMKZmlyc3RfY2FuZGlkYXRlX3NlY29uZCA8LSBmaXJzdF9jYW5kaWRhdGVfdGhpcmQgLSBhbXBsaWNvbl9sZW5ndGgKZmlyc3RfY2FuZGlkYXRlX3N0YXJ0IDwtIGZpcnN0X2NhbmRpZGF0ZV9zZWNvbmQgLSBwcmltZXJfbGVuZ3RoCmZpcnN0X2NhbmRpZGF0ZV9lbmQgPC0gZmlyc3RfY2FuZGlkYXRlX3RoaXJkICsgcHJpbWVyX2xlbmd0aApmaXJzdF9jYW5kaWRhdGVfcmVnaW9uIDwtIHN1YnNlcShmaXJzdF9jYW5kaWRhdGVfY2hyLCBmaXJzdF9jYW5kaWRhdGVfc3RhcnQsIGZpcnN0X2NhbmRpZGF0ZV9lbmQpCmZpcnN0X2NhbmRpZGF0ZV9yZWdpb24KZmlyc3RfY2FuZGlkYXRlXzVwIDwtIHN1YnNlcShmaXJzdF9jYW5kaWRhdGVfY2hyLCBmaXJzdF9jYW5kaWRhdGVfc3RhcnQsIGZpcnN0X2NhbmRpZGF0ZV9zZWNvbmQpCmFzLmNoYXJhY3RlcihmaXJzdF9jYW5kaWRhdGVfNXApCmZpcnN0X2NhbmRpZGF0ZV8zcCA8LSBzcGdzOjpyZXZlcnNlQ29tcGxlbWVudChzdWJzZXEoZmlyc3RfY2FuZGlkYXRlX2NociwgZmlyc3RfY2FuZGlkYXRlX3RoaXJkLCBmaXJzdF9jYW5kaWRhdGVfZW5kKSkKZmlyc3RfY2FuZGlkYXRlXzNwCgoKIyMgKiBMcGFMMTMtMTggMTQyODQ0IDYxMwpzZWNvbmRfY2FuZGlkYXRlX2NociA8LSBnZW5vbWVbWyJMcGFMMTNfMTgiXV0KcHJpbWVyX2xlbmd0aCA8LSAyMgphbXBsaWNvbl9sZW5ndGggPC0gNjEzCnNlY29uZF9jYW5kaWRhdGVfdGhpcmQgPC0gMTQyODQ0CnNlY29uZF9jYW5kaWRhdGVfc2Vjb25kIDwtIHNlY29uZF9jYW5kaWRhdGVfdGhpcmQgLSBhbXBsaWNvbl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9zdGFydCA8LSBzZWNvbmRfY2FuZGlkYXRlX3NlY29uZCAtIHByaW1lcl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9lbmQgPC0gc2Vjb25kX2NhbmRpZGF0ZV90aGlyZCArIHByaW1lcl9sZW5ndGgKc2Vjb25kX2NhbmRpZGF0ZV9yZWdpb24gPC0gc3Vic2VxKHNlY29uZF9jYW5kaWRhdGVfY2hyLCBzZWNvbmRfY2FuZGlkYXRlX3N0YXJ0LCBzZWNvbmRfY2FuZGlkYXRlX2VuZCkKc2Vjb25kX2NhbmRpZGF0ZV9yZWdpb24Kc2Vjb25kX2NhbmRpZGF0ZV81cCA8LSBzdWJzZXEoc2Vjb25kX2NhbmRpZGF0ZV9jaHIsIHNlY29uZF9jYW5kaWRhdGVfc3RhcnQsIHNlY29uZF9jYW5kaWRhdGVfc2Vjb25kKQphcy5jaGFyYWN0ZXIoc2Vjb25kX2NhbmRpZGF0ZV81cCkKc2Vjb25kX2NhbmRpZGF0ZV8zcCA8LSBzcGdzOjpyZXZlcnNlQ29tcGxlbWVudChzdWJzZXEoc2Vjb25kX2NhbmRpZGF0ZV9jaHIsIHNlY29uZF9jYW5kaWRhdGVfdGhpcmQsIHNlY29uZF9jYW5kaWRhdGVfZW5kKSkKc2Vjb25kX2NhbmRpZGF0ZV8zcAoKCiMjICogTHBhTDEzLTI5IDgzMDM0MiAyNTIKdGhpcmRfY2FuZGlkYXRlX2NociA8LSBnZW5vbWVbWyJMcGFMMTNfMjkiXV0KcHJpbWVyX2xlbmd0aCA8LSAyMgphbXBsaWNvbl9sZW5ndGggPC0gMjUyCnRoaXJkX2NhbmRpZGF0ZV90aGlyZCA8LSA4MzAzNDIKdGhpcmRfY2FuZGlkYXRlX3NlY29uZCA8LSB0aGlyZF9jYW5kaWRhdGVfdGhpcmQgLSBhbXBsaWNvbl9sZW5ndGgKdGhpcmRfY2FuZGlkYXRlX3N0YXJ0IDwtIHRoaXJkX2NhbmRpZGF0ZV9zZWNvbmQgLSBwcmltZXJfbGVuZ3RoCnRoaXJkX2NhbmRpZGF0ZV9lbmQgPC0gdGhpcmRfY2FuZGlkYXRlX3RoaXJkICsgcHJpbWVyX2xlbmd0aAp0aGlyZF9jYW5kaWRhdGVfcmVnaW9uIDwtIHN1YnNlcSh0aGlyZF9jYW5kaWRhdGVfY2hyLCB0aGlyZF9jYW5kaWRhdGVfc3RhcnQsIHRoaXJkX2NhbmRpZGF0ZV9lbmQpCnRoaXJkX2NhbmRpZGF0ZV9yZWdpb24KdGhpcmRfY2FuZGlkYXRlXzVwIDwtIHN1YnNlcSh0aGlyZF9jYW5kaWRhdGVfY2hyLCB0aGlyZF9jYW5kaWRhdGVfc3RhcnQsIHRoaXJkX2NhbmRpZGF0ZV9zZWNvbmQpCmFzLmNoYXJhY3Rlcih0aGlyZF9jYW5kaWRhdGVfNXApCnRoaXJkX2NhbmRpZGF0ZV8zcCA8LSBzcGdzOjpyZXZlcnNlQ29tcGxlbWVudChzdWJzZXEodGhpcmRfY2FuZGlkYXRlX2NociwgdGhpcmRfY2FuZGlkYXRlX3RoaXJkLCB0aGlyZF9jYW5kaWRhdGVfZW5kKSkKdGhpcmRfY2FuZGlkYXRlXzNwCiMjIFlvdSBhcmUgYSBnYXJiYWdlIHBvbHlweXJpbWlkaW5lIHRyYWN0LgojIyBXaGljaCBpcyBhY3R1YWxseSBpbnRlcmVzdGluZyBpZiB0aGUgbXV0YXRpb25zIG1lc3MgaXQgdXAuCgoKIyMgKiBMcGFMMTMtMzMgMTMzMTUwNyA4NDMKZm91cnRoX2NhbmRpZGF0ZV9jaHIgPC0gZ2Vub21lW1siTHBhTDEzXzMzIl1dCnByaW1lcl9sZW5ndGggPC0gMjIKYW1wbGljb25fbGVuZ3RoIDwtIDg0Mwpmb3VydGhfY2FuZGlkYXRlX3RoaXJkIDwtIDEzMzE1MDcKZm91cnRoX2NhbmRpZGF0ZV9zZWNvbmQgPC0gZm91cnRoX2NhbmRpZGF0ZV90aGlyZCAtIGFtcGxpY29uX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX3N0YXJ0IDwtIGZvdXJ0aF9jYW5kaWRhdGVfc2Vjb25kIC0gcHJpbWVyX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX2VuZCA8LSBmb3VydGhfY2FuZGlkYXRlX3RoaXJkICsgcHJpbWVyX2xlbmd0aApmb3VydGhfY2FuZGlkYXRlX3JlZ2lvbiA8LSBzdWJzZXEoZm91cnRoX2NhbmRpZGF0ZV9jaHIsIGZvdXJ0aF9jYW5kaWRhdGVfc3RhcnQsIGZvdXJ0aF9jYW5kaWRhdGVfZW5kKQpmb3VydGhfY2FuZGlkYXRlX3JlZ2lvbgpmb3VydGhfY2FuZGlkYXRlXzVwIDwtIHN1YnNlcShmb3VydGhfY2FuZGlkYXRlX2NociwgZm91cnRoX2NhbmRpZGF0ZV9zdGFydCwgZm91cnRoX2NhbmRpZGF0ZV9zZWNvbmQpCmFzLmNoYXJhY3Rlcihmb3VydGhfY2FuZGlkYXRlXzVwKQpmb3VydGhfY2FuZGlkYXRlXzNwIDwtIHNwZ3M6OnJldmVyc2VDb21wbGVtZW50KHN1YnNlcShmb3VydGhfY2FuZGlkYXRlX2NociwgZm91cnRoX2NhbmRpZGF0ZV90aGlyZCwgZm91cnRoX2NhbmRpZGF0ZV9lbmQpKQpmb3VydGhfY2FuZGlkYXRlXzNwCmBgYAoKIyMgR28gaHVudGluZyBmb3IgU2FuZ2VyIHNlcXVlbmNpbmcgcmVnaW9ucwoKSSBtYWRlIGEgZnVuIGxpdHRsZSBmdW5jdGlvbiB3aGljaCBzaG91bGQgZmluZCByZWdpb25zIHdoaWNoIGhhdmUgbG90cyBvZiB2YXJpYW50cwphc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBleHBlcmltZW50YWwgZmFjdG9yLgoKYGBge3Igc2FuZ2VyX2Z1biwgZXZhbD1GQUxTRX0KcGhlbm8gPC0gc3Vic2V0X2V4cHQobHBfZXhwdCwgc3Vic2V0ID0gImNvbmRpdGlvbj09J3oyLjInfGNvbmRpdGlvbj09J3oyLjMnIikKcGhlbm8gPC0gc3Vic2V0X2V4cHQocGhlbm8sIHN1YnNldCA9ICIhaXMubmEocERhdGEocGhlbm8pW1snYmNmdGFibGUnXV0pIikKcGhlbm9fc25wcyA8LSBzbShjb3VudF9leHB0X3NucHMocGhlbm8sIGFubm90X2NvbHVtbiA9ICJiY2Z0YWJsZSIpKQoKZnVuX3N0dWZmIDwtIHNucF9kZW5zaXR5X3ByaW1lcnMocGhlbm9fc25wcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnNnZW5vbWU9IkJTR2Vub21lLkxlaXNobWFuaWEucGFuYW1lbnNpcy5NSE9NQ09MODFMMTMudjUzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2ZmPSJyZWZlcmVuY2UvVHJpVHJ5cERCLTUzX0xwYW5hbWVuc2lzTUhPTUNPTDgxTDEzLmdmZiIpCmRyb3Bfc2NhZmZvbGRzIDwtIGdyZXBsKHggPSByb3duYW1lcyhmdW5fc3R1ZmYkZmF2b3JpdGVzKSwgcGF0dGVybiA9ICJTQ0FGIikKZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnMgPC0gZnVuX3N0dWZmW1siZmF2b3JpdGVzIl1dWyFkcm9wX3NjYWZmb2xkcywgXQpmYXZvcml0ZV9wcmltZXJfcmVnaW9uc1tbImJpbiJdXSA8LSByb3duYW1lcyhmYXZvcml0ZV9wcmltZXJfcmVnaW9ucykKbGlicmFyeShkcGx5cikKZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnMgPC0gZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnMgJT4lCiAgcmVsb2NhdGUoYmluKQpgYGAKCiMjIENvbWJpbmUgdGhpcyB0YWJsZSB3aXRoIDIuMi8yLjMgZ2VuZXMKCkhlcmUgaXMgbXkgbm90ZSBmcm9tIG91ciBtZWV0aW5nOgoKQ3Jvc3MgcmVmZXJlbmNlIHByaW1lcnMgdG8gREUgZ2VuZXMgb2YgMi4yLzIuMyBhbmQvb3IgcmVzaXN0YW5jZS9zdXNjcGV0aWJsZSwKYWRkIGEgY29sdW1uIHRvIHRoZSBwcmltZXIgc3ByZWFkc2hlZXQgd2l0aCB0aGUgREUgZ2VuZXMgKGluIHJldHJvc3BlY3QgSSBhbSBndWVzc2luZwp0aGlzIGFjdHVhbGx5IG1lYW5zIHRvIHB1dCB0aGUgbG9nRkMgYXMgYSBjb2x1bW4uCgpPbmUgbmljZSB0aGluZywgSSBkaWQgYSBzZW1hbnRpYyByZW1vdmFsIG9uIHRoZSBscF9leHB0LCBzbyB0aGUgc2V0IG9mIGxvZ0ZDL3B2YWx1ZXMKc2hvdWxkIG5vdCBoYXZlIGFueSBvZiB0aGUgb2ZmZW5kaW5nIHR5cGVzOyB0aHVzIEkgc2hvdWxkIGJlIGFibGUgdG8gYXV0b21hZ2ljYWxseQpnZXQgcmlkIG9mIHRoZW0gaW4gdGhlIG1lcmdlLgoKYGBge3IgeHJlZl9wcmltZXJzX2RlZ30KbG9nZmMgPC0genlfdGFibGVbWyJkYXRhIl1dW1siejIzX3ZzX3oyMiJdXQpsb2dmY19jb2x1bW5zIDwtIGxvZ2ZjWywgYygiZGVzZXFfbG9nZmMiLCAiZGVzZXFfYWRqcCIpXQpjb2xuYW1lcyhsb2dmY19jb2x1bW5zKSA8LSBjKCJ6MjNfbG9nZmMiLCAiejIzX2FkanAiKQpuZXdfdGFibGUgPC0gbWVyZ2UoZmF2b3JpdGVfcHJpbWVyX3JlZ2lvbnMsIGxvZ2ZjX2NvbHVtbnMsCiAgICAgICAgICAgICAgICAgICBieS54ID0gImNsb3Nlc3RfZ2VuZV9iZWZvcmVfaWQiLCBieS55ID0gInJvdy5uYW1lcyIpCnN1cyA8LSBzdXNfdGFibGVbWyJkYXRhIl1dW1sic2Vuc2l0aXZlX3ZzX3Jlc2lzdGFudCJdXQpzdXNfY29sdW1ucyA8LSBzdXNbLCBjKCJkZXNlcV9sb2dmYyIsICJkZXNlcV9hZGpwIildCmNvbG5hbWVzKHN1c19jb2x1bW5zKSA8LSBjKCJzdXNfbG9nZmMiLCAic3VzX2FkanAiKQpuZXdfdGFibGUgPC0gbWVyZ2UobmV3X3RhYmxlLCBzdXNfY29sdW1ucywKICAgICAgICAgICAgICAgICAgIGJ5LnggPSAiY2xvc2VzdF9nZW5lX2JlZm9yZV9pZCIsIGJ5LnkgPSAicm93Lm5hbWVzIikgJT4lCiAgcmVsb2NhdGUoYmluKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1uZXdfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD0iZXhjZWwvZmF2b3JpdGVfcHJpbWVyc194cmVmX3p5X3N1cy4KYGBgCgoKIyMgTWFrZSBhIGhlYXRtYXAgZGVzY3JpYmluZyB0aGUgY2x1c3RlcmluZyBvZiB2YXJpYW50cwoKV2UgY2FuIGNyb3NzIHJlZmVyZW5jZSB0aGUgdmFyaWFudHMgYWdhaW5zdCB0aGUgenltb2RlbWUgc3RhdHVzIGFuZApwbG90IGEgaGVhdG1hcCBvZiB0aGUgcmVzdWx0cyBhbmQgaG9wZWZ1bGx5IHNlZSBob3cgdGhleSBzZXBhcmF0ZS4KCmBgYHtyIHp5bW9faGVhdG1hcHN9CnNucF9nZW5lcyA8LSBzbShzbnBzX3ZzX2dlbmVzKGxwX2V4cHQsIG5ld19zZXRzLCBleHB0X25hbWVfY29sID0gImNocm9tb3NvbWUiKSkKbmV3X3p5bW9fbm9ybSA8LSBub3JtYWxpemVfZXhwdChuZXdfc25wcywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtID0gVFJVRSkKbmV3X3p5bW9fbm9ybSA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG5ld196eW1vX25vcm0sIGZhY3QgPSAicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyIpCgp6eW1vX2hlYXQgPC0gcGxvdF9kaXNoZWF0KG5ld196eW1vX25vcm0pCnp5bW9faGVhdFtbInBsb3QiXV0KYGBgCgojIyMgQW5ub3RhdGVkIGhlYXRtYXAgb2YgdmFyaWFudHMKCk5vdyBsZXQgdXMgdHJ5IHRvIG1ha2UgYSBoZWF0bWFwIHdoaWNoIGluY2x1ZGVzIHNvbWUgb2YgdGhlIGFubm90YXRpb24gZGF0YS4KCmBgYHtyIHp5bW9faGVhdF9wYW5lbF9nZW5lc30KZGVzIDwtIGJvdGhfbm9ybVtbImRlc2lnbiJdXQp1bmRlZl9pZHggPC0gaXMubmEoZGVzW1sic3RyYWluIl1dKQpkZXNbdW5kZWZfaWR4LCAic3RyYWluIl0gPC0gInVua25vd24iCgojI2htY29scyA8LSBjb2xvclJhbXBQYWxldHRlKGMoInllbGxvdyIsImJsYWNrIiwiZGFya2JsdWUiKSkoMjU2KQpjb3JyZWxhdGlvbnMgPC0gaHBnbF9jb3IoZXhwcnMoYm90aF9ub3JtKSkKCnp5bW9fbWlzc2luZ19pZHggPC0gaXMubmEoZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSkKZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1sicGhlbm90eXBpY2NoYXJhY3RlcmlzdGljcyJdXSkKZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA8LSBhcy5jaGFyYWN0ZXIoZGVzW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSkKZGVzW3p5bW9fbWlzc2luZ19pZHgsICJwaGVub3R5cGljY2hhcmFjdGVyaXN0aWNzIl0gPC0gInVua25vd24iCm15ZGVuZHJvIDwtIGxpc3QoCiAgImNsdXN0ZnVuIiA9IGhjbHVzdCwKICAibHdkIiA9IDIuMCkKY29sX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShkZXNbLCBjKCJwaGVub3R5cGljY2hhcmFjdGVyaXN0aWNzIiwgImNsaW5pY2FsY2F0ZWdvcmljYWwiKV0pCgp1bmtub3duX2NsaW5pY2FsIDwtIGlzLm5hKGNvbF9kYXRhW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSkKcm93X2RhdGEgPC0gYXMuZGF0YS5mcmFtZShkZXNbLCBjKCJzdHJhaW4iKV0pCmNvbG5hbWVzKGNvbF9kYXRhKSA8LSBjKCJ6eW1vZGVtZSIsICJvdXRjb21lIikKY29sX2RhdGFbdW5rbm93bl9jbGluaWNhbCwgIm91dGNvbWUiXSA8LSAidW5kZWZpbmVkIgoKY29sbmFtZXMocm93X2RhdGEpIDwtIGMoInN0cmFpbiIpCm15YW5ub3QgPC0gbGlzdCgKICAiQ29sIiA9IGxpc3QoImRhdGEiID0gY29sX2RhdGEpLAogICJSb3ciID0gbGlzdCgiZGF0YSIgPSByb3dfZGF0YSkpCm15Y2x1c3QgPC0gbGlzdCgiY3V0aCIgPSAxLjAsCiAgICAgICAgICAgICAgICAiY29sIiA9IEJyZXdlckNsdXN0ZXJDb2wpCm15bGFicyA8LSBsaXN0KAogICJSb3ciID0gbGlzdCgibnJvdyIgPSA0KSwKICAiQ29sIiA9IGxpc3QoIm5yb3ciID0gNCkpCmhtY29scyA8LSBjb2xvclJhbXBQYWxldHRlKGMoImRhcmtibHVlIiwgImJlaWdlIikpKDI0MCkKbWFwMSA8LSBhbm5IZWF0bWFwMigKICBjb3JyZWxhdGlvbnMsCiAgZGVuZHJvZ3JhbSA9IG15ZGVuZHJvLAogIGFubm90YXRpb24gPSBteWFubm90LAogIGNsdXN0ZXIgPSBteWNsdXN0LAogIGxhYmVscyA9IG15bGFicywKICAjIyBUaGUgZm9sbG93aW5nIGNvbnRyb2xzIGlmIHRoZSBwaWN0dXJlIGlzIHN5bW1ldHJpYwogIHNjYWxlID0gIm5vbmUiLAogIGNvbCA9IGhtY29scykKcHAoZmlsZSA9ICJpbWFnZXMvZGVuZHJvX2hlYXRtYXAucG5nIiwgaW1hZ2UgPSBtYXAxLCBoZWlnaHQgPSAyMCwgd2lkdGggPSAyMCkKYGBgCgpQcmludCB0aGUgbGFyZ2VyIGhlYXRtYXAgc28gdGhhdCBhbGwgdGhlIGxhYmVscyBhcHBlYXIuICBLZWVwIGluIG1pbmQKdGhhdCBhcyB3ZSBnZXQgbW9yZSBzYW1wbGVzLCB0aGlzIGltYWdlIG5lZWRzIHRvIGNvbnRpbnVlIGdldHRpbmcKYmlnZ2VyLgoKIVtiaWcgaGVhdG1hcF0oaW1hZ2VzL2RlbmRyb19oZWF0bWFwLnBuZykKCgpgYGB7ciB0aGVyZXNhX2lkZWF9Cgp4cmVmX3Byb3AgPC0gdGFibGUocGhlbm9fc25wc1tbImNvbmRpdGlvbnMiXV0pCnBoZW5vX3NucHMkY29uZGl0aW9ucwppZHhfdGJsIDwtIGV4cHJzKHBoZW5vX3NucHMpID4gNQpuZXdfdGJsIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzID0gcm93bmFtZXMoZXhwcnMocGhlbm9fc25wcykpKQpmb3IgKG4gaW4gbmFtZXMoeHJlZl9wcm9wKSkgewogIG5ld190YmxbW25dXSA8LSAwCiAgaWR4X2NvbHMgPC0gd2hpY2gocGhlbm9fc25wc1tbImNvbmRpdGlvbnMiXV0gPT0gbikKICBwcm9wX2NvbCA8LSByb3dTdW1zKGlkeF90YmxbLCBpZHhfY29sc10pIC8geHJlZl9wcm9wW25dCiAgbmV3X3RibFtuXSA8LSBwcm9wX2NvbAp9CmtlZXBlcnMgPC0gZ3JlcGwoeCA9IHJvd25hbWVzKG5ld190YmwpLCBwYXR0ZXJuID0gIkxwYUwxMyIpCm5ld190YmwgPC0gbmV3X3RibFtrZWVwZXJzLCBdCm5ld190YmxbWyJzdHJvbmcyMiJdXSA8LSAxLjAwMSAtIG5ld190YmxbWyJ6Mi4yIl1dCm5ld190YmxbWyJzdHJvbmcyMyJdXSA8LSAxLjAwMSAtIG5ld190YmxbWyJ6Mi4zIl1dCnMyMl9uYSA8LSBuZXdfdGJsW1sic3Ryb25nMjIiXV0gPiAxCm5ld190YmxbczIyX25hLCAic3Ryb25nMjIiXSA8LSAxCnMyM19uYSA8LSBuZXdfdGJsW1sic3Ryb25nMjMiXV0gPiAxCm5ld190YmxbczIzX25hLCAic3Ryb25nMjMiXSA8LSAxCgpuZXdfdGJsW1siU05QIl1dIDwtIHJvd25hbWVzKG5ld190YmwpCm5ld190YmxbWyJDaHJvbW9zb21lIl1dIDwtIGdzdWIoeCA9IG5ld190YmxbWyJTTlAiXV0sIHBhdHRlcm4gPSAiY2hyXyguKilfcG9zXy4qIiwgcmVwbGFjZW1lbnQgPSAiXFwxIikKbmV3X3RibFtbIlBvc2l0aW9uIl1dIDwtIGdzdWIoeCA9IG5ld190YmxbWyJTTlAiXV0sIHBhdHRlcm4gPSAiLipfcG9zXyhcXGQrKV8uKiIsIHJlcGxhY2VtZW50ID0gIlxcMSIpCm5ld190YmwgPC0gbmV3X3RibFssIGMoIlNOUCIsICJDaHJvbW9zb21lIiwgIlBvc2l0aW9uIiwgInN0cm9uZzIyIiwgInN0cm9uZzIzIildCgoKbGlicmFyeShDTXBsb3QpCnNpbXBsaWZ5IDwtIG5ld190YmwKc2ltcGxpZnlbWyJzdHJvbmcyMiJdXSA8LSBOVUxMCgoKQ01wbG90KHNpbXBsaWZ5LCBiaW4uc2l6ZSA9IDEwMDAwMCkKCkNNcGxvdChuZXdfdGJsLCBwbG90LnR5cGU9Im0iLCBtdWx0cmFja3M9VFJVRSwgdGhyZXNob2xkID0gYygwLjAxLCAwLjA1KSwKICAgICAgIHRocmVzaG9sZC5sd2Q9YygxLDEpLCB0aHJlc2hvbGQuY29sPWMoImJsYWNrIiwiZ3JleSIpLAogICAgICAgYW1wbGlmeT1UUlVFLCBiaW4uc2l6ZT0xMDAwMCwKICAgICAgIGNoci5kZW4uY29sPWMoImRhcmtncmVlbiIsICJ5ZWxsb3ciLCAicmVkIiksCiAgICAgICBzaWduYWwuY29sPWMoInJlZCIsICJncmVlbiIsICJibHVlIiksCiAgICAgICBzaWduYWwuY2V4PTEsIGZpbGU9ImpwZyIsIG1lbW89IiIsIGRwaT0zMDAsIGZpbGUub3V0cHV0PVRSVUUsIHZlcmJvc2U9VFJVRSkKYGBgCgohW1NOUCBEZW5zaXR5XShTTlAtRGVuc2l0eS5yYXRpby5qcGcpCiFbQ2lyY3VsYXIgTWFuaGF0dGFuXShDaXJjdWxhci1NYW5oYXR0YW4ucmF0aW8uanBnKQohW1JlY3Rhbmd1bGFyIE1hbmhhdHRhbl0oUmVjdGFuZ3VsYXItTWFuaGF0dGFuLnJhdGlvLmpwZykKIVtRUV0oUVFwbG90LnJhdGlvLmpwZykKCiMjIFRyeSBvdXQgTWF0cml4RVFUTAoKVGhpcyB0b29sIGxvb2tzIGEgbGl0dGxlIG9wYXF1ZSwgYnV0IHByb3ZpZGVzIHNhbXBsZSBkYXRhIHdpdGggdGhpbmdzCnRoYXQgbWFrZSBzZW5zZSB0byBtZSBhbmQgc2hvdWxkIGJlIHByZXR0eSBlYXN5IHRvIHJlY2FwaXR1bGF0ZSBpbiBvdXIKZGF0YS4KCjEuICBjb3ZhcmlhdGVzLnR4dDogQ29sdW1ucyBhcmUgc2FtcGxlcywgcm93cyBhcmUgdGhpbmdzIGZyb20gcERhdGEgLS0gdGhlCiAgICBtb3N0IGxpa2VseSBvbmVzIG9mIGludGVyZXN0IGZvciBvdXIgZGF0YSB3b3VsZCBiZSB6eW1vZGVtZSwKICAgIHNlbnNpdGl2aXR5CjIuICBnZW5lbG9jLnR4dDogY29sdW1ucyBhcmUgJ2dlbmVpZCcsICdjaHInLCAnbGVmdCcsICdyaWdodCcuICBJCiAgICBndWVzcyBJIGNhbiBhc3N1bWUgbGVmdCBhbmQgcmlnaHQgYXJlIHN0YXJ0L3N0b3A7IGluIHdoaWNoIGNhc2UKICAgIHRoaXMgaXMgdHJpdmlhbGx5IGFjcXVpcmFibGUgZnJvbSBmRGF0YS4KMy4gIGdlLnR4dDogVGhpcyBhcHBlYXJzIHRvIGJlIGEgbG9nKHJwa20vY3BtKSB0YWJsZSB3aXRoIHJvd3MgYXMgZ2VuZXMgYW5kCiAgICBjb2x1bW5zIGFzIHNhbXBsZXMKNC4gIHNucHNsb2MudHh0OiBjb2x1bW5zIGFyZSAnc25waWQnLCAnY2hyJywgJ3BvcycKNS4gIHNucHMudHh0OiBjb2x1bW5zIGFyZSBzYW1wbGVzLCByb3dzIGFyZSB0aGUgaWRzIGZyb20gc25zcGxvYywKICAgIHZhbHVlcyBhIDAsMSwyLiAgSSBhc3N1bWUgMCBpcyBpZGVudGljYWwgYW5kIDEuLjEyIGFyZSB0aGUgdmFyaW91cwogICAgQS0+VEdDIFQtPkFHQyBDLT5BR1QgRy0+QUNUCgpgYGB7ciBtYXRyaXhlcXRsLCBldmFsPUZBTFNFfQojIyBGb3IgdGhpcywgbGV0IHVzIHVzZSB0aGUgJ25ld19zbnBzJyBkYXRhIHN0cnVjdHVyZS4KIyMgQ2F2ZWF0IGhlcmU6IHRoZXNlIG5lZWQgdG8gYmUgY29lcmNlZCB0byBudW1iZXJzLgpteV9jb3ZhcmlhdGVzIDwtIHBEYXRhKG5ld19zbnBzKVssIGMoInBoZW5vdHlwaWNjaGFyYWN0ZXJpc3RpY3MiLCAiY2xpbmljYWxjYXRlZ29yaWNhbCIpXQpmb3IgKGNvbCBpbiBjb2xuYW1lcyhteV9jb3ZhcmlhdGVzKSkgewogIG15X2NvdmFyaWF0ZXNbW2NvbF1dIDwtIGFzLm51bWVyaWMoYXMuZmFjdG9yKG15X2NvdmFyaWF0ZXNbW2NvbF1dKSkKfQpteV9jb3ZhcmlhdGVzIDwtIHQobXlfY292YXJpYXRlcykKCm15X2dlbmVsb2MgPC0gZkRhdGEobHBfZXhwdClbLCBjKCJnaWQiLCAiY2hyb21vc29tZSIsICJzdGFydCIsICJlbmQiKV0KY29sbmFtZXMobXlfZ2VuZWxvYykgPC0gYygiZ2VuZWlkIiwgImNociIsICJsZWZ0IiwgInJpZ2h0IikKCm15X2dlIDwtIGV4cHJzKG5vcm1hbGl6ZV9leHB0KGxwX2V4cHQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iKSkKdXNlZF9zYW1wbGVzIDwtIHRvbG93ZXIoY29sbmFtZXMobXlfZ2UpKSAlaW4lIGNvbG5hbWVzKGV4cHJzKG5ld19zbnBzKSkKbXlfZ2UgPC0gbXlfZ2VbLCB1c2VkX3NhbXBsZXNdCgpteV9zbnBzbG9jIDwtIGRhdGEuZnJhbWUocm93bmFtZXMgPSByb3duYW1lcyhleHBycyhuZXdfc25wcykpKQojIyBPaCwgY2F2ZWF0IGhlcmU6IEJlY2F1c2Ugb2YgdGhlIHdheSBJIHN0b3JlZCB0aGUgZGF0YSwKIyMgSSBjb3VsZCBoYXZlIGR1cGxpY2F0ZSByb3dzIHdoaWNoIHByZXN1bWFibHkgd2lsbCBtYWtlIG1hdHJpeEVRVEwgc2FkCm15X3NucHNsb2NbWyJjaHIiXV0gPC0gZ3N1YihwYXR0ZXJuID0gIl5jaHJfKC4rKV9wb3MoLispX3JlZl8uKiQiLCByZXBsYWNlbWVudCA9ICJcXDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHJvd25hbWVzKG15X3NucHNsb2MpKQpteV9zbnBzbG9jW1sicG9zIl1dIDwtIGdzdWIocGF0dGVybiA9ICJeY2hyXyguKylfcG9zKC4rKV9yZWZfLiokIiwgcmVwbGFjZW1lbnQgPSAiXFwyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSByb3duYW1lcyhteV9zbnBzbG9jKSkKdGVzdCA8LSBkdXBsaWNhdGVkKG15X3NucHNsb2MpCiMjIEVhY2ggZHVwbGljYXRlZCByb3cgd291bGQgYmUgYW5vdGhlciB2YXJpYW50IGF0IHRoYXQgcG9zaXRpb247CiMjIHNvIGluIHRoZW9yeSB3ZSB3b3VsZCBkbyBhIHJsZSB0byBudW1iZXIgdGhlbSBJIGFtIGd1ZXNzaW5nCiMjIEhvd2V2ZXIsIEkgZG8gbm90IGhhdmUgZGlmZmVyZW50IHZhcmlhbnRzIHNvIEkgdGhpbmsgSSBjYW4gaWdub3JlIHRoaXMgZm9yIHRoZSBtb21lbnQKIyMgYnV0IHdpbGwgbmVlZCB0byBtYWtlIG15IG1hdHJpeCBlaXRoZXIgMCBvciAxLgppZiAoc3VtKHRlc3QpID4gMCkgewogIG1lc3NhZ2UoIlRoZXJlIGFyZTogIiwgc3VtKGR1cGxpY2F0ZWQpLCAiIGR1cGxpY2F0ZWQgZW50cmllcy4iKQogIGtlZXBfaWR4IDwtICEgdGVzdAogIG15X3NucHNsb2MgPC0gbXlfc25wc2xvY1trZWVwX2lkeCwgXQp9CgpteV9zbnBzIDwtIGV4cHJzKG5ld19zbnBzKQpvbmVfaWR4IDwtIG15X3NucHMgPiAwCm15X3NucHNbb25lX2lkeF0gPC0gMQoKIyMgT2ssIGF0IHRoaXMgcG9pbnQgSSB0aGluayBJIGhhdmUgYWxsIHRoZSBwaWVjZXMgd2hpY2ggdGhpcyBtZXRob2Qgd2FudHMuLi4KIyMgT2gsIG5vIEkgZ3Vlc3Mgbm90OyBpdCBhY3R1YWxseSB3YW50cyB0aGUgZGF0YSBhcyBhIHNldCBvZiBmaWxlbmFtZXMuLi4KbGlicmFyeShNYXRyaXhFUVRMKQp3cml0ZS50YWJsZShteV9zbnBzLCAiZXF0bC9zbnBzLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KG15X3NucHMsICJlcXRsL3NucHMudHN2IiwgKQp3cml0ZS50YWJsZShteV9zbnBzbG9jLCAiZXF0bC9zbnBzbG9jLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KG15X3NucHNsb2MsICJlcXRsL3NucHNsb2MudHN2IikKd3JpdGUudGFibGUoYXMuZGF0YS5mcmFtZShteV9nZSksICJlcXRsL2dlLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KGFzLmRhdGEuZnJhbWUobXlfZ2UpLCAiZXF0bC9nZS50c3YiKQp3cml0ZS50YWJsZShhcy5kYXRhLmZyYW1lKG15X2dlbmVsb2MpLCAiZXF0bC9nZW5lbG9jLnRzdiIsIG5hID0gIk5BIiwgY29sLm5hbWVzID0gVFJVRSwgcm93Lm5hbWVzID0gVFJVRSwgc2VwID0gIlx0IiwgcXVvdGUgPSBUUlVFKQojIyByZWFkcjo6d3JpdGVfdHN2KGFzLmRhdGEuZnJhbWUobXlfZ2VuZWxvYyksICJlcXRsL2dlbmVsb2MudHN2IikKd3JpdGUudGFibGUoYXMuZGF0YS5mcmFtZShteV9jb3ZhcmlhdGVzKSwgImVxdGwvY292YXJpYXRlcy50c3YiLCBuYSA9ICJOQSIsIGNvbC5uYW1lcyA9IFRSVUUsIHJvdy5uYW1lcyA9IFRSVUUsIHNlcCA9ICJcdCIsIHF1b3RlID0gVFJVRSkKIyMgcmVhZHI6OndyaXRlX3Rzdihhcy5kYXRhLmZyYW1lKG15X2NvdmFyaWF0ZXMpLCAiZXF0bC9jb3ZhcmlhdGVzLnRzdiIpCgp1c2VNb2RlbCA9IG1vZGVsTElORUFSICMgbW9kZWxBTk9WQSwgbW9kZWxMSU5FQVIsIG9yIG1vZGVsTElORUFSX0NST1NTCgojIEdlbm90eXBlIGZpbGUgbmFtZQpTTlBfZmlsZV9uYW1lID0gImVxdGwvc25wcy50c3YiCnNucHNfbG9jYXRpb25fZmlsZV9uYW1lID0gImVxdGwvc25wc2xvYy50c3YiCmV4cHJlc3Npb25fZmlsZV9uYW1lID0gImVxdGwvZ2UudHN2IgpnZW5lX2xvY2F0aW9uX2ZpbGVfbmFtZSA9ICJlcXRsL2dlbmVsb2MudHN2Igpjb3ZhcmlhdGVzX2ZpbGVfbmFtZSA9ICJlcXRsL2NvdmFyaWF0ZXMudHN2IgojIE91dHB1dCBmaWxlIG5hbWUKb3V0cHV0X2ZpbGVfbmFtZV9jaXMgPSB0ZW1wZmlsZSgpCm91dHB1dF9maWxlX25hbWVfdHJhID0gdGVtcGZpbGUoKQojIE9ubHkgYXNzb2NpYXRpb25zIHNpZ25pZmljYW50IGF0IHRoaXMgbGV2ZWwgd2lsbCBiZSBzYXZlZApwdk91dHB1dFRocmVzaG9sZF9jaXMgPSAwLjEKcHZPdXRwdXRUaHJlc2hvbGRfdHJhID0gMC4xCiMgRXJyb3IgY292YXJpYW5jZSBtYXRyaXgKIyBTZXQgdG8gbnVtZXJpYygpIGZvciBpZGVudGl0eS4KZXJyb3JDb3ZhcmlhbmNlID0gbnVtZXJpYygpCiMgZXJyb3JDb3ZhcmlhbmNlID0gcmVhZC50YWJsZSgiU2FtcGxlX0RhdGEvZXJyb3JDb3ZhcmlhbmNlLnR4dCIpOwojIERpc3RhbmNlIGZvciBsb2NhbCBnZW5lLVNOUCBwYWlycwpjaXNEaXN0ID0gMWU2CiMjIExvYWQgZ2Vub3R5cGUgZGF0YQpzbnBzID0gU2xpY2VkRGF0YSRuZXcoKQpzbnBzJGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpzbnBzJGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CnNucHMkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpzbnBzJGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKc25wcyRmaWxlU2xpY2VTaXplID0gMjAwMCAgICAgICMgcmVhZCBmaWxlIGluIHNsaWNlcyBvZiAyLDAwMCByb3dzCnNucHMkTG9hZEZpbGUoU05QX2ZpbGVfbmFtZSkKIyMgTG9hZCBnZW5lIGV4cHJlc3Npb24gZGF0YQpnZW5lID0gU2xpY2VkRGF0YSRuZXcoKQpnZW5lJGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpnZW5lJGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CmdlbmUkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpnZW5lJGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKZ2VuZSRmaWxlU2xpY2VTaXplID0gMjAwMCAgICAgICMgcmVhZCBmaWxlIGluIHNsaWNlcyBvZiAyLDAwMCByb3dzCmdlbmUkTG9hZEZpbGUoZXhwcmVzc2lvbl9maWxlX25hbWUpCiMjIExvYWQgY292YXJpYXRlcwpjdnJ0ID0gU2xpY2VkRGF0YSRuZXcoKQpjdnJ0JGZpbGVEZWxpbWl0ZXIgPSAiXHQiICAgICAgIyB0aGUgVEFCIGNoYXJhY3RlcgpjdnJ0JGZpbGVPbWl0Q2hhcmFjdGVycyA9ICJOQSIgIyBkZW5vdGUgbWlzc2luZyB2YWx1ZXM7CmN2cnQkZmlsZVNraXBSb3dzID0gMSAgICAgICAgICAjIG9uZSByb3cgb2YgY29sdW1uIGxhYmVscwpjdnJ0JGZpbGVTa2lwQ29sdW1ucyA9IDEgICAgICAgIyBvbmUgY29sdW1uIG9mIHJvdyBsYWJlbHMKaWYobGVuZ3RoKGNvdmFyaWF0ZXNfZmlsZV9uYW1lKSA+IDApIHsKICBjdnJ0JExvYWRGaWxlKGNvdmFyaWF0ZXNfZmlsZV9uYW1lKQp9CiMjIFJ1biB0aGUgYW5hbHlzaXMKc25wc3BvcyA9IHJlYWQudGFibGUoc25wc19sb2NhdGlvbl9maWxlX25hbWUsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKZ2VuZXBvcyA9IHJlYWQudGFibGUoZ2VuZV9sb2NhdGlvbl9maWxlX25hbWUsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCm1lID0gTWF0cml4X2VRVExfbWFpbigKICAgIHNucHMgPSBzbnBzLAogICAgZ2VuZSA9IGdlbmUsCiAgICBjdnJ0ID0gY3ZydCwKICAgIG91dHB1dF9maWxlX25hbWUgPSBvdXRwdXRfZmlsZV9uYW1lX3RyYSwKICAgIHB2T3V0cHV0VGhyZXNob2xkID0gcHZPdXRwdXRUaHJlc2hvbGRfdHJhLAogICAgdXNlTW9kZWwgPSB1c2VNb2RlbCwKICAgIGVycm9yQ292YXJpYW5jZSA9IGVycm9yQ292YXJpYW5jZSwKICAgIHZlcmJvc2UgPSBUUlVFLAogICAgb3V0cHV0X2ZpbGVfbmFtZS5jaXMgPSBvdXRwdXRfZmlsZV9uYW1lX2NpcywKICAgIHB2T3V0cHV0VGhyZXNob2xkLmNpcyA9IHB2T3V0cHV0VGhyZXNob2xkX2NpcywKICAgIHNucHNwb3MgPSBzbnBzcG9zLAogICAgZ2VuZXBvcyA9IGdlbmVwb3MsCiAgICBjaXNEaXN0ID0gY2lzRGlzdCwKICAgIHB2YWx1ZS5oaXN0ID0gInFxcGxvdCIsCiAgICBtaW4ucHYuYnkuZ2VuZXNucCA9IEZBTFNFLAogICAgbm9GRFJzYXZlTWVtb3J5ID0gRkFMU0UpOwpgYGAKCgoKYGBge3Igc2F2ZW1lfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkpCn0KYGBgCgpgYGB7ciBsb2FkbWVfYWZ0ZXIsIGV2YWwgPSBGQUxTRX0KdG1wIDwtIGxvYWRtZShmaWxlbmFtZSA9IHNhdmVmaWxlKQpgYGAK