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

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

1.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/macrophage_samples.xlsx"

2 Annotations

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

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

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", overwrite = FALSE)
panamensis_entry <- get_eupath_entry("MHOM", metadata = meta[["valid"]])
panamensis_db <- make_eupath_orgdb(panamensis_entry)
panamensis_pkg <- panamensis_db[["pkgname"]]
package_name <- panamensis_db[["pkgname"]]
if (is.null(panamensis_pkg)) {
  panamensis_pkg <- panamensis_entry[["OrgdbPkg"]]
  package_name <- panamensis_pkg
}

tt <- library(panamensis_pkg, character.only = TRUE)
panamensis_env <- get0(panamensis_pkg)
all_fields <- columns(panamensis_env)
all_lp_annot <- sm(load_orgdb_annotations(
    panamensis_env,
    keytype = "gid",
    fields = c("annot_gene_entrez_id", "annot_gene_name",
               "annot_strand", "annot_chromosome", "annot_cds_length",
               "annot_gene_product")))$genes
## Testing to see just how big the full database is.
## testing <- load_orgdb_annotations(panamensis_pkg, keytype = "gid", fields = "all")

lp_go <- load_orgdb_go(panamensis_pkg)
lp_go <- lp_go[, c("GID", "GO")]
lp_lengths <- all_lp_annot[, c("gid", "annot_cds_length")]
colnames(lp_lengths)  <- c("ID", "length")
all_lp_annot[["annot_gene_product"]] <- tolower(all_lp_annot[["annot_gene_product"]])
orthos <- sm(extract_eupath_orthologs(db = panamensis_pkg))
data_structures <- c(data_structures, "lp_lengths", "lp_go", "all_lp_annot")
all_installed <- rownames(installed.packages())
candidates <- grepl(pattern = "^org.Lpanamensis.MHOM.*v68.eg.db", x = all_installed)
orgdb_pkg_name <- all_installed[candidates]

tt <- library(orgdb_pkg_name, character.only = TRUE)
## Loading required package: AnnotationDbi
## Loading required package: stats4
## Loading required package: BiocGenerics
## Loading required package: generics
## 
## Attaching package: 'generics'
## The following object is masked from 'package:dplyr':
## 
##     explain
## The following objects are masked from 'package:base':
## 
##     as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
##     setequal, union
## 
## Attaching package: 'BiocGenerics'
## The following object is masked from 'package:dplyr':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     Filter, Find, Map, Position, Reduce, anyDuplicated, aperm, append,
##     as.data.frame, basename, cbind, colnames, dirname, do.call,
##     duplicated, eval, evalq, get, grep, grepl, is.unsorted, lapply,
##     mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     rank, rbind, rownames, sapply, saveRDS, table, tapply, unique,
##     unsplit, which.max, which.min
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## Loading required package: IRanges
## Loading required package: S4Vectors
## 
## Attaching package: 'S4Vectors'
## The following objects are masked from 'package:dplyr':
## 
##     first, rename
## The following object is masked from 'package:utils':
## 
##     findMatches
## The following objects are masked from 'package:base':
## 
##     I, expand.grid, unname
## 
## Attaching package: 'IRanges'
## The following objects are masked from 'package:dplyr':
## 
##     collapse, desc, slice
## The following object is masked from 'package:glue':
## 
##     trim
## 
## Attaching package: 'AnnotationDbi'
## The following object is masked from 'package:dplyr':
## 
##     select
## 
panamensis_pkg <- get0(orgdb_pkg_name)
all_fields <- columns(panamensis_pkg)
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

lp_go <- load_orgdb_go(panamensis_pkg)
## The chosen keytype was not available.  Using 'GID'.
## This is an orgdb, good.
## 'select()' returned 1:many mapping between keys and columns
## 'select()' returned 1:many mapping between keys and columns
lp_go <- lp_go[, c("GID", "GO")]
lp_lengths <- all_lp_annot[, c("gid", "annot_cds_length")]
colnames(lp_lengths)  <- c("ID", "length")
all_lp_annot[["annot_gene_product"]] <- tolower(all_lp_annot[["annot_gene_product"]])
data_structures <- c(data_structures, "lp_lengths", "lp_go", "all_lp_annot")

3 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)
library(as.character(testing_panamensis), character.only = TRUE)
lp_genome <- get0(as.character(testing_panamensis))
data_structures <- c(data_structures, "lp_genome")

4 Generate Expressionsets and Sample Estimation

The process of sample estimation takes two primary inputs:

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

An expressionSet(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.

4.1 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(
    "none" = "#000000",
    "z22" = "#0000cc",
    "z23" = "#cc0000"),
  "cf" = list(
    "cure" = "#006f00",
    "fail" = "#9dffa0",
    "unknown" = "#cbcbcb",
    "notapplicable" = "#000000"),
  "condition" = list(
    "inf" = "#199c75",
    "inf_sb" = "#d65d00",
    "uninf" = "#6e6ea3",
    "uninf_sb" = "#d83956"),
  "significance" = list(
    "lt0" = "#ffe0e0",
    "lt1" = "#ffa0a0",
    "lt2" = "#f94040",
    "lt4" = "#a00000",
    "gt0" = "#eeccf9",
    "gt1" = "#de8bf9",
    "gt2" = "#ad07e3",
    "gt4" = "#410257"),
  "drug" = list(
    "none" = "#989898",
    "antimony" = "#088b64"),
  "oldnew" = list(
    "previous" = "#2233aa",
    "current" =  "#9c0303"),
  "infectedp" = list(
    "uninfected" = "#676767",
    "infected" = "#ac06e2"),
  "treatment_zymo" = list(
    "inf_sb_z23" = "#E7298A",
    "inf_z23" = "#D95F02",
    "uninf_none" = "#66A61E",
    "uninf_sb_none" = "#E6AB02",
    "inf_z22" = "#1B9E77",
    "inf_sb_z22" = "#7570B3"),
  "donor" = list(
    "d01" = "#8d0000",
    "d02" = "#E6AB02",
    "d09" = "#7570B3",
    "d81" = "#2233aa"),
  "susceptibility" = list(
    "resistant" = "#8563a7",
    "sensitive" = "#8d0000",
    "ambiguous" = "#cbcbcb",
    "unknown" = "#555555"))
data_structures <- c(data_structures, "color_choices")

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

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

** Note **: I forgot to commit the addition of plot_metadata factors() in the last run of this. In addition, I need to add an explicit month to load_biomart_annotations() or change the function to search a couple more months before it stops trying to find an archive.

hs_annot <- load_biomart_annotations(year = "2020", month = "04", symbol_columns = "hgnc_symbol")
## 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.
## Including symbols, there are 67159 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_se(sample_sheet, gene_info = macr_annot,
                           file_column = "hg38100hisatfile") %>%
  set_conditions(fact = "macrophagetreatment") %>%
  set_batches(fact = "macrophagezymodeme") %>%
  sanitize_expt_pData(columns = sanitize_columns) %>%
  subset_se(nonzero = 12000)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': could not find function "set_batches"
fixed_genenames <- gsub(x = rownames(assay(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 'x' in selecting a method for function 'assay': object 'hs_macrophage' not found
hs_macrophage <- set_se_genenames(hs_macrophage, ids = fixed_genenames)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': error in evaluating the argument 'x' in selecting a method for function 'assay': object 'hs_macrophage' not found
table(colData(hs_macrophage)$condition)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'hs_macrophage' not found
## Added to make a simplified PCA plot.
colData(hs_macrophage)[["experiment"]] <- "macrophage"
## Error: object 'hs_macrophage' not found
## The following 3 lines were copy/pasted to datastructures and should be removed soon.
nostrain <- is.na(colData(hs_macrophage)[["strainid"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'hs_macrophage' not found
colData(hs_macrophage)[nostrain, "strainid"] <- "none"
## Error: object 'hs_macrophage' not found
colData(hs_macrophage)[["strain_zymo"]] <- paste0("s", colData(hs_macrophage)[["strainid"]],
                                                "_", colData(hs_macrophage)[["macrophagezymodeme"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'hs_macrophage' not found
uninfected <- colData(hs_macrophage)[["strain_zymo"]] == "snone_none"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'hs_macrophage' not found
colData(hs_macrophage)[uninfected, "strain_zymo"] <- "uninfected"
## Error: object 'hs_macrophage' not found
colData(hs_macrophage)[["infectedp"]] <- "infected"
## Error: object 'hs_macrophage' not found
colData(hs_macrophage)[uninfected, "infectedp"] <- "uninfected"
## Error: object 'hs_macrophage' not found
data_structures <- c(data_structures, "hs_macrophage")

5.2 Double-check sample IDs against the sample sheet

1 sample has been excluded from the analysis but is in the sample sheet. I am reasonably certain I know which, but will double-check here.

sample_sheet_ids = c("TMRC30051","TMRC30057","TMRC30059","TMRC30060","TMRC30061","TMRC30062",
                     "TMRC30063","TMRC30064","TMRC30065","TMRC30066","TMRC30067","TMRC30069",
                     "TMRC30117","TMRC30162","TMRC30243","TMRC30244","TMRC30245","TMRC30246",
                     "TMRC30247","TMRC30248","TMRC30249","TMRC30250","TMRC30251","TMRC30252",
                     "TMRC30266","TMRC30267","TMRC30268","TMRC30286","TMRC30326","TMRC30316",
                     "TMRC30317","TMRC30322","TMRC30323","TMRC30328","TMRC30318","TMRC30319",
                     "TMRC30324","TMRC30325","TMRC30320","TMRC30321","TMRC30327","TMRC30312",
                     "TMRC30297","TMRC30298","TMRC30299","TMRC30300","TMRC30295","TMRC30296",
                     "TMRC30303","TMRC30304","TMRC30301","TMRC30302","TMRC30314","TMRC30315",
                     "TMRC30313")
found <- sample_sheet_ids %in% colnames(assay(hs_macrophage))
colnames(assay(hs_macrophage))[!found]

5.3 Subset and create different groupings

all_human <- sanitize_expt_pData(hs_macrophage, columns = "drug") %>%
  set_conditions(fact = "drug") %>%
  set_batches(fact = "typeofcells")
## Error in set_batches(., fact = "typeofcells"): could not find function "set_batches"
data_structures <- c(data_structures, "all_human")

## The following 3 lines were copy/pasted to datastructures and should be removed soon.
no_strain_idx <- colData(all_human)[["strainid"]] == "none"
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'all_human' not found
##colData(all_human)[["strainid"]] <- paste0("s", colData(all_human)[["strainid"]],
##                                         "_", colData(all_human)[["macrophagezymodeme"]])
colData(all_human)[no_strain_idx, "strainid"] <- "none"
## Error: object 'all_human' not found
table(colData(all_human)[["strainid"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'all_human' not found
all_human_types <- set_conditions(all_human, fact = "typeofcells") %>%
  set_batches(fact = "drug")
## Error in set_batches(., fact = "drug"): could not find function "set_batches"
data_structures <- c(data_structures, "all_human_types")

type_zymo_fact <- paste0(colData(all_human_types)[["condition"]], "_",
                         colData(all_human_types)[["macrophagezymodeme"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'all_human_types' not found
type_zymo <- set_conditions(all_human_types, fact = type_zymo_fact)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'se' in selecting a method for function 'set_conditions': object 'all_human_types' not found
data_structures <- c(data_structures, "type_zymo")

type_drug_fact <- paste0(colData(all_human_types)[["condition"]], "_",
                         colData(all_human_types)[["drug"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'all_human_types' not found
type_drug <- set_conditions(all_human_types, fact = type_drug_fact)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'se' in selecting a method for function 'set_conditions': object 'all_human_types' not found
data_structures <- c(data_structures, "type_drug")

strain_fact <- colData(all_human_types)[["strainid"]]
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'all_human_types' not found
table(strain_fact)
## Error: object 'strain_fact' not found
new_conditions <- paste0(colData(hs_macrophage)[["macrophagetreatment"]], "_",
                         colData(hs_macrophage)[["macrophagezymodeme"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': object 'hs_macrophage' not found
## Note the sanitize() call is redundant with the addition of sanitize() in the
## datastructures file, but I don't want to wait to rerun that.
hs_macr <- set_conditions(hs_macrophage, fact = new_conditions) %>%
  sanitize_expt_pData(column = "drug") %>%
  set_se_colors(color_choices[["treatment_zymo"]]) %>%
  subset_se(subset = "typeofcells!='U937'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'colData': error in evaluating the argument 'object' in selecting a method for function 'pData': error in evaluating the argument 'se' in selecting a method for function 'set_conditions': object 'hs_macrophage' not found
data_structures <- c(data_structures, "hs_macr")

ggstats_parasite <- plot_metadata_factors(hs_macr, column = "parasitemappingrate",
                                         type = "ggstats", scale = "log2")
## 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 'pData': object 'hs_macr' not found
pp(file = "images/ggstats_parasiterate_all_macrophage_drug_treatment.png")
ggstats_parasite
## Error: object 'ggstats_parasite' not found
dev.off()
## png 
##   2
ggstats_parasite
## Error: object 'ggstats_parasite' not found
hs_macr_drug_expt <- set_conditions(hs_macr, fact = "drug")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'se' in selecting a method for function 'set_conditions': object 'hs_macr' not found
hs_macr_strain_expt <- set_conditions(hs_macr, fact = "macrophagezymodeme") %>%
  subset_se(subset = "macrophagezymodeme != 'none'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'se' in selecting a method for function 'set_conditions': object 'hs_macr' not found
data_structures <- c(data_structures, "hs_macr_strain_expt")

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

Let us see if the sankey plot of these samples looks useful…

ggstats_slreads <- plot_metadata_factors(hs_macrophage, column = "hisatlpsinglemapped",
                                         type = "ggstats", scale = "log2")
## 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 'pData': object 'hs_macrophage' not found
pp(file = "images/ggstats_slreads_all_macrophage.png")
ggstats_slreads
## Error: object 'ggstats_slreads' not found
dev.off()
## png 
##   2
ggstats_slreads
## Error: object 'ggstats_slreads' not found
ggstats_violin <- plot_metadata_factors(hs_macrophage, column = "hisatlpsinglemapped",
                                        scale = "log2")
## 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 'pData': object 'hs_macrophage' not found
ggstats_violin
## Error: object 'ggstats_violin' not found
macr_sankey <- plot_meta_sankey(hs_macrophage, color_choices = color_choices,
                                factors = c("oldnew", "drug", "infectedp", "macrophagezymodeme"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'design' in selecting a method for function 'plot_meta_sankey': object 'hs_macrophage' not found
macr_sankey
## Error: object 'macr_sankey' not found

Finally, split off the U937 samples.

hs_u937 <- subset_se(hs_macrophage, subset = "typeofcells!='Macrophages'")
## Error: object 'hs_macrophage' not found
data_structures <- c(data_structures, "hs_u937")

5.4 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_se(
  sample_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_conditions(fact = "macrophagezymodeme") %>%
  set_batches(fact = "macrophagetreatment")
## Error in set_batches(., fact = "macrophagetreatment"): could not find function "set_batches"
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 'x' in selecting a method for function 'ncol': error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'lp_macrophage' not found
lp_macrophage_filt <- subset_se(lp_macrophage, nonzero = 2500) %>%
  semantic_filter(semantic = c("amastin", "gp63", "leishmanolysin"),
                  semantic_column = "annot_gene_product")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'input' in selecting a method for function 'semantic_filter': 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 'x' in selecting a method for function 'ncol': 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: object 'lp_macrophage_filt' not found
lp_macrophage_nosb <- subset_se(lp_macrophage, subset="batch!='inf_sb'")
## Error: 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 'x' in selecting a method for function 'ncol': 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 <- gather_preprocessing_metadata(sample_sheet, specification = spec)
## 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.
## Checking the state of the condition column.
## Checking the state of the batch column.
## Checking the condition factor.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: trimomatic_input already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: trimomatic_output already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: trimomatic_percent already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: fastqc_pct_gc already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: hisat_genome_single_concordant already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: hisat_genome_multi_concordant already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: hisat_genome_single_all already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: hisat_genome_multi_all already exists, replacing it.
## Warning in gather_preprocessing_metadata(sample_sheet, specification = spec):
## Column: hisat_count_table already exists, replacing it.
## preprocessing/TMRC30051/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30057/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30059/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30060/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30061/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30062/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30063/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30064/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30065/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30066/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30067/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30069/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30117/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30162/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30243/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30244/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30245/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30246/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30247/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30248/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30249/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30250/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30251/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30252/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30266/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30267/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30268/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30286/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30291/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30292/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30293/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30294/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30295/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30296/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30297/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30298/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30299/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30300/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30301/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30302/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30303/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30304/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30305/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30306/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30307/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30308/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30309/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30310/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30311/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30312/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30313/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30314/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30315/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30316/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30317/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30318/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30319/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30320/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30321/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30322/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30323/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30324/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30325/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30326/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30327/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30328/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30330/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30331/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## preprocessing/TMRC30332/outputs/*hisat*_*/*_*genome*_gene_ID_fcounts.csv.xz
## Writing new metadata to: sample_sheets/macrophage_samples_modified.xlsx

6 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: hs_macrophage, all_human,
## all_human_types, type_zymo, type_drug, hs_macr, hs_macr_strain_expt, hs_u937,
## lp_macrophage, lp_macrophage_filt, lp_macrophage_nosb.
save(list = data_structures, file = glue("rda/tmrc2_data_structures-v{ver}.rda"))
pander::pander(sessionInfo())
## Warning: Your system is mis-configured: '/etc/localtime' is not a symlink
## Warning: It is strongly recommended to set envionment variable TZ to
## 'America/New_York' (or equivalent)

R version 4.5.0 (2025-04-11)

Platform: x86_64-pc-linux-gnu

locale: C

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

other attached packages: org.Lpanamensis.MHOMCOL81L13.v68.eg.db(v.2024.09), AnnotationDbi(v.1.70.0), IRanges(v.2.42.0), S4Vectors(v.0.46.0), Biobase(v.2.68.0), BiocGenerics(v.0.54.0), generics(v.0.1.4), dplyr(v.1.1.4), Heatplus(v.3.16.0), ggplot2(v.3.5.2), glue(v.1.8.0) and hpgltools(v.1.2)

loaded via a namespace (and not attached): RColorBrewer(v.1.1-3), jsonlite(v.2.0.0), magrittr(v.2.0.3), GenomicFeatures(v.1.60.0), farver(v.2.1.2), rmarkdown(v.2.29), fs(v.1.6.6), BiocIO(v.1.18.0), vctrs(v.0.6.5), memoise(v.2.0.1), Rsamtools(v.2.24.0), RCurl(v.1.98-1.17), htmltools(v.0.5.8.1), S4Arrays(v.1.8.1), progress(v.1.2.3), curl(v.7.0.0), broom(v.1.0.9), SparseArray(v.1.8.1), sass(v.0.4.10), bslib(v.0.9.0), htmlwidgets(v.1.6.4), httr2(v.1.2.1), plyr(v.1.8.9), plotly(v.4.11.0), cachem(v.1.1.0), GenomicAlignments(v.1.44.0), mime(v.0.13), lifecycle(v.1.0.4), iterators(v.1.0.14), pkgconfig(v.2.0.3), Matrix(v.1.7-3), R6(v.2.6.1), fastmap(v.1.2.0), GenomeInfoDbData(v.1.2.14), MatrixGenerics(v.1.20.0), shiny(v.1.11.1), digest(v.0.6.37), DESeq2(v.1.48.1), GenomicRanges(v.1.60.0), RSQLite(v.2.4.3), filelock(v.1.0.3), httr(v.1.4.7), abind(v.1.4-8), compiler(v.4.5.0), pander(v.0.6.6), bit64(v.4.6.0-1), withr(v.3.0.2), backports(v.1.5.0), BiocParallel(v.1.42.1), DBI(v.1.2.3), R.utils(v.2.13.0), biomaRt(v.2.64.0), rappdirs(v.0.3.3), DelayedArray(v.0.34.1), rjson(v.0.2.23), tools(v.4.5.0), zip(v.2.3.3), httpuv(v.1.6.16), varhandle(v.2.0.6), R.oo(v.1.27.1), restfulr(v.0.0.16), GOSemSim(v.2.34.0), promises(v.1.3.3), grid(v.4.5.0), reshape2(v.1.4.4), fgsea(v.1.34.2), gtable(v.0.3.6), tzdb(v.0.5.0), R.methodsS3(v.1.8.2), tidyr(v.1.3.1), hms(v.1.1.3), data.table(v.1.17.8), xml2(v.1.4.0), XVector(v.0.48.0), foreach(v.1.5.2), pillar(v.1.11.0), stringr(v.1.5.1), vroom(v.1.6.5), yulab.utils(v.0.2.1), limma(v.3.64.3), later(v.1.4.3), splines(v.4.5.0), BiocFileCache(v.2.16.1), lattice(v.0.22-7), rtracklayer(v.1.68.0), bit(v.4.6.0), annotate(v.1.86.1), tidyselect(v.1.2.1), GO.db(v.3.21.0), locfit(v.1.5-9.12), Biostrings(v.2.76.0), knitr(v.1.50), edgeR(v.4.6.3), SummarizedExperiment(v.1.38.1), xfun(v.0.53), statmod(v.1.5.0), matrixStats(v.1.5.0), stringi(v.1.8.7), UCSC.utils(v.1.4.0), lazyeval(v.0.2.2), yaml(v.2.3.10), evaluate(v.1.0.4), codetools(v.0.2-20), tibble(v.3.3.0), qvalue(v.2.40.0), graph(v.1.86.0), cli(v.3.6.5), xtable(v.1.8-4), jquerylib(v.0.1.4), dichromat(v.2.0-0.1), Rcpp(v.1.1.0), GenomeInfoDb(v.1.44.2), dbplyr(v.2.5.0), png(v.0.1-8), XML(v.3.99-0.19), parallel(v.4.5.0), readr(v.2.1.5), blob(v.1.2.4), prettyunits(v.1.2.0), DOSE(v.4.2.0), bitops(v.1.0-9), viridisLite(v.0.4.2), GSEABase(v.1.70.0), scales(v.1.4.0), openxlsx(v.4.2.8), purrr(v.1.1.0), crayon(v.1.5.3), rlang(v.1.1.6), cowplot(v.1.2.0), fastmatch(v.1.1-6) and KEGGREST(v.1.48.1)

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 7e330419388a441dce04bfb7cce31bb7c8be3ef4
## This is hpgltools commit: Thu Aug 28 22:20:45 2025 -0400: 7e330419388a441dce04bfb7cce31bb7c8be3ef4
message("Saving to ", savefile)
## Saving to 01datasets.rda.xz
# tmp <- sm(saveme(filename = savefile))
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiTWFjcm9waGFnZSByZXNwb25zZSB0byBkaWZmZXJlbnQgc3RyYWlucyBgciBTeXMuZ2V0ZW52KCdWRVJTSU9OJylgOiBEYXRhIFNldCBDcmVhdGlvbiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgbWF4LXdpZHRoOiAxNjAwcHg7Cn0KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShIZWF0cGx1cykKbGlicmFyeShkcGx5cikKCmtuaXRyOjpvcHRzX2tuaXQkc2V0KAogIHByb2dyZXNzID0gVFJVRSwgdmVyYm9zZSA9IFRSVUUsIHdpZHRoID0gOTAsIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXJyb3IgPSBUUlVFLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnJldGluYSA9IDIsCiAgb3V0LndpZHRoID0gIjEwMCUiLCBkZXYgPSAicG5nIiwKICBkZXYuYXJncyA9IGxpc3QoInBuZyIgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpKQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKAogIGRpZ2l0cyA9IDQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSkKdmVyIDwtIFN5cy5nZXRlbnYoIlZFUlNJT04iKQpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAiJVklbSVkIikKCnJtZF9maWxlIDwtICIwMWRhdGFzZXRzLlJtZCIKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCmRhdGFfc3RydWN0dXJlcyA8LSBjKCkKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBkb2N1bWVudCBpcyBpbnRlbmRlZCB0byBjcmVhdGUgdGhlIGRhdGEgc3RydWN0dXJlcyB1c2VkIHRvCmV2YWx1YXRlIG91ciBUTVJDMiBzYW1wbGVzLiAgSW4gc29tZSBjYXNlcywgdGhpcyBpbmNsdWRlcyBvbmx5IHRob3NlCnNhbXBsZXMgc3RhcnRpbmcgaW4gMjAxOTsgaW4gb3RoZXIgaW5zdGFuY2VzIEkgYW0gaW5jbHVkaW5nIG91cgpwcmV2aW91cyAoMjAxNS0yMDE2KSBzYW1wbGVzLgoKSW4gYWxsIGNhc2VzIHRoZSBwcm9jZXNzaW5nIHBlcmZvcm1lZCB3YXM6CgoxLiAgRGVmYXVsdCB0cmltbWluZyB3YXMgcGVyZm9ybWVkLgoyLiAgSGlzYXQyIHdhcyB1c2VkIHRvIG1hcCB0aGUgcmVtYWluaW5nIHJlYWRzIGFnYWluc3QgdGhlIExlaXNobWFuaWEKICAgIHBhbmFtZW5zaXMgZ2Vub21lIHJldmlzaW9uIDM2LgozLiAgVGhlIGFsaWdubWVudHMgZnJvbSBoaXNhdDIgd2VyZSB1c2VkIHRvIGNvdW50IHJlYWRzL2dlbmUgYWdhaW5zdCB0aGUKICAgIHJldmlzaW9uIDM2IGFubm90YXRpb25zIHdpdGggaHRzZXEuCjQuICBUaGVzZSBhbGlnbm1lbnRzIHdlcmUgYWxzbyBwYXNzZWQgdG8gdGhlIHBpbGV1cCBmdW5jdGlvbmFsaXR5IG9mIHNhbXRvb2xzCiAgICBhbmQgdGhlIHZjZi9iY2YgdXRpbGl0aWVzIGluIG9yZGVyIHRvIG1ha2UgYSBtYXRyaXggb2YgYWxsIG9ic2VydmVkCiAgICBkaWZmZXJlbmNlcyBiZXR3ZWVuIGVhY2ggc2FtcGxlIHdpdGggcmVzcGVjdCB0byB0aGUgcmVmZXJlbmNlLgo1LiAgVGhlIGZyZWViYXllcyB2YXJpYW50IGVzdGltYXRpb24gdG9vbCB3YXMgdXNlZCBpbiBhZGRpdGlvbiB0byAjNAogICAgdG8gc2VhcmNoIGZvciB2YXJpYW50IHBvc2l0aW9ucyBpbiBhIG1vcmUgcm9idXN0IGZhc2hpb24uCjYuICBUaGUgdHJpbW1lZCByZWFkcyB3ZXJlIHBhc3NlZCB0byBrcmFrZW4yIHVzaW5nIGEgdmlyYWwgZGF0YWJhc2UgaW4KICAgIG9yZGVyIHRvIGxvb2sgZm9yIHNhbXBsZXMgd2l0aCBwb3RlbnRpYWwgTFJWIHNlcXVlbmNlLgo3LiAgQW4gZXhwbGljaXQsIGdyZXAtYmFzZWQgc2VhcmNoIGZvciBzcGxpY2VkIGxlYWRlciByZWFkcyB3YXMgdXNlZAogICAgYWdhaW5zdCBhbGwgaHVtYW4tZGVyaXZlZCBzYW1wbGVzLiAgVGhlIHJlc3VsdHMgZnJvbSB0aGlzIHdlcmUKICAgIGNvcHkvcGFzdGVkIGludG8gdGhlIHNhbXBsZSBzaGVldC4KCiMjIE11bHRpcGxlIGRhdGFzZXRzCgpJbiBhIGNvdXBsZSBvZiBpbXBvcnRhbnQgd2F5cyB0aGUgVE1SQzIgZGF0YSBpcyBtdWNoIG1vcmUgY29tcGxleCB0aGFuIHRoZQpUTVJDMzoKCjEuICBJdCBjb21wcmlzZXMgbXVsdGlwbGUsIGNvbXBsZXRlbHkgc2VwYXJhdGUgcXVlcmllczoKICAgIGEuICBTZXF1ZW5jaW5nIHRoZSBwYXJhc2l0ZSBzYW1wbGVzCiAgICBiLiAgU2VxdWVuY2luZyBhIHNldCBvZiBodW1hbiBtYWNyb3BoYWdlIHNhbXBsZXMgd2hpY2ggd2VyZSBpbmZlY3RlZAogICAgICAgIHdpdGggc3BlY2lmaWMgcGFyYXNpdGUgc2FtcGxlcy4KMi4gIFRoZSBwYXJhc2l0ZSB0cmFuc2NyaXB0b21pYyBzYW1wbGVzIGNvbXByaXNlIG11bHRpcGxlIGRpZmZlcmVudAogICAgdHlwZXMgb2YgcXVlcmllczoKICAgIGEuICBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiB0byBsb29rIGF0IHN0cmFpbiwgc3VzY2VwdGliaWxpdHksIGFuZAogICAgY2xpbmljYWwgb3V0Y29tZXMuCiAgICBiLiAgSW5kaXZpZHVhbCB2YXJpYW50IHNlYXJjaGVzIHRvIGxvb2sgZm9yIHBvdGVudGlhbGx5IHVzZWZ1bAogICAgU05QcyBmb3IgY2xhc3NpZmljYXRpb24gb2YgcGFyYXNpdGUgc2FtcGxlcy4KMy4gIFRoZSBodW1hbiBtYWNyb3BoYWdlIHNhbXBsZXMgbWF5IGJlIHVzZWQgdG8gcXVlcnkgYm90aCB0aGUgaG9zdAogICAgYW5kIHBhcmFzaXRlIHRyYW5zY3JpcHRvbWVzIGJlY2F1c2UgKGF0IGxlYXN0IHdoZW4gbm90IGRydWcKICAgIHRyZWF0ZWQpIHRoZXJlIGlzIGEgdHJlbWVuZG91cyBwb3B1bGF0aW9uIG9mIHBhcmFzaXRlIHJlYWRzIGluCiAgICB0aGVtLgoKIyMgU2FtcGxlIHNoZWV0KHMpCgpPdXIgc2hhcmVkIG9ubGluZSBzYW1wbGUgc2hlZXQgaXMgbmVhcmx5IHN0YXRpYyBhdCB0aGUgdGltZSBvZiB0aGlzCndyaXRpbmcgKDIwMjIwOSksIEkgZXhwZWN0IGF0IHRoaXMgcG9pbnQgdGhlIG9ubHkgbGlrZWx5IHVwZGF0ZXMgd2lsbApiZSB0byBhbm5vdGF0ZSBzb21lIHN0cmFpbnMgYXMgbW9yZSBvciBsZXNzIHN1c2NlcHRpYmxlIHRvIGRydWcKdHJlYXRtZW50LgoKYGBge3J9CnNhbXBsZV9zaGVldCA8LSAic2FtcGxlX3NoZWV0cy9tYWNyb3BoYWdlX3NhbXBsZXMueGxzeCIKYGBgCgojIEFubm90YXRpb25zCgpFdmVyeXRoaW5nIHdoaWNoIGZvbGxvd3MgZGVwZW5kcyBvbiB0aGUgRXhpc3RpbmcgVHJpVHJ5cERCIGFubm90YXRpb25zIHJldmlzaW9uCjQ2LCBjaXJjYSAyMDE5LiAgVGhlIGZvbGxvd2luZyBibG9jayBsb2FkcyBhIGRhdGFiYXNlIG9mIHRoZXNlIGFubm90YXRpb25zIGFuZAp0dXJucyBpdCBpbnRvIGEgbWF0cml4IHdoZXJlIHRoZSByb3dzIGFyZSBnZW5lcyBhbmQgY29sdW1ucyBhcmUgYWxsIHRoZQphbm5vdGF0aW9uIHR5cGVzIHByb3ZpZGVkIGJ5IFRyaVRyeXBEQi4KClRoZSBzYW1lIGRhdGFiYXNlIHdhcyB1c2VkIHRvIGNyZWF0ZSBhIG1hdHJpeCBvZiBvcnRob2xvZ291cyBnZW5lcyBiZXR3ZWVuCkwucGFuYW1lbnNpcyBhbmQgYWxsIG9mIHRoZSBvdGhlciBzcGVjaWVzIGluIHRoZSBUcmlUcnlwREIuCgpUaGUgc2FtZSBkYXRhYmFzZSBvZiBhbm5vdGF0aW9ucyBhbHNvIHByb3ZpZGVzIG1hcHBpbmdzIHRvIHRoZSBzZXQgb2YKYW5ub3RhdGVkIEdPIGNhdGVnb3JpZXMgZm9yIHRoZSBMLnBhbmFtZW5zaXMgZ2Vub21lIGFsb25nIHdpdGggZ2VuZQpsZW5ndGhzLgoKYGBge3IsIGV2YWw9RkFMU0V9Cm1ldGEgPC0gZG93bmxvYWRfZXVwYXRoX21ldGFkYXRhKHdlYnNlcnZpY2UgPSAidHJpdHJ5cGRiIiwgb3ZlcndyaXRlID0gRkFMU0UpCnBhbmFtZW5zaXNfZW50cnkgPC0gZ2V0X2V1cGF0aF9lbnRyeSgiTUhPTSIsIG1ldGFkYXRhID0gbWV0YVtbInZhbGlkIl1dKQpwYW5hbWVuc2lzX2RiIDwtIG1ha2VfZXVwYXRoX29yZ2RiKHBhbmFtZW5zaXNfZW50cnkpCnBhbmFtZW5zaXNfcGtnIDwtIHBhbmFtZW5zaXNfZGJbWyJwa2duYW1lIl1dCnBhY2thZ2VfbmFtZSA8LSBwYW5hbWVuc2lzX2RiW1sicGtnbmFtZSJdXQppZiAoaXMubnVsbChwYW5hbWVuc2lzX3BrZykpIHsKICBwYW5hbWVuc2lzX3BrZyA8LSBwYW5hbWVuc2lzX2VudHJ5W1siT3JnZGJQa2ciXV0KICBwYWNrYWdlX25hbWUgPC0gcGFuYW1lbnNpc19wa2cKfQoKdHQgPC0gbGlicmFyeShwYW5hbWVuc2lzX3BrZywgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpwYW5hbWVuc2lzX2VudiA8LSBnZXQwKHBhbmFtZW5zaXNfcGtnKQphbGxfZmllbGRzIDwtIGNvbHVtbnMocGFuYW1lbnNpc19lbnYpCmFsbF9scF9hbm5vdCA8LSBzbShsb2FkX29yZ2RiX2Fubm90YXRpb25zKAogICAgcGFuYW1lbnNpc19lbnYsCiAgICBrZXl0eXBlID0gImdpZCIsCiAgICBmaWVsZHMgPSBjKCJhbm5vdF9nZW5lX2VudHJlel9pZCIsICJhbm5vdF9nZW5lX25hbWUiLAogICAgICAgICAgICAgICAiYW5ub3Rfc3RyYW5kIiwgImFubm90X2Nocm9tb3NvbWUiLCAiYW5ub3RfY2RzX2xlbmd0aCIsCiAgICAgICAgICAgICAgICJhbm5vdF9nZW5lX3Byb2R1Y3QiKSkpJGdlbmVzCiMjIFRlc3RpbmcgdG8gc2VlIGp1c3QgaG93IGJpZyB0aGUgZnVsbCBkYXRhYmFzZSBpcy4KIyMgdGVzdGluZyA8LSBsb2FkX29yZ2RiX2Fubm90YXRpb25zKHBhbmFtZW5zaXNfcGtnLCBrZXl0eXBlID0gImdpZCIsIGZpZWxkcyA9ICJhbGwiKQoKbHBfZ28gPC0gbG9hZF9vcmdkYl9nbyhwYW5hbWVuc2lzX3BrZykKbHBfZ28gPC0gbHBfZ29bLCBjKCJHSUQiLCAiR08iKV0KbHBfbGVuZ3RocyA8LSBhbGxfbHBfYW5ub3RbLCBjKCJnaWQiLCAiYW5ub3RfY2RzX2xlbmd0aCIpXQpjb2xuYW1lcyhscF9sZW5ndGhzKSAgPC0gYygiSUQiLCAibGVuZ3RoIikKYWxsX2xwX2Fubm90W1siYW5ub3RfZ2VuZV9wcm9kdWN0Il1dIDwtIHRvbG93ZXIoYWxsX2xwX2Fubm90W1siYW5ub3RfZ2VuZV9wcm9kdWN0Il1dKQpvcnRob3MgPC0gc20oZXh0cmFjdF9ldXBhdGhfb3J0aG9sb2dzKGRiID0gcGFuYW1lbnNpc19wa2cpKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9sZW5ndGhzIiwgImxwX2dvIiwgImFsbF9scF9hbm5vdCIpCmBgYAoKYGBge3J9CmFsbF9pbnN0YWxsZWQgPC0gcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpCmNhbmRpZGF0ZXMgPC0gZ3JlcGwocGF0dGVybiA9ICJeb3JnLkxwYW5hbWVuc2lzLk1IT00uKnY2OC5lZy5kYiIsIHggPSBhbGxfaW5zdGFsbGVkKQpvcmdkYl9wa2dfbmFtZSA8LSBhbGxfaW5zdGFsbGVkW2NhbmRpZGF0ZXNdCgp0dCA8LSBsaWJyYXJ5KG9yZ2RiX3BrZ19uYW1lLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCnBhbmFtZW5zaXNfcGtnIDwtIGdldDAob3JnZGJfcGtnX25hbWUpCmFsbF9maWVsZHMgPC0gY29sdW1ucyhwYW5hbWVuc2lzX3BrZykKYWxsX2xwX2Fubm90IDwtIHNtKGxvYWRfb3JnZGJfYW5ub3RhdGlvbnMoCiAgICBwYW5hbWVuc2lzX3BrZywKICAgIGtleXR5cGUgPSAiZ2lkIiwKICAgIGZpZWxkcyA9IGMoImFubm90X2dlbmVfZW50cmV6X2lkIiwgImFubm90X2dlbmVfbmFtZSIsCiAgICAgICAgICAgICAgICJhbm5vdF9zdHJhbmQiLCAiYW5ub3RfY2hyb21vc29tZSIsICJhbm5vdF9jZHNfbGVuZ3RoIiwKICAgICAgICAgICAgICAgImFubm90X2dlbmVfcHJvZHVjdCIpKSkkZ2VuZXMKCmxwX2dvIDwtIGxvYWRfb3JnZGJfZ28ocGFuYW1lbnNpc19wa2cpCmxwX2dvIDwtIGxwX2dvWywgYygiR0lEIiwgIkdPIildCmxwX2xlbmd0aHMgPC0gYWxsX2xwX2Fubm90WywgYygiZ2lkIiwgImFubm90X2Nkc19sZW5ndGgiKV0KY29sbmFtZXMobHBfbGVuZ3RocykgIDwtIGMoIklEIiwgImxlbmd0aCIpCmFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSA8LSB0b2xvd2VyKGFsbF9scF9hbm5vdFtbImFubm90X2dlbmVfcHJvZHVjdCJdXSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfbGVuZ3RocyIsICJscF9nbyIsICJhbGxfbHBfYW5ub3QiKQpgYGAKCiMgTG9hZCBhIGdlbm9tZQoKVGhlIGZvbGxvd2luZyBibG9jayBsb2FkcyB0aGUgZnVsbCBnZW5vbWUgc2VxdWVuY2UgZm9yIHBhbmFtZW5zaXMuICBXZQptYXkgdXNlIHRoaXMgbGF0ZXIgdG8gYXR0ZW1wdCB0byBlc3RpbWF0ZSBQQ1IgcHJpbWVycyB0byBkaXNjZXJuIHN0cmFpbnMuCgpJIGFtIG5vdCBzdXJlIGhvdyB0byBpbmNyZWFzZSB0aGUgbnVtYmVyIG9mIG9wZW4gZmlsZXMgaW4gYSBjb250YWluZXIsCmFzIGEgcmVzdWx0IHRoaXMgZG9lcyBub3Qgd29yay4KCmBgYHtyIGdlbm9tZSwgZXZhbD1GQUxTRX0KdGVzdGluZ19wYW5hbWVuc2lzIDwtIG1ha2VfZXVwYXRoX2JzZ2Vub21lKGVudHJ5ID0gcGFuYW1lbnNpc19lbnRyeSkKbGlicmFyeShhcy5jaGFyYWN0ZXIodGVzdGluZ19wYW5hbWVuc2lzKSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpscF9nZW5vbWUgPC0gZ2V0MChhcy5jaGFyYWN0ZXIodGVzdGluZ19wYW5hbWVuc2lzKSkKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAibHBfZ2Vub21lIikKYGBgCgojIEdlbmVyYXRlIEV4cHJlc3Npb25zZXRzIGFuZCBTYW1wbGUgRXN0aW1hdGlvbgoKVGhlIHByb2Nlc3Mgb2Ygc2FtcGxlIGVzdGltYXRpb24gdGFrZXMgdHdvIHByaW1hcnkgaW5wdXRzOgoKMS4gIFRoZSBzYW1wbGUgc2hlZXQsIHdoaWNoIGNvbnRhaW5zIGFsbCB0aGUgbWV0YWRhdGEgd2UgY3VycmVudGx5IGhhdmUgb24gaGFuZCwKICAgIGluY2x1ZGluZyBmaWxlbmFtZXMgZm9yIHRoZSBvdXRwdXRzIG9mICMzIGFuZCAjNCBhYm92ZS4KMi4gIFRoZSBnZW5lIGFubm90YXRpb25zLgoKQW4gZXhwcmVzc2lvblNldChvciBzdW1tYXJpemVkRXhwZXJpbWVudCkgaXMgYSBkYXRhIHN0cnVjdHVyZSB1c2VkIGluClIgdG8gZXhhbWluZSBSTkFTZXEgZGF0YS4gIEl0IGlzIGNvbXByaXNlZCBvZiBhbm5vdGF0aW9ucywgbWV0YWRhdGEsCmFuZCBleHByZXNzaW9uIGRhdGEuICBJbiB0aGUgY2FzZSBvZiBvdXIgcHJvY2Vzc2luZyBwaXBlbGluZSwgdGhlCmxvY2F0aW9uIG9mIHRoZSBleHByZXNzaW9uIGRhdGEgaXMgcHJvdmlkZWQgYnkgdGhlIGZpbGVuYW1lcyBpbiB0aGUgbWV0YWRhdGEuCgojIyBEZWZpbmUgY29sb3JzCgpUaGUgZm9sbG93aW5nIGxpc3QgY29udGFpbnMgdGhlIGNvbG9ycyB3ZSBoYXZlIGNob3NlbiB0byB1c2Ugd2hlbgpwbG90dGluZyB0aGUgdmFyaW91cyB3YXlzIG9mIGRpc2Nlcm5pbmcgdGhlIGRhdGEuCgpgYGB7cn0KY29sb3JfY2hvaWNlcyA8LSBsaXN0KAogICJzdHJhaW4iID0gbGlzdCgKICAgICMjICJ6MS4wIiA9ICIjMzMzMzMzIiwgIyMgQ2hhbmdlZCB0aGlzIHRvICdicmF6JyB0byBtYWtlIGl0IGVhc2llciB0byBmaW5kIHRoZW0uCiAgICAiejIuMCIgPSAiIzU1NTU1NSIsCiAgICAiejMuMCIgPSAiIzc3Nzc3NyIsCiAgICAiejIuMSIgPSAiIzg3NDQwMCIsCiAgICAiejIuMiIgPSAiIzAwMDBjYyIsCiAgICAiejIuMyIgPSAiI2NjMDAwMCIsCiAgICAiejIuNCIgPSAiI2RmNzAwMCIsCiAgICAiejMuMiIgPSAiIzg4ODg4OCIsCiAgICAiejEuMCIgPSAiI2NjMDBjYyIsCiAgICAiejEuNSIgPSAiI2NjMDBjYyIsCiAgICAiYjI5MDQiID0gIiNjYzAwY2MiLAogICAgInVua25vd24iID0gIiNjYmNiY2IiKSwKICAjIyAibnVsbCIgPSAiIzAwMDAwMCIpLAogICJ6eW1vIiA9IGxpc3QoCiAgICAibm9uZSIgPSAiIzAwMDAwMCIsCiAgICAiejIyIiA9ICIjMDAwMGNjIiwKICAgICJ6MjMiID0gIiNjYzAwMDAiKSwKICAiY2YiID0gbGlzdCgKICAgICJjdXJlIiA9ICIjMDA2ZjAwIiwKICAgICJmYWlsIiA9ICIjOWRmZmEwIiwKICAgICJ1bmtub3duIiA9ICIjY2JjYmNiIiwKICAgICJub3RhcHBsaWNhYmxlIiA9ICIjMDAwMDAwIiksCiAgImNvbmRpdGlvbiIgPSBsaXN0KAogICAgImluZiIgPSAiIzE5OWM3NSIsCiAgICAiaW5mX3NiIiA9ICIjZDY1ZDAwIiwKICAgICJ1bmluZiIgPSAiIzZlNmVhMyIsCiAgICAidW5pbmZfc2IiID0gIiNkODM5NTYiKSwKICAic2lnbmlmaWNhbmNlIiA9IGxpc3QoCiAgICAibHQwIiA9ICIjZmZlMGUwIiwKICAgICJsdDEiID0gIiNmZmEwYTAiLAogICAgImx0MiIgPSAiI2Y5NDA0MCIsCiAgICAibHQ0IiA9ICIjYTAwMDAwIiwKICAgICJndDAiID0gIiNlZWNjZjkiLAogICAgImd0MSIgPSAiI2RlOGJmOSIsCiAgICAiZ3QyIiA9ICIjYWQwN2UzIiwKICAgICJndDQiID0gIiM0MTAyNTciKSwKICAiZHJ1ZyIgPSBsaXN0KAogICAgIm5vbmUiID0gIiM5ODk4OTgiLAogICAgImFudGltb255IiA9ICIjMDg4YjY0IiksCiAgIm9sZG5ldyIgPSBsaXN0KAogICAgInByZXZpb3VzIiA9ICIjMjIzM2FhIiwKICAgICJjdXJyZW50IiA9ICAiIzljMDMwMyIpLAogICJpbmZlY3RlZHAiID0gbGlzdCgKICAgICJ1bmluZmVjdGVkIiA9ICIjNjc2NzY3IiwKICAgICJpbmZlY3RlZCIgPSAiI2FjMDZlMiIpLAogICJ0cmVhdG1lbnRfenltbyIgPSBsaXN0KAogICAgImluZl9zYl96MjMiID0gIiNFNzI5OEEiLAogICAgImluZl96MjMiID0gIiNEOTVGMDIiLAogICAgInVuaW5mX25vbmUiID0gIiM2NkE2MUUiLAogICAgInVuaW5mX3NiX25vbmUiID0gIiNFNkFCMDIiLAogICAgImluZl96MjIiID0gIiMxQjlFNzciLAogICAgImluZl9zYl96MjIiID0gIiM3NTcwQjMiKSwKICAiZG9ub3IiID0gbGlzdCgKICAgICJkMDEiID0gIiM4ZDAwMDAiLAogICAgImQwMiIgPSAiI0U2QUIwMiIsCiAgICAiZDA5IiA9ICIjNzU3MEIzIiwKICAgICJkODEiID0gIiMyMjMzYWEiKSwKICAic3VzY2VwdGliaWxpdHkiID0gbGlzdCgKICAgICJyZXNpc3RhbnQiID0gIiM4NTYzYTciLAogICAgInNlbnNpdGl2ZSIgPSAiIzhkMDAwMCIsCiAgICAiYW1iaWd1b3VzIiA9ICIjY2JjYmNiIiwKICAgICJ1bmtub3duIiA9ICIjNTU1NTU1IikpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImNvbG9yX2Nob2ljZXMiKQpgYGAKCiMgTWFjcm9waGFnZSBkYXRhCgpBbGwgb2YgdGhlIGFib3ZlIGZvY3VzZWQgZW50aXJlIG9uIHRoZSBwYXJhc2l0ZSBzYW1wbGVzLCBub3cgbGV0IHVzCnB1bGwgdXAgdGhlIG1hY3JvcGhhZ2UgaW5mZWN0ZWQgc2FtcGxlcy4gIFRoaXMgd2lsbCBjb21wcmlzZSB0d28KZGF0YXNldHMsIG9uZSBvZiB0aGUgaHVtYW4gYW5kIG9uZSBvZiB0aGUgcGFyYXNpdGUuCgojIyBNYWNyb3BoYWdlIGhvc3QgZGF0YQoKVGhlIG1ldGFkYXRhIGZvciB0aGUgbWFjcm9waGFnZSBzYW1wbGVzIGNvbnRhaW5zIGEgY291cGxlIG9mIGNvbHVtbnMKZm9yIG1hcHBlZCBodW1hbiBhbmQgcGFyYXNpdGUgcmVhZHMuICBXZSB3aWxsIHRoZXJlZm9yZSB1c2UgdGhlbQpzZXBhcmF0ZWx5IHRvIGNyZWF0ZSB0d28gZXhwcmVzc2lvbnNldHMsIG9uZSBmb3IgZWFjaCBzcGVjaWVzLgoKKiogTm90ZSAqKjogSSBmb3Jnb3QgdG8gY29tbWl0IHRoZSBhZGRpdGlvbiBvZiBwbG90X21ldGFkYXRhIGZhY3RvcnMoKSBpbiB0aGUgbGFzdCBydW4gb2YgdGhpcy4KSW4gYWRkaXRpb24sIEkgbmVlZCB0byBhZGQgYW4gZXhwbGljaXQgbW9udGggdG8KbG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKCkgX29yXyBjaGFuZ2UgdGhlIGZ1bmN0aW9uIHRvIHNlYXJjaCBhIGNvdXBsZQptb3JlIG1vbnRocyBiZWZvcmUgaXQgc3RvcHMgdHJ5aW5nIHRvIGZpbmQgYW4gYXJjaGl2ZS4KCmBgYHtyfQpoc19hbm5vdCA8LSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoeWVhciA9ICIyMDIwIiwgbW9udGggPSAiMDQiLCBzeW1ib2xfY29sdW1ucyA9ICJoZ25jX3N5bWJvbCIpCmhzX2Fubm90IDwtIGhzX2Fubm90W1siYW5ub3RhdGlvbiJdXQpoc19hbm5vdFtbInRyYW5zY3JpcHQiXV0gPC0gcGFzdGUwKHJvd25hbWVzKGhzX2Fubm90KSwgIi4iLCBoc19hbm5vdFtbInRyYW5zY3JpcHRfdmVyc2lvbiJdXSkKcm93bmFtZXMoaHNfYW5ub3QpIDwtIG1ha2UubmFtZXMoaHNfYW5ub3RbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZSA9IFRSVUUpCnJvd25hbWVzKGhzX2Fubm90KSA8LSBwYXN0ZTAoImdlbmU6Iiwgcm93bmFtZXMoaHNfYW5ub3QpKQp0eF9nZW5lX21hcCA8LSBoc19hbm5vdFssIGMoInRyYW5zY3JpcHQiLCAiZW5zZW1ibF9nZW5lX2lkIildCgpzYW5pdGl6ZV9jb2x1bW5zIDwtIGMoImRydWciLCAibWFjcm9waGFnZXRyZWF0bWVudCIsICJtYWNyb3BoYWdlenltb2RlbWUiKQptYWNyX2Fubm90IDwtIGhzX2Fubm90CnJvd25hbWVzKG1hY3JfYW5ub3QpIDwtIGdzdWIoeCA9IHJvd25hbWVzKG1hY3JfYW5ub3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiXmdlbmU6IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQoKaHNfbWFjcm9waGFnZSA8LSBjcmVhdGVfc2Uoc2FtcGxlX3NoZWV0LCBnZW5lX2luZm8gPSBtYWNyX2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbiA9ICJoZzM4MTAwaGlzYXRmaWxlIikgJT4lCiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJtYWNyb3BoYWdldHJlYXRtZW50IikgJT4lCiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJtYWNyb3BoYWdlenltb2RlbWUiKSAlPiUKICBzYW5pdGl6ZV9leHB0X3BEYXRhKGNvbHVtbnMgPSBzYW5pdGl6ZV9jb2x1bW5zKSAlPiUKICBzdWJzZXRfc2Uobm9uemVybyA9IDEyMDAwKQpmaXhlZF9nZW5lbmFtZXMgPC0gZ3N1Yih4ID0gcm93bmFtZXMoYXNzYXkoaHNfbWFjcm9waGFnZSkpLCBwYXR0ZXJuID0gIl5nZW5lOiIsCiAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiIpCmhzX21hY3JvcGhhZ2UgPC0gc2V0X3NlX2dlbmVuYW1lcyhoc19tYWNyb3BoYWdlLCBpZHMgPSBmaXhlZF9nZW5lbmFtZXMpCnRhYmxlKGNvbERhdGEoaHNfbWFjcm9waGFnZSkkY29uZGl0aW9uKQojIyBBZGRlZCB0byBtYWtlIGEgc2ltcGxpZmllZCBQQ0EgcGxvdC4KY29sRGF0YShoc19tYWNyb3BoYWdlKVtbImV4cGVyaW1lbnQiXV0gPC0gIm1hY3JvcGhhZ2UiCgojIyBUaGUgZm9sbG93aW5nIDMgbGluZXMgd2VyZSBjb3B5L3Bhc3RlZCB0byBkYXRhc3RydWN0dXJlcyBhbmQgc2hvdWxkIGJlIHJlbW92ZWQgc29vbi4Kbm9zdHJhaW4gPC0gaXMubmEoY29sRGF0YShoc19tYWNyb3BoYWdlKVtbInN0cmFpbmlkIl1dKQpjb2xEYXRhKGhzX21hY3JvcGhhZ2UpW25vc3RyYWluLCAic3RyYWluaWQiXSA8LSAibm9uZSIKCmNvbERhdGEoaHNfbWFjcm9waGFnZSlbWyJzdHJhaW5fenltbyJdXSA8LSBwYXN0ZTAoInMiLCBjb2xEYXRhKGhzX21hY3JvcGhhZ2UpW1sic3RyYWluaWQiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfIiwgY29sRGF0YShoc19tYWNyb3BoYWdlKVtbIm1hY3JvcGhhZ2V6eW1vZGVtZSJdXSkKdW5pbmZlY3RlZCA8LSBjb2xEYXRhKGhzX21hY3JvcGhhZ2UpW1sic3RyYWluX3p5bW8iXV0gPT0gInNub25lX25vbmUiCmNvbERhdGEoaHNfbWFjcm9waGFnZSlbdW5pbmZlY3RlZCwgInN0cmFpbl96eW1vIl0gPC0gInVuaW5mZWN0ZWQiCgpjb2xEYXRhKGhzX21hY3JvcGhhZ2UpW1siaW5mZWN0ZWRwIl1dIDwtICJpbmZlY3RlZCIKY29sRGF0YShoc19tYWNyb3BoYWdlKVt1bmluZmVjdGVkLCAiaW5mZWN0ZWRwIl0gPC0gInVuaW5mZWN0ZWQiCgpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJoc19tYWNyb3BoYWdlIikKYGBgCgojIyBEb3VibGUtY2hlY2sgc2FtcGxlIElEcyBhZ2FpbnN0IHRoZSBzYW1wbGUgc2hlZXQKCjEgc2FtcGxlIGhhcyBiZWVuIGV4Y2x1ZGVkIGZyb20gdGhlIGFuYWx5c2lzIGJ1dCBpcyBpbiB0aGUgc2FtcGxlCnNoZWV0LiAgSSBhbSByZWFzb25hYmx5IGNlcnRhaW4gSSBrbm93IHdoaWNoLCBidXQgd2lsbCBkb3VibGUtY2hlY2sKaGVyZS4KCmBgYHtyLCBldmFsPUZBTFNFfQpzYW1wbGVfc2hlZXRfaWRzID0gYygiVE1SQzMwMDUxIiwiVE1SQzMwMDU3IiwiVE1SQzMwMDU5IiwiVE1SQzMwMDYwIiwiVE1SQzMwMDYxIiwiVE1SQzMwMDYyIiwKICAgICAgICAgICAgICAgICAgICAgIlRNUkMzMDA2MyIsIlRNUkMzMDA2NCIsIlRNUkMzMDA2NSIsIlRNUkMzMDA2NiIsIlRNUkMzMDA2NyIsIlRNUkMzMDA2OSIsCiAgICAgICAgICAgICAgICAgICAgICJUTVJDMzAxMTciLCJUTVJDMzAxNjIiLCJUTVJDMzAyNDMiLCJUTVJDMzAyNDQiLCJUTVJDMzAyNDUiLCJUTVJDMzAyNDYiLAogICAgICAgICAgICAgICAgICAgICAiVE1SQzMwMjQ3IiwiVE1SQzMwMjQ4IiwiVE1SQzMwMjQ5IiwiVE1SQzMwMjUwIiwiVE1SQzMwMjUxIiwiVE1SQzMwMjUyIiwKICAgICAgICAgICAgICAgICAgICAgIlRNUkMzMDI2NiIsIlRNUkMzMDI2NyIsIlRNUkMzMDI2OCIsIlRNUkMzMDI4NiIsIlRNUkMzMDMyNiIsIlRNUkMzMDMxNiIsCiAgICAgICAgICAgICAgICAgICAgICJUTVJDMzAzMTciLCJUTVJDMzAzMjIiLCJUTVJDMzAzMjMiLCJUTVJDMzAzMjgiLCJUTVJDMzAzMTgiLCJUTVJDMzAzMTkiLAogICAgICAgICAgICAgICAgICAgICAiVE1SQzMwMzI0IiwiVE1SQzMwMzI1IiwiVE1SQzMwMzIwIiwiVE1SQzMwMzIxIiwiVE1SQzMwMzI3IiwiVE1SQzMwMzEyIiwKICAgICAgICAgICAgICAgICAgICAgIlRNUkMzMDI5NyIsIlRNUkMzMDI5OCIsIlRNUkMzMDI5OSIsIlRNUkMzMDMwMCIsIlRNUkMzMDI5NSIsIlRNUkMzMDI5NiIsCiAgICAgICAgICAgICAgICAgICAgICJUTVJDMzAzMDMiLCJUTVJDMzAzMDQiLCJUTVJDMzAzMDEiLCJUTVJDMzAzMDIiLCJUTVJDMzAzMTQiLCJUTVJDMzAzMTUiLAogICAgICAgICAgICAgICAgICAgICAiVE1SQzMwMzEzIikKZm91bmQgPC0gc2FtcGxlX3NoZWV0X2lkcyAlaW4lIGNvbG5hbWVzKGFzc2F5KGhzX21hY3JvcGhhZ2UpKQpjb2xuYW1lcyhhc3NheShoc19tYWNyb3BoYWdlKSlbIWZvdW5kXQpgYGAKCiMjIFN1YnNldCBhbmQgY3JlYXRlIGRpZmZlcmVudCBncm91cGluZ3MKCmBgYHtyfQphbGxfaHVtYW4gPC0gc2FuaXRpemVfZXhwdF9wRGF0YShoc19tYWNyb3BoYWdlLCBjb2x1bW5zID0gImRydWciKSAlPiUKICBzZXRfY29uZGl0aW9ucyhmYWN0ID0gImRydWciKSAlPiUKICBzZXRfYmF0Y2hlcyhmYWN0ID0gInR5cGVvZmNlbGxzIikKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAiYWxsX2h1bWFuIikKCiMjIFRoZSBmb2xsb3dpbmcgMyBsaW5lcyB3ZXJlIGNvcHkvcGFzdGVkIHRvIGRhdGFzdHJ1Y3R1cmVzIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCBzb29uLgpub19zdHJhaW5faWR4IDwtIGNvbERhdGEoYWxsX2h1bWFuKVtbInN0cmFpbmlkIl1dID09ICJub25lIgojI2NvbERhdGEoYWxsX2h1bWFuKVtbInN0cmFpbmlkIl1dIDwtIHBhc3RlMCgicyIsIGNvbERhdGEoYWxsX2h1bWFuKVtbInN0cmFpbmlkIl1dLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iLCBjb2xEYXRhKGFsbF9odW1hbilbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCmNvbERhdGEoYWxsX2h1bWFuKVtub19zdHJhaW5faWR4LCAic3RyYWluaWQiXSA8LSAibm9uZSIKdGFibGUoY29sRGF0YShhbGxfaHVtYW4pW1sic3RyYWluaWQiXV0pCgphbGxfaHVtYW5fdHlwZXMgPC0gc2V0X2NvbmRpdGlvbnMoYWxsX2h1bWFuLCBmYWN0ID0gInR5cGVvZmNlbGxzIikgJT4lCiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJkcnVnIikKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAiYWxsX2h1bWFuX3R5cGVzIikKCnR5cGVfenltb19mYWN0IDwtIHBhc3RlMChjb2xEYXRhKGFsbF9odW1hbl90eXBlcylbWyJjb25kaXRpb24iXV0sICJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbIm1hY3JvcGhhZ2V6eW1vZGVtZSJdXSkKdHlwZV96eW1vIDwtIHNldF9jb25kaXRpb25zKGFsbF9odW1hbl90eXBlcywgZmFjdCA9IHR5cGVfenltb19mYWN0KQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJ0eXBlX3p5bW8iKQoKdHlwZV9kcnVnX2ZhY3QgPC0gcGFzdGUwKGNvbERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbImNvbmRpdGlvbiJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YShhbGxfaHVtYW5fdHlwZXMpW1siZHJ1ZyJdXSkKdHlwZV9kcnVnIDwtIHNldF9jb25kaXRpb25zKGFsbF9odW1hbl90eXBlcywgZmFjdCA9IHR5cGVfZHJ1Z19mYWN0KQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJ0eXBlX2RydWciKQoKc3RyYWluX2ZhY3QgPC0gY29sRGF0YShhbGxfaHVtYW5fdHlwZXMpW1sic3RyYWluaWQiXV0KdGFibGUoc3RyYWluX2ZhY3QpCgpuZXdfY29uZGl0aW9ucyA8LSBwYXN0ZTAoY29sRGF0YShoc19tYWNyb3BoYWdlKVtbIm1hY3JvcGhhZ2V0cmVhdG1lbnQiXV0sICJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEoaHNfbWFjcm9waGFnZSlbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCiMjIE5vdGUgdGhlIHNhbml0aXplKCkgY2FsbCBpcyByZWR1bmRhbnQgd2l0aCB0aGUgYWRkaXRpb24gb2Ygc2FuaXRpemUoKSBpbiB0aGUKIyMgZGF0YXN0cnVjdHVyZXMgZmlsZSwgYnV0IEkgZG9uJ3Qgd2FudCB0byB3YWl0IHRvIHJlcnVuIHRoYXQuCmhzX21hY3IgPC0gc2V0X2NvbmRpdGlvbnMoaHNfbWFjcm9waGFnZSwgZmFjdCA9IG5ld19jb25kaXRpb25zKSAlPiUKICBzYW5pdGl6ZV9leHB0X3BEYXRhKGNvbHVtbiA9ICJkcnVnIikgJT4lCiAgc2V0X3NlX2NvbG9ycyhjb2xvcl9jaG9pY2VzW1sidHJlYXRtZW50X3p5bW8iXV0pICU+JQogIHN1YnNldF9zZShzdWJzZXQgPSAidHlwZW9mY2VsbHMhPSdVOTM3JyIpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImhzX21hY3IiKQoKZ2dzdGF0c19wYXJhc2l0ZSA8LSBwbG90X21ldGFkYXRhX2ZhY3RvcnMoaHNfbWFjciwgY29sdW1uID0gInBhcmFzaXRlbWFwcGluZ3JhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiZ2dzdGF0cyIsIHNjYWxlID0gImxvZzIiKQpwcChmaWxlID0gImltYWdlcy9nZ3N0YXRzX3BhcmFzaXRlcmF0ZV9hbGxfbWFjcm9waGFnZV9kcnVnX3RyZWF0bWVudC5wbmciKQpnZ3N0YXRzX3BhcmFzaXRlCmRldi5vZmYoKQpnZ3N0YXRzX3BhcmFzaXRlCgpoc19tYWNyX2RydWdfZXhwdCA8LSBzZXRfY29uZGl0aW9ucyhoc19tYWNyLCBmYWN0ID0gImRydWciKQoKaHNfbWFjcl9zdHJhaW5fZXhwdCA8LSBzZXRfY29uZGl0aW9ucyhoc19tYWNyLCBmYWN0ID0gIm1hY3JvcGhhZ2V6eW1vZGVtZSIpICU+JQogIHN1YnNldF9zZShzdWJzZXQgPSAibWFjcm9waGFnZXp5bW9kZW1lICE9ICdub25lJyIpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImhzX21hY3Jfc3RyYWluX2V4cHQiKQoKdGFibGUoY29sRGF0YShoc19tYWNyKVtbInN0cmFpbmlkIl1dKQpgYGAKCkxldCB1cyBzZWUgaWYgdGhlIHNhbmtleSBwbG90IG9mIHRoZXNlIHNhbXBsZXMgbG9va3MgdXNlZnVsLi4uCgpgYGB7cn0KZ2dzdGF0c19zbHJlYWRzIDwtIHBsb3RfbWV0YWRhdGFfZmFjdG9ycyhoc19tYWNyb3BoYWdlLCBjb2x1bW4gPSAiaGlzYXRscHNpbmdsZW1hcHBlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJnZ3N0YXRzIiwgc2NhbGUgPSAibG9nMiIpCnBwKGZpbGUgPSAiaW1hZ2VzL2dnc3RhdHNfc2xyZWFkc19hbGxfbWFjcm9waGFnZS5wbmciKQpnZ3N0YXRzX3NscmVhZHMKZGV2Lm9mZigpCmdnc3RhdHNfc2xyZWFkcwpnZ3N0YXRzX3Zpb2xpbiA8LSBwbG90X21ldGFkYXRhX2ZhY3RvcnMoaHNfbWFjcm9waGFnZSwgY29sdW1uID0gImhpc2F0bHBzaW5nbGVtYXBwZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAibG9nMiIpCmdnc3RhdHNfdmlvbGluCgptYWNyX3NhbmtleSA8LSBwbG90X21ldGFfc2Fua2V5KGhzX21hY3JvcGhhZ2UsIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcnMgPSBjKCJvbGRuZXciLCAiZHJ1ZyIsICJpbmZlY3RlZHAiLCAibWFjcm9waGFnZXp5bW9kZW1lIikpCm1hY3Jfc2Fua2V5CmBgYAoKRmluYWxseSwgc3BsaXQgb2ZmIHRoZSBVOTM3IHNhbXBsZXMuCgpgYGB7cn0KaHNfdTkzNyA8LSBzdWJzZXRfc2UoaHNfbWFjcm9waGFnZSwgc3Vic2V0ID0gInR5cGVvZmNlbGxzIT0nTWFjcm9waGFnZXMnIikKZGF0YV9zdHJ1Y3R1cmVzIDwtIGMoZGF0YV9zdHJ1Y3R1cmVzLCAiaHNfdTkzNyIpCmBgYAoKIyMgTWFjcm9waGFnZSBwYXJhc2l0ZSBkYXRhCgpJbiB0aGUgcHJldmlvdXMgYmxvY2ssIHdlIHVzZWQgYSBuZXcgaW52b2NhdGlvbiBvZiBlbnNlbWJsLWRlcml2ZWQKYW5ub3RhdGlvbiBkYXRhLCB0aGlzIHRpbWUgd2UgY2FuIGp1c3QgdXNlIG91ciBleGlzdGluZyBwYXJhc2l0ZSBnZW5lCmFubm90YXRpb25zLgoKYGBge3J9CmxwX21hY3JvcGhhZ2UgPC0gY3JlYXRlX3NlKAogIHNhbXBsZV9zaGVldCwgZmlsZV9jb2x1bW4gPSAibHBhbmFtZW5zaXN2MzZoaXNhdGZpbGUiLCBnZW5lX2luZm8gPSBhbGxfbHBfYW5ub3QsCiAgc2F2ZWZpbGUgPSBnbHVlKCJyZGEvbHBfbWFjcm9waGFnZS12e3Zlcn0ucmRhIiksCiAgYW5ub3RhdGlvbiA9ICJvcmcuTHBhbmFtZW5zaXMuTUhPTUNPTDgxTDEzLnY0Ni5lZy5kYiIpICU+JQogIHNldF9jb25kaXRpb25zKGZhY3QgPSAibWFjcm9waGFnZXp5bW9kZW1lIikgJT4lCiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJtYWNyb3BoYWdldHJlYXRtZW50IikKCnVuZmlsdF93cml0dGVuIDwtIHdyaXRlX2V4cHQoCiAgbHBfbWFjcm9waGFnZSwKICBleGNlbCA9IGdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUve3Zlcn0vcmVhZF9jb3VudHMvbHBfbWFjcm9waGFnZV9yZWFkc191bmZpbHRlcmVkLXZ7dmVyfS54bHN4IikpCgpscF9tYWNyb3BoYWdlX2ZpbHQgPC0gc3Vic2V0X3NlKGxwX21hY3JvcGhhZ2UsIG5vbnplcm8gPSAyNTAwKSAlPiUKICBzZW1hbnRpY19maWx0ZXIoc2VtYW50aWMgPSBjKCJhbWFzdGluIiwgImdwNjMiLCAibGVpc2htYW5vbHlzaW4iKSwKICAgICAgICAgICAgICAgICAgc2VtYW50aWNfY29sdW1uID0gImFubm90X2dlbmVfcHJvZHVjdCIpCmRhdGFfc3RydWN0dXJlcyA8LSBjKGRhdGFfc3RydWN0dXJlcywgImxwX21hY3JvcGhhZ2UiLCAibHBfbWFjcm9waGFnZV9maWx0IikKCmZpbHRfd3JpdHRlbiA8LSB3cml0ZV9leHB0KGxwX21hY3JvcGhhZ2VfZmlsdCwKICBleGNlbCA9IGdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUve3Zlcn0vcmVhZF9jb3VudHMvbHBfbWFjcm9waGFnZV9yZWFkc19maWx0ZXJlZC12e3Zlcn0ueGxzeCIpKQpscF9tYWNyb3BoYWdlIDwtIGxwX21hY3JvcGhhZ2VfZmlsdAoKbHBfbWFjcm9waGFnZV9ub3NiIDwtIHN1YnNldF9zZShscF9tYWNyb3BoYWdlLCBzdWJzZXQ9ImJhdGNoIT0naW5mX3NiJyIpCmxwX25vc2Jfd3JpdGUgPC0gd3JpdGVfZXhwdCgKICBscF9tYWNyb3BoYWdlX25vc2IsCiAgZXhjZWwgPSBnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL3t2ZXJ9L3JlYWRfY291bnRzL2xwX21hY3JvcGhhZ2Vfbm9zYl9yZWFkcy12e3Zlcn0ueGxzeCIpKQpkYXRhX3N0cnVjdHVyZXMgPC0gYyhkYXRhX3N0cnVjdHVyZXMsICJscF9tYWNyb3BoYWdlX25vc2IiKQoKc3BlYyA8LSBtYWtlX3JuYXNlcV9zcGVjKCkKdGVzdCA8LSBnYXRoZXJfcHJlcHJvY2Vzc2luZ19tZXRhZGF0YShzYW1wbGVfc2hlZXQsIHNwZWNpZmljYXRpb24gPSBzcGVjKQpgYGAKCiMgU2F2ZSBhbGwgZGF0YSBzdHJ1Y3R1cmVzIGludG8gb25lIHJkYQoKYGBge3J9CmZvdW5kX2lkeCA8LSBkYXRhX3N0cnVjdHVyZXMgJWluJSBscygpCmlmIChzdW0oIWZvdW5kX2lkeCkgPiAwKSB7CiAgbm90X2ZvdW5kIDwtIGRhdGFfc3RydWN0dXJlc1shZm91bmRfaWR4XQogIHdhcm5pbmcoIlNvbWUgZGF0YXN0cnVjdHVyZXMgd2VyZSBub3QgZ2VuZXJhdGVkOiAiLCB0b1N0cmluZyhub3RfZm91bmQpLCAiLiIpCiAgZGF0YV9zdHJ1Y3R1cmVzIDwtIGRhdGFfc3RydWN0dXJlc1tmb3VuZF9pZHhdCn0Kc2F2ZShsaXN0ID0gZGF0YV9zdHJ1Y3R1cmVzLCBmaWxlID0gZ2x1ZSgicmRhL3RtcmMyX2RhdGFfc3RydWN0dXJlcy12e3Zlcn0ucmRhIikpCmBgYAoKYGBge3J9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkKbWVzc2FnZSgiU2F2aW5nIHRvICIsIHNhdmVmaWxlKQojIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkpCmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsPUZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=