From 435d5544371a83cc7c090f8e304131f0e673e931 Mon Sep 17 00:00:00 2001 From: Ally Hawkins Date: Thu, 6 Feb 2025 17:46:41 -0600 Subject: [PATCH] re-render --- .../02-explore-consensus-results.nb.html | 139 +++++++++++------- .../03-osteosarcoma-consensus-celltypes.Rmd | 9 +- ...3-osteosarcoma-consensus-celltypes.nb.html | 31 ++-- 3 files changed, 117 insertions(+), 62 deletions(-) diff --git a/analyses/cell-type-consensus/exploratory-notebooks/02-explore-consensus-results.nb.html b/analyses/cell-type-consensus/exploratory-notebooks/02-explore-consensus-results.nb.html index 597fb76d9..c0f913593 100644 --- a/analyses/cell-type-consensus/exploratory-notebooks/02-explore-consensus-results.nb.html +++ b/analyses/cell-type-consensus/exploratory-notebooks/02-explore-consensus-results.nb.html @@ -11,7 +11,7 @@ - + Explore consensus cell types @@ -1750,7 +1750,7 @@

Explore consensus cell types

Ally Hawkins

-

2025-02-05

+

2025-02-06

@@ -1777,8 +1777,7 @@

2025-02-05

notebook.

- - +
suppressPackageStartupMessages({
   # load required packages
   library(ggplot2)
@@ -1789,15 +1788,13 @@ 

2025-02-05

theme_classic() )
-

Data setup

- - +
# The base path for the OpenScPCA repository, found by its (hidden) .git directory
 repository_base <- rprojroot::find_root(rprojroot::is_git_root)
 module_base <- file.path(repository_base, "analyses", "cell-type-consensus")
@@ -1808,13 +1805,11 @@ 

Data setup

# diagnoses table used for labeling plots diagnoses_file <- file.path(module_base, "sample-info", "project-diagnoses.tsv")
- - - +
# list all results files 
 results_files <- list.files(results_dir, pattern = "_consensus-cell-types\\.tsv.\\gz$", full.names = TRUE)
 
@@ -1827,24 +1822,20 @@ 

Data setup

project_ids <- setdiff(project_ids, cell_line_projects) # remove cell line projects results_files <- results_files[project_ids]
- - - +
# source summarize_celltypes() function
 setup_functions <- file.path(module_base, "exploratory-notebooks", "utils", "setup-functions.R")
 source(setup_functions)
- - - +
# read in diagnoses
 diagnoses_df <- readr::read_tsv(diagnoses_file)
 
@@ -1858,10 +1849,8 @@ 

Data setup

dplyr::mutate( # create a label for plotting project_label = glue::glue("{project_id}:{diagnosis}") - ) -
+ ) -
@@ -1872,8 +1861,7 @@

Is it all just Unknown?

SingleR and CellAssign was identified.

- - +
unknown_only <- all_results_df |> 
   dplyr::filter(consensus_annotation == "Unknown")
 
@@ -1884,10 +1872,11 @@ 

Is it all just Unknown?

labs( x = "", y = "Percent of cells annotated as Unknown" - ) -
+ ) - + +

+

It looks like we do have some samples that aren’t just all “Unknown”! @@ -1898,8 +1887,7 @@

Is it all just Unknown?

have cells called as “Unknown”.

- - +
high_tumor_df <- unknown_only |> 
   dplyr::mutate(no_cells_identified = percent_cells_annotation == 100) |> 
   dplyr::group_by(project_label) |> 
@@ -1911,21 +1899,24 @@ 

Is it all just Unknown?

# set order for plots dplyr::mutate(project_label = forcats::fct_reorder(project_label, total_libraries, .desc = TRUE))
-

Which projects have the highest proportion of samples with all “Unknown”?

- - +
# table with percentage of samples 
 high_tumor_df |> 
   dplyr::select(project_label, percentage_unknown) |> 
-  dplyr::arrange(desc(percentage_unknown))
-
+ dplyr::arrange(desc(percentage_unknown)) + +
+ +
@@ -1937,8 +1928,7 @@

Is it all just Unknown?

patient tissue counterparts.

- - +
# list of projects with pdx 
 pdx_projects <- c(
   "SCPCP000003",
@@ -1969,7 +1959,9 @@ 

Is it all just Unknown?

y = "Percent of cells annotated as Unknown" )
- + +

+

It looks like in SCPCP000003 and @@ -1992,8 +1984,7 @@

Number of cell types observed

for all samples. This does not include cells labeled as “Unknown”.

- - +
num_celltypes_df <- all_results_df |> 
   # add a new line for facet labels 
   dplyr::mutate(facet_label = glue::glue("{project_id}\n{diagnosis}")) |>
@@ -2011,7 +2002,9 @@ 

Number of cell types observed

) + theme_bw()
- + +

+ @@ -2025,8 +2018,7 @@

Distribution of consensus cell types

types.

- - +
plot_df <- all_results_df |> 
     dplyr::group_by(project_id) |> 
     dplyr::mutate(
@@ -2036,9 +2028,17 @@ 

Distribution of consensus cell types

forcats::fct_infreq() |> # make sure all remaining and unknown are last, use this to assign colors in specific order forcats::fct_relevel("All remaining cell types", "Unknown", after = Inf) - ) - -# get all unique cell types ordered by frequency + )
+ + +
Warning: There was 1 warning in `dplyr::mutate()`.
+ℹ In argument: `top_celltypes = forcats::fct_relevel(...)`.
+ℹ In group 19: `project_id = "SCPCP000021"`.
+Caused by warning:
+! 1 unknown level in `f`: All remaining cell types
+ + +
# get all unique cell types ordered by frequency 
 unique_celltypes <- plot_df |> 
   dplyr::filter(!top_celltypes %in% c("All remaining cell types", "Unknown")) |> 
   dplyr::pull(top_celltypes) |> 
@@ -2055,13 +2055,11 @@ 

Distribution of consensus cell types

) names(colors) <- c(unique_celltypes, "All remaining cell types", "Unknown")
- - - +
project_labels <- unique(all_results_df$project_label)
 
 # stacked bar chart showing the distribution of the top 9 cell types for each project, including Unknown
@@ -2094,7 +2092,9 @@ 

Distribution of consensus cell types

}) |> patchwork::wrap_plots(ncol = 1)
- + +

+

This looks really promising! A few observations:

@@ -2131,8 +2131,7 @@

Most frequently observed cell types

of libraries the cell type is observed.

- - +
all_results_df |> 
   dplyr::filter(consensus_annotation != "Unknown") |> 
   dplyr::group_by(consensus_annotation) |> 
@@ -2143,9 +2142,14 @@ 

Most frequently observed cell types

median_percentage = median(percent_cells_annotation), max_percentage = max(percent_cells_annotation) ) |> - dplyr::arrange(desc(total_libraries)) -
+ dplyr::arrange(desc(total_libraries)) + +
+ +
@@ -2154,11 +2158,42 @@

Most frequently observed cell types

Session info

- - +
# record the versions of the packages used in this analysis and other environment information
 sessionInfo()
+ +
R version 4.4.2 (2024-10-31)
+Platform: aarch64-apple-darwin20
+Running under: macOS Sequoia 15.3
+
+Matrix products: default
+BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
+LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0
+
+locale:
+[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
+
+time zone: America/Chicago
+tzcode source: internal
+
+attached base packages:
+[1] stats     graphics  grDevices datasets  utils     methods   base     
+
+other attached packages:
+[1] ggplot2_3.5.1
+
+loaded via a namespace (and not attached):
+ [1] sass_0.4.9          utf8_1.2.4          generics_0.1.3      renv_1.0.11         stringi_1.8.4       hms_1.1.3          
+ [7] digest_0.6.37       magrittr_2.0.3      evaluate_1.0.1      grid_4.4.2          fastmap_1.2.0       rprojroot_2.0.4    
+[13] jsonlite_1.8.9      BiocManager_1.30.25 purrr_1.0.2         fansi_1.0.6         scales_1.3.0        tweenr_2.0.3       
+[19] jquerylib_0.1.4     cli_3.6.3           rlang_1.1.4         crayon_1.5.3        polyclip_1.10-7     bit64_4.5.2        
+[25] munsell_0.5.1       withr_3.0.2         cachem_1.1.0        yaml_2.3.10         tools_4.4.2         parallel_4.4.2     
+[31] tzdb_0.4.0          dplyr_1.1.4         colorspace_2.1-1    forcats_1.0.0       vctrs_0.6.5         R6_2.5.1           
+[37] lifecycle_1.0.4     stringr_1.5.1       bit_4.5.0.1         vroom_1.6.5         MASS_7.3-61         pkgconfig_2.0.3    
+[43] pillar_1.9.0        bslib_0.8.0         gtable_0.3.6        Rcpp_1.0.13-1       glue_1.8.0          ggforce_0.4.2      
+[49] xfun_0.49           tibble_3.2.1        tidyselect_1.2.1    knitr_1.49          farver_2.1.2        patchwork_1.3.0    
+[55] htmltools_0.5.8.1   rmarkdown_2.29      labeling_0.4.3      readr_2.1.5         compiler_4.4.2     
diff --git a/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.Rmd b/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.Rmd index c7266d6c2..2c3728d2d 100644 --- a/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.Rmd +++ b/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.Rmd @@ -194,7 +194,7 @@ We have already looked at this in `02-explore-consensus-results.Rmd`, but here w all_results_df <- all_results_df |> dplyr::mutate( # get most frequently observed cell types across libraries in that project - top_celltypes = forcats::fct_lump_n(consensus_annotation, 10, other_level = "All remaining cell types", ties.method = "first") |> + top_celltypes = forcats::fct_lump_n(consensus_annotation, 15, other_level = "All remaining cell types", ties.method = "first") |> # sort by frequency forcats::fct_infreq() |> # make sure all remaining and unknown are last, use this to assign colors in specific order @@ -236,6 +236,13 @@ Generally, we see most annotated cells are smooth muscle cells and endothelial c There also appears to be some samples that have macrophages and/or T cell populations. We also see a handful of samples that don't have any cells that are annotated. +```{r} +stacked_barchart(total_order_df, fill_color = "top_celltypes", facet_variable = "project_id", colors = all_celltype_colors) +``` + +It looks like both total number of cells that are classified and composition of those cells is project dependent. +This makes sense since sample prep is probably different across labs. + ## Immune cell populations Let's look specifically at immune cell populations. diff --git a/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.nb.html b/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.nb.html index 032f4072d..4645c1095 100644 --- a/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.nb.html +++ b/analyses/cell-type-consensus/exploratory-notebooks/03-osteosarcoma-consensus-celltypes.nb.html @@ -1975,12 +1975,12 @@

Composition of top cell types

cells labeled with a consensus label.

- +
# add column of "top cell types" for easier plotting 
 all_results_df <- all_results_df |> 
   dplyr::mutate(
     # get most frequently observed cell types across libraries in that project 
-    top_celltypes = forcats::fct_lump_n(consensus_annotation, 10, other_level = "All remaining cell types", ties.method = "first") |> 
+    top_celltypes = forcats::fct_lump_n(consensus_annotation, 15, other_level = "All remaining cell types", ties.method = "first") |> 
       # sort by frequency 
       forcats::fct_infreq() |> 
       # make sure all remaining and unknown are last, use this to assign colors in specific order
@@ -2032,7 +2032,7 @@ 

Composition of top cell types

stacked_barchart(total_order_df, fill_color = "top_celltypes", colors = all_celltype_colors)
-

+

@@ -2042,6 +2042,19 @@

Composition of top cell types

to be some samples that have macrophages and/or T cell populations. We also see a handful of samples that don’t have any cells that are annotated.

+ + + +
stacked_barchart(total_order_df, fill_color = "top_celltypes", facet_variable = "project_id", colors = all_celltype_colors)
+ + +

+ + + +

It looks like both total number of cells that are classified and +composition of those cells is project dependent. This makes sense since +sample prep is probably different across labs.

Immune cell populations

@@ -2258,7 +2271,7 @@

Is there any relationship between immune cell percentage and patchwork::wrap_plots(ncol = 1, guides = "collect")

-

+

@@ -2286,28 +2299,28 @@

Is there any relationship between immune cell percentage and
[[1]]
-

+


 [[2]]
-

+


 [[3]]
-

+


 [[4]]
-

+

@@ -2361,7 +2374,7 @@

Session info

-
LS0tCnRpdGxlOiAiQ29uc2Vuc3VzIGNlbGwgdHlwZXMgYWNyb3NzIG9zdGVvc2FyY29tYSBzYW1wbGVzIgphdXRob3I6IEFsbHkgSGF3a2lucwpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KClRoaXMgbm90ZWJvb2sgc3VtbWFyaXplcyB0aGUgY29uc2Vuc3VzIGNlbGwgdHlwZXMgaWRlbnRpZmllZCBpbiBhbGwgb3N0ZW9zYXJjb21hIHNhbXBsZXMgdGhhdCBhcmUgcGFydCBvZiBTY1BDQS4gClRoaXMgaW5jbHVkZXMgYWxsIHNhbXBsZXMgZnJvbSBgU0NQQ1AwMDAwMTdgLCBgU0NQQ1AwMDAwMThgLCBhbmQgYFNDUENQMDAwMDIzYC4gCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBsb29raW5nIGF0IGFueSBkaWZmZXJlbmNlcyBpbiBjZWxsIGNvbXBvc2l0aW9uIGFjcm9zcyBzYW1wbGVzLCB3aXRoIGEgcGFydGljdWxhciBpbnRlcmVzdCBpbiBsb29raW5nIGF0IHRoZSBpbW11bmUgY2VsbCBwb3B1bGF0aW9ucy4gCgpgYGB7ciBwYWNrYWdlc30Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICAjIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMKICBsaWJyYXJ5KGdncGxvdDIpCn0pCgojIFNldCBkZWZhdWx0IGdncGxvdCB0aGVtZQp0aGVtZV9zZXQoCiAgdGhlbWVfY2xhc3NpYygpCikKYGBgCgoKIyMgRnVuY3Rpb25zCgpgYGB7cn0KIyBiYXJjaGFydCB3aXRoIG9yIHdpdGhvdXQgZmFjZXRpbmcKIyBlYWNoIGJhciBpcyBhIHN0YWNrZWQgYmFyY2hhcnQgdXNpbmcgdGhlIGZpbGxfY29sb3IKIyBmYWNldGluZyBpcyBvbmx5IGRvbmUgaWYgYSBmYWNldF92YXJpYWJsZSBpcyBwcm92aWRlZApzdGFja2VkX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKAogICAgZGYsIAogICAgZmlsbF9jb2xvciwgCiAgICBmYWNldF92YXJpYWJsZSA9IE5VTEwsCiAgICBjb2xvcnMKKXsKICAKICBiYXJjaGFydCA8LSBnZ3Bsb3QoZGYpICsgCiAgICBhZXMoCiAgICAgIHggPSBsaWJyYXJ5X2lkLCAKICAgICAgeSA9IHBlcmNlbnRfY2VsbHNfYW5ub3RhdGlvbiwgCiAgICAgIGZpbGwgPSAhIXN5bShmaWxsX2NvbG9yKQogICAgKSArCiAgICBnZW9tX2NvbCgpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKAogICAgICBmaWxsPSAiY2VsbCB0eXBlIgogICAgKQogIAogIGlmKCFpcy5udWxsKGZhY2V0X3ZhcmlhYmxlKSl7CiAgICBiYXJjaGFydCA8LSBiYXJjaGFydCArCiAgICAgIGZhY2V0X3dyYXAodmFycyghIXN5bShmYWNldF92YXJpYWJsZSkpLCBzY2FsZXMgPSJmcmVlIikKICB9CiAgCiAgcmV0dXJuKGJhcmNoYXJ0KQp9CgojIHNpbmEgcGxvdCBsb29raW5nIGF0IGltbXVuZSBwZXJjZW50YWdlIG9uIHRoZSB5LWF4aXMgCnNpbmFfcGxvdCA8LSBmdW5jdGlvbihkZiwgcGxvdF9jb2x1bW4pewogIAogIGdncGxvdChpbW11bmVfcGxvdF9kZiwgYWVzKHggPSAhIXN5bShwbG90X2NvbHVtbiksIHkgPSBwZXJjZW50X2ltbXVuZSkpICsKICAgIGdnZm9yY2U6Omdlb21fc2luYSgpICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueT1tZWRpYW4sIGdlb209ImNyb3NzYmFyIiAsIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDAuMikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSksCiAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwxMCwxMCwxMCkpICsKICAgIGxhYnMoCiAgICAgIHggPSAiIiwgCiAgICAgIHkgPSAiUGVyY2VudCBvZiBjZWxscyBhbm5vdGF0ZWQgYXMgSW1tdW5lIiwKICAgICAgdGl0bGUgPSBwbG90X2NvbHVtbgogICAgKQogIAp9CmBgYAoKCiMjIERhdGEgc2V0dXAKCgpgYGB7ciBiYXNlIHBhdGhzfQojIFRoZSBiYXNlIHBhdGggZm9yIHRoZSBPcGVuU2NQQ0EgcmVwb3NpdG9yeSwgZm91bmQgYnkgaXRzIChoaWRkZW4pIC5naXQgZGlyZWN0b3J5CnJlcG9zaXRvcnlfYmFzZSA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6OmlzX2dpdF9yb290KQptb2R1bGVfYmFzZSA8LSBmaWxlLnBhdGgocmVwb3NpdG9yeV9iYXNlLCAiYW5hbHlzZXMiLCAiY2VsbC10eXBlLWNvbnNlbnN1cyIpCgojIHJlc3VsdHMgZGlyZWN0b3J5IHdpdGggY2VsbC10eXBlLWNvbnNlbnN1cyAKcmVzdWx0c19kaXIgPC0gZmlsZS5wYXRoKG1vZHVsZV9iYXNlLCAicmVzdWx0cyIsICJjZWxsLXR5cGUtY29uc2Vuc3VzIikKCiMgZGF0YSBkaXJlY3Rvcnkgd2hlcmUgcHJvamVjdCBtZXRhZGF0YSBmaWxlcyBsaXZlCmRhdGFfZGlyIDwtIGZpbGUucGF0aChyZXBvc2l0b3J5X2Jhc2UsICJkYXRhIiwgImN1cnJlbnQiKQpgYGAKCmBgYHtyfQojIGxpc3QgYWxsIHJlc3VsdHMgZmlsZXMgCnJlc3VsdHNfZmlsZXMgPC0gbGlzdC5maWxlcyhyZXN1bHRzX2RpciwgcGF0dGVybiA9ICJfY29uc2Vuc3VzLWNlbGwtdHlwZXNcXC50c3YuXFxneiQiLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgZ2V0IHByb2plY3QgaWRzIGZyb20gZmlsZSBsaXN0IGFuZCBhc3NpZ24gYXMgbmFtZXMKcHJvamVjdF9pZHMgPC0gc3RyaW5ncjo6c3RyX3JlbW92ZShiYXNlbmFtZShyZXN1bHRzX2ZpbGVzKSwgIl9jb25zZW5zdXMtY2VsbC10eXBlcy50c3YuZ3oiKQpuYW1lcyhyZXN1bHRzX2ZpbGVzKSA8LSBwcm9qZWN0X2lkcwoKIyBncmFiIG9ubHkgb3N0ZW8gcHJvamVjdHMKb3N0ZW9fcHJvamVjdF9pZHMgPC0gYygiU0NQQ1AwMDAwMTciLCAiU0NQQ1AwMDAwMTgiLCAiU0NQQ1AwMDAwMjMiKQpyZXN1bHRzX2ZpbGVzIDwtIHJlc3VsdHNfZmlsZXNbb3N0ZW9fcHJvamVjdF9pZHNdCgojIGxpc3QgcHJvamVjdCBtZXRhZGF0YSBmaWxlcyBhbmQgZ3JhYiBvbmx5IG9zdGVvIG1ldGFkYXRhIAptZXRhZGF0YV9maWxlcyA8LSBsaXN0LmZpbGVzKGRhdGFfZGlyLCBwYXR0ZXJuID0gInNpbmdsZV9jZWxsX21ldGFkYXRhXFwudHN2JCIsIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFKQptZXRhZGF0YV9pZHMgPC0gc3RyaW5ncjo6d29yZChkaXJuYW1lKG1ldGFkYXRhX2ZpbGVzKSwgLTEsIHNlcCA9ICIvIikKbmFtZXMobWV0YWRhdGFfZmlsZXMpIDwtIG1ldGFkYXRhX2lkcwpvc3Rlb19tZXRhZGF0YV9maWxlcyA8LSBtZXRhZGF0YV9maWxlc1tvc3Rlb19wcm9qZWN0X2lkc10KCiMgbGlzdCBvZiBhbGwgaW1tdW5lIGNlbGwgdHlwZXMgCmNvbnNlbnN1c19pbW11bmVfZmlsZSA8LSBmaWxlLnBhdGgobW9kdWxlX2Jhc2UsICJyZWZlcmVuY2VzIiwgImNvbnNlbnN1cy1pbW11bmUtY2VsbC10eXBlcy50c3YiKQpgYGAKCmBgYHtyfQojIHNvdXJjZSBzdW1tYXJpemVfY2VsbHR5cGVzKCkgZnVuY3Rpb24Kc2V0dXBfZnVuY3Rpb25zIDwtIGZpbGUucGF0aChtb2R1bGVfYmFzZSwgImV4cGxvcmF0b3J5LW5vdGVib29rcyIsICJ1dGlscyIsICJzZXR1cC1mdW5jdGlvbnMuUiIpCnNvdXJjZShzZXR1cF9mdW5jdGlvbnMpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CiMgZ2V0IGltbXVuZSBjZWxsIHR5cGVzIAppbW11bmVfZGYgPC0gcmVhZHI6OnJlYWRfdHN2KGNvbnNlbnN1c19pbW11bmVfZmlsZSkKaW1tdW5lX3R5cGVzIDwtIGltbXVuZV9kZiRjb25zZW5zdXNfYW5ub3RhdGlvbgoKIyByZWFkIGluIG1ldGFkYXRhCmFsbF9tZXRhZGF0YV9kZiA8LSBvc3Rlb19tZXRhZGF0YV9maWxlcyB8PgogIHB1cnJyOjptYXAocmVhZHI6OnJlYWRfdHN2KSB8PgogIGRwbHlyOjpiaW5kX3Jvd3MoKSB8PgogICMgc2VsZWN0IGNvbHVtbnMgdGhhdCBtaWdodCBiZSB1c2VmdWwgCiAgZHBseXI6OnNlbGVjdCgKICAgIHByb2plY3RfaWQgPSBzY3BjYV9wcm9qZWN0X2lkLAogICAgbGlicmFyeV9pZCA9IHNjcGNhX2xpYnJhcnlfaWQsCiAgICBkaXNlYXNlX3RpbWluZywKICAgIGFnZSwKICAgIHNleCwKICAgIHRpc3N1ZV9sb2NhdGlvbiwKICAgIHByaW1hcnlfb3JfbWV0YXN0YXNpcywKICAgIHNlcV91bml0CiAgKQoKIyByZWFkIGluIHJlc3VsdHMgYW5kIHByZXAgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcgCmFsbF9yZXN1bHRzX2RmIDwtIHJlc3VsdHNfZmlsZXMgfD4gCiAgcHVycnI6OmltYXAoc3VtbWFyaXplX2NlbGx0eXBlcykgfD4gCiAgZHBseXI6OmJpbmRfcm93cyguaWQgPSAicHJvamVjdF9pZCIpIHw+IAogICMgam9pbiB3aXRoIHNhbXBsZSBtZXRhZGF0YQogIGRwbHlyOjpsZWZ0X2pvaW4oYWxsX21ldGFkYXRhX2RmLCBieSA9IGMoInByb2plY3RfaWQiLCAibGlicmFyeV9pZCIpKSB8PgogICMgcmVtb3ZlIHBkeCBzYW1wbGVzIAogIGRwbHlyOjpmaWx0ZXIoc2FtcGxlX3R5cGUgIT0gInBhdGllbnQtZGVyaXZlZCB4ZW5vZ3JhZnQiKQpgYGAKCgpgYGB7cn0KIyBhc3NpZ24gYSBjb2xvciBzY2hlbWUgZm9yIGFsbCBiYXIgY2hhcnRzIAoKIyBnZXQgYWxsIHBvc3NpYmxlIGNlbGwgdHlwZXMgCiMgdGhlcmUgYXJlIGV4YWN0bHkgMjUgb2YgdGhlbSBzbyB3aWxsIHVzZSBhbHBoYWJldCB3aXRoIHR3byBncmV5cyBmb3IgdW5rbm93bi9hbGwgcmVtYWluaW5nIAp1bmlxdWVfY2VsbHR5cGVzIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjpmaWx0ZXIocGVyY2VudF9jZWxsc19hbm5vdGF0aW9uID4gMC4xLCAjIHdlJ3JlIG9ubHkgZXZlciBnb2luZyB0byBwbG90IGNlbGwgdHlwZXMgdGhhdCBhcmUgZ3JlYXRlciB0aGFuIDElCiAgICAgICAgICAgICAgICAhY29uc2Vuc3VzX2Fubm90YXRpb24gPT0gIlVua25vd24iKSB8PiAKICBkcGx5cjo6cHVsbChjb25zZW5zdXNfYW5ub3RhdGlvbikgfD4gCiAgdW5pcXVlKCkgfD4KICBhcy5jaGFyYWN0ZXIoKQoKIyBkZWZpbmUgY29sb3JzIGZvciBhbGwgY2VsbCB0eXBlcwphbGxfY2VsbHR5cGVfY29sb3JzIDwtIGMoCiAgcGFsZXR0ZS5jb2xvcnMocGFsZXR0ZSA9ICJhbHBoYWJldCIpWzE6MjVdLAogICJncmV5NjAiLCAjIGFsbCByZW1haW5pbmcKICAiZ3JleTk1IiwgIyB1bmtub3duCiAgImdyZXk2MCIgIyBub24taW1tdW5lLCB1c2UgdGhlIHNhbWUgYXMgYWxsIHJlbWFpbmluZyBzaW5jZSB0aGV5IGFyZSBuZXZlciBpbiB0aGUgc2FtZSBwbG90CikKbmFtZXMoYWxsX2NlbGx0eXBlX2NvbG9ycykgPC0gYyh1bmlxdWVfY2VsbHR5cGVzLCAiQWxsIHJlbWFpbmluZyBjZWxsIHR5cGVzIiwgIlVua25vd24iLCAibm9uLWltbXVuZSIpCgojIGRlZmluZSBhIHRocmVlIGNvbG9yIHNjaGVtZSBmb3IgaW1tdW5lLCBvdGhlciwgYW5kIHVua25vd24KdGhyZWVfY29sb3Jfc2NoZW1lIDwtIGMoCiAgImltbXVuZSIgPSAibmF2eSIsCiAgIm5vbi1pbW11bmUiID0gImdyZXk2MCIsCiAgIlVua25vd24iID0gImdyZXk5NSIKKQpgYGAKCiMjIENvbXBvc2l0aW9uIG9mIHRvcCBjZWxsIHR5cGVzIAoKSGVyZSB3ZSBsb29rIGF0IHRoZSB0b3AgY2VsbCB0eXBlcyBpZGVudGlmaWVkIGFjcm9zcyBhbGwgc2FtcGxlcy4gCldlIGhhdmUgYWxyZWFkeSBsb29rZWQgYXQgdGhpcyBpbiBgMDItZXhwbG9yZS1jb25zZW5zdXMtcmVzdWx0cy5SbWRgLCBidXQgaGVyZSB3ZSB3aWxsIHBsb3QgYWxsIHNhbXBsZXMgZnJvbSBhbGwgdGhyZWUgb3N0ZW8gcHJvamVjdHMgb3JkZXJlZCBieSB0aGUgdG90YWwgcGVyY2VudCBvZiBjZWxscyBsYWJlbGVkIHdpdGggYSBjb25zZW5zdXMgbGFiZWwuIAoKYGBge3J9CiMgYWRkIGNvbHVtbiBvZiAidG9wIGNlbGwgdHlwZXMiIGZvciBlYXNpZXIgcGxvdHRpbmcgCmFsbF9yZXN1bHRzX2RmIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICAjIGdldCBtb3N0IGZyZXF1ZW50bHkgb2JzZXJ2ZWQgY2VsbCB0eXBlcyBhY3Jvc3MgbGlicmFyaWVzIGluIHRoYXQgcHJvamVjdCAKICAgIHRvcF9jZWxsdHlwZXMgPSBmb3JjYXRzOjpmY3RfbHVtcF9uKGNvbnNlbnN1c19hbm5vdGF0aW9uLCAxMCwgb3RoZXJfbGV2ZWwgPSAiQWxsIHJlbWFpbmluZyBjZWxsIHR5cGVzIiwgdGllcy5tZXRob2QgPSAiZmlyc3QiKSB8PiAKICAgICAgIyBzb3J0IGJ5IGZyZXF1ZW5jeSAKICAgICAgZm9yY2F0czo6ZmN0X2luZnJlcSgpIHw+IAogICAgICAjIG1ha2Ugc3VyZSBhbGwgcmVtYWluaW5nIGFuZCB1bmtub3duIGFyZSBsYXN0LCB1c2UgdGhpcyB0byBhc3NpZ24gY29sb3JzIGluIHNwZWNpZmljIG9yZGVyCiAgICAgIGZvcmNhdHM6OmZjdF9yZWxldmVsKCJBbGwgcmVtYWluaW5nIGNlbGwgdHlwZXMiLCAiVW5rbm93biIsIGFmdGVyID0gSW5mKSwKICApCmBgYAoKCmBgYHtyfQojIGdldCBhIHZlY3RvciBvZiBsaWJyYXJ5IGlkcyBvcmRlcmVkIGJ5IHRvdGFsIHBlcmNlbnRhZ2UgYW5ub3RhdGVkCmxpYnJhcnlfbGV2ZWxzIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjpmaWx0ZXIoY29uc2Vuc3VzX2Fubm90YXRpb24gIT0gIlVua25vd24iKSB8PiAKICBkcGx5cjo6Z3JvdXBfYnkobGlicmFyeV9pZCkgfD4gCiAgZHBseXI6OnN1bW1hcml6ZSgKICAgIHRvdGFsX3BlcmNlbnRfYW5ub3RhdGVkID0gc3VtKHRvdGFsX2NlbGxzX3Blcl9hbm5vdGF0aW9uKS90b3RhbF9jZWxsc19wZXJfbGlicmFyeQogICkgfD4KICB1bmlxdWUoKSB8PiAKICBkcGx5cjo6YXJyYW5nZShkZXNjKHRvdGFsX3BlcmNlbnRfYW5ub3RhdGVkKSkgfD4gCiAgZHBseXI6OnB1bGwobGlicmFyeV9pZCkKCiMgYXBwZW5kIGFueSBsaWJyYXJpZXMgdGhhdCBoYXZlIDAgY2VsbHMgYW5ub3RhdGVkCm5vbl9hbm5vdGF0ZWRfbGlicyA8LSBzZXRkaWZmKHVuaXF1ZShhbGxfcmVzdWx0c19kZiRsaWJyYXJ5X2lkKSwgbGlicmFyeV9sZXZlbHMpCmxpYnJhcnlfbGV2ZWxzIDwtIGMobGlicmFyeV9sZXZlbHMsIG5vbl9hbm5vdGF0ZWRfbGlicykKCiMgcmVvcmRlciBieSB0b3RhbCBwZXJjZW50YWdlIGFubm90YXRlZCAKdG90YWxfb3JkZXJfZGYgPC0gYWxsX3Jlc3VsdHNfZGYgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgIGxpYnJhcnlfaWQgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChsaWJyYXJ5X2lkLCBsaWJyYXJ5X2xldmVscykKICApCmBgYAoKCmBgYHtyfQpzdGFja2VkX2JhcmNoYXJ0KHRvdGFsX29yZGVyX2RmLCBmaWxsX2NvbG9yID0gInRvcF9jZWxsdHlwZXMiLCBjb2xvcnMgPSBhbGxfY2VsbHR5cGVfY29sb3JzKQpgYGAKCkl0IGxvb2tzIGxpa2UgdGhlcmUncyBkZWZpbml0ZWx5IHNvbWUgdmFyaWF0aW9uIGJldHdlZW4gZGlzdHJpYnV0aW9ucyBvZiBjZWxsIHR5cGVzIHdpdGhpbiB0aGUgb3N0ZW8gc2FtcGxlcy4gCkdlbmVyYWxseSwgd2Ugc2VlIG1vc3QgYW5ub3RhdGVkIGNlbGxzIGFyZSBzbW9vdGggbXVzY2xlIGNlbGxzIGFuZCBlbmRvdGhlbGlhbCBjZWxscy4gClRoZXJlIGFsc28gYXBwZWFycyB0byBiZSBzb21lIHNhbXBsZXMgdGhhdCBoYXZlIG1hY3JvcGhhZ2VzIGFuZC9vciBUIGNlbGwgcG9wdWxhdGlvbnMuIApXZSBhbHNvIHNlZSBhIGhhbmRmdWwgb2Ygc2FtcGxlcyB0aGF0IGRvbid0IGhhdmUgYW55IGNlbGxzIHRoYXQgYXJlIGFubm90YXRlZC4KCiMjIEltbXVuZSBjZWxsIHBvcHVsYXRpb25zCgpMZXQncyBsb29rIHNwZWNpZmljYWxseSBhdCBpbW11bmUgY2VsbCBwb3B1bGF0aW9ucy4gClRvIGRvIHRoaXMgd2Ugd2lsbCBsdW1wIGFsbCBpbW11bmUgY2VsbHMgYXMgImltbXVuZSIsIGFsbCBub24taW1tdW5lIGFzICJub24taW1tdW5lIiwgYW5kIGFsbCB1bmtub3duIGFzICJ1bmtub3duIi4gCkhlcmUgd2Ugd2lsbCBzb3J0IGJ5IHRvdGFsIHBlcmNlbnRhZ2Ugb2YgaW1tdW5lIGNlbGxzLiAKCmBgYHtyfQojIGxvb2sgYXQgaW1tdW5lIGNlbGwgdHlwZXMgdnMuIHVua25vd24gdnMuIG90aGVyIAphbGxfcmVzdWx0c19kZiA8LSBhbGxfcmVzdWx0c19kZiB8PiAKICAjZHBseXI6OmxlZnRfam9pbihpbW11bmVfZGYsIGJ5ID0gYygiY29uc2Vuc3VzX2Fubm90YXRpb24iLCAiY29uc2Vuc3VzX29udG9sb2d5IikpIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICAjIGZpcnN0IGdldCBhIGNvbHVtbiB0aGF0IGlzIGp1c3QgaW1tdW5lLCB1bmtub3duLCBvciBvdGhlcgogICAgaW1tdW5lX2NhdGVnb3J5ID0gZHBseXI6OmNhc2Vfd2hlbigKICAgICAgY29uc2Vuc3VzX2Fubm90YXRpb24gJWluJSBpbW11bmVfdHlwZXMgfiAiaW1tdW5lIiwKICAgICAgY29uc2Vuc3VzX2Fubm90YXRpb24gPT0gIlVua25vd24iIH4gIlVua25vd24iLAogICAgICAuZGVmYXVsdCA9ICJub24taW1tdW5lIgogICAgKQogICkKYGBgCgpgYGB7cn0KIyBub3cgc29ydCBqdXN0IGJ5IGltbXVuZSBwZXJjZW50YWdlCmltbXVuZV9wY3RfZGYgPC0gYWxsX3Jlc3VsdHNfZGYgfD4gCiAgZHBseXI6OmZpbHRlcihpbW11bmVfY2F0ZWdvcnkgPT0gImltbXVuZSIpIHw+IAogIGRwbHlyOjpncm91cF9ieShsaWJyYXJ5X2lkKSB8PiAKICBkcGx5cjo6c3VtbWFyaXplKAogICAgcGVyY2VudF9pbW11bmUgPSBzdW0odG90YWxfY2VsbHNfcGVyX2Fubm90YXRpb24pL3RvdGFsX2NlbGxzX3Blcl9saWJyYXJ5CiAgKSB8PgogIGRwbHlyOjpzZWxlY3QobGlicmFyeV9pZCwgcGVyY2VudF9pbW11bmUpIHw+IAogIHVuaXF1ZSgpIAoKbGlicmFyeV9sZXZlbHMgPC0gaW1tdW5lX3BjdF9kZiB8PiAKICBkcGx5cjo6YXJyYW5nZShkZXNjKHBlcmNlbnRfaW1tdW5lKSkgfD4gCiAgZHBseXI6OnB1bGwobGlicmFyeV9pZCkKCiMgYXBwZW5kIGFueSBsaWJyYXJpZXMgdGhhdCBoYXZlIDAgaW1tdW5lIGNlbGxzIGFubm90YXRlZApub25fYW5ub3RhdGVkX2xpYnMgPC0gc2V0ZGlmZih1bmlxdWUoYWxsX3Jlc3VsdHNfZGYkbGlicmFyeV9pZCksIGxpYnJhcnlfbGV2ZWxzKQpsaWJyYXJ5X2xldmVscyA8LSBjKGxpYnJhcnlfbGV2ZWxzLCBub25fYW5ub3RhdGVkX2xpYnMpCgppbW11bmVfcmVzdWx0c19kZiA8LSBhbGxfcmVzdWx0c19kZiB8PiAKICBkcGx5cjo6bGVmdF9qb2luKGltbXVuZV9wY3RfZGYsIGJ5ID0gYygibGlicmFyeV9pZCIpKSB8PiAKICBkcGx5cjo6bXV0YXRlKAogICAgcGVyY2VudF9pbW11bmUgPSBkcGx5cjo6aWZfZWxzZShpcy5uYShwZXJjZW50X2ltbXVuZSksIDAsIHBlcmNlbnRfaW1tdW5lKSwKICAgIGxpYnJhcnlfaWQgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChsaWJyYXJ5X2lkLCBsaWJyYXJ5X2xldmVscykKICApCgpzdGFja2VkX2JhcmNoYXJ0KGltbXVuZV9yZXN1bHRzX2RmLCBmaWxsX2NvbG9yID0gImltbXVuZV9jYXRlZ29yeSIsIGNvbG9ycyA9IHRocmVlX2NvbG9yX3NjaGVtZSkKYGBgCkxldCdzIHNlZSBob3cgdGhlIHBlcmNlbnRhZ2Ugb2YgaW1tdW5lIGNlbGxzIGNvbXBhcmVzIGFjcm9zcyBwcm9qZWN0cy4gCgpgYGB7cn0Kc3RhY2tlZF9iYXJjaGFydChpbW11bmVfcmVzdWx0c19kZiwgZmlsbF9jb2xvciA9ICJpbW11bmVfY2F0ZWdvcnkiLCBmYWNldF92YXJpYWJsZSA9ICJwcm9qZWN0X2lkIiwgY29sb3JzID0gdGhyZWVfY29sb3Jfc2NoZW1lKQpgYGAKCldoZW4gbG9va2luZyBhdCBhbGwgc2FtcGxlcyB0b2dldGhlciB3ZSBkbyBzZWUgdmFyaWF0aW9uIGluIGltbXVuZSBjZWxscyBjbGFzc2lmaWVkIGFuZCBpdCBhcHBlYXJzIHRoYXQgYFNDUENQMDAwMDE3YCBhbmQgYFNDUENQMDAwMDE4YCBoYXZlIG1vcmUgY2VsbHMgY2xhc3NpZmllZCBpbiBnZW5lcmFsIGFuZCBoYXZlIG1vcmUgY2VsbHMgY2xhc3NpZmllZCBhcyBpbW11bmUuIApJdCBkb2VzIGFwcGVhciB0aGF0IGxpYnJhcmllcyB0aGF0IGhhdmUgbW9yZSBpbW11bmUgY2VsbCBjb21wb3NpdGlvbiBhbHNvIGhhdmUgYSBoaWdoZXIgcGVyY2VudGFnZSBvZiBub24taW1tdW5lIGNlbGwgdHlwZXMgd2hpY2ggY291bGQgdmVyeSB3ZWxsIGJlIGEgdGVjaG5pY2FsIGFydGlmYWN0IGFuZCByZWxhdGVkIHRvIHNhbXBsZSBwcmVwLiAKCkp1c3QgZm9yIHZpc3VhbGl6YXRpb24gcHVycG9zZXMsIGxldCdzIGNsYXNzaWZ5IHRoZXNlIGFzICJob3QiIGFuZCAiY29sZCIsIHdoZXJlICJob3QiIHR1bW9ycyBoYXZlIGFuIGltbXVuZSBjb21wb3NpdGlvbiA+IDUlLgoKYGBge3J9CmltbXVuZV9yZXN1bHRzX2RmIDwtIGltbXVuZV9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICAjIGNsYXNzaWZ5IGhvdC9jb2xkIGJhc2VkIG9uIGltbXVuZSBwZXJjZW50ID4gNSAlCiAgICBob3RfY29sZCA9IGRwbHlyOjppZl9lbHNlKHBlcmNlbnRfaW1tdW5lID4gLjA1LCAiaG90IiwgImNvbGQiKQogICkKYGBgCgpgYGB7cn0Kc3RhY2tlZF9iYXJjaGFydChpbW11bmVfcmVzdWx0c19kZiwgZmlsbF9jb2xvciA9ICJpbW11bmVfY2F0ZWdvcnkiLCBmYWNldF92YXJpYWJsZSA9ICJob3RfY29sZCIsIGNvbG9ycyA9IHRocmVlX2NvbG9yX3NjaGVtZSkKYGBgCgpPdXIgdGhyZXNob2xkIGlzIHByZXR0eSBhcmJpdHJhcnksIGJ1dCBJIHRoaW5rIHRoZXJlIGFyZSBkZWZpbml0ZWx5IHNvbWUgImNvbGQiIHR1bW9ycyB3aGVyZSB3ZSBzZWUgbGl0dGxlIHRvIG5vIGltbXVuZSBpbnZvbHZlbWVudC4gCgpCZWxvdyB3ZSBjYW4gbG9vayBhdCBhbGwgaW1tdW5lIGNlbGwgdHlwZXMgdnMuIGFsbCBub24taW1tdW5lLiAKCmBgYHtyfQppbW11bmVfcmVzdWx0c19kZiA8LSBpbW11bmVfcmVzdWx0c19kZiB8PiAKICBkcGx5cjo6bXV0YXRlKAogICAgaXNfaW1tdW5lID0gZHBseXI6OmlmX2Vsc2UoCiAgICAgIGltbXVuZV9jYXRlZ29yeSA9PSAiaW1tdW5lIiB8IHRvcF9jZWxsdHlwZXMgPT0gIlVua25vd24iLAogICAgICBjb25zZW5zdXNfYW5ub3RhdGlvbiwKICAgICAgIm5vbi1pbW11bmUiCiAgICApCiAgKQoKc3RhY2tlZF9iYXJjaGFydChpbW11bmVfcmVzdWx0c19kZiwgZmlsbF9jb2xvciA9ICJpc19pbW11bmUiLCBjb2xvcnMgPSBhbGxfY2VsbHR5cGVfY29sb3JzKQpgYGAKCkdlbmVyYWxseSwgaWYgaW1tdW5lIGNlbGxzIGFyZSBwcmVzZW50IHRoZXkgdGVuZCB0byBiZSBtYWNyb3BoYWdlcy4gClRoZXJlJ3MgYWxzbyBhIGxvdCBvZiBUIGNlbGwgcG9wdWxhdGlvbnMsIHdoaWNoIG1ha2VzIHNlbnNlIHNpbmNlIGl0IGhhcyBiZWVuIHByZXZpb3VzbHkgbm90ZWQgdGhhdCBvc3Rlb3NhcmNvbWEgaGFzIGEgaGlnaCBwZXJjZW50YWdlIG9mIFQgY2VsbCBpbmZpbHRyYXRlIChodHRwczovL2RvaS5vcmcvMTAuMTg2MzIvb25jb3RhcmdldC4xOTA3MSkuICAKCiMjIElzIHRoZXJlIGFueSByZWxhdGlvbnNoaXAgYmV0d2VlbiBpbW11bmUgY2VsbCBwZXJjZW50YWdlIGFuZCBjbGluaWNhbCBtZXRhZGF0YT8gCgpPbmUgdGhpbmcgSSB3YXMgY3VyaW91cyBhYm91dCB3YXMgd2hldGhlciBvciBub3QgdGhlcmUgYXJlIGFueSBkaWZmZXJlbmNlcyBpbiB0aGUgcHJlc2VuY2Ugb2YgaW1tdW5lIGNlbGxzIGJhc2VkIG9uIGNsaW5pY2FsIG1ldGFkYXRhIHN1Y2ggYXMgcHJpbWFyeSB2cy4gbWV0YXN0YXNpcywgaW5pdGlhbCBkaWFnbm9zaXMgdnMuIHJlY3VycmVuY2UsIGFuZCB0aXNzdWUgbG9jYXRpb24gKGJvbmUgdnMuIHNvZnQgdGlzc3VlKS4gCkkgYWxzbyBleHBlY3QgdGhlcmUgbWlnaHQgYmUgc29tZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHNpbmdsZS1jZWxsIGFuZCBzaW5nbGUtbnVjbGVpIHNhbXBsZXMuIAoKQmVsb3cgSSBsb29rIGF0IHRoZSBpbW11bmUgY2VsbCBwZXJjZW50YWdlIHN0cmF0aWZpZWQgYnkgZWFjaCBvZiB0aGUgbWVudGlvbmVkIG1ldGFkYXRhLiAKVGhpcyBpcyBqdXN0IGEgcHJlbGltaW5hcnkgbG9vayBhbmQgaWYgd2UgcmVhbGx5IHdhbnQgdG8gZGlnIGludG8gdGhpcyBmdXJ0aGVyIHdlIHNob3VsZCBjb25zaWRlciBsb29raW5nIGF0IGFsZ29yaXRobXMgZm9yIGNvbXBhcmluZyBjZWxsIHR5cGUgY29tcG9zaXRpb24gaW4gc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhLCBidXQgdGhhdCBpcyBvdXRzaWRlIHRoZSBzY29wZSBvZiB0aGlzIG5vdGVib29rLiAKCmBgYHtyfQojIGRvIHNvbWUgZGF0YSB3cmFuZ2xpbmcgb24gdGhlIG1ldGFkYXRhIGNvbHVtbnMgd2Ugd2FudCB0byBsb29rIGF0IAppbW11bmVfcmVzdWx0c19kZiA8LSBpbW11bmVfcmVzdWx0c19kZiB8PiAKICBkcGx5cjo6bXV0YXRlKAogICAgcHJpbWFyeV9vcl9tZXRhc3Rhc2lzID0gZHBseXI6OmlmX2Vsc2UoIWlzLm5hKHByaW1hcnlfb3JfbWV0YXN0YXNpcyksIHByaW1hcnlfb3JfbWV0YXN0YXNpcywgZGlzZWFzZV90aW1pbmcpLAogICAgZGlzZWFzZV90aW1pbmdfbW9kID0gZHBseXI6OmlmX2Vsc2UoZGlzZWFzZV90aW1pbmcgJWluJSBjKCJJbml0aWFsIGRpYWdub3NpcyIsICJSZWN1cnJlbmNlIiksIGRpc2Vhc2VfdGltaW5nLCAib3RoZXIiKSwKICAgIHRpc3N1ZV9sb2NhdGlvbl9tb2QgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHRpc3N1ZV9sb2NhdGlvbiwgIkJvbmV8ZmVtdXJ8SHVtZXJ1c3xUaWJpYSIpIH4gIkJvbmUiLAogICAgICAjc3RyaW5ncjo6c3RyX2RldGVjdCh0aXNzdWVfbG9jYXRpb24sICJmZW11ciIpIH4gIkJvbmUiLAogICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KHRpc3N1ZV9sb2NhdGlvbiwgImx1bmd8THVuZ3xDaGVzdCIpIH4gImx1bmcgb3IgY2hlc3QiLAogICAgICAuZGVmYXVsdCA9ICJvdGhlciIKICAgICkKICApCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTB9CiMgZ2V0IGEgbGlzdCBvZiBtZXRhZGF0YSB3ZSBjYXJlIGFib3V0IAptZXRhZGF0YV9jYXRlZ29yaWVzIDwtIGMoCiAgInByaW1hcnlfb3JfbWV0YXN0YXNpcyIsCiAgImRpc2Vhc2VfdGltaW5nX21vZCIsCiAgInRpc3N1ZV9sb2NhdGlvbl9tb2QiLAogICJzZXFfdW5pdCIKKQoKIyBtYWtlIHN0YWNrZWQgYmFyIHBsb3RzIGxvb2tpbmcgYXQgb25seSBpbW11bmUgYW5kIG5vbiBpbW11bmUgCm1ldGFkYXRhX2NhdGVnb3JpZXMgfD4gCiAgcHVycnI6Om1hcChcKGNhdGVnb3J5KXsKICAgIAogICAgc3RhY2tlZF9iYXJjaGFydCgKICAgICAgaW1tdW5lX3Jlc3VsdHNfZGYsCiAgICAgIGZpbGxfY29sb3IgPSAiaW1tdW5lX2NhdGVnb3J5IiwKICAgICAgZmFjZXRfdmFyaWFibGUgPSBjYXRlZ29yeSwKICAgICAgY29sb3JzID0gdGhyZWVfY29sb3Jfc2NoZW1lCiAgICApCn0pIHw+CiAgcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKG5jb2wgPSAxLCBndWlkZXMgPSAiY29sbGVjdCIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9MTB9CiMgbm93IGxvb2sgYXQgYWxsIHRvcCBjZWxsdHlwZXMgCm1ldGFkYXRhX2NhdGVnb3JpZXMgfD4gCiAgcHVycnI6Om1hcChcKGNhdGVnb3J5KXsKICAgIAogICAgc3RhY2tlZF9iYXJjaGFydCgKICAgICAgaW1tdW5lX3Jlc3VsdHNfZGYsCiAgICAgIGZpbGxfY29sb3IgPSAidG9wX2NlbGx0eXBlcyIsCiAgICAgIGZhY2V0X3ZhcmlhYmxlID0gY2F0ZWdvcnksCiAgICAgIGNvbG9ycyA9IGFsbF9jZWxsdHlwZV9jb2xvcnMKICAgICkKfSkgfD4KICBwYXRjaHdvcms6OndyYXBfcGxvdHMobmNvbCA9IDEsIGd1aWRlcyA9ICJjb2xsZWN0IikKYGBgCgpCZWxvdyBhcmUgc2luYSBwbG90cyB0aGF0IGNvbXBhcmUgdGhlIHRvdGFsIGltbXVuZSBwZXJjZW50YWdlIGZvciBhbGwgc2FtcGxlcyBpbiBhIGdpdmVuIGNhdGVnb3J5LiAKCmBgYHtyfQppbW11bmVfcGxvdF9kZiA8LSBpbW11bmVfcmVzdWx0c19kZiB8PiAKICAjIGp1c3QgbG9vayBhdCBpbW11bmUgcG9wdWxhdGlvbiBhY3Jvc3MgZGlmZmVyZW50IGRpYWdub3NlcyAKICBkcGx5cjo6c2VsZWN0KGxpYnJhcnlfaWQsIHByaW1hcnlfb3JfbWV0YXN0YXNpcywgZGlzZWFzZV90aW1pbmdfbW9kLCB0aXNzdWVfbG9jYXRpb25fbW9kLCBwZXJjZW50X2ltbXVuZSwgc2VxX3VuaXQpIHw+IAogIHVuaXF1ZSgpCmBgYAoKYGBge3J9Cm1ldGFkYXRhX2NhdGVnb3JpZXMgfD4gCiAgcHVycnI6Om1hcChcKGNhdGVnb3J5KXsKICAgIHNpbmFfcGxvdChpbW11bmVfcGxvdF9kZiwgY2F0ZWdvcnkpCiAgfSkKYGBgCgpJdCBsb29rcyBsaWtlIHRoZXJlIG1pZ2h0IGJlIGhpZ2hlciBpbW11bmUgaW5maWx0cmF0ZSBpbiAiYm9uZSIgc2FtcGxlcywgYnV0IGFnYWluIEkgdGhpbmsgaWYgd2Ugd2FudCB0byBtYWtlIGFueSBjb25jbHVzaW9ucyB3ZSBuZWVkIHRvIGxvb2sgYXQgc29mdHdhcmUgdGhhdCBoZWxwcyBjb3JyZWN0IGZvciB0ZWNobmljYWwgYXJ0aWZhY3RzLiAKVGhlcmUgbWF5IGFsc28gYmUgYSBkaWZmZXJlbmNlIGluIHNpbmdsZS1jZWxsIGFuZCBzaW5nbGUtbnVjbGVpLCBidXQgdGhlcmUgYXJlIG11Y2ggZmV3ZXIgc2luZ2xlLWNlbGwgc2FtcGxlcyBzbyBpdCdzIGhhcmQgdG8gc2F5LiAKCgojIyBTZXNzaW9uIGluZm8gCgpgYGB7ciBzZXNzaW9uIGluZm99CiMgcmVjb3JkIHRoZSB2ZXJzaW9ucyBvZiB0aGUgcGFja2FnZXMgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIGFuZCBvdGhlciBlbnZpcm9ubWVudCBpbmZvcm1hdGlvbgpzZXNzaW9uSW5mbygpCmBgYAo=
+
LS0tCnRpdGxlOiAiQ29uc2Vuc3VzIGNlbGwgdHlwZXMgYWNyb3NzIG9zdGVvc2FyY29tYSBzYW1wbGVzIgphdXRob3I6IEFsbHkgSGF3a2lucwpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KClRoaXMgbm90ZWJvb2sgc3VtbWFyaXplcyB0aGUgY29uc2Vuc3VzIGNlbGwgdHlwZXMgaWRlbnRpZmllZCBpbiBhbGwgb3N0ZW9zYXJjb21hIHNhbXBsZXMgdGhhdCBhcmUgcGFydCBvZiBTY1BDQS4gClRoaXMgaW5jbHVkZXMgYWxsIHNhbXBsZXMgZnJvbSBgU0NQQ1AwMDAwMTdgLCBgU0NQQ1AwMDAwMThgLCBhbmQgYFNDUENQMDAwMDIzYC4gCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBsb29raW5nIGF0IGFueSBkaWZmZXJlbmNlcyBpbiBjZWxsIGNvbXBvc2l0aW9uIGFjcm9zcyBzYW1wbGVzLCB3aXRoIGEgcGFydGljdWxhciBpbnRlcmVzdCBpbiBsb29raW5nIGF0IHRoZSBpbW11bmUgY2VsbCBwb3B1bGF0aW9ucy4gCgpgYGB7ciBwYWNrYWdlc30Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICAjIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMKICBsaWJyYXJ5KGdncGxvdDIpCn0pCgojIFNldCBkZWZhdWx0IGdncGxvdCB0aGVtZQp0aGVtZV9zZXQoCiAgdGhlbWVfY2xhc3NpYygpCikKYGBgCgoKIyMgRnVuY3Rpb25zCgpgYGB7cn0KIyBiYXJjaGFydCB3aXRoIG9yIHdpdGhvdXQgZmFjZXRpbmcKIyBlYWNoIGJhciBpcyBhIHN0YWNrZWQgYmFyY2hhcnQgdXNpbmcgdGhlIGZpbGxfY29sb3IKIyBmYWNldGluZyBpcyBvbmx5IGRvbmUgaWYgYSBmYWNldF92YXJpYWJsZSBpcyBwcm92aWRlZApzdGFja2VkX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKAogICAgZGYsIAogICAgZmlsbF9jb2xvciwgCiAgICBmYWNldF92YXJpYWJsZSA9IE5VTEwsCiAgICBjb2xvcnMKKXsKICAKICBiYXJjaGFydCA8LSBnZ3Bsb3QoZGYpICsgCiAgICBhZXMoCiAgICAgIHggPSBsaWJyYXJ5X2lkLCAKICAgICAgeSA9IHBlcmNlbnRfY2VsbHNfYW5ub3RhdGlvbiwgCiAgICAgIGZpbGwgPSAhIXN5bShmaWxsX2NvbG9yKQogICAgKSArCiAgICBnZW9tX2NvbCgpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBsYWJzKAogICAgICBmaWxsPSAiY2VsbCB0eXBlIgogICAgKQogIAogIGlmKCFpcy5udWxsKGZhY2V0X3ZhcmlhYmxlKSl7CiAgICBiYXJjaGFydCA8LSBiYXJjaGFydCArCiAgICAgIGZhY2V0X3dyYXAodmFycyghIXN5bShmYWNldF92YXJpYWJsZSkpLCBzY2FsZXMgPSJmcmVlIikKICB9CiAgCiAgcmV0dXJuKGJhcmNoYXJ0KQp9CgojIHNpbmEgcGxvdCBsb29raW5nIGF0IGltbXVuZSBwZXJjZW50YWdlIG9uIHRoZSB5LWF4aXMgCnNpbmFfcGxvdCA8LSBmdW5jdGlvbihkZiwgcGxvdF9jb2x1bW4pewogIAogIGdncGxvdChpbW11bmVfcGxvdF9kZiwgYWVzKHggPSAhIXN5bShwbG90X2NvbHVtbiksIHkgPSBwZXJjZW50X2ltbXVuZSkpICsKICAgIGdnZm9yY2U6Omdlb21fc2luYSgpICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueT1tZWRpYW4sIGdlb209ImNyb3NzYmFyIiAsIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDAuMikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSksCiAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwxMCwxMCwxMCkpICsKICAgIGxhYnMoCiAgICAgIHggPSAiIiwgCiAgICAgIHkgPSAiUGVyY2VudCBvZiBjZWxscyBhbm5vdGF0ZWQgYXMgSW1tdW5lIiwKICAgICAgdGl0bGUgPSBwbG90X2NvbHVtbgogICAgKQogIAp9CmBgYAoKCiMjIERhdGEgc2V0dXAKCgpgYGB7ciBiYXNlIHBhdGhzfQojIFRoZSBiYXNlIHBhdGggZm9yIHRoZSBPcGVuU2NQQ0EgcmVwb3NpdG9yeSwgZm91bmQgYnkgaXRzIChoaWRkZW4pIC5naXQgZGlyZWN0b3J5CnJlcG9zaXRvcnlfYmFzZSA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6OmlzX2dpdF9yb290KQptb2R1bGVfYmFzZSA8LSBmaWxlLnBhdGgocmVwb3NpdG9yeV9iYXNlLCAiYW5hbHlzZXMiLCAiY2VsbC10eXBlLWNvbnNlbnN1cyIpCgojIHJlc3VsdHMgZGlyZWN0b3J5IHdpdGggY2VsbC10eXBlLWNvbnNlbnN1cyAKcmVzdWx0c19kaXIgPC0gZmlsZS5wYXRoKG1vZHVsZV9iYXNlLCAicmVzdWx0cyIsICJjZWxsLXR5cGUtY29uc2Vuc3VzIikKCiMgZGF0YSBkaXJlY3Rvcnkgd2hlcmUgcHJvamVjdCBtZXRhZGF0YSBmaWxlcyBsaXZlCmRhdGFfZGlyIDwtIGZpbGUucGF0aChyZXBvc2l0b3J5X2Jhc2UsICJkYXRhIiwgImN1cnJlbnQiKQpgYGAKCmBgYHtyfQojIGxpc3QgYWxsIHJlc3VsdHMgZmlsZXMgCnJlc3VsdHNfZmlsZXMgPC0gbGlzdC5maWxlcyhyZXN1bHRzX2RpciwgcGF0dGVybiA9ICJfY29uc2Vuc3VzLWNlbGwtdHlwZXNcXC50c3YuXFxneiQiLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgZ2V0IHByb2plY3QgaWRzIGZyb20gZmlsZSBsaXN0IGFuZCBhc3NpZ24gYXMgbmFtZXMKcHJvamVjdF9pZHMgPC0gc3RyaW5ncjo6c3RyX3JlbW92ZShiYXNlbmFtZShyZXN1bHRzX2ZpbGVzKSwgIl9jb25zZW5zdXMtY2VsbC10eXBlcy50c3YuZ3oiKQpuYW1lcyhyZXN1bHRzX2ZpbGVzKSA8LSBwcm9qZWN0X2lkcwoKIyBncmFiIG9ubHkgb3N0ZW8gcHJvamVjdHMKb3N0ZW9fcHJvamVjdF9pZHMgPC0gYygiU0NQQ1AwMDAwMTciLCAiU0NQQ1AwMDAwMTgiLCAiU0NQQ1AwMDAwMjMiKQpyZXN1bHRzX2ZpbGVzIDwtIHJlc3VsdHNfZmlsZXNbb3N0ZW9fcHJvamVjdF9pZHNdCgojIGxpc3QgcHJvamVjdCBtZXRhZGF0YSBmaWxlcyBhbmQgZ3JhYiBvbmx5IG9zdGVvIG1ldGFkYXRhIAptZXRhZGF0YV9maWxlcyA8LSBsaXN0LmZpbGVzKGRhdGFfZGlyLCBwYXR0ZXJuID0gInNpbmdsZV9jZWxsX21ldGFkYXRhXFwudHN2JCIsIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFKQptZXRhZGF0YV9pZHMgPC0gc3RyaW5ncjo6d29yZChkaXJuYW1lKG1ldGFkYXRhX2ZpbGVzKSwgLTEsIHNlcCA9ICIvIikKbmFtZXMobWV0YWRhdGFfZmlsZXMpIDwtIG1ldGFkYXRhX2lkcwpvc3Rlb19tZXRhZGF0YV9maWxlcyA8LSBtZXRhZGF0YV9maWxlc1tvc3Rlb19wcm9qZWN0X2lkc10KCiMgbGlzdCBvZiBhbGwgaW1tdW5lIGNlbGwgdHlwZXMgCmNvbnNlbnN1c19pbW11bmVfZmlsZSA8LSBmaWxlLnBhdGgobW9kdWxlX2Jhc2UsICJyZWZlcmVuY2VzIiwgImNvbnNlbnN1cy1pbW11bmUtY2VsbC10eXBlcy50c3YiKQpgYGAKCmBgYHtyfQojIHNvdXJjZSBzdW1tYXJpemVfY2VsbHR5cGVzKCkgZnVuY3Rpb24Kc2V0dXBfZnVuY3Rpb25zIDwtIGZpbGUucGF0aChtb2R1bGVfYmFzZSwgImV4cGxvcmF0b3J5LW5vdGVib29rcyIsICJ1dGlscyIsICJzZXR1cC1mdW5jdGlvbnMuUiIpCnNvdXJjZShzZXR1cF9mdW5jdGlvbnMpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CiMgZ2V0IGltbXVuZSBjZWxsIHR5cGVzIAppbW11bmVfZGYgPC0gcmVhZHI6OnJlYWRfdHN2KGNvbnNlbnN1c19pbW11bmVfZmlsZSkKaW1tdW5lX3R5cGVzIDwtIGltbXVuZV9kZiRjb25zZW5zdXNfYW5ub3RhdGlvbgoKIyByZWFkIGluIG1ldGFkYXRhCmFsbF9tZXRhZGF0YV9kZiA8LSBvc3Rlb19tZXRhZGF0YV9maWxlcyB8PgogIHB1cnJyOjptYXAocmVhZHI6OnJlYWRfdHN2KSB8PgogIGRwbHlyOjpiaW5kX3Jvd3MoKSB8PgogICMgc2VsZWN0IGNvbHVtbnMgdGhhdCBtaWdodCBiZSB1c2VmdWwgCiAgZHBseXI6OnNlbGVjdCgKICAgIHByb2plY3RfaWQgPSBzY3BjYV9wcm9qZWN0X2lkLAogICAgbGlicmFyeV9pZCA9IHNjcGNhX2xpYnJhcnlfaWQsCiAgICBkaXNlYXNlX3RpbWluZywKICAgIGFnZSwKICAgIHNleCwKICAgIHRpc3N1ZV9sb2NhdGlvbiwKICAgIHByaW1hcnlfb3JfbWV0YXN0YXNpcywKICAgIHNlcV91bml0CiAgKQoKIyByZWFkIGluIHJlc3VsdHMgYW5kIHByZXAgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcgCmFsbF9yZXN1bHRzX2RmIDwtIHJlc3VsdHNfZmlsZXMgfD4gCiAgcHVycnI6OmltYXAoc3VtbWFyaXplX2NlbGx0eXBlcykgfD4gCiAgZHBseXI6OmJpbmRfcm93cyguaWQgPSAicHJvamVjdF9pZCIpIHw+IAogICMgam9pbiB3aXRoIHNhbXBsZSBtZXRhZGF0YQogIGRwbHlyOjpsZWZ0X2pvaW4oYWxsX21ldGFkYXRhX2RmLCBieSA9IGMoInByb2plY3RfaWQiLCAibGlicmFyeV9pZCIpKSB8PgogICMgcmVtb3ZlIHBkeCBzYW1wbGVzIAogIGRwbHlyOjpmaWx0ZXIoc2FtcGxlX3R5cGUgIT0gInBhdGllbnQtZGVyaXZlZCB4ZW5vZ3JhZnQiKQpgYGAKCgpgYGB7cn0KIyBhc3NpZ24gYSBjb2xvciBzY2hlbWUgZm9yIGFsbCBiYXIgY2hhcnRzIAoKIyBnZXQgYWxsIHBvc3NpYmxlIGNlbGwgdHlwZXMgCiMgdGhlcmUgYXJlIGV4YWN0bHkgMjUgb2YgdGhlbSBzbyB3aWxsIHVzZSBhbHBoYWJldCB3aXRoIHR3byBncmV5cyBmb3IgdW5rbm93bi9hbGwgcmVtYWluaW5nIAp1bmlxdWVfY2VsbHR5cGVzIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjpmaWx0ZXIocGVyY2VudF9jZWxsc19hbm5vdGF0aW9uID4gMC4xLCAjIHdlJ3JlIG9ubHkgZXZlciBnb2luZyB0byBwbG90IGNlbGwgdHlwZXMgdGhhdCBhcmUgZ3JlYXRlciB0aGFuIDElCiAgICAgICAgICAgICAgICAhY29uc2Vuc3VzX2Fubm90YXRpb24gPT0gIlVua25vd24iKSB8PiAKICBkcGx5cjo6cHVsbChjb25zZW5zdXNfYW5ub3RhdGlvbikgfD4gCiAgdW5pcXVlKCkgfD4KICBhcy5jaGFyYWN0ZXIoKQoKIyBkZWZpbmUgY29sb3JzIGZvciBhbGwgY2VsbCB0eXBlcwphbGxfY2VsbHR5cGVfY29sb3JzIDwtIGMoCiAgcGFsZXR0ZS5jb2xvcnMocGFsZXR0ZSA9ICJhbHBoYWJldCIpWzE6MjVdLAogICJncmV5NjAiLCAjIGFsbCByZW1haW5pbmcKICAiZ3JleTk1IiwgIyB1bmtub3duCiAgImdyZXk2MCIgIyBub24taW1tdW5lLCB1c2UgdGhlIHNhbWUgYXMgYWxsIHJlbWFpbmluZyBzaW5jZSB0aGV5IGFyZSBuZXZlciBpbiB0aGUgc2FtZSBwbG90CikKbmFtZXMoYWxsX2NlbGx0eXBlX2NvbG9ycykgPC0gYyh1bmlxdWVfY2VsbHR5cGVzLCAiQWxsIHJlbWFpbmluZyBjZWxsIHR5cGVzIiwgIlVua25vd24iLCAibm9uLWltbXVuZSIpCgojIGRlZmluZSBhIHRocmVlIGNvbG9yIHNjaGVtZSBmb3IgaW1tdW5lLCBvdGhlciwgYW5kIHVua25vd24KdGhyZWVfY29sb3Jfc2NoZW1lIDwtIGMoCiAgImltbXVuZSIgPSAibmF2eSIsCiAgIm5vbi1pbW11bmUiID0gImdyZXk2MCIsCiAgIlVua25vd24iID0gImdyZXk5NSIKKQpgYGAKCiMjIENvbXBvc2l0aW9uIG9mIHRvcCBjZWxsIHR5cGVzIAoKSGVyZSB3ZSBsb29rIGF0IHRoZSB0b3AgY2VsbCB0eXBlcyBpZGVudGlmaWVkIGFjcm9zcyBhbGwgc2FtcGxlcy4gCldlIGhhdmUgYWxyZWFkeSBsb29rZWQgYXQgdGhpcyBpbiBgMDItZXhwbG9yZS1jb25zZW5zdXMtcmVzdWx0cy5SbWRgLCBidXQgaGVyZSB3ZSB3aWxsIHBsb3QgYWxsIHNhbXBsZXMgZnJvbSBhbGwgdGhyZWUgb3N0ZW8gcHJvamVjdHMgb3JkZXJlZCBieSB0aGUgdG90YWwgcGVyY2VudCBvZiBjZWxscyBsYWJlbGVkIHdpdGggYSBjb25zZW5zdXMgbGFiZWwuIAoKYGBge3J9CiMgYWRkIGNvbHVtbiBvZiAidG9wIGNlbGwgdHlwZXMiIGZvciBlYXNpZXIgcGxvdHRpbmcgCmFsbF9yZXN1bHRzX2RmIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICAjIGdldCBtb3N0IGZyZXF1ZW50bHkgb2JzZXJ2ZWQgY2VsbCB0eXBlcyBhY3Jvc3MgbGlicmFyaWVzIGluIHRoYXQgcHJvamVjdCAKICAgIHRvcF9jZWxsdHlwZXMgPSBmb3JjYXRzOjpmY3RfbHVtcF9uKGNvbnNlbnN1c19hbm5vdGF0aW9uLCAxNSwgb3RoZXJfbGV2ZWwgPSAiQWxsIHJlbWFpbmluZyBjZWxsIHR5cGVzIiwgdGllcy5tZXRob2QgPSAiZmlyc3QiKSB8PiAKICAgICAgIyBzb3J0IGJ5IGZyZXF1ZW5jeSAKICAgICAgZm9yY2F0czo6ZmN0X2luZnJlcSgpIHw+IAogICAgICAjIG1ha2Ugc3VyZSBhbGwgcmVtYWluaW5nIGFuZCB1bmtub3duIGFyZSBsYXN0LCB1c2UgdGhpcyB0byBhc3NpZ24gY29sb3JzIGluIHNwZWNpZmljIG9yZGVyCiAgICAgIGZvcmNhdHM6OmZjdF9yZWxldmVsKCJBbGwgcmVtYWluaW5nIGNlbGwgdHlwZXMiLCAiVW5rbm93biIsIGFmdGVyID0gSW5mKSwKICApCmBgYAoKCmBgYHtyfQojIGdldCBhIHZlY3RvciBvZiBsaWJyYXJ5IGlkcyBvcmRlcmVkIGJ5IHRvdGFsIHBlcmNlbnRhZ2UgYW5ub3RhdGVkCmxpYnJhcnlfbGV2ZWxzIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjpmaWx0ZXIoY29uc2Vuc3VzX2Fubm90YXRpb24gIT0gIlVua25vd24iKSB8PiAKICBkcGx5cjo6Z3JvdXBfYnkobGlicmFyeV9pZCkgfD4gCiAgZHBseXI6OnN1bW1hcml6ZSgKICAgIHRvdGFsX3BlcmNlbnRfYW5ub3RhdGVkID0gc3VtKHRvdGFsX2NlbGxzX3Blcl9hbm5vdGF0aW9uKS90b3RhbF9jZWxsc19wZXJfbGlicmFyeQogICkgfD4KICB1bmlxdWUoKSB8PiAKICBkcGx5cjo6YXJyYW5nZShkZXNjKHRvdGFsX3BlcmNlbnRfYW5ub3RhdGVkKSkgfD4gCiAgZHBseXI6OnB1bGwobGlicmFyeV9pZCkKCiMgYXBwZW5kIGFueSBsaWJyYXJpZXMgdGhhdCBoYXZlIDAgY2VsbHMgYW5ub3RhdGVkCm5vbl9hbm5vdGF0ZWRfbGlicyA8LSBzZXRkaWZmKHVuaXF1ZShhbGxfcmVzdWx0c19kZiRsaWJyYXJ5X2lkKSwgbGlicmFyeV9sZXZlbHMpCmxpYnJhcnlfbGV2ZWxzIDwtIGMobGlicmFyeV9sZXZlbHMsIG5vbl9hbm5vdGF0ZWRfbGlicykKCiMgcmVvcmRlciBieSB0b3RhbCBwZXJjZW50YWdlIGFubm90YXRlZCAKdG90YWxfb3JkZXJfZGYgPC0gYWxsX3Jlc3VsdHNfZGYgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgIGxpYnJhcnlfaWQgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChsaWJyYXJ5X2lkLCBsaWJyYXJ5X2xldmVscykKICApCmBgYAoKCmBgYHtyfQpzdGFja2VkX2JhcmNoYXJ0KHRvdGFsX29yZGVyX2RmLCBmaWxsX2NvbG9yID0gInRvcF9jZWxsdHlwZXMiLCBjb2xvcnMgPSBhbGxfY2VsbHR5cGVfY29sb3JzKQpgYGAKCkl0IGxvb2tzIGxpa2UgdGhlcmUncyBkZWZpbml0ZWx5IHNvbWUgdmFyaWF0aW9uIGJldHdlZW4gZGlzdHJpYnV0aW9ucyBvZiBjZWxsIHR5cGVzIHdpdGhpbiB0aGUgb3N0ZW8gc2FtcGxlcy4gCkdlbmVyYWxseSwgd2Ugc2VlIG1vc3QgYW5ub3RhdGVkIGNlbGxzIGFyZSBzbW9vdGggbXVzY2xlIGNlbGxzIGFuZCBlbmRvdGhlbGlhbCBjZWxscy4gClRoZXJlIGFsc28gYXBwZWFycyB0byBiZSBzb21lIHNhbXBsZXMgdGhhdCBoYXZlIG1hY3JvcGhhZ2VzIGFuZC9vciBUIGNlbGwgcG9wdWxhdGlvbnMuIApXZSBhbHNvIHNlZSBhIGhhbmRmdWwgb2Ygc2FtcGxlcyB0aGF0IGRvbid0IGhhdmUgYW55IGNlbGxzIHRoYXQgYXJlIGFubm90YXRlZC4KCmBgYHtyfQpzdGFja2VkX2JhcmNoYXJ0KHRvdGFsX29yZGVyX2RmLCBmaWxsX2NvbG9yID0gInRvcF9jZWxsdHlwZXMiLCBmYWNldF92YXJpYWJsZSA9ICJwcm9qZWN0X2lkIiwgY29sb3JzID0gYWxsX2NlbGx0eXBlX2NvbG9ycykKYGBgCgpJdCBsb29rcyBsaWtlIGJvdGggdG90YWwgbnVtYmVyIG9mIGNlbGxzIHRoYXQgYXJlIGNsYXNzaWZpZWQgYW5kIGNvbXBvc2l0aW9uIG9mIHRob3NlIGNlbGxzIGlzIHByb2plY3QgZGVwZW5kZW50LiAKVGhpcyBtYWtlcyBzZW5zZSBzaW5jZSBzYW1wbGUgcHJlcCBpcyBwcm9iYWJseSBkaWZmZXJlbnQgYWNyb3NzIGxhYnMuIAoKIyMgSW1tdW5lIGNlbGwgcG9wdWxhdGlvbnMKCkxldCdzIGxvb2sgc3BlY2lmaWNhbGx5IGF0IGltbXVuZSBjZWxsIHBvcHVsYXRpb25zLiAKVG8gZG8gdGhpcyB3ZSB3aWxsIGx1bXAgYWxsIGltbXVuZSBjZWxscyBhcyAiaW1tdW5lIiwgYWxsIG5vbi1pbW11bmUgYXMgIm5vbi1pbW11bmUiLCBhbmQgYWxsIHVua25vd24gYXMgInVua25vd24iLiAKSGVyZSB3ZSB3aWxsIHNvcnQgYnkgdG90YWwgcGVyY2VudGFnZSBvZiBpbW11bmUgY2VsbHMuIAoKYGBge3J9CiMgbG9vayBhdCBpbW11bmUgY2VsbCB0eXBlcyB2cy4gdW5rbm93biB2cy4gb3RoZXIgCmFsbF9yZXN1bHRzX2RmIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogICNkcGx5cjo6bGVmdF9qb2luKGltbXVuZV9kZiwgYnkgPSBjKCJjb25zZW5zdXNfYW5ub3RhdGlvbiIsICJjb25zZW5zdXNfb250b2xvZ3kiKSkgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgICMgZmlyc3QgZ2V0IGEgY29sdW1uIHRoYXQgaXMganVzdCBpbW11bmUsIHVua25vd24sIG9yIG90aGVyCiAgICBpbW11bmVfY2F0ZWdvcnkgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBjb25zZW5zdXNfYW5ub3RhdGlvbiAlaW4lIGltbXVuZV90eXBlcyB+ICJpbW11bmUiLAogICAgICBjb25zZW5zdXNfYW5ub3RhdGlvbiA9PSAiVW5rbm93biIgfiAiVW5rbm93biIsCiAgICAgIC5kZWZhdWx0ID0gIm5vbi1pbW11bmUiCiAgICApCiAgKQpgYGAKCmBgYHtyfQojIG5vdyBzb3J0IGp1c3QgYnkgaW1tdW5lIHBlcmNlbnRhZ2UKaW1tdW5lX3BjdF9kZiA8LSBhbGxfcmVzdWx0c19kZiB8PiAKICBkcGx5cjo6ZmlsdGVyKGltbXVuZV9jYXRlZ29yeSA9PSAiaW1tdW5lIikgfD4gCiAgZHBseXI6Omdyb3VwX2J5KGxpYnJhcnlfaWQpIHw+IAogIGRwbHlyOjpzdW1tYXJpemUoCiAgICBwZXJjZW50X2ltbXVuZSA9IHN1bSh0b3RhbF9jZWxsc19wZXJfYW5ub3RhdGlvbikvdG90YWxfY2VsbHNfcGVyX2xpYnJhcnkKICApIHw+CiAgZHBseXI6OnNlbGVjdChsaWJyYXJ5X2lkLCBwZXJjZW50X2ltbXVuZSkgfD4gCiAgdW5pcXVlKCkgCgpsaWJyYXJ5X2xldmVscyA8LSBpbW11bmVfcGN0X2RmIHw+IAogIGRwbHlyOjphcnJhbmdlKGRlc2MocGVyY2VudF9pbW11bmUpKSB8PiAKICBkcGx5cjo6cHVsbChsaWJyYXJ5X2lkKQoKIyBhcHBlbmQgYW55IGxpYnJhcmllcyB0aGF0IGhhdmUgMCBpbW11bmUgY2VsbHMgYW5ub3RhdGVkCm5vbl9hbm5vdGF0ZWRfbGlicyA8LSBzZXRkaWZmKHVuaXF1ZShhbGxfcmVzdWx0c19kZiRsaWJyYXJ5X2lkKSwgbGlicmFyeV9sZXZlbHMpCmxpYnJhcnlfbGV2ZWxzIDwtIGMobGlicmFyeV9sZXZlbHMsIG5vbl9hbm5vdGF0ZWRfbGlicykKCmltbXVuZV9yZXN1bHRzX2RmIDwtIGFsbF9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjpsZWZ0X2pvaW4oaW1tdW5lX3BjdF9kZiwgYnkgPSBjKCJsaWJyYXJ5X2lkIikpIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBwZXJjZW50X2ltbXVuZSA9IGRwbHlyOjppZl9lbHNlKGlzLm5hKHBlcmNlbnRfaW1tdW5lKSwgMCwgcGVyY2VudF9pbW11bmUpLAogICAgbGlicmFyeV9pZCA9IGZvcmNhdHM6OmZjdF9yZWxldmVsKGxpYnJhcnlfaWQsIGxpYnJhcnlfbGV2ZWxzKQogICkKCnN0YWNrZWRfYmFyY2hhcnQoaW1tdW5lX3Jlc3VsdHNfZGYsIGZpbGxfY29sb3IgPSAiaW1tdW5lX2NhdGVnb3J5IiwgY29sb3JzID0gdGhyZWVfY29sb3Jfc2NoZW1lKQpgYGAKTGV0J3Mgc2VlIGhvdyB0aGUgcGVyY2VudGFnZSBvZiBpbW11bmUgY2VsbHMgY29tcGFyZXMgYWNyb3NzIHByb2plY3RzLiAKCmBgYHtyfQpzdGFja2VkX2JhcmNoYXJ0KGltbXVuZV9yZXN1bHRzX2RmLCBmaWxsX2NvbG9yID0gImltbXVuZV9jYXRlZ29yeSIsIGZhY2V0X3ZhcmlhYmxlID0gInByb2plY3RfaWQiLCBjb2xvcnMgPSB0aHJlZV9jb2xvcl9zY2hlbWUpCmBgYAoKV2hlbiBsb29raW5nIGF0IGFsbCBzYW1wbGVzIHRvZ2V0aGVyIHdlIGRvIHNlZSB2YXJpYXRpb24gaW4gaW1tdW5lIGNlbGxzIGNsYXNzaWZpZWQgYW5kIGl0IGFwcGVhcnMgdGhhdCBgU0NQQ1AwMDAwMTdgIGFuZCBgU0NQQ1AwMDAwMThgIGhhdmUgbW9yZSBjZWxscyBjbGFzc2lmaWVkIGluIGdlbmVyYWwgYW5kIGhhdmUgbW9yZSBjZWxscyBjbGFzc2lmaWVkIGFzIGltbXVuZS4gCkl0IGRvZXMgYXBwZWFyIHRoYXQgbGlicmFyaWVzIHRoYXQgaGF2ZSBtb3JlIGltbXVuZSBjZWxsIGNvbXBvc2l0aW9uIGFsc28gaGF2ZSBhIGhpZ2hlciBwZXJjZW50YWdlIG9mIG5vbi1pbW11bmUgY2VsbCB0eXBlcyB3aGljaCBjb3VsZCB2ZXJ5IHdlbGwgYmUgYSB0ZWNobmljYWwgYXJ0aWZhY3QgYW5kIHJlbGF0ZWQgdG8gc2FtcGxlIHByZXAuIAoKSnVzdCBmb3IgdmlzdWFsaXphdGlvbiBwdXJwb3NlcywgbGV0J3MgY2xhc3NpZnkgdGhlc2UgYXMgImhvdCIgYW5kICJjb2xkIiwgd2hlcmUgImhvdCIgdHVtb3JzIGhhdmUgYW4gaW1tdW5lIGNvbXBvc2l0aW9uID4gNSUuCgpgYGB7cn0KaW1tdW5lX3Jlc3VsdHNfZGYgPC0gaW1tdW5lX3Jlc3VsdHNfZGYgfD4gCiAgZHBseXI6Om11dGF0ZSgKICAgICMgY2xhc3NpZnkgaG90L2NvbGQgYmFzZWQgb24gaW1tdW5lIHBlcmNlbnQgPiA1ICUKICAgIGhvdF9jb2xkID0gZHBseXI6OmlmX2Vsc2UocGVyY2VudF9pbW11bmUgPiAuMDUsICJob3QiLCAiY29sZCIpCiAgKQpgYGAKCmBgYHtyfQpzdGFja2VkX2JhcmNoYXJ0KGltbXVuZV9yZXN1bHRzX2RmLCBmaWxsX2NvbG9yID0gImltbXVuZV9jYXRlZ29yeSIsIGZhY2V0X3ZhcmlhYmxlID0gImhvdF9jb2xkIiwgY29sb3JzID0gdGhyZWVfY29sb3Jfc2NoZW1lKQpgYGAKCk91ciB0aHJlc2hvbGQgaXMgcHJldHR5IGFyYml0cmFyeSwgYnV0IEkgdGhpbmsgdGhlcmUgYXJlIGRlZmluaXRlbHkgc29tZSAiY29sZCIgdHVtb3JzIHdoZXJlIHdlIHNlZSBsaXR0bGUgdG8gbm8gaW1tdW5lIGludm9sdmVtZW50LiAKCkJlbG93IHdlIGNhbiBsb29rIGF0IGFsbCBpbW11bmUgY2VsbCB0eXBlcyB2cy4gYWxsIG5vbi1pbW11bmUuIAoKYGBge3J9CmltbXVuZV9yZXN1bHRzX2RmIDwtIGltbXVuZV9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBpc19pbW11bmUgPSBkcGx5cjo6aWZfZWxzZSgKICAgICAgaW1tdW5lX2NhdGVnb3J5ID09ICJpbW11bmUiIHwgdG9wX2NlbGx0eXBlcyA9PSAiVW5rbm93biIsCiAgICAgIGNvbnNlbnN1c19hbm5vdGF0aW9uLAogICAgICAibm9uLWltbXVuZSIKICAgICkKICApCgpzdGFja2VkX2JhcmNoYXJ0KGltbXVuZV9yZXN1bHRzX2RmLCBmaWxsX2NvbG9yID0gImlzX2ltbXVuZSIsIGNvbG9ycyA9IGFsbF9jZWxsdHlwZV9jb2xvcnMpCmBgYAoKR2VuZXJhbGx5LCBpZiBpbW11bmUgY2VsbHMgYXJlIHByZXNlbnQgdGhleSB0ZW5kIHRvIGJlIG1hY3JvcGhhZ2VzLiAKVGhlcmUncyBhbHNvIGEgbG90IG9mIFQgY2VsbCBwb3B1bGF0aW9ucywgd2hpY2ggbWFrZXMgc2Vuc2Ugc2luY2UgaXQgaGFzIGJlZW4gcHJldmlvdXNseSBub3RlZCB0aGF0IG9zdGVvc2FyY29tYSBoYXMgYSBoaWdoIHBlcmNlbnRhZ2Ugb2YgVCBjZWxsIGluZmlsdHJhdGUgKGh0dHBzOi8vZG9pLm9yZy8xMC4xODYzMi9vbmNvdGFyZ2V0LjE5MDcxKS4gIAoKIyMgSXMgdGhlcmUgYW55IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGltbXVuZSBjZWxsIHBlcmNlbnRhZ2UgYW5kIGNsaW5pY2FsIG1ldGFkYXRhPyAKCk9uZSB0aGluZyBJIHdhcyBjdXJpb3VzIGFib3V0IHdhcyB3aGV0aGVyIG9yIG5vdCB0aGVyZSBhcmUgYW55IGRpZmZlcmVuY2VzIGluIHRoZSBwcmVzZW5jZSBvZiBpbW11bmUgY2VsbHMgYmFzZWQgb24gY2xpbmljYWwgbWV0YWRhdGEgc3VjaCBhcyBwcmltYXJ5IHZzLiBtZXRhc3Rhc2lzLCBpbml0aWFsIGRpYWdub3NpcyB2cy4gcmVjdXJyZW5jZSwgYW5kIHRpc3N1ZSBsb2NhdGlvbiAoYm9uZSB2cy4gc29mdCB0aXNzdWUpLiAKSSBhbHNvIGV4cGVjdCB0aGVyZSBtaWdodCBiZSBzb21lIGRpZmZlcmVuY2VzIGJldHdlZW4gc2luZ2xlLWNlbGwgYW5kIHNpbmdsZS1udWNsZWkgc2FtcGxlcy4gCgpCZWxvdyBJIGxvb2sgYXQgdGhlIGltbXVuZSBjZWxsIHBlcmNlbnRhZ2Ugc3RyYXRpZmllZCBieSBlYWNoIG9mIHRoZSBtZW50aW9uZWQgbWV0YWRhdGEuIApUaGlzIGlzIGp1c3QgYSBwcmVsaW1pbmFyeSBsb29rIGFuZCBpZiB3ZSByZWFsbHkgd2FudCB0byBkaWcgaW50byB0aGlzIGZ1cnRoZXIgd2Ugc2hvdWxkIGNvbnNpZGVyIGxvb2tpbmcgYXQgYWxnb3JpdGhtcyBmb3IgY29tcGFyaW5nIGNlbGwgdHlwZSBjb21wb3NpdGlvbiBpbiBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEsIGJ1dCB0aGF0IGlzIG91dHNpZGUgdGhlIHNjb3BlIG9mIHRoaXMgbm90ZWJvb2suIAoKYGBge3J9CiMgZG8gc29tZSBkYXRhIHdyYW5nbGluZyBvbiB0aGUgbWV0YWRhdGEgY29sdW1ucyB3ZSB3YW50IHRvIGxvb2sgYXQgCmltbXVuZV9yZXN1bHRzX2RmIDwtIGltbXVuZV9yZXN1bHRzX2RmIHw+IAogIGRwbHlyOjptdXRhdGUoCiAgICBwcmltYXJ5X29yX21ldGFzdGFzaXMgPSBkcGx5cjo6aWZfZWxzZSghaXMubmEocHJpbWFyeV9vcl9tZXRhc3Rhc2lzKSwgcHJpbWFyeV9vcl9tZXRhc3Rhc2lzLCBkaXNlYXNlX3RpbWluZyksCiAgICBkaXNlYXNlX3RpbWluZ19tb2QgPSBkcGx5cjo6aWZfZWxzZShkaXNlYXNlX3RpbWluZyAlaW4lIGMoIkluaXRpYWwgZGlhZ25vc2lzIiwgIlJlY3VycmVuY2UiKSwgZGlzZWFzZV90aW1pbmcsICJvdGhlciIpLAogICAgdGlzc3VlX2xvY2F0aW9uX21vZCA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QodGlzc3VlX2xvY2F0aW9uLCAiQm9uZXxmZW11cnxIdW1lcnVzfFRpYmlhIikgfiAiQm9uZSIsCiAgICAgICNzdHJpbmdyOjpzdHJfZGV0ZWN0KHRpc3N1ZV9sb2NhdGlvbiwgImZlbXVyIikgfiAiQm9uZSIsCiAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QodGlzc3VlX2xvY2F0aW9uLCAibHVuZ3xMdW5nfENoZXN0IikgfiAibHVuZyBvciBjaGVzdCIsCiAgICAgIC5kZWZhdWx0ID0gIm90aGVyIgogICAgKQogICkKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMH0KIyBnZXQgYSBsaXN0IG9mIG1ldGFkYXRhIHdlIGNhcmUgYWJvdXQgCm1ldGFkYXRhX2NhdGVnb3JpZXMgPC0gYygKICAicHJpbWFyeV9vcl9tZXRhc3Rhc2lzIiwKICAiZGlzZWFzZV90aW1pbmdfbW9kIiwKICAidGlzc3VlX2xvY2F0aW9uX21vZCIsCiAgInNlcV91bml0IgopCgojIG1ha2Ugc3RhY2tlZCBiYXIgcGxvdHMgbG9va2luZyBhdCBvbmx5IGltbXVuZSBhbmQgbm9uIGltbXVuZSAKbWV0YWRhdGFfY2F0ZWdvcmllcyB8PiAKICBwdXJycjo6bWFwKFwoY2F0ZWdvcnkpewogICAgCiAgICBzdGFja2VkX2JhcmNoYXJ0KAogICAgICBpbW11bmVfcmVzdWx0c19kZiwKICAgICAgZmlsbF9jb2xvciA9ICJpbW11bmVfY2F0ZWdvcnkiLAogICAgICBmYWNldF92YXJpYWJsZSA9IGNhdGVnb3J5LAogICAgICBjb2xvcnMgPSB0aHJlZV9jb2xvcl9zY2hlbWUKICAgICkKfSkgfD4KICBwYXRjaHdvcms6OndyYXBfcGxvdHMobmNvbCA9IDEsIGd1aWRlcyA9ICJjb2xsZWN0IikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMH0KIyBub3cgbG9vayBhdCBhbGwgdG9wIGNlbGx0eXBlcyAKbWV0YWRhdGFfY2F0ZWdvcmllcyB8PiAKICBwdXJycjo6bWFwKFwoY2F0ZWdvcnkpewogICAgCiAgICBzdGFja2VkX2JhcmNoYXJ0KAogICAgICBpbW11bmVfcmVzdWx0c19kZiwKICAgICAgZmlsbF9jb2xvciA9ICJ0b3BfY2VsbHR5cGVzIiwKICAgICAgZmFjZXRfdmFyaWFibGUgPSBjYXRlZ29yeSwKICAgICAgY29sb3JzID0gYWxsX2NlbGx0eXBlX2NvbG9ycwogICAgKQp9KSB8PgogIHBhdGNod29yazo6d3JhcF9wbG90cyhuY29sID0gMSwgZ3VpZGVzID0gImNvbGxlY3QiKQpgYGAKCkJlbG93IGFyZSBzaW5hIHBsb3RzIHRoYXQgY29tcGFyZSB0aGUgdG90YWwgaW1tdW5lIHBlcmNlbnRhZ2UgZm9yIGFsbCBzYW1wbGVzIGluIGEgZ2l2ZW4gY2F0ZWdvcnkuIAoKYGBge3J9CmltbXVuZV9wbG90X2RmIDwtIGltbXVuZV9yZXN1bHRzX2RmIHw+IAogICMganVzdCBsb29rIGF0IGltbXVuZSBwb3B1bGF0aW9uIGFjcm9zcyBkaWZmZXJlbnQgZGlhZ25vc2VzIAogIGRwbHlyOjpzZWxlY3QobGlicmFyeV9pZCwgcHJpbWFyeV9vcl9tZXRhc3Rhc2lzLCBkaXNlYXNlX3RpbWluZ19tb2QsIHRpc3N1ZV9sb2NhdGlvbl9tb2QsIHBlcmNlbnRfaW1tdW5lLCBzZXFfdW5pdCkgfD4gCiAgdW5pcXVlKCkKYGBgCgpgYGB7cn0KbWV0YWRhdGFfY2F0ZWdvcmllcyB8PiAKICBwdXJycjo6bWFwKFwoY2F0ZWdvcnkpewogICAgc2luYV9wbG90KGltbXVuZV9wbG90X2RmLCBjYXRlZ29yeSkKICB9KQpgYGAKCkl0IGxvb2tzIGxpa2UgdGhlcmUgbWlnaHQgYmUgaGlnaGVyIGltbXVuZSBpbmZpbHRyYXRlIGluICJib25lIiBzYW1wbGVzLCBidXQgYWdhaW4gSSB0aGluayBpZiB3ZSB3YW50IHRvIG1ha2UgYW55IGNvbmNsdXNpb25zIHdlIG5lZWQgdG8gbG9vayBhdCBzb2Z0d2FyZSB0aGF0IGhlbHBzIGNvcnJlY3QgZm9yIHRlY2huaWNhbCBhcnRpZmFjdHMuIApUaGVyZSBtYXkgYWxzbyBiZSBhIGRpZmZlcmVuY2UgaW4gc2luZ2xlLWNlbGwgYW5kIHNpbmdsZS1udWNsZWksIGJ1dCB0aGVyZSBhcmUgbXVjaCBmZXdlciBzaW5nbGUtY2VsbCBzYW1wbGVzIHNvIGl0J3MgaGFyZCB0byBzYXkuIAoKCiMjIFNlc3Npb24gaW5mbyAKCmBgYHtyIHNlc3Npb24gaW5mb30KIyByZWNvcmQgdGhlIHZlcnNpb25zIG9mIHRoZSBwYWNrYWdlcyB1c2VkIGluIHRoaXMgYW5hbHlzaXMgYW5kIG90aGVyIGVudmlyb25tZW50IGluZm9ybWF0aW9uCnNlc3Npb25JbmZvKCkKYGBgCg==