1 Simulated digestion of PE proteins: 20171205

I did a little reading of the paper: “Structural basis of the PE-PPE protein interaction in Mycobacterium tuberculosis” and quickly realized that when Dr. Briken was asking for the set of PE containing genes, he was not in fact asking for the set of all genes with ‘PE’ in them, but in fact a set of annotated genes.

I therefore extracted those gene IDs from the gene annotations and left them in the file ‘annotated_pe_genes.txt’. In my previous test, I did a string search of all the peptides for ones containing ‘PE’ or ‘PPE’. This time I will just use the annotated peptides.

Let us therefore read peptide sequences into memory and extract only these 161 peptides. Then perform some digestions and see what happens.

1.1 Reading the peptides

This is performed via the R Biostrings package.

## Start out reading in all peptides.
mtb_peptides <- Biostrings::readAAStringSet(filepath="reference/mtb_cds.fasta")
summary(mtb_peptides)
##      Length       Class        Mode 
##        4008 AAStringSet          S4
## Get the IDs of the PE proteins.
pe_ids <- read.table("reference/annotated_pe_genes.txt", header=FALSE)[["V1"]]
## Subset all peptides for just these.
mtb_pe <- mtb_peptides[pe_ids, ]
summary(mtb_pe)
##      Length       Class        Mode 
##         161 AAStringSet          S4
pe_fasta <- Biostrings::writeXStringSet(x=mtb_pe, filepath="reference/mtb_pe.fasta")

1.2 Look for idealized digestion products

The cleaver package provides easy sample digestions of arbitrary peptide sequences. In addition, the BRAIN package provides center-mass calculations for the resulting peptide fragments. These may therefore be plotted as example spectra. I will copy the plotting implementation from the cleaver documentation in the following code block.

At this point, it is useful to note some information provide by Yan: “I’d like to be able to look at the sizes of expected trypsin and chymotrypsin digests and compare the unidentified spectra in the raw data to see if they match up. That will give us a rough idea on whether our problem is more in digestion or MSMS data itself. … Would you be able to do in silico digestion of all PE proteins by trypsin, cymotrypsin, Glu-C and Asp-N? Assuming we use the same LCMS method, our best bet is to identify peptides in the range of 700-3000 Da…”

1.3 Perform test digestions

The above function should probably be changed a little to provide some better visualization, but for the moment let us just see what happens.

1.3.1 Trypsin

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
cleavage_histogram <- function(pep_sequences, enzyme="trypsin",
                               start=600, end=1500, color="black") {
  products <- cleaver::cleave(pep_sequences, enzym=enzyme)
  prod_df <- as.data.frame(products)
  prod_df <- as.tbl(prod_df[, c("group_name", "value")])
  colnames(prod_df) <- c("group_name", "sequence")

  gather_masses <- function(sequence) {
    atoms <- try(BRAIN::getAtomsFromSeq(sequence), silent=TRUE)
    if (class(atoms) != "try-error") {
      d <- BRAIN::useBRAIN(atoms)
      ret <- round(d[["avgMass"]])
    } else {
      ret <- 0
    }
    return(ret)
  }

  new_df <- prod_df %>% rowwise() %>% mutate(mass=gather_masses(sequence))

  plot <- ggplot2::ggplot(data=new_df, ggplot2::aes_string(x="mass")) +
    ggplot2::geom_histogram(binwidth=1, colour=color) +
    ggplot2::scale_x_continuous(limits=c(start, end))

  retlist <- list(
    "plot" = plot,
    "masses" = new_df)
  return(retlist)
}
tt <- pp(file="images/tryp_intensity_600_1500.png")
## Going to write the image to: images/tryp_intensity_600_1500.png when dev.off() is called.
tryp_low <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="trypsin",
                            start=600, end=1500))
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/tryp_intensity_1500_3000.png")
## Going to write the image to: images/tryp_intensity_1500_3000.png when dev.off() is called.
tryp_mid <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="trypsin",
                            start=1500, end=3000))
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/tryp_intensity_1500_3000.png")
## Going to write the image to: images/tryp_intensity_1500_3000.png when dev.off() is called.
tryp_high <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="trypsin",
                             start=3000, end=5000))
dev.off()
## X11cairo 
##        2

1.3.2 Again as histograms rather than approximate intensity

tt <- pp(file="images/pe_tryp_600_1500.png")
## Going to write the image to: images/pe_tryp_600_1500.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, color="red")$plot
## Warning: Removed 1492 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_tryp_1500_3000.png")
## Going to write the image to: images/pe_tryp_1500_3000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, start=1500, end=3000, color="red")$plot
## Warning: Removed 1461 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_tryp_3000_5000.png")
## Going to write the image to: images/pe_tryp_3000_5000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, start=3000, end=5000, color="red")$plot
## Warning: Removed 1618 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2

1.3.3 ChymoTrypsin high specificity

tt <- pp(file="images/chymo_intensity_600_1500.png")
## Going to write the image to: images/chymo_intensity_600_1500.png when dev.off() is called.
chy_low <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="chymotrypsin-high",))
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/chymo_intensity_1500_3000.png")
## Going to write the image to: images/chymo_intensity_1500_3000.png when dev.off() is called.
chy_mid <-  sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="chymotrypsin-high",
                            start=2000, end=3500))
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/chymo_intensity_3000_5000.png")
## Going to write the image to: images/chymo_intensity_3000_5000.png when dev.off() is called.
chy_high <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="chymotrypsin-high",
                            start=3500, end=5000))
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_chymo_600_1500.png")
## Going to write the image to: images/pe_chymo_600_1500.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="chymotrypsin-high", color="blue")$plot
## Warning: Removed 2945 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_chymo_1500_3000.png")
## Going to write the image to: images/pe_chymo_1500_3000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="chymotrypsin-high", start=1500, end=3000, color="blue")$plot
## Warning: Removed 3785 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_chymo_3000_5000.png")
## Going to write the image to: images/pe_chymo_3000_5000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="chymotrypsin-high", start=3000, end=5000, color="blue")$plot
## Warning: Removed 4267 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2

1.3.4 asp-n endopeptidase

aspn_low <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase"))

aspn_mid <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase",
                             start=2000, end=3500))

aspn_high <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase",
                             start=3500, end=5000))

cleavage_histogram(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase", color="darkgreen")$plot
## Warning: Removed 2105 rows containing non-finite values (stat_bin).

dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_aspn_1500_3000.png")
## Going to write the image to: images/pe_aspn_1500_3000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase", start=1500, end=3000, color="darkgreen")$plot
## Warning: Removed 2003 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_aspn_3000_5000.png")
## Going to write the image to: images/pe_aspn_3000_5000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase", start=3000, end=5000, color="darkgreen")$plot
## Warning: Removed 2259 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_glu_1500_3000.png")
## Going to write the image to: images/pe_glu_1500_3000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase", color="purple")$plot
## Warning: Removed 1333 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_glu_1500_3000.png")
## Going to write the image to: images/pe_glu_1500_3000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase", start=1500, end=3000, color="darkgreen")$plot
## Warning: Removed 1388 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2
tt <- pp(file="images/pe_glu_3000_5000.png")
## Going to write the image to: images/pe_glu_3000_5000.png when dev.off() is called.
cleavage_histogram(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase", start=3000, end=5000, color="darkgreen")$plot
## Warning: Removed 1479 rows containing non-finite values (stat_bin).
dev.off()
## X11cairo 
##        2

1.3.5 glu-c endopeptidase

glu_low <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase",
                           start=700, end=2000))

glu_high <- sm(plot_cleaved(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase",
                            start=2000, end=3000))

1.4 Compare simulated PE vs all

all_tryp <- cleavage_histogram(pep_sequences=mtb_pe)$masses
all_tryp$enzyme <- "tryp"
all_chy <- cleavage_histogram(pep_sequences=mtb_pe, enzyme="chymotrypsin-high")$masses
all_chy$enzyme <- "chymo"
all_aspn <- cleavage_histogram(pep_sequences=mtb_pe, enzyme="asp-n endopeptidase")$masses
all_aspn$enzyme <- "aspn"
all_glu <- cleavage_histogram(pep_sequences=mtb_pe, enzyme="glutamyl endopeptidase")$masses
all_glu$enzyme <- "glu"

all_df <- all_tryp[, c("enzyme", "mass")]
all_df <- rbind(all_df, all_chy[, c("enzyme","mass")])
all_df <- rbind(all_df, all_aspn[, c("enzyme", "mass")])
all_df <- rbind(all_df, all_glu[, c("enzyme", "mass")])
all_df <- as.data.frame(all_df)
all_df$enzyme <- as.factor(all_df$enzyme)
all_df$l2mass <- log2(all_df$mass + 1)

comparison <- ggplot(data=all_df, aes_string(x="mass", group="enzyme", colour="enzyme")) +
  geom_density() +
  scale_x_continuous(limits=c(0,10000))
## Error in ggplot(data = all_df, aes_string(x = "mass", group = "enzyme", : could not find function "ggplot"
pp(file="images/density_enzymes.png")
## Going to write the image to: images/density_enzymes.png when dev.off() is called.
## NULL
comparison
## Error in eval(expr, envir, enclos): object 'comparison' not found
dev.off()
## X11cairo 
##        2
pe_distribution <- tryp_low[["sizes"]]
all_trypsin_distribution <- plot_cleaved(pep_sequences=mtb_peptides, enzyme="trypsin", start=2000, end=2010)

all_chymo_distribution <- plot_cleaved(pep_sequences=mtb_peptides, enzyme="chymotrypsin-high", start=2000, end=2010)

pe_names <- unique(pe_distribution[["cds"]])

distribution <- all_trypsin_distribution
plot_spectra <- function(distribution, subset=pe_names) {
  all_sizes <- distribution[["sizes"]]
  all_sizes[["subset"]] <- 0
  subset_found <- all_sizes[["cds"]] %in% subset
  all_sizes[subset_found, "subset"] <- 1
  all_sizes[["average_mass"]] <- as.numeric(all_sizes[["average_mass"]])
  all_sizes[["highest_likelihood"]] <- as.numeric(all_sizes[["highest_likelihood"]])

  a_plot <- ggplot2::ggplot(data=all_sizes,
                            ggplot2::aes_string(x="average_mass",
                                                y="highest_likelihood",
                                                colour="as.factor(subset)")) +
    ggplot2::geom_point(alpha=0.3, size=2, stat="identity") +
    ggplot2::scale_color_manual(name="as.factor(subset)",
                                values=c("0"="darkblue", "1"="darkred"))
  return(a_plot)
}

trypsin_dist_plot <- plot_spectra(all_trypsin_distribution)
pp(file="images/tryp_dist_plot.png")
## Going to write the image to: images/tryp_dist_plot.png when dev.off() is called.
## NULL
trypsin_dist_plot
dev.off()
## X11cairo 
##        2
chymotrypsin_dist_plot <- plot_spectra(all_chymo_distribution)

pp(file="images/chymo_dist_plot.png")
## Going to write the image to: images/chymo_dist_plot.png when dev.off() is called.
## NULL
chymotrypsin_dist_plot
dev.off()
## X11cairo 
##        2
## I think this demonstrates nicely how much more efficient chymotrypsin is for pe proteins.
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: stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: bindrcpp(v.0.2), dplyr(v.0.7.4) and hpgltools(v.2018.03)

loaded via a namespace (and not attached): Rcpp(v.0.12.16), bindr(v.0.1.1), pillar(v.1.2.1), compiler(v.3.4.4), plyr(v.1.8.4), XVector(v.0.18.0), base64enc(v.0.1-3), iterators(v.1.0.9), tools(v.3.4.4), zlibbioc(v.1.24.0), digest(v.0.6.15), evaluate(v.0.10.1), lattice(v.0.20-35), memoise(v.1.1.0), tibble(v.1.4.2), gtable(v.0.2.0), pkgconfig(v.2.0.1), rlang(v.0.2.0), foreach(v.1.4.4), commonmark(v.1.4), yaml(v.2.1.18), parallel(v.3.4.4), withr(v.2.1.2), stringr(v.1.3.0), knitr(v.1.20), roxygen2(v.6.0.1), xml2(v.1.2.0), Biostrings(v.2.46.0), S4Vectors(v.0.16.0), devtools(v.1.13.5), IRanges(v.2.12.0), rprojroot(v.1.3-2), stats4(v.3.4.4), grid(v.3.4.4), glue(v.1.2.0), data.table(v.1.10.4-3), Biobase(v.2.38.0), PolynomF(v.1.0-1), R6(v.2.2.2), rmarkdown(v.1.9), pander(v.0.6.1), ggplot2(v.2.2.1), cleaver(v.1.16.0), magrittr(v.1.5), backports(v.1.1.2), htmltools(v.0.3.6), scales(v.0.5.0), codetools(v.0.2-15), BiocGenerics(v.0.24.0), assertthat(v.0.2.0), colorspace(v.1.3-2), labeling(v.0.3), stringi(v.1.1.7), lazyeval(v.0.2.1), munsell(v.0.4.3) and BRAIN(v.1.24.0)

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 2a0661d6e37f8a3d8831eb3bbd6347c0d9c4b3b7
## R> packrat::restore()
## This is hpgltools commit: Thu Mar 29 16:59:07 2018 -0400: 2a0661d6e37f8a3d8831eb3bbd6347c0d9c4b3b7
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
## Saving to 03_simulated_pe_digestions-v20171205.rda.xz
tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxNzogVGVzdGluZyBvdXQgUHJvdGVvbWljcyBhbmFseXNlcy4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICAgY29sbGFwc2VkOiBmYWxzZQogICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcz1UUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0PTgsCiAgICAgICAgICAgICAgICAgICAgICBkcGk9OTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnNldC5zZWVkKDEpCnZlciA8LSAiMjAxNzEyMDUiCnByZXZpb3VzX2ZpbGUgPC0gIjAxX2Fubm90YXRpb24uUm1kIgoKdG1wIDwtIHRyeShzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkpCnJtZF9maWxlIDwtICIwM19zaW11bGF0ZWRfcGVfZGlnZXN0aW9ucy5SbWQiCmBgYAoKIyBTaW11bGF0ZWQgZGlnZXN0aW9uIG9mIFBFIHByb3RlaW5zOiBgciB2ZXJgCgpJIGRpZCBhIGxpdHRsZSByZWFkaW5nIG9mIHRoZSBwYXBlcjoKIlN0cnVjdHVyYWwgYmFzaXMgb2YgdGhlIFBFLVBQRSBwcm90ZWluIGludGVyYWN0aW9uIGluIE15Y29iYWN0ZXJpdW0KdHViZXJjdWxvc2lzIiBhbmQgcXVpY2tseSByZWFsaXplZCB0aGF0IHdoZW4gRHIuIEJyaWtlbiB3YXMgYXNraW5nIGZvciB0aGUgc2V0Cm9mIFBFIGNvbnRhaW5pbmcgZ2VuZXMsIGhlIHdhcyBub3QgaW4gZmFjdCBhc2tpbmcgZm9yIHRoZSBzZXQgb2YgYWxsIGdlbmVzIHdpdGgKJ1BFJyBpbiB0aGVtLCBidXQgaW4gZmFjdCBhIHNldCBvZiBhbm5vdGF0ZWQgZ2VuZXMuCgpJIHRoZXJlZm9yZSBleHRyYWN0ZWQgdGhvc2UgZ2VuZSBJRHMgZnJvbSB0aGUgZ2VuZSBhbm5vdGF0aW9ucyBhbmQgbGVmdCB0aGVtIGluCnRoZSBmaWxlICdhbm5vdGF0ZWRfcGVfZ2VuZXMudHh0Jy4gIEluIG15IHByZXZpb3VzIHRlc3QsIEkgZGlkIGEgc3RyaW5nIHNlYXJjaApvZiBhbGwgdGhlIHBlcHRpZGVzIGZvciBvbmVzIGNvbnRhaW5pbmcgJ1BFJyBvciAnUFBFJy4gIFRoaXMgdGltZSBJIHdpbGwganVzdAp1c2UgdGhlIGFubm90YXRlZCBwZXB0aWRlcy4KCkxldCB1cyB0aGVyZWZvcmUgcmVhZCBwZXB0aWRlIHNlcXVlbmNlcyBpbnRvIG1lbW9yeSBhbmQgZXh0cmFjdCBvbmx5IHRoZXNlIDE2MQpwZXB0aWRlcy4gIFRoZW4gcGVyZm9ybSBzb21lIGRpZ2VzdGlvbnMgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCgojIyBSZWFkaW5nIHRoZSBwZXB0aWRlcwoKVGhpcyBpcyBwZXJmb3JtZWQgdmlhIHRoZSBSIEJpb3N0cmluZ3MgcGFja2FnZS4KCmBgYHtyIHBlcHRpZGVzfQojIyBTdGFydCBvdXQgcmVhZGluZyBpbiBhbGwgcGVwdGlkZXMuCm10Yl9wZXB0aWRlcyA8LSBCaW9zdHJpbmdzOjpyZWFkQUFTdHJpbmdTZXQoZmlsZXBhdGg9InJlZmVyZW5jZS9tdGJfY2RzLmZhc3RhIikKc3VtbWFyeShtdGJfcGVwdGlkZXMpCgojIyBHZXQgdGhlIElEcyBvZiB0aGUgUEUgcHJvdGVpbnMuCnBlX2lkcyA8LSByZWFkLnRhYmxlKCJyZWZlcmVuY2UvYW5ub3RhdGVkX3BlX2dlbmVzLnR4dCIsIGhlYWRlcj1GQUxTRSlbWyJWMSJdXQojIyBTdWJzZXQgYWxsIHBlcHRpZGVzIGZvciBqdXN0IHRoZXNlLgptdGJfcGUgPC0gbXRiX3BlcHRpZGVzW3BlX2lkcywgXQpzdW1tYXJ5KG10Yl9wZSkKCnBlX2Zhc3RhIDwtIEJpb3N0cmluZ3M6OndyaXRlWFN0cmluZ1NldCh4PW10Yl9wZSwgZmlsZXBhdGg9InJlZmVyZW5jZS9tdGJfcGUuZmFzdGEiKQpgYGAKCiMjIExvb2sgZm9yIGlkZWFsaXplZCBkaWdlc3Rpb24gcHJvZHVjdHMKClRoZSBjbGVhdmVyIHBhY2thZ2UgcHJvdmlkZXMgZWFzeSBzYW1wbGUgZGlnZXN0aW9ucyBvZiBhcmJpdHJhcnkgcGVwdGlkZQpzZXF1ZW5jZXMuICBJbiBhZGRpdGlvbiwgdGhlIEJSQUlOIHBhY2thZ2UgcHJvdmlkZXMgY2VudGVyLW1hc3MgY2FsY3VsYXRpb25zIGZvcgp0aGUgcmVzdWx0aW5nIHBlcHRpZGUgZnJhZ21lbnRzLiAgVGhlc2UgbWF5IHRoZXJlZm9yZSBiZSBwbG90dGVkIGFzIGV4YW1wbGUKc3BlY3RyYS4gIEkgd2lsbCBjb3B5IHRoZSBwbG90dGluZyBpbXBsZW1lbnRhdGlvbiBmcm9tIHRoZSBjbGVhdmVyIGRvY3VtZW50YXRpb24KaW4gdGhlIGZvbGxvd2luZyBjb2RlIGJsb2NrLgoKQXQgdGhpcyBwb2ludCwgaXQgaXMgdXNlZnVsIHRvIG5vdGUgc29tZSBpbmZvcm1hdGlvbiBwcm92aWRlIGJ5IFlhbjoKIkknZCBsaWtlIHRvIGJlIGFibGUgdG8gbG9vayBhdCB0aGUgc2l6ZXMgb2YgZXhwZWN0ZWQgdHJ5cHNpbiBhbmQgY2h5bW90cnlwc2luCmRpZ2VzdHMgYW5kIGNvbXBhcmUgdGhlIHVuaWRlbnRpZmllZCBzcGVjdHJhIGluIHRoZSByYXcgZGF0YSB0byBzZWUgaWYgdGhleQptYXRjaCB1cC4gIFRoYXQgd2lsbCBnaXZlIHVzIGEgcm91Z2ggaWRlYSBvbiB3aGV0aGVyIG91ciBwcm9ibGVtIGlzIG1vcmUgaW4KZGlnZXN0aW9uIG9yIE1TTVMgZGF0YSBpdHNlbGYuICAuLi4gIFdvdWxkIHlvdSBiZSBhYmxlIHRvIGRvIGluIHNpbGljbyBkaWdlc3Rpb24Kb2YgYWxsIFBFIHByb3RlaW5zIGJ5IHRyeXBzaW4sIGN5bW90cnlwc2luLCBHbHUtQyBhbmQgQXNwLU4/ICBBc3N1bWluZyB3ZSB1c2UKdGhlIHNhbWUgTENNUyBtZXRob2QsIG91ciBiZXN0IGJldCBpcyB0byBpZGVudGlmeSBwZXB0aWRlcyBpbiB0aGUgcmFuZ2Ugb2YKNzAwLTMwMDAgRGEuLi4iCgojIyBQZXJmb3JtIHRlc3QgZGlnZXN0aW9ucwoKVGhlIGFib3ZlIGZ1bmN0aW9uIHNob3VsZCBwcm9iYWJseSBiZSBjaGFuZ2VkIGEgbGl0dGxlIHRvIHByb3ZpZGUgc29tZSBiZXR0ZXIKdmlzdWFsaXphdGlvbiwgYnV0IGZvciB0aGUgbW9tZW50IGxldCB1cyBqdXN0IHNlZSB3aGF0IGhhcHBlbnMuCgojIyMgVHJ5cHNpbgoKYGBge3IgYmFkX3Bsb3R9CmxpYnJhcnkoZHBseXIpCmNsZWF2YWdlX2hpc3RvZ3JhbSA8LSBmdW5jdGlvbihwZXBfc2VxdWVuY2VzLCBlbnp5bWU9InRyeXBzaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9NjAwLCBlbmQ9MTUwMCwgY29sb3I9ImJsYWNrIikgewogIHByb2R1Y3RzIDwtIGNsZWF2ZXI6OmNsZWF2ZShwZXBfc2VxdWVuY2VzLCBlbnp5bT1lbnp5bWUpCiAgcHJvZF9kZiA8LSBhcy5kYXRhLmZyYW1lKHByb2R1Y3RzKQogIHByb2RfZGYgPC0gYXMudGJsKHByb2RfZGZbLCBjKCJncm91cF9uYW1lIiwgInZhbHVlIildKQogIGNvbG5hbWVzKHByb2RfZGYpIDwtIGMoImdyb3VwX25hbWUiLCAic2VxdWVuY2UiKQoKICBnYXRoZXJfbWFzc2VzIDwtIGZ1bmN0aW9uKHNlcXVlbmNlKSB7CiAgICBhdG9tcyA8LSB0cnkoQlJBSU46OmdldEF0b21zRnJvbVNlcShzZXF1ZW5jZSksIHNpbGVudD1UUlVFKQogICAgaWYgKGNsYXNzKGF0b21zKSAhPSAidHJ5LWVycm9yIikgewogICAgICBkIDwtIEJSQUlOOjp1c2VCUkFJTihhdG9tcykKICAgICAgcmV0IDwtIHJvdW5kKGRbWyJhdmdNYXNzIl1dKQogICAgfSBlbHNlIHsKICAgICAgcmV0IDwtIDAKICAgIH0KICAgIHJldHVybihyZXQpCiAgfQoKICBuZXdfZGYgPC0gcHJvZF9kZiAlPiUgcm93d2lzZSgpICU+JSBtdXRhdGUobWFzcz1nYXRoZXJfbWFzc2VzKHNlcXVlbmNlKSkKCiAgcGxvdCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YT1uZXdfZGYsIGdncGxvdDI6OmFlc19zdHJpbmcoeD0ibWFzcyIpKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xLCBjb2xvdXI9Y29sb3IpICsKICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YyhzdGFydCwgZW5kKSkKCiAgcmV0bGlzdCA8LSBsaXN0KAogICAgInBsb3QiID0gcGxvdCwKICAgICJtYXNzZXMiID0gbmV3X2RmKQogIHJldHVybihyZXRsaXN0KQp9CmBgYAoKYGBge3IgcGxvdF90cnlwfQoKdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL3RyeXBfaW50ZW5zaXR5XzYwMF8xNTAwLnBuZyIpCnRyeXBfbG93IDwtIHNtKHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJ0cnlwc2luIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0PTYwMCwgZW5kPTE1MDApKQpkZXYub2ZmKCkKCnR0IDwtIHBwKGZpbGU9ImltYWdlcy90cnlwX2ludGVuc2l0eV8xNTAwXzMwMDAucG5nIikKdHJ5cF9taWQgPC0gc20ocGxvdF9jbGVhdmVkKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9InRyeXBzaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9MTUwMCwgZW5kPTMwMDApKQpkZXYub2ZmKCkKdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL3RyeXBfaW50ZW5zaXR5XzE1MDBfMzAwMC5wbmciKQp0cnlwX2hpZ2ggPC0gc20ocGxvdF9jbGVhdmVkKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9InRyeXBzaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0PTMwMDAsIGVuZD01MDAwKSkKZGV2Lm9mZigpCmBgYAoKIyMjIEFnYWluIGFzIGhpc3RvZ3JhbXMgcmF0aGVyIHRoYW4gYXBwcm94aW1hdGUgaW50ZW5zaXR5CgpgYGB7ciB0cnlwX2hpc3R9CnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV90cnlwXzYwMF8xNTAwLnBuZyIpCmNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgY29sb3I9InJlZCIpJHBsb3QKZGV2Lm9mZigpCnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV90cnlwXzE1MDBfMzAwMC5wbmciKQpjbGVhdmFnZV9oaXN0b2dyYW0ocGVwX3NlcXVlbmNlcz1tdGJfcGUsIHN0YXJ0PTE1MDAsIGVuZD0zMDAwLCBjb2xvcj0icmVkIikkcGxvdApkZXYub2ZmKCkKdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL3BlX3RyeXBfMzAwMF81MDAwLnBuZyIpCmNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgc3RhcnQ9MzAwMCwgZW5kPTUwMDAsIGNvbG9yPSJyZWQiKSRwbG90CmRldi5vZmYoKQpgYGAKCiMjIyBDaHltb1RyeXBzaW4gaGlnaCBzcGVjaWZpY2l0eQoKYGBge3IgcGxvdF9jaHltb30KdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL2NoeW1vX2ludGVuc2l0eV82MDBfMTUwMC5wbmciKQpjaHlfbG93IDwtIHNtKHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJjaHltb3RyeXBzaW4taGlnaCIsKSkKZGV2Lm9mZigpCnR0IDwtIHBwKGZpbGU9ImltYWdlcy9jaHltb19pbnRlbnNpdHlfMTUwMF8zMDAwLnBuZyIpCmNoeV9taWQgPC0gIHNtKHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJjaHltb3RyeXBzaW4taGlnaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydD0yMDAwLCBlbmQ9MzUwMCkpCmRldi5vZmYoKQp0dCA8LSBwcChmaWxlPSJpbWFnZXMvY2h5bW9faW50ZW5zaXR5XzMwMDBfNTAwMC5wbmciKQpjaHlfaGlnaCA8LSBzbShwbG90X2NsZWF2ZWQocGVwX3NlcXVlbmNlcz1tdGJfcGUsIGVuenltZT0iY2h5bW90cnlwc2luLWhpZ2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9MzUwMCwgZW5kPTUwMDApKQpkZXYub2ZmKCkKYGBgCgpgYGB7ciBjaHl0cnlwX2hpc3R9CnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV9jaHltb182MDBfMTUwMC5wbmciKQpjbGVhdmFnZV9oaXN0b2dyYW0ocGVwX3NlcXVlbmNlcz1tdGJfcGUsIGVuenltZT0iY2h5bW90cnlwc2luLWhpZ2giLCBjb2xvcj0iYmx1ZSIpJHBsb3QKZGV2Lm9mZigpCnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV9jaHltb18xNTAwXzMwMDAucG5nIikKY2xlYXZhZ2VfaGlzdG9ncmFtKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImNoeW1vdHJ5cHNpbi1oaWdoIiwgc3RhcnQ9MTUwMCwgZW5kPTMwMDAsIGNvbG9yPSJibHVlIikkcGxvdApkZXYub2ZmKCkKdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL3BlX2NoeW1vXzMwMDBfNTAwMC5wbmciKQpjbGVhdmFnZV9oaXN0b2dyYW0ocGVwX3NlcXVlbmNlcz1tdGJfcGUsIGVuenltZT0iY2h5bW90cnlwc2luLWhpZ2giLCBzdGFydD0zMDAwLCBlbmQ9NTAwMCwgY29sb3I9ImJsdWUiKSRwbG90CmRldi5vZmYoKQpgYGAKCiMjIyBhc3AtbiBlbmRvcGVwdGlkYXNlCgpgYGB7ciBwbG90X2FzcG59CmFzcG5fbG93IDwtIHNtKHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJhc3AtbiBlbmRvcGVwdGlkYXNlIikpCmFzcG5fbWlkIDwtIHNtKHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJhc3AtbiBlbmRvcGVwdGlkYXNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydD0yMDAwLCBlbmQ9MzUwMCkpCmFzcG5faGlnaCA8LSBzbShwbG90X2NsZWF2ZWQocGVwX3NlcXVlbmNlcz1tdGJfcGUsIGVuenltZT0iYXNwLW4gZW5kb3BlcHRpZGFzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9MzUwMCwgZW5kPTUwMDApKQpgYGAKCmBgYHtyIGFzcG5faGlzdH0KY2xlYXZhZ2VfaGlzdG9ncmFtKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImFzcC1uIGVuZG9wZXB0aWRhc2UiLCBjb2xvcj0iZGFya2dyZWVuIikkcGxvdApkZXYub2ZmKCkKdHQgPC0gcHAoZmlsZT0iaW1hZ2VzL3BlX2FzcG5fMTUwMF8zMDAwLnBuZyIpCmNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJhc3AtbiBlbmRvcGVwdGlkYXNlIiwgc3RhcnQ9MTUwMCwgZW5kPTMwMDAsIGNvbG9yPSJkYXJrZ3JlZW4iKSRwbG90CmRldi5vZmYoKQp0dCA8LSBwcChmaWxlPSJpbWFnZXMvcGVfYXNwbl8zMDAwXzUwMDAucG5nIikKY2xlYXZhZ2VfaGlzdG9ncmFtKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImFzcC1uIGVuZG9wZXB0aWRhc2UiLCBzdGFydD0zMDAwLCBlbmQ9NTAwMCwgY29sb3I9ImRhcmtncmVlbiIpJHBsb3QKZGV2Lm9mZigpCnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV9nbHVfMTUwMF8zMDAwLnBuZyIpCmNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJnbHV0YW15bCBlbmRvcGVwdGlkYXNlIiwgY29sb3I9InB1cnBsZSIpJHBsb3QKZGV2Lm9mZigpCnR0IDwtIHBwKGZpbGU9ImltYWdlcy9wZV9nbHVfMTUwMF8zMDAwLnBuZyIpCmNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJnbHV0YW15bCBlbmRvcGVwdGlkYXNlIiwgc3RhcnQ9MTUwMCwgZW5kPTMwMDAsIGNvbG9yPSJkYXJrZ3JlZW4iKSRwbG90CmRldi5vZmYoKQp0dCA8LSBwcChmaWxlPSJpbWFnZXMvcGVfZ2x1XzMwMDBfNTAwMC5wbmciKQpjbGVhdmFnZV9oaXN0b2dyYW0ocGVwX3NlcXVlbmNlcz1tdGJfcGUsIGVuenltZT0iZ2x1dGFteWwgZW5kb3BlcHRpZGFzZSIsIHN0YXJ0PTMwMDAsIGVuZD01MDAwLCBjb2xvcj0iZGFya2dyZWVuIikkcGxvdApkZXYub2ZmKCkKYGBgCgojIyMgZ2x1LWMgZW5kb3BlcHRpZGFzZQoKYGBge3IgcGxvdF9nbHV9CmdsdV9sb3cgPC0gc20ocGxvdF9jbGVhdmVkKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImdsdXRhbXlsIGVuZG9wZXB0aWRhc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydD03MDAsIGVuZD0yMDAwKSkKZ2x1X2hpZ2ggPC0gc20ocGxvdF9jbGVhdmVkKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImdsdXRhbXlsIGVuZG9wZXB0aWRhc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ9MjAwMCwgZW5kPTMwMDApKQpgYGAKCiMjIENvbXBhcmUgc2ltdWxhdGVkIFBFIHZzIGFsbAoKYGBge3IgYm94cGxvdF9lbnp5bWVzfQphbGxfdHJ5cCA8LSBjbGVhdmFnZV9oaXN0b2dyYW0ocGVwX3NlcXVlbmNlcz1tdGJfcGUpJG1hc3NlcwphbGxfdHJ5cCRlbnp5bWUgPC0gInRyeXAiCmFsbF9jaHkgPC0gY2xlYXZhZ2VfaGlzdG9ncmFtKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImNoeW1vdHJ5cHNpbi1oaWdoIikkbWFzc2VzCmFsbF9jaHkkZW56eW1lIDwtICJjaHltbyIKYWxsX2FzcG4gPC0gY2xlYXZhZ2VfaGlzdG9ncmFtKHBlcF9zZXF1ZW5jZXM9bXRiX3BlLCBlbnp5bWU9ImFzcC1uIGVuZG9wZXB0aWRhc2UiKSRtYXNzZXMKYWxsX2FzcG4kZW56eW1lIDwtICJhc3BuIgphbGxfZ2x1IDwtIGNsZWF2YWdlX2hpc3RvZ3JhbShwZXBfc2VxdWVuY2VzPW10Yl9wZSwgZW56eW1lPSJnbHV0YW15bCBlbmRvcGVwdGlkYXNlIikkbWFzc2VzCmFsbF9nbHUkZW56eW1lIDwtICJnbHUiCgphbGxfZGYgPC0gYWxsX3RyeXBbLCBjKCJlbnp5bWUiLCAibWFzcyIpXQphbGxfZGYgPC0gcmJpbmQoYWxsX2RmLCBhbGxfY2h5WywgYygiZW56eW1lIiwibWFzcyIpXSkKYWxsX2RmIDwtIHJiaW5kKGFsbF9kZiwgYWxsX2FzcG5bLCBjKCJlbnp5bWUiLCAibWFzcyIpXSkKYWxsX2RmIDwtIHJiaW5kKGFsbF9kZiwgYWxsX2dsdVssIGMoImVuenltZSIsICJtYXNzIildKQphbGxfZGYgPC0gYXMuZGF0YS5mcmFtZShhbGxfZGYpCmFsbF9kZiRlbnp5bWUgPC0gYXMuZmFjdG9yKGFsbF9kZiRlbnp5bWUpCmFsbF9kZiRsMm1hc3MgPC0gbG9nMihhbGxfZGYkbWFzcyArIDEpCgpjb21wYXJpc29uIDwtIGdncGxvdChkYXRhPWFsbF9kZiwgYWVzX3N0cmluZyh4PSJtYXNzIiwgZ3JvdXA9ImVuenltZSIsIGNvbG91cj0iZW56eW1lIikpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDAsMTAwMDApKQpwcChmaWxlPSJpbWFnZXMvZGVuc2l0eV9lbnp5bWVzLnBuZyIpCmNvbXBhcmlzb24KZGV2Lm9mZigpCmBgYAoKYGBge3IgcGV9CnBlX2Rpc3RyaWJ1dGlvbiA8LSB0cnlwX2xvd1tbInNpemVzIl1dCmFsbF90cnlwc2luX2Rpc3RyaWJ1dGlvbiA8LSBwbG90X2NsZWF2ZWQocGVwX3NlcXVlbmNlcz1tdGJfcGVwdGlkZXMsIGVuenltZT0idHJ5cHNpbiIsIHN0YXJ0PTIwMDAsIGVuZD0yMDEwKQphbGxfY2h5bW9fZGlzdHJpYnV0aW9uIDwtIHBsb3RfY2xlYXZlZChwZXBfc2VxdWVuY2VzPW10Yl9wZXB0aWRlcywgZW56eW1lPSJjaHltb3RyeXBzaW4taGlnaCIsIHN0YXJ0PTIwMDAsIGVuZD0yMDEwKQpwZV9uYW1lcyA8LSB1bmlxdWUocGVfZGlzdHJpYnV0aW9uW1siY2RzIl1dKQoKZGlzdHJpYnV0aW9uIDwtIGFsbF90cnlwc2luX2Rpc3RyaWJ1dGlvbgpwbG90X3NwZWN0cmEgPC0gZnVuY3Rpb24oZGlzdHJpYnV0aW9uLCBzdWJzZXQ9cGVfbmFtZXMpIHsKICBhbGxfc2l6ZXMgPC0gZGlzdHJpYnV0aW9uW1sic2l6ZXMiXV0KICBhbGxfc2l6ZXNbWyJzdWJzZXQiXV0gPC0gMAogIHN1YnNldF9mb3VuZCA8LSBhbGxfc2l6ZXNbWyJjZHMiXV0gJWluJSBzdWJzZXQKICBhbGxfc2l6ZXNbc3Vic2V0X2ZvdW5kLCAic3Vic2V0Il0gPC0gMQogIGFsbF9zaXplc1tbImF2ZXJhZ2VfbWFzcyJdXSA8LSBhcy5udW1lcmljKGFsbF9zaXplc1tbImF2ZXJhZ2VfbWFzcyJdXSkKICBhbGxfc2l6ZXNbWyJoaWdoZXN0X2xpa2VsaWhvb2QiXV0gPC0gYXMubnVtZXJpYyhhbGxfc2l6ZXNbWyJoaWdoZXN0X2xpa2VsaWhvb2QiXV0pCgogIGFfcGxvdCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YT1hbGxfc2l6ZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjphZXNfc3RyaW5nKHg9ImF2ZXJhZ2VfbWFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9ImhpZ2hlc3RfbGlrZWxpaG9vZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91cj0iYXMuZmFjdG9yKHN1YnNldCkiKSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9wb2ludChhbHBoYT0wLjMsIHNpemU9Miwgc3RhdD0iaWRlbnRpdHkiKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iYXMuZmFjdG9yKHN1YnNldCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKCIwIj0iZGFya2JsdWUiLCAiMSI9ImRhcmtyZWQiKSkKICByZXR1cm4oYV9wbG90KQp9Cgp0cnlwc2luX2Rpc3RfcGxvdCA8LSBwbG90X3NwZWN0cmEoYWxsX3RyeXBzaW5fZGlzdHJpYnV0aW9uKQpwcChmaWxlPSJpbWFnZXMvdHJ5cF9kaXN0X3Bsb3QucG5nIikKdHJ5cHNpbl9kaXN0X3Bsb3QKZGV2Lm9mZigpCmNoeW1vdHJ5cHNpbl9kaXN0X3Bsb3QgPC0gcGxvdF9zcGVjdHJhKGFsbF9jaHltb19kaXN0cmlidXRpb24pCnBwKGZpbGU9ImltYWdlcy9jaHltb19kaXN0X3Bsb3QucG5nIikKY2h5bW90cnlwc2luX2Rpc3RfcGxvdApkZXYub2ZmKCkKIyMgSSB0aGluayB0aGlzIGRlbW9uc3RyYXRlcyBuaWNlbHkgaG93IG11Y2ggbW9yZSBlZmZpY2llbnQgY2h5bW90cnlwc2luIGlzIGZvciBwZSBwcm90ZWlucy4KYGBgCgpgYGB7ciBzYXZlbWV9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCg==