DOI

1 Introduction

The R markdown documents in this directory are intended to provide a complete accounting of the analyses performed in the preparation of

“Innate biosignature of treatment failure in patients with cutaneous leishmaniasis.”

I assume that if anyone ever reads this, s/he is looking for the source of the data, figures, and tables from that paper and to see if the methods employed to generate them are good, bad, indifferent, or garbage. These documents are being generated by a singularity container which provides the input count tables (Once we have accessions, I will make a companion which is able to create them), sample sheets, input documents, and all the software used to process them. The overal configuration of the container is contained in the toplevel .yml file and provides the base OS (Debian stable) and the scripts used to install the software. ‘local/bin/setup_debian.sh’ handles the base container; ‘local/bin/setup_hpgltools.sh’ sets up R, bioconductor, and my package ‘hpgltools’, and ‘local/bin/runscript’ is the script run if one invokes the container without any arguments; when run it uses the various installed R packages to ‘render’ the Rmd files in /data to freshly created html. This README is the first document rendered.

2 Figure/Table locations

As of 20240919, Maria Adelaida kindly sent me the putatively final set of figures/tables. I am going to lay out the location in the html logs and their Rmd parents where these may be found. If you wish to play along, make sure you run the entire 01datastructures.Rmd.

Also, this container is automatically regenerated and rerun when I make changes; so one may just go here to play along (that is where I am going to hunt down the figures/tables):

https://containerbook.umiacs.io/

2.1 Figure 1

These numbers are coming from 01datastructures: when considering the samples from the perspective of how many people fall into each category, that is coming directly from section 4.1 “Metadata Sources” and the demographics xlsx file. This provides the number of people who fall into each category of panel A/B.

2.2 Figure 2

2.2.1 Panel A

TODO: Clarify v1/v2/v3 vs. Pre-Tx, Mid-Tx, End-Tx in the notebook

This is also derived from 01datastructures, but from the perspective of the numbers of samples which survive our various filters. Thus, to arrive at these numbers, one should start at section 6.1 “Create Expressionset.” and wander through the document; however doing so will likely make most people sad because it is a long journey. Instead, you may skip down to section 14 “Summarize: Tabulate sample numbers”. The section labeled ‘Both’ provides these numbers. Note, this table used to be just Tumaco, which follows.

The numbers of samples in each group are restated in the summaries. The only real caveat is that I wrote them as ‘visit1’ or ‘v1’ for Pre-Tx, ‘visit2’ for Mid-Tx, and ‘visit3’ for End-Tx.

Another way to recapitulate these numbers is to check out the sankey plots in section 8 ‘Visualize the sample breakdown’. An example invocation looks like:

clinic_type_outcome_sankey <- plot_meta_sankey(
  tc_valid, factors = c("clinic", "typeofcells", "finaloutcome"),
  drill_down = TRUE, color_choices = color_choices)
clinic_type_outcome_sankey

clinic_ethnicity_outcome_sankey <- plot_meta_sankey(
  tc_valid, factors = c("clinic", "etnia", "finaloutcome"),
  drill_down = TRUE, color_choices = color_choices)
clinic_ethnicity_outcome_sankey

clinic_sex_outcome_sankey <- plot_meta_sankey(
  tc_valid, factors = c("clinic", "sex", "finaloutcome"),
  drill_down = TRUE, color_choices = color_choices)
clinic_sex_outcome_sankey

2.2.2 Panel B

Found in 02visualization, section 8 “Global views of all cell types” Hey, check it, different types of immune cells are different!

One invocation looks like this (there are a few versions):

tc_pca <- plot_pca(tc_norm, plot_labels = FALSE,
                    plot_title = "PCA - Cell type", size_column = "visitnumber")
tc_pca

2.2.3 Panel C

Ibid. Both panels are actually a little further down in section 8.1.

Here is the invocation:

tc_cf_corheat <- plot_corheat(tc_cf_norm, plot_title = "Heirarchical clustering:
         cell types")
tc_cf_corheat

2.3 Figure 3

Maria Adelaida did a tremendous amount of work to move the various ggplot legends around so that this fits in a single panel in a coherent fashion.

2.3.1 Panel A

Section 9.8 of 02visualization: “PCA: Compare clinics”

tc_clinic_type_nb_pca <- plot_pca(tc_clinic_type_nb)
tc_clinic_type_nb_pca

2.3.2 Panel B

Section 9.5 of 02visualization: “Eosinophils by clinic”

tc_eosinophils_pca <- plot_pca(tc_eosinophils_norm, plot_labels = FALSE)
tc_eosinophils_pca

2.3.3 Panel C

Section 9.6 of 02visualization: “Monocytes by clnic”

tc_monocytes_pca <- plot_pca(tc_monocytes_norm, plot_labels = FALSE)
tc_monocytes_pca

2.3.4 Panel D

Section 9.7 of 02visualization: “Neutrophils by clnic”

tc_neutrophils_pca <- plot_pca(tc_neutrophils_norm, plot_labels = FALSE)
tc_neutrophils_pca

2.3.5 Panel E

Section 9.1 of 02visualization: “Biopsies”

tc_biopsies_pca <- plot_pca(tc_biopsies_norm)
tc_biopsies_pca

2.4 Figure 4

2.4.1 Panel A, left

Section 10.2.4 “Figure 4A: Monocytes”

t_monocyte_pca <- plot_pca(t_monocyte_norm,
  plot_labels = FALSE)
t_monocyte_pca

2.4.2 Panel A, middle

Section 10.2.8 “Figure 4A: Eosinophils”

t_eosinophil_pca <- plot_pca(t_eosinophil_norm,
                             plot_labels = FALSE)
t_eosinophil_pca

2.4.3 Panel A, right

Section 10.2.6 “Figure 4A: Neutrophils”

t_neutrophil_pca <- plot_pca(t_neutrophil_norm,
                             plot_labels = FALSE)
t_neutrophil_pca

2.5 Panel B

These move to the document 04differential_expression_tumaco.

2.5.1 Panel B, left, middle, and right

Section 7.0.4 “Figure 4B: Volcano plots” For some reason I did not have separate sections for each cell type.

num_color <- color_choices[["clinic_cf"]][["tumaco_failure"]]
den_color <- color_choices[["clinic_cf"]][["tumaco_cure"]]
wanted_genes <- c("FI44L", "IFI27", "PRR5", "PRR5-ARHGAP8", "RHCE",
                  "FBXO39", "RSAD2", "SMTNL1", "USP18", "AFAP1")

cf_monocyte_table <- t_cf_monocyte_table_sva[["data"]][["outcome"]]
cf_monocyte_volcano <- plot_volcano_condition_de(
  cf_monocyte_table, "outcome", label = wanted_genes,
  fc_col = "deseq_logfc", p_col = "deseq_adjp", line_position = NULL,
  color_high = num_color, color_low = den_color, label_size = 6)
pp(file = glue("images/cf_monocyte_volcano_labeled-v{ver}.svg"))
cf_monocyte_volcano[["plot"]]
dev.off()

2.5.2 Panel C

TODO: Add similar venn ~ section 8

I played with versions of this using AUCC and UpSet plots throughout the 04differential_expression_tumaco document; but did not generate this specific image. (Maybe I should make a version of it?)

2.6 Figure 5

TODO: Clarify section names

I did not perform any of the STRING analyses and therefore am unable to comment on panels A,C,E,G. I should bug Alejandro.

The lower panels are all coming from 05enrichment and are using the treeplot() result from gotermsim() of the gProfiler2 results.

2.6.1 Panel B

05enrichment, section 2.10.1 “gProfiler” (I am going to change these headings to be a bit more informative…)

t_cf_eosinophil_sig_sva_up_gp <- simple_gprofiler(
  t_cf_eosinophil_sig_sva_up,
  excel = glue("{xlsx_prefix}/Gene_Set_Enrichment/t_cf_eosinophil_up_gp-v{ver}.xlsx"))
t_cf_eosinophil_sig_sva_up_gp

2.6.2 Panel D

05enrichment, Section 2.12.1 “gProfiler”.

t_cf_neutrophil_sig_sva_up_gp <- simple_gprofiler(
  t_cf_neutrophil_sig_sva_up,
  excel = glue("{xlsx_prefix}/Gene_Set_Enrichment/t_cf_neutrophil_up_gp-v{ver}.xlsx"))
t_cf_neutrophil_sig_sva_up_gp

2.6.3 Panel F

Ibid, Section 2.11.1 “gProfiler”

t_cf_monocyte_sig_sva_up_gp <- simple_gprofiler(
  t_cf_monocyte_sig_sva_up,
  excel = glue("{xlsx_prefix}/Gene_Set_Enrichment/t_cf_monocyte_up_gp-v{ver}.xlsx"))
t_cf_monocyte_sig_sva_up_gp

2.6.4 Panel H

Ibid, Section 2.4.1 “gProfiler” but it is pretty far down; just before the clusterProfiler analyses.

t_cf_clinicalnb_gp_down <- simple_gprofiler(
  t_clinicalnb_cf_sig_sva_down,
  excel = glue("{xlsx_prefix}/Gene_Set_Overrepresentation/clinicalnb_fail_up_gp-v{ver}.xlsx"))
t_cf_clinicalnb_gp_down

## and

go_termsim <- enrichplot::pairwise_termsim(t_cf_clinicalnb_gp_down[["BP_enrich"]])
t_cf_clinicalnb_gp_go_down_tree <- sm(enrichplot::treeplot(go_termsim))
pp(file = "images/overrepresentation/t_cf_clinicalnb_gp_down_tree.pdf",
   width = treeplot_width, height = treeplot_height)
t_cf_clinicalnb_gp_go_down_tree
dev.off()

2.7 Figure S1

TODO: Clarify sections

Head back to 02visualization; this is where Theresa taught me regression analysis!

2.7.1 Panel A

02visualization, Near the bottom of section 7.2 “Regression analyses vs outcome” (I need to rename these sections too, these are cross correlations, not regression; I used to have them all together in a big pile and split them up, but didn’t properly rename the headings.)

t_regression_queries <- c("Weight", "Sex", "Ethnicity", "Age")
t_cross_df <- t_regression_numeric[, t_regression_queries]
t_regression_cross <- corr_cross(t_cross_df)
pp(file = "figures/tumaco_weight_sex_ethnicity_age_numeric_crosscor.svg")
t_regression_cross
dev.off()

2.7.2 Panel B

02visualization, 7.2.1 “Copy these with only the Tumaco people”

regression_tests <- c("Age", "Clinic", "Ethnicity", "Sex", "Weight")
lm_regression_demographics <- extract_linear_regression(
  regression_numeric, query = "Therapeutic_Outcome_Final", factors = regression_tests,
  excel = glue("excel/numeric_demographics_regression_final_sex_clinic_ethnicity_age-v{ver}.xlsx"))

## and

pp(file = "images/demographics_only_linear_regression.svg")
lm_regression_demographics[["forest"]]
dev.off()

2.7.3 Panel C

Ibid, Section 7.2.2

tc_log_iterative_regression_demographics <- iterate_logistic_regression(
  regression_df, query = "Therapeutic_Outcome_Final", factors = regression_tests,
  excel = glue("excel/tc_simple_logistic_regression-v{ver}.xlsx"))

## and

pp(file = glue("figures/tc_simple_logistic_regression-v{ver}.svg"))
tc_log_iterative_regression_demographics[["forest"]]
dev.off()

2.7.4 Panel D

Ibid.

t_log_regression_demographics <- extract_logistic_regression(
  t_regression_df, query = "Therapeutic_Outcome_Final", factors = t_regression_tests,
  excel = glue("excel/t_multivariable_logistic_regression-v{ver}.xlsx"))

## and

pp(file = glue("figures/t_multivariable_logistic_regression-v{ver}.svg"))
t_log_regression_demographics[["forest"]]
dev.off()

2.7.5 Panels E and F

TODO: readd

Hmm I deleted these from my notebook, I did not think we were going to use them but instead only include C/D. Adding them back momentarily.

2.8 Figure S2

2.8.1 Panel B/C

These are waay down in Section 16 “Parasite distribution” of 02visualization.

lp_cf_norm_pca <- plot_pca(lp_cf_norm)

2.9 Figure S4

TODO: rename section

One must return to 01datastructures for this image. It was used to define the coverage cutoff for filtering samples and is found at section 7.2 “Figure S2: Non-zero genes before sample filtering” (I guess I should rename this too)

all_nz <- plot_nonzero(hs_expt)

2.10 Figure S5

These are all scattered through 02visualization.

2.10.1 Panel A

Section 9.8 “Compare clinics”

tc_clinic_type_pca <- plot_pca(tc_clinic_type_norm)
tc_clinic_type_pca

2.10.2 Panel B

Section 9.5 “Eosinophils by clinic” No fails from Cali for Eosinophils!

tc_eosinophils_pca <- plot_pca(tc_eosinophils_norm, plot_labels = FALSE)
tc_eosinophils_pca

2.10.3 Panel C

Section 9.6 “Monocytes by clinic”

tc_monocytes_pca <- plot_pca(tc_monocytes_norm, plot_labels = FALSE)
tc_monocytes_pca

2.10.4 Panel D

Section 9.7 “Neutrophils by clinic”

tc_neutrophils_pca <- plot_pca(tc_neutrophils_norm, plot_labels = FALSE)
tc_neutrophils_pca

2.10.5 Panel E

Section 9.1 “Biopsies by clinic”

tc_biopsies_pca <- plot_pca(tc_biopsies_norm)
tc_biopsies_pca

2.10.6 Panel F

At the bottom of section 9.2.3 “Eosinophil samples, both clinics”

plot_pca(etnia_eo_nb)

2.10.7 Panel G

At the bottom of section 9.2.4 “Monocyte samples, both clinics”

plot_pca(etnia_mo_nb)

2.10.8 Panel H

At the bottom of section 9.2.5 “Neutrophil samples, both clinics”

plot_pca(etnia_ne_nb)

2.11 Figure S6

TODO: Someone asked me to changes these colors to this vicious set of greens. The original black/grey/white is nicer.

2.11.1 Panel A/B/C

These images are scattered through section 11.4.1 “Comparing 3 visits by cell type” (I changed the colors back just now 20240919, those greens are a horror show, where was April to yell at me!?)

t_visit_monocyte_norm_pca <- plot_pca(t_visit_monocyte_norm, plot_labels = FALSE)
pp(file = "images/t_monocyte_visit_norm_pca.pdf")
t_visit_monocyte_norm_pca$plot
dev.off()

## replace monocyte with the relevant celltypes for the others.

2.11.2 Panel D

These bottom panels are comparing my simplified model to a more thorough visit-in-model analysis. This first, monocyte comparison is in section 6.0.2 of 04differential_expression_tumaco.

Note, hpgltools is now able to handle arbitrarily complex models across all methods (deseq/edger/etc…) though I didn’t finish it until a few days ago and it has not yet been fully tested.

## The original pairwise invocation with sva:
##t_cf_monocyte_de_sva <- all_pairwise(t_monocyte, model_batch = "svaseq",
##                                     filter = TRUE, parallel = FALSE,
##                                     methods = methods)
test_monocytes <- normalize_expt(t_monocytes, filter = "simple")

This continues for a few blocks of relatively dense code invoking sva with a model containing visit number.

2.11.3 Panel E

Ibid, section 7.0.3

This section is nearly identically dense, and starts with the following:

## The original pairwise invocation with sva:
#t_cf_eosinophil_de_sva <- all_pairwise(t_eosinophils, model_batch = "svaseq",
#                                       filter = TRUE, parallel=FALSE, methods = methods)
test_eosinophils <- normalize_expt(t_eosinophils, filter = "simple")

2.11.4 Panel F

Ibid, section 7.0.2

TODO: This portion of the 04differential_expression_tumaco is poorly organized.

## The original pairwise invocation with sva:
## t_cf_neutrophil_de_sva <- all_pairwise(t_neutrophils, model_batch = "svaseq",
##                                        parallel = parallel, filter = TRUE,
##                                        methods = methods)
test_neutrophils <- normalize_expt(t_neutrophils, filter = "simple")

2.12 Figure S7

This images harken back to 02visualization

2.12.1 Panel A

Section 10.2.1 of 02visualization

t_clinical_nobiop_pca <- plot_pca(t_clinical_nobiop_norm, plot_labels = FALSE)
pp(file = "figures/t_clinical_nobiop_figxxa.pdf")
t_clinical_nobiop_pca[["plot"]]
dev.off()

2.12.2 Panel B

The next image in 10.2

TODO: Check that the device is properly creating pdfs in this section; it looks like it might be creating pngs for some of these?

t_clinical_nobiop_nb_pca <- plot_pca(t_clinical_nobiop_nb, plot_labels = FALSE)
pp(file = "figures/t_clinical_nobiop_sva_figxxb.pdf")
t_clinical_nobiop_nb_pca[["plot"]]
dev.off()

2.13 Figure S8, S9, S10

These are not in my notebooks.

2.14 Figure S11

2.14.1 Panel A

Section 10.2.1

tc_clinical_nobiop_pca <- plot_pca(tc_clinical_nobiop_norm, plot_labels = FALSE)
pp(file = "figures/tc_clinical_nobiop_figxxc.pdf")
tc_clinical_nobiop_pca[["plot"]]

2.14.2 Panel B

and the immediately following image

tc_clinical_nobiop_nb_pca <- plot_pca(tc_clinical_nobiop_nb, plot_labels = FALSE)
pp(file = "figures/tc_clinical_nobiop_sva_figxxd.pdf")
tc_clinical_nobiop_nb_pca[["plot"]]
dev.off()

2.14.3 Panel C

I think this is the only image taken from 03differential_expression_both; it comes from section 5.2.1; in my last iteration of the notebook it failed because I forgot to tell it to use the color_choices (fixed)

tc_clinical_cf_de_batch <- all_pairwise(tc_clinical_nobiop, filter = TRUE,
                                        parallel = parallel, model_batch = TRUE,
                                        methods = methods)

2.15 Table S1

This was manually collated by Maria Adelaida; I think all the numbers do correspond to the regression f-values/p-values.

2.16 Table S2

This is a very slightly modified copy of the sample sheet in sample_sheets/tmrc3_samples_pruned.xlsx One noteworthy thing: if one reprocesses the raw data and runs ‘gather_preprocessing_metadata()’, it will suck up all the logs from any tools for which I have written regexes and append the results as columns at the right of this. I am more than a little proud of that.

2.17 Table S3

This is a slightly modified copy of the result of the ‘svpc_fstats()’ invocations found at the end of Section 17 in 02visualization. (my little function adds a funky heatmap to the output)

queries <- c("typeofcells", "visitnumber", "clinic", "donor")
tc_clinical_fpstats <- svpc_fstats(tc_clinical, num_pcs = 5, queries = queries)

2.18 Table S4

This is a slightly modified copy of two results:

2.18.1 Biopsies DE

This is a modified version of the result when one invokes combine_de_tables(), as per section 6.0.2 of 04differential_expression_tumaco; this container should therefore provide those numbers if one looks in ‘analyses/4_tumaco/DE_Cure_Fail/Biopsies/t_biopsy_cf_table_sva-v202409.xlsx’ That xlsx workbook has a worksheet named ‘outcome’ (the second); this worksheet comprises columns Q-V from it. (also yay! the numbers are the same between my container (which changes constantly and gets rebuilt with each change) and the copy that was used for the paper!)

t_cf_biopsy_table_sva <- combine_de_tables(
  t_cf_biopsy_de_sva, keepers = t_cf_contrast,
  excel = glue("{cf_prefix}/Biopsies/t_biopsy_cf_table_sva-v{ver}.xlsx"))
t_cf_biopsy_table_sva

2.18.2 Bipsies GO

Looking more carefully at this, I think this is not from my overrepresentation analysis; but came from STRING?

The invocation for my version of this resides in 05enrichment, section 2.9.1 and the xlsx file in the container should be found in ‘analyses/Gene_Set_Enrichment/t_cf_biopsy_sig_sva_up_gp-v202409.xlsx’ for gProfiler, and with a similar name containing ‘cp’ for clusterProfiler.

t_cf_biopsy_sig_sva_gp_up <- simple_gprofiler(
  t_cf_biopsy_sig_sva_up,
  excel = glue("{xlsx_prefix}/Gene_Set_Enrichment/t_cf_biopsy_sig_sva_up_gp-v{ver}.xlsx"))
t_cf_biopsy_sig_sva_gp_up

## or perhaps if you prefer clusterProfiler

t_cf_biopsy_sig_sva_cp_up <- simple_cprofiler(
  t_cf_biopsy_sig_sva_up, de_table = t_cf_biopsy_table_sva,
  orgdb = "org.Hs.eg.db",
  excel = glue("{xlsx_prefix}/Gene_Set_Enrichment/t_cf_biopsy_sig_sva_up_cp-v{ver}.xlsx"))

2.19 Table S5

This is a redacted combination of a few files:

2.19.1 worksheet Monocytes

Section 6.0.2 provides the invocation of combine_de_tables() which produces the ‘analysis/4_Tumaco/DE_Cure_Fail/Monocytes/t_monocyte_cf_table-sva-v202409.xlsx’ that comprises the logFC etc values in this worksheet. Interestingly, the top 5 genes all shifted down in logFC by ~ 0.002 in my container-derived worksheet vs this table. I think that is an acceptable difference? I did spot check a few genes in the top 5000 and it looks like the order is maintained.

t_cf_monocyte_table_sva <- combine_de_tables(
  t_cf_monocyte_de_sva, keepers = t_cf_contrast,
  excel = glue("{cf_prefix}/Monocytes/t_monocyte_cf_table_sva-v{ver}.xlsx"))
t_cf_monocyte_table_sva

2.19.2 worksheet Neutrophils

Same logic, but Section 7.0.2 with the analagously named xlsx file in the Neutrophils directory; these numbers also appear to have shifted slightly (but this time by ~ 0.001 up to 0.1 logFC) and I do see a couple of genes out of order… I am going to check in with Maria Adelaida.

t_cf_neutrophil_table_sva <- combine_de_tables(
  t_cf_neutrophil_de_sva, keepers = t_cf_contrast,
  excel = glue("{cf_prefix}/Neutrophils/t_neutrophil_cf_table_sva-v{ver}.xlsx"))
t_cf_neutrophil_table_sva

2.19.3 worksheet Eosinophils

Ibid, section 7.0.3. Once again the values look to have shifted down by ~ 0.001 to 0.01 logFC.

t_cf_eosinophil_table_sva <- combine_de_tables(
  t_cf_eosinophil_de_sva, keepers = t_cf_contrast,
  excel = glue("{cf_prefix}/Eosinophils/t_eosinophil_cf_table_sva-v{ver}.xlsx"))
t_cf_eosinophil_table_sva

2.19.4 worksheet All_innate

This is actually way earlier in the differential expression document, section 3.1 when the variable ‘t_cf_clinicalnb_table_sva’ is created to produce the xlsx file ‘analyses/4_tumaco/DE_Cure_Fail/All_Samples/t_clinical_nobiop_cf_table_sva-v202409.xlsx’

These numbers match up pretty much exactly (I set the number of significant digits to 4 I think, but this worksheet is 3?)

t_cf_clinical_table_sva <- combine_de_tables(
  t_cf_clinical_de_sva, keepers = cf_contrast,
  excel = glue("{cf_prefix}/All_Samples/t_clinical_cf_table_sva-v{ver}.xlsx"))
t_cf_clinical_table_sva

2.20 Table S6

I do not think they used my gProfiler/clusterProfiler results for this.

2.21 Table S7

This comes from 06lrt_gsva, section 3.

with the caveat that I think the C2 and C7 results are more interesting. Also, the results produced by the container are sparser with respect to the annotations because I did not want to steal the gmt/xml annotations from broad. If you happen to have the xml/gmt files, I left the original invocations there so you can get the full table with the paper titles etc (also, note that later versions of mSigDB changed the xml format so that it no longer parses properly in R; so those functions are now smrt enough to handle the new gmt/json files).

tc_celltype_gsva_h <- simple_gsva(
    tc_valid,
    signatures = broad_h,
    msig_xml = "reference/msigdb/msigdb_v7.5.1.xml",
    signature_category = "h")
tc_celltype_gsva_h_sig <- get_sig_gsva_categories(
    tc_celltype_gsva_h,
    excel = "analyses/3_cali_and_tumaco/GSVA/tc_valid_gsva_h.xlsx")

2.22 Table S8

I am reasonably certain that Alejandro produced the inputs for this; however the container produces nearly identical versions of the pieces in 07wgcna, section 9.

written_interesting <- write_xlsx(fData(l2input)[interesting_genes, ],
                                  excel = glue("excel/wgcna_interesting_genes-v{ver}.xlsx"))

## Note that we can do similarity matrices on the samples too in order to get
## dendrograms which may get interesting groups of samples?

2.23 Table S9

This is not run automatically by the container because it will run most computers out of memory and/or take a really long time. If your computer has ~ 512G ram, open 08classifier_highvar.Rmd and run section 11.2; the resulting xlsx output files should look like this (except cooler because I add some plots).

tc_vall_summary_xlsx <- glue("excel/tc_vall_ml_summary-v{ver}.xlsx")
tc_vall_knn <- classify_n_times(tc_vall_texprs, tc_vall_meta,
                                outcome_column = ref_col,
                                method = "knn", sampler = "cv")
written <- write_classifier_summary(tc_vall_knn, excel = tc_vall_summary_xlsx)
tc_vall_gb <- classify_n_times(tc_vall_texprs, tc_vall_meta,
                               outcome_column = ref_col,
                               method = "xgbTree", sampler = "cv")
written <- write_classifier_summary(tc_vall_gb, excel = written[["wb"]])
tc_vall_glm <- classify_n_times(tc_vall_texprs, tc_vall_meta,
                                outcome_column = ref_col,
                                method = "glmnet", sampler = "cv")
written <- write_classifier_summary(tc_vall_glm, excel = written[["wb"]])
tc_vall_rf <- classify_n_times(tc_vall_texprs, tc_vall_meta,
                               outcome_column = ref_col,
                               method = "ranger", sampler = "cv")
written <- write_classifier_summary(tc_vall_rf, excel = written[["wb"]])
openxlsx::saveWorkbook(written[["wb"]], file = tc_vall_summary_xlsx)

3 Structure

The Rmd files may be rendered in any order with one very important exception: the 01datastructures.Rmd file must be run first. It reads all of the sample sheets and count tables and writes out a series of data files used by all the other documents.

Note: All the references are in the documents, not here.

3.1 01datastructures

This is responsible for setting the stage for everything that follows. It collects annotations from the 2020 ensembl human database, the experimental metadata from the xlsx files in sample_sheets/, and the counts found in preprocessing/ and combines them into an initial, large expressionSet. It tallies up the samples according to many/most of the likely factors of interest, filters the data, and extracts the various subsets into separate datastructures.

3.2 02visualization

Dominated by a long series of PCA explorations. It is basically a playground for me to poke at the various data subsets in order to try to get a feeling for what is the most appropriate way to think about the data. It was where we eventually decided that we cannot use the Cali data, for example.

In later iterations it included a series of regression analyses and further examinations into the sensitivities of the PCA and surrogate variable analyses. It should be noted that these analyses were entirely Theresa’s idea, I copied them into this document and made some minor changes.

3.3 03differential_expression_both

This document performs some differential expression analyses using both the samples from Cali and Tumaco. Partially this was done to assuage my interest, and partially to reinforce the idea that the Cali samples really do not play well with others.

3.4 04differential_expression_tumaco

Ibid, but only Tumaco. This is the real meat of the analysis and seeks to try out various ways of performing differential expression using the Tumaco data in order to see which provide the most robust ways of examining the potential questions in the data.

3.5 05enrichment

Read the xlsx files from 03 and 04 above and pass the resulting gene sets and/or DE tables to gProfiler2 and clusterProfiler. gProfiler was used to perform over-representation analyses of the significantly increased/decreased genes (or both together) of the various contrasts vs. the databases provided by gProfiler. The same task was performed using clusterProfiler with two exceptions: clusterProfiler uses the orgdb annotations for its gene groups and is therefore (by default, but not exclusively) limited to GO/KEGG/DAVID; conversely, one may trivially pass the full DE table to clusterProfiler and thus perform the full GSEA analysis. (I have been playing with passing reactome (via ReactomePA) and mSigDB to these methods).

3.6 06lrt_gsva

Theresa also suggested we try a series of Likelihood Ratio Tests (LRT) to examine trends in the data; thus making DESeq2/EdgeR sensitive to not only increased/decreased gene expression across two conditions, but shared/divergent trends across multiple factors in the metadata. This document provides a version of this.

At the same time we were doing that, she and I put together a simplified method for querying the mSigDB via GSVA. These queries are in this document too.

3.7 07wgcna

Alejandro performed a set of WGCNA analyses using the normalized expression values. He kindly sent me a copy of his R script and I reformatted it somewhat into this document.

3.8 08classifier_highvar

I wanted to explore machine learning classifiers. I had this dataset (and the parasite transcriptomes) open, so I decided to play with them. It was never intended for publication by me but as a fun learning experience; but here it is…

4 Introduction to the singularity container

Of the various options, I found singularity to be the most attractive. I therefore wrote a default Makefile with a few targets to create and manipulate images because I cannot be bothered to remember all of the various commands.

5 The images

I am hoping to create 2 image templates for the TMRC analyses: preprocessing and analyses. I will therefore have a few locally maintained shell scripts which contain the base image setup tasks, the tasks required to setup the tools used, download the data, and perform the work.

6 Setting up the base image

I intend to use Debian stable. I am copying the required setup files into the current working directory and invoking make to create the container. I have a few targets which are intended to make this easier to remember.

6.1 Creating the base image

The following command runs singularity with options suitable to create the image. This to me is a little unnerving, because a bunch of stuff gets run as root.

make

6.2 Testing stuff out and making changes

The overlay target drops the user into the container with R/W permissions. It creates a directory ‘cure_Fail_analyses_overlay’ which may be modified at will.

make cure_fail_analyses.overlay

6.3 Using the container for arbitrary Rmd/md files

The container’s runscript has some logic built in which can process arbitrary markdown documents into html via knitr and pandoc.

cd someplace_with_Rmd
/locationofcontainers/cure_fail_host_analyses.sif -i markdown01.Rmd:markdown02.Rmd
LS0tCnRpdGxlOiAiVE1SQzMgYHIgU3lzLmdldGVudignVkVSU0lPTicpYDogUkVBRE1FL0ludHJvZHVjdGlvbiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgIGNvbGxhcHNlZDogZmFsc2UKICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgoKWyFbRE9JXShodHRwczovL3plbm9kby5vcmcvYmFkZ2UvNzEyMTA0NTE4LnN2ZyldKGh0dHBzOi8vemVub2RvLm9yZy9kb2kvMTAuNTI4MS96ZW5vZG8uMTM3OTg3ODgpCgojIEludHJvZHVjdGlvbgoKVGhlIFIgbWFya2Rvd24gZG9jdW1lbnRzIGluIHRoaXMgZGlyZWN0b3J5IGFyZSBpbnRlbmRlZCB0byBwcm92aWRlIGEKY29tcGxldGUgYWNjb3VudGluZyBvZiB0aGUgYW5hbHlzZXMgcGVyZm9ybWVkIGluIHRoZSBwcmVwYXJhdGlvbiBvZgoKIklubmF0ZSBiaW9zaWduYXR1cmUgb2YgdHJlYXRtZW50IGZhaWx1cmUgaW4gcGF0aWVudHMgd2l0aCBjdXRhbmVvdXMKbGVpc2htYW5pYXNpcy4iCgpJIGFzc3VtZSB0aGF0IGlmIGFueW9uZSBldmVyIHJlYWRzIHRoaXMsIHMvaGUgaXMgbG9va2luZyBmb3IgdGhlCnNvdXJjZSBvZiB0aGUgZGF0YSwgZmlndXJlcywgYW5kIHRhYmxlcyBmcm9tIHRoYXQgcGFwZXIgYW5kIHRvIHNlZSBpZgp0aGUgbWV0aG9kcyBlbXBsb3llZCB0byBnZW5lcmF0ZSB0aGVtIGFyZSBnb29kLCBiYWQsIGluZGlmZmVyZW50LCBvcgpnYXJiYWdlLiAgVGhlc2UgZG9jdW1lbnRzIGFyZSBiZWluZyBnZW5lcmF0ZWQgYnkgYSBzaW5ndWxhcml0eQpjb250YWluZXIgd2hpY2ggcHJvdmlkZXMgdGhlIGlucHV0IGNvdW50IHRhYmxlcyAoT25jZSB3ZSBoYXZlCmFjY2Vzc2lvbnMsIEkgd2lsbCBtYWtlIGEgY29tcGFuaW9uIHdoaWNoIGlzIGFibGUgdG8gY3JlYXRlIHRoZW0pLApzYW1wbGUgc2hlZXRzLCBpbnB1dCBkb2N1bWVudHMsIGFuZCBhbGwgdGhlIHNvZnR3YXJlIHVzZWQgdG8gcHJvY2Vzcwp0aGVtLiAgVGhlIG92ZXJhbCBjb25maWd1cmF0aW9uIG9mIHRoZSBjb250YWluZXIgaXMgY29udGFpbmVkIGluIHRoZQp0b3BsZXZlbCAueW1sIGZpbGUgYW5kIHByb3ZpZGVzIHRoZSBiYXNlIE9TIChEZWJpYW4gc3RhYmxlKSBhbmQgdGhlCnNjcmlwdHMgdXNlZCB0byBpbnN0YWxsIHRoZSBzb2Z0d2FyZS4gICdsb2NhbC9iaW4vc2V0dXBfZGViaWFuLnNoJwpoYW5kbGVzIHRoZSBiYXNlIGNvbnRhaW5lcjsgJ2xvY2FsL2Jpbi9zZXR1cF9ocGdsdG9vbHMuc2gnIHNldHMgdXAgUiwKYmlvY29uZHVjdG9yLCBhbmQgbXkgcGFja2FnZSAnaHBnbHRvb2xzJywgYW5kICdsb2NhbC9iaW4vcnVuc2NyaXB0JyBpcwp0aGUgc2NyaXB0IHJ1biBpZiBvbmUgaW52b2tlcyB0aGUgY29udGFpbmVyIHdpdGhvdXQgYW55IGFyZ3VtZW50czsKd2hlbiBydW4gaXQgdXNlcyB0aGUgdmFyaW91cyBpbnN0YWxsZWQgUiBwYWNrYWdlcyB0byAncmVuZGVyJyB0aGUgUm1kCmZpbGVzIGluIC9kYXRhIHRvIGZyZXNobHkgY3JlYXRlZCBodG1sLiAgVGhpcyBSRUFETUUgaXMgdGhlIGZpcnN0CmRvY3VtZW50IHJlbmRlcmVkLgoKIyBGaWd1cmUvVGFibGUgbG9jYXRpb25zCgpBcyBvZiAyMDI0MDkxOSwgTWFyaWEgQWRlbGFpZGEga2luZGx5IHNlbnQgbWUgdGhlIHB1dGF0aXZlbHkgZmluYWwgc2V0Cm9mIGZpZ3VyZXMvdGFibGVzLiAgSSBhbSBnb2luZyB0byBsYXkgb3V0IHRoZSBsb2NhdGlvbiBpbiB0aGUgaHRtbApsb2dzIGFuZCB0aGVpciBSbWQgcGFyZW50cyB3aGVyZSB0aGVzZSBtYXkgYmUgZm91bmQuICBJZiB5b3Ugd2lzaCB0bwpwbGF5IGFsb25nLCBtYWtlIHN1cmUgeW91IHJ1biB0aGUgZW50aXJlIDAxZGF0YXN0cnVjdHVyZXMuUm1kLgoKQWxzbywgdGhpcyBjb250YWluZXIgaXMgYXV0b21hdGljYWxseSByZWdlbmVyYXRlZCBhbmQgcmVydW4gd2hlbiBJCm1ha2UgY2hhbmdlczsgc28gb25lIG1heSBqdXN0IGdvIGhlcmUgdG8gcGxheSBhbG9uZyAodGhhdCBpcyB3aGVyZSBJCmFtIGdvaW5nIHRvIGh1bnQgZG93biB0aGUgZmlndXJlcy90YWJsZXMpOgoKaHR0cHM6Ly9jb250YWluZXJib29rLnVtaWFjcy5pby8KCiMjIEZpZ3VyZSAxCgpUaGVzZSBudW1iZXJzIGFyZSBjb21pbmcgZnJvbSAwMWRhdGFzdHJ1Y3R1cmVzOiAgd2hlbiBjb25zaWRlcmluZyB0aGUKc2FtcGxlcyBmcm9tIHRoZSBwZXJzcGVjdGl2ZSBvZiBob3cgbWFueSBwZW9wbGUgZmFsbCBpbnRvIGVhY2gKY2F0ZWdvcnksIHRoYXQgaXMgY29taW5nIGRpcmVjdGx5IGZyb20gc2VjdGlvbiA0LjEgIk1ldGFkYXRhIFNvdXJjZXMiCmFuZCB0aGUgZGVtb2dyYXBoaWNzIHhsc3ggZmlsZS4gIFRoaXMgcHJvdmlkZXMgdGhlIG51bWJlciBvZiBwZW9wbGUKd2hvIGZhbGwgaW50byBlYWNoIGNhdGVnb3J5IG9mIHBhbmVsIEEvQi4KCiMjIEZpZ3VyZSAyCgojIyMgUGFuZWwgQQoKVE9ETzogQ2xhcmlmeSB2MS92Mi92MyB2cy4gUHJlLVR4LCBNaWQtVHgsIEVuZC1UeCBpbiB0aGUgbm90ZWJvb2sKClRoaXMgaXMgYWxzbyBkZXJpdmVkIGZyb20gMDFkYXRhc3RydWN0dXJlcywgYnV0IGZyb20gdGhlIHBlcnNwZWN0aXZlCm9mIHRoZSBudW1iZXJzIG9mIHNhbXBsZXMgd2hpY2ggc3Vydml2ZSBvdXIgdmFyaW91cyBmaWx0ZXJzLiAgVGh1cywgdG8KYXJyaXZlIGF0IHRoZXNlIG51bWJlcnMsIG9uZSBzaG91bGQgc3RhcnQgYXQgc2VjdGlvbiA2LjEgIkNyZWF0ZQpFeHByZXNzaW9uc2V0LiIgYW5kIHdhbmRlciB0aHJvdWdoIHRoZSBkb2N1bWVudDsgaG93ZXZlciBkb2luZyBzbyB3aWxsCmxpa2VseSBtYWtlIG1vc3QgcGVvcGxlIHNhZCBiZWNhdXNlIGl0IGlzIGEgbG9uZyBqb3VybmV5LiAgSW5zdGVhZCwKeW91IG1heSBza2lwIGRvd24gdG8gc2VjdGlvbiAxNCAiU3VtbWFyaXplOiBUYWJ1bGF0ZSBzYW1wbGUgbnVtYmVycyIuClRoZSBzZWN0aW9uIGxhYmVsZWQgJ0JvdGgnIHByb3ZpZGVzIHRoZXNlIG51bWJlcnMuICBOb3RlLCB0aGlzIHRhYmxlCnVzZWQgdG8gYmUganVzdCBUdW1hY28sIHdoaWNoIGZvbGxvd3MuCgpUaGUgbnVtYmVycyBvZiBzYW1wbGVzIGluIGVhY2ggZ3JvdXAgYXJlIHJlc3RhdGVkIGluIHRoZSBzdW1tYXJpZXMuClRoZSBvbmx5IHJlYWwgY2F2ZWF0IGlzIHRoYXQgSSB3cm90ZSB0aGVtIGFzICd2aXNpdDEnIG9yICd2MScgZm9yClByZS1UeCwgJ3Zpc2l0MicgZm9yIE1pZC1UeCwgYW5kICd2aXNpdDMnIGZvciBFbmQtVHguCgpBbm90aGVyIHdheSB0byByZWNhcGl0dWxhdGUgdGhlc2UgbnVtYmVycyBpcyB0byBjaGVjayBvdXQgdGhlIHNhbmtleQpwbG90cyBpbiBzZWN0aW9uIDggJ1Zpc3VhbGl6ZSB0aGUgc2FtcGxlIGJyZWFrZG93bicuICBBbiBleGFtcGxlIGludm9jYXRpb24gbG9va3MgbGlrZToKCmBgYHtyLCBldmFsPUZBTFNFfQpjbGluaWNfdHlwZV9vdXRjb21lX3NhbmtleSA8LSBwbG90X21ldGFfc2Fua2V5KAogIHRjX3ZhbGlkLCBmYWN0b3JzID0gYygiY2xpbmljIiwgInR5cGVvZmNlbGxzIiwgImZpbmFsb3V0Y29tZSIpLAogIGRyaWxsX2Rvd24gPSBUUlVFLCBjb2xvcl9jaG9pY2VzID0gY29sb3JfY2hvaWNlcykKY2xpbmljX3R5cGVfb3V0Y29tZV9zYW5rZXkKCmNsaW5pY19ldGhuaWNpdHlfb3V0Y29tZV9zYW5rZXkgPC0gcGxvdF9tZXRhX3NhbmtleSgKICB0Y192YWxpZCwgZmFjdG9ycyA9IGMoImNsaW5pYyIsICJldG5pYSIsICJmaW5hbG91dGNvbWUiKSwKICBkcmlsbF9kb3duID0gVFJVRSwgY29sb3JfY2hvaWNlcyA9IGNvbG9yX2Nob2ljZXMpCmNsaW5pY19ldGhuaWNpdHlfb3V0Y29tZV9zYW5rZXkKCmNsaW5pY19zZXhfb3V0Y29tZV9zYW5rZXkgPC0gcGxvdF9tZXRhX3NhbmtleSgKICB0Y192YWxpZCwgZmFjdG9ycyA9IGMoImNsaW5pYyIsICJzZXgiLCAiZmluYWxvdXRjb21lIiksCiAgZHJpbGxfZG93biA9IFRSVUUsIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzKQpjbGluaWNfc2V4X291dGNvbWVfc2Fua2V5CmBgYAoKIyMjIFBhbmVsIEIKCkZvdW5kIGluIDAydmlzdWFsaXphdGlvbiwgc2VjdGlvbiA4ICJHbG9iYWwgdmlld3Mgb2YgYWxsIGNlbGwgdHlwZXMiCkhleSwgY2hlY2sgaXQsIGRpZmZlcmVudCB0eXBlcyBvZiBpbW11bmUgY2VsbHMgYXJlIGRpZmZlcmVudCEKCk9uZSBpbnZvY2F0aW9uIGxvb2tzIGxpa2UgdGhpcyAodGhlcmUgYXJlIGEgZmV3IHZlcnNpb25zKToKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19wY2EgPC0gcGxvdF9wY2EodGNfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBDQSAtIENlbGwgdHlwZSIsIHNpemVfY29sdW1uID0gInZpc2l0bnVtYmVyIikKdGNfcGNhCmBgYAoKIyMjIFBhbmVsIEMKCkliaWQuICBCb3RoIHBhbmVscyBhcmUgYWN0dWFsbHkgYSBsaXR0bGUgZnVydGhlciBkb3duIGluIHNlY3Rpb24gOC4xLgoKSGVyZSBpcyB0aGUgaW52b2NhdGlvbjoKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19jZl9jb3JoZWF0IDwtIHBsb3RfY29yaGVhdCh0Y19jZl9ub3JtLCBwbG90X3RpdGxlID0gIkhlaXJhcmNoaWNhbCBjbHVzdGVyaW5nOgogICAgICAgICBjZWxsIHR5cGVzIikKdGNfY2ZfY29yaGVhdApgYGAKCiMjIEZpZ3VyZSAzCgpNYXJpYSBBZGVsYWlkYSBkaWQgYSB0cmVtZW5kb3VzIGFtb3VudCBvZiB3b3JrIHRvIG1vdmUgdGhlIHZhcmlvdXMKZ2dwbG90IGxlZ2VuZHMgYXJvdW5kIHNvIHRoYXQgdGhpcyBmaXRzIGluIGEgc2luZ2xlIHBhbmVsIGluIGEKY29oZXJlbnQgZmFzaGlvbi4KCiMjIyBQYW5lbCBBCgpTZWN0aW9uIDkuOCBvZiAwMnZpc3VhbGl6YXRpb246ICJQQ0E6IENvbXBhcmUgY2xpbmljcyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19jbGluaWNfdHlwZV9uYl9wY2EgPC0gcGxvdF9wY2EodGNfY2xpbmljX3R5cGVfbmIpCnRjX2NsaW5pY190eXBlX25iX3BjYQpgYGAKCiMjIyBQYW5lbCBCCgpTZWN0aW9uIDkuNSBvZiAwMnZpc3VhbGl6YXRpb246ICJFb3Npbm9waGlscyBieSBjbGluaWMiCgpgYGB7ciwgZXZhbD1GQUxTRX0KdGNfZW9zaW5vcGhpbHNfcGNhIDwtIHBsb3RfcGNhKHRjX2Vvc2lub3BoaWxzX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpCnRjX2Vvc2lub3BoaWxzX3BjYQpgYGAKCiMjIyBQYW5lbCBDCgpTZWN0aW9uIDkuNiBvZiAwMnZpc3VhbGl6YXRpb246ICJNb25vY3l0ZXMgYnkgY2xuaWMiCgpgYGB7ciwgZXZhbD1GQUxTRX0KdGNfbW9ub2N5dGVzX3BjYSA8LSBwbG90X3BjYSh0Y19tb25vY3l0ZXNfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdGNfbW9ub2N5dGVzX3BjYQpgYGAKCiMjIyBQYW5lbCBECgpTZWN0aW9uIDkuNyBvZiAwMnZpc3VhbGl6YXRpb246ICJOZXV0cm9waGlscyBieSBjbG5pYyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19uZXV0cm9waGlsc19wY2EgPC0gcGxvdF9wY2EodGNfbmV1dHJvcGhpbHNfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdGNfbmV1dHJvcGhpbHNfcGNhCmBgYAoKIyMjIFBhbmVsIEUKClNlY3Rpb24gOS4xIG9mIDAydmlzdWFsaXphdGlvbjogIkJpb3BzaWVzIgoKYGBge3IsIGV2YWw9RkFMU0V9CnRjX2Jpb3BzaWVzX3BjYSA8LSBwbG90X3BjYSh0Y19iaW9wc2llc19ub3JtKQp0Y19iaW9wc2llc19wY2EKYGBgCgojIyBGaWd1cmUgNAoKIyMjIFBhbmVsIEEsIGxlZnQKClNlY3Rpb24gMTAuMi40ICJGaWd1cmUgNEE6IE1vbm9jeXRlcyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0X21vbm9jeXRlX3BjYSA8LSBwbG90X3BjYSh0X21vbm9jeXRlX25vcm0sCiAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdF9tb25vY3l0ZV9wY2EKYGBgCgojIyMgUGFuZWwgQSwgbWlkZGxlCgpTZWN0aW9uIDEwLjIuOCAiRmlndXJlIDRBOiBFb3Npbm9waGlscyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0X2Vvc2lub3BoaWxfcGNhIDwtIHBsb3RfcGNhKHRfZW9zaW5vcGhpbF9ub3JtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCnRfZW9zaW5vcGhpbF9wY2EKYGBgCgojIyMgUGFuZWwgQSwgcmlnaHQKClNlY3Rpb24gMTAuMi42ICJGaWd1cmUgNEE6IE5ldXRyb3BoaWxzIgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfbmV1dHJvcGhpbF9wY2EgPC0gcGxvdF9wY2EodF9uZXV0cm9waGlsX25vcm0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdF9uZXV0cm9waGlsX3BjYQpgYGAKCiMjIFBhbmVsIEIKClRoZXNlIG1vdmUgdG8gdGhlIGRvY3VtZW50IDA0ZGlmZmVyZW50aWFsX2V4cHJlc3Npb25fdHVtYWNvLgoKIyMjIFBhbmVsIEIsIGxlZnQsIG1pZGRsZSwgYW5kIHJpZ2h0CgpTZWN0aW9uIDcuMC40ICJGaWd1cmUgNEI6IFZvbGNhbm8gcGxvdHMiICBGb3Igc29tZSByZWFzb24gSSBkaWQgbm90CmhhdmUgc2VwYXJhdGUgc2VjdGlvbnMgZm9yIGVhY2ggY2VsbCB0eXBlLgoKYGBge3IsIGV2YWw9RkFMU0V9Cm51bV9jb2xvciA8LSBjb2xvcl9jaG9pY2VzW1siY2xpbmljX2NmIl1dW1sidHVtYWNvX2ZhaWx1cmUiXV0KZGVuX2NvbG9yIDwtIGNvbG9yX2Nob2ljZXNbWyJjbGluaWNfY2YiXV1bWyJ0dW1hY29fY3VyZSJdXQp3YW50ZWRfZ2VuZXMgPC0gYygiRkk0NEwiLCAiSUZJMjciLCAiUFJSNSIsICJQUlI1LUFSSEdBUDgiLCAiUkhDRSIsCiAgICAgICAgICAgICAgICAgICJGQlhPMzkiLCAiUlNBRDIiLCAiU01UTkwxIiwgIlVTUDE4IiwgIkFGQVAxIikKCmNmX21vbm9jeXRlX3RhYmxlIDwtIHRfY2ZfbW9ub2N5dGVfdGFibGVfc3ZhW1siZGF0YSJdXVtbIm91dGNvbWUiXV0KY2ZfbW9ub2N5dGVfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIGNmX21vbm9jeXRlX3RhYmxlLCAib3V0Y29tZSIsIGxhYmVsID0gd2FudGVkX2dlbmVzLAogIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBsaW5lX3Bvc2l0aW9uID0gTlVMTCwKICBjb2xvcl9oaWdoID0gbnVtX2NvbG9yLCBjb2xvcl9sb3cgPSBkZW5fY29sb3IsIGxhYmVsX3NpemUgPSA2KQpwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2NmX21vbm9jeXRlX3ZvbGNhbm9fbGFiZWxlZC12e3Zlcn0uc3ZnIikpCmNmX21vbm9jeXRlX3ZvbGNhbm9bWyJwbG90Il1dCmRldi5vZmYoKQpgYGAKCiMjIyBQYW5lbCBDCgpUT0RPOiBBZGQgc2ltaWxhciB2ZW5uIH4gc2VjdGlvbiA4CgpJIHBsYXllZCB3aXRoIHZlcnNpb25zIG9mIHRoaXMgdXNpbmcgQVVDQyBhbmQgVXBTZXQgcGxvdHMgdGhyb3VnaG91dAp0aGUgMDRkaWZmZXJlbnRpYWxfZXhwcmVzc2lvbl90dW1hY28gZG9jdW1lbnQ7IGJ1dCBkaWQgbm90IGdlbmVyYXRlCnRoaXMgc3BlY2lmaWMgaW1hZ2UuICAoTWF5YmUgSSBzaG91bGQgbWFrZSBhIHZlcnNpb24gb2YgaXQ/KQoKIyMgRmlndXJlIDUKClRPRE86IENsYXJpZnkgc2VjdGlvbiBuYW1lcwoKSSBkaWQgbm90IHBlcmZvcm0gYW55IG9mIHRoZSBTVFJJTkcgYW5hbHlzZXMgYW5kIHRoZXJlZm9yZSBhbSB1bmFibGUKdG8gY29tbWVudCBvbiBwYW5lbHMgQSxDLEUsRy4gIEkgc2hvdWxkIGJ1ZyBBbGVqYW5kcm8uCgpUaGUgbG93ZXIgcGFuZWxzIGFyZSBhbGwgY29taW5nIGZyb20gMDVlbnJpY2htZW50IGFuZCBhcmUgdXNpbmcgdGhlCnRyZWVwbG90KCkgcmVzdWx0IGZyb20gZ290ZXJtc2ltKCkgb2YgdGhlIGdQcm9maWxlcjIgcmVzdWx0cy4KCiMjIyBQYW5lbCBCCgowNWVucmljaG1lbnQsIHNlY3Rpb24gMi4xMC4xICJnUHJvZmlsZXIiIChJIGFtIGdvaW5nIHRvIGNoYW5nZSB0aGVzZQpoZWFkaW5ncyB0byBiZSBhIGJpdCBtb3JlIGluZm9ybWF0aXZlLi4uKQoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfZW9zaW5vcGhpbF9zaWdfc3ZhX3VwX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoCiAgdF9jZl9lb3Npbm9waGlsX3NpZ19zdmFfdXAsCiAgZXhjZWwgPSBnbHVlKCJ7eGxzeF9wcmVmaXh9L0dlbmVfU2V0X0VucmljaG1lbnQvdF9jZl9lb3Npbm9waGlsX3VwX2dwLXZ7dmVyfS54bHN4IikpCnRfY2ZfZW9zaW5vcGhpbF9zaWdfc3ZhX3VwX2dwCmBgYAoKIyMjIFBhbmVsIEQKCjA1ZW5yaWNobWVudCwgU2VjdGlvbiAyLjEyLjEgImdQcm9maWxlciIuCgpgYGB7ciwgZXZhbD1GQUxTRX0KdF9jZl9uZXV0cm9waGlsX3NpZ19zdmFfdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcigKICB0X2NmX25ldXRyb3BoaWxfc2lnX3N2YV91cCwKICBleGNlbCA9IGdsdWUoInt4bHN4X3ByZWZpeH0vR2VuZV9TZXRfRW5yaWNobWVudC90X2NmX25ldXRyb3BoaWxfdXBfZ3Atdnt2ZXJ9Lnhsc3giKSkKdF9jZl9uZXV0cm9waGlsX3NpZ19zdmFfdXBfZ3AKYGBgCgojIyMgUGFuZWwgRgoKSWJpZCwgU2VjdGlvbiAyLjExLjEgImdQcm9maWxlciIKCmBgYHtyLCBldmFsPUZBTFNFfQp0X2NmX21vbm9jeXRlX3NpZ19zdmFfdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcigKICB0X2NmX21vbm9jeXRlX3NpZ19zdmFfdXAsCiAgZXhjZWwgPSBnbHVlKCJ7eGxzeF9wcmVmaXh9L0dlbmVfU2V0X0VucmljaG1lbnQvdF9jZl9tb25vY3l0ZV91cF9ncC12e3Zlcn0ueGxzeCIpKQp0X2NmX21vbm9jeXRlX3NpZ19zdmFfdXBfZ3AKYGBgCgojIyMgUGFuZWwgSAoKSWJpZCwgU2VjdGlvbiAyLjQuMSAiZ1Byb2ZpbGVyIiBidXQgaXQgaXMgcHJldHR5IGZhciBkb3duOyBqdXN0IGJlZm9yZQp0aGUgY2x1c3RlclByb2ZpbGVyIGFuYWx5c2VzLgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfY2xpbmljYWxuYl9ncF9kb3duIDwtIHNpbXBsZV9ncHJvZmlsZXIoCiAgdF9jbGluaWNhbG5iX2NmX3NpZ19zdmFfZG93biwKICBleGNlbCA9IGdsdWUoInt4bHN4X3ByZWZpeH0vR2VuZV9TZXRfT3ZlcnJlcHJlc2VudGF0aW9uL2NsaW5pY2FsbmJfZmFpbF91cF9ncC12e3Zlcn0ueGxzeCIpKQp0X2NmX2NsaW5pY2FsbmJfZ3BfZG93bgoKIyMgYW5kCgpnb190ZXJtc2ltIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0odF9jZl9jbGluaWNhbG5iX2dwX2Rvd25bWyJCUF9lbnJpY2giXV0pCnRfY2ZfY2xpbmljYWxuYl9ncF9nb19kb3duX3RyZWUgPC0gc20oZW5yaWNocGxvdDo6dHJlZXBsb3QoZ29fdGVybXNpbSkpCnBwKGZpbGUgPSAiaW1hZ2VzL292ZXJyZXByZXNlbnRhdGlvbi90X2NmX2NsaW5pY2FsbmJfZ3BfZG93bl90cmVlLnBkZiIsCiAgIHdpZHRoID0gdHJlZXBsb3Rfd2lkdGgsIGhlaWdodCA9IHRyZWVwbG90X2hlaWdodCkKdF9jZl9jbGluaWNhbG5iX2dwX2dvX2Rvd25fdHJlZQpkZXYub2ZmKCkKYGBgCgojIyBGaWd1cmUgUzEKClRPRE86IENsYXJpZnkgc2VjdGlvbnMKCkhlYWQgYmFjayB0byAwMnZpc3VhbGl6YXRpb247IHRoaXMgaXMgd2hlcmUgVGhlcmVzYSB0YXVnaHQgbWUKcmVncmVzc2lvbiBhbmFseXNpcyEKCiMjIyBQYW5lbCBBCgowMnZpc3VhbGl6YXRpb24sIE5lYXIgdGhlIGJvdHRvbSBvZiBzZWN0aW9uIDcuMiAiUmVncmVzc2lvbiBhbmFseXNlcwp2cyBvdXRjb21lIiAgKEkgbmVlZCB0byByZW5hbWUgdGhlc2Ugc2VjdGlvbnMgdG9vLCB0aGVzZSBhcmUgY3Jvc3MKY29ycmVsYXRpb25zLCBub3QgcmVncmVzc2lvbjsgSSB1c2VkIHRvIGhhdmUgdGhlbSBhbGwgdG9nZXRoZXIgaW4gYQpiaWcgcGlsZSBhbmQgc3BsaXQgdGhlbSB1cCwgYnV0IGRpZG4ndCBwcm9wZXJseSByZW5hbWUgdGhlIGhlYWRpbmdzLikKCmBgYHtyLCBldmFsPUZBTFNFfQp0X3JlZ3Jlc3Npb25fcXVlcmllcyA8LSBjKCJXZWlnaHQiLCAiU2V4IiwgIkV0aG5pY2l0eSIsICJBZ2UiKQp0X2Nyb3NzX2RmIDwtIHRfcmVncmVzc2lvbl9udW1lcmljWywgdF9yZWdyZXNzaW9uX3F1ZXJpZXNdCnRfcmVncmVzc2lvbl9jcm9zcyA8LSBjb3JyX2Nyb3NzKHRfY3Jvc3NfZGYpCnBwKGZpbGUgPSAiZmlndXJlcy90dW1hY29fd2VpZ2h0X3NleF9ldGhuaWNpdHlfYWdlX251bWVyaWNfY3Jvc3Njb3Iuc3ZnIikKdF9yZWdyZXNzaW9uX2Nyb3NzCmRldi5vZmYoKQpgYGAKCiMjIyBQYW5lbCBCCgowMnZpc3VhbGl6YXRpb24sIDcuMi4xICJDb3B5IHRoZXNlIHdpdGggb25seSB0aGUgVHVtYWNvIHBlb3BsZSIKCmBgYHtyLCBldmFsPUZBTFNFfQpyZWdyZXNzaW9uX3Rlc3RzIDwtIGMoIkFnZSIsICJDbGluaWMiLCAiRXRobmljaXR5IiwgIlNleCIsICJXZWlnaHQiKQpsbV9yZWdyZXNzaW9uX2RlbW9ncmFwaGljcyA8LSBleHRyYWN0X2xpbmVhcl9yZWdyZXNzaW9uKAogIHJlZ3Jlc3Npb25fbnVtZXJpYywgcXVlcnkgPSAiVGhlcmFwZXV0aWNfT3V0Y29tZV9GaW5hbCIsIGZhY3RvcnMgPSByZWdyZXNzaW9uX3Rlc3RzLAogIGV4Y2VsID0gZ2x1ZSgiZXhjZWwvbnVtZXJpY19kZW1vZ3JhcGhpY3NfcmVncmVzc2lvbl9maW5hbF9zZXhfY2xpbmljX2V0aG5pY2l0eV9hZ2Utdnt2ZXJ9Lnhsc3giKSkKCiMjIGFuZAoKcHAoZmlsZSA9ICJpbWFnZXMvZGVtb2dyYXBoaWNzX29ubHlfbGluZWFyX3JlZ3Jlc3Npb24uc3ZnIikKbG1fcmVncmVzc2lvbl9kZW1vZ3JhcGhpY3NbWyJmb3Jlc3QiXV0KZGV2Lm9mZigpCmBgYAoKIyMjIFBhbmVsIEMKCkliaWQsIFNlY3Rpb24gNy4yLjIKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19sb2dfaXRlcmF0aXZlX3JlZ3Jlc3Npb25fZGVtb2dyYXBoaWNzIDwtIGl0ZXJhdGVfbG9naXN0aWNfcmVncmVzc2lvbigKICByZWdyZXNzaW9uX2RmLCBxdWVyeSA9ICJUaGVyYXBldXRpY19PdXRjb21lX0ZpbmFsIiwgZmFjdG9ycyA9IHJlZ3Jlc3Npb25fdGVzdHMsCiAgZXhjZWwgPSBnbHVlKCJleGNlbC90Y19zaW1wbGVfbG9naXN0aWNfcmVncmVzc2lvbi12e3Zlcn0ueGxzeCIpKQoKIyMgYW5kCgpwcChmaWxlID0gZ2x1ZSgiZmlndXJlcy90Y19zaW1wbGVfbG9naXN0aWNfcmVncmVzc2lvbi12e3Zlcn0uc3ZnIikpCnRjX2xvZ19pdGVyYXRpdmVfcmVncmVzc2lvbl9kZW1vZ3JhcGhpY3NbWyJmb3Jlc3QiXV0KZGV2Lm9mZigpCmBgYAoKIyMjIFBhbmVsIEQKCkliaWQuCgpgYGB7ciwgZXZhbD1GQUxTRX0KdF9sb2dfcmVncmVzc2lvbl9kZW1vZ3JhcGhpY3MgPC0gZXh0cmFjdF9sb2dpc3RpY19yZWdyZXNzaW9uKAogIHRfcmVncmVzc2lvbl9kZiwgcXVlcnkgPSAiVGhlcmFwZXV0aWNfT3V0Y29tZV9GaW5hbCIsIGZhY3RvcnMgPSB0X3JlZ3Jlc3Npb25fdGVzdHMsCiAgZXhjZWwgPSBnbHVlKCJleGNlbC90X211bHRpdmFyaWFibGVfbG9naXN0aWNfcmVncmVzc2lvbi12e3Zlcn0ueGxzeCIpKQoKIyMgYW5kCgpwcChmaWxlID0gZ2x1ZSgiZmlndXJlcy90X211bHRpdmFyaWFibGVfbG9naXN0aWNfcmVncmVzc2lvbi12e3Zlcn0uc3ZnIikpCnRfbG9nX3JlZ3Jlc3Npb25fZGVtb2dyYXBoaWNzW1siZm9yZXN0Il1dCmRldi5vZmYoKQpgYGAKCiMjIyBQYW5lbHMgRSBhbmQgRgoKVE9ETzogcmVhZGQKCkhtbSBJIGRlbGV0ZWQgdGhlc2UgZnJvbSBteSBub3RlYm9vaywgSSBkaWQgbm90IHRoaW5rIHdlIHdlcmUgZ29pbmcgdG8KdXNlIHRoZW0gYnV0IGluc3RlYWQgb25seSBpbmNsdWRlIEMvRC4gIEFkZGluZyB0aGVtIGJhY2sgbW9tZW50YXJpbHkuCgojIyBGaWd1cmUgUzIKCiMjIyBQYW5lbCBCL0MKClRoZXNlIGFyZSB3YWF5IGRvd24gaW4gU2VjdGlvbiAxNiAiUGFyYXNpdGUgZGlzdHJpYnV0aW9uIiBvZiAwMnZpc3VhbGl6YXRpb24uCgpgYGB7ciwgZXZhbD1GQUxTRX0KbHBfY2Zfbm9ybV9wY2EgPC0gcGxvdF9wY2EobHBfY2Zfbm9ybSkKYGBgCgojIyBGaWd1cmUgUzQKClRPRE86IHJlbmFtZSBzZWN0aW9uCgpPbmUgbXVzdCByZXR1cm4gdG8gMDFkYXRhc3RydWN0dXJlcyBmb3IgdGhpcyBpbWFnZS4gIEl0IHdhcyB1c2VkIHRvCmRlZmluZSB0aGUgY292ZXJhZ2UgY3V0b2ZmIGZvciBmaWx0ZXJpbmcgc2FtcGxlcyBhbmQgaXMgZm91bmQgYXQKc2VjdGlvbiA3LjIgIkZpZ3VyZSBTMjogTm9uLXplcm8gZ2VuZXMgYmVmb3JlIHNhbXBsZSBmaWx0ZXJpbmciICAoSQpndWVzcyBJIHNob3VsZCByZW5hbWUgdGhpcyB0b28pCgpgYGB7ciwgZXZhbD1GQUxTRX0KYWxsX256IDwtIHBsb3Rfbm9uemVybyhoc19leHB0KQpgYGAKCiMjIEZpZ3VyZSBTNQoKVGhlc2UgYXJlIGFsbCBzY2F0dGVyZWQgdGhyb3VnaCAwMnZpc3VhbGl6YXRpb24uCgojIyMgUGFuZWwgQQoKU2VjdGlvbiA5LjggIkNvbXBhcmUgY2xpbmljcyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19jbGluaWNfdHlwZV9wY2EgPC0gcGxvdF9wY2EodGNfY2xpbmljX3R5cGVfbm9ybSkKdGNfY2xpbmljX3R5cGVfcGNhCmBgYAoKIyMjIFBhbmVsIEIKClNlY3Rpb24gOS41ICJFb3Npbm9waGlscyBieSBjbGluaWMiICBObyBmYWlscyBmcm9tIENhbGkgZm9yCkVvc2lub3BoaWxzIQoKYGBge3IsIGV2YWw9RkFMU0V9CnRjX2Vvc2lub3BoaWxzX3BjYSA8LSBwbG90X3BjYSh0Y19lb3Npbm9waGlsc19ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQp0Y19lb3Npbm9waGlsc19wY2EKYGBgCgojIyMgUGFuZWwgQwoKU2VjdGlvbiA5LjYgIk1vbm9jeXRlcyBieSBjbGluaWMiCgpgYGB7ciwgZXZhbD1GQUxTRX0KdGNfbW9ub2N5dGVzX3BjYSA8LSBwbG90X3BjYSh0Y19tb25vY3l0ZXNfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdGNfbW9ub2N5dGVzX3BjYQpgYGAKCiMjIyBQYW5lbCBECgpTZWN0aW9uIDkuNyAiTmV1dHJvcGhpbHMgYnkgY2xpbmljIgoKYGBge3IsIGV2YWw9RkFMU0V9CnRjX25ldXRyb3BoaWxzX3BjYSA8LSBwbG90X3BjYSh0Y19uZXV0cm9waGlsc19ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQp0Y19uZXV0cm9waGlsc19wY2EKYGBgCgojIyMgUGFuZWwgRQoKU2VjdGlvbiA5LjEgIkJpb3BzaWVzIGJ5IGNsaW5pYyIKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19iaW9wc2llc19wY2EgPC0gcGxvdF9wY2EodGNfYmlvcHNpZXNfbm9ybSkKdGNfYmlvcHNpZXNfcGNhCmBgYAoKIyMjIFBhbmVsIEYKCkF0IHRoZSBib3R0b20gb2Ygc2VjdGlvbiA5LjIuMyAiRW9zaW5vcGhpbCBzYW1wbGVzLCBib3RoIGNsaW5pY3MiCgpgYGB7ciwgZXZhbD1GQUxTRX0KcGxvdF9wY2EoZXRuaWFfZW9fbmIpCmBgYAoKIyMjIFBhbmVsIEcKCkF0IHRoZSBib3R0b20gb2Ygc2VjdGlvbiA5LjIuNCAiTW9ub2N5dGUgc2FtcGxlcywgYm90aCBjbGluaWNzIgoKYGBge3IsIGV2YWw9RkFMU0V9CnBsb3RfcGNhKGV0bmlhX21vX25iKQpgYGAKCiMjIyBQYW5lbCBICgpBdCB0aGUgYm90dG9tIG9mIHNlY3Rpb24gOS4yLjUgIk5ldXRyb3BoaWwgc2FtcGxlcywgYm90aCBjbGluaWNzIgoKYGBge3IsIGV2YWw9RkFMU0V9CnBsb3RfcGNhKGV0bmlhX25lX25iKQpgYGAKCiMjIEZpZ3VyZSBTNgoKVE9ETzogU29tZW9uZSBhc2tlZCBtZSB0byBjaGFuZ2VzIHRoZXNlIGNvbG9ycyB0byB0aGlzIHZpY2lvdXMgc2V0IG9mCmdyZWVucy4gIFRoZSBvcmlnaW5hbCBibGFjay9ncmV5L3doaXRlIGlzIG5pY2VyLgoKIyMjIFBhbmVsIEEvQi9DCgpUaGVzZSBpbWFnZXMgYXJlIHNjYXR0ZXJlZCB0aHJvdWdoIHNlY3Rpb24gMTEuNC4xICJDb21wYXJpbmcgMyB2aXNpdHMKYnkgY2VsbCB0eXBlIiAoSSBjaGFuZ2VkIHRoZSBjb2xvcnMgYmFjayBqdXN0IG5vdyAyMDI0MDkxOSwgdGhvc2UKZ3JlZW5zIGFyZSBhIGhvcnJvciBzaG93LCB3aGVyZSB3YXMgQXByaWwgdG8geWVsbCBhdCBtZSE/KQoKYGBge3IsIGV2YWw9RkFMU0V9CnRfdmlzaXRfbW9ub2N5dGVfbm9ybV9wY2EgPC0gcGxvdF9wY2EodF92aXNpdF9tb25vY3l0ZV9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy90X21vbm9jeXRlX3Zpc2l0X25vcm1fcGNhLnBkZiIpCnRfdmlzaXRfbW9ub2N5dGVfbm9ybV9wY2EkcGxvdApkZXYub2ZmKCkKCiMjIHJlcGxhY2UgbW9ub2N5dGUgd2l0aCB0aGUgcmVsZXZhbnQgY2VsbHR5cGVzIGZvciB0aGUgb3RoZXJzLgpgYGAKCiMjIyBQYW5lbCBECgpUaGVzZSBib3R0b20gcGFuZWxzIGFyZSBjb21wYXJpbmcgbXkgc2ltcGxpZmllZCBtb2RlbCB0byBhIG1vcmUKdGhvcm91Z2ggdmlzaXQtaW4tbW9kZWwgYW5hbHlzaXMuICBUaGlzIGZpcnN0LCBtb25vY3l0ZSBjb21wYXJpc29uIGlzCmluIHNlY3Rpb24gNi4wLjIgb2YgMDRkaWZmZXJlbnRpYWxfZXhwcmVzc2lvbl90dW1hY28uCgpOb3RlLCBocGdsdG9vbHMgaXMgbm93IGFibGUgdG8gaGFuZGxlIGFyYml0cmFyaWx5IGNvbXBsZXggbW9kZWxzCmFjcm9zcyBhbGwgbWV0aG9kcyAoZGVzZXEvZWRnZXIvZXRjLi4uKSB0aG91Z2ggSSBkaWRuJ3QgZmluaXNoIGl0CnVudGlsIGEgZmV3IGRheXMgYWdvIGFuZCBpdCBoYXMgbm90IHlldCBiZWVuIGZ1bGx5IHRlc3RlZC4KCmBgYHtyLCBldmFsPUZBTFNFfQojIyBUaGUgb3JpZ2luYWwgcGFpcndpc2UgaW52b2NhdGlvbiB3aXRoIHN2YToKIyN0X2NmX21vbm9jeXRlX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UodF9tb25vY3l0ZSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgcGFyYWxsZWwgPSBGQUxTRSwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kcyA9IG1ldGhvZHMpCnRlc3RfbW9ub2N5dGVzIDwtIG5vcm1hbGl6ZV9leHB0KHRfbW9ub2N5dGVzLCBmaWx0ZXIgPSAic2ltcGxlIikKYGBgCgpUaGlzIGNvbnRpbnVlcyBmb3IgYSBmZXcgYmxvY2tzIG9mIHJlbGF0aXZlbHkgZGVuc2UgY29kZSBpbnZva2luZyBzdmEKd2l0aCBhIG1vZGVsIGNvbnRhaW5pbmcgdmlzaXQgbnVtYmVyLgoKIyMjIFBhbmVsIEUKCkliaWQsIHNlY3Rpb24gNy4wLjMKClRoaXMgc2VjdGlvbiBpcyBuZWFybHkgaWRlbnRpY2FsbHkgZGVuc2UsIGFuZCBzdGFydHMgd2l0aCB0aGUgZm9sbG93aW5nOgoKYGBge3IsIGV2YWw9RkFMU0V9CiMjIFRoZSBvcmlnaW5hbCBwYWlyd2lzZSBpbnZvY2F0aW9uIHdpdGggc3ZhOgojdF9jZl9lb3Npbm9waGlsX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UodF9lb3Npbm9waGlscywgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIHBhcmFsbGVsPUZBTFNFLCBtZXRob2RzID0gbWV0aG9kcykKdGVzdF9lb3Npbm9waGlscyA8LSBub3JtYWxpemVfZXhwdCh0X2Vvc2lub3BoaWxzLCBmaWx0ZXIgPSAic2ltcGxlIikKYGBgCgojIyMgUGFuZWwgRgoKSWJpZCwgc2VjdGlvbiA3LjAuMgoKVE9ETzogVGhpcyBwb3J0aW9uIG9mIHRoZSAwNGRpZmZlcmVudGlhbF9leHByZXNzaW9uX3R1bWFjbyBpcyBwb29ybHkKb3JnYW5pemVkLgoKYGBge3IsIGV2YWw9RkFMU0V9CiMjIFRoZSBvcmlnaW5hbCBwYWlyd2lzZSBpbnZvY2F0aW9uIHdpdGggc3ZhOgojIyB0X2NmX25ldXRyb3BoaWxfZGVfc3ZhIDwtIGFsbF9wYWlyd2lzZSh0X25ldXRyb3BoaWxzLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IHBhcmFsbGVsLCBmaWx0ZXIgPSBUUlVFLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2RzID0gbWV0aG9kcykKdGVzdF9uZXV0cm9waGlscyA8LSBub3JtYWxpemVfZXhwdCh0X25ldXRyb3BoaWxzLCBmaWx0ZXIgPSAic2ltcGxlIikKYGBgCgojIyBGaWd1cmUgUzcKClRoaXMgaW1hZ2VzIGhhcmtlbiBiYWNrIHRvIDAydmlzdWFsaXphdGlvbgoKIyMjIFBhbmVsIEEKClNlY3Rpb24gMTAuMi4xIG9mIDAydmlzdWFsaXphdGlvbgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2xpbmljYWxfbm9iaW9wX3BjYSA8LSBwbG90X3BjYSh0X2NsaW5pY2FsX25vYmlvcF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImZpZ3VyZXMvdF9jbGluaWNhbF9ub2Jpb3BfZmlneHhhLnBkZiIpCnRfY2xpbmljYWxfbm9iaW9wX3BjYVtbInBsb3QiXV0KZGV2Lm9mZigpCmBgYAoKIyMjIFBhbmVsIEIKClRoZSBuZXh0IGltYWdlIGluIDEwLjIKClRPRE86IENoZWNrIHRoYXQgdGhlIGRldmljZSBpcyBwcm9wZXJseSBjcmVhdGluZyBwZGZzIGluIHRoaXMgc2VjdGlvbjsKaXQgbG9va3MgbGlrZSBpdCBtaWdodCBiZSBjcmVhdGluZyBwbmdzIGZvciBzb21lIG9mIHRoZXNlPwoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2xpbmljYWxfbm9iaW9wX25iX3BjYSA8LSBwbG90X3BjYSh0X2NsaW5pY2FsX25vYmlvcF9uYiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJmaWd1cmVzL3RfY2xpbmljYWxfbm9iaW9wX3N2YV9maWd4eGIucGRmIikKdF9jbGluaWNhbF9ub2Jpb3BfbmJfcGNhW1sicGxvdCJdXQpkZXYub2ZmKCkKYGBgCgojIyBGaWd1cmUgUzgsIFM5LCBTMTAKClRoZXNlIGFyZSBub3QgaW4gbXkgbm90ZWJvb2tzLgoKIyMgRmlndXJlIFMxMQoKIyMjIFBhbmVsIEEKClNlY3Rpb24gMTAuMi4xCgpgYGB7ciwgZXZhbD1GQUxTRX0KdGNfY2xpbmljYWxfbm9iaW9wX3BjYSA8LSBwbG90X3BjYSh0Y19jbGluaWNhbF9ub2Jpb3Bfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJmaWd1cmVzL3RjX2NsaW5pY2FsX25vYmlvcF9maWd4eGMucGRmIikKdGNfY2xpbmljYWxfbm9iaW9wX3BjYVtbInBsb3QiXV0KYGBgCgojIyMgUGFuZWwgQgoKYW5kIHRoZSBpbW1lZGlhdGVseSBmb2xsb3dpbmcgaW1hZ2UKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19jbGluaWNhbF9ub2Jpb3BfbmJfcGNhIDwtIHBsb3RfcGNhKHRjX2NsaW5pY2FsX25vYmlvcF9uYiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICJmaWd1cmVzL3RjX2NsaW5pY2FsX25vYmlvcF9zdmFfZmlneHhkLnBkZiIpCnRjX2NsaW5pY2FsX25vYmlvcF9uYl9wY2FbWyJwbG90Il1dCmRldi5vZmYoKQpgYGAKCiMjIyBQYW5lbCBDCgpJIHRoaW5rIHRoaXMgaXMgdGhlIG9ubHkgaW1hZ2UgdGFrZW4gZnJvbQowM2RpZmZlcmVudGlhbF9leHByZXNzaW9uX2JvdGg7IGl0IGNvbWVzIGZyb20gc2VjdGlvbiA1LjIuMTsgaW4gbXkKbGFzdCBpdGVyYXRpb24gb2YgdGhlIG5vdGVib29rIGl0IGZhaWxlZCBiZWNhdXNlIEkgZm9yZ290IHRvIHRlbGwgaXQKdG8gdXNlIHRoZSBjb2xvcl9jaG9pY2VzIChmaXhlZCkKCmBgYHtyLCBldmFsPUZBTFNFfQp0Y19jbGluaWNhbF9jZl9kZV9iYXRjaCA8LSBhbGxfcGFpcndpc2UodGNfY2xpbmljYWxfbm9iaW9wLCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBwYXJhbGxlbCwgbW9kZWxfYmF0Y2ggPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kcyA9IG1ldGhvZHMpCmBgYAoKIyMgVGFibGUgUzEKClRoaXMgd2FzIG1hbnVhbGx5IGNvbGxhdGVkIGJ5IE1hcmlhIEFkZWxhaWRhOyBJIHRoaW5rIGFsbCB0aGUgbnVtYmVycwpkbyBjb3JyZXNwb25kIHRvIHRoZSByZWdyZXNzaW9uIGYtdmFsdWVzL3AtdmFsdWVzLgoKIyMgVGFibGUgUzIKClRoaXMgaXMgYSB2ZXJ5IHNsaWdodGx5IG1vZGlmaWVkIGNvcHkgb2YgdGhlIHNhbXBsZSBzaGVldCBpbgpzYW1wbGVfc2hlZXRzL3RtcmMzX3NhbXBsZXNfcHJ1bmVkLnhsc3ggIE9uZSBub3Rld29ydGh5IHRoaW5nOiBpZiBvbmUKcmVwcm9jZXNzZXMgdGhlIHJhdyBkYXRhIGFuZCBydW5zICdnYXRoZXJfcHJlcHJvY2Vzc2luZ19tZXRhZGF0YSgpJywKaXQgd2lsbCBzdWNrIHVwIGFsbCB0aGUgbG9ncyBmcm9tIGFueSB0b29scyBmb3Igd2hpY2ggSSBoYXZlIHdyaXR0ZW4KcmVnZXhlcyBhbmQgYXBwZW5kIHRoZSByZXN1bHRzIGFzIGNvbHVtbnMgYXQgdGhlIHJpZ2h0IG9mIHRoaXMuICBJIGFtCm1vcmUgdGhhbiBhIGxpdHRsZSBwcm91ZCBvZiB0aGF0LgoKIyMgVGFibGUgUzMKClRoaXMgaXMgYSBzbGlnaHRseSBtb2RpZmllZCBjb3B5IG9mIHRoZSByZXN1bHQgb2YgdGhlICdzdnBjX2ZzdGF0cygpJwppbnZvY2F0aW9ucyBmb3VuZCBhdCB0aGUgZW5kIG9mIFNlY3Rpb24gMTcgaW4gMDJ2aXN1YWxpemF0aW9uLiAgKG15CmxpdHRsZSBmdW5jdGlvbiBhZGRzIGEgZnVua3kgaGVhdG1hcCB0byB0aGUgb3V0cHV0KQoKYGBge3IsIGV2YWw9RkFMU0V9CnF1ZXJpZXMgPC0gYygidHlwZW9mY2VsbHMiLCAidmlzaXRudW1iZXIiLCAiY2xpbmljIiwgImRvbm9yIikKdGNfY2xpbmljYWxfZnBzdGF0cyA8LSBzdnBjX2ZzdGF0cyh0Y19jbGluaWNhbCwgbnVtX3BjcyA9IDUsIHF1ZXJpZXMgPSBxdWVyaWVzKQpgYGAKCiMjIFRhYmxlIFM0CgpUaGlzIGlzIGEgc2xpZ2h0bHkgbW9kaWZpZWQgY29weSBvZiB0d28gcmVzdWx0czoKCiMjIyBCaW9wc2llcyBERQoKVGhpcyBpcyBhIG1vZGlmaWVkIHZlcnNpb24gb2YgdGhlIHJlc3VsdCB3aGVuIG9uZSBpbnZva2VzCmNvbWJpbmVfZGVfdGFibGVzKCksIGFzIHBlciBzZWN0aW9uIDYuMC4yIG9mCjA0ZGlmZmVyZW50aWFsX2V4cHJlc3Npb25fdHVtYWNvOyB0aGlzIGNvbnRhaW5lciBzaG91bGQgdGhlcmVmb3JlCnByb3ZpZGUgdGhvc2UgbnVtYmVycyBpZiBvbmUgbG9va3MgaW4KJ2FuYWx5c2VzLzRfdHVtYWNvL0RFX0N1cmVfRmFpbC9CaW9wc2llcy90X2Jpb3BzeV9jZl90YWJsZV9zdmEtdjIwMjQwOS54bHN4JwpUaGF0IHhsc3ggd29ya2Jvb2sgaGFzIGEgd29ya3NoZWV0IG5hbWVkICdvdXRjb21lJyAodGhlIHNlY29uZCk7IHRoaXMKd29ya3NoZWV0IGNvbXByaXNlcyBjb2x1bW5zIFEtViBmcm9tIGl0LiAgKGFsc28geWF5ISB0aGUgbnVtYmVycyBhcmUKdGhlIHNhbWUgYmV0d2VlbiBteSBjb250YWluZXIgKHdoaWNoIGNoYW5nZXMgY29uc3RhbnRseSBhbmQgZ2V0cwpyZWJ1aWx0IHdpdGggZWFjaCBjaGFuZ2UpIGFuZCB0aGUgY29weSB0aGF0IHdhcyB1c2VkIGZvciB0aGUgcGFwZXIhKQoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfYmlvcHN5X3RhYmxlX3N2YSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICB0X2NmX2Jpb3BzeV9kZV9zdmEsIGtlZXBlcnMgPSB0X2NmX2NvbnRyYXN0LAogIGV4Y2VsID0gZ2x1ZSgie2NmX3ByZWZpeH0vQmlvcHNpZXMvdF9iaW9wc3lfY2ZfdGFibGVfc3ZhLXZ7dmVyfS54bHN4IikpCnRfY2ZfYmlvcHN5X3RhYmxlX3N2YQpgYGAKCiMjIyBCaXBzaWVzIEdPCgpMb29raW5nIG1vcmUgY2FyZWZ1bGx5IGF0IHRoaXMsIEkgdGhpbmsgdGhpcyBpcyBub3QgZnJvbSBteQpvdmVycmVwcmVzZW50YXRpb24gYW5hbHlzaXM7IGJ1dCBjYW1lIGZyb20gU1RSSU5HPwoKVGhlIGludm9jYXRpb24gZm9yIG15IHZlcnNpb24gb2YgdGhpcyByZXNpZGVzIGluIDA1ZW5yaWNobWVudCwgc2VjdGlvbgoyLjkuMSBhbmQgdGhlIHhsc3ggZmlsZSBpbiB0aGUgY29udGFpbmVyIHNob3VsZCBiZSBmb3VuZCBpbgonYW5hbHlzZXMvR2VuZV9TZXRfRW5yaWNobWVudC90X2NmX2Jpb3BzeV9zaWdfc3ZhX3VwX2dwLXYyMDI0MDkueGxzeCcKZm9yIGdQcm9maWxlciwgYW5kIHdpdGggYSBzaW1pbGFyIG5hbWUgY29udGFpbmluZyAnY3AnIGZvcgpjbHVzdGVyUHJvZmlsZXIuCgpgYGB7ciwgZXZhbD1GQUxTRX0KdF9jZl9iaW9wc3lfc2lnX3N2YV9ncF91cCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKAogIHRfY2ZfYmlvcHN5X3NpZ19zdmFfdXAsCiAgZXhjZWwgPSBnbHVlKCJ7eGxzeF9wcmVmaXh9L0dlbmVfU2V0X0VucmljaG1lbnQvdF9jZl9iaW9wc3lfc2lnX3N2YV91cF9ncC12e3Zlcn0ueGxzeCIpKQp0X2NmX2Jpb3BzeV9zaWdfc3ZhX2dwX3VwCgojIyBvciBwZXJoYXBzIGlmIHlvdSBwcmVmZXIgY2x1c3RlclByb2ZpbGVyCgp0X2NmX2Jpb3BzeV9zaWdfc3ZhX2NwX3VwIDwtIHNpbXBsZV9jcHJvZmlsZXIoCiAgdF9jZl9iaW9wc3lfc2lnX3N2YV91cCwgZGVfdGFibGUgPSB0X2NmX2Jpb3BzeV90YWJsZV9zdmEsCiAgb3JnZGIgPSAib3JnLkhzLmVnLmRiIiwKICBleGNlbCA9IGdsdWUoInt4bHN4X3ByZWZpeH0vR2VuZV9TZXRfRW5yaWNobWVudC90X2NmX2Jpb3BzeV9zaWdfc3ZhX3VwX2NwLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMgVGFibGUgUzUKClRoaXMgaXMgYSByZWRhY3RlZCBjb21iaW5hdGlvbiBvZiBhIGZldyBmaWxlczoKCiMjIyB3b3Jrc2hlZXQgTW9ub2N5dGVzCgpTZWN0aW9uIDYuMC4yIHByb3ZpZGVzIHRoZSBpbnZvY2F0aW9uIG9mIGNvbWJpbmVfZGVfdGFibGVzKCkgd2hpY2gKcHJvZHVjZXMgdGhlCidhbmFseXNpcy80X1R1bWFjby9ERV9DdXJlX0ZhaWwvTW9ub2N5dGVzL3RfbW9ub2N5dGVfY2ZfdGFibGUtc3ZhLXYyMDI0MDkueGxzeCcKdGhhdCBjb21wcmlzZXMgdGhlIGxvZ0ZDIGV0YyB2YWx1ZXMgaW4gdGhpcyB3b3Jrc2hlZXQuICBJbnRlcmVzdGluZ2x5LAp0aGUgdG9wIDUgZ2VuZXMgYWxsIHNoaWZ0ZWQgZG93biBpbiBsb2dGQyBieSB+IDAuMDAyIGluIG15CmNvbnRhaW5lci1kZXJpdmVkIHdvcmtzaGVldCB2cyB0aGlzIHRhYmxlLiAgSSB0aGluayB0aGF0IGlzIGFuCmFjY2VwdGFibGUgZGlmZmVyZW5jZT8gIEkgZGlkIHNwb3QgY2hlY2sgYSBmZXcgZ2VuZXMgaW4gdGhlIHRvcCA1MDAwCmFuZCBpdCBsb29rcyBsaWtlIHRoZSBvcmRlciBpcyBtYWludGFpbmVkLgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfbW9ub2N5dGVfdGFibGVfc3ZhIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHRfY2ZfbW9ub2N5dGVfZGVfc3ZhLCBrZWVwZXJzID0gdF9jZl9jb250cmFzdCwKICBleGNlbCA9IGdsdWUoIntjZl9wcmVmaXh9L01vbm9jeXRlcy90X21vbm9jeXRlX2NmX3RhYmxlX3N2YS12e3Zlcn0ueGxzeCIpKQp0X2NmX21vbm9jeXRlX3RhYmxlX3N2YQpgYGAKCiMjIyB3b3Jrc2hlZXQgTmV1dHJvcGhpbHMKClNhbWUgbG9naWMsIGJ1dCBTZWN0aW9uIDcuMC4yIHdpdGggdGhlIGFuYWxhZ291c2x5IG5hbWVkIHhsc3ggZmlsZSBpbgp0aGUgTmV1dHJvcGhpbHMgZGlyZWN0b3J5OyB0aGVzZSBudW1iZXJzIGFsc28gYXBwZWFyIHRvIGhhdmUKc2hpZnRlZCBzbGlnaHRseSAoYnV0IHRoaXMgdGltZSBieSB+IDAuMDAxIHVwIHRvIDAuMSBsb2dGQykgYW5kIEkgZG8Kc2VlIGEgY291cGxlIG9mIGdlbmVzIG91dCBvZiBvcmRlci4uLiAgSSBhbSBnb2luZyB0byBjaGVjayBpbiB3aXRoCk1hcmlhIEFkZWxhaWRhLgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfbmV1dHJvcGhpbF90YWJsZV9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgdF9jZl9uZXV0cm9waGlsX2RlX3N2YSwga2VlcGVycyA9IHRfY2ZfY29udHJhc3QsCiAgZXhjZWwgPSBnbHVlKCJ7Y2ZfcHJlZml4fS9OZXV0cm9waGlscy90X25ldXRyb3BoaWxfY2ZfdGFibGVfc3ZhLXZ7dmVyfS54bHN4IikpCnRfY2ZfbmV1dHJvcGhpbF90YWJsZV9zdmEKYGBgCgojIyMgd29ya3NoZWV0IEVvc2lub3BoaWxzCgpJYmlkLCBzZWN0aW9uIDcuMC4zLiAgT25jZSBhZ2FpbiB0aGUgdmFsdWVzIGxvb2sgdG8gaGF2ZSBzaGlmdGVkIGRvd24KYnkgfiAwLjAwMSB0byAwLjAxIGxvZ0ZDLgoKYGBge3IsIGV2YWw9RkFMU0V9CnRfY2ZfZW9zaW5vcGhpbF90YWJsZV9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgdF9jZl9lb3Npbm9waGlsX2RlX3N2YSwga2VlcGVycyA9IHRfY2ZfY29udHJhc3QsCiAgZXhjZWwgPSBnbHVlKCJ7Y2ZfcHJlZml4fS9Fb3Npbm9waGlscy90X2Vvc2lub3BoaWxfY2ZfdGFibGVfc3ZhLXZ7dmVyfS54bHN4IikpCnRfY2ZfZW9zaW5vcGhpbF90YWJsZV9zdmEKYGBgCgojIyMgd29ya3NoZWV0IEFsbF9pbm5hdGUKClRoaXMgaXMgYWN0dWFsbHkgd2F5IGVhcmxpZXIgaW4gdGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGRvY3VtZW50LApzZWN0aW9uIDMuMSB3aGVuIHRoZSB2YXJpYWJsZSAndF9jZl9jbGluaWNhbG5iX3RhYmxlX3N2YScgaXMgY3JlYXRlZAp0byBwcm9kdWNlIHRoZSB4bHN4IGZpbGUKJ2FuYWx5c2VzLzRfdHVtYWNvL0RFX0N1cmVfRmFpbC9BbGxfU2FtcGxlcy90X2NsaW5pY2FsX25vYmlvcF9jZl90YWJsZV9zdmEtdjIwMjQwOS54bHN4JwoKVGhlc2UgbnVtYmVycyBtYXRjaCB1cCBwcmV0dHkgbXVjaCBleGFjdGx5IChJIHNldCB0aGUgbnVtYmVyIG9mCnNpZ25pZmljYW50IGRpZ2l0cyB0byA0IEkgdGhpbmssIGJ1dCB0aGlzIHdvcmtzaGVldCBpcyAzPykKCmBgYHtyLCBldmFsPUZBTFNFfQp0X2NmX2NsaW5pY2FsX3RhYmxlX3N2YSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICB0X2NmX2NsaW5pY2FsX2RlX3N2YSwga2VlcGVycyA9IGNmX2NvbnRyYXN0LAogIGV4Y2VsID0gZ2x1ZSgie2NmX3ByZWZpeH0vQWxsX1NhbXBsZXMvdF9jbGluaWNhbF9jZl90YWJsZV9zdmEtdnt2ZXJ9Lnhsc3giKSkKdF9jZl9jbGluaWNhbF90YWJsZV9zdmEKYGBgCgojIyBUYWJsZSBTNgoKSSBkbyBub3QgdGhpbmsgdGhleSB1c2VkIG15IGdQcm9maWxlci9jbHVzdGVyUHJvZmlsZXIgcmVzdWx0cyBmb3IKdGhpcy4KCiMjIFRhYmxlIFM3CgpUaGlzIGNvbWVzIGZyb20gMDZscnRfZ3N2YSwgc2VjdGlvbiAzLgoKd2l0aCB0aGUgY2F2ZWF0IHRoYXQgSSB0aGluayB0aGUgQzIgYW5kIEM3IHJlc3VsdHMgYXJlIG1vcmUKaW50ZXJlc3RpbmcuICBBbHNvLCB0aGUgcmVzdWx0cyBwcm9kdWNlZCBieSB0aGUgY29udGFpbmVyIGFyZSBzcGFyc2VyCndpdGggcmVzcGVjdCB0byB0aGUgYW5ub3RhdGlvbnMgYmVjYXVzZSBJIGRpZCBub3Qgd2FudCB0byBzdGVhbCB0aGUKZ210L3htbCBhbm5vdGF0aW9ucyBmcm9tIGJyb2FkLiAgSWYgeW91IGhhcHBlbiB0byBoYXZlIHRoZSB4bWwvZ210CmZpbGVzLCBJIGxlZnQgdGhlIG9yaWdpbmFsIGludm9jYXRpb25zIHRoZXJlIHNvIHlvdSBjYW4gZ2V0IHRoZSBmdWxsCnRhYmxlIHdpdGggdGhlIHBhcGVyIHRpdGxlcyBldGMgKGFsc28sIG5vdGUgdGhhdCBsYXRlciB2ZXJzaW9ucyBvZgptU2lnREIgY2hhbmdlZCB0aGUgeG1sIGZvcm1hdCBzbyB0aGF0IGl0IG5vIGxvbmdlciBwYXJzZXMgcHJvcGVybHkgaW4KUjsgc28gdGhvc2UgZnVuY3Rpb25zIGFyZSBub3cgc21ydCBlbm91Z2ggdG8gaGFuZGxlIHRoZSBuZXcgZ210L2pzb24KZmlsZXMpLgoKYGBge3IsIGV2YWw9RkFMU0V9CnRjX2NlbGx0eXBlX2dzdmFfaCA8LSBzaW1wbGVfZ3N2YSgKICAgIHRjX3ZhbGlkLAogICAgc2lnbmF0dXJlcyA9IGJyb2FkX2gsCiAgICBtc2lnX3htbCA9ICJyZWZlcmVuY2UvbXNpZ2RiL21zaWdkYl92Ny41LjEueG1sIiwKICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJoIikKdGNfY2VsbHR5cGVfZ3N2YV9oX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHRjX2NlbGx0eXBlX2dzdmFfaCwKICAgIGV4Y2VsID0gImFuYWx5c2VzLzNfY2FsaV9hbmRfdHVtYWNvL0dTVkEvdGNfdmFsaWRfZ3N2YV9oLnhsc3giKQpgYGAKCiMjIFRhYmxlIFM4CgpJIGFtIHJlYXNvbmFibHkgY2VydGFpbiB0aGF0IEFsZWphbmRybyBwcm9kdWNlZCB0aGUgaW5wdXRzIGZvciB0aGlzOwpob3dldmVyIHRoZSBjb250YWluZXIgcHJvZHVjZXMgbmVhcmx5IGlkZW50aWNhbCB2ZXJzaW9ucyBvZiB0aGUgcGllY2VzCmluIDA3d2djbmEsIHNlY3Rpb24gOS4KCmBgYHtyLCBldmFsPUZBTFNFfQp3cml0dGVuX2ludGVyZXN0aW5nIDwtIHdyaXRlX3hsc3goZkRhdGEobDJpbnB1dClbaW50ZXJlc3RpbmdfZ2VuZXMsIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWUoImV4Y2VsL3dnY25hX2ludGVyZXN0aW5nX2dlbmVzLXZ7dmVyfS54bHN4IikpCgojIyBOb3RlIHRoYXQgd2UgY2FuIGRvIHNpbWlsYXJpdHkgbWF0cmljZXMgb24gdGhlIHNhbXBsZXMgdG9vIGluIG9yZGVyIHRvIGdldAojIyBkZW5kcm9ncmFtcyB3aGljaCBtYXkgZ2V0IGludGVyZXN0aW5nIGdyb3VwcyBvZiBzYW1wbGVzPwpgYGAKCiMjIFRhYmxlIFM5CgpUaGlzIGlzIG5vdCBydW4gYXV0b21hdGljYWxseSBieSB0aGUgY29udGFpbmVyIGJlY2F1c2UgaXQgd2lsbCBydW4KbW9zdCBjb21wdXRlcnMgb3V0IG9mIG1lbW9yeSBhbmQvb3IgdGFrZSBhIHJlYWxseSBsb25nIHRpbWUuICBJZiB5b3VyCmNvbXB1dGVyIGhhcyB+IDUxMkcgcmFtLCBvcGVuIDA4Y2xhc3NpZmllcl9oaWdodmFyLlJtZCBhbmQgcnVuIHNlY3Rpb24KMTEuMjsgdGhlIHJlc3VsdGluZyB4bHN4IG91dHB1dCBmaWxlcyBzaG91bGQgbG9vayBsaWtlIHRoaXMgKGV4Y2VwdApjb29sZXIgYmVjYXVzZSBJIGFkZCBzb21lIHBsb3RzKS4KCmBgYHtyLCBldmFsPUZBTFNFfQp0Y192YWxsX3N1bW1hcnlfeGxzeCA8LSBnbHVlKCJleGNlbC90Y192YWxsX21sX3N1bW1hcnktdnt2ZXJ9Lnhsc3giKQp0Y192YWxsX2tubiA8LSBjbGFzc2lmeV9uX3RpbWVzKHRjX3ZhbGxfdGV4cHJzLCB0Y192YWxsX21ldGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZV9jb2x1bW4gPSByZWZfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJrbm4iLCBzYW1wbGVyID0gImN2IikKd3JpdHRlbiA8LSB3cml0ZV9jbGFzc2lmaWVyX3N1bW1hcnkodGNfdmFsbF9rbm4sIGV4Y2VsID0gdGNfdmFsbF9zdW1tYXJ5X3hsc3gpCnRjX3ZhbGxfZ2IgPC0gY2xhc3NpZnlfbl90aW1lcyh0Y192YWxsX3RleHBycywgdGNfdmFsbF9tZXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZV9jb2x1bW4gPSByZWZfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInhnYlRyZWUiLCBzYW1wbGVyID0gImN2IikKd3JpdHRlbiA8LSB3cml0ZV9jbGFzc2lmaWVyX3N1bW1hcnkodGNfdmFsbF9nYiwgZXhjZWwgPSB3cml0dGVuW1sid2IiXV0pCnRjX3ZhbGxfZ2xtIDwtIGNsYXNzaWZ5X25fdGltZXModGNfdmFsbF90ZXhwcnMsIHRjX3ZhbGxfbWV0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRjb21lX2NvbHVtbiA9IHJlZl9jb2wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImdsbW5ldCIsIHNhbXBsZXIgPSAiY3YiKQp3cml0dGVuIDwtIHdyaXRlX2NsYXNzaWZpZXJfc3VtbWFyeSh0Y192YWxsX2dsbSwgZXhjZWwgPSB3cml0dGVuW1sid2IiXV0pCnRjX3ZhbGxfcmYgPC0gY2xhc3NpZnlfbl90aW1lcyh0Y192YWxsX3RleHBycywgdGNfdmFsbF9tZXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0Y29tZV9jb2x1bW4gPSByZWZfY29sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJhbmdlciIsIHNhbXBsZXIgPSAiY3YiKQp3cml0dGVuIDwtIHdyaXRlX2NsYXNzaWZpZXJfc3VtbWFyeSh0Y192YWxsX3JmLCBleGNlbCA9IHdyaXR0ZW5bWyJ3YiJdXSkKb3Blbnhsc3g6OnNhdmVXb3JrYm9vayh3cml0dGVuW1sid2IiXV0sIGZpbGUgPSB0Y192YWxsX3N1bW1hcnlfeGxzeCkKYGBgCgojIFN0cnVjdHVyZQoKVGhlIFJtZCBmaWxlcyBtYXkgYmUgcmVuZGVyZWQgaW4gYW55IG9yZGVyIHdpdGggb25lIHZlcnkgaW1wb3J0YW50CmV4Y2VwdGlvbjogdGhlIDAxZGF0YXN0cnVjdHVyZXMuUm1kIGZpbGUgbXVzdCBiZSBydW4gZmlyc3QuICBJdCByZWFkcwphbGwgb2YgdGhlIHNhbXBsZSBzaGVldHMgYW5kIGNvdW50IHRhYmxlcyBhbmQgd3JpdGVzIG91dCBhIHNlcmllcyBvZgpkYXRhIGZpbGVzIHVzZWQgYnkgYWxsIHRoZSBvdGhlciBkb2N1bWVudHMuCgpOb3RlOiBBbGwgdGhlIHJlZmVyZW5jZXMgYXJlIGluIHRoZSBkb2N1bWVudHMsIG5vdCBoZXJlLgoKIyMgMDFkYXRhc3RydWN0dXJlcwoKVGhpcyBpcyByZXNwb25zaWJsZSBmb3Igc2V0dGluZyB0aGUgc3RhZ2UgZm9yIGV2ZXJ5dGhpbmcgdGhhdCBmb2xsb3dzLgpJdCBjb2xsZWN0cyBhbm5vdGF0aW9ucyBmcm9tIHRoZSAyMDIwIGVuc2VtYmwgaHVtYW4gZGF0YWJhc2UsIHRoZQpleHBlcmltZW50YWwgbWV0YWRhdGEgZnJvbSB0aGUgeGxzeCBmaWxlcyBpbiBzYW1wbGVfc2hlZXRzLywgYW5kIHRoZQpjb3VudHMgZm91bmQgaW4gcHJlcHJvY2Vzc2luZy8gYW5kIGNvbWJpbmVzIHRoZW0gaW50byBhbiBpbml0aWFsLApsYXJnZSBleHByZXNzaW9uU2V0LiAgSXQgdGFsbGllcyB1cCB0aGUgc2FtcGxlcyBhY2NvcmRpbmcgdG8gbWFueS9tb3N0Cm9mIHRoZSBsaWtlbHkgZmFjdG9ycyBvZiBpbnRlcmVzdCwgZmlsdGVycyB0aGUgZGF0YSwgYW5kIGV4dHJhY3RzIHRoZQp2YXJpb3VzIHN1YnNldHMgaW50byBzZXBhcmF0ZSBkYXRhc3RydWN0dXJlcy4KCiMjIDAydmlzdWFsaXphdGlvbgoKRG9taW5hdGVkIGJ5IGEgbG9uZyBzZXJpZXMgb2YgUENBIGV4cGxvcmF0aW9ucy4gIEl0IGlzIGJhc2ljYWxseSBhCnBsYXlncm91bmQgZm9yIG1lIHRvIHBva2UgYXQgdGhlIHZhcmlvdXMgZGF0YSBzdWJzZXRzIGluIG9yZGVyIHRvIHRyeQp0byBnZXQgYSBmZWVsaW5nIGZvciB3aGF0IGlzIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byB0aGluayBhYm91dAp0aGUgZGF0YS4gIEl0IHdhcyB3aGVyZSB3ZSBldmVudHVhbGx5IGRlY2lkZWQgdGhhdCB3ZSBjYW5ub3QgdXNlIHRoZQpDYWxpIGRhdGEsIGZvciBleGFtcGxlLgoKSW4gbGF0ZXIgaXRlcmF0aW9ucyBpdCBpbmNsdWRlZCBhIHNlcmllcyBvZiByZWdyZXNzaW9uIGFuYWx5c2VzIGFuZApmdXJ0aGVyIGV4YW1pbmF0aW9ucyBpbnRvIHRoZSBzZW5zaXRpdml0aWVzIG9mIHRoZSBQQ0EgYW5kIHN1cnJvZ2F0ZQp2YXJpYWJsZSBhbmFseXNlcy4gIEl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZXNlIGFuYWx5c2VzIHdlcmUKZW50aXJlbHkgVGhlcmVzYSdzIGlkZWEsIEkgY29waWVkIHRoZW0gaW50byB0aGlzIGRvY3VtZW50IGFuZCBtYWRlCnNvbWUgbWlub3IgY2hhbmdlcy4KCiMjIDAzZGlmZmVyZW50aWFsX2V4cHJlc3Npb25fYm90aAoKVGhpcyBkb2N1bWVudCBwZXJmb3JtcyBzb21lIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2VzIHVzaW5nCmJvdGggdGhlIHNhbXBsZXMgZnJvbSBDYWxpIGFuZCBUdW1hY28uICBQYXJ0aWFsbHkgdGhpcyB3YXMgZG9uZSB0bwphc3N1YWdlIG15IGludGVyZXN0LCBhbmQgcGFydGlhbGx5IHRvIHJlaW5mb3JjZSB0aGUgaWRlYSB0aGF0IHRoZSBDYWxpCnNhbXBsZXMgcmVhbGx5IGRvIG5vdCBwbGF5IHdlbGwgd2l0aCBvdGhlcnMuCgojIyAwNGRpZmZlcmVudGlhbF9leHByZXNzaW9uX3R1bWFjbwoKSWJpZCwgYnV0IG9ubHkgVHVtYWNvLiAgVGhpcyBpcyB0aGUgcmVhbCBtZWF0IG9mIHRoZSBhbmFseXNpcyBhbmQKc2Vla3MgdG8gdHJ5IG91dCB2YXJpb3VzIHdheXMgb2YgcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgp1c2luZyB0aGUgVHVtYWNvIGRhdGEgaW4gb3JkZXIgdG8gc2VlIHdoaWNoIHByb3ZpZGUgdGhlIG1vc3Qgcm9idXN0CndheXMgb2YgZXhhbWluaW5nIHRoZSBwb3RlbnRpYWwgcXVlc3Rpb25zIGluIHRoZSBkYXRhLgoKIyMgMDVlbnJpY2htZW50CgpSZWFkIHRoZSB4bHN4IGZpbGVzIGZyb20gMDMgYW5kIDA0IGFib3ZlIGFuZCBwYXNzIHRoZSByZXN1bHRpbmcgZ2VuZQpzZXRzIGFuZC9vciBERSB0YWJsZXMgdG8gZ1Byb2ZpbGVyMiBhbmQgY2x1c3RlclByb2ZpbGVyLiAgZ1Byb2ZpbGVyCndhcyB1c2VkIHRvIHBlcmZvcm0gb3Zlci1yZXByZXNlbnRhdGlvbiBhbmFseXNlcyBvZiB0aGUgc2lnbmlmaWNhbnRseQppbmNyZWFzZWQvZGVjcmVhc2VkIGdlbmVzIChvciBib3RoIHRvZ2V0aGVyKSBvZiB0aGUgdmFyaW91cyBjb250cmFzdHMKdnMuIHRoZSBkYXRhYmFzZXMgcHJvdmlkZWQgYnkgZ1Byb2ZpbGVyLiAgVGhlIHNhbWUgdGFzayB3YXMgcGVyZm9ybWVkCnVzaW5nIGNsdXN0ZXJQcm9maWxlciB3aXRoIHR3byBleGNlcHRpb25zOiBjbHVzdGVyUHJvZmlsZXIgdXNlcyB0aGUKb3JnZGIgYW5ub3RhdGlvbnMgZm9yIGl0cyBnZW5lIGdyb3VwcyBhbmQgaXMgdGhlcmVmb3JlIChieSBkZWZhdWx0LApidXQgbm90IGV4Y2x1c2l2ZWx5KSBsaW1pdGVkIHRvIEdPL0tFR0cvREFWSUQ7IGNvbnZlcnNlbHksIG9uZSBtYXkKdHJpdmlhbGx5IHBhc3MgdGhlIGZ1bGwgREUgdGFibGUgdG8gY2x1c3RlclByb2ZpbGVyIGFuZCB0aHVzIHBlcmZvcm0KdGhlIGZ1bGwgR1NFQSBhbmFseXNpcy4gKEkgaGF2ZSBiZWVuIHBsYXlpbmcgd2l0aCBwYXNzaW5nIHJlYWN0b21lCih2aWEgUmVhY3RvbWVQQSkgYW5kIG1TaWdEQiB0byB0aGVzZSBtZXRob2RzKS4KCiMjIDA2bHJ0X2dzdmEKClRoZXJlc2EgYWxzbyBzdWdnZXN0ZWQgd2UgdHJ5IGEgc2VyaWVzIG9mIExpa2VsaWhvb2QgUmF0aW8gVGVzdHMgKExSVCkKdG8gZXhhbWluZSB0cmVuZHMgaW4gdGhlIGRhdGE7IHRodXMgbWFraW5nIERFU2VxMi9FZGdlUiBzZW5zaXRpdmUgdG8Kbm90IG9ubHkgaW5jcmVhc2VkL2RlY3JlYXNlZCBnZW5lIGV4cHJlc3Npb24gYWNyb3NzIHR3byBjb25kaXRpb25zLApidXQgc2hhcmVkL2RpdmVyZ2VudCB0cmVuZHMgYWNyb3NzIG11bHRpcGxlIGZhY3RvcnMgaW4gdGhlIG1ldGFkYXRhLgpUaGlzIGRvY3VtZW50IHByb3ZpZGVzIGEgdmVyc2lvbiBvZiB0aGlzLgoKQXQgdGhlIHNhbWUgdGltZSB3ZSB3ZXJlIGRvaW5nIHRoYXQsIHNoZSBhbmQgSSBwdXQgdG9nZXRoZXIgYQpzaW1wbGlmaWVkIG1ldGhvZCBmb3IgcXVlcnlpbmcgdGhlIG1TaWdEQiB2aWEgR1NWQS4gIFRoZXNlIHF1ZXJpZXMgYXJlCmluIHRoaXMgZG9jdW1lbnQgdG9vLgoKIyMgMDd3Z2NuYQoKQWxlamFuZHJvIHBlcmZvcm1lZCBhIHNldCBvZiBXR0NOQSBhbmFseXNlcyB1c2luZyB0aGUgbm9ybWFsaXplZApleHByZXNzaW9uIHZhbHVlcy4gIEhlIGtpbmRseSBzZW50IG1lIGEgY29weSBvZiBoaXMgUiBzY3JpcHQgYW5kIEkKcmVmb3JtYXR0ZWQgaXQgc29tZXdoYXQgaW50byB0aGlzIGRvY3VtZW50LgoKIyMgMDhjbGFzc2lmaWVyX2hpZ2h2YXIKCkkgd2FudGVkIHRvIGV4cGxvcmUgbWFjaGluZSBsZWFybmluZyBjbGFzc2lmaWVycy4gSSBoYWQgdGhpcyBkYXRhc2V0CihhbmQgdGhlIHBhcmFzaXRlIHRyYW5zY3JpcHRvbWVzKSBvcGVuLCBzbyBJIGRlY2lkZWQgdG8gcGxheSB3aXRoCnRoZW0uICBJdCB3YXMgbmV2ZXIgaW50ZW5kZWQgZm9yIHB1YmxpY2F0aW9uIGJ5IG1lIGJ1dCBhcyBhIGZ1bgpsZWFybmluZyBleHBlcmllbmNlOyBidXQgaGVyZSBpdCBpcy4uLgoKIyBJbnRyb2R1Y3Rpb24gdG8gdGhlIHNpbmd1bGFyaXR5IGNvbnRhaW5lcgoKT2YgdGhlIHZhcmlvdXMgb3B0aW9ucywgSSBmb3VuZCBzaW5ndWxhcml0eSB0byBiZSB0aGUgbW9zdCBhdHRyYWN0aXZlLgpJIHRoZXJlZm9yZSB3cm90ZSBhIGRlZmF1bHQgTWFrZWZpbGUgd2l0aCBhIGZldyB0YXJnZXRzIHRvIGNyZWF0ZSBhbmQKbWFuaXB1bGF0ZSBpbWFnZXMgYmVjYXVzZSBJIGNhbm5vdCBiZSBib3RoZXJlZCB0byByZW1lbWJlciBhbGwgb2YgdGhlCnZhcmlvdXMgY29tbWFuZHMuCgojIFRoZSBpbWFnZXMKCkkgYW0gaG9waW5nIHRvIGNyZWF0ZSAyIGltYWdlIHRlbXBsYXRlcyBmb3IgdGhlIFRNUkMgYW5hbHlzZXM6CnByZXByb2Nlc3NpbmcgYW5kIGFuYWx5c2VzLiBJIHdpbGwgdGhlcmVmb3JlIGhhdmUgYSBmZXcgbG9jYWxseQptYWludGFpbmVkIHNoZWxsIHNjcmlwdHMgd2hpY2ggY29udGFpbiB0aGUgYmFzZSBpbWFnZSBzZXR1cCB0YXNrcywgdGhlCnRhc2tzIHJlcXVpcmVkIHRvIHNldHVwIHRoZSB0b29scyB1c2VkLCBkb3dubG9hZCB0aGUgZGF0YSwgYW5kIHBlcmZvcm0KdGhlIHdvcmsuCgojIFNldHRpbmcgdXAgdGhlIGJhc2UgaW1hZ2UKCkkgaW50ZW5kIHRvIHVzZSBEZWJpYW4gc3RhYmxlLiAgSSBhbSBjb3B5aW5nIHRoZSByZXF1aXJlZCBzZXR1cCBmaWxlcwppbnRvIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGFuZCBpbnZva2luZyBtYWtlIHRvIGNyZWF0ZQp0aGUgY29udGFpbmVyLiAgSSBoYXZlIGEgZmV3IHRhcmdldHMgd2hpY2ggYXJlIGludGVuZGVkIHRvIG1ha2UgdGhpcwplYXNpZXIgdG8gcmVtZW1iZXIuCgojIyBDcmVhdGluZyB0aGUgYmFzZSBpbWFnZQoKVGhlIGZvbGxvd2luZyBjb21tYW5kIHJ1bnMgc2luZ3VsYXJpdHkgd2l0aCBvcHRpb25zIHN1aXRhYmxlIHRvIGNyZWF0ZQp0aGUgaW1hZ2UuICBUaGlzIHRvIG1lIGlzIGEgbGl0dGxlIHVubmVydmluZywgYmVjYXVzZSBhIGJ1bmNoIG9mIHN0dWZmCmdldHMgcnVuIGFzIHJvb3QuCgpgYGB7YmFzaCwgZXZhbD1GQUxTRX0KbWFrZQpgYGAKCiMjIFRlc3Rpbmcgc3R1ZmYgb3V0IGFuZCBtYWtpbmcgY2hhbmdlcwoKVGhlIG92ZXJsYXkgdGFyZ2V0IGRyb3BzIHRoZSB1c2VyIGludG8gdGhlIGNvbnRhaW5lciB3aXRoIFIvVwpwZXJtaXNzaW9ucy4gIEl0IGNyZWF0ZXMgYSBkaXJlY3RvcnkgJ2N1cmVfRmFpbF9hbmFseXNlc19vdmVybGF5JyB3aGljaAptYXkgYmUgbW9kaWZpZWQgYXQgd2lsbC4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQptYWtlIGN1cmVfZmFpbF9hbmFseXNlcy5vdmVybGF5CmBgYAoKIyMgVXNpbmcgdGhlIGNvbnRhaW5lciBmb3IgYXJiaXRyYXJ5IFJtZC9tZCBmaWxlcwoKVGhlIGNvbnRhaW5lcidzIHJ1bnNjcmlwdCBoYXMgc29tZSBsb2dpYyBidWlsdCBpbiB3aGljaCBjYW4gcHJvY2VzcwphcmJpdHJhcnkgbWFya2Rvd24gZG9jdW1lbnRzIGludG8gaHRtbCB2aWEga25pdHIgYW5kIHBhbmRvYy4KCmBgYHtiYXNoLCBldmFsPUZBTFNFfQpjZCBzb21lcGxhY2Vfd2l0aF9SbWQKL2xvY2F0aW9ub2Zjb250YWluZXJzL2N1cmVfZmFpbF9ob3N0X2FuYWx5c2VzLnNpZiAtaSBtYXJrZG93bjAxLlJtZDptYXJrZG93bjAyLlJtZApgYGAK