1 TODO

  1. Have a set where we merge 2.1/2.2, 2.3/2.4.
  2. Represent the transition from a global view of the samples without any classification, then state the subpopulations/zymodemes, then add sensitivity/resistance, then cure/fail.
  3. Perhaps make an explicit plot where all samples are one color excepting a relatively small number of previously assayed set? The samples which would be colored in this view would be from Olga’s 2014 paper I think.
  4. Make a flow diagram going from s/r -> subpopulation -> c/f/u. (sankey)
  5. Make a table similar to the TMRC3 containing the statuses of the samples.
  6. Explicitly consider metadata column ‘P’ for reference strains – make an all grey plot with a few samples colored taken from this column.

2 Changelog

2.1 20230524/20230628

  • Frozen metadata, now using sample sheet ‘ClinicalStrains_TMRC2_Frozen 21062023.xlsx’

2.2 20230410

  • Updating the version number due to some moderately intrusive changes I made in order to more carefully create plots of the differential expresison data. I don’t think anything I did should actually change any of the data, but some of the analyses are definitely affected (note that the only change in results is due to a mistake I made in defining one of the contrasts, all other changes are just plot aesthetic improvements)

2.3 20230205

  • Did the stuff on this morning’s TODO which came out of this morning’s meeting: do a PCA without the oddball strains (already done in the worksheet), highlight reference strains, and add L.major IDs and Descriptions (done by appending a collapsed version of the ortholog data to the all_lp_annot data).

  • Fixed human IDs for the macrophage data.

  • Changed input metadata sheets: primarily because I only remembered yesterday to finish the SL search for samples >TMRC20095. They are running now and will be added momentarily (I will have to redownload the sheet).

  • Setting up to make a hclust/phylogenetic tree of strains, use these are reference: 2168(2.3), 2272(2.2), for other 2.x choose arbitrarily (lower numbers are better).

  • Added another sanitize columns call for Antimony vs. antimony and None vs. none in the TMRC2 macrophage samples.

3 Introduction

This document is intended to create the data structures used to evaluate our TMRC2 samples. 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.
  5. The freebayes variant estimation tool was used in addition to #4 to search for variant positions in a more robust fashion.
  6. The trimmed reads were passed to kraken2 using a viral database in order to look for samples with potential LRV sequence.
  7. An explicit, grep-based search for spliced leader reads was used against all human-derived samples. The results from this were copy/pasted into the sample sheet.

4 Notes 20221206 meeting

I am thinking that this meeting will bring Maria Adelaida fully back into the analyses of the parasite data, and therefore may focus primarily on the goals rather than the analyses?

  • Maria Adelaida meeting with Olgla/Mariana: integrating transcriptomics/genomics question.
  • Paper on relationship btwn primary metadata factors via transcriptome/genome.
  • Second on drug susceptibility without those factors (I think this means the macrophages)
  • Definition of species? MAG: Define consensus sequences for various strains/species. We effectively have this on hand, though the quality may be a little less good for 2.3.
  • Resulting goal: Create a tree of the strains (I am just going to call zymodemes strains from now on). ** What organisms would we include in a tree to describe these relationships: guyanensis, braziliensis 2904, 2.2, 2.3, 2.1, 2.4, panamensis reference, peruviania(sp? I have not seen this genome), panama, 2903; actually this may be tricky because we have always done this with a specific reference strain (panamensis col) which is one of the strains in the comparison. hmm… ** Check the most variant strains for identity (Luc) ** Methods for creating tree, traditional phylogeny vs. variant hclust?
  • PCR queries, works well if one performs sanger sequencing.

4.1 Multiple datasets

In a couple of important ways the TMRC2 data is much more complex than the TMRC3:

  1. It comprises multiple, completely separate queries:
    1. Sequencing the parasite samples
    2. Sequencing a set of human macrophage samples which were infected with specific parasite samples.
  2. The parasite transcriptomic samples comprise multiple different types of queries:
    1. Differential expression to look at strain, susceptibility, and clinical outcomes.
    2. Individual variant searches to look for potentially useful SNPs for classification of parasite samples.
  3. The human macrophage samples may be used to query both the host and parasite transcriptomes because (at least when not drug treated) there is a tremendous population of parasite reads in them.

4.2 Sample sheet(s)

Our shared online sample sheet is nearly static at the time of this writing (202209), I expect at this point the only likely updates will be to annotate some strains as more or less susceptible to drug treatment.

sample_sheet <- "sample_sheets/ClinicalStrains_TMRC2.xlsx"
macrophage_sheet <- "sample_sheets/tmrc2_macrophage_samples.xlsx"

4.2.1 Modify the sample sheet

The following block provides an example invocation of how I automatically extract things like percent reads mapped/trimmed/etc from the logs produced by trimomatic/cutadapt/hisat/salmon/etc. The caveat is that this container only has a small portion of the material available in the main working tree, as a result the new columns added to the sample sheet are relatively sparse compared to what I get on my computer.

In addition, because these samples have gone through ~ 3 different versions of my pipeline, and the code which extracts the numbers explicitly assumes only the most recent version (because it is the best!), it does not get out the data for all the samples.

modified <- gather_preprocessing_metadata(sample_sheet, species = "lpanamensis_v36")
## Writing new metadata to: sample_sheets/ClinicalStrains_TMRC2_modified.xlsx

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

The same database of annotations also provides mappings to the set of annotated GO categories for the L.panamensis genome along with gene lengths.

## meta <- download_eupath_metadata(webservice = "tritrypdb", eu_version = "v46")
meta <- download_eupath_metadata(webservice = "tritrypdb")
## Error in download_eupath_metadata(webservice = "tritrypdb"): could not find function "download_eupath_metadata"
panamensis_entry <- get_eupath_entry("MHOM", metadata = meta[["valid"]])
## Error in get_eupath_entry("MHOM", metadata = meta[["valid"]]): could not find function "get_eupath_entry"
panamensis_db <- make_eupath_orgdb(panamensis_entry)
## Error in make_eupath_orgdb(panamensis_entry): could not find function "make_eupath_orgdb"
panamensis_pkg <- panamensis_db[["pkgname"]]
## Error in eval(expr, envir, enclos): object 'panamensis_db' not found
package_name <- panamensis_db[["pkgname"]]
## Error in eval(expr, envir, enclos): object 'panamensis_db' not found
if (is.null(panamensis_pkg)) {
  panamensis_pkg <- panamensis_db[["orgdb_name"]]
  package_name <- panamensis_pkg
}
## Error in eval(expr, envir, enclos): object 'panamensis_pkg' not found
tt <- library(panamensis_pkg, character.only = TRUE)
## Error in eval(expr, envir, enclos): object 'panamensis_pkg' not found
panamensis_pkg <- get0(panamensis_pkg)
## Error in eval(expr, envir, enclos): object 'panamensis_pkg' not found
all_fields <- columns(panamensis_pkg)
## Error in columns(panamensis_pkg): could not find function "columns"
all_lp_annot <- sm(load_orgdb_annotations(
    panamensis_pkg,
    keytype = "gid",
    fields = c("annot_gene_entrez_id", "annot_gene_name",
               "annot_strand", "annot_chromosome", "annot_cds_length",
               "annot_gene_product")))$genes
## Error in eval(expr, envir, enclos): object 'panamensis_pkg' not found
lp_go <- load_orgdb_go(package_name)
## Error in eval(expr, envir, enclos): object 'package_name' not found
lp_go <- lp_go[, c("GID", "GO")]
## Error in eval(expr, envir, enclos): object 'lp_go' not found
lp_lengths <- all_lp_annot[, c("gid", "annot_cds_length")]
## Error in eval(expr, envir, enclos): object 'all_lp_annot' not found
colnames(lp_lengths)  <- c("ID", "length")
## Error: object 'lp_lengths' not found
all_lp_annot[["annot_gene_product"]] <- tolower(all_lp_annot[["annot_gene_product"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'tolower': object 'all_lp_annot' not found
orthos <- sm(extract_eupath_orthologs(db = panamensis_pkg))
## Error in extract_eupath_orthologs(db = panamensis_pkg): could not find function "extract_eupath_orthologs"
data_structures <- c(data_structures, "lp_lengths", "lp_go", "all_lp_annot", "meta")

5.1 Repeat for the L.major annotations

Recently there was a request to include the Leishmania major gene IDs and descriptions. Thus I will extract them along with the orthologs and append that to the annotations used.

Having spent the time to run the following code, I realized that the orthologs data structure above actually already has the gene IDs and descriptions.

Thus I will leave my query in place to extract the major annotations, but follow it up with a collapse of the major orthologs and appending of that to the panamensis annotations.

orgdb <- "org.Lmajor.Friedlin.v49.eg.db"
tt <- sm(library(orgdb, character.only = TRUE))
major_db <- org.Lmajor.Friedlin.v49.eg.db
all_fields <- columns(pan_db)
all_lm_annot <- sm(load_orgdb_annotations(
    major_db,
    keytype = "gid",
    fields = c("annot_gene_entrez_id", "annot_gene_name",
               "annot_strand", "annot_chromosome", "annot_cds_length",
               "annot_gene_product")))$genes

wanted_orthos_idx <- orthos[["ORTHOLOGS_SPECIES"]] == "Leishmania major strain Friedlin"
sum(wanted_orthos_idx)
wanted_orthos <- orthos[wanted_orthos_idx, ]
wanted_orthos <- wanted_orthos[, c("GID", "ORTHOLOGS_ID", "ORTHOLOGS_NAME")]

collapsed_orthos <- wanted_orthos %>%
  group_by(GID) %>%
  summarise(collapsed_id = stringr::str_c(ORTHOLOGS_ID, collapse = " ; "),
            collapsed_name = stringr::str_c(ORTHOLOGS_NAME, collapse = " ; "))
all_lp_annot <- merge(all_lp_annot, collapsed_orthos, by.x = "row.names",
                      by.y = "GID", all.x = TRUE)
rownames(all_lp_annot) <- all_lp_annot[["Row.names"]]
all_lp_annot[["Row.names"]] <- NULL
data_structures <- c(data_structures, "lp_lengths", "lp_go", "all_lp_annot")

6 Load a genome

The following block loads the full genome sequence for panamensis. We may use this later to attempt to estimate PCR primers to discern strains.

I am not sure how to increase the number of open files in a container, as a result this does not work.

## testing_panamensis <- make_eupath_bsgenome(entry = panamensis_entry, eu_version = "v46")
testing_panamensis <- make_eupath_bsgenome(entry = panamensis_entry)
library(as.character(testing_panamensis), character.only = TRUE)
lp_genome <- get0(as.character(testing_panamensis))
data_structures <- c(data_structures, "lp_genome", "meta")

7 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(or summarizedExperiment) 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.

7.1 Notes

The following samples are much lower coverage:

  • TMRC20002
  • TMRC20006
  • TMRC20007
  • TMRC20008

There is a set of strains which acquired resistance in vitro. These are included in the dataset, but there are not likely enough of them to query that question explicitly.

7.2 Define colors

The following list contains the colors we have chosen to use when plotting the various ways of discerning the data.

color_choices <- list(
    "strain" = list(
        ## "z1.0" = "#333333", ## Changed this to 'braz' to make it easier to find them.
        "z2.0" = "#555555",
        "z3.0" = "#777777",
        "z2.1" = "#874400",
        "z2.2" = "#0000cc",
        "z2.3" = "#cc0000",
        "z2.4" = "#df7000",
        "z3.2" = "#888888",
        "z1.0" = "#cc00cc",
        "z1.5" = "#cc00cc",
        "b2904" = "#cc00cc",
        "unknown" = "#cbcbcb"),
    ## "null" = "#000000"),
    "zymo" = list(
      "z22" = "#0000cc",
      "z23" = "#cc0000"),
    "cf" = list(
        "cure" = "#006f00",
        "fail" = "#9dffa0",
        "unknown" = "#cbcbcb",
        "notapplicable" = "#000000"),
    "susceptibility" = list(
        "resistant" = "#8563a7",
        "sensitive" = "#8d0000",
        "ambiguous" = "#cbcbcb",
        "unknown" = "#555555"))
data_structures <- c(data_structures, "color_choices")

8 Parasite-only data structure

The data structure ‘lp_expt’ contains the data for all samples which have hisat2 count tables, and which pass a few initial quality tests (e.g. they must have more than 8550 genes with >0 counts and >5e6 reads which mapped to a gene); genes which are annotated with a few key redundant categories (leishmanolysin for example) are also culled.

8.1 All (almost) samples

There are a few metadata columns which we really want to make certain are standardized.

Note: I changed this to print both the number of reads and genes for removed samples.

sanitize_columns <- c("passagenumber", "clinicalresponse", "clinicalcategorical",
                      "zymodemecategorical", "included")
lp_expt <- create_expt(sample_sheet,
                       gene_info = all_lp_annot,
                       annotation_name = package_name,
                       savefile = glue("rda/tmrc2_lp_expt_all_raw-v{ver}.rda"),
                       id_column = "hpglidentifier",
                       annotation = package_name, ## this is redundantredundant
                       file_column = "lpanamensisv36hisatfile") %>%
  set_expt_conditions(fact = "zymodemecategorical", colors = color_choices[["strain"]]) %>%
  semantic_expt_filter(semantic = c("amastin", "gp63", "leishmanolysin"),
                       semantic_column = "annot_gene_product") %>%
  sanitize_expt_pData(columns = sanitize_columns) %>%
  subset_expt(subset = "included=='yes'") %>%
  set_expt_factors(columns = sanitize_columns, class = "factor")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'exprs': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'package_name' not found
data_structures <- c(data_structures, "lp_expt")
save(list = "lp_expt", file = glue("rda/tmrc2_lp_expt_all_sanitized-v{ver}.rda"))
## Error in save(list = "lp_expt", file = glue("rda/tmrc2_lp_expt_all_sanitized-v{ver}.rda")): object 'lp_expt' not found
table(pData(lp_expt)[["zymodemecategorical"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
table(pData(lp_expt)[["clinicalresponse"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
table(pData(lp_expt)[["clinicalcategorical"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
ncol(exprs(lp_expt))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'ncol': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_expt' not found

8.3 Extract samples from only the two ‘canonical’ strains

8.3.1 Quick divergence

Here is a table of my current classifier’s interpretation of the strains.

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

8.3.2 Merge 2.1/2.2 and 2.4/2.3

merged_zymo <- lp_expt
## Error in eval(expr, envir, enclos): object 'lp_expt' not found
pData(merged_zymo)[["zymodeme"]] <- as.character(pData(merged_zymo)[["zymodemecategorical"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'merged_zymo' not found
z21_idx <- pData(merged_zymo)[["zymodeme"]] == "z21"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'merged_zymo' not found
pData(merged_zymo)[z21_idx, "zymodeme"] <- "z22"
## Error: object 'merged_zymo' not found
z24_idx <- pData(merged_zymo)[["zymodeme"]] == "z24"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'merged_zymo' not found
pData(merged_zymo)[z24_idx, "zymodeme"] <- "z23"
## Error: object 'merged_zymo' not found
keepers <- pData(merged_zymo)[["zymodeme"]] == "z22" |
  pData(merged_zymo)[["zymodeme"]] == "z23"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'merged_zymo' not found
merged_zymo <- merged_zymo[, keepers] %>%
  set_expt_conditions(fact = "zymodeme", colors = color_choices[["zymo"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'merged_zymo' not found

9 Add library sizes before filtering

table(pData(lp_expt)[["clinicalcategorical"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
unknown_ids <- pData(lp_expt)[["clinicalcategorical"]] == "unknown"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
rownames(pData(lp_expt))[unknown_ids]
## 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 'pData': object 'lp_expt' not found
failed_ids <- pData(lp_expt)[["clinicalcategorical"]] == "fail"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
rownames(pData(lp_expt))[failed_ids]
## 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 'pData': object 'lp_expt' not found
pre_libsize <- plot_libsize(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_libsize': object 'lp_expt' not found
pre_libsize
## Error in eval(expr, envir, enclos): object 'pre_libsize' not found
pdf(file = "figures/library_size_pre_filter.pdf", width = 24, height = 12)
## Error in pdf(file = "figures/library_size_pre_filter.pdf", width = 24, : cannot open file 'figures/library_size_pre_filter.pdf'
pre_libsize$plot
## Error in eval(expr, envir, enclos): object 'pre_libsize' not found
dev.off()
## null device 
##           1
pre_nonzero <- plot_nonzero(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_nonzero': object 'lp_expt' not found
pre_nonzero
## Error in eval(expr, envir, enclos): object 'pre_nonzero' not found
pdf(file = "figures/nonzero_pre_filter.pdf")
## Error in pdf(file = "figures/nonzero_pre_filter.pdf"): cannot open file 'figures/nonzero_pre_filter.pdf'
pre_nonzero$plot
## Error in eval(expr, envir, enclos): object 'pre_nonzero' not found
dev.off()
## null device 
##           1
lp_expt_pre <- lp_expt
## Error in eval(expr, envir, enclos): object 'lp_expt' not found
lp_expt <- subset_expt(lp_expt, nonzero = 8550)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_expt' not found
post_nonzero <- plot_nonzero(lp_expt)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'data' in selecting a method for function 'plot_nonzero': object 'lp_expt' not found
post_nonzero
## Error in eval(expr, envir, enclos): object 'post_nonzero' not found

9.1 Extract historical susceptibility data

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

Note that these cutoffs are only valid for the historical data. The newer susceptibility data uses a cutoff of 0.78 for sensitive. I will set ambiguous to 0.5 to 0.78?

max_resist_historical <- 0.35
min_sensitive_historical <- 0.49

## 202305: Removed ambiguous category for the current set.
max_resist_current <- 0.77
min_sensitive_current <- 0.77

The sanitize_percent() function seeks to make the percentage values recorded by excel more reliable. Unfortunately, sometimes excel displays the value ‘49%’ when the information recorded in the worksheet is any one of the following:

  • ’49%
  • 0.49
  • “0.49”

Thus, the following block will sanitize these percentage values into a single decimal number and make a categorical variable from it using pre-defined values for resistant/ambiguous/sensitive. This categorical variable will be stored in a new column: ‘sus_category_historical’.

st <- pData(lp_expt)[["susceptibilityinfectionreduction32ugmlsbvhistoricaldata"]]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
starting <- sanitize_percent(st)
## Error in eval(expr, envir, enclos): object 'st' not found
st
## Error in eval(expr, envir, enclos): object 'st' not found
starting
## Error in eval(expr, envir, enclos): object 'starting' not found
sus_categorical <- starting
## Error in eval(expr, envir, enclos): object 'starting' not found
na_idx <- is.na(starting)
## Error in eval(expr, envir, enclos): object 'starting' not found
sum(na_idx)
## Error in eval(expr, envir, enclos): object 'na_idx' not found
sus_categorical[na_idx] <- "unknown"
## Error: object 'sus_categorical' not found
resist_idx <- starting <= max_resist_historical
## Error in eval(expr, envir, enclos): object 'starting' not found
sus_categorical[resist_idx] <- "resistant"
## Error: object 'sus_categorical' not found
indeterminant_idx <- starting > max_resist_historical &
  starting < min_sensitive_historical
## Error in eval(expr, envir, enclos): object 'starting' not found
sus_categorical[indeterminant_idx] <- "ambiguous"
## Error: object 'sus_categorical' not found
susceptible_idx <- starting >= min_sensitive_historical
## Error in eval(expr, envir, enclos): object 'starting' not found
sus_categorical[susceptible_idx] <- "sensitive"
## Error: object 'sus_categorical' not found
sus_categorical <- as.factor(sus_categorical)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.factor': object 'sus_categorical' not found
pData(lp_expt)[["sus_category_historical"]] <- sus_categorical
## Error in eval(expr, envir, enclos): object 'sus_categorical' not found
table(sus_categorical)
## Error in eval(expr, envir, enclos): object 'sus_categorical' not found
two_sankey <- plot_meta_sankey(
  merged_zymo, factors = c("zymodeme", "clinicalcategorical", "susceptibility"),
  drill_down = TRUE, color_choices = color_choices)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'design' in selecting a method for function 'plot_meta_sankey': object 'merged_zymo' not found
two_sankey
## Error in eval(expr, envir, enclos): object 'two_sankey' not found

9.2 Extract current susceptibility data

The same process will be repeated for the current iteration of the sensitivity assay and stored in the ‘sus_category_current’ column.

starting_current <- sanitize_percent(pData(lp_expt)[["susceptibilityinfectionreduction32ugmlsbvcurrentdata"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
sus_categorical_current <- starting_current
## Error in eval(expr, envir, enclos): object 'starting_current' not found
na_idx <- is.na(starting_current)
## Error in eval(expr, envir, enclos): object 'starting_current' not found
sum(na_idx)
## Error in eval(expr, envir, enclos): object 'na_idx' not found
sus_categorical_current[na_idx] <- "unknown"
## Error: object 'sus_categorical_current' not found
## The following is only valid when we had three categories, resistant/ambiguous/sensitive
## The new cutoffs drop ambiguous.
#resist_idx <- starting_current <= max_resist_current
#sus_categorical_current[resist_idx] <- "resistant"
#indeterminant_idx <- starting_current > max_resist_current &
#  starting_current < min_sensitive_current
#sus_categorical_current[indeterminant_idx] <- "ambiguous"
#susceptible_idx <- starting_current >= min_sensitive_current
#sus_categorical_current[susceptible_idx] <- "sensitive"
#sus_categorical_current <- as.factor(sus_categorical_current)
resist_idx <- starting_current <= max_resist_current
## Error in eval(expr, envir, enclos): object 'starting_current' not found
sensitive_idx <- !resist_idx
## Error in eval(expr, envir, enclos): object 'resist_idx' not found
sus_categorical_current[resist_idx] <- "resistant"
## Error: object 'sus_categorical_current' not found
sus_categorical_current[sensitive_idx] <- "sensitive"
## Error: object 'sus_categorical_current' not found
sus_categorical_current <- as.factor(sus_categorical_current)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.factor': object 'sus_categorical_current' not found
pData(lp_expt)[["sus_category_current"]] <- sus_categorical_current
## Error in eval(expr, envir, enclos): object 'sus_categorical_current' not found
pData(lp_expt)[["susceptibility"]] <- sus_categorical_current
## Error in eval(expr, envir, enclos): object 'sus_categorical_current' not found
table(sus_categorical_current)
## Error in eval(expr, envir, enclos): object 'sus_categorical_current' not found
lp_sankey <- plot_meta_sankey(
  lp_expt, factors = c("zymodemecategorical", "clinicalcategorical", "susceptibility"),
  drill_down = TRUE, color_choices = color_choices)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'design' in selecting a method for function 'plot_meta_sankey': object 'lp_expt' not found
lp_sankey
## Error in eval(expr, envir, enclos): object 'lp_sankey' not found

In many queries, we will seek to compare only the two primary strains, zymodeme 2.2 and 2.3. The following block will extract only those samples.

Note: IMPORTANT Maria Adelaida prefers not to use lp_two_strains. We should not at this time use the merged 2.1/2.2 and 2.4/2.3 categories.

lp_strain <- lp_expt %>%
  set_expt_batches(fact = sus_categorical_current) %>%
  set_expt_colors(color_choices[["strain"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
table(pData(lp_strain)[["condition"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_strain' not found
save(list = "lp_strain", file = glue("rda/tmrc2_lp_strain-v{ver}.rda"))
## Error in save(list = "lp_strain", file = glue("rda/tmrc2_lp_strain-v{ver}.rda")): object 'lp_strain' not found
data_structures <- c(data_structures, "lp_strain")

lp_two_strains <- merged_zymo
## Error in eval(expr, envir, enclos): object 'merged_zymo' not found
save(list = "lp_two_strains",
     file = glue("rda/tmrc2_lp_two_strains-v{ver}.rda"))
## Error in save(list = "lp_two_strains", file = glue("rda/tmrc2_lp_two_strains-v{ver}.rda")): object 'lp_two_strains' not found
data_structures <- c(data_structures, "lp_two_strains")

9.3 Clinical outcome

Clinical outcome is by far the most problematic comparison in this data, but here is the recategorization of the data using it:

lp_cf <- set_expt_conditions(lp_expt, fact = "clinicalcategorical",
                             colors = color_choices[["cf"]]) %>%
  set_expt_batches(fact = sus_categorical_current)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
table(pData(lp_cf)[["condition"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_cf' not found
data_structures <- c(data_structures, "lp_cf")
save(list = "lp_cf",
     file = glue("rda/tmrc2_lp_cf-v{ver}.rda"))
## Error in save(list = "lp_cf", file = glue("rda/tmrc2_lp_cf-v{ver}.rda")): object 'lp_cf' not found
lp_cf_known <- subset_expt(lp_cf, subset = "condition!='unknown'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_cf' not found
data_structures <- c(data_structures, "lp_cf_known")
save(list = "lp_cf_known",
     file = glue("rda/tmrc2_lp_cf_known-v{ver}.rda"))
## Error in save(list = "lp_cf_known", file = glue("rda/tmrc2_lp_cf_known-v{ver}.rda")): object 'lp_cf_known' not found
data_structures <- c(data_structures, "lp_cf_known")
save(list = "lp_cf_known",
     file = glue("rda/tmrc2_lp_cf_known-v{ver}.rda"))
## Error in save(list = "lp_cf_known", file = glue("rda/tmrc2_lp_cf_known-v{ver}.rda")): object 'lp_cf_known' not found

9.4 Create a historical susceptibility dataset

Use the factorized version of susceptibility to categorize the samples by the historical data.

lp_susceptibility_historical <- set_expt_conditions(
  lp_expt, fact = "sus_category_historical", colors = color_choices[["susceptibility"]]) %>%
  set_expt_batches(fact = "clinicalcategorical")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
save(list = "lp_susceptibility_historical",
     file = glue("rda/tmrc2_lp_susceptibility_historical-v{ver}.rda"))
## Error in save(list = "lp_susceptibility_historical", file = glue("rda/tmrc2_lp_susceptibility_historical-v{ver}.rda")): object 'lp_susceptibility_historical' not found
data_structures <- c(data_structures, "lp_susceptibility_historical")

9.5 Create a current susceptibility dataset

Use the factorized version of susceptibility to categorize the samples by the historical data.

This will likely be our canonical susceptibility dataset, so I will remove the suffix and just call it ‘lp_susceptibility’.

lp_susceptibility <- set_expt_conditions(
  lp_expt, fact = "sus_category_current", colors = color_choices[["susceptibility"]]) %>%
  set_expt_batches(fact = "clinicalcategorical")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_expt' not found
save(list = "lp_susceptibility",
     file = glue("rda/tmrc2_lp_susceptibility-v{ver}.rda"))
## Error in save(list = "lp_susceptibility", file = glue("rda/tmrc2_lp_susceptibility-v{ver}.rda")): object 'lp_susceptibility' not found
data_structures <- c(data_structures, "lp_susceptibility")

9.6 Pull out only the samples with two zymodemes

I think this is redundant with a previous block, but I am leaving it until I am certain that it is not required in a following document.

Note: IMPORTANT This is the set Maria Adeliada prefers to use.

lp_zymo <- subset_expt(lp_expt, subset = "condition=='z2.2'|condition=='z2.3'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_expt' not found
data_structures <- c(data_structures, "lp_zymo")
save(list = "lp_zymo",
     file = glue("rda/tmrc2_lp_zymo-v{ver}.rda"))
## Error in save(list = "lp_zymo", file = glue("rda/tmrc2_lp_zymo-v{ver}.rda")): object 'lp_zymo' not found

10 Variant data using parasite RNASeq reads

The following section will create some initial data structures of the observed variants in the parasite samples. This will include some of our 2016 samples for some classification queries.

10.1 The 2016 variant data

I changed and improved the mapping and variant detection methods from what we used for the 2016 data. So some small changes will be required to merge them.

lp_previous <- create_expt("sample_sheets/tmrc2_samples_20191203.xlsx",
                           file_column = "tophat2file",
                           savefile = glue("rda/lp_previous-v{ver}.rda"))
tt <- lp_previous$expressionset
rownames(tt) <- gsub(pattern = "^exon_", replacement = "", x = rownames(tt))
rownames(tt) <- gsub(pattern = "\\.1$", replacement = "", x = rownames(tt))
rownames(tt) <- gsub(pattern = "\\-1$", replacement = "", x = rownames(tt))
lp_previous$expressionset <- tt
rm(tt)
data_structures <- c(data_structures, "lp_previous")

10.2 Create the SNP expressionset

The count_expt_snps() function uses our expressionset data and a metadata column in order to extract the mpileup or freebayes-based variant calls and create matrices of the likelihood that each position-per-sample is in fact a variant.

There is an important caveat here which changed on 202301: I was interpreting using the PAIRED tag, which is only used for, unsurprisingly, paired-end samples. A couple samples are not paired and so were failing silently. The QA tag looks like it is more appropriate and should work across both types. One way to find out, I am setting it here and will look to see if the results make more sense for my test samples (TMRC2001, TMRC2005, TMRC2007).

## The next line drops the samples which are missing the SNP pipeline.
lp_snp <- subset_expt(lp_expt, subset = "!is.na(pData(lp_expt)[['freebayessummary']])")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_expt' not found
lp_snp_sufficient <- subset_expt(lp_snp, subset = "rownames!='TMRC20082'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_snp' not found
lp_snp_only22_23_ref <- subset_expt(lp_snp, subset = "zymodemereference=='z2.2'|zymodemereference=='z2.3'") %>%
  subset_expt(subset = "rownames!='TMRC20082'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_snp' not found
lp_snp_22_23_ml <- subset_expt(lp_snp, subset = "knnv2classification=='z22'|knnv2classification=='z23'") %>%
  subset_expt(subset = "rownames!='TMRC20082'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_snp' not found
new_snps_sufficient <- count_expt_snps(lp_snp_sufficient, annot_column = "freebayessummary", snp_column = "QA",
                                       reader = "readr")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_snp_sufficient' not found
new_snps_only22_23_ref_suf <- count_expt_snps(lp_snp_only22_23_ref, annot_column = "freebayessummary", snp_column = "QA",
                                              reader = "readr")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_snp_only22_23_ref' not found
new_snps_22_23_ml_suf <- count_expt_snps(lp_snp_22_23_ml, annot_column = "freebayessummary", snp_column = "QA",
                                         reader = "readr")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_snp_22_23_ml' not found
## Lets see if we get numbers which make sense.
summary(exprs(new_snps)[["tmrc20001"]])  ## My weirdo sample
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'new_snps' not found
summary(exprs(new_snps)[["tmrc20072"]])  ## Another sample chosen at random
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'new_snps' not found
summary(exprs(new_snps)[["tmrc20021"]])  ## Another sample chosen at random
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'new_snps' not found
## Now that we are reasonably confident that things make more sense, lets save and move on...
data_structures <- c(data_structures, "new_snps", "lp_snp")

tt <- normalize_expt(new_snps, transform = "log2")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'normalize_expt': object 'new_snps' not found
plot_boxplot(tt)
## Error in eval(expr, envir, enclos): object 'tt' not found

Now let us pull in the 2016 data.

old_snps <- count_expt_snps(lp_previous, annot_column = "bcftable", snp_column = 2)
data_structures <- c(data_structures, "old_snps")

save(list = "lp_snp",
     file = glue("rda/lp_snp-v{ver}.rda"))
data_structures <- c(data_structures, "lp_snp")
save(list = "new_snps",
     file = glue("rda/new_snps-v{ver}.rda"))
data_structures <- c(data_structures, "new_snps")
save(list = "old_snps",
     file = glue("rda/old_snps-v{ver}.rda"))
data_structures <- c(data_structures, "old_snps")

nonzero_snps <- exprs(new_snps) != 0
colSums(nonzero_snps)

10.3 Combine the previous and current data

As far as I can tell, freebayes and mpileup are reasonably similar in their sensitivity/specificity; so combining the two datasets like this is expected to work with minimal problems. The most likely problem is that my mpileup-based pipeline is unable to handle indels.

## My old_snps is using an older annotation incorrectly, so fix it here:
#annotation(old_snps) <- annotation(new_snps)
both_snps <- combine_expts(new_snps, old_snps)
save(list = "both_snps",
     file = glue("rda/both_snps-v{ver}.rda"))
data_structures <- c(data_structures, "both_snps")

11 Subclade manual interpretation

I am taking a heatmap from our variant data and manually identifying sample groups.

  • A: TMRC20025, TMRC20027, TMRC20028
  • B: hpgl0641, hpgl0247, hpgl0631, hpgl0658, close to A
  • C: TMRC20008, TMRC20007, TMRC20001, TMRC20005, hpgl0318, TMRC20012
  • D: hpgl0643, hpgl0316, hpgl0320, hpgl0641, close to C
  • E: TMRC20032, TMRC20061
  • F: TMRC20040, TMRC20036, hpgl0245, TMRC20103, TMRC20093, TMRC20045, TMRC20041, TMRC20072, TMRC20046, TMRC20057, TMRC20097, TMRC20084, close to E
  • G: hpgl0632, hpgl0652, hpgl0248, hpgl0659
  • H: hpgl0654, hpgl0634, hpgl0243, hpgl0243, closest to G
  • I: hpgl0242, hpgl0322, hpgl0636, hpgl0663, hpgl0638, close to H
  • J: TMRC20017, TMRC20033, TMRC20053, TMRC20063, TMRC20056, TMRC20074, TMRC20055, TMRC20022, TMRC20026, TMRC20083, TMRC20077, TMRC20060
  • K: TMRC20050, TMRC20042, TMRC20078, TMRC20049, TMRC20069, TMRC20044, close to J
  • L: TMRC20076, TMRC20024, TMRC2009
  • M: TMRC20019, TMRC20020, TMRC20031, TMRC20014, TMRC20011, close to L
  • N: TMRC20096, TMRC20081, TMRC20110, TMRC20092, TMRC20088, TMRC20101, TMRC20106, TMRC20091, TMRC20109, TMRC20087, TMRC20086, closeish to M
  • O: TMRC20095, TMRC20016, TMRC20018, quite far from everyone
  • P: TMRC20082, TMRC20075, pretty separate too
  • Q: hpgl0246, hpgl0653, hpgl0633, hpgl0244, hpgl0635, hpgl0655, hpgl0639, hpgl0662
  • R: TMRC20059, TMRC20089, TMRC20021, TMRC20048, TMRC20067
  • S: TMRC20013, TMRC20010, TMRC20037, TMRC20066, TMRC20062, TMRC20038, close to R
  • T: TMRC20015, TMRC20108, TMRC20099, TMRC20102, TMRC20085, TMRC20090, TMRC20104, TMRC20098, TMRC20100, TMRC20107
  • U: TMRC20047, TMRC20068, TMRC20080, TMRC20105, TMRC20094, TMRC20065, TMRC20071, TMRC20064, TMRC20043, TMRC20070, TMRC20062, TMRC20051, TMRC20079, TMRC20073, TMRC20058, TMRC20054

12 Macrophage data

All of the above focused entire on the parasite samples, now let us pull up the macrophage infected samples. This will comprise two datasets, one of the human and one of the parasite.

12.1 Macrophage host data

The metadata for the macrophage samples contains a couple of columns for mapped human and parasite reads. We will therefore use them separately to create two expressionsets, one for each species.

hs_annot <- load_biomart_annotations(year = "2020", month = 4)
## Using mart: ENSEMBL_MART_ENSEMBL from host: apr2020.archive.ensembl.org.
## Successfully connected to the hsapiens_gene_ensembl database.
## Finished downloading ensembl gene annotations.
## Finished downloading ensembl structure annotations.
## symbol columns is null, pattern matching 'symbol'.
## Including symbols, there are 68503 vs the 249740 gene annotations.
## Not dropping haplotype chromosome annotations, set drop_haplotypes = TRUE if this is bad.
## Saving annotations to hsapiens_biomart_annotations.rda.
## Finished save().
hs_annot <- hs_annot[["annotation"]]
hs_annot[["transcript"]] <- paste0(rownames(hs_annot), ".", hs_annot[["transcript_version"]])
rownames(hs_annot) <- make.names(hs_annot[["ensembl_gene_id"]], unique = TRUE)
rownames(hs_annot) <- paste0("gene:", rownames(hs_annot))
tx_gene_map <- hs_annot[, c("transcript", "ensembl_gene_id")]

sanitize_columns <- c("drug", "macrophagetreatment", "macrophagezymodeme")
macr_annot <- hs_annot
rownames(macr_annot) <- gsub(x = rownames(macr_annot),
                             pattern = "^gene:",
                             replacement = "")
hs_macrophage <- create_expt(
    macrophage_sheet,
    gene_info = macr_annot,
    file_column = "hg38100hisatfile") %>%
  set_expt_conditions(fact = "macrophagetreatment") %>%
  set_expt_batches(fact = "macrophagezymodeme") %>%
  sanitize_expt_pData(columns = sanitize_columns) %>%
  subset_expt(nonzero = 12000)
## Reading the sample metadata.
## Did not find the column: sampleid.
## Setting the ID column to the first column.
## Did not find the condition column in the sample sheet.
## Filling it in as undefined.
## Did not find the batch column in the sample sheet.
## Filling it in as undefined.
## The sample definitions comprises: 69 rows(samples) and 80 columns(metadata fields).
## Warning in file(file, "rt"): cannot open file
## '/z1/sw/singularity/clinical_strains_analyses/data/preprocessing/TMRC30051/outputs/03hisat2_hg38_100/hg38_100_genome-paired_gene_sno_gene_ID.count.xz': No
## such file or directory
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': cannot open the connection
fixed_genenames <- gsub(x = rownames(exprs(hs_macrophage)), pattern = "^gene:",
                        replacement = "")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'gsub': error in evaluating the argument 'x' in selecting a method for function 'rownames': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'hs_macrophage' not found
hs_macrophage <- set_expt_genenames(hs_macrophage, ids = fixed_genenames)
## Error in eval(expr, envir, enclos): object 'hs_macrophage' not found
table(pData(hs_macrophage)$condition)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'hs_macrophage' not found
## The following 3 lines were copy/pasted to datastructures and should be removed soon.
nostrain <- is.na(pData(hs_macrophage)[["strainid"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'hs_macrophage' not found
pData(hs_macrophage)[nostrain, "strainid"] <- "none"
## Error: object 'hs_macrophage' not found
pData(hs_macrophage)[["strain_zymo"]] <- paste0("s", pData(hs_macrophage)[["strainid"]],
                                                "_", pData(hs_macrophage)[["macrophagezymodeme"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'hs_macrophage' not found
uninfected <- pData(hs_macrophage)[["strain_zymo"]] == "snone_none"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'hs_macrophage' not found
pData(hs_macrophage)[uninfected, "strain_zymo"] <- "uninfected"
## Error: object 'hs_macrophage' not found
data_structures <- c(data_structures, "hs_macrophage")

Finally, split off the U937 samples.

hs_u937 <- subset_expt(hs_macrophage, subset = "typeofcells!='Macrophages'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'hs_macrophage' not found
data_structures <- c(data_structures, "hs_u937")

12.2 Macrophage parasite data

In the previous block, we used a new invocation of ensembl-derived annotation data, this time we can just use our existing parasite gene annotations.

lp_macrophage <- create_expt(macrophage_sheet,
                             file_column = "lpanamensisv36hisatfile",
                             gene_info = all_lp_annot,
                             savefile = glue("rda/lp_macrophage-v{ver}.rda"),
                             annotation = "org.Lpanamensis.MHOMCOL81L13.v46.eg.db") %>%
set_expt_conditions(fact = "macrophagezymodeme") %>%
  set_expt_batches(fact = "macrophagetreatment")
## Reading the sample metadata.
## Did not find the column: sampleid.
## Setting the ID column to the first column.
## Did not find the condition column in the sample sheet.
## Filling it in as undefined.
## Did not find the batch column in the sample sheet.
## Filling it in as undefined.
## The sample definitions comprises: 69 rows(samples) and 80 columns(metadata fields).
## Warning in file(file, "rt"): cannot open file
## '/z1/sw/singularity/clinical_strains_analyses/data/preprocessing/TMRC30051/outputs/40hisat2_lpanamensis_v36/lpanamensis_v36_genome-paired_all_sno_gene_ID.count.xz':
## No such file or directory
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'object' in selecting a method for function 'pData': cannot open the connection
unfilt_written <- write_expt(
  lp_macrophage,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/lp_macrophage_reads_unfiltered-v{ver}.xlsx"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_macrophage' not found
lp_macrophage_filt <- subset_expt(lp_macrophage, nonzero = 2500) %>%
  semantic_expt_filter(semantic = c("amastin", "gp63", "leishmanolysin"),
                       semantic_column = "annot_gene_product")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_macrophage' not found
data_structures <- c(data_structures, "lp_macrophage", "lp_macrophage_filt")
filt_written <- write_expt(lp_macrophage_filt,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/lp_macrophage_reads_filtered-v{ver}.xlsx"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_macrophage_filt' not found
lp_macrophage <- lp_macrophage_filt
## Error in eval(expr, envir, enclos): object 'lp_macrophage_filt' not found
lp_macrophage_nosb <- subset_expt(lp_macrophage, subset = "batch!='inf_sb'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'subset_expt': object 'lp_macrophage' not found
lp_nosb_write <- write_expt(
  lp_macrophage_nosb,
  excel = glue("analyses/macrophage_de/{ver}/read_counts/lp_macrophage_nosb_reads-v{ver}.xlsx"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_macrophage_nosb' not found
data_structures <- c(data_structures, "lp_macrophage_nosb")

spec <- make_rnaseq_spec()
test <- sm(gather_preprocessing_metadata(macrophage_sheet, specification = spec))

13 Plot SL Reads on a per condition basis

lp_meta <- pData(lp_macrophage)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_macrophage' not found
lp_meta[["slvsreads_log"]] <- log10(lp_meta[["slvsreads"]])
## Error in eval(expr, envir, enclos): object 'lp_meta' not found
inf_values <- is.infinite(lp_meta[["slvsreads_log"]])
## Error in eval(expr, envir, enclos): object 'lp_meta' not found
lp_meta[inf_values, "slvsreads_log"] <- -10
## Error: object 'lp_meta' not found
color_vector <- as.character(color_choices[["strain"]])
names(color_vector) <- names(color_choices[["strain"]])
color_vector <- color_vector[c("z2.2", "z2.3", "unknown")]
names(color_vector) <- c("z2.2", "z2.3", "none")
sl_violin <- ggplot(lp_meta,
                    aes(x = .data[["condition"]], y = .data[["slvsreads_log"]],
                        fill = .data[["condition"]])) +
  geom_violin() +
  geom_point() +
  scale_fill_manual(values = color_vector)
## Error in eval(expr, envir, enclos): object 'lp_meta' not found
sl_violin
## Error in eval(expr, envir, enclos): object 'sl_violin' not found
ggstatsplot::ggbetweenstats(lp_meta, x = "condition", y = "slvsreads_log")
## Error in eval(expr, envir, enclos): object 'lp_meta' not found

14 Make a silly ploidy plot

I want to make an estimate of ploidy using transcriptomic data. This is by definition a foold’s errand, but I think it might work.

lp_rpkm <- normalize_expt(lp_expt, convert = "rpkm", filter = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'expt' in selecting a method for function 'normalize_expt': object 'lp_expt' not found
## Exclude scaffolds
unwanted <- grepl(pattern = "SCAF", x = fData(lp_rpkm)[["chromosome"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'grepl': error in evaluating the argument 'object' in selecting a method for function 'fData': object 'lp_rpkm' not found
## I think my subset logic is bacwards...
lp_wanted <- lp_rpkm[!unwanted, ]
## Error in eval(expr, envir, enclos): object 'lp_rpkm' not found
summary_df <- as.data.frame(exprs(lp_wanted))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_wanted' not found
summary_df[["gene_mean"]] <- rowMeans(summary_df, na.rm = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rowMeans': object 'summary_df' not found
summary_df[["chromosome"]] <- fData(lp_wanted)[["chromosome"]]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': object 'lp_wanted' not found
summary_df <- summary_df[, c("gene_mean", "chromosome")] %>%
  group_by(chromosome) %>%
  summarize(chr_mean = mean(gene_mean, na.rm = TRUE))
## Error in eval(expr, envir, enclos): object 'summary_df' not found
min_rpkm <- min(summary_df[["chr_mean"]])
## Error in eval(expr, envir, enclos): object 'summary_df' not found
summary_df[["chr_mean"]] <- summary_df[["chr_mean"]] / min_rpkm
## Error in eval(expr, envir, enclos): object 'summary_df' not found
ggplot(summary_df, aes(y = chromosome, x = chr_mean)) +
  geom_col(position = "identity")
## Error in eval(expr, envir, enclos): object 'summary_df' not found
wanted <- pData(lp_wanted)[["knnv2classification"]] == "z22" | pData(lp_wanted)[["knnv2classification"]] == "z23"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_wanted' not found
lp_z <- lp_wanted[, wanted]
## Error in eval(expr, envir, enclos): object 'lp_wanted' not found
z22_samples <- pData(lp_z)[["knnv2classification"]] == "z22"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_z' not found
z23_samples <- pData(lp_z)[["knnv2classification"]] == "z23"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'lp_z' not found
lp_z_exprs <- as.data.frame(exprs(lp_z))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_z' not found
lp_z_exprs[["z22_gene_mean"]] <- rowMeans(lp_z_exprs[, z22_samples], na.rm = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rowMeans': object 'lp_z_exprs' not found
lp_z_exprs[["z23_gene_mean"]] <- rowMeans(lp_z_exprs[, z23_samples], na.rm = TRUE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rowMeans': object 'lp_z_exprs' not found
lp_z_exprs[["chromosome"]] <- fData(lp_z)[["chromosome"]]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'fData': object 'lp_z' not found
lp_z_means <- lp_z_exprs[, c("z22_gene_mean", "z23_gene_mean", "chromosome")] %>%
  group_by(chromosome) %>%
  summarize(z22_mean = mean(z22_gene_mean, na.rm = TRUE),
            z23_mean = mean(z23_gene_mean, na.rm = TRUE))
## Error in eval(expr, envir, enclos): object 'lp_z_exprs' not found
tt <- reshape2::melt(lp_z_means, id.vars = "chromosome")
## Error in eval(expr, envir, enclos): object 'lp_z_means' not found
ggplot(tt, aes(x = value, y = chromosome)) +
  geom_bar(aes(fill = variable), position = "dodge", stat = "identity")
## Error in eval(expr, envir, enclos): object 'tt' not found

15 Save all data structures into one rda

found_idx <- data_structures %in% ls()
if (sum(!found_idx) > 0) {
  not_found <- data_structures[!found_idx]
  warning("Some datastructures were not generated: ", toString(not_found), ".")
  data_structures <- data_structures[found_idx]
}
## Warning: Some datastructures were not generated: lp_lengths, lp_go, all_lp_annot, meta, lp_expt, lp_strain, lp_two_strains, lp_cf, lp_cf_known, lp_cf_known,
## lp_susceptibility_historical, lp_susceptibility, lp_zymo, new_snps, lp_snp, hs_macrophage, hs_u937, lp_macrophage, lp_macrophage_filt, lp_macrophage_nosb.
save(list = data_structures, file = glue("rda/tmrc2_data_structures-v{ver}.rda"))
## Warning in gzfile(file, "wb"): cannot open compressed file 'rda/tmrc2_data_structures-v202409.rda', probable reason 'No such file or directory'
## Error in gzfile(file, "wb"): cannot open the connection
pander::pander(sessionInfo())

R version 4.3.1 (2023-06-16)

Platform: x86_64-pc-linux-gnu (64-bit)

locale: LC_CTYPE=en_US.UTF-8, LC_NUMERIC=C, LC_TIME=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C

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

other attached packages: hpgltools(v.1.0), Matrix(v.1.6-5), SummarizedExperiment(v.1.32.0), GenomicRanges(v.1.54.1), GenomeInfoDb(v.1.38.6), IRanges(v.2.36.0), S4Vectors(v.0.40.2), MatrixGenerics(v.1.14.0), matrixStats(v.1.2.0), Biobase(v.2.62.0), BiocGenerics(v.0.48.1), Heatplus(v.3.10.0), ggplot2(v.3.5.0), glue(v.1.7.0) and dplyr(v.1.1.4)

loaded via a namespace (and not attached): RColorBrewer(v.1.1-3), jsonlite(v.1.8.8), correlation(v.0.8.4), datawizard(v.0.9.1), magrittr(v.2.0.3), TH.data(v.1.1-2), estimability(v.1.5), rmarkdown(v.2.25), fs(v.1.6.3), BiocIO(v.1.12.0), zlibbioc(v.1.48.0), vctrs(v.0.6.5), memoise(v.2.0.1), Rsamtools(v.2.18.0), paletteer(v.1.6.0), RCurl(v.1.98-1.14), progress(v.1.2.3), htmltools(v.0.5.7), S4Arrays(v.1.2.0), curl(v.5.2.0), SparseArray(v.1.2.4), sass(v.0.4.8), bslib(v.0.6.1), htmlwidgets(v.1.6.4), sandwich(v.3.1-0), plyr(v.1.8.9), zoo(v.1.8-12), emmeans(v.1.10.0), plotly(v.4.10.4), cachem(v.1.0.8), GenomicAlignments(v.1.38.2), mime(v.0.12), lifecycle(v.1.0.4), iterators(v.1.0.14), pkgconfig(v.2.0.3), R6(v.2.5.1), fastmap(v.1.1.1), GenomeInfoDbData(v.1.2.11), shiny(v.1.8.0), digest(v.0.6.34), colorspace(v.2.1-0), rematch2(v.2.1.2), patchwork(v.1.2.0), AnnotationDbi(v.1.64.1), RSQLite(v.2.3.5), filelock(v.1.0.3), fansi(v.1.0.6), httr(v.1.4.7), abind(v.1.4-5), compiler(v.4.3.1), pander(v.0.6.5), bit64(v.4.0.5), withr(v.3.0.0), BiocParallel(v.1.36.0), DBI(v.1.2.2), biomaRt(v.2.58.2), MASS(v.7.3-60.0.1), rappdirs(v.0.3.3), DelayedArray(v.0.28.0), rjson(v.0.2.21), HDO.db(v.0.99.1), tools(v.4.3.1), zip(v.2.3.1), httpuv(v.1.6.14), statsExpressions(v.1.5.3), varhandle(v.2.0.6), restfulr(v.0.0.15), GOSemSim(v.2.28.1), promises(v.1.2.1), grid(v.4.3.1), reshape2(v.1.4.4), fgsea(v.1.28.0), generics(v.0.1.3), gtable(v.0.3.4), tidyr(v.1.3.1), hms(v.1.1.3), data.table(v.1.15.0), xml2(v.1.3.6), utf8(v.1.2.4), XVector(v.0.42.0), foreach(v.1.5.2), pillar(v.1.9.0), stringr(v.1.5.1), yulab.utils(v.0.1.4), later(v.1.3.2), splines(v.4.3.1), BiocFileCache(v.2.10.1), lattice(v.0.22-5), survival(v.3.5-8), rtracklayer(v.1.62.0), bit(v.4.0.5), annotate(v.1.80.0), ggstatsplot(v.0.12.2), tidyselect(v.1.2.0), GO.db(v.3.18.0), Biostrings(v.2.70.2), knitr(v.1.45), xfun(v.0.42), stringi(v.1.8.3), lazyeval(v.0.2.2), yaml(v.2.3.8), evaluate(v.0.23), codetools(v.0.2-19), tibble(v.3.2.1), qvalue(v.2.34.0), graph(v.1.80.0), cli(v.3.6.2), parameters(v.0.21.5), xtable(v.1.8-4), munsell(v.0.5.0), jquerylib(v.0.1.4), Rcpp(v.1.0.12), zeallot(v.0.1.0), dbplyr(v.2.4.0), coda(v.0.19-4.1), png(v.0.1-8), XML(v.3.99-0.16.1), parallel(v.4.3.1), ellipsis(v.0.3.2), blob(v.1.2.4), prettyunits(v.1.2.0), bayestestR(v.0.13.2), DOSE(v.3.28.2), bitops(v.1.0-7), mvtnorm(v.1.2-4), viridisLite(v.0.4.2), GSEABase(v.1.64.0), scales(v.1.3.0), insight(v.0.19.8), openxlsx(v.4.2.5.2), purrr(v.1.0.2), crayon(v.1.5.2), rlang(v.1.1.3), multcomp(v.1.4-25), cowplot(v.1.1.3), fastmatch(v.1.1-4) and KEGGREST(v.1.42.0)

message("This is hpgltools commit: ", get_git_commit())
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 2ba131c696f93b44a2360e412fbba5b008699c83
## This is hpgltools commit: Thu Sep 19 10:49:55 2024 -0400: 2ba131c696f93b44a2360e412fbba5b008699c83
message("Saving to ", savefile)
## Saving to 01datasets.rda.xz
# tmp <- sm(saveme(filename = savefile))
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzIgYHIgU3lzLmdldGVudignVkVSU0lPTicpYDogRGF0YSBTZXQgQ3JlYXRpb24iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCmJpYmxpb2dyYXBoeTogYXRiLmJpYgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHplbmJ1cm4KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSAubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTYwMHB4Owp9CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogIGZvbnQtc2l6ZTogMTZweAp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEhlYXRwbHVzKQpsaWJyYXJ5KGhwZ2x0b29scykKCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzID0gVFJVRSwgdmVyYm9zZSA9IFRSVUUsIHdpZHRoID0gOTAsIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXJyb3IgPSBUUlVFLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gOSwgZmlnLnJldGluYSA9IDIsCiAgb3V0LndpZHRoID0gIjEwMCUiLCBkZXYgPSAicG5nIiwKICBkZXYuYXJncyA9IGxpc3QocG5nID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKSkKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSBTeXMuZ2V0ZW52KCJWRVJTSU9OIikKcHJldmlvdXNfZmlsZSA8LSAiIgpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAiJVklbSVkIikKCnJtZF9maWxlIDwtICIwMWRhdGFzZXRzLlJtZCIKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCmRhdGFfc3RydWN0dXJlcyA8LSBjKCkKYGBgCgojIFRPRE8KCjEuICBIYXZlIGEgc2V0IHdoZXJlIHdlIG1lcmdlIDIuMS8yLjIsIDIuMy8yLjQuCjIuICBSZXByZXNlbnQgdGhlIHRyYW5zaXRpb24gZnJvbSBhIGdsb2JhbCB2aWV3IG9mIHRoZSBzYW1wbGVzIHdpdGhvdXQKICAgIGFueSBjbGFzc2lmaWNhdGlvbiwgdGhlbiBzdGF0ZSB0aGUgc3VicG9wdWxhdGlvbnMvenltb2RlbWVzLCB0aGVuCiAgICBhZGQgc2Vuc2l0aXZpdHkvcmVzaXN0YW5jZSwgdGhlbiBjdXJlL2ZhaWwuCjMuICBQZXJoYXBzIG1ha2UgYW4gZXhwbGljaXQgcGxvdCB3aGVyZSBhbGwgc2FtcGxlcyBhcmUgb25lIGNvbG9yCiAgICBleGNlcHRpbmcgYSByZWxhdGl2ZWx5IHNtYWxsIG51bWJlciBvZiBwcmV2aW91c2x5IGFzc2F5ZWQgc2V0PwogICAgVGhlIHNhbXBsZXMgd2hpY2ggd291bGQgYmUgY29sb3JlZCBpbiB0aGlzIHZpZXcgd291bGQgYmUgZnJvbQogICAgT2xnYSdzIDIwMTQgcGFwZXIgSSB0aGluay4KNC4gIE1ha2UgYSBmbG93IGRpYWdyYW0gZ29pbmcgZnJvbSBzL3IgLT4gc3VicG9wdWxhdGlvbiAtPgogICAgYy9mL3UuIChzYW5rZXkpCjUuICBNYWtlIGEgdGFibGUgc2ltaWxhciB0byB0aGUgVE1SQzMgY29udGFpbmluZyB0aGUgc3RhdHVzZXMgb2YgdGhlCiAgICBzYW1wbGVzLgo2LiAgRXhwbGljaXRseSBjb25zaWRlciBtZXRhZGF0YSBjb2x1bW4gJ1AnIGZvciByZWZlcmVuY2Ugc3RyYWlucyAtLQogICAgbWFrZSBhbiBhbGwgZ3JleSBwbG90IHdpdGggYSBmZXcgc2FtcGxlcyBjb2xvcmVkIHRha2VuIGZyb20gdGhpcwogICAgY29sdW1uLgoKIyBDaGFuZ2Vsb2cKCiMjIDIwMjMwNTI0LzIwMjMwNjI4CgoqIEZyb3plbiBtZXRhZGF0YSwgbm93IHVzaW5nIHNhbXBsZSBzaGVldCAnQ2xpbmljYWxTdHJhaW5zX1RNUkMyX0Zyb3plblwgMjEwNjIwMjMueGxzeCcKCiMjIDIwMjMwNDEwCgoqIFVwZGF0aW5nIHRoZSB2ZXJzaW9uIG51bWJlciBkdWUgdG8gc29tZSBtb2RlcmF0ZWx5IGludHJ1c2l2ZSBjaGFuZ2VzCiAgSSBtYWRlIGluIG9yZGVyIHRvIG1vcmUgY2FyZWZ1bGx5IGNyZWF0ZSBwbG90cyBvZiB0aGUgZGlmZmVyZW50aWFsCiAgZXhwcmVzaXNvbiBkYXRhLiAgSSBkb24ndCB0aGluayBhbnl0aGluZyBJIGRpZCBzaG91bGQgYWN0dWFsbHkKICBjaGFuZ2UgYW55IG9mIHRoZSBkYXRhLCBidXQgc29tZSBvZiB0aGUgYW5hbHlzZXMgYXJlIGRlZmluaXRlbHkKICBhZmZlY3RlZCAobm90ZSB0aGF0IHRoZSBvbmx5IGNoYW5nZSBpbiByZXN1bHRzIGlzIGR1ZSB0byBhIG1pc3Rha2UgSQogIG1hZGUgaW4gZGVmaW5pbmcgb25lIG9mIHRoZSBjb250cmFzdHMsIGFsbCBvdGhlciBjaGFuZ2VzIGFyZSBqdXN0CiAgcGxvdCBhZXN0aGV0aWMgaW1wcm92ZW1lbnRzKQoKIyMgMjAyMzAyMDUKCiogRGlkIHRoZSBzdHVmZiBvbiB0aGlzIG1vcm5pbmcncyBUT0RPIHdoaWNoIGNhbWUgb3V0IG9mIHRoaXMKICBtb3JuaW5nJ3MgbWVldGluZzogZG8gYSBQQ0Egd2l0aG91dCB0aGUgb2RkYmFsbCBzdHJhaW5zIChhbHJlYWR5CiAgZG9uZSBpbiB0aGUgd29ya3NoZWV0KSwgaGlnaGxpZ2h0IHJlZmVyZW5jZSBzdHJhaW5zLCBhbmQgYWRkIEwubWFqb3IKICBJRHMgYW5kIERlc2NyaXB0aW9ucyAoZG9uZSBieSBhcHBlbmRpbmcgYSBjb2xsYXBzZWQgdmVyc2lvbiBvZiB0aGUKICBvcnRob2xvZyBkYXRhIHRvIHRoZSBhbGxfbHBfYW5ub3QgZGF0YSkuCgoqIEZpeGVkIGh1bWFuIElEcyBmb3IgdGhlIG1hY3JvcGhhZ2UgZGF0YS4KKiBDaGFuZ2VkIGlucHV0IG1ldGFkYXRhIHNoZWV0czogcHJpbWFyaWx5IGJlY2F1c2UgSSBvbmx5IHJlbWVtYmVyZWQKICB5ZXN0ZXJkYXkgdG8gZmluaXNoIHRoZSBTTCBzZWFyY2ggZm9yIHNhbXBsZXMgPlRNUkMyMDA5NS4gIFRoZXkgYXJlCiAgcnVubmluZyBub3cgYW5kIHdpbGwgYmUgYWRkZWQgbW9tZW50YXJpbHkgKEkgd2lsbCBoYXZlIHRvIHJlZG93bmxvYWQKICB0aGUgc2hlZXQpLgoqIFNldHRpbmcgdXAgdG8gbWFrZSBhIGhjbHVzdC9waHlsb2dlbmV0aWMgdHJlZSBvZiBzdHJhaW5zLCB1c2UgdGhlc2UKICBhcmUgcmVmZXJlbmNlOiAyMTY4KDIuMyksIDIyNzIoMi4yKSwgZm9yIG90aGVyIDIueCBjaG9vc2UKICBhcmJpdHJhcmlseSAobG93ZXIgbnVtYmVycyBhcmUgYmV0dGVyKS4KKiBBZGRlZCBhbm90aGVyIHNhbml0aXplIGNvbHVtbnMgY2FsbCBmb3IgQW50aW1vbnkgdnMuIGFudGltb255IGFuZCBOb25lIHZzLgogIG5vbmUgaW4gdGhlIFRNUkMyIG1hY3JvcGhhZ2Ugc2FtcGxlcy4KCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IGlzIGludGVuZGVkIHRvIGNyZWF0ZSB0aGUgZGF0YSBzdHJ1Y3R1cmVzIHVzZWQgdG8KZXZhbHVhdGUgb3VyIFRNUkMyIHNhbXBsZXMuICBJbiBzb21lIGNhc2VzLCB0aGlzIGluY2x1ZGVzIG9ubHkgdGhvc2UKc2FtcGxlcyBzdGFydGluZyBpbiAyMDE5OyBpbiBvdGhlciBpbnN0YW5jZXMgSSBhbSBpbmNsdWRpbmcgb3VyCnByZXZpb3VzICgyMDE1LTIwMTYpIHNhbXBsZXMuCgpJbiBhbGwgY2FzZXMgdGhlIHByb2Nlc3NpbmcgcGVyZm9ybWVkIHdhczoKCjEuICBEZWZhdWx0IHRyaW1taW5nIHdhcyBwZXJmb3JtZWQuCjIuICBIaXNhdDIgd2FzIHVzZWQgdG8gbWFwIHRoZSByZW1haW5pbmcgcmVhZHMgYWdhaW5zdCB0aGUgTGVpc2htYW5pYQogICAgcGFuYW1lbnNpcyBnZW5vbWUgcmV2aXNpb24gMzYuCjMuICBUaGUgYWxpZ25tZW50cyBmcm9tIGhpc2F0MiB3ZXJlIHVzZWQgdG8gY291bnQgcmVhZHMvZ2VuZSBhZ2FpbnN0IHRoZQogICAgcmV2aXNpb24gMzYgYW5ub3RhdGlvbnMgd2l0aCBodHNlcS4KNC4gIFRoZXNlIGFsaWdubWVudHMgd2VyZSBhbHNvIHBhc3NlZCB0byB0aGUgcGlsZXVwIGZ1bmN0aW9uYWxpdHkgb2Ygc2FtdG9vbHMKICAgIGFuZCB0aGUgdmNmL2JjZiB1dGlsaXRpZXMgaW4gb3JkZXIgdG8gbWFrZSBhIG1hdHJpeCBvZiBhbGwgb2JzZXJ2ZWQKICAgIGRpZmZlcmVuY2VzIGJldHdlZW4gZWFjaCBzYW1wbGUgd2l0aCByZXNwZWN0IHRvIHRoZSByZWZlcmVuY2UuCjUuICBUaGUgZnJlZWJheWVzIHZhcmlhbnQgZXN0aW1hdGlvbiB0b29sIHdhcyB1c2VkIGluIGFkZGl0aW9uIHRvICM0CiAgICB0byBzZWFyY2ggZm9yIHZhcmlhbnQgcG9zaXRpb25zIGluIGEgbW9yZSByb2J1c3QgZmFzaGlvbi4KNi4gIFRoZSB0cmltbWVkIHJlYWRzIHdlcmUgcGFzc2VkIHRvIGtyYWtlbjIgdXNpbmcgYSB2aXJhbCBkYXRhYmFzZSBpbgogICAgb3JkZXIgdG8gbG9vayBmb3Igc2FtcGxlcyB3aXRoIHBvdGVudGlhbCBMUlYgc2VxdWVuY2UuCjcuICBBbiBleHBsaWNpdCwgZ3JlcC1iYXNlZCBzZWFyY2ggZm9yIHNwbGljZWQgbGVhZGVyIHJlYWRzIHdhcyB1c2VkCiAgICBhZ2FpbnN0IGFsbCBodW1hbi1kZXJpdmVkIHNhbXBsZXMuICBUaGUgcmVzdWx0cyBmcm9tIHRoaXMgd2VyZQogICAgY29weS9wYXN0ZWQgaW50byB0aGUgc2FtcGxlIHNoZWV0LgoKIyBOb3RlcyAyMDIyMTIwNiBtZWV0aW5nCgpJIGFtIHRoaW5raW5nIHRoYXQgdGhpcyBtZWV0aW5nIHdpbGwgYnJpbmcgTWFyaWEgQWRlbGFpZGEgZnVsbHkgYmFjawppbnRvIHRoZSBhbmFseXNlcyBvZiB0aGUgcGFyYXNpdGUgZGF0YSwgYW5kIHRoZXJlZm9yZSBtYXkgZm9jdXMKcHJpbWFyaWx5IG9uIHRoZSBnb2FscyByYXRoZXIgdGhhbiB0aGUgYW5hbHlzZXM/CgoqIE1hcmlhIEFkZWxhaWRhIG1lZXRpbmcgd2l0aCBPbGdsYS9NYXJpYW5hOiBpbnRlZ3JhdGluZwogIHRyYW5zY3JpcHRvbWljcy9nZW5vbWljcyBxdWVzdGlvbi4KKiBQYXBlciBvbiByZWxhdGlvbnNoaXAgYnR3biBwcmltYXJ5IG1ldGFkYXRhIGZhY3RvcnMgdmlhIHRyYW5zY3JpcHRvbWUvZ2Vub21lLgoqIFNlY29uZCBvbiBkcnVnIHN1c2NlcHRpYmlsaXR5IHdpdGhvdXQgdGhvc2UgZmFjdG9ycyAoSSB0aGluayB0aGlzCiAgbWVhbnMgdGhlIG1hY3JvcGhhZ2VzKQoqIERlZmluaXRpb24gb2Ygc3BlY2llcz8gIE1BRzogRGVmaW5lIGNvbnNlbnN1cyBzZXF1ZW5jZXMgZm9yIHZhcmlvdXMKICBzdHJhaW5zL3NwZWNpZXMuICBXZSBlZmZlY3RpdmVseSBoYXZlIHRoaXMgb24gaGFuZCwgdGhvdWdoIHRoZQogIHF1YWxpdHkgbWF5IGJlIGEgbGl0dGxlIGxlc3MgZ29vZCBmb3IgMi4zLgoqIFJlc3VsdGluZyBnb2FsOiBDcmVhdGUgYSB0cmVlIG9mIHRoZSBzdHJhaW5zIChJIGFtIGp1c3QgZ29pbmcgdG8KICBjYWxsIHp5bW9kZW1lcyBzdHJhaW5zIGZyb20gbm93IG9uKS4KKiogIFdoYXQgb3JnYW5pc21zIHdvdWxkIHdlIGluY2x1ZGUgaW4gYSB0cmVlIHRvIGRlc2NyaWJlIHRoZXNlCiAgICByZWxhdGlvbnNoaXBzOiBndXlhbmVuc2lzLCBicmF6aWxpZW5zaXMgMjkwNCwgMi4yLCAyLjMsIDIuMSwgMi40LAogICAgcGFuYW1lbnNpcyByZWZlcmVuY2UsIHBlcnV2aWFuaWEoc3A/IEkgaGF2ZSBub3Qgc2VlbiB0aGlzIGdlbm9tZSksCiAgICBwYW5hbWEsIDI5MDM7IGFjdHVhbGx5IHRoaXMgbWF5IGJlIHRyaWNreSBiZWNhdXNlIHdlIGhhdmUgYWx3YXlzCiAgICBkb25lIHRoaXMgd2l0aCBhIHNwZWNpZmljIHJlZmVyZW5jZSBzdHJhaW4gKHBhbmFtZW5zaXMgY29sKSB3aGljaCBpcwogICAgb25lIG9mIHRoZSBzdHJhaW5zIGluIHRoZSBjb21wYXJpc29uLiAgaG1tLi4uCioqICBDaGVjayB0aGUgbW9zdCB2YXJpYW50IHN0cmFpbnMgZm9yIGlkZW50aXR5IChMdWMpCioqICBNZXRob2RzIGZvciBjcmVhdGluZyB0cmVlLCB0cmFkaXRpb25hbCBwaHlsb2dlbnkgdnMuIHZhcmlhbnQKICAgIGhjbHVzdD8KKiBQQ1IgcXVlcmllcywgd29ya3Mgd2VsbCBpZiBvbmUgcGVyZm9ybXMgc2FuZ2VyIHNlcXVlbmNpbmcuCgojIyBNdWx0aXBsZSBkYXRhc2V0cwoKSW4gYSBjb3VwbGUgb2YgaW1wb3J0YW50IHdheXMgdGhlIFRNUkMyIGRhdGEgaXMgbXVjaCBtb3JlIGNvbXBsZXggdGhhbiB0aGUKVE1SQzM6CgoxLiAgSXQgY29tcHJpc2VzIG11bHRpcGxlLCBjb21wbGV0ZWx5IHNlcGFyYXRlIHF1ZXJpZXM6CiAgICBhLiAgU2VxdWVuY2luZyB0aGUgcGFyYXNpdGUgc2FtcGxlcwogICAgYi4gIFNlcXVlbmNpbmcgYSBzZXQgb2YgaHVtYW4gbWFjcm9waGFnZSBzYW1wbGVzIHdoaWNoIHdlcmUgaW5mZWN0ZWQKICAgICAgICB3aXRoIHNwZWNpZmljIHBhcmFzaXRlIHNhbXBsZXMuCjIuICBUaGUgcGFyYXNpdGUgdHJhbnNjcmlwdG9taWMgc2FtcGxlcyBjb21wcmlzZSBtdWx0aXBsZSBkaWZmZXJlbnQKICAgIHR5cGVzIG9mIHF1ZXJpZXM6CiAgICBhLiAgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gdG8gbG9vayBhdCBzdHJhaW4sIHN1c2NlcHRpYmlsaXR5LCBhbmQKICAgIGNsaW5pY2FsIG91dGNvbWVzLgogICAgYi4gIEluZGl2aWR1YWwgdmFyaWFudCBzZWFyY2hlcyB0byBsb29rIGZvciBwb3RlbnRpYWxseSB1c2VmdWwKICAgIFNOUHMgZm9yIGNsYXNzaWZpY2F0aW9uIG9mIHBhcmFzaXRlIHNhbXBsZXMuCjMuICBUaGUgaHVtYW4gbWFjcm9waGFnZSBzYW1wbGVzIG1heSBiZSB1c2VkIHRvIHF1ZXJ5IGJvdGggdGhlIGhvc3QKICAgIGFuZCBwYXJhc2l0ZSB0cmFuc2NyaXB0b21lcyBiZWNhdXNlIChhdCBsZWFzdCB3aGVuIG5vdCBkcnVnCiAgICB0cmVhdGVkKSB0aGVyZSBpcyBhIHRyZW1lbmRvdXMgcG9wdWxhdGlvbiBvZiBwYXJhc2l0ZSByZWFkcyBpbgogICAgdGhlbS4KCiMjIFNhbXBsZSBzaGVldChzKQoKT3VyIHNoYXJlZCBvbmxpbmUgc2FtcGxlIHNoZWV0IGlzIG5lYXJseSBzdGF0aWMgYXQgdGhlIHRpbWUgb2YgdGhpcwp3cml0aW5nICgyMDIyMDkpLCBJIGV4cGVjdCBhdCB0aGlzIHBvaW50IHRoZSBvbmx5IGxpa2VseSB1cGRhdGVzIHdpbGwKYmUgdG8gYW5ub3RhdGUgc29tZSBzdHJhaW5zIGFzIG1vcmUgb3IgbGVzcyBzdXNjZXB0aWJsZSB0byBkcnVnCnRyZWF0bWVudC4KCmBgYHtyfQpzYW1wbGVfc2hlZXQgPC0gInNhbXBsZV9zaGVldHMvQ2xpbmljYWxTdHJhaW5zX1RNUkMyLnhsc3giCm1hY3JvcGhhZ2Vfc2hlZXQgPC0gInNhbXBsZV9zaGVldHMvdG1yYzJfbWFjcm9waGFnZV9zYW1wbGVzLnhsc3giCmBgYAoKIyMjIE1vZGlmeSB0aGUgc2FtcGxlIHNoZWV0CgpUaGUgZm9sbG93aW5nIGJsb2NrIHByb3ZpZGVzIGFuIGV4YW1wbGUgaW52b2NhdGlvbiBvZiBob3cgSQphdXRvbWF0aWNhbGx5IGV4dHJhY3QgdGhpbmdzIGxpa2UgcGVyY2VudCByZWFkcyBtYXBwZWQvdHJpbW1lZC9ldGMKZnJvbSB0aGUgbG9ncyBwcm9kdWNlZCBieSB0cmltb21hdGljL2N1dGFkYXB0L2hpc2F0L3NhbG1vbi9ldGMuICBUaGUKY2F2ZWF0IGlzIHRoYXQgdGhpcyBjb250YWluZXIgb25seSBoYXMgYSBzbWFsbCBwb3J0aW9uIG9mIHRoZSBtYXRlcmlhbAphdmFpbGFibGUgaW4gdGhlIG1haW4gd29ya2luZyB0cmVlLCBhcyBhIHJlc3VsdCB0aGUgbmV3IGNvbHVtbnMgYWRkZWQKdG8gdGhlIHNhbXBsZSBzaGVldCBhcmUgcmVsYXRpdmVseSBzcGFyc2UgY29tcGFyZWQgdG8gd2hhdCBJIGdldCBvbiBteQpjb21wdXRlci4KCkluIGFkZGl0aW9uLCBiZWNhdXNlIHRoZXNlIHNhbXBsZXMgaGF2ZSBnb25lIHRocm91Z2ggfiAzIGRpZmZlcmVudAp2ZXJzaW9ucyBvZiBteSBwaXBlbGluZSwgYW5kIHRoZSBjb2RlIHdoaWNoIGV4dHJhY3RzIHRoZSBudW1iZXJzCmV4cGxpY2l0bHkgYXNzdW1lcyBvbmx5IHRoZSBtb3N0IHJlY2VudCB2ZXJzaW9uIChiZWNhdXNlIGl0IGlzIHRoZQpiZXN0ISksIGl0IGRvZXMgbm90IGdldCBvdXQgdGhlIGRhdGEgZm9yIGFsbCB0aGUgc2FtcGxlcy4KCmBgYHtyfQptb2RpZmllZCA8LSBnYXRoZXJfcHJlcHJvY2Vzc2luZ19tZXRhZGF0YShzYW1wbGVfc2hlZXQsIHNwZWNpZXMgPSAibHBhbmFtZW5zaXNfdjM2IikKYGBgCgojIEFubm90YXRpb25zCgpFdmVyeXRoaW5nIHdoaWNoIGZvbGxvd3MgZGVwZW5kcyBvbiB0aGUgRXhpc3RpbmcgVHJpVHJ5cERCIGFubm90YXRpb25zIHJldmlzaW9uCjQ2LCBjaXJjYSAyMDE5LiAgVGhlIGZvbGxvd2luZyBibG9jayBsb2FkcyBhIGRhdGFiYXNlIG9mIHRoZXNlIGFubm90YXRpb25zIGFuZAp0dXJucyBpdCBpbnRvIGEgbWF0cml4IHdoZXJlIHRoZSByb3dzIGFyZSBnZW5lcyBhbmQgY29sdW1ucyBhcmUgYWxsIHRoZQphbm5vdGF0aW9uIHR5cGVzIHByb3ZpZGVkIGJ5IFRyaVRyeXBEQi4KClRoZSBzYW1lIGRhdGFiYXNlIHdhcyB1c2VkIHRvIGNyZWF0ZSBhIG1hdHJpeCBvZiBvcnRob2xvZ291cyBnZW5lcyBiZXR3ZWVuCkwucGFuYW1lbnNpcyBhbmQgYWxsIG9mIHRoZSBvdGhlciBzcGVjaWVzIGluIHRoZSBUcmlUcnlwREIuCgpUaGUgc2FtZSBkYXRhYmFzZSBvZiBhbm5vdGF0aW9ucyBhbHNvIHByb3ZpZGVzIG1hcHBpbmdzIHRvIHRoZSBzZXQgb2YKYW5ub3RhdGVkIEdPIGNhdGVnb3JpZXMgZm9yIHRoZSBMLnBhbmFtZW5zaXMgZ2Vub21lIGFsb25nIHdpdGggZ2VuZQpsZW5ndGhzLgoKYGBge3J9CiMjIG1ldGEgPC0gZG93bmxvYWRfZXVwYXRoX21ldGFkYXRhKHdlYnNlcnZpY2UgPSAidHJpdHJ5cGRiIiwgZXVfdmVyc2lvbiA9ICJ2NDYiKQptZXRhIDwtIGRvd25sb2FkX2V1cGF0aF9tZXRhZGF0YSh3ZWJzZXJ2aWNlID0gInRyaXRyeXBkYiIpCnBhbmFtZW5zaXNfZW50cnkgPC0gZ2V0X2V1cGF0aF9lbnRyeSgiTUhPTSIsIG1ldGFkYXRhID0gbWV0YVtbInZhbGlkIl1dKQpwYW5hbWVuc2lzX2RiIDwtIG1ha2VfZXVwYXRoX29yZ2RiKHBhbmFtZW5zaXNfZW50cnkpCnBhbmFtZW5zaXNfcGtnIDwtIHBhbmFtZW5zaXNfZGJbWyJwa2duYW1lIl1dCnBhY2thZ2VfbmFtZSA8LSBwYW5hbWVuc2lzX2RiW1sicGtnbmFtZSJdXQppZiAoaXMubnVsbChwYW5hbWVuc2lzX3BrZykpIHsKICBwYW5hbWVuc2lzX3BrZyA8LSBwYW5hbWVuc2lzX2RiW1sib3JnZGJfbmFtZSJdXQogIHBhY2thZ2VfbmFtZSA8LSBwYW5hbWVuc2lzX3BrZwp9CnR0IDwtIGxpYnJhcnkocGFuYW1lbnNpc19wa2csIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKcGFuYW1lbnNpc19wa2cgPC0gZ2V0MChwYW5hbWVuc2lzX3BrZykKYWxsX2ZpZWxkcyA8LSBjb2x1bW5zKHBhbmFtZW5zaXNfcGtnKQphbGxfbHBfYW5ub3QgPC0gc20obG9hZF9vcmdkYl9hbm5vdGF0aW9ucygKICAgIHBhbmFtZW5zaXNfcGtnLAogICAga2V5dHlwZSA9ICJnaWQiLAogICAgZmllbGRzID0gYygiYW5ub3RfZ2VuZV9lbnRyZXpfaWQiLCAiYW5ub3RfZ2VuZV9uYW1lIiwKICAgICAgICAgICAgICAgImFubm90X3N0cmFuZCIsICJhbm5vdF9jaHJvbW9zb21lIiwgImFubm90X2Nkc19sZW5ndGgiLAogICAgICAgICAgICAgICAiYW5ub3RfZ2VuZV9wcm9kdWN0IikpKSRnZW5lcwoKbHBfZ28gPC0gbG9hZF9vcmdkYl9nbyhwYWNrYWdlX25hbWUpCmxwX2dvIDwtIGxwX2dvWywgYygiR0lEIiwgIkdPIildCmxwX2xlbmd0aHMgPC0gYWxsX2xwX2Fubm90WywgYygiZ2lkIiwgImFubm90X2Nkc19sZW5ndGgiKV0KY29sbmFtZXMobHBfbGVuZ3RocykgIDwtIGMoIklEIiwgImxlbmd0aCIpCmFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSA8LSB0b2xvd2VyKGFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSkKb3J0aG9zIDwtIHNtKGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncyhkYiA9IHBhbmFtZW5zaXNfcGtnKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfbGVuZ3RocyIsICJscF9nbyIsICJhbGxfbHBfYW5ub3QiLCAibWV0YSIpCmBgYAoKIyMgUmVwZWF0IGZvciB0aGUgTC5tYWpvciBhbm5vdGF0aW9ucwoKUmVjZW50bHkgdGhlcmUgd2FzIGEgcmVxdWVzdCB0byBpbmNsdWRlIHRoZSBMZWlzaG1hbmlhIG1ham9yIGdlbmUgSURzCmFuZCBkZXNjcmlwdGlvbnMuICBUaHVzIEkgd2lsbCBleHRyYWN0IHRoZW0gYWxvbmcgd2l0aCB0aGUgb3J0aG9sb2dzCmFuZCBhcHBlbmQgdGhhdCB0byB0aGUgYW5ub3RhdGlvbnMgdXNlZC4KCkhhdmluZyBzcGVudCB0aGUgdGltZSB0byBydW4gdGhlIGZvbGxvd2luZyBjb2RlLCBJIHJlYWxpemVkIHRoYXQgdGhlCm9ydGhvbG9ncyBkYXRhIHN0cnVjdHVyZSBhYm92ZSBhY3R1YWxseSBhbHJlYWR5IGhhcyB0aGUgZ2VuZSBJRHMgYW5kCmRlc2NyaXB0aW9ucy4KClRodXMgSSB3aWxsIGxlYXZlIG15IHF1ZXJ5IGluIHBsYWNlIHRvIGV4dHJhY3QgdGhlIG1ham9yIGFubm90YXRpb25zLApidXQgZm9sbG93IGl0IHVwIHdpdGggYSBjb2xsYXBzZSBvZiB0aGUgbWFqb3Igb3J0aG9sb2dzIGFuZCBhcHBlbmRpbmcKb2YgdGhhdCB0byB0aGUgcGFuYW1lbnNpcyBhbm5vdGF0aW9ucy4KCmBgYHtyIGV1cGF0aGRiX2xtYWpvciwgZXZhbD1GQUxTRX0Kb3JnZGIgPC0gIm9yZy5MbWFqb3IuRnJpZWRsaW4udjQ5LmVnLmRiIgp0dCA8LSBzbShsaWJyYXJ5KG9yZ2RiLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQptYWpvcl9kYiA8LSBvcmcuTG1ham9yLkZyaWVkbGluLnY0OS5lZy5kYgphbGxfZmllbGRzIDwtIGNvbHVtbnMocGFuX2RiKQphbGxfbG1fYW5ub3QgPC0gc20obG9hZF9vcmdkYl9hbm5vdGF0aW9ucygKICAgIG1ham9yX2RiLAogICAga2V5dHlwZSA9ICJnaWQiLAogICAgZmllbGRzID0gYygiYW5ub3RfZ2VuZV9lbnRyZXpfaWQiLCAiYW5ub3RfZ2VuZV9uYW1lIiwKICAgICAgICAgICAgICAgImFubm90X3N0cmFuZCIsICJhbm5vdF9jaHJvbW9zb21lIiwgImFubm90X2Nkc19sZW5ndGgiLAogICAgICAgICAgICAgICAiYW5ub3RfZ2VuZV9wcm9kdWN0IikpKSRnZW5lcwoKd2FudGVkX29ydGhvc19pZHggPC0gb3J0aG9zW1siT1JUSE9MT0dTX1NQRUNJRVMiXV0gPT0gIkxlaXNobWFuaWEgbWFqb3Igc3RyYWluIEZyaWVkbGluIgpzdW0od2FudGVkX29ydGhvc19pZHgpCndhbnRlZF9vcnRob3MgPC0gb3J0aG9zW3dhbnRlZF9vcnRob3NfaWR4LCBdCndhbnRlZF9vcnRob3MgPC0gd2FudGVkX29ydGhvc1ssIGMoIkdJRCIsICJPUlRIT0xPR1NfSUQiLCAiT1JUSE9MT0dTX05BTUUiKV0KCmNvbGxhcHNlZF9vcnRob3MgPC0gd2FudGVkX29ydGhvcyAlPiUKICBncm91cF9ieShHSUQpICU+JQogIHN1bW1hcmlzZShjb2xsYXBzZWRfaWQgPSBzdHJpbmdyOjpzdHJfYyhPUlRIT0xPR1NfSUQsIGNvbGxhcHNlID0gIiA7ICIpLAogICAgICAgICAgICBjb2xsYXBzZWRfbmFtZSA9IHN0cmluZ3I6OnN0cl9jKE9SVEhPTE9HU19OQU1FLCBjb2xsYXBzZSA9ICIgOyAiKSkKYWxsX2xwX2Fubm90IDwtIG1lcmdlKGFsbF9scF9hbm5vdCwgY29sbGFwc2VkX29ydGhvcywgYnkueCA9ICJyb3cubmFtZXMiLAogICAgICAgICAgICAgICAgICAgICAgYnkueSA9ICJHSUQiLCBhbGwueCA9IFRSVUUpCnJvd25hbWVzKGFsbF9scF9hbm5vdCkgPC0gYWxsX2xwX2Fubm90W1siUm93Lm5hbWVzIl1dCmFsbF9scF9hbm5vdFtbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX2xlbmd0aHMiLCAibHBfZ28iLCAiYWxsX2xwX2Fubm90IikKYGBgCgojIExvYWQgYSBnZW5vbWUKClRoZSBmb2xsb3dpbmcgYmxvY2sgbG9hZHMgdGhlIGZ1bGwgZ2Vub21lIHNlcXVlbmNlIGZvciBwYW5hbWVuc2lzLiAgV2UKbWF5IHVzZSB0aGlzIGxhdGVyIHRvIGF0dGVtcHQgdG8gZXN0aW1hdGUgUENSIHByaW1lcnMgdG8gZGlzY2VybiBzdHJhaW5zLgoKSSBhbSBub3Qgc3VyZSBob3cgdG8gaW5jcmVhc2UgdGhlIG51bWJlciBvZiBvcGVuIGZpbGVzIGluIGEgY29udGFpbmVyLAphcyBhIHJlc3VsdCB0aGlzIGRvZXMgbm90IHdvcmsuCgpgYGB7ciBnZW5vbWUsIGV2YWw9RkFMU0V9CiMjIHRlc3RpbmdfcGFuYW1lbnNpcyA8LSBtYWtlX2V1cGF0aF9ic2dlbm9tZShlbnRyeSA9IHBhbmFtZW5zaXNfZW50cnksIGV1X3ZlcnNpb24gPSAidjQ2IikKdGVzdGluZ19wYW5hbWVuc2lzIDwtIG1ha2VfZXVwYXRoX2JzZ2Vub21lKGVudHJ5ID0gcGFuYW1lbnNpc19lbnRyeSkKbGlicmFyeShhcy5jaGFyYWN0ZXIodGVzdGluZ19wYW5hbWVuc2lzKSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpscF9nZW5vbWUgPC0gZ2V0MChhcy5jaGFyYWN0ZXIodGVzdGluZ19wYW5hbWVuc2lzKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfZ2Vub21lIiwgIm1ldGEiKQpgYGAKCiMgR2VuZXJhdGUgRXhwcmVzc2lvbnNldHMgYW5kIFNhbXBsZSBFc3RpbWF0aW9uCgpUaGUgcHJvY2VzcyBvZiBzYW1wbGUgZXN0aW1hdGlvbiB0YWtlcyB0d28gcHJpbWFyeSBpbnB1dHM6CgoxLiAgVGhlIHNhbXBsZSBzaGVldCwgd2hpY2ggY29udGFpbnMgYWxsIHRoZSBtZXRhZGF0YSB3ZSBjdXJyZW50bHkgaGF2ZSBvbiBoYW5kLAogICAgaW5jbHVkaW5nIGZpbGVuYW1lcyBmb3IgdGhlIG91dHB1dHMgb2YgIzMgYW5kICM0IGFib3ZlLgoyLiAgVGhlIGdlbmUgYW5ub3RhdGlvbnMuCgpBbiBleHByZXNzaW9uU2V0KG9yIHN1bW1hcml6ZWRFeHBlcmltZW50KSBpcyBhIGRhdGEgc3RydWN0dXJlIHVzZWQgaW4KUiB0byBleGFtaW5lIFJOQVNlcSBkYXRhLiAgSXQgaXMgY29tcHJpc2VkIG9mIGFubm90YXRpb25zLCBtZXRhZGF0YSwKYW5kIGV4cHJlc3Npb24gZGF0YS4gIEluIHRoZSBjYXNlIG9mIG91ciBwcm9jZXNzaW5nIHBpcGVsaW5lLCB0aGUKbG9jYXRpb24gb2YgdGhlIGV4cHJlc3Npb24gZGF0YSBpcyBwcm92aWRlZCBieSB0aGUgZmlsZW5hbWVzIGluIHRoZSBtZXRhZGF0YS4KCiMjIE5vdGVzCgpUaGUgZm9sbG93aW5nIHNhbXBsZXMgYXJlIG11Y2ggbG93ZXIgY292ZXJhZ2U6CgoqIFRNUkMyMDAwMgoqIFRNUkMyMDAwNgoqIFRNUkMyMDAwNwoqIFRNUkMyMDAwOAoKVGhlcmUgaXMgYSBzZXQgb2Ygc3RyYWlucyB3aGljaCBhY3F1aXJlZCByZXNpc3RhbmNlIGluIHZpdHJvLiAgVGhlc2UKYXJlIGluY2x1ZGVkIGluIHRoZSBkYXRhc2V0LCBidXQgdGhlcmUgYXJlIG5vdCBsaWtlbHkgZW5vdWdoIG9mIHRoZW0KdG8gcXVlcnkgdGhhdCBxdWVzdGlvbiBleHBsaWNpdGx5LgoKIyMgRGVmaW5lIGNvbG9ycwoKVGhlIGZvbGxvd2luZyBsaXN0IGNvbnRhaW5zIHRoZSBjb2xvcnMgd2UgaGF2ZSBjaG9zZW4gdG8gdXNlIHdoZW4KcGxvdHRpbmcgdGhlIHZhcmlvdXMgd2F5cyBvZiBkaXNjZXJuaW5nIHRoZSBkYXRhLgoKYGBge3J9CmNvbG9yX2Nob2ljZXMgPC0gbGlzdCgKICAgICJzdHJhaW4iID0gbGlzdCgKICAgICAgICAjIyAiejEuMCIgPSAiIzMzMzMzMyIsICMjIENoYW5nZWQgdGhpcyB0byAnYnJheicgdG8gbWFrZSBpdCBlYXNpZXIgdG8gZmluZCB0aGVtLgogICAgICAgICJ6Mi4wIiA9ICIjNTU1NTU1IiwKICAgICAgICAiejMuMCIgPSAiIzc3Nzc3NyIsCiAgICAgICAgInoyLjEiID0gIiM4NzQ0MDAiLAogICAgICAgICJ6Mi4yIiA9ICIjMDAwMGNjIiwKICAgICAgICAiejIuMyIgPSAiI2NjMDAwMCIsCiAgICAgICAgInoyLjQiID0gIiNkZjcwMDAiLAogICAgICAgICJ6My4yIiA9ICIjODg4ODg4IiwKICAgICAgICAiejEuMCIgPSAiI2NjMDBjYyIsCiAgICAgICAgInoxLjUiID0gIiNjYzAwY2MiLAogICAgICAgICJiMjkwNCIgPSAiI2NjMDBjYyIsCiAgICAgICAgInVua25vd24iID0gIiNjYmNiY2IiKSwKICAgICMjICJudWxsIiA9ICIjMDAwMDAwIiksCiAgICAienltbyIgPSBsaXN0KAogICAgICAiejIyIiA9ICIjMDAwMGNjIiwKICAgICAgInoyMyIgPSAiI2NjMDAwMCIpLAogICAgImNmIiA9IGxpc3QoCiAgICAgICAgImN1cmUiID0gIiMwMDZmMDAiLAogICAgICAgICJmYWlsIiA9ICIjOWRmZmEwIiwKICAgICAgICAidW5rbm93biIgPSAiI2NiY2JjYiIsCiAgICAgICAgIm5vdGFwcGxpY2FibGUiID0gIiMwMDAwMDAiKSwKICAgICJzdXNjZXB0aWJpbGl0eSIgPSBsaXN0KAogICAgICAgICJyZXNpc3RhbnQiID0gIiM4NTYzYTciLAogICAgICAgICJzZW5zaXRpdmUiID0gIiM4ZDAwMDAiLAogICAgICAgICJhbWJpZ3VvdXMiID0gIiNjYmNiY2IiLAogICAgICAgICJ1bmtub3duIiA9ICIjNTU1NTU1IikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImNvbG9yX2Nob2ljZXMiKQpgYGAKCiMgUGFyYXNpdGUtb25seSBkYXRhIHN0cnVjdHVyZQoKVGhlIGRhdGEgc3RydWN0dXJlICdscF9leHB0JyBjb250YWlucyB0aGUgZGF0YSBmb3IgYWxsIHNhbXBsZXMgd2hpY2gKaGF2ZSBoaXNhdDIgY291bnQgdGFibGVzLCBhbmQgd2hpY2ggcGFzcyBhIGZldyBpbml0aWFsIHF1YWxpdHkgdGVzdHMKKGUuZy4gdGhleSBtdXN0IGhhdmUgbW9yZSB0aGFuIDg1NTAgZ2VuZXMgd2l0aCA+MCBjb3VudHMgYW5kID41ZTYKcmVhZHMgd2hpY2ggbWFwcGVkIHRvIGEgZ2VuZSk7IGdlbmVzIHdoaWNoIGFyZSBhbm5vdGF0ZWQgd2l0aCBhIGZldwprZXkgcmVkdW5kYW50IGNhdGVnb3JpZXMgKGxlaXNobWFub2x5c2luIGZvciBleGFtcGxlKSBhcmUgYWxzbyBjdWxsZWQuCgojIyBBbGwgKGFsbW9zdCkgc2FtcGxlcwoKVGhlcmUgYXJlIGEgZmV3IG1ldGFkYXRhIGNvbHVtbnMgd2hpY2ggd2UgcmVhbGx5IHdhbnQgdG8gbWFrZSBjZXJ0YWluCmFyZSBzdGFuZGFyZGl6ZWQuCgpOb3RlOiBJIGNoYW5nZWQgdGhpcyB0byBwcmludCBib3RoIHRoZSBudW1iZXIgb2YgcmVhZHMgYW5kIGdlbmVzIGZvciByZW1vdmVkIHNhbXBsZXMuCgpgYGB7cn0Kc2FuaXRpemVfY29sdW1ucyA8LSBjKCJwYXNzYWdlbnVtYmVyIiwgImNsaW5pY2FscmVzcG9uc2UiLCAiY2xpbmljYWxjYXRlZ29yaWNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAienltb2RlbWVjYXRlZ29yaWNhbCIsICJpbmNsdWRlZCIpCmxwX2V4cHQgPC0gY3JlYXRlX2V4cHQoc2FtcGxlX3NoZWV0LAogICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGFsbF9scF9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25hbWUgPSBwYWNrYWdlX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgc2F2ZWZpbGUgPSBnbHVlKCJyZGEvdG1yYzJfbHBfZXhwdF9hbGxfcmF3LXZ7dmVyfS5yZGEiKSwKICAgICAgICAgICAgICAgICAgICAgICBpZF9jb2x1bW4gPSAiaHBnbGlkZW50aWZpZXIiLAogICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb24gPSBwYWNrYWdlX25hbWUsICMjIHRoaXMgaXMgcmVkdW5kYW50cmVkdW5kYW50CiAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAibHBhbmFtZW5zaXN2MzZoaXNhdGZpbGUiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAienltb2RlbWVjYXRlZ29yaWNhbCIsIGNvbG9ycyA9IGNvbG9yX2Nob2ljZXNbWyJzdHJhaW4iXV0pICU+JQogIHNlbWFudGljX2V4cHRfZmlsdGVyKHNlbWFudGljID0gYygiYW1hc3RpbiIsICJncDYzIiwgImxlaXNobWFub2x5c2luIiksCiAgICAgICAgICAgICAgICAgICAgICAgc2VtYW50aWNfY29sdW1uID0gImFubm90X2dlbmVfcHJvZHVjdCIpICU+JQogIHNhbml0aXplX2V4cHRfcERhdGEoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMpICU+JQogIHN1YnNldF9leHB0KHN1YnNldCA9ICJpbmNsdWRlZD09J3llcyciKSAlPiUKICBzZXRfZXhwdF9mYWN0b3JzKGNvbHVtbnMgPSBzYW5pdGl6ZV9jb2x1bW5zLCBjbGFzcyA9ICJmYWN0b3IiKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9leHB0IikKc2F2ZShsaXN0ID0gImxwX2V4cHQiLCBmaWxlID0gZ2x1ZSgicmRhL3RtcmMyX2xwX2V4cHRfYWxsX3Nhbml0aXplZC12e3Zlcn0ucmRhIikpCgp0YWJsZShwRGF0YShscF9leHB0KVtbInp5bW9kZW1lY2F0ZWdvcmljYWwiXV0pCnRhYmxlKHBEYXRhKGxwX2V4cHQpW1siY2xpbmljYWxyZXNwb25zZSJdXSkKdGFibGUocERhdGEobHBfZXhwdClbWyJjbGluaWNhbGNhdGVnb3JpY2FsIl1dKQpuY29sKGV4cHJzKGxwX2V4cHQpKQpgYGAKCiMjIFByaW50IHNhbXBsZSBJRHMgYnkgc3RhdHVzCgojIyMgQ3VyZQoKYGBge3J9CmN1cmVfaWRzIDwtIHBEYXRhKGxwX2V4cHQpW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA9PSAiY3VyZSIKcm93bmFtZXMocERhdGEobHBfZXhwdCkpW2N1cmVfaWRzXQpgYGAKCiMjIyBGYWlsCgpgYGB7cn0KZmFpbF9pZHMgPC0gcERhdGEobHBfZXhwdClbWyJjbGluaWNhbGNhdGVnb3JpY2FsIl1dID09ICJmYWlsIgpyb3duYW1lcyhwRGF0YShscF9leHB0KSlbZmFpbF9pZHNdCmBgYAoKIyMjIFVua25vd24KCmBgYHtyfQp1bmtub3duX2lkcyA8LSBwRGF0YShscF9leHB0KVtbImNsaW5pY2FsY2F0ZWdvcmljYWwiXV0gPT0gInVua25vd24iCnJvd25hbWVzKHBEYXRhKGxwX2V4cHQpKVt1bmtub3duX2lkc10KYGBgCgpBbGwgdGhlIGZvbGxvd2luZyBkYXRhIHdpbGwgZGVyaXZlIGZyb20gdGhpcyBzdGFydGluZyBwb2ludC4KCiMjIEV4dHJhY3Qgc2FtcGxlcyBmcm9tIG9ubHkgdGhlIHR3byAnY2Fub25pY2FsJyBzdHJhaW5zCgojIyMgUXVpY2sgZGl2ZXJnZW5jZQoKSGVyZSBpcyBhIHRhYmxlIG9mIG15IGN1cnJlbnQgY2xhc3NpZmllcidzIGludGVycHJldGF0aW9uIG9mIHRoZSBzdHJhaW5zLgoKYGBge3J9CnRhYmxlKHBEYXRhKGxwX2V4cHQpW1sia25udjJjbGFzc2lmaWNhdGlvbiJdXSkKYGBgCgojIyMgTWVyZ2UgMi4xLzIuMiBhbmQgMi40LzIuMwoKYGBge3J9Cm1lcmdlZF96eW1vIDwtIGxwX2V4cHQKcERhdGEobWVyZ2VkX3p5bW8pW1sienltb2RlbWUiXV0gPC0gYXMuY2hhcmFjdGVyKHBEYXRhKG1lcmdlZF96eW1vKVtbInp5bW9kZW1lY2F0ZWdvcmljYWwiXV0pCnoyMV9pZHggPC0gcERhdGEobWVyZ2VkX3p5bW8pW1sienltb2RlbWUiXV0gPT0gInoyMSIKcERhdGEobWVyZ2VkX3p5bW8pW3oyMV9pZHgsICJ6eW1vZGVtZSJdIDwtICJ6MjIiCgp6MjRfaWR4IDwtIHBEYXRhKG1lcmdlZF96eW1vKVtbInp5bW9kZW1lIl1dID09ICJ6MjQiCnBEYXRhKG1lcmdlZF96eW1vKVt6MjRfaWR4LCAienltb2RlbWUiXSA8LSAiejIzIgoKa2VlcGVycyA8LSBwRGF0YShtZXJnZWRfenltbylbWyJ6eW1vZGVtZSJdXSA9PSAiejIyIiB8CiAgcERhdGEobWVyZ2VkX3p5bW8pW1sienltb2RlbWUiXV0gPT0gInoyMyIKbWVyZ2VkX3p5bW8gPC0gbWVyZ2VkX3p5bW9bLCBrZWVwZXJzXSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAienltb2RlbWUiLCBjb2xvcnMgPSBjb2xvcl9jaG9pY2VzW1sienltbyJdXSkKYGBgCgojIEFkZCBsaWJyYXJ5IHNpemVzIGJlZm9yZSBmaWx0ZXJpbmcKCmBgYHtyfQp0YWJsZShwRGF0YShscF9leHB0KVtbImNsaW5pY2FsY2F0ZWdvcmljYWwiXV0pCnVua25vd25faWRzIDwtIHBEYXRhKGxwX2V4cHQpW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA9PSAidW5rbm93biIKcm93bmFtZXMocERhdGEobHBfZXhwdCkpW3Vua25vd25faWRzXQpmYWlsZWRfaWRzIDwtIHBEYXRhKGxwX2V4cHQpW1siY2xpbmljYWxjYXRlZ29yaWNhbCJdXSA9PSAiZmFpbCIKcm93bmFtZXMocERhdGEobHBfZXhwdCkpW2ZhaWxlZF9pZHNdCgpwcmVfbGlic2l6ZSA8LSBwbG90X2xpYnNpemUobHBfZXhwdCkKcHJlX2xpYnNpemUKCnBkZihmaWxlID0gImZpZ3VyZXMvbGlicmFyeV9zaXplX3ByZV9maWx0ZXIucGRmIiwgd2lkdGggPSAyNCwgaGVpZ2h0ID0gMTIpCnByZV9saWJzaXplJHBsb3QKZGV2Lm9mZigpCgpwcmVfbm9uemVybyA8LSBwbG90X25vbnplcm8obHBfZXhwdCkKcHJlX25vbnplcm8KcGRmKGZpbGUgPSAiZmlndXJlcy9ub256ZXJvX3ByZV9maWx0ZXIucGRmIikKcHJlX25vbnplcm8kcGxvdApkZXYub2ZmKCkKCmxwX2V4cHRfcHJlIDwtIGxwX2V4cHQKbHBfZXhwdCA8LSBzdWJzZXRfZXhwdChscF9leHB0LCBub256ZXJvID0gODU1MCkKCnBvc3Rfbm9uemVybyA8LSBwbG90X25vbnplcm8obHBfZXhwdCkKcG9zdF9ub256ZXJvCmBgYAoKIyMgRXh0cmFjdCBoaXN0b3JpY2FsIHN1c2NlcHRpYmlsaXR5IGRhdGEKCkNvbHVtbiAnUScgaW4gdGhlIHNhbXBsZSBzaGVldCwgbWFrZSBhIGNhdGVnb3JpY2FsIHZlcnNpb24gb2YgaXQgd2l0aCB0aGVzZSBwYXJhbWV0ZXJzOgoKKiAwIDw9IHggPD0gMzUgaXMgcmVzaXN0YW50CiogMzYgPD0geCA8PSA0OCBpcyBhbWJpZ3VvdXMKKiA0OSA8PSB4IGlzIHNlbnNpdGl2ZQoKTm90ZSB0aGF0IHRoZXNlIGN1dG9mZnMgYXJlIG9ubHkgdmFsaWQgZm9yIHRoZSBoaXN0b3JpY2FsIGRhdGEuICBUaGUKbmV3ZXIgc3VzY2VwdGliaWxpdHkgZGF0YSB1c2VzIGEgY3V0b2ZmIG9mIDAuNzggZm9yIHNlbnNpdGl2ZS4gIEkgd2lsbApzZXQgYW1iaWd1b3VzIHRvIDAuNSB0byAwLjc4PwoKYGBge3J9Cm1heF9yZXNpc3RfaGlzdG9yaWNhbCA8LSAwLjM1Cm1pbl9zZW5zaXRpdmVfaGlzdG9yaWNhbCA8LSAwLjQ5CgojIyAyMDIzMDU6IFJlbW92ZWQgYW1iaWd1b3VzIGNhdGVnb3J5IGZvciB0aGUgY3VycmVudCBzZXQuCm1heF9yZXNpc3RfY3VycmVudCA8LSAwLjc3Cm1pbl9zZW5zaXRpdmVfY3VycmVudCA8LSAwLjc3CmBgYAoKVGhlIHNhbml0aXplX3BlcmNlbnQoKSBmdW5jdGlvbiBzZWVrcyB0byBtYWtlIHRoZSBwZXJjZW50YWdlIHZhbHVlcwpyZWNvcmRlZCBieSBleGNlbCBtb3JlIHJlbGlhYmxlLiAgVW5mb3J0dW5hdGVseSwgc29tZXRpbWVzIGV4Y2VsCmRpc3BsYXlzIHRoZSB2YWx1ZSAnNDklJyB3aGVuIHRoZSBpbmZvcm1hdGlvbiByZWNvcmRlZCBpbiB0aGUKd29ya3NoZWV0IGlzIGFueSBvbmUgb2YgdGhlIGZvbGxvd2luZzoKCiogJzQ5JQoqIDAuNDkKKiAiMC40OSIKClRodXMsIHRoZSBmb2xsb3dpbmcgYmxvY2sgd2lsbCBzYW5pdGl6ZSB0aGVzZSBwZXJjZW50YWdlIHZhbHVlcyBpbnRvIGEKc2luZ2xlIGRlY2ltYWwgbnVtYmVyIGFuZCBtYWtlIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgZnJvbSBpdCB1c2luZwpwcmUtZGVmaW5lZCB2YWx1ZXMgZm9yIHJlc2lzdGFudC9hbWJpZ3VvdXMvc2Vuc2l0aXZlLiAgVGhpcwpjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aWxsIGJlIHN0b3JlZCBpbiBhIG5ldyBjb2x1bW46ICdzdXNfY2F0ZWdvcnlfaGlzdG9yaWNhbCcuCgpgYGB7cn0Kc3QgPC0gcERhdGEobHBfZXhwdClbWyJzdXNjZXB0aWJpbGl0eWluZmVjdGlvbnJlZHVjdGlvbjMydWdtbHNidmhpc3RvcmljYWxkYXRhIl1dCnN0YXJ0aW5nIDwtIHNhbml0aXplX3BlcmNlbnQoc3QpCnN0CnN0YXJ0aW5nCnN1c19jYXRlZ29yaWNhbCA8LSBzdGFydGluZwpuYV9pZHggPC0gaXMubmEoc3RhcnRpbmcpCnN1bShuYV9pZHgpCnN1c19jYXRlZ29yaWNhbFtuYV9pZHhdIDwtICJ1bmtub3duIgoKcmVzaXN0X2lkeCA8LSBzdGFydGluZyA8PSBtYXhfcmVzaXN0X2hpc3RvcmljYWwKc3VzX2NhdGVnb3JpY2FsW3Jlc2lzdF9pZHhdIDwtICJyZXNpc3RhbnQiCmluZGV0ZXJtaW5hbnRfaWR4IDwtIHN0YXJ0aW5nID4gbWF4X3Jlc2lzdF9oaXN0b3JpY2FsICYKICBzdGFydGluZyA8IG1pbl9zZW5zaXRpdmVfaGlzdG9yaWNhbApzdXNfY2F0ZWdvcmljYWxbaW5kZXRlcm1pbmFudF9pZHhdIDwtICJhbWJpZ3VvdXMiCnN1c2NlcHRpYmxlX2lkeCA8LSBzdGFydGluZyA+PSBtaW5fc2Vuc2l0aXZlX2hpc3RvcmljYWwKc3VzX2NhdGVnb3JpY2FsW3N1c2NlcHRpYmxlX2lkeF0gPC0gInNlbnNpdGl2ZSIKCnN1c19jYXRlZ29yaWNhbCA8LSBhcy5mYWN0b3Ioc3VzX2NhdGVnb3JpY2FsKQpwRGF0YShscF9leHB0KVtbInN1c19jYXRlZ29yeV9oaXN0b3JpY2FsIl1dIDwtIHN1c19jYXRlZ29yaWNhbAp0YWJsZShzdXNfY2F0ZWdvcmljYWwpCgp0d29fc2Fua2V5IDwtIHBsb3RfbWV0YV9zYW5rZXkoCiAgbWVyZ2VkX3p5bW8sIGZhY3RvcnMgPSBjKCJ6eW1vZGVtZSIsICJjbGluaWNhbGNhdGVnb3JpY2FsIiwgInN1c2NlcHRpYmlsaXR5IiksCiAgZHJpbGxfZG93biA9IFRSVUUsIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzKQp0d29fc2Fua2V5CmBgYAoKIyMgRXh0cmFjdCBjdXJyZW50IHN1c2NlcHRpYmlsaXR5IGRhdGEKClRoZSBzYW1lIHByb2Nlc3Mgd2lsbCBiZSByZXBlYXRlZCBmb3IgdGhlIGN1cnJlbnQgaXRlcmF0aW9uIG9mIHRoZQpzZW5zaXRpdml0eSBhc3NheSBhbmQgc3RvcmVkIGluIHRoZSAnc3VzX2NhdGVnb3J5X2N1cnJlbnQnIGNvbHVtbi4KCmBgYHtyfQpzdGFydGluZ19jdXJyZW50IDwtIHNhbml0aXplX3BlcmNlbnQocERhdGEobHBfZXhwdClbWyJzdXNjZXB0aWJpbGl0eWluZmVjdGlvbnJlZHVjdGlvbjMydWdtbHNidmN1cnJlbnRkYXRhIl1dKQpzdXNfY2F0ZWdvcmljYWxfY3VycmVudCA8LSBzdGFydGluZ19jdXJyZW50Cm5hX2lkeCA8LSBpcy5uYShzdGFydGluZ19jdXJyZW50KQpzdW0obmFfaWR4KQpzdXNfY2F0ZWdvcmljYWxfY3VycmVudFtuYV9pZHhdIDwtICJ1bmtub3duIgoKIyMgVGhlIGZvbGxvd2luZyBpcyBvbmx5IHZhbGlkIHdoZW4gd2UgaGFkIHRocmVlIGNhdGVnb3JpZXMsIHJlc2lzdGFudC9hbWJpZ3VvdXMvc2Vuc2l0aXZlCiMjIFRoZSBuZXcgY3V0b2ZmcyBkcm9wIGFtYmlndW91cy4KI3Jlc2lzdF9pZHggPC0gc3RhcnRpbmdfY3VycmVudCA8PSBtYXhfcmVzaXN0X2N1cnJlbnQKI3N1c19jYXRlZ29yaWNhbF9jdXJyZW50W3Jlc2lzdF9pZHhdIDwtICJyZXNpc3RhbnQiCiNpbmRldGVybWluYW50X2lkeCA8LSBzdGFydGluZ19jdXJyZW50ID4gbWF4X3Jlc2lzdF9jdXJyZW50ICYKIyAgc3RhcnRpbmdfY3VycmVudCA8IG1pbl9zZW5zaXRpdmVfY3VycmVudAojc3VzX2NhdGVnb3JpY2FsX2N1cnJlbnRbaW5kZXRlcm1pbmFudF9pZHhdIDwtICJhbWJpZ3VvdXMiCiNzdXNjZXB0aWJsZV9pZHggPC0gc3RhcnRpbmdfY3VycmVudCA+PSBtaW5fc2Vuc2l0aXZlX2N1cnJlbnQKI3N1c19jYXRlZ29yaWNhbF9jdXJyZW50W3N1c2NlcHRpYmxlX2lkeF0gPC0gInNlbnNpdGl2ZSIKI3N1c19jYXRlZ29yaWNhbF9jdXJyZW50IDwtIGFzLmZhY3RvcihzdXNfY2F0ZWdvcmljYWxfY3VycmVudCkKcmVzaXN0X2lkeCA8LSBzdGFydGluZ19jdXJyZW50IDw9IG1heF9yZXNpc3RfY3VycmVudApzZW5zaXRpdmVfaWR4IDwtICFyZXNpc3RfaWR4CnN1c19jYXRlZ29yaWNhbF9jdXJyZW50W3Jlc2lzdF9pZHhdIDwtICJyZXNpc3RhbnQiCnN1c19jYXRlZ29yaWNhbF9jdXJyZW50W3NlbnNpdGl2ZV9pZHhdIDwtICJzZW5zaXRpdmUiCnN1c19jYXRlZ29yaWNhbF9jdXJyZW50IDwtIGFzLmZhY3RvcihzdXNfY2F0ZWdvcmljYWxfY3VycmVudCkKCnBEYXRhKGxwX2V4cHQpW1sic3VzX2NhdGVnb3J5X2N1cnJlbnQiXV0gPC0gc3VzX2NhdGVnb3JpY2FsX2N1cnJlbnQKcERhdGEobHBfZXhwdClbWyJzdXNjZXB0aWJpbGl0eSJdXSA8LSBzdXNfY2F0ZWdvcmljYWxfY3VycmVudAp0YWJsZShzdXNfY2F0ZWdvcmljYWxfY3VycmVudCkKCmxwX3NhbmtleSA8LSBwbG90X21ldGFfc2Fua2V5KAogIGxwX2V4cHQsIGZhY3RvcnMgPSBjKCJ6eW1vZGVtZWNhdGVnb3JpY2FsIiwgImNsaW5pY2FsY2F0ZWdvcmljYWwiLCAic3VzY2VwdGliaWxpdHkiKSwKICBkcmlsbF9kb3duID0gVFJVRSwgY29sb3JfY2hvaWNlcyA9IGNvbG9yX2Nob2ljZXMpCmxwX3NhbmtleQpgYGAKCkluIG1hbnkgcXVlcmllcywgd2Ugd2lsbCBzZWVrIHRvIGNvbXBhcmUgb25seSB0aGUgdHdvIHByaW1hcnkgc3RyYWlucywKenltb2RlbWUgMi4yIGFuZCAyLjMuICBUaGUgZm9sbG93aW5nIGJsb2NrIHdpbGwgZXh0cmFjdCBvbmx5IHRob3NlCnNhbXBsZXMuCgpOb3RlOiAqSU1QT1JUQU5UKiBNYXJpYSBBZGVsYWlkYSBwcmVmZXJzIG5vdCB0byB1c2UgbHBfdHdvX3N0cmFpbnMuICBXZSBzaG91bGQgbm90IGF0IHRoaXMgdGltZQp1c2UgdGhlIG1lcmdlZCAyLjEvMi4yIGFuZCAyLjQvMi4zIGNhdGVnb3JpZXMuCgpgYGB7cn0KbHBfc3RyYWluIDwtIGxwX2V4cHQgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gc3VzX2NhdGVnb3JpY2FsX2N1cnJlbnQpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcl9jaG9pY2VzW1sic3RyYWluIl1dKQp0YWJsZShwRGF0YShscF9zdHJhaW4pW1siY29uZGl0aW9uIl1dKQpzYXZlKGxpc3QgPSAibHBfc3RyYWluIiwgZmlsZSA9IGdsdWUoInJkYS90bXJjMl9scF9zdHJhaW4tdnt2ZXJ9LnJkYSIpKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9zdHJhaW4iKQoKbHBfdHdvX3N0cmFpbnMgPC0gbWVyZ2VkX3p5bW8Kc2F2ZShsaXN0ID0gImxwX3R3b19zdHJhaW5zIiwKICAgICBmaWxlID0gZ2x1ZSgicmRhL3RtcmMyX2xwX3R3b19zdHJhaW5zLXZ7dmVyfS5yZGEiKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfdHdvX3N0cmFpbnMiKQpgYGAKCiMjIENsaW5pY2FsIG91dGNvbWUKCkNsaW5pY2FsIG91dGNvbWUgaXMgYnkgZmFyIHRoZSBtb3N0IHByb2JsZW1hdGljIGNvbXBhcmlzb24gaW4gdGhpcwpkYXRhLCBidXQgaGVyZSBpcyB0aGUgcmVjYXRlZ29yaXphdGlvbiBvZiB0aGUgZGF0YSB1c2luZyBpdDoKCmBgYHtyfQpscF9jZiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGxwX2V4cHQsIGZhY3QgPSAiY2xpbmljYWxjYXRlZ29yaWNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbImNmIl1dKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSBzdXNfY2F0ZWdvcmljYWxfY3VycmVudCkKdGFibGUocERhdGEobHBfY2YpW1siY29uZGl0aW9uIl1dKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9jZiIpCnNhdmUobGlzdCA9ICJscF9jZiIsCiAgICAgZmlsZSA9IGdsdWUoInJkYS90bXJjMl9scF9jZi12e3Zlcn0ucmRhIikpCgpscF9jZl9rbm93biA8LSBzdWJzZXRfZXhwdChscF9jZiwgc3Vic2V0ID0gImNvbmRpdGlvbiE9J3Vua25vd24nIikKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfY2Zfa25vd24iKQpzYXZlKGxpc3QgPSAibHBfY2Zfa25vd24iLAogICAgIGZpbGUgPSBnbHVlKCJyZGEvdG1yYzJfbHBfY2Zfa25vd24tdnt2ZXJ9LnJkYSIpKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9jZl9rbm93biIpCnNhdmUobGlzdCA9ICJscF9jZl9rbm93biIsCiAgICAgZmlsZSA9IGdsdWUoInJkYS90bXJjMl9scF9jZl9rbm93bi12e3Zlcn0ucmRhIikpCmBgYAoKIyMgQ3JlYXRlIGEgaGlzdG9yaWNhbCBzdXNjZXB0aWJpbGl0eSBkYXRhc2V0CgpVc2UgdGhlIGZhY3Rvcml6ZWQgdmVyc2lvbiBvZiBzdXNjZXB0aWJpbGl0eSB0byBjYXRlZ29yaXplIHRoZSBzYW1wbGVzCmJ5IHRoZSBoaXN0b3JpY2FsIGRhdGEuCgpgYGB7cn0KbHBfc3VzY2VwdGliaWxpdHlfaGlzdG9yaWNhbCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKAogIGxwX2V4cHQsIGZhY3QgPSAic3VzX2NhdGVnb3J5X2hpc3RvcmljYWwiLCBjb2xvcnMgPSBjb2xvcl9jaG9pY2VzW1sic3VzY2VwdGliaWxpdHkiXV0pICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJjbGluaWNhbGNhdGVnb3JpY2FsIikKc2F2ZShsaXN0ID0gImxwX3N1c2NlcHRpYmlsaXR5X2hpc3RvcmljYWwiLAogICAgIGZpbGUgPSBnbHVlKCJyZGEvdG1yYzJfbHBfc3VzY2VwdGliaWxpdHlfaGlzdG9yaWNhbC12e3Zlcn0ucmRhIikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX3N1c2NlcHRpYmlsaXR5X2hpc3RvcmljYWwiKQpgYGAKCiMjIENyZWF0ZSBhIGN1cnJlbnQgc3VzY2VwdGliaWxpdHkgZGF0YXNldAoKVXNlIHRoZSBmYWN0b3JpemVkIHZlcnNpb24gb2Ygc3VzY2VwdGliaWxpdHkgdG8gY2F0ZWdvcml6ZSB0aGUgc2FtcGxlcwpieSB0aGUgaGlzdG9yaWNhbCBkYXRhLgoKVGhpcyB3aWxsIGxpa2VseSBiZSBvdXIgY2Fub25pY2FsIHN1c2NlcHRpYmlsaXR5IGRhdGFzZXQsIHNvIEkgd2lsbApyZW1vdmUgdGhlIHN1ZmZpeCBhbmQganVzdCBjYWxsIGl0ICdscF9zdXNjZXB0aWJpbGl0eScuCgpgYGB7cn0KbHBfc3VzY2VwdGliaWxpdHkgPC0gc2V0X2V4cHRfY29uZGl0aW9ucygKICBscF9leHB0LCBmYWN0ID0gInN1c19jYXRlZ29yeV9jdXJyZW50IiwgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbInN1c2NlcHRpYmlsaXR5Il1dKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiY2xpbmljYWxjYXRlZ29yaWNhbCIpCnNhdmUobGlzdCA9ICJscF9zdXNjZXB0aWJpbGl0eSIsCiAgICAgZmlsZSA9IGdsdWUoInJkYS90bXJjMl9scF9zdXNjZXB0aWJpbGl0eS12e3Zlcn0ucmRhIikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX3N1c2NlcHRpYmlsaXR5IikKYGBgCgojIyBQdWxsIG91dCBvbmx5IHRoZSBzYW1wbGVzIHdpdGggdHdvIHp5bW9kZW1lcwoKSSB0aGluayB0aGlzIGlzIHJlZHVuZGFudCB3aXRoIGEgcHJldmlvdXMgYmxvY2ssIGJ1dCBJIGFtIGxlYXZpbmcgaXQKdW50aWwgSSBhbSBjZXJ0YWluIHRoYXQgaXQgaXMgbm90IHJlcXVpcmVkIGluIGEgZm9sbG93aW5nIGRvY3VtZW50LgoKTm90ZTogKklNUE9SVEFOVCogVGhpcyBpcyB0aGUgc2V0IE1hcmlhIEFkZWxpYWRhIHByZWZlcnMgdG8gdXNlLgoKYGBge3Igenltb19kZSwgZmlnLnNob3c9ImhpZGUifQpscF96eW1vIDwtIHN1YnNldF9leHB0KGxwX2V4cHQsIHN1YnNldCA9ICJjb25kaXRpb249PSd6Mi4yJ3xjb25kaXRpb249PSd6Mi4zJyIpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX3p5bW8iKQpzYXZlKGxpc3QgPSAibHBfenltbyIsCiAgICAgZmlsZSA9IGdsdWUoInJkYS90bXJjMl9scF96eW1vLXZ7dmVyfS5yZGEiKSkKYGBgCgojIFZhcmlhbnQgZGF0YSB1c2luZyBwYXJhc2l0ZSBSTkFTZXEgcmVhZHMKClRoZSBmb2xsb3dpbmcgc2VjdGlvbiB3aWxsIGNyZWF0ZSBzb21lIGluaXRpYWwgZGF0YSBzdHJ1Y3R1cmVzIG9mIHRoZQpvYnNlcnZlZCB2YXJpYW50cyBpbiB0aGUgcGFyYXNpdGUgc2FtcGxlcy4gIFRoaXMgd2lsbCBpbmNsdWRlIHNvbWUgb2YKb3VyIDIwMTYgc2FtcGxlcyBmb3Igc29tZSBjbGFzc2lmaWNhdGlvbiBxdWVyaWVzLgoKIyMgVGhlIDIwMTYgdmFyaWFudCBkYXRhCgpJIGNoYW5nZWQgYW5kIGltcHJvdmVkIHRoZSBtYXBwaW5nIGFuZCB2YXJpYW50IGRldGVjdGlvbiBtZXRob2RzIGZyb20Kd2hhdCB3ZSB1c2VkIGZvciB0aGUgMjAxNiBkYXRhLiAgU28gc29tZSBzbWFsbCBjaGFuZ2VzIHdpbGwgYmUKcmVxdWlyZWQgdG8gbWVyZ2UgdGhlbS4KCmBgYHtyIG9sZG5ld192YXJpYW50cywgZXZhbD1GQUxTRX0KbHBfcHJldmlvdXMgPC0gY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvdG1yYzJfc2FtcGxlc18yMDE5MTIwMy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidG9waGF0MmZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYXZlZmlsZSA9IGdsdWUoInJkYS9scF9wcmV2aW91cy12e3Zlcn0ucmRhIikpCnR0IDwtIGxwX3ByZXZpb3VzJGV4cHJlc3Npb25zZXQKcm93bmFtZXModHQpIDwtIGdzdWIocGF0dGVybiA9ICJeZXhvbl8iLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gcm93bmFtZXModHQpKQpyb3duYW1lcyh0dCkgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLjEkIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHJvd25hbWVzKHR0KSkKcm93bmFtZXModHQpIDwtIGdzdWIocGF0dGVybiA9ICJcXC0xJCIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSByb3duYW1lcyh0dCkpCmxwX3ByZXZpb3VzJGV4cHJlc3Npb25zZXQgPC0gdHQKcm0odHQpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX3ByZXZpb3VzIikKYGBgCgojIyBDcmVhdGUgdGhlIFNOUCBleHByZXNzaW9uc2V0CgpUaGUgY291bnRfZXhwdF9zbnBzKCkgZnVuY3Rpb24gdXNlcyBvdXIgZXhwcmVzc2lvbnNldCBkYXRhIGFuZCBhCm1ldGFkYXRhIGNvbHVtbiBpbiBvcmRlciB0byBleHRyYWN0IHRoZSBtcGlsZXVwIG9yIGZyZWViYXllcy1iYXNlZAp2YXJpYW50IGNhbGxzIGFuZCBjcmVhdGUgbWF0cmljZXMgb2YgdGhlIGxpa2VsaWhvb2QgdGhhdCBlYWNoCnBvc2l0aW9uLXBlci1zYW1wbGUgaXMgaW4gZmFjdCBhIHZhcmlhbnQuCgpUaGVyZSBpcyBhbiBpbXBvcnRhbnQgY2F2ZWF0IGhlcmUgd2hpY2ggY2hhbmdlZCBvbiAyMDIzMDE6ICBJIHdhcwppbnRlcnByZXRpbmcgdXNpbmcgdGhlIFBBSVJFRCB0YWcsIHdoaWNoIGlzIG9ubHkgdXNlZCBmb3IsCnVuc3VycHJpc2luZ2x5LCBwYWlyZWQtZW5kIHNhbXBsZXMuICBBIGNvdXBsZSBzYW1wbGVzIGFyZSBub3QgcGFpcmVkCmFuZCBzbyB3ZXJlIGZhaWxpbmcgc2lsZW50bHkuICBUaGUgUUEgdGFnIGxvb2tzIGxpa2UgaXQgaXMgbW9yZQphcHByb3ByaWF0ZSBhbmQgc2hvdWxkIHdvcmsgYWNyb3NzIGJvdGggdHlwZXMuICBPbmUgd2F5IHRvIGZpbmQgb3V0LCBJCmFtIHNldHRpbmcgaXQgaGVyZSBhbmQgd2lsbCBsb29rIHRvIHNlZSBpZiB0aGUgcmVzdWx0cyBtYWtlIG1vcmUgc2Vuc2UKZm9yIG15IHRlc3Qgc2FtcGxlcyAoVE1SQzIwMDEsIFRNUkMyMDA1LCBUTVJDMjAwNykuCgpgYGB7cn0KIyMgVGhlIG5leHQgbGluZSBkcm9wcyB0aGUgc2FtcGxlcyB3aGljaCBhcmUgbWlzc2luZyB0aGUgU05QIHBpcGVsaW5lLgpscF9zbnAgPC0gc3Vic2V0X2V4cHQobHBfZXhwdCwgc3Vic2V0ID0gIiFpcy5uYShwRGF0YShscF9leHB0KVtbJ2ZyZWViYXllc3N1bW1hcnknXV0pIikKCmxwX3NucF9zdWZmaWNpZW50IDwtIHN1YnNldF9leHB0KGxwX3NucCwgc3Vic2V0ID0gInJvd25hbWVzIT0nVE1SQzIwMDgyJyIpCmxwX3NucF9vbmx5MjJfMjNfcmVmIDwtIHN1YnNldF9leHB0KGxwX3NucCwgc3Vic2V0ID0gInp5bW9kZW1lcmVmZXJlbmNlPT0nejIuMid8enltb2RlbWVyZWZlcmVuY2U9PSd6Mi4zJyIpICU+JQogIHN1YnNldF9leHB0KHN1YnNldCA9ICJyb3duYW1lcyE9J1RNUkMyMDA4MiciKQpscF9zbnBfMjJfMjNfbWwgPC0gc3Vic2V0X2V4cHQobHBfc25wLCBzdWJzZXQgPSAia25udjJjbGFzc2lmaWNhdGlvbj09J3oyMid8a25udjJjbGFzc2lmaWNhdGlvbj09J3oyMyciKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQgPSAicm93bmFtZXMhPSdUTVJDMjAwODInIikKCm5ld19zbnBzX3N1ZmZpY2llbnQgPC0gY291bnRfZXhwdF9zbnBzKGxwX3NucF9zdWZmaWNpZW50LCBhbm5vdF9jb2x1bW4gPSAiZnJlZWJheWVzc3VtbWFyeSIsIHNucF9jb2x1bW4gPSAiUUEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkZXIgPSAicmVhZHIiKQpuZXdfc25wc19vbmx5MjJfMjNfcmVmX3N1ZiA8LSBjb3VudF9leHB0X3NucHMobHBfc25wX29ubHkyMl8yM19yZWYsIGFubm90X2NvbHVtbiA9ICJmcmVlYmF5ZXNzdW1tYXJ5Iiwgc25wX2NvbHVtbiA9ICJRQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkZXIgPSAicmVhZHIiKQpuZXdfc25wc18yMl8yM19tbF9zdWYgPC0gY291bnRfZXhwdF9zbnBzKGxwX3NucF8yMl8yM19tbCwgYW5ub3RfY29sdW1uID0gImZyZWViYXllc3N1bW1hcnkiLCBzbnBfY29sdW1uID0gIlFBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkZXIgPSAicmVhZHIiKQoKIyMgTGV0cyBzZWUgaWYgd2UgZ2V0IG51bWJlcnMgd2hpY2ggbWFrZSBzZW5zZS4Kc3VtbWFyeShleHBycyhuZXdfc25wcylbWyJ0bXJjMjAwMDEiXV0pICAjIyBNeSB3ZWlyZG8gc2FtcGxlCnN1bW1hcnkoZXhwcnMobmV3X3NucHMpW1sidG1yYzIwMDcyIl1dKSAgIyMgQW5vdGhlciBzYW1wbGUgY2hvc2VuIGF0IHJhbmRvbQpzdW1tYXJ5KGV4cHJzKG5ld19zbnBzKVtbInRtcmMyMDAyMSJdXSkgICMjIEFub3RoZXIgc2FtcGxlIGNob3NlbiBhdCByYW5kb20KIyMgTm93IHRoYXQgd2UgYXJlIHJlYXNvbmFibHkgY29uZmlkZW50IHRoYXQgdGhpbmdzIG1ha2UgbW9yZSBzZW5zZSwgbGV0cyBzYXZlIGFuZCBtb3ZlIG9uLi4uCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgIm5ld19zbnBzIiwgImxwX3NucCIpCgp0dCA8LSBub3JtYWxpemVfZXhwdChuZXdfc25wcywgdHJhbnNmb3JtID0gImxvZzIiKQpwbG90X2JveHBsb3QodHQpCmBgYAoKTm93IGxldCB1cyBwdWxsIGluIHRoZSAyMDE2IGRhdGEuCgpgYGB7ciBtZXJnZV9uZXdfb2xkLCBldmFsPUZBTFNFfQpvbGRfc25wcyA8LSBjb3VudF9leHB0X3NucHMobHBfcHJldmlvdXMsIGFubm90X2NvbHVtbiA9ICJiY2Z0YWJsZSIsIHNucF9jb2x1bW4gPSAyKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJvbGRfc25wcyIpCgpzYXZlKGxpc3QgPSAibHBfc25wIiwKICAgICBmaWxlID0gZ2x1ZSgicmRhL2xwX3NucC12e3Zlcn0ucmRhIikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX3NucCIpCnNhdmUobGlzdCA9ICJuZXdfc25wcyIsCiAgICAgZmlsZSA9IGdsdWUoInJkYS9uZXdfc25wcy12e3Zlcn0ucmRhIikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgIm5ld19zbnBzIikKc2F2ZShsaXN0ID0gIm9sZF9zbnBzIiwKICAgICBmaWxlID0gZ2x1ZSgicmRhL29sZF9zbnBzLXZ7dmVyfS5yZGEiKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAib2xkX3NucHMiKQoKbm9uemVyb19zbnBzIDwtIGV4cHJzKG5ld19zbnBzKSAhPSAwCmNvbFN1bXMobm9uemVyb19zbnBzKQpgYGAKCiMjIENvbWJpbmUgdGhlIHByZXZpb3VzIGFuZCBjdXJyZW50IGRhdGEKCkFzIGZhciBhcyBJIGNhbiB0ZWxsLCBmcmVlYmF5ZXMgYW5kIG1waWxldXAgYXJlIHJlYXNvbmFibHkgc2ltaWxhciBpbgp0aGVpciBzZW5zaXRpdml0eS9zcGVjaWZpY2l0eTsgc28gY29tYmluaW5nIHRoZSB0d28gZGF0YXNldHMgbGlrZSB0aGlzCmlzIGV4cGVjdGVkIHRvIHdvcmsgd2l0aCBtaW5pbWFsIHByb2JsZW1zLiAgVGhlIG1vc3QgbGlrZWx5IHByb2JsZW0gaXMKdGhhdCBteSBtcGlsZXVwLWJhc2VkIHBpcGVsaW5lIGlzIHVuYWJsZSB0byBoYW5kbGUgaW5kZWxzLgoKYGBge3IgY29tYmluZV9vbGRfc25wcywgZXZhbD1GQUxTRX0KIyMgTXkgb2xkX3NucHMgaXMgdXNpbmcgYW4gb2xkZXIgYW5ub3RhdGlvbiBpbmNvcnJlY3RseSwgc28gZml4IGl0IGhlcmU6CiNhbm5vdGF0aW9uKG9sZF9zbnBzKSA8LSBhbm5vdGF0aW9uKG5ld19zbnBzKQpib3RoX3NucHMgPC0gY29tYmluZV9leHB0cyhuZXdfc25wcywgb2xkX3NucHMpCnNhdmUobGlzdCA9ICJib3RoX3NucHMiLAogICAgIGZpbGUgPSBnbHVlKCJyZGEvYm90aF9zbnBzLXZ7dmVyfS5yZGEiKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAiYm90aF9zbnBzIikKYGBgCgojIFN1YmNsYWRlIG1hbnVhbCBpbnRlcnByZXRhdGlvbgoKSSBhbSB0YWtpbmcgYSBoZWF0bWFwIGZyb20gb3VyIHZhcmlhbnQgZGF0YSBhbmQgbWFudWFsbHkgaWRlbnRpZnlpbmcgc2FtcGxlIGdyb3Vwcy4KCiogQTogVE1SQzIwMDI1LCBUTVJDMjAwMjcsIFRNUkMyMDAyOAoqIEI6IGhwZ2wwNjQxLCBocGdsMDI0NywgaHBnbDA2MzEsIGhwZ2wwNjU4LCBjbG9zZSB0byBBCiogQzogVE1SQzIwMDA4LCBUTVJDMjAwMDcsIFRNUkMyMDAwMSwgVE1SQzIwMDA1LCBocGdsMDMxOCwgVE1SQzIwMDEyCiogRDogaHBnbDA2NDMsIGhwZ2wwMzE2LCBocGdsMDMyMCwgaHBnbDA2NDEsIGNsb3NlIHRvIEMKKiBFOiBUTVJDMjAwMzIsIFRNUkMyMDA2MQoqIEY6IFRNUkMyMDA0MCwgVE1SQzIwMDM2LCBocGdsMDI0NSwgVE1SQzIwMTAzLCBUTVJDMjAwOTMsIFRNUkMyMDA0NSwKICAgICBUTVJDMjAwNDEsIFRNUkMyMDA3MiwgVE1SQzIwMDQ2LCBUTVJDMjAwNTcsIFRNUkMyMDA5NywgVE1SQzIwMDg0LAogICAgIGNsb3NlIHRvIEUKKiBHOiBocGdsMDYzMiwgaHBnbDA2NTIsIGhwZ2wwMjQ4LCBocGdsMDY1OQoqIEg6IGhwZ2wwNjU0LCBocGdsMDYzNCwgaHBnbDAyNDMsIGhwZ2wwMjQzLCBjbG9zZXN0IHRvIEcKKiBJOiBocGdsMDI0MiwgaHBnbDAzMjIsIGhwZ2wwNjM2LCBocGdsMDY2MywgaHBnbDA2MzgsIGNsb3NlIHRvIEgKKiBKOiBUTVJDMjAwMTcsIFRNUkMyMDAzMywgVE1SQzIwMDUzLCBUTVJDMjAwNjMsIFRNUkMyMDA1NiwgVE1SQzIwMDc0LAogICAgIFRNUkMyMDA1NSwgVE1SQzIwMDIyLCBUTVJDMjAwMjYsIFRNUkMyMDA4MywgVE1SQzIwMDc3LCBUTVJDMjAwNjAKKiBLOiBUTVJDMjAwNTAsIFRNUkMyMDA0MiwgVE1SQzIwMDc4LCBUTVJDMjAwNDksIFRNUkMyMDA2OSwgVE1SQzIwMDQ0LAogICAgIGNsb3NlIHRvIEoKKiBMOiBUTVJDMjAwNzYsIFRNUkMyMDAyNCwgVE1SQzIwMDkKKiBNOiBUTVJDMjAwMTksIFRNUkMyMDAyMCwgVE1SQzIwMDMxLCBUTVJDMjAwMTQsIFRNUkMyMDAxMSwgY2xvc2UgdG8gTAoqIE46IFRNUkMyMDA5NiwgVE1SQzIwMDgxLCBUTVJDMjAxMTAsIFRNUkMyMDA5MiwgVE1SQzIwMDg4LCBUTVJDMjAxMDEsCiAgICAgVE1SQzIwMTA2LCBUTVJDMjAwOTEsIFRNUkMyMDEwOSwgVE1SQzIwMDg3LCBUTVJDMjAwODYsIGNsb3NlaXNoCiAgICAgdG8gTQoqIE86IFRNUkMyMDA5NSwgVE1SQzIwMDE2LCBUTVJDMjAwMTgsIHF1aXRlIGZhciBmcm9tIGV2ZXJ5b25lCiogUDogVE1SQzIwMDgyLCBUTVJDMjAwNzUsIHByZXR0eSBzZXBhcmF0ZSB0b28KKiBROiBocGdsMDI0NiwgaHBnbDA2NTMsIGhwZ2wwNjMzLCBocGdsMDI0NCwgaHBnbDA2MzUsIGhwZ2wwNjU1LAogICAgIGhwZ2wwNjM5LCBocGdsMDY2MgoqIFI6IFRNUkMyMDA1OSwgVE1SQzIwMDg5LCBUTVJDMjAwMjEsIFRNUkMyMDA0OCwgVE1SQzIwMDY3CiogUzogVE1SQzIwMDEzLCBUTVJDMjAwMTAsIFRNUkMyMDAzNywgVE1SQzIwMDY2LCBUTVJDMjAwNjIsIFRNUkMyMDAzOCwKICAgICBjbG9zZSB0byBSCiogVDogVE1SQzIwMDE1LCBUTVJDMjAxMDgsIFRNUkMyMDA5OSwgVE1SQzIwMTAyLCBUTVJDMjAwODUsIFRNUkMyMDA5MCwKICAgICBUTVJDMjAxMDQsIFRNUkMyMDA5OCwgVE1SQzIwMTAwLCBUTVJDMjAxMDcKKiBVOiBUTVJDMjAwNDcsIFRNUkMyMDA2OCwgVE1SQzIwMDgwLCBUTVJDMjAxMDUsIFRNUkMyMDA5NCwgVE1SQzIwMDY1LAogICAgIFRNUkMyMDA3MSwgVE1SQzIwMDY0LCBUTVJDMjAwNDMsIFRNUkMyMDA3MCwgVE1SQzIwMDYyLCBUTVJDMjAwNTEsCiAgICAgVE1SQzIwMDc5LCBUTVJDMjAwNzMsIFRNUkMyMDA1OCwgVE1SQzIwMDU0CgojIE1hY3JvcGhhZ2UgZGF0YQoKQWxsIG9mIHRoZSBhYm92ZSBmb2N1c2VkIGVudGlyZSBvbiB0aGUgcGFyYXNpdGUgc2FtcGxlcywgbm93IGxldCB1cwpwdWxsIHVwIHRoZSBtYWNyb3BoYWdlIGluZmVjdGVkIHNhbXBsZXMuICBUaGlzIHdpbGwgY29tcHJpc2UgdHdvCmRhdGFzZXRzLCBvbmUgb2YgdGhlIGh1bWFuIGFuZCBvbmUgb2YgdGhlIHBhcmFzaXRlLgoKIyMgTWFjcm9waGFnZSBob3N0IGRhdGEKClRoZSBtZXRhZGF0YSBmb3IgdGhlIG1hY3JvcGhhZ2Ugc2FtcGxlcyBjb250YWlucyBhIGNvdXBsZSBvZiBjb2x1bW5zCmZvciBtYXBwZWQgaHVtYW4gYW5kIHBhcmFzaXRlIHJlYWRzLiAgV2Ugd2lsbCB0aGVyZWZvcmUgdXNlIHRoZW0Kc2VwYXJhdGVseSB0byBjcmVhdGUgdHdvIGV4cHJlc3Npb25zZXRzLCBvbmUgZm9yIGVhY2ggc3BlY2llcy4KCmBgYHtyfQpoc19hbm5vdCA8LSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoeWVhciA9ICIyMDIwIiwgbW9udGggPSA0KQpoc19hbm5vdCA8LSBoc19hbm5vdFtbImFubm90YXRpb24iXV0KaHNfYW5ub3RbWyJ0cmFuc2NyaXB0Il1dIDwtIHBhc3RlMChyb3duYW1lcyhoc19hbm5vdCksICIuIiwgaHNfYW5ub3RbWyJ0cmFuc2NyaXB0X3ZlcnNpb24iXV0pCnJvd25hbWVzKGhzX2Fubm90KSA8LSBtYWtlLm5hbWVzKGhzX2Fubm90W1siZW5zZW1ibF9nZW5lX2lkIl1dLCB1bmlxdWUgPSBUUlVFKQpyb3duYW1lcyhoc19hbm5vdCkgPC0gcGFzdGUwKCJnZW5lOiIsIHJvd25hbWVzKGhzX2Fubm90KSkKdHhfZ2VuZV9tYXAgPC0gaHNfYW5ub3RbLCBjKCJ0cmFuc2NyaXB0IiwgImVuc2VtYmxfZ2VuZV9pZCIpXQoKc2FuaXRpemVfY29sdW1ucyA8LSBjKCJkcnVnIiwgIm1hY3JvcGhhZ2V0cmVhdG1lbnQiLCAibWFjcm9waGFnZXp5bW9kZW1lIikKbWFjcl9hbm5vdCA8LSBoc19hbm5vdApyb3duYW1lcyhtYWNyX2Fubm90KSA8LSBnc3ViKHggPSByb3duYW1lcyhtYWNyX2Fubm90KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl5nZW5lOiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIikKaHNfbWFjcm9waGFnZSA8LSBjcmVhdGVfZXhwdCgKICAgIG1hY3JvcGhhZ2Vfc2hlZXQsCiAgICBnZW5lX2luZm8gPSBtYWNyX2Fubm90LAogICAgZmlsZV9jb2x1bW4gPSAiaGczODEwMGhpc2F0ZmlsZSIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJtYWNyb3BoYWdldHJlYXRtZW50IikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gIm1hY3JvcGhhZ2V6eW1vZGVtZSIpICU+JQogIHNhbml0aXplX2V4cHRfcERhdGEoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMpICU+JQogIHN1YnNldF9leHB0KG5vbnplcm8gPSAxMjAwMCkKZml4ZWRfZ2VuZW5hbWVzIDwtIGdzdWIoeCA9IHJvd25hbWVzKGV4cHJzKGhzX21hY3JvcGhhZ2UpKSwgcGF0dGVybiA9ICJeZ2VuZToiLAogICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQpoc19tYWNyb3BoYWdlIDwtIHNldF9leHB0X2dlbmVuYW1lcyhoc19tYWNyb3BoYWdlLCBpZHMgPSBmaXhlZF9nZW5lbmFtZXMpCnRhYmxlKHBEYXRhKGhzX21hY3JvcGhhZ2UpJGNvbmRpdGlvbikKCiMjIFRoZSBmb2xsb3dpbmcgMyBsaW5lcyB3ZXJlIGNvcHkvcGFzdGVkIHRvIGRhdGFzdHJ1Y3R1cmVzIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCBzb29uLgpub3N0cmFpbiA8LSBpcy5uYShwRGF0YShoc19tYWNyb3BoYWdlKVtbInN0cmFpbmlkIl1dKQpwRGF0YShoc19tYWNyb3BoYWdlKVtub3N0cmFpbiwgInN0cmFpbmlkIl0gPC0gIm5vbmUiCgpwRGF0YShoc19tYWNyb3BoYWdlKVtbInN0cmFpbl96eW1vIl1dIDwtIHBhc3RlMCgicyIsIHBEYXRhKGhzX21hY3JvcGhhZ2UpW1sic3RyYWluaWQiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfIiwgcERhdGEoaHNfbWFjcm9waGFnZSlbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCnVuaW5mZWN0ZWQgPC0gcERhdGEoaHNfbWFjcm9waGFnZSlbWyJzdHJhaW5fenltbyJdXSA9PSAic25vbmVfbm9uZSIKcERhdGEoaHNfbWFjcm9waGFnZSlbdW5pbmZlY3RlZCwgInN0cmFpbl96eW1vIl0gPC0gInVuaW5mZWN0ZWQiCgpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJoc19tYWNyb3BoYWdlIikKYGBgCgpGaW5hbGx5LCBzcGxpdCBvZmYgdGhlIFU5Mzcgc2FtcGxlcy4KCmBgYHtyfQpoc191OTM3IDwtIHN1YnNldF9leHB0KGhzX21hY3JvcGhhZ2UsIHN1YnNldCA9ICJ0eXBlb2ZjZWxscyE9J01hY3JvcGhhZ2VzJyIpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImhzX3U5MzciKQpgYGAKCiMjIE1hY3JvcGhhZ2UgcGFyYXNpdGUgZGF0YQoKSW4gdGhlIHByZXZpb3VzIGJsb2NrLCB3ZSB1c2VkIGEgbmV3IGludm9jYXRpb24gb2YgZW5zZW1ibC1kZXJpdmVkCmFubm90YXRpb24gZGF0YSwgdGhpcyB0aW1lIHdlIGNhbiBqdXN0IHVzZSBvdXIgZXhpc3RpbmcgcGFyYXNpdGUgZ2VuZQphbm5vdGF0aW9ucy4KCmBgYHtyfQpscF9tYWNyb3BoYWdlIDwtIGNyZWF0ZV9leHB0KG1hY3JvcGhhZ2Vfc2hlZXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAibHBhbmFtZW5zaXN2MzZoaXNhdGZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGFsbF9scF9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYXZlZmlsZSA9IGdsdWUoInJkYS9scF9tYWNyb3BoYWdlLXZ7dmVyfS5yZGEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uID0gIm9yZy5McGFuYW1lbnNpcy5NSE9NQ09MODFMMTMudjQ2LmVnLmRiIikgJT4lCnNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJtYWNyb3BoYWdlenltb2RlbWUiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAibWFjcm9waGFnZXRyZWF0bWVudCIpCgp1bmZpbHRfd3JpdHRlbiA8LSB3cml0ZV9leHB0KAogIGxwX21hY3JvcGhhZ2UsCiAgZXhjZWwgPSBnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL3t2ZXJ9L3JlYWRfY291bnRzL2xwX21hY3JvcGhhZ2VfcmVhZHNfdW5maWx0ZXJlZC12e3Zlcn0ueGxzeCIpKQoKbHBfbWFjcm9waGFnZV9maWx0IDwtIHN1YnNldF9leHB0KGxwX21hY3JvcGhhZ2UsIG5vbnplcm8gPSAyNTAwKSAlPiUKICBzZW1hbnRpY19leHB0X2ZpbHRlcihzZW1hbnRpYyA9IGMoImFtYXN0aW4iLCAiZ3A2MyIsICJsZWlzaG1hbm9seXNpbiIpLAogICAgICAgICAgICAgICAgICAgICAgIHNlbWFudGljX2NvbHVtbiA9ICJhbm5vdF9nZW5lX3Byb2R1Y3QiKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9tYWNyb3BoYWdlIiwgImxwX21hY3JvcGhhZ2VfZmlsdCIpCmZpbHRfd3JpdHRlbiA8LSB3cml0ZV9leHB0KGxwX21hY3JvcGhhZ2VfZmlsdCwKICBleGNlbCA9IGdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUve3Zlcn0vcmVhZF9jb3VudHMvbHBfbWFjcm9waGFnZV9yZWFkc19maWx0ZXJlZC12e3Zlcn0ueGxzeCIpKQpscF9tYWNyb3BoYWdlIDwtIGxwX21hY3JvcGhhZ2VfZmlsdAoKbHBfbWFjcm9waGFnZV9ub3NiIDwtIHN1YnNldF9leHB0KGxwX21hY3JvcGhhZ2UsIHN1YnNldCA9ICJiYXRjaCE9J2luZl9zYiciKQpscF9ub3NiX3dyaXRlIDwtIHdyaXRlX2V4cHQoCiAgbHBfbWFjcm9waGFnZV9ub3NiLAogIGV4Y2VsID0gZ2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS97dmVyfS9yZWFkX2NvdW50cy9scF9tYWNyb3BoYWdlX25vc2JfcmVhZHMtdnt2ZXJ9Lnhsc3giKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfbWFjcm9waGFnZV9ub3NiIikKCnNwZWMgPC0gbWFrZV9ybmFzZXFfc3BlYygpCnRlc3QgPC0gc20oZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEobWFjcm9waGFnZV9zaGVldCwgc3BlY2lmaWNhdGlvbiA9IHNwZWMpKQpgYGAKCiMgUGxvdCBTTCBSZWFkcyBvbiBhIHBlciBjb25kaXRpb24gYmFzaXMKCmBgYHtyfQpscF9tZXRhIDwtIHBEYXRhKGxwX21hY3JvcGhhZ2UpCmxwX21ldGFbWyJzbHZzcmVhZHNfbG9nIl1dIDwtIGxvZzEwKGxwX21ldGFbWyJzbHZzcmVhZHMiXV0pCmluZl92YWx1ZXMgPC0gaXMuaW5maW5pdGUobHBfbWV0YVtbInNsdnNyZWFkc19sb2ciXV0pCmxwX21ldGFbaW5mX3ZhbHVlcywgInNsdnNyZWFkc19sb2ciXSA8LSAtMTAKCmNvbG9yX3ZlY3RvciA8LSBhcy5jaGFyYWN0ZXIoY29sb3JfY2hvaWNlc1tbInN0cmFpbiJdXSkKbmFtZXMoY29sb3JfdmVjdG9yKSA8LSBuYW1lcyhjb2xvcl9jaG9pY2VzW1sic3RyYWluIl1dKQpjb2xvcl92ZWN0b3IgPC0gY29sb3JfdmVjdG9yW2MoInoyLjIiLCAiejIuMyIsICJ1bmtub3duIildCm5hbWVzKGNvbG9yX3ZlY3RvcikgPC0gYygiejIuMiIsICJ6Mi4zIiwgIm5vbmUiKQpzbF92aW9saW4gPC0gZ2dwbG90KGxwX21ldGEsCiAgICAgICAgICAgICAgICAgICAgYWVzKHggPSAuZGF0YVtbImNvbmRpdGlvbiJdXSwgeSA9IC5kYXRhW1sic2x2c3JlYWRzX2xvZyJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IC5kYXRhW1siY29uZGl0aW9uIl1dKSkgKwogIGdlb21fdmlvbGluKCkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfdmVjdG9yKQpzbF92aW9saW4KCmdnc3RhdHNwbG90OjpnZ2JldHdlZW5zdGF0cyhscF9tZXRhLCB4ID0gImNvbmRpdGlvbiIsIHkgPSAic2x2c3JlYWRzX2xvZyIpCmBgYAoKIyBNYWtlIGEgc2lsbHkgcGxvaWR5IHBsb3QKCkkgd2FudCB0byBtYWtlIGFuIGVzdGltYXRlIG9mIHBsb2lkeSB1c2luZyB0cmFuc2NyaXB0b21pYyBkYXRhLiAgVGhpcwppcyBieSBkZWZpbml0aW9uIGEgZm9vbGQncyBlcnJhbmQsIGJ1dCBJIHRoaW5rIGl0IG1pZ2h0IHdvcmsuCgpgYGB7cn0KbHBfcnBrbSA8LSBub3JtYWxpemVfZXhwdChscF9leHB0LCBjb252ZXJ0ID0gInJwa20iLCBmaWx0ZXIgPSBUUlVFKQoKIyMgRXhjbHVkZSBzY2FmZm9sZHMKdW53YW50ZWQgPC0gZ3JlcGwocGF0dGVybiA9ICJTQ0FGIiwgeCA9IGZEYXRhKGxwX3Jwa20pW1siY2hyb21vc29tZSJdXSkKIyMgSSB0aGluayBteSBzdWJzZXQgbG9naWMgaXMgYmFjd2FyZHMuLi4KbHBfd2FudGVkIDwtIGxwX3Jwa21bIXVud2FudGVkLCBdCgpzdW1tYXJ5X2RmIDwtIGFzLmRhdGEuZnJhbWUoZXhwcnMobHBfd2FudGVkKSkKc3VtbWFyeV9kZltbImdlbmVfbWVhbiJdXSA8LSByb3dNZWFucyhzdW1tYXJ5X2RmLCBuYS5ybSA9IFRSVUUpCnN1bW1hcnlfZGZbWyJjaHJvbW9zb21lIl1dIDwtIGZEYXRhKGxwX3dhbnRlZClbWyJjaHJvbW9zb21lIl1dCnN1bW1hcnlfZGYgPC0gc3VtbWFyeV9kZlssIGMoImdlbmVfbWVhbiIsICJjaHJvbW9zb21lIildICU+JQogIGdyb3VwX2J5KGNocm9tb3NvbWUpICU+JQogIHN1bW1hcml6ZShjaHJfbWVhbiA9IG1lYW4oZ2VuZV9tZWFuLCBuYS5ybSA9IFRSVUUpKQoKbWluX3Jwa20gPC0gbWluKHN1bW1hcnlfZGZbWyJjaHJfbWVhbiJdXSkKc3VtbWFyeV9kZltbImNocl9tZWFuIl1dIDwtIHN1bW1hcnlfZGZbWyJjaHJfbWVhbiJdXSAvIG1pbl9ycGttCmdncGxvdChzdW1tYXJ5X2RmLCBhZXMoeSA9IGNocm9tb3NvbWUsIHggPSBjaHJfbWVhbikpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJpZGVudGl0eSIpCgp3YW50ZWQgPC0gcERhdGEobHBfd2FudGVkKVtbImtubnYyY2xhc3NpZmljYXRpb24iXV0gPT0gInoyMiIgfCBwRGF0YShscF93YW50ZWQpW1sia25udjJjbGFzc2lmaWNhdGlvbiJdXSA9PSAiejIzIgpscF96IDwtIGxwX3dhbnRlZFssIHdhbnRlZF0KejIyX3NhbXBsZXMgPC0gcERhdGEobHBfeilbWyJrbm52MmNsYXNzaWZpY2F0aW9uIl1dID09ICJ6MjIiCnoyM19zYW1wbGVzIDwtIHBEYXRhKGxwX3opW1sia25udjJjbGFzc2lmaWNhdGlvbiJdXSA9PSAiejIzIgpscF96X2V4cHJzIDwtIGFzLmRhdGEuZnJhbWUoZXhwcnMobHBfeikpCmxwX3pfZXhwcnNbWyJ6MjJfZ2VuZV9tZWFuIl1dIDwtIHJvd01lYW5zKGxwX3pfZXhwcnNbLCB6MjJfc2FtcGxlc10sIG5hLnJtID0gVFJVRSkKbHBfel9leHByc1tbInoyM19nZW5lX21lYW4iXV0gPC0gcm93TWVhbnMobHBfel9leHByc1ssIHoyM19zYW1wbGVzXSwgbmEucm0gPSBUUlVFKQpscF96X2V4cHJzW1siY2hyb21vc29tZSJdXSA8LSBmRGF0YShscF96KVtbImNocm9tb3NvbWUiXV0KbHBfel9tZWFucyA8LSBscF96X2V4cHJzWywgYygiejIyX2dlbmVfbWVhbiIsICJ6MjNfZ2VuZV9tZWFuIiwgImNocm9tb3NvbWUiKV0gJT4lCiAgZ3JvdXBfYnkoY2hyb21vc29tZSkgJT4lCiAgc3VtbWFyaXplKHoyMl9tZWFuID0gbWVhbih6MjJfZ2VuZV9tZWFuLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB6MjNfbWVhbiA9IG1lYW4oejIzX2dlbmVfbWVhbiwgbmEucm0gPSBUUlVFKSkKCnR0IDwtIHJlc2hhcGUyOjptZWx0KGxwX3pfbWVhbnMsIGlkLnZhcnMgPSAiY2hyb21vc29tZSIpCmdncGxvdCh0dCwgYWVzKHggPSB2YWx1ZSwgeSA9IGNocm9tb3NvbWUpKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSB2YXJpYWJsZSksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpCmBgYAoKIyBTYXZlIGFsbCBkYXRhIHN0cnVjdHVyZXMgaW50byBvbmUgcmRhCgpgYGB7cn0KZm91bmRfaWR4IDwtIGRhdGFfc3RydWN0dXJlcyAlaW4lIGxzKCkKaWYgKHN1bSghZm91bmRfaWR4KSA+IDApIHsKICBub3RfZm91bmQgPC0gZGF0YV9zdHJ1Y3R1cmVzWyFmb3VuZF9pZHhdCiAgd2FybmluZygiU29tZSBkYXRhc3RydWN0dXJlcyB3ZXJlIG5vdCBnZW5lcmF0ZWQ6ICIsIHRvU3RyaW5nKG5vdF9mb3VuZCksICIuIikKICBkYXRhX3N0cnVjdHVyZXMgPC0gZGF0YV9zdHJ1Y3R1cmVzW2ZvdW5kX2lkeF0KfQpzYXZlKGxpc3QgPSBkYXRhX3N0cnVjdHVyZXMsIGZpbGUgPSBnbHVlKCJyZGEvdG1yYzJfZGF0YV9zdHJ1Y3R1cmVzLXZ7dmVyfS5yZGEiKSkKYGBgCgpgYGB7cn0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKbWVzc2FnZSgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKQptZXNzYWdlKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpCiMgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKYGBgCgpgYGB7ciBsb2FkbWVfYWZ0ZXIsIGV2YWw9RkFMU0V9CnRtcCA8LSBsb2FkbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==