Summary of Findings:

This was an exploration of how TMB is affected by using nonsynonymous filters. It addresses part 1 of this OpenPBTA issue As far as the TMB comparisons go, it doesn’t matter if we use Variant_Classification filters or not. They are highly correlated no matter what and the same general TCGA to PBTA differences seem to persist.

Usage

If both run_caller_consensus_analysis-tcga.sh and run_caller_consensus_analysis-pbta.sh have been run, you can run this command. This will prepare the files needed for this notebook and run this notebook:

# bash run_explorations.sh

Table of Contents generated with DocToc

Setup

# Magrittr pipe
`%>%` <- dplyr::`%>%`
source(file.path("..", "..", "tmb-compare", "util", "cdf-plot-function.R"))
dir.create("plots", showWarnings = FALSE)

Read in the TMB files

Read in PBTA data

Import the tmb calculations that are not filtered by nonsynonymous classifications.

tmb_pbta_no_filter <- data.table::fread(file.path(
  "..",
  "results",
  "no_filter",
  "pbta-snv-mutation-tmb-coding.tsv"
)) %>%
  dplyr::filter(experimental_strategy != "Panel") %>%
  dplyr::mutate(filter = "no filter")

Repeat same steps for original tmb calculations (with filter).

tmb_pbta_with_filter <- data.table::fread(file.path(
  "..",
  "results",
  "consensus",
  "pbta-snv-mutation-tmb-coding.tsv"
)) %>%
  dplyr::filter(experimental_strategy != "Panel") %>%
  dplyr::mutate(filter = "filter")

Combine the unfilter and filtered data sets into one.

tmb_pbta <- dplyr::inner_join(tmb_pbta_no_filter,
  dplyr::select(tmb_pbta_with_filter, Tumor_Sample_Barcode, tmb),
  by = "Tumor_Sample_Barcode",
  suffix = c("_no_filter", "_filter")
)

Read in TCGA data

Repeat the same steps for the TCGA data.

tmb_tcga_no_filter <- data.table::fread(file.path(
  "..",
  "results",
  "no_filter",
  "tcga-snv-mutation-tmb-coding.tsv"
)) %>%
  dplyr::mutate(filter = "no filter")
tmb_tcga_with_filter <- data.table::fread(file.path(
  "..",
  "results",
  "consensus",
  "tcga-snv-mutation-tmb-coding.tsv"
)) %>%
  dplyr::mutate(filter = "filter")

Join these together.

tmb_tcga <- dplyr::inner_join(tmb_tcga_no_filter,
  dplyr::select(tmb_tcga_with_filter, Tumor_Sample_Barcode, tmb),
  by = "Tumor_Sample_Barcode",
  suffix = c("_no_filter", "_filter")
)

Does the filter change a participant’s TMB?

Plot PBTA data

Correlate first with Pearson’s.

cor.test(tmb_pbta$tmb_filter, tmb_pbta$tmb_no_filter)

    Pearson's product-moment correlation

data:  tmb_pbta$tmb_filter and tmb_pbta$tmb_no_filter
t = 2488.9, df = 934, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.9999143 0.9999337
sample estimates:
      cor 
0.9999246 
pbta_cor_plot <- ggplot2::ggplot(
  tmb_pbta,
  ggplot2::aes(x = tmb_no_filter, y = tmb_filter, color = short_histology)
) +
  ggplot2::geom_point() +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none")

pbta_cor_plot

This data is very skewed, let’s try a nonparametric correlation.

cor.test(tmb_pbta$tmb_filter, tmb_pbta$tmb_no_filter, method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  tmb_pbta$tmb_filter and tmb_pbta$tmb_no_filter
S = 3031423, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9778195 

Still pretty good.

Plot TCGA data

cor.test(tmb_tcga$tmb_filter, tmb_tcga$tmb_no_filter)

    Pearson's product-moment correlation

data:  tmb_tcga$tmb_filter and tmb_tcga$tmb_no_filter
t = 4296.2, df = 316, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.9999893 0.9999931
sample estimates:
      cor 
0.9999914 
tcga_cor_plot <- ggplot2::ggplot(
  tmb_tcga,
  ggplot2::aes(x = tmb_no_filter, y = tmb_filter, color = short_histology)
) +
  ggplot2::geom_point() +
  ggplot2::xlim(0, 5) +
  ggplot2::ylim(0, 5) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none")

tcga_cor_plot

Correlate with nonparametric correlation since we did that for PBTA.

cor.test(tmb_tcga$tmb_filter, tmb_tcga$tmb_no_filter, method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  tmb_tcga$tmb_filter and tmb_tcga$tmb_no_filter
S = 60671, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9886798 

Are some histologies affected more than others?

Let’s make the same plots but by short_histology.

Plotting PBTA data, but setting the scales to “free” since the histologies have very different tmb ranges.

pbta_cor_plot + 
  ggplot2::facet_wrap(~short_histology, scales = "free")

Make the same plot for TCGA.

tcga_cor_plot + 
  ggplot2::facet_wrap(~short_histology)

Does the filter affect the TCGA-PBTA comparison change?

Put PBTA and TCGA data into one long format data frame.

all_data <- dplyr::bind_rows(list(tcga = tmb_tcga, pbta = tmb_pbta), .id = "dataset") %>%
  dplyr::select(tmb_filter, tmb_no_filter, dataset, Tumor_Sample_Barcode, short_histology) %>%
  tidyr::gather("filter", "tmb", -Tumor_Sample_Barcode, -dataset, -short_histology)

Plot the data overall.

ggplot2::ggplot(all_data, ggplot2::aes(x = dataset, y = tmb)) +
  ggforce::geom_sina() +
  ggplot2::theme_classic() +
  ggplot2::ylim(0, 10) +
  ggplot2::theme(legend.position = "none") +
  ggplot2::facet_wrap(~"filter") 

Plot the ratio of the nonfilter/filter tmb

We’ll plot this by short_histology.

all_data %>% 
  tidyr::spread("filter","tmb") %>% 
  dplyr::mutate(ratio = tmb_filter/tmb_no_filter) %>% 
ggplot2::ggplot(ggplot2::aes(x = short_histology, y = ratio, color = short_histology)) + 
  ggplot2::geom_violin() + 
  ggplot2::theme_classic() + 
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1), 
                 legend.position = "none") + 
  ggplot2::xlab("") + 
  ggplot2::ylab("tmb_filter/tmb_no_filter")

Plot the TMB plot with no filter data

This code is directly copied from tmb-compare-tcga/tmb-compare-tcga.Rmd.

pbta_plot <- cdf_plot(
  df = tmb_pbta_no_filter,
  plot_title = "PBTA",
  num_col = "tmb",
  group_col = "short_histology",
  color = "#3BC8A2",
  n_group = 5,
  x_lim = c(-1.2, 1.2),
  y_lim = c(0, 400),
  x_lab = "",
  y_lab = "Coding Mutations per Mb", 
  breaks = c(0, 3, 10, 30, 100, 300)
) +
  ggplot2::theme(
    strip.text.x = ggplot2::element_text(size = 12), 
    plot.margin = grid::unit(c(0.5, 0, 0.6, 0.5), "cm")
  )
the condition has length > 1 and only the first element will be used
tcga_plot <- cdf_plot(
  df = tmb_tcga_no_filter,
  plot_title = "TCGA (Adult)",
  num_col = "tmb",
  group_col = "short_histology",
  color = "#630882",
  n_group = 5,
  x_lim = c(-1.2, 1.2),
  y_lim = c(0, 400),
  x_lab = "",
  y_lab = "Coding Mutations per Mb",
  breaks = c()
) +
  ggplot2::theme(
    axis.title.y = ggplot2::element_blank(),
    axis.text.y = ggplot2::element_blank(),
    axis.ticks.y = ggplot2::element_blank(),
    strip.text.x = ggplot2::element_text(size = 9), 
    plot.margin = grid::unit(c(0.5, 1, 0.1, 0), "cm")
  )
the condition has length > 1 and only the first element will be used
# Put the plots together
tmb_plot <- cowplot::plot_grid(pbta_plot, tcga_plot,
  align = "v",
  axis = "left",
  rel_widths = c(2.5, 1),
  label_size = 12
)
Removed 3 rows containing missing values (geom_point).Removed 1 rows containing missing values (geom_point).
# Save the plot to a png
cowplot::save_plot(file.path("plots", "no_filter_tmb-cdf-pbta-tcga.png"),
  plot = tmb_plot, base_width = 35, base_height = 20, unit = "cm"
)

Print from png

No filter TMB Plot

With filter TMB Plot

## Session Info

sessionInfo()
R version 3.6.0 (2019-04-26)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)

Matrix products: default
BLAS/LAPACK: /usr/lib/libopenblasp-r0.2.19.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
 [4] LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=C             
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.1         pillar_1.4.2       compiler_3.6.0     RColorBrewer_1.1-2 plyr_1.8.4        
 [6] R.methodsS3_1.7.1  R.utils_2.9.0      base64enc_0.1-3    tools_3.6.0        digest_0.6.20     
[11] jsonlite_1.6       evaluate_0.14      tibble_2.1.3       gtable_0.3.0       pkgconfig_2.0.2   
[16] rlang_0.4.0        GGally_1.4.0       rstudioapi_0.10    yaml_2.2.0         xfun_0.8          
[21] colorblindr_0.1.0  dplyr_0.8.3        stringr_1.4.0      knitr_1.23         cowplot_0.9.4     
[26] grid_3.6.0         tidyselect_0.2.5   reshape_0.8.8      glue_1.3.1         data.table_1.12.2 
[31] R6_2.4.0           rmarkdown_1.13     polyclip_1.10-0    farver_1.1.0       tweenr_1.0.1      
[36] tidyr_0.8.3        ggplot2_3.2.0      purrr_0.3.2        reshape2_1.4.3     magrittr_1.5      
[41] MASS_7.3-51.4      scales_1.0.0       htmltools_0.3.6    assertthat_0.2.1   ggforce_0.2.2     
[46] colorspace_1.4-1   labeling_0.3       stringi_1.4.3      lazyeval_0.2.2     munsell_0.5.0     
[51] crayon_1.3.4       R.oo_1.22.0       
LS0tCnRpdGxlOiAiRXhwbG9yZSBpbXBhY3Qgb2YgTm9uIFN5bm9ueW1vdXMgRmlsdGVycyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKYXV0aG9yOiBDLiBTYXZvbmVuIGZvciBBTFNGIENDREwKZGF0ZTogMjAyMAotLS0KCiMjIyBTdW1tYXJ5IG9mIEZpbmRpbmdzOgoKVGhpcyB3YXMgYW4gZXhwbG9yYXRpb24gb2YgaG93IFRNQiBpcyBhZmZlY3RlZCBieSB1c2luZyBub25zeW5vbnltb3VzIGZpbHRlcnMuIApJdCBhZGRyZXNzZXMgcGFydCAxIG9mIFt0aGlzIE9wZW5QQlRBIGlzc3VlXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuUEJUQS1hbmFseXNpcy9pc3N1ZXMvNzI5KQpBcyBmYXIgYXMgdGhlIFRNQiBjb21wYXJpc29ucyBnbywgaXQgZG9lc24ndCBtYXR0ZXIgaWYgd2UgdXNlIGBWYXJpYW50X0NsYXNzaWZpY2F0aW9uYCBmaWx0ZXJzIG9yIG5vdC4gClRoZXkgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIG5vIG1hdHRlciB3aGF0IGFuZCB0aGUgc2FtZSBnZW5lcmFsIFRDR0EgdG8gUEJUQSBkaWZmZXJlbmNlcyBzZWVtIHRvIHBlcnNpc3QuIAoKIyMjIFVzYWdlCgpJZiBib3RoIGBydW5fY2FsbGVyX2NvbnNlbnN1c19hbmFseXNpcy10Y2dhLnNoYCBhbmQgYHJ1bl9jYWxsZXJfY29uc2Vuc3VzX2FuYWx5c2lzLXBidGEuc2hgIGhhdmUgYmVlbiBydW4sIHlvdSBjYW4gcnVuIHRoaXMgY29tbWFuZC4gClRoaXMgd2lsbCBwcmVwYXJlIHRoZSBmaWxlcyBuZWVkZWQgZm9yIHRoaXMgbm90ZWJvb2sgYW5kIHJ1biB0aGlzIG5vdGVib29rOgoKYGBgCiMgYmFzaCBydW5fZXhwbG9yYXRpb25zLnNoCmBgYAoKPCEtLSBTVEFSVCBkb2N0b2MgZ2VuZXJhdGVkIFRPQyBwbGVhc2Uga2VlcCBjb21tZW50IGhlcmUgdG8gYWxsb3cgYXV0byB1cGRhdGUgLS0+CjwhLS0gRE9OJ1QgRURJVCBUSElTIFNFQ1RJT04sIElOU1RFQUQgUkUtUlVOIGRvY3RvYyBUTyBVUERBVEUgLS0+CioqVGFibGUgb2YgQ29udGVudHMqKiAgKmdlbmVyYXRlZCB3aXRoIFtEb2NUb2NdKGh0dHBzOi8vZ2l0aHViLmNvbS90aGxvcmVuei9kb2N0b2MpKgoKLSBbUmVhZCBpbiB0aGUgVE1CIGZpbGVzXSgjcmVhZC1pbi10aGUtdG1iLWZpbGVzKQogIC0gW1JlYWQgaW4gUEJUQSBkYXRhXSgjcmVhZC1pbi1wYnRhLWRhdGEpCiAgLSBbUmVhZCBpbiBUQ0dBIGRhdGFdKCNyZWFkLWluLXRjZ2EtZGF0YSkKLSBbRG9lcyB0aGUgZmlsdGVyIGNoYW5nZSBhIHBhcnRpY2lwYW50J3MgVE1CP10oI2RvZXMtdGhlLWZpbHRlci1jaGFuZ2UtYS1wYXJ0aWNpcGFudHMtdG1iKQogIC0gW1Bsb3QgUEJUQSBkYXRhXSgjcGxvdC1wYnRhLWRhdGEpCiAgLSBbUGxvdCBUQ0dBIGRhdGFdKCNwbG90LXRjZ2EtZGF0YSkKLSBbQXJlIHNvbWUgaGlzdG9sb2dpZXMgYWZmZWN0ZWQgbW9yZSB0aGFuIG90aGVycz9dKCNhcmUtc29tZS1oaXN0b2xvZ2llcy1hZmZlY3RlZC1tb3JlLXRoYW4tb3RoZXJzKQotIFtEb2VzIHRoZSBmaWx0ZXIgYWZmZWN0IHRoZSBUQ0dBLVBCVEEgY29tcGFyaXNvbiBjaGFuZ2U/XSgjZG9lcy10aGUtZmlsdGVyLWFmZmVjdC10aGUtdGNnYS1wYnRhLWNvbXBhcmlzb24tY2hhbmdlKQotIFtQbG90IHRoZSByYXRpbyBvZiB0aGUgbm9uZmlsdGVyL2ZpbHRlciB0bWJdKCNwbG90LXRoZS1yYXRpby1vZi10aGUtbm9uZmlsdGVyZmlsdGVyLXRtYikKLSBbUGxvdCB0aGUgVE1CIHBsb3Qgd2l0aCBubyBmaWx0ZXIgZGF0YV0oI3Bsb3QtdGhlLXRtYi1wbG90LXdpdGgtbm8tZmlsdGVyLWRhdGEpCiAgLSBbTm8gZmlsdGVyIFRNQiBQbG90XSgjbm8tZmlsdGVyLXRtYi1wbG90KQogIC0gW1dpdGggZmlsdGVyIFRNQiBQbG90XSgjd2l0aC1maWx0ZXItdG1iLXBsb3QpCi0gW1Nlc3Npb24gSW5mb10oI3Nlc3Npb24taW5mbykKCjwhLS0gRU5EIGRvY3RvYyBnZW5lcmF0ZWQgVE9DIHBsZWFzZSBrZWVwIGNvbW1lbnQgaGVyZSB0byBhbGxvdyBhdXRvIHVwZGF0ZSAtLT4KCiMjIFNldHVwCgpgYGB7cn0KIyBNYWdyaXR0ciBwaXBlCmAlPiVgIDwtIGRwbHlyOjpgJT4lYApgYGAKCmBgYHtyfQpzb3VyY2UoZmlsZS5wYXRoKCIuLiIsICIuLiIsICJ0bWItY29tcGFyZSIsICJ1dGlsIiwgImNkZi1wbG90LWZ1bmN0aW9uLlIiKSkKYGBgCgpgYGB7cn0KZGlyLmNyZWF0ZSgicGxvdHMiLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKYGBgCgojIyBSZWFkIGluIHRoZSBUTUIgZmlsZXMKCiMjIyBSZWFkIGluIFBCVEEgZGF0YQoKSW1wb3J0IHRoZSB0bWIgY2FsY3VsYXRpb25zIHRoYXQgYXJlIG5vdCBmaWx0ZXJlZCBieSBub25zeW5vbnltb3VzIGNsYXNzaWZpY2F0aW9ucy4KCmBgYHtyfQp0bWJfcGJ0YV9ub19maWx0ZXIgPC0gZGF0YS50YWJsZTo6ZnJlYWQoZmlsZS5wYXRoKAogICIuLiIsCiAgInJlc3VsdHMiLAogICJub19maWx0ZXIiLAogICJwYnRhLXNudi1tdXRhdGlvbi10bWItY29kaW5nLnRzdiIKKSkgJT4lCiAgZHBseXI6OmZpbHRlcihleHBlcmltZW50YWxfc3RyYXRlZ3kgIT0gIlBhbmVsIikgJT4lCiAgZHBseXI6Om11dGF0ZShmaWx0ZXIgPSAibm8gZmlsdGVyIikKYGBgCgpSZXBlYXQgc2FtZSBzdGVwcyBmb3Igb3JpZ2luYWwgdG1iIGNhbGN1bGF0aW9ucyAod2l0aCBmaWx0ZXIpLgoKYGBge3J9CnRtYl9wYnRhX3dpdGhfZmlsdGVyIDwtIGRhdGEudGFibGU6OmZyZWFkKGZpbGUucGF0aCgKICAiLi4iLAogICJyZXN1bHRzIiwKICAiY29uc2Vuc3VzIiwKICAicGJ0YS1zbnYtbXV0YXRpb24tdG1iLWNvZGluZy50c3YiCikpICU+JQogIGRwbHlyOjpmaWx0ZXIoZXhwZXJpbWVudGFsX3N0cmF0ZWd5ICE9ICJQYW5lbCIpICU+JQogIGRwbHlyOjptdXRhdGUoZmlsdGVyID0gImZpbHRlciIpCmBgYAoKQ29tYmluZSB0aGUgdW5maWx0ZXIgYW5kIGZpbHRlcmVkIGRhdGEgc2V0cyBpbnRvIG9uZS4gCgpgYGB7cn0KdG1iX3BidGEgPC0gZHBseXI6OmlubmVyX2pvaW4odG1iX3BidGFfbm9fZmlsdGVyLAogIGRwbHlyOjpzZWxlY3QodG1iX3BidGFfd2l0aF9maWx0ZXIsIFR1bW9yX1NhbXBsZV9CYXJjb2RlLCB0bWIpLAogIGJ5ID0gIlR1bW9yX1NhbXBsZV9CYXJjb2RlIiwKICBzdWZmaXggPSBjKCJfbm9fZmlsdGVyIiwgIl9maWx0ZXIiKQopCmBgYAoKIyMjIFJlYWQgaW4gVENHQSBkYXRhCgpSZXBlYXQgdGhlIHNhbWUgc3RlcHMgZm9yIHRoZSBUQ0dBIGRhdGEuIAoKYGBge3J9CnRtYl90Y2dhX25vX2ZpbHRlciA8LSBkYXRhLnRhYmxlOjpmcmVhZChmaWxlLnBhdGgoCiAgIi4uIiwKICAicmVzdWx0cyIsCiAgIm5vX2ZpbHRlciIsCiAgInRjZ2Etc252LW11dGF0aW9uLXRtYi1jb2RpbmcudHN2IgopKSAlPiUKICBkcGx5cjo6bXV0YXRlKGZpbHRlciA9ICJubyBmaWx0ZXIiKQpgYGAKCmBgYHtyfQp0bWJfdGNnYV93aXRoX2ZpbHRlciA8LSBkYXRhLnRhYmxlOjpmcmVhZChmaWxlLnBhdGgoCiAgIi4uIiwKICAicmVzdWx0cyIsCiAgImNvbnNlbnN1cyIsCiAgInRjZ2Etc252LW11dGF0aW9uLXRtYi1jb2RpbmcudHN2IgopKSAlPiUKICBkcGx5cjo6bXV0YXRlKGZpbHRlciA9ICJmaWx0ZXIiKQpgYGAKCkpvaW4gdGhlc2UgdG9nZXRoZXIuIAoKYGBge3J9CnRtYl90Y2dhIDwtIGRwbHlyOjppbm5lcl9qb2luKHRtYl90Y2dhX25vX2ZpbHRlciwKICBkcGx5cjo6c2VsZWN0KHRtYl90Y2dhX3dpdGhfZmlsdGVyLCBUdW1vcl9TYW1wbGVfQmFyY29kZSwgdG1iKSwKICBieSA9ICJUdW1vcl9TYW1wbGVfQmFyY29kZSIsCiAgc3VmZml4ID0gYygiX25vX2ZpbHRlciIsICJfZmlsdGVyIikKKQpgYGAKCiMjIERvZXMgdGhlIGZpbHRlciBjaGFuZ2UgYSBwYXJ0aWNpcGFudCdzIFRNQj8KCiMjIyBQbG90IFBCVEEgZGF0YQoKQ29ycmVsYXRlIGZpcnN0IHdpdGggUGVhcnNvbidzLiAKCmBgYHtyfQpjb3IudGVzdCh0bWJfcGJ0YSR0bWJfZmlsdGVyLCB0bWJfcGJ0YSR0bWJfbm9fZmlsdGVyKQpgYGAKCmBgYHtyfQpwYnRhX2Nvcl9wbG90IDwtIGdncGxvdDI6OmdncGxvdCgKICB0bWJfcGJ0YSwKICBnZ3Bsb3QyOjphZXMoeCA9IHRtYl9ub19maWx0ZXIsIHkgPSB0bWJfZmlsdGVyLCBjb2xvciA9IHNob3J0X2hpc3RvbG9neSkKKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludCgpICsKICBnZ3Bsb3QyOjp0aGVtZV9jbGFzc2ljKCkgKwogIGdncGxvdDI6OnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBidGFfY29yX3Bsb3QKYGBgCgpUaGlzIGRhdGEgaXMgdmVyeSBza2V3ZWQsIGxldCdzIHRyeSBhIG5vbnBhcmFtZXRyaWMgY29ycmVsYXRpb24uIAoKYGBge3J9CmNvci50ZXN0KHRtYl9wYnRhJHRtYl9maWx0ZXIsIHRtYl9wYnRhJHRtYl9ub19maWx0ZXIsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCmBgYAoKU3RpbGwgcHJldHR5IGdvb2QuIAoKIyMjIFBsb3QgVENHQSBkYXRhCgpgYGB7cn0KY29yLnRlc3QodG1iX3RjZ2EkdG1iX2ZpbHRlciwgdG1iX3RjZ2EkdG1iX25vX2ZpbHRlcikKYGBgCgpgYGB7cn0KdGNnYV9jb3JfcGxvdCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoCiAgdG1iX3RjZ2EsCiAgZ2dwbG90Mjo6YWVzKHggPSB0bWJfbm9fZmlsdGVyLCB5ID0gdG1iX2ZpbHRlciwgY29sb3IgPSBzaG9ydF9oaXN0b2xvZ3kpCikgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoKSArCiAgZ2dwbG90Mjo6eGxpbSgwLCA1KSArCiAgZ2dwbG90Mjo6eWxpbSgwLCA1KSArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgp0Y2dhX2Nvcl9wbG90CmBgYAoKQ29ycmVsYXRlIHdpdGggbm9ucGFyYW1ldHJpYyBjb3JyZWxhdGlvbiBzaW5jZSB3ZSBkaWQgdGhhdCBmb3IgUEJUQS4gCgpgYGB7cn0KY29yLnRlc3QodG1iX3RjZ2EkdG1iX2ZpbHRlciwgdG1iX3RjZ2EkdG1iX25vX2ZpbHRlciwgbWV0aG9kID0gInNwZWFybWFuIikKYGBgCgojIyBBcmUgc29tZSBoaXN0b2xvZ2llcyBhZmZlY3RlZCBtb3JlIHRoYW4gb3RoZXJzPyAKCkxldCdzIG1ha2UgdGhlIHNhbWUgcGxvdHMgYnV0IGJ5ICBgc2hvcnRfaGlzdG9sb2d5YC4gCgpQbG90dGluZyBQQlRBIGRhdGEsIGJ1dCBzZXR0aW5nIHRoZSBzY2FsZXMgdG8gImZyZWUiIHNpbmNlIHRoZSBoaXN0b2xvZ2llcyBoYXZlIHZlcnkgZGlmZmVyZW50IHRtYiByYW5nZXMuIAoKYGBge3J9CnBidGFfY29yX3Bsb3QgKyAKICBnZ3Bsb3QyOjpmYWNldF93cmFwKH5zaG9ydF9oaXN0b2xvZ3ksIHNjYWxlcyA9ICJmcmVlIikKYGBgCgpNYWtlIHRoZSBzYW1lIHBsb3QgZm9yIFRDR0EuIAoKYGBge3J9CnRjZ2FfY29yX3Bsb3QgKyAKICBnZ3Bsb3QyOjpmYWNldF93cmFwKH5zaG9ydF9oaXN0b2xvZ3kpCmBgYAoKIyMgRG9lcyB0aGUgZmlsdGVyIGFmZmVjdCB0aGUgVENHQS1QQlRBIGNvbXBhcmlzb24gY2hhbmdlPwoKUHV0IFBCVEEgYW5kIFRDR0EgZGF0YSBpbnRvIG9uZSBsb25nIGZvcm1hdCBkYXRhIGZyYW1lLiAKCmBgYHtyfQphbGxfZGF0YSA8LSBkcGx5cjo6YmluZF9yb3dzKGxpc3QodGNnYSA9IHRtYl90Y2dhLCBwYnRhID0gdG1iX3BidGEpLCAuaWQgPSAiZGF0YXNldCIpICU+JQogIGRwbHlyOjpzZWxlY3QodG1iX2ZpbHRlciwgdG1iX25vX2ZpbHRlciwgZGF0YXNldCwgVHVtb3JfU2FtcGxlX0JhcmNvZGUsIHNob3J0X2hpc3RvbG9neSkgJT4lCiAgdGlkeXI6OmdhdGhlcigiZmlsdGVyIiwgInRtYiIsIC1UdW1vcl9TYW1wbGVfQmFyY29kZSwgLWRhdGFzZXQsIC1zaG9ydF9oaXN0b2xvZ3kpCmBgYAoKUGxvdCB0aGUgZGF0YSBvdmVyYWxsLiAKCmBgYHtyfQpnZ3Bsb3QyOjpnZ3Bsb3QoYWxsX2RhdGEsIGdncGxvdDI6OmFlcyh4ID0gZGF0YXNldCwgeSA9IHRtYikpICsKICBnZ2ZvcmNlOjpnZW9tX3NpbmEoKSArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp5bGltKDAsIDEwKSArCiAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+ImZpbHRlciIpIApgYGAKCiMjIFBsb3QgdGhlIHJhdGlvIG9mIHRoZSBub25maWx0ZXIvZmlsdGVyIHRtYgoKV2UnbGwgcGxvdCB0aGlzIGJ5IGBzaG9ydF9oaXN0b2xvZ3lgLiAKCmBgYHtyfQphbGxfZGF0YSAlPiUgCiAgdGlkeXI6OnNwcmVhZCgiZmlsdGVyIiwidG1iIikgJT4lIAogIGRwbHlyOjptdXRhdGUocmF0aW8gPSB0bWJfZmlsdGVyL3RtYl9ub19maWx0ZXIpICU+JSAKZ2dwbG90Mjo6Z2dwbG90KGdncGxvdDI6OmFlcyh4ID0gc2hvcnRfaGlzdG9sb2d5LCB5ID0gcmF0aW8sIGNvbG9yID0gc2hvcnRfaGlzdG9sb2d5KSkgKyAKICBnZ3Bsb3QyOjpnZW9tX3Zpb2xpbigpICsgCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsgCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50ZXh0LnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIAogIGdncGxvdDI6OnhsYWIoIiIpICsgCiAgZ2dwbG90Mjo6eWxhYigidG1iX2ZpbHRlci90bWJfbm9fZmlsdGVyIikKYGBgCgoKIyMgUGxvdCB0aGUgVE1CIHBsb3Qgd2l0aCBubyBmaWx0ZXIgZGF0YQoKVGhpcyBjb2RlIGlzIGRpcmVjdGx5IGNvcGllZCBmcm9tIGB0bWItY29tcGFyZS10Y2dhL3RtYi1jb21wYXJlLXRjZ2EuUm1kYC4KCmBgYHtyfQpwYnRhX3Bsb3QgPC0gY2RmX3Bsb3QoCiAgZGYgPSB0bWJfcGJ0YV9ub19maWx0ZXIsCiAgcGxvdF90aXRsZSA9ICJQQlRBIiwKICBudW1fY29sID0gInRtYiIsCiAgZ3JvdXBfY29sID0gInNob3J0X2hpc3RvbG9neSIsCiAgY29sb3IgPSAiIzNCQzhBMiIsCiAgbl9ncm91cCA9IDUsCiAgeF9saW0gPSBjKC0xLjIsIDEuMiksCiAgeV9saW0gPSBjKDAsIDQwMCksCiAgeF9sYWIgPSAiIiwKICB5X2xhYiA9ICJDb2RpbmcgTXV0YXRpb25zIHBlciBNYiIsIAogIGJyZWFrcyA9IGMoMCwgMywgMTAsIDMwLCAxMDAsIDMwMCkKKSArCiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBzdHJpcC50ZXh0LnggPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgCiAgICBwbG90Lm1hcmdpbiA9IGdyaWQ6OnVuaXQoYygwLjUsIDAsIDAuNiwgMC41KSwgImNtIikKICApCmBgYAoKYGBge3J9CnRjZ2FfcGxvdCA8LSBjZGZfcGxvdCgKICBkZiA9IHRtYl90Y2dhX25vX2ZpbHRlciwKICBwbG90X3RpdGxlID0gIlRDR0EgKEFkdWx0KSIsCiAgbnVtX2NvbCA9ICJ0bWIiLAogIGdyb3VwX2NvbCA9ICJzaG9ydF9oaXN0b2xvZ3kiLAogIGNvbG9yID0gIiM2MzA4ODIiLAogIG5fZ3JvdXAgPSA1LAogIHhfbGltID0gYygtMS4yLCAxLjIpLAogIHlfbGltID0gYygwLCA0MDApLAogIHhfbGFiID0gIiIsCiAgeV9sYWIgPSAiQ29kaW5nIE11dGF0aW9ucyBwZXIgTWIiLAogIGJyZWFrcyA9IGMoKQopICsKICBnZ3Bsb3QyOjp0aGVtZSgKICAgIGF4aXMudGl0bGUueSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC54ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSA5KSwgCiAgICBwbG90Lm1hcmdpbiA9IGdyaWQ6OnVuaXQoYygwLjUsIDEsIDAuMSwgMCksICJjbSIpCiAgKQpgYGAKCmBgYHtyfQojIFB1dCB0aGUgcGxvdHMgdG9nZXRoZXIKdG1iX3Bsb3QgPC0gY293cGxvdDo6cGxvdF9ncmlkKHBidGFfcGxvdCwgdGNnYV9wbG90LAogIGFsaWduID0gInYiLAogIGF4aXMgPSAibGVmdCIsCiAgcmVsX3dpZHRocyA9IGMoMi41LCAxKSwKICBsYWJlbF9zaXplID0gMTIKKQpgYGAKCmBgYHtyfQojIFNhdmUgdGhlIHBsb3QgdG8gYSBwbmcKY293cGxvdDo6c2F2ZV9wbG90KGZpbGUucGF0aCgicGxvdHMiLCAibm9fZmlsdGVyX3RtYi1jZGYtcGJ0YS10Y2dhLnBuZyIpLAogIHBsb3QgPSB0bWJfcGxvdCwgYmFzZV93aWR0aCA9IDM1LCBiYXNlX2hlaWdodCA9IDIwLCB1bml0ID0gImNtIgopCmBgYAoKUHJpbnQgZnJvbSBwbmcKCiMjIyBObyBmaWx0ZXIgVE1CIFBsb3QKIVtdKC4vcGxvdHMvbm9fZmlsdGVyX3RtYi1jZGYtcGJ0YS10Y2dhLnBuZykKCiMjIyBXaXRoIGZpbHRlciBUTUIgUGxvdAohW10oLi4vLi4vdG1iLWNvbXBhcmUvcGxvdHMvdG1iLWNkZi1wYnRhLXRjZ2EucG5nKQojIyBTZXNzaW9uIEluZm8KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=