1 Test different ortholog/paralog search methods.

2 ortholog version: 20180301

One of Steve’s goals is to provide ortholog tables across Leishmania major, braziliensis, and mexicana. There are quite a few possible ways to do this. Lets explore some of them here.

3 Create sqlite databases for species of interest

The following block is not run except manually, because it takes effing forever. Also, I used the wrong braziliensis strain!

## The only nice thing about my organismdbi maker is that it takes arbitrary
## strings and will try to find the appropriate species.
braz_sqlite <- make_eupath_organismdbi("2904")  ## shortcut for braziliensis strain 2904
braz_sqlite <- make_eupath_organismdbi("major") ## This is sufficient to get Friedlin
braz_sqlite <- make_eupath_organismdbi("mexicana") ## There is only one mexicana I think
braz_sqlite <- make_eupath_organismdbi("tarentolae") ## There is only 1 tarentolae
braz_sqlite <- make_eupath_organismdbi("TREU927") ## I am assuming 927
braz_sqlite <- make_eupath_organismdbi("Brener") ## cruzi is super confusing, this is probably wrong.

4 Load the sqlite data from the eupathdb

tt <- sm(library(org.Lbraziliensis.MHOMBR75M2904.v36.eg.db))
tt <- sm(library(org.Lmajor.Friedlin.v36.eg.db))
tt <- sm(library(org.Lmexicana.MHOMGT2001U1103.v36.eg.db))

## Shortcut the database names
braziliensis_db <- org.Lbraziliensis.MHOMBR75M2904.v36.eg.db
major_db <- org.Lmajor.Friedlin.v36.eg.db
mexicana_db <- org.Lmexicana.MHOMGT2001U1103.v36.eg.db

all_speciesnames <- extract_eupath_orthologs(braziliensis_db, print_speciesnames=TRUE)
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## [1] "E. monterogeii strain LV88, L. aethiopica L147, L. arabica strain LEM1108, L. braziliensis MHOM/BR/75/M2903, L. enriettii strain LEM3045, L. gerbilli strain LEM452, L. sp. MAR LEM2494, L. major strain LV39c5, L. major strain SD 75.1, L. panamensis MHOM/COL/81/L13, L. tropica L590, L. turanica strain LEM423, L. braziliensis MHOM/BR/75/M2904, L. donovani BPK282A1, L. infantum JPCM5, L. major strain Friedlin, L. mexicana MHOM/GT/2001/U1103, L. pyrrhocoris H10, L. tarentolae Parrot-TarII, T. cruzi cruzi strain Dm28c, B. ayalai B08-376, C. fasciculata strain Cf-Cl, T. grayi ANR4, L. seymouri ATCC 30220, T. cruzi Dm28c, T. cruzi Sylvio X10/1-2012, T. theileri isolate Edinburgh, T. rangeli SC58, T. brucei Lister strain 427, T. brucei brucei TREU927, T. brucei gambiense DAL972, T. cruzi CL Brener Non-Esmeraldo-like, T. cruzi CL Brener Esmeraldo-like, T. congolense IL3000, T. cruzi Sylvio X10/1, T. cruzi marinkellei strain B7, T. evansi strain STIB 805, T. vivax Y486, T. cruzi strain CL Brener"
lm <- "L. major strain Friedlin"
lb <- "L. braziliensis MHOM/BR/75/M2904"
lmx <- "L. mexicana MHOM/GT/2001/U1103"
lt <- "L. tarentolae Parrot-TarII"
tb <- "T. brucei brucei TREU927"
tc <- "T. cruzi CL Brener Esmeraldo-like"
large_query <- c(lm, lb, lmx, lt, tb, tc)

5 Perform ortholog searches.

## Get the braziliensis friends
small_query <- c(lm, lmx)
mmb_braz <- extract_eupath_orthologs(
  braziliensis_db,
  query_species=small_query)
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. major strain Friedlin
## Found species: L. mexicana MHOM/GT/2001/U1103
knitr::kable(head(mmb_braz))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LbrM.01.0010 LmjF.01.0630 L. major strain Friedlin OG5_183099 21 OG5_183099 2 0.5385
LbrM.01.0010 LmxM.01.0630 L. mexicana MHOM/GT/2001/U1103 OG5_183099 21 OG5_183099 2 0.5385
LbrM.01.0020 LmjF.01.0620 L. major strain Friedlin OG5_148171 37 OG5_148171 2 0.9487
LbrM.01.0020 LmxM.01.0620 L. mexicana MHOM/GT/2001/U1103 OG5_148171 37 OG5_148171 2 0.9487
LbrM.01.0030 LmjF.01.0610 L. major strain Friedlin OG5_128104 37 OG5_128104 2 0.9487
LbrM.01.0030 LmxM.01.0610 L. mexicana MHOM/GT/2001/U1103 OG5_128104 37 OG5_128104 2 0.9487
## Get the major friends.
## I am changing how these columns are named in the sqlite database to try and follow their conventions.
small_query <- c(lb, lmx)
mmb_major <- extract_eupath_orthologs(
  major_db,
  query_species=small_query,
  id_column="Ortholog_ID",
  org_column="Organism",
  url_column="Ortholog_Group",
  count_column="Ortholog_count")
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. braziliensis MHOM/BR/75/M2904
## Found species: L. mexicana MHOM/GT/2001/U1103
knitr::kable(head(mmb_major))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LmjF.01.0010 LbrM.01.0040 L. braziliensis MHOM/BR/75/M2904 OG5_183100 21 OG5_183100 2 0.5385
LmjF.01.0010 LmxM.01.0010 L. mexicana MHOM/GT/2001/U1103 OG5_183100 21 OG5_183100 2 0.5385
LmjF.01.0020 LbrM.01.0050 L. braziliensis MHOM/BR/75/M2904 OG5_148223 39 OG5_148223 2 1.0000
LmjF.01.0020 LmxM.01.0020 L. mexicana MHOM/GT/2001/U1103 OG5_148223 39 OG5_148223 2 1.0000
LmjF.01.0030 LbrM.01.0060 L. braziliensis MHOM/BR/75/M2904 OG5_127200 79 OG5_127200 4 2.0256
LmjF.01.0030 LbrM.13.1470 L. braziliensis MHOM/BR/75/M2904 OG5_127200 79 OG5_127200 4 2.0256
## Get the friends of mexicana
small_query <- c(lb, lm)
mmb_mex <- extract_eupath_orthologs(
  mexicana_db,
  query_species=small_query,
  id_column="Ortholog_ID",
  org_column="Organism",
  url_column="Ortholog_Group",
  count_column="Ortholog_count")
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. braziliensis MHOM/BR/75/M2904
## Found species: L. major strain Friedlin
knitr::kable(head(mmb_mex))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LmxM.01.0010 LbrM.01.0040 L. braziliensis MHOM/BR/75/M2904 OG5_183100 21 OG5_183100 2 0.5385
LmxM.01.0010 LmjF.01.0010 L. major strain Friedlin OG5_183100 21 OG5_183100 2 0.5385
LmxM.01.0020 LbrM.01.0050 L. braziliensis MHOM/BR/75/M2904 OG5_148223 39 OG5_148223 2 1.0000
LmxM.01.0020 LmjF.01.0020 L. major strain Friedlin OG5_148223 39 OG5_148223 2 1.0000
LmxM.01.0030 LbrM.01.0060 L. braziliensis MHOM/BR/75/M2904 OG5_127200 79 OG5_127200 4 2.0256
LmxM.01.0030 LbrM.13.1470 L. braziliensis MHOM/BR/75/M2904 OG5_127200 79 OG5_127200 4 2.0256

5.2 Also perform some with a couple of extra species

mmb_braz_large <- extract_eupath_orthologs(braziliensis_db, query_species=large_query)
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. major strain Friedlin
## Found species: L. braziliensis MHOM/BR/75/M2904
## Found species: L. mexicana MHOM/GT/2001/U1103
## Found species: L. tarentolae Parrot-TarII
## Found species: T. brucei brucei TREU927
## Found species: T. cruzi CL Brener Esmeraldo-like
knitr::kable(head(mmb_braz_large))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LbrM.01.0010 LbrM.01.0010 L. braziliensis MHOM/BR/75/M2904 OG5_183099 21 OG5_183099 4 0.5385
LbrM.01.0010 LmjF.01.0630 L. major strain Friedlin OG5_183099 21 OG5_183099 4 0.5385
LbrM.01.0010 LmxM.01.0630 L. mexicana MHOM/GT/2001/U1103 OG5_183099 21 OG5_183099 4 0.5385
LbrM.01.0010 LtaP01.0610 L. tarentolae Parrot-TarII OG5_183099 21 OG5_183099 4 0.5385
LbrM.01.0020 LbrM.01.0020 L. braziliensis MHOM/BR/75/M2904 OG5_148171 37 OG5_148171 6 0.9487
LbrM.01.0020 LmjF.01.0620 L. major strain Friedlin OG5_148171 37 OG5_148171 6 0.9487
mmb_major_large <- extract_eupath_orthologs(
  major_db,
  query_species=large_query,
  id_column="Ortholog_ID",
  org_column="Organism",
  url_column="Ortholog_Group",
  count_column="Ortholog_count")
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. major strain Friedlin
## Found species: L. braziliensis MHOM/BR/75/M2904
## Found species: L. mexicana MHOM/GT/2001/U1103
## Found species: L. tarentolae Parrot-TarII
## Found species: T. brucei brucei TREU927
## Found species: T. cruzi CL Brener Esmeraldo-like
knitr::kable(head(mmb_major_large))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LmjF.01.0010 LbrM.01.0040 L. braziliensis MHOM/BR/75/M2904 OG5_183100 21 OG5_183100 4 0.5385
LmjF.01.0010 LmjF.01.0010 L. major strain Friedlin OG5_183100 21 OG5_183100 4 0.5385
LmjF.01.0010 LmxM.01.0010 L. mexicana MHOM/GT/2001/U1103 OG5_183100 21 OG5_183100 4 0.5385
LmjF.01.0010 LtaP01.0010 L. tarentolae Parrot-TarII OG5_183100 21 OG5_183100 4 0.5385
LmjF.01.0020 LbrM.01.0050 L. braziliensis MHOM/BR/75/M2904 OG5_148223 39 OG5_148223 6 1.0000
LmjF.01.0020 LmjF.01.0020 L. major strain Friedlin OG5_148223 39 OG5_148223 6 1.0000
mmb_mex_large <- extract_eupath_orthologs(
  mexicana_db,
  query_species=large_query,
  id_column="Ortholog_ID",
  org_column="Organism",
  url_column="Ortholog_Group",
  count_column="Ortholog_count")
## 'select()' returned 1:many mapping between keys and columns
## There are 39 possible species in this group.
## Found species: L. major strain Friedlin
## Found species: L. braziliensis MHOM/BR/75/M2904
## Found species: L. mexicana MHOM/GT/2001/U1103
## Found species: L. tarentolae Parrot-TarII
## Found species: T. brucei brucei TREU927
## Found species: T. cruzi CL Brener Esmeraldo-like
knitr::kable(head(mmb_mex_large))
GID ORTHOLOG_ID ORTHOLOG_SPECIES ORTHOLOG_URL ORTHOLOG_COUNT ORTHOLOG_GROUP QUERIES_IN_GROUP GROUP_REPRESENTATION
LmxM.01.0010 LbrM.01.0040 L. braziliensis MHOM/BR/75/M2904 OG5_183100 21 OG5_183100 4 0.5385
LmxM.01.0010 LmjF.01.0010 L. major strain Friedlin OG5_183100 21 OG5_183100 4 0.5385
LmxM.01.0010 LmxM.01.0010 L. mexicana MHOM/GT/2001/U1103 OG5_183100 21 OG5_183100 4 0.5385
LmxM.01.0010 LtaP01.0010 L. tarentolae Parrot-TarII OG5_183100 21 OG5_183100 4 0.5385
LmxM.01.0020 LbrM.01.0050 L. braziliensis MHOM/BR/75/M2904 OG5_148223 39 OG5_148223 6 1.0000
LmxM.01.0020 LmjF.01.0020 L. major strain Friedlin OG5_148223 39 OG5_148223 6 1.0000

5.3 Write out the resulting tables

write.csv(x=mmb_braz, file="braziliensis_orthos_small.csv")
write.csv(x=mmb_major, file="major_orthos_small.csv")
write.csv(x=mmb_mex, file="mexicana_orthos_small.csv")

write.csv(x=mmb_braz_large, file="braziliensis_orthos_large.csv")
write.csv(x=mmb_major_large, file="major_orthos_large.csv")
write.csv(x=mmb_mex_large, file="mexicana_orthos_large.csv")

5.4 Now lets poke at the tables

5.4.1 How many groups?

If we get the number of unique group IDs, that should tell us how many orthology groups are in each data set.

## How many ortholog groups are in the data?
length(unique(mmb_braz[["ORTHOLOG_GROUP"]]))
## [1] 7313
length(unique(mmb_major[["ORTHOLOG_GROUP"]]))
## [1] 7469
length(unique(mmb_mex[["ORTHOLOG_GROUP"]]))
## [1] 7455

5.4.2 How many unique genes?

Any gene not in an ortholog group should be unique to that species. So lets merge the ortholog GIDs to the set of all genes in that species and see how many are left as NA.

maj <- unique(mmb_major[, c("GID", "ORTHOLOG_GROUP")])
colnames(maj) <- c("lmajor", "ID")
all <- as.data.frame(keys(major_db))
colnames(all) <- "lmajor"
all <- merge(all, maj, by="lmajor", all.x=TRUE)
na_idx <- is.na(all[["ID"]])
all[na_idx, "ID"] <- "lmajor"
maj <- all
major_alone <- sum(na_idx)
major_alone
## [1] 95
mex <- unique(mmb_mex[, c("GID", "ORTHOLOG_GROUP")])
colnames(mex) <- c("lmexicana", "ID")
all <- as.data.frame(keys(mexicana_db))
colnames(all) <- "lmexicana"
all <- merge(all, mex, by="lmexicana", all.x=TRUE)
na_idx <- is.na(all[["ID"]])
all[na_idx, "ID"] <- "lmexicana"
mex <- all
mexicana_alone <- sum(na_idx)
mexicana_alone
## [1] 106
braz <- unique(mmb_braz[, c("GID", "ORTHOLOG_GROUP")])
colnames(braz) <- c("lbraziliensis", "ID")
all <- as.data.frame(keys(braziliensis_db))
colnames(all) <- "lbraziliensis"
all <- merge(all, braz, by="lbraziliensis", all.x=TRUE)
na_idx <- is.na(all[["ID"]])
all[na_idx, "ID"] <- "lbraziliensis"
braz <- all
braziliensis_alone <- sum(na_idx)
braziliensis_alone
## [1] 339

5.4.3 Groups of two species

In the above, we made tables of ortholog family and gene ID. Therefore, if we merge them by family ID, then the number of unique families should give us an idea of pairwise similarity.

This is not quite the same thing as what we would want in a venn of the three species, as it includes the set of genes shared among all 3 species.

maj_mex <- merge(x=maj, y=mex, by="ID")
maj_mex_shared <- length(unique(maj_mex[["ID"]]))
maj_mex_shared
## [1] 7442
maj_braz <- merge(x=maj, y=braz, by="ID")
maj_braz_shared <- length(unique(maj_braz[["ID"]]))
maj_braz_shared
## [1] 7300
mex_braz <- merge(x=mex, y=braz, by="ID")
mex_braz_shared <- length(unique(mex_braz[["ID"]]))
mex_braz_shared
## [1] 7286

5.4.4 Shared among all three

Merging together any two of the pairs should get us the set of families in all three species.

maj_mex_braz <- merge(x=maj, y=mex, by="ID")
maj_mex_braz <- merge(x=maj_mex_braz, y=braz, by="ID")
all_shared <- length(unique(maj_mex_braz[["ID"]]))
all_shared
## [1] 7273

5.4.5 Union Intersections

Finally, the set of shared in each of the three pairs which are not shared among all three species.

Happily, we can get this by just asking for the set of IDs in the pair which are not in the set of all three.

mex_braz_only_idx <- ! mex_braz[["ID"]] %in% maj_mex_braz[["ID"]]
mex_braz_only_shared <- mex_braz[mex_braz_only_idx, ]
mex_braz_only <- length(unique(mex_braz_only_shared[["ID"]]))
mex_braz_only
## [1] 13
maj_braz_only_idx <- ! maj_braz[["ID"]] %in% maj_mex_braz[["ID"]]
maj_braz_only_shared <- maj_braz[maj_braz_only_idx, ]
maj_braz_only <- length(unique(maj_braz_only_shared[["ID"]]))
maj_braz_only
## [1] 27
maj_mex_only_idx <- ! maj_mex[["ID"]] %in% maj_mex_braz[["ID"]]
maj_mex_only_shared <- maj_mex[maj_mex_only_idx, ]
maj_mex_only <- length(unique(maj_mex_only_shared[["ID"]]))
maj_mex_only
## [1] 169

5.5 Make a venn of the data from above

names <- c("braziliensis", "major", "mexicana")
weights <- c(0,  ## The set of in-nothing
             braziliensis_alone, major_alone, maj_braz_only,
             mexicana_alone, mex_braz_only, maj_mex_only,
             all_shared)
venn_goodness <- Vennerable::Venn(SetNames=names,
                                  Weight=weights)
venn_plot <- Vennerable::plot(venn_goodness, doWeights=FALSE)

message(paste0("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 5d8c266e48bb9f73cdac8300e5c7c9f5baf003dc
## R> packrat::restore()
## This is hpgltools commit: Wed Mar 21 15:55:32 2018 -0400: 5d8c266e48bb9f73cdac8300e5c7c9f5baf003dc
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
## Saving to ortholog_search-v20180301.rda.xz
tmp <- sm(saveme(filename=this_save))
pander::pander(sessionInfo())

R version 3.4.4 (2018-03-15)

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

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

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

other attached packages: hpgltools(v.2018.03), dplyr(v.0.7.4), org.Lmexicana.MHOMGT2001U1103.v36.eg.db(v.2018.03), org.Lmajor.Friedlin.v36.eg.db(v.2018.03), reactome.db(v.1.62.0), GO.db(v.3.5.0), TxDb.Leishmania.braziliensis.MHOMBR75M2904.TriTrypDB.v36(v.2018.03), GenomicFeatures(v.1.30.3), GenomicRanges(v.1.30.3), GenomeInfoDb(v.1.14.0), org.Lbraziliensis.MHOMBR75M2904.v36.eg.db(v.2018.03), AnnotationForge(v.1.20.0), AnnotationDbi(v.1.40.0), IRanges(v.2.12.0), S4Vectors(v.0.16.0), Biobase(v.2.38.0), BiocGenerics(v.0.24.0) and bindrcpp(v.0.2)

loaded via a namespace (and not attached): bitops(v.1.0-6), matrixStats(v.0.53.1), devtools(v.1.13.5), bit64(v.0.9-7), RColorBrewer(v.1.1-2), progress(v.1.1.2), httr(v.1.3.1), rprojroot(v.1.3-2), backports(v.1.1.2), tools(v.3.4.4), utf8(v.1.1.3), R6(v.2.2.2), DBI(v.0.8), lazyeval(v.0.2.1), colorspace(v.1.3-2), withr(v.2.1.2), prettyunits(v.1.0.2), RMySQL(v.0.10.14), bit(v.1.1-12), curl(v.3.1), compiler(v.3.4.4), git2r(v.0.21.0), graph(v.1.56.0), cli(v.1.0.0), rvest(v.0.3.2), xml2(v.1.2.0), DelayedArray(v.0.4.1), rtracklayer(v.1.38.3), scales(v.0.5.0), RBGL(v.1.54.0), commonmark(v.1.4), stringr(v.1.3.0), digest(v.0.6.15), Rsamtools(v.1.30.0), rmarkdown(v.1.9), XVector(v.0.18.0), base64enc(v.0.1-3), htmltools(v.0.3.6), pkgconfig(v.2.0.1), highr(v.0.6), rlang(v.0.2.0), RSQLite(v.2.0), BiocInstaller(v.1.28.0), bindr(v.0.1.1), jsonlite(v.1.5), BiocParallel(v.1.12.0), RCurl(v.1.95-4.10), magrittr(v.1.5), GenomeInfoDbData(v.1.0.0), Matrix(v.1.2-12), Rcpp(v.0.12.16), munsell(v.0.4.3), yaml(v.2.1.18), stringi(v.1.1.7), SummarizedExperiment(v.1.8.1), zlibbioc(v.1.24.0), plyr(v.1.8.4), grid(v.3.4.4), blob(v.1.1.0), crayon(v.1.3.4), lattice(v.0.20-35), Biostrings(v.2.46.0), pander(v.0.6.1), knitr(v.1.20), pillar(v.1.2.1), reshape2(v.1.4.3), codetools(v.0.2-15), biomaRt(v.2.34.2), XML(v.3.98-1.10), glue(v.1.2.0), evaluate(v.0.10.1), Vennerable(v.3.1.0.9000), data.table(v.1.10.4-3), selectr(v.0.3-2), foreach(v.1.4.4), testthat(v.2.0.0), gtable(v.0.2.0), assertthat(v.0.2.0), ggplot2(v.2.2.1), roxygen2(v.6.0.1), tibble(v.1.4.2), OrganismDbi(v.1.20.0), iterators(v.1.0.9), GenomicAlignments(v.1.14.1) and memoise(v.1.1.0)

LS0tCnRpdGxlOiAiU29tZSBvcnRob2xvZyBzZWFyY2hpbmcuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiBodG1sX2RvY3VtZW50OgogIGNvZGVfZG93bmxvYWQ6IHRydWUKICBjb2RlX2ZvbGRpbmc6IHNob3cKICBmaWdfY2FwdGlvbjogdHJ1ZQogIGZpZ19oZWlnaHQ6IDcKICBmaWdfd2lkdGg6IDcKICBoaWdobGlnaHQ6IHRhbmdvCiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogY29zbW8KICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGg9OTAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGg9OCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplPTEwKSkKc2V0LnNlZWQoMSkKdmVyIDwtICIyMDE4MDMwMSIKcHJldmlvdXNfZmlsZSA8LSAiaW5kZXguUm1kIgoKdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCnJtZF9maWxlIDwtICJvcnRob2xvZ19zZWFyY2guUm1kIgpgYGAKClRlc3QgZGlmZmVyZW50IG9ydGhvbG9nL3BhcmFsb2cgc2VhcmNoIG1ldGhvZHMuCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIG9ydGhvbG9nIHZlcnNpb246IGByIHZlcmAKCk9uZSBvZiBTdGV2ZSdzIGdvYWxzIGlzIHRvIHByb3ZpZGUgb3J0aG9sb2cgdGFibGVzIGFjcm9zcyBMZWlzaG1hbmlhIG1ham9yLApicmF6aWxpZW5zaXMsIGFuZCBtZXhpY2FuYS4gIFRoZXJlIGFyZSBxdWl0ZSBhIGZldyBwb3NzaWJsZSB3YXlzIHRvIGRvIHRoaXMuCkxldHMgZXhwbG9yZSBzb21lIG9mIHRoZW0gaGVyZS4KCiMgQ3JlYXRlIHNxbGl0ZSBkYXRhYmFzZXMgZm9yIHNwZWNpZXMgb2YgaW50ZXJlc3QKClRoZSBmb2xsb3dpbmcgYmxvY2sgaXMgbm90IHJ1biBleGNlcHQgbWFudWFsbHksIGJlY2F1c2UgaXQgdGFrZXMgZWZmaW5nIGZvcmV2ZXIuCkFsc28sIEkgdXNlZCB0aGUgd3JvbmcgYnJhemlsaWVuc2lzIHN0cmFpbiEKCmBgYHtyIGNyZWF0ZV9zcWxpdGUsIGV2YWw9RkFMU0V9CiMjIFRoZSBvbmx5IG5pY2UgdGhpbmcgYWJvdXQgbXkgb3JnYW5pc21kYmkgbWFrZXIgaXMgdGhhdCBpdCB0YWtlcyBhcmJpdHJhcnkKIyMgc3RyaW5ncyBhbmQgd2lsbCB0cnkgdG8gZmluZCB0aGUgYXBwcm9wcmlhdGUgc3BlY2llcy4KYnJhel9zcWxpdGUgPC0gbWFrZV9ldXBhdGhfb3JnYW5pc21kYmkoIjI5MDQiKSAgIyMgc2hvcnRjdXQgZm9yIGJyYXppbGllbnNpcyBzdHJhaW4gMjkwNApicmF6X3NxbGl0ZSA8LSBtYWtlX2V1cGF0aF9vcmdhbmlzbWRiaSgibWFqb3IiKSAjIyBUaGlzIGlzIHN1ZmZpY2llbnQgdG8gZ2V0IEZyaWVkbGluCmJyYXpfc3FsaXRlIDwtIG1ha2VfZXVwYXRoX29yZ2FuaXNtZGJpKCJtZXhpY2FuYSIpICMjIFRoZXJlIGlzIG9ubHkgb25lIG1leGljYW5hIEkgdGhpbmsKYnJhel9zcWxpdGUgPC0gbWFrZV9ldXBhdGhfb3JnYW5pc21kYmkoInRhcmVudG9sYWUiKSAjIyBUaGVyZSBpcyBvbmx5IDEgdGFyZW50b2xhZQpicmF6X3NxbGl0ZSA8LSBtYWtlX2V1cGF0aF9vcmdhbmlzbWRiaSgiVFJFVTkyNyIpICMjIEkgYW0gYXNzdW1pbmcgOTI3CmJyYXpfc3FsaXRlIDwtIG1ha2VfZXVwYXRoX29yZ2FuaXNtZGJpKCJCcmVuZXIiKSAjIyBjcnV6aSBpcyBzdXBlciBjb25mdXNpbmcsIHRoaXMgaXMgcHJvYmFibHkgd3JvbmcuCmBgYAoKIyBMb2FkIHRoZSBzcWxpdGUgZGF0YSBmcm9tIHRoZSBldXBhdGhkYgoKYGBge3Igb3J0aG9sb2dfc3FsaXRlfQp0dCA8LSBzbShsaWJyYXJ5KG9yZy5MYnJhemlsaWVuc2lzLk1IT01CUjc1TTI5MDQudjM2LmVnLmRiKSkKdHQgPC0gc20obGlicmFyeShvcmcuTG1ham9yLkZyaWVkbGluLnYzNi5lZy5kYikpCnR0IDwtIHNtKGxpYnJhcnkob3JnLkxtZXhpY2FuYS5NSE9NR1QyMDAxVTExMDMudjM2LmVnLmRiKSkKCiMjIFNob3J0Y3V0IHRoZSBkYXRhYmFzZSBuYW1lcwpicmF6aWxpZW5zaXNfZGIgPC0gb3JnLkxicmF6aWxpZW5zaXMuTUhPTUJSNzVNMjkwNC52MzYuZWcuZGIKbWFqb3JfZGIgPC0gb3JnLkxtYWpvci5GcmllZGxpbi52MzYuZWcuZGIKbWV4aWNhbmFfZGIgPC0gb3JnLkxtZXhpY2FuYS5NSE9NR1QyMDAxVTExMDMudjM2LmVnLmRiCgphbGxfc3BlY2llc25hbWVzIDwtIGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncyhicmF6aWxpZW5zaXNfZGIsIHByaW50X3NwZWNpZXNuYW1lcz1UUlVFKQoKbG0gPC0gIkwuIG1ham9yIHN0cmFpbiBGcmllZGxpbiIKbGIgPC0gIkwuIGJyYXppbGllbnNpcyBNSE9NL0JSLzc1L00yOTA0IgpsbXggPC0gIkwuIG1leGljYW5hIE1IT00vR1QvMjAwMS9VMTEwMyIKbHQgPC0gIkwuIHRhcmVudG9sYWUgUGFycm90LVRhcklJIgp0YiA8LSAiVC4gYnJ1Y2VpIGJydWNlaSBUUkVVOTI3Igp0YyA8LSAiVC4gY3J1emkgQ0wgQnJlbmVyIEVzbWVyYWxkby1saWtlIgpsYXJnZV9xdWVyeSA8LSBjKGxtLCBsYiwgbG14LCBsdCwgdGIsIHRjKQpgYGAKCiMgUGVyZm9ybSBvcnRob2xvZyBzZWFyY2hlcy4KCmBgYHtyIHNlYXJjaH0KIyMgR2V0IHRoZSBicmF6aWxpZW5zaXMgZnJpZW5kcwpzbWFsbF9xdWVyeSA8LSBjKGxtLCBsbXgpCm1tYl9icmF6IDwtIGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncygKICBicmF6aWxpZW5zaXNfZGIsCiAgcXVlcnlfc3BlY2llcz1zbWFsbF9xdWVyeSkKa25pdHI6OmthYmxlKGhlYWQobW1iX2JyYXopKQoKIyMgR2V0IHRoZSBtYWpvciBmcmllbmRzLgojIyBJIGFtIGNoYW5naW5nIGhvdyB0aGVzZSBjb2x1bW5zIGFyZSBuYW1lZCBpbiB0aGUgc3FsaXRlIGRhdGFiYXNlIHRvIHRyeSBhbmQgZm9sbG93IHRoZWlyIGNvbnZlbnRpb25zLgpzbWFsbF9xdWVyeSA8LSBjKGxiLCBsbXgpCm1tYl9tYWpvciA8LSBleHRyYWN0X2V1cGF0aF9vcnRob2xvZ3MoCiAgbWFqb3JfZGIsCiAgcXVlcnlfc3BlY2llcz1zbWFsbF9xdWVyeSwKICBpZF9jb2x1bW49Ik9ydGhvbG9nX0lEIiwKICBvcmdfY29sdW1uPSJPcmdhbmlzbSIsCiAgdXJsX2NvbHVtbj0iT3J0aG9sb2dfR3JvdXAiLAogIGNvdW50X2NvbHVtbj0iT3J0aG9sb2dfY291bnQiKQprbml0cjo6a2FibGUoaGVhZChtbWJfbWFqb3IpKQoKIyMgR2V0IHRoZSBmcmllbmRzIG9mIG1leGljYW5hCnNtYWxsX3F1ZXJ5IDwtIGMobGIsIGxtKQptbWJfbWV4IDwtIGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncygKICBtZXhpY2FuYV9kYiwKICBxdWVyeV9zcGVjaWVzPXNtYWxsX3F1ZXJ5LAogIGlkX2NvbHVtbj0iT3J0aG9sb2dfSUQiLAogIG9yZ19jb2x1bW49Ik9yZ2FuaXNtIiwKICB1cmxfY29sdW1uPSJPcnRob2xvZ19Hcm91cCIsCiAgY291bnRfY29sdW1uPSJPcnRob2xvZ19jb3VudCIpCmtuaXRyOjprYWJsZShoZWFkKG1tYl9tZXgpKQpgYGAKCiMjIFByaW50IGEgcXVpY2sgc3VtbWFyeSB0YWJsZSBvZiBob3cgbWFueSB0aW1lcyBlYWNoIElEIGhhcyBvcnRob2xvZ3MuCgpBIGNhdmVhdCBoZXJlLCB0aGUgJ1FVRVJJRVNfSU5fR1JPVVAnIGNvbHVtbiBpcyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBvcnRob2xvZyBJRHMgZm91bmQuClRodXMgYSAxIGluIGl0IG1lYW5zIHRoYXQgdGhlcmUgd2FzIDEgb2JzZXJ2ZWQgR0lEIGZyb20gYW5vdGhlciBzcGVjaWVzLgoKYGBge3IgdGFibGVtZX0KdGFibGUobW1iX2JyYXokUVVFUklFU19JTl9HUk9VUCkKdGFibGUobW1iX21ham9yJFFVRVJJRVNfSU5fR1JPVVApCnRhYmxlKG1tYl9tZXgkUVVFUklFU19JTl9HUk9VUCkKYGBgCgojIyBBbHNvIHBlcmZvcm0gc29tZSB3aXRoIGEgY291cGxlIG9mIGV4dHJhIHNwZWNpZXMKCmBgYHtyIGxhcmdlcl9zZWFyY2hlc30KbW1iX2JyYXpfbGFyZ2UgPC0gZXh0cmFjdF9ldXBhdGhfb3J0aG9sb2dzKGJyYXppbGllbnNpc19kYiwgcXVlcnlfc3BlY2llcz1sYXJnZV9xdWVyeSkKa25pdHI6OmthYmxlKGhlYWQobW1iX2JyYXpfbGFyZ2UpKQoKbW1iX21ham9yX2xhcmdlIDwtIGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncygKICBtYWpvcl9kYiwKICBxdWVyeV9zcGVjaWVzPWxhcmdlX3F1ZXJ5LAogIGlkX2NvbHVtbj0iT3J0aG9sb2dfSUQiLAogIG9yZ19jb2x1bW49Ik9yZ2FuaXNtIiwKICB1cmxfY29sdW1uPSJPcnRob2xvZ19Hcm91cCIsCiAgY291bnRfY29sdW1uPSJPcnRob2xvZ19jb3VudCIpCmtuaXRyOjprYWJsZShoZWFkKG1tYl9tYWpvcl9sYXJnZSkpCgptbWJfbWV4X2xhcmdlIDwtIGV4dHJhY3RfZXVwYXRoX29ydGhvbG9ncygKICBtZXhpY2FuYV9kYiwKICBxdWVyeV9zcGVjaWVzPWxhcmdlX3F1ZXJ5LAogIGlkX2NvbHVtbj0iT3J0aG9sb2dfSUQiLAogIG9yZ19jb2x1bW49Ik9yZ2FuaXNtIiwKICB1cmxfY29sdW1uPSJPcnRob2xvZ19Hcm91cCIsCiAgY291bnRfY29sdW1uPSJPcnRob2xvZ19jb3VudCIpCmtuaXRyOjprYWJsZShoZWFkKG1tYl9tZXhfbGFyZ2UpKQpgYGAKCiMjIFdyaXRlIG91dCB0aGUgcmVzdWx0aW5nIHRhYmxlcwoKYGBge3Igd3JpdGVfdGhlbX0Kd3JpdGUuY3N2KHg9bW1iX2JyYXosIGZpbGU9ImJyYXppbGllbnNpc19vcnRob3Nfc21hbGwuY3N2IikKd3JpdGUuY3N2KHg9bW1iX21ham9yLCBmaWxlPSJtYWpvcl9vcnRob3Nfc21hbGwuY3N2IikKd3JpdGUuY3N2KHg9bW1iX21leCwgZmlsZT0ibWV4aWNhbmFfb3J0aG9zX3NtYWxsLmNzdiIpCgp3cml0ZS5jc3YoeD1tbWJfYnJhel9sYXJnZSwgZmlsZT0iYnJhemlsaWVuc2lzX29ydGhvc19sYXJnZS5jc3YiKQp3cml0ZS5jc3YoeD1tbWJfbWFqb3JfbGFyZ2UsIGZpbGU9Im1ham9yX29ydGhvc19sYXJnZS5jc3YiKQp3cml0ZS5jc3YoeD1tbWJfbWV4X2xhcmdlLCBmaWxlPSJtZXhpY2FuYV9vcnRob3NfbGFyZ2UuY3N2IikKYGBgCgojIyBOb3cgbGV0cyBwb2tlIGF0IHRoZSB0YWJsZXMKCiMjIyBIb3cgbWFueSBncm91cHM/CgpJZiB3ZSBnZXQgdGhlIG51bWJlciBvZiB1bmlxdWUgZ3JvdXAgSURzLCB0aGF0IHNob3VsZCB0ZWxsIHVzIGhvdyBtYW55IG9ydGhvbG9neQpncm91cHMgYXJlIGluIGVhY2ggZGF0YSBzZXQuCgpgYGB7ciBleGFtaW5lX3RhYmxlc30KIyMgSG93IG1hbnkgb3J0aG9sb2cgZ3JvdXBzIGFyZSBpbiB0aGUgZGF0YT8KbGVuZ3RoKHVuaXF1ZShtbWJfYnJheltbIk9SVEhPTE9HX0dST1VQIl1dKSkKbGVuZ3RoKHVuaXF1ZShtbWJfbWFqb3JbWyJPUlRIT0xPR19HUk9VUCJdXSkpCmxlbmd0aCh1bmlxdWUobW1iX21leFtbIk9SVEhPTE9HX0dST1VQIl1dKSkKYGBgCgojIyMgSG93IG1hbnkgdW5pcXVlIGdlbmVzPwoKQW55IGdlbmUgbm90IGluIGFuIG9ydGhvbG9nIGdyb3VwIHNob3VsZCBiZSB1bmlxdWUgdG8gdGhhdCBzcGVjaWVzLgpTbyBsZXRzIG1lcmdlIHRoZSBvcnRob2xvZyBHSURzIHRvIHRoZSBzZXQgb2YgYWxsIGdlbmVzIGluIHRoYXQgc3BlY2llcyBhbmQgc2VlCmhvdyBtYW55IGFyZSBsZWZ0IGFzIE5BLgoKYGBge3IgdW5pcXVlX2dlbmVzfQptYWogPC0gdW5pcXVlKG1tYl9tYWpvclssIGMoIkdJRCIsICJPUlRIT0xPR19HUk9VUCIpXSkKY29sbmFtZXMobWFqKSA8LSBjKCJsbWFqb3IiLCAiSUQiKQphbGwgPC0gYXMuZGF0YS5mcmFtZShrZXlzKG1ham9yX2RiKSkKY29sbmFtZXMoYWxsKSA8LSAibG1ham9yIgphbGwgPC0gbWVyZ2UoYWxsLCBtYWosIGJ5PSJsbWFqb3IiLCBhbGwueD1UUlVFKQpuYV9pZHggPC0gaXMubmEoYWxsW1siSUQiXV0pCmFsbFtuYV9pZHgsICJJRCJdIDwtICJsbWFqb3IiCm1haiA8LSBhbGwKbWFqb3JfYWxvbmUgPC0gc3VtKG5hX2lkeCkKbWFqb3JfYWxvbmUKCm1leCA8LSB1bmlxdWUobW1iX21leFssIGMoIkdJRCIsICJPUlRIT0xPR19HUk9VUCIpXSkKY29sbmFtZXMobWV4KSA8LSBjKCJsbWV4aWNhbmEiLCAiSUQiKQphbGwgPC0gYXMuZGF0YS5mcmFtZShrZXlzKG1leGljYW5hX2RiKSkKY29sbmFtZXMoYWxsKSA8LSAibG1leGljYW5hIgphbGwgPC0gbWVyZ2UoYWxsLCBtZXgsIGJ5PSJsbWV4aWNhbmEiLCBhbGwueD1UUlVFKQpuYV9pZHggPC0gaXMubmEoYWxsW1siSUQiXV0pCmFsbFtuYV9pZHgsICJJRCJdIDwtICJsbWV4aWNhbmEiCm1leCA8LSBhbGwKbWV4aWNhbmFfYWxvbmUgPC0gc3VtKG5hX2lkeCkKbWV4aWNhbmFfYWxvbmUKCmJyYXogPC0gdW5pcXVlKG1tYl9icmF6WywgYygiR0lEIiwgIk9SVEhPTE9HX0dST1VQIildKQpjb2xuYW1lcyhicmF6KSA8LSBjKCJsYnJhemlsaWVuc2lzIiwgIklEIikKYWxsIDwtIGFzLmRhdGEuZnJhbWUoa2V5cyhicmF6aWxpZW5zaXNfZGIpKQpjb2xuYW1lcyhhbGwpIDwtICJsYnJhemlsaWVuc2lzIgphbGwgPC0gbWVyZ2UoYWxsLCBicmF6LCBieT0ibGJyYXppbGllbnNpcyIsIGFsbC54PVRSVUUpCm5hX2lkeCA8LSBpcy5uYShhbGxbWyJJRCJdXSkKYWxsW25hX2lkeCwgIklEIl0gPC0gImxicmF6aWxpZW5zaXMiCmJyYXogPC0gYWxsCmJyYXppbGllbnNpc19hbG9uZSA8LSBzdW0obmFfaWR4KQpicmF6aWxpZW5zaXNfYWxvbmUKYGBgCgojIyMgR3JvdXBzIG9mIHR3byBzcGVjaWVzCgpJbiB0aGUgYWJvdmUsIHdlIG1hZGUgdGFibGVzIG9mIG9ydGhvbG9nIGZhbWlseSBhbmQgZ2VuZSBJRC4gIFRoZXJlZm9yZSwgaWYgd2UKbWVyZ2UgdGhlbSBieSBmYW1pbHkgSUQsIHRoZW4gdGhlIG51bWJlciBvZiB1bmlxdWUgZmFtaWxpZXMgc2hvdWxkIGdpdmUgdXMgYW4KaWRlYSBvZiBwYWlyd2lzZSBzaW1pbGFyaXR5LgoKVGhpcyBpcyBub3QgcXVpdGUgdGhlIHNhbWUgdGhpbmcgYXMgd2hhdCB3ZSB3b3VsZCB3YW50IGluIGEgdmVubiBvZiB0aGUgdGhyZWUKc3BlY2llcywgYXMgaXQgaW5jbHVkZXMgdGhlIHNldCBvZiBnZW5lcyBzaGFyZWQgYW1vbmcgYWxsIDMgc3BlY2llcy4KCmBgYHtyIG1lcmdlX3BhaXJzfQptYWpfbWV4IDwtIG1lcmdlKHg9bWFqLCB5PW1leCwgYnk9IklEIikKbWFqX21leF9zaGFyZWQgPC0gbGVuZ3RoKHVuaXF1ZShtYWpfbWV4W1siSUQiXV0pKQptYWpfbWV4X3NoYXJlZAoKbWFqX2JyYXogPC0gbWVyZ2UoeD1tYWosIHk9YnJheiwgYnk9IklEIikKbWFqX2JyYXpfc2hhcmVkIDwtIGxlbmd0aCh1bmlxdWUobWFqX2JyYXpbWyJJRCJdXSkpCm1hal9icmF6X3NoYXJlZAoKbWV4X2JyYXogPC0gbWVyZ2UoeD1tZXgsIHk9YnJheiwgYnk9IklEIikKbWV4X2JyYXpfc2hhcmVkIDwtIGxlbmd0aCh1bmlxdWUobWV4X2JyYXpbWyJJRCJdXSkpCm1leF9icmF6X3NoYXJlZApgYGAKCiMjIyBTaGFyZWQgYW1vbmcgYWxsIHRocmVlCgpNZXJnaW5nIHRvZ2V0aGVyIGFueSB0d28gb2YgdGhlIHBhaXJzIHNob3VsZCBnZXQgdXMgdGhlIHNldCBvZiBmYW1pbGllcyBpbiBhbGwKdGhyZWUgc3BlY2llcy4KCmBgYHtyIG1lcmdlX2FsbH0KbWFqX21leF9icmF6IDwtIG1lcmdlKHg9bWFqLCB5PW1leCwgYnk9IklEIikKbWFqX21leF9icmF6IDwtIG1lcmdlKHg9bWFqX21leF9icmF6LCB5PWJyYXosIGJ5PSJJRCIpCmFsbF9zaGFyZWQgPC0gbGVuZ3RoKHVuaXF1ZShtYWpfbWV4X2JyYXpbWyJJRCJdXSkpCmFsbF9zaGFyZWQKYGBgCgojIyMgVW5pb24gSW50ZXJzZWN0aW9ucwoKRmluYWxseSwgdGhlIHNldCBvZiBzaGFyZWQgaW4gZWFjaCBvZiB0aGUgdGhyZWUgcGFpcnMgd2hpY2ggYXJlIG5vdCBzaGFyZWQgYW1vbmcKYWxsIHRocmVlIHNwZWNpZXMuCgpIYXBwaWx5LCB3ZSBjYW4gZ2V0IHRoaXMgYnkganVzdCBhc2tpbmcgZm9yIHRoZSBzZXQgb2YgSURzIGluIHRoZSBwYWlyIHdoaWNoIGFyZQpub3QgaW4gdGhlIHNldCBvZiBhbGwgdGhyZWUuCgpgYGB7ciB1bmlvbl9pbnRlcnNlY3R9Cm1leF9icmF6X29ubHlfaWR4IDwtICEgbWV4X2JyYXpbWyJJRCJdXSAlaW4lIG1hal9tZXhfYnJheltbIklEIl1dCm1leF9icmF6X29ubHlfc2hhcmVkIDwtIG1leF9icmF6W21leF9icmF6X29ubHlfaWR4LCBdCm1leF9icmF6X29ubHkgPC0gbGVuZ3RoKHVuaXF1ZShtZXhfYnJhel9vbmx5X3NoYXJlZFtbIklEIl1dKSkKbWV4X2JyYXpfb25seQoKbWFqX2JyYXpfb25seV9pZHggPC0gISBtYWpfYnJheltbIklEIl1dICVpbiUgbWFqX21leF9icmF6W1siSUQiXV0KbWFqX2JyYXpfb25seV9zaGFyZWQgPC0gbWFqX2JyYXpbbWFqX2JyYXpfb25seV9pZHgsIF0KbWFqX2JyYXpfb25seSA8LSBsZW5ndGgodW5pcXVlKG1hal9icmF6X29ubHlfc2hhcmVkW1siSUQiXV0pKQptYWpfYnJhel9vbmx5CgptYWpfbWV4X29ubHlfaWR4IDwtICEgbWFqX21leFtbIklEIl1dICVpbiUgbWFqX21leF9icmF6W1siSUQiXV0KbWFqX21leF9vbmx5X3NoYXJlZCA8LSBtYWpfbWV4W21hal9tZXhfb25seV9pZHgsIF0KbWFqX21leF9vbmx5IDwtIGxlbmd0aCh1bmlxdWUobWFqX21leF9vbmx5X3NoYXJlZFtbIklEIl1dKSkKbWFqX21leF9vbmx5CmBgYAoKIyMgTWFrZSBhIHZlbm4gb2YgdGhlIGRhdGEgZnJvbSBhYm92ZQoKYGBge3IgdmVubn0KbmFtZXMgPC0gYygiYnJhemlsaWVuc2lzIiwgIm1ham9yIiwgIm1leGljYW5hIikKd2VpZ2h0cyA8LSBjKDAsICAjIyBUaGUgc2V0IG9mIGluLW5vdGhpbmcKICAgICAgICAgICAgIGJyYXppbGllbnNpc19hbG9uZSwgbWFqb3JfYWxvbmUsIG1hal9icmF6X29ubHksCiAgICAgICAgICAgICBtZXhpY2FuYV9hbG9uZSwgbWV4X2JyYXpfb25seSwgbWFqX21leF9vbmx5LAogICAgICAgICAgICAgYWxsX3NoYXJlZCkKdmVubl9nb29kbmVzcyA8LSBWZW5uZXJhYmxlOjpWZW5uKFNldE5hbWVzPW5hbWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2VpZ2h0PXdlaWdodHMpCnZlbm5fcGxvdCA8LSBWZW5uZXJhYmxlOjpwbG90KHZlbm5fZ29vZG5lc3MsIGRvV2VpZ2h0cz1GQUxTRSkKYGBgCgpgYGB7ciBzYXZlbWV9Cm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKYGBgCg==