1 Introduction

This dataset contains multiple experiments.

2 Annotations

pa14_gff <- load_gff_annotations("reference/paeruginosa_pa14.gff", id_col="gene_id")
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = TRUE)
## Had a successful gff import with rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = TRUE)
## Returning a df with 16 columns and 11946 rows.
rownames(pa14_gff) <- pa14_gff[["gene_id"]]
## The Alias column has PA14_00010

pa14_microbes <- as.data.frame(load_microbesonline_annotations("PA14"))
## Found 1 entry.
## Pseudomonas aeruginosa UCBPP-PA14Proteobacteria2006-11-22yes105972208963
## The species being downloaded is: Pseudomonas aeruginosa UCBPP-PA14
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=208963;export=tab
## The sysName column has PA14_0010

pa14_annot <- merge(pa14_gff, pa14_microbes, by.x="Alias", by.y="sysName")
rownames(pa14_annot) <- pa14_annot[["gene_id"]]

pa14_go <- load_microbesonline_go(species = "PA14")
## Found 1 entry.
## Pseudomonas aeruginosa UCBPP-PA14Proteobacteria2006-11-22yes105972208963
## The species being downloaded is: Pseudomonas aeruginosa UCBPP-PA14 and is being downloaded as 208963.tab.

3 Make the expressionset

Given the above annotations, now lets pull in the counts.

I am switching to the sheet all_samples_modified_gcd.xlsx for the moment because I added a space in the strain name for the gcd sampl

pa14_expt <- create_expt("sample_sheets/all_samples_modified_gcd.xlsx",
                         gene_info=pa14_annot, file_column="hisatcounttable")
## Reading the sample metadata.
## Did not find the condition column in the sample sheet.
## Filling it in as undefined.
## Did not find the batch column in the sample sheet.
## Filling it in as undefined.
## The sample definitions comprises: 105 rows(samples) and 31 columns(metadata fields).
## Matched 5972 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 5979 rows and 105 columns.

4 Quick global look at the data

While we are at it, lets drop the two sad samples.

pa14_libsize <- plot_libsize(pa14_expt)
pa14_libsize$plot

pa14_nonzero <- plot_nonzero(pa14_expt)
pa14_nonzero$plot
## Warning: ggrepel: 100 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pa14_expt <- subset_expt(pa14_expt, nonzero=5500)
## The samples (and read coverage) removed when filtering 5500 non-zero genes are:
##  SM040  SM048 
##  43984 316632
## subset_expt(): There were 105, now there are 103 samples.

4.1 A few queries

I know a priori that April is interested to see how the 4 library preparations look with respect to each other. Let us therefore create a data structure to look explicitly at that.

pa14_libprep <- set_expt_conditions(pa14_expt, fact="libraryprepbatch") %>%
  set_expt_batches(fact="organisms")

pa14_lib_norm <- normalize_expt(pa14_libprep, filter=TRUE,
                                convert="cpm", norm="quant", transform="log2")
## Removing 6 low-count genes (5973 remaining).
## transform_counts: Found 35 values equal to 0, adding 1 to the matrix.
plot_pca(pa14_lib_norm)$plot
## plot labels was not set and there are more than 100 samples, disabling it.

plot_corheat(pa14_lib_norm)$plot

libprep_pca_info <- pca_information(
    pa14_lib_norm, plot_pcas=TRUE,
    expt_factors=c("libraryprepbatch", "organisms", "strains", "media", "bioreplicate"))
## plot labels was not set and there are more than 100 samples, disabling it.
libprep_pca_info$anova_f_heatmap

libprep_pca_info$pca_plots[[2]]
## Warning: ggrepel: 76 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

libprep_pca_info$pca_plots[[3]]
## Warning: ggrepel: 102 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

libprep_pca_info$pca_plots[[4]]
## Warning: ggrepel: 85 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

libprep_pca_info$pca_plots[[5]]
## Warning: ggrepel: 77 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

To my eyes they look reasonably mixed, suggesting that library prep batch is not a dominant factor in the data.

At this point, I am thinking that we should separate the data by the experiments, but I will first just show the relationships among all the data.

5 Looking at other factors

As far as I see, there are three factors which are of primary interest:

  1. PA14 strain
  2. Media used
  3. Bioreplicate

The last will be used as batch in the following plots.

pa14_media <- set_expt_conditions(pa14_expt, fact="media") %>%
  set_expt_batches(fact="bioreplicate")
pa14_media_norm <- normalize_expt(pa14_media, transform="log2", convert="cpm",
                                  filter=TRUE, norm="quant")
## Removing 6 low-count genes (5973 remaining).
## transform_counts: Found 35 values equal to 0, adding 1 to the matrix.
plot_pca(pa14_media_norm)$plot
## plot labels was not set and there are more than 100 samples, disabling it.

pa14_strains <- set_expt_conditions(pa14_expt, fact="strains") %>%
  set_expt_batches(fact="bioreplicate")
pa14_strains_norm <- normalize_expt(pa14_strains, transform="log2", convert="cpm",
                                  filter=TRUE, norm="quant")
## Removing 6 low-count genes (5973 remaining).
## transform_counts: Found 35 values equal to 0, adding 1 to the matrix.
plot_pca(pa14_strains_norm)$plot
## plot labels was not set and there are more than 100 samples, disabling it.

Disregarding the various experiments performed, I think we can state that media separates the data in a fashion which is more interesting than strain. Given the number of (what I assume are) closely related strains, I am thinking it might prove to be a good idea to perform my variant search tool on this data and see how well they held up with respect to the reference strain.

6 Separate the experiments

I have been told repeatedly that there are multiple experiments in this data, but apparently I have not paid proper attention because I cannot remember which is which, and to my eyes it is not obvious in the sample sheet.

With this in mind, I spoke with Solomon briefly and have an idea of the 3 logical groups in his data. Let us therefore separate and examine those first.

6.1 Metabolism and infection

For the moment, I am going to call Solomon’s samples ‘metabolism and infection.’ I will also complicate the ‘condition’ of the data by combining the media and strain, but shortly thereafter will split that back. I think the reason why will become clear.

initials_factor <- gsub(x=rownames(pData(pa14_expt)), pattern="^(..).*$", replacement="\\1")
pData(pa14_expt)[["initials"]] <- as.factor(initials_factor)
strain_media <- paste0(pData(pa14_expt)[["strains"]], "_",
                       pData(pa14_expt)[["media"]])
pData(pa14_expt)[["strain_media"]] <- strain_media

## Lets set some colors
## WT: grayscale, eda: blue, edd: green, gcd: purple, pgl: red, zwf: yellow
colors_by_strain <- list(
    "PA14 WT" = "#000000",
    "PA14 eda" = "#0000dd",
    "PA14 edd" = "#00dd00",
    "PA14 gcd" = "#dd00dd",
    "PA14 pgl" = "#dd0000",
    "PA14 zwf" = "#dddd00")

infect_metabolism <- subset_expt(pa14_expt, subset="initials=='SM'") %>%
  set_expt_conditions(fact="strains") %>%
  set_expt_batches(fact="media")
## subset_expt(): There were 103, now there are 58 samples.
plot_legend(infect_metabolism)

## $colors
##       condition           batch  colors
## sm001   PA14 WT              LB #66A61E
## sm002   PA14 WT LB + 0.5 M urea #66A61E
## sm003   PA14 WT      Mice Urine #66A61E
## sm004   PA14 WT            PBST #66A61E
## sm005  PA14 eda      Mice Urine #1B9E77
## sm006  PA14 eda            PBST #1B9E77
## sm007  PA14 edd      Mice Urine #D95F02
## sm008  PA14 edd            PBST #D95F02
## sm009  PA14 gcd      Mice Urine #7570B3
## sm010  PA14 gcd            PBST #7570B3
## sm011  PA14 pgl      Mice Urine #E7298A
## sm012  PA14 pgl            PBST #E7298A
## sm013  PA14 zwf      Mice Urine #E6AB02
## sm014  PA14 zwf            PBST #E6AB02
## sm015   PA14 WT              LB #66A61E
## sm016   PA14 WT LB + 0.5 M urea #66A61E
## sm017   PA14 WT      Mice Urine #66A61E
## sm018   PA14 WT            PBST #66A61E
## sm019  PA14 eda      Mice Urine #1B9E77
## sm020  PA14 eda            PBST #1B9E77
## sm021  PA14 edd      Mice Urine #D95F02
## sm022  PA14 edd            PBST #D95F02
## sm023  PA14 gcd      Mice Urine #7570B3
## sm024  PA14 gcd            PBST #7570B3
## sm025  PA14 pgl      Mice Urine #E7298A
## sm026  PA14 pgl            PBST #E7298A
## sm027  PA14 zwf      Mice Urine #E6AB02
## sm028  PA14 zwf            PBST #E6AB02
## sm029   PA14 WT              LB #66A61E
## sm030   PA14 WT LB + 0.5 M urea #66A61E
## sm031   PA14 WT      Mice Urine #66A61E
## sm032   PA14 WT            PBST #66A61E
## sm033  PA14 eda      Mice Urine #1B9E77
## sm034  PA14 eda            PBST #1B9E77
## sm035  PA14 edd      Mice Urine #D95F02
## sm036  PA14 edd            PBST #D95F02
## sm037  PA14 gcd      Mice Urine #7570B3
## sm038  PA14 gcd            PBST #7570B3
## sm039  PA14 pgl      Mice Urine #E7298A
## sm041  PA14 zwf      Mice Urine #E6AB02
## sm042  PA14 zwf            PBST #E6AB02
## sm043   PA14 WT   Mice instiled #66A61E
## sm044   PA14 WT   Mice instiled #66A61E
## sm045   PA14 WT   Mice instiled #66A61E
## sm046  PA14 eda   Mice instiled #1B9E77
## sm047  PA14 eda   Mice instiled #1B9E77
## sm049  PA14 edd   Mice instiled #D95F02
## sm050  PA14 edd   Mice instiled #D95F02
## sm051  PA14 edd   Mice instiled #D95F02
## sm052  PA14 gcd   Mice instiled #7570B3
## sm053  PA14 gcd   Mice instiled #7570B3
## sm054  PA14 gcd   Mice instiled #7570B3
## sm055  PA14 pgl   Mice instiled #E7298A
## sm056  PA14 pgl   Mice instiled #E7298A
## sm057  PA14 pgl   Mice instiled #E7298A
## sm058  PA14 zwf   Mice instiled #E6AB02
## sm059  PA14 zwf   Mice instiled #E6AB02
## sm060  PA14 zwf   Mice instiled #E6AB02
## 
## $plot
metabolism_control <- subset_expt(infect_metabolism,
                                  subset="media=='LB'|media=='LB + 0.5 M urea'") %>%
  set_expt_conditions(fact="media") %>%
  set_expt_batches("bioreplicate")
## subset_expt(): There were 58, now there are 6 samples.
metabolism_starvation <- subset_expt(infect_metabolism,
                                     subset="media=='PBST'|media=='Mice Urine'") %>%
  set_expt_colors(colors=colors_by_strain) %>%
  set_expt_conditions(fact="media") %>%
  set_expt_batches(fact="strains")
## subset_expt(): There were 58, now there are 35 samples.
metabolism_starvation_strain <- set_expt_conditions(metabolism_starvation, fact="strains") %>%
  set_expt_batches(fact="media")

metabolism_exudate <- subset_expt(infect_metabolism,
                                  subset="media=='Mice instiled'")
## subset_expt(): There were 58, now there are 17 samples.

6.2 Glance at these 4 subsets

As a whole group, these samples are a bit confusing. The mouse instiled samples are prety obvious, but the other sources of variance remain a bit of a mystery to me.

global_norm <- normalize_expt(infect_metabolism, filter=TRUE, convert="cpm",
                              norm="quant", transform="log2") %>%
  set_expt_conditions(fact="media")
## Removing 13 low-count genes (5966 remaining).
## transform_counts: Found 1 values equal to 0, adding 1 to the matrix.
plot_pca(global_norm)$plot
## Warning: ggrepel: 16 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

tmp <- global_norm %>%
  set_expt_conditions(fact="strains")
plot_pca(tmp)$plot
## Warning: ggrepel: 48 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

7 The smallest experiment: LB vs. LB+urea

This is a group of 6 samples, 3 in LB and three in LB+urea. This should therefore be the most straight forward comparison.

mc_norm <- normalize_expt(metabolism_control, transform="log2",
                          convert="cpm", norm="quant", filter=TRUE)
## Removing 73 low-count genes (5906 remaining).
plot_pca(mc_norm)$plot

7.1 Metabolism control experiment, DE

mc_san <- sanitize_expt(metabolism_control)
mc_de <- all_pairwise(mc_san, model_batch=TRUE, filter=TRUE)
## Plotting a PCA before surrogate/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
mc_tables <- combine_de_tables(
    mc_de,
    excel=glue::glue("excel/metabolism_control_tables-v{ver}.xlsx"),
    sig_excel=glue::glue("excel/metabolism_control_sig-v{ver}.xlsx"))

hmm, is there any chance that SM001 and SM005 are flipped? If they were, then both clades would have 1 of each bioreplicate.

8 Starving strains

The second group is a little more complex, it seeks to simultaneously compare the strains (WT vs. mutants) and the environment (PBS vs. urine).

This design is complex enough that I think we need to choose colors more carefully.

ms_norm <- normalize_expt(metabolism_starvation, filter=TRUE, norm="quant",
                          convert="cpm", transform="log2")
## Removing 30 low-count genes (5949 remaining).
plot_pca(ms_norm)$plot

ms_de <- all_pairwise(metabolism_starvation, model_batch=TRUE)
## Plotting a PCA before surrogate/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
ms_tables <- combine_de_tables(
    ms_de,
    excel=glue::glue("excel/metabolism_starvation_tables-v{ver}.xlsx"),
    sig_excel=glue::glue("excel/metabolism_starvation_sig-v{ver}.xlsx"))

9 Metabolism Starvation GO

ms_up <- ms_tables[["significant"]][["deseq"]][["ups"]][[1]]
ms_down <- ms_tables[["significant"]][["deseq"]][["downs"]][[1]]

## The go data from microbesonline is keyed by the gene name
## (e.g. dnaA), not gene ID or PA id or whatever.
pa14_lengths <- pa14_annot[, c("name.x", "width")]
colnames(pa14_lengths) <- c("ID", "width")

rownames(ms_up) <- make.names(ms_up[["namex"]], unique=TRUE)
ms_up_goseq <- simple_goseq(ms_up, go_db=pa14_go, length_db=pa14_lengths)
## Found 378 go_db genes and 717 length_db genes out of 717.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
ms_up_goseq[["pvalue_plots"]][["bpp_plot_over"]]

ms_up_goseq[["pvalue_plots"]][["mfp_plot_over"]]

rownames(ms_down) <- make.names(ms_down[["namex"]], unique=TRUE)
ms_down_goseq <- simple_goseq(ms_down, go_db=pa14_go, length_db=pa14_lengths)
## Found 468 go_db genes and 672 length_db genes out of 673.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
ms_down_goseq[["pvalue_plots"]][["bpp_plot_over"]]

ms_down_goseq[["pvalue_plots"]][["mfp_plot_over"]]

9.1 Compare strains

This time let us compare the strains and lower the variance from media.

mss_norm <- normalize_expt(metabolism_starvation_strain, filter=TRUE, convert="cpm", norm="quant",
                           batch="svaseq", transform="log2")
## Warning in normalize_expt(metabolism_starvation_strain, filter = TRUE, convert =
## "cpm", : Quantile normalization and sva do not always play well together.
## Removing 30 low-count genes (5949 remaining).
## batch_counts: Before batch/surrogate estimation, 0 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 1787 entries are 0<x<1: 1%.
## Setting 16 low elements to zero.
## transform_counts: Found 16 values equal to 0, adding 1 to the matrix.
plot_pca(mss_norm)$plot

mss_urine <- subset_expt(metabolism_starvation_strain, subset="batch=='Mice Urine'")
## subset_expt(): There were 35, now there are 18 samples.
interesting <- list(
    "eda_vs_wt" = c("PA14eda", "PA14WT"),
    "edd_vs_wt" = c("PA14edd", "PA14WT"),
    "gcd_vs_wt" = c("PA14gcd", "PA14WT"),
    "pgl_vs_wt" = c("PA14pgl", "PA14WT"),
    "zfw_vs_wt" = c("PA14zwf", "PA14WT"))

mss_urine_de <- all_pairwise(mss_urine, model_batch="svaseq", filter=TRUE)
## batch_counts: Before batch/surrogate estimation, 29 entries are x==0: 0%.
## Plotting a PCA before surrogate/batch inclusion.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## Removing 0 low-count genes (5941 remaining).
## batch_counts: Before batch/surrogate estimation, 29 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 506 entries are 0<x<1: 0%.
## Setting 11 low elements to zero.
## transform_counts: Found 11 values equal to 0, adding 1 to the matrix.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

mss_urine_table <- combine_de_tables(
    mss_urine_de, keepers=interesting,
    excel=glue::glue("excel/metabolism_starvation_strain_tables-v{ver}.xlsx"),
    sig_excel=glue::glue("excel/metabolism_starvation_strain_sig-v{ver}.xlsx"))

10 Exudate

Comapre the strains during the instillation process

exudate_norm <- normalize_expt(metabolism_exudate, filter=TRUE, convert="cpm",
                               norm="quant", transform="log2")
## Removing 69 low-count genes (5910 remaining).
## transform_counts: Found 76 values equal to 0, adding 1 to the matrix.
plot_pca(exudate_norm)$plot

10.1 Exudate DE

exudate_de <- all_pairwise(metabolism_exudate, model_batch=TRUE, filter=TRUE)
## Plotting a PCA before surrogate/batch inclusion.
## Using limma's removeBatchEffect to visualize with(out) batch inclusion.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.

exudate_tables <- combine_de_tables(
    exudate_de, keepers=interesting,
    excel=glue::glue("excel/exudate_tables-v{ver}.xlsx"),
    sig_excel=glue::glue("excel/exudate_sig-v{ver}.xlsx"))

11 Check mouse counts

mm_expt <- create_expt("sample_sheets/all_samples_modified2.xlsx",
                       gene_info=pa14_annot, file_column="mousetable")
## Reading the sample metadata.
## Did not find the condition column in the sample sheet.
## Filling it in as undefined.
## Did not find the batch column in the sample sheet.
## Filling it in as undefined.
## The sample definitions comprises: 105 rows(samples) and 32 columns(metadata fields).
## Warning in create_expt("sample_sheets/all_samples_modified2.xlsx", gene_info
## = pa14_annot, : Some samples were removed when cross referencing the samples
## against the count data.
## Warning in create_expt("sample_sheets/all_samples_modified2.xlsx", gene_info =
## pa14_annot, : Even after changing the rownames in gene info, they do not match
## the count table.
## Even after changing the rownames in gene info, they do not match the count table.
## Here are the first few rownames from the count tables:
## gene:ENSMUSG00000000001, gene:ENSMUSG00000000003, gene:ENSMUSG00000000028, gene:ENSMUSG00000000037, gene:ENSMUSG00000000049, gene:ENSMUSG00000000056
## Here are the first few rownames from the gene information table:
## gene1650835, gene1650837, gene1650839, gene1650841, gene1650843, gene1650845
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Warning in create_expt("sample_sheets/all_samples_modified2.xlsx", gene_info =
## pa14_annot, : The following samples have no counts! SM029SM032SM038SM040
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 25753 rows and 35 columns.
plot_libsize(mm_expt)$plot
## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 4 rows containing missing values (geom_bar).

pander::pander(sessionInfo())
message(paste0("This is hpgltools commit: ", get_git_commit()))
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiU29tZSBQc2V1ZG9tb25hcyBSTkFzZXEgZGF0YTogU00uIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB3aWR0aDogMzAwCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgQmlvY1N0eWxlOjpodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQ9IiVZJW0lZCIpCnByZXZpb3VzX2ZpbGUgPC0gIiIKdmVyIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCAiJVklbSVkIikKCiMjdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKQpybWRfZmlsZSA8LSAiaW5kZXhfc20uUm1kIgpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRhdGFzZXQgY29udGFpbnMgbXVsdGlwbGUgZXhwZXJpbWVudHMuCgojIEFubm90YXRpb25zCgpgYGB7ciBhbm5vdGF0aW9ufQpwYTE0X2dmZiA8LSBsb2FkX2dmZl9hbm5vdGF0aW9ucygicmVmZXJlbmNlL3BhZXJ1Z2lub3NhX3BhMTQuZ2ZmIiwgaWRfY29sPSJnZW5lX2lkIikKcm93bmFtZXMocGExNF9nZmYpIDwtIHBhMTRfZ2ZmW1siZ2VuZV9pZCJdXQojIyBUaGUgQWxpYXMgY29sdW1uIGhhcyBQQTE0XzAwMDEwCgpwYTE0X21pY3JvYmVzIDwtIGFzLmRhdGEuZnJhbWUobG9hZF9taWNyb2Jlc29ubGluZV9hbm5vdGF0aW9ucygiUEExNCIpKQojIyBUaGUgc3lzTmFtZSBjb2x1bW4gaGFzIFBBMTRfMDAxMAoKcGExNF9hbm5vdCA8LSBtZXJnZShwYTE0X2dmZiwgcGExNF9taWNyb2JlcywgYnkueD0iQWxpYXMiLCBieS55PSJzeXNOYW1lIikKcm93bmFtZXMocGExNF9hbm5vdCkgPC0gcGExNF9hbm5vdFtbImdlbmVfaWQiXV0KCnBhMTRfZ28gPC0gbG9hZF9taWNyb2Jlc29ubGluZV9nbyhzcGVjaWVzID0gIlBBMTQiKQpgYGAKCiMgTWFrZSB0aGUgZXhwcmVzc2lvbnNldAoKR2l2ZW4gdGhlIGFib3ZlIGFubm90YXRpb25zLCBub3cgbGV0cyBwdWxsIGluIHRoZSBjb3VudHMuCgpJIGFtIHN3aXRjaGluZyB0byB0aGUgc2hlZXQgYWxsX3NhbXBsZXNfbW9kaWZpZWRfZ2NkLnhsc3ggZm9yIHRoZQptb21lbnQgYmVjYXVzZSBJIGFkZGVkIGEgc3BhY2UgaW4gdGhlIHN0cmFpbiBuYW1lIGZvciB0aGUgZ2NkIHNhbXBsCgpgYGB7ciBleHByZXNzaW9uc2V0fQpwYTE0X2V4cHQgPC0gY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvYWxsX3NhbXBsZXNfbW9kaWZpZWRfZ2NkLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvPXBhMTRfYW5ub3QsIGZpbGVfY29sdW1uPSJoaXNhdGNvdW50dGFibGUiKQpgYGAKCiMgUXVpY2sgZ2xvYmFsIGxvb2sgYXQgdGhlIGRhdGEKCldoaWxlIHdlIGFyZSBhdCBpdCwgbGV0cyBkcm9wIHRoZSB0d28gc2FkIHNhbXBsZXMuCgpgYGB7ciBtZXRyaWNzfQpwYTE0X2xpYnNpemUgPC0gcGxvdF9saWJzaXplKHBhMTRfZXhwdCkKcGExNF9saWJzaXplJHBsb3QKCnBhMTRfbm9uemVybyA8LSBwbG90X25vbnplcm8ocGExNF9leHB0KQpwYTE0X25vbnplcm8kcGxvdAoKcGExNF9leHB0IDwtIHN1YnNldF9leHB0KHBhMTRfZXhwdCwgbm9uemVybz01NTAwKQpgYGAKCiMjIEEgZmV3IHF1ZXJpZXMKCkkga25vdyBhIHByaW9yaSB0aGF0IEFwcmlsIGlzIGludGVyZXN0ZWQgdG8gc2VlIGhvdyB0aGUgNCBsaWJyYXJ5CnByZXBhcmF0aW9ucyBsb29rIHdpdGggcmVzcGVjdCB0byBlYWNoIG90aGVyLiAgTGV0IHVzIHRoZXJlZm9yZSBjcmVhdGUKYSBkYXRhIHN0cnVjdHVyZSB0byBsb29rIGV4cGxpY2l0bHkgYXQgdGhhdC4KCmBgYHtyIGxpYnByZXB9CnBhMTRfbGlicHJlcCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHBhMTRfZXhwdCwgZmFjdD0ibGlicmFyeXByZXBiYXRjaCIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdD0ib3JnYW5pc21zIikKCnBhMTRfbGliX25vcm0gPC0gbm9ybWFsaXplX2V4cHQocGExNF9saWJwcmVwLCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIsIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKHBhMTRfbGliX25vcm0pJHBsb3QKcGxvdF9jb3JoZWF0KHBhMTRfbGliX25vcm0pJHBsb3QKCmxpYnByZXBfcGNhX2luZm8gPC0gcGNhX2luZm9ybWF0aW9uKAogICAgcGExNF9saWJfbm9ybSwgcGxvdF9wY2FzPVRSVUUsCiAgICBleHB0X2ZhY3RvcnM9YygibGlicmFyeXByZXBiYXRjaCIsICJvcmdhbmlzbXMiLCAic3RyYWlucyIsICJtZWRpYSIsICJiaW9yZXBsaWNhdGUiKSkKbGlicHJlcF9wY2FfaW5mbyRhbm92YV9mX2hlYXRtYXAKbGlicHJlcF9wY2FfaW5mbyRwY2FfcGxvdHNbWzJdXQpsaWJwcmVwX3BjYV9pbmZvJHBjYV9wbG90c1tbM11dCmxpYnByZXBfcGNhX2luZm8kcGNhX3Bsb3RzW1s0XV0KbGlicHJlcF9wY2FfaW5mbyRwY2FfcGxvdHNbWzVdXQpgYGAKClRvIG15IGV5ZXMgdGhleSBsb29rIHJlYXNvbmFibHkgbWl4ZWQsIHN1Z2dlc3RpbmcgdGhhdCBsaWJyYXJ5IHByZXAKYmF0Y2ggaXMgbm90IGEgZG9taW5hbnQgZmFjdG9yIGluIHRoZSBkYXRhLgoKQXQgdGhpcyBwb2ludCwgSSBhbSB0aGlua2luZyB0aGF0IHdlIHNob3VsZCBzZXBhcmF0ZSB0aGUgZGF0YSBieSB0aGUKZXhwZXJpbWVudHMsIGJ1dCBJIHdpbGwgZmlyc3QganVzdCBzaG93IHRoZSByZWxhdGlvbnNoaXBzIGFtb25nIGFsbAp0aGUgZGF0YS4KCiMgTG9va2luZyBhdCBvdGhlciBmYWN0b3JzCgpBcyBmYXIgYXMgSSBzZWUsIHRoZXJlIGFyZSB0aHJlZSBmYWN0b3JzIHdoaWNoIGFyZSBvZiBwcmltYXJ5CmludGVyZXN0OgoKMS4gUEExNCBzdHJhaW4KMi4gTWVkaWEgdXNlZAozLiBCaW9yZXBsaWNhdGUKClRoZSBsYXN0IHdpbGwgYmUgdXNlZCBhcyBiYXRjaCBpbiB0aGUgZm9sbG93aW5nIHBsb3RzLgoKYGBge3Igb3RoZXJfZmFjdG9yc30KcGExNF9tZWRpYSA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHBhMTRfZXhwdCwgZmFjdD0ibWVkaWEiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9ImJpb3JlcGxpY2F0ZSIpCnBhMTRfbWVkaWFfbm9ybSA8LSBub3JtYWxpemVfZXhwdChwYTE0X21lZGlhLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IikKcGxvdF9wY2EocGExNF9tZWRpYV9ub3JtKSRwbG90CgpwYTE0X3N0cmFpbnMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhwYTE0X2V4cHQsIGZhY3Q9InN0cmFpbnMiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9ImJpb3JlcGxpY2F0ZSIpCnBhMTRfc3RyYWluc19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHBhMTRfc3RyYWlucywgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIpCnBsb3RfcGNhKHBhMTRfc3RyYWluc19ub3JtKSRwbG90CmBgYAoKRGlzcmVnYXJkaW5nIHRoZSB2YXJpb3VzIGV4cGVyaW1lbnRzIHBlcmZvcm1lZCwgSSB0aGluayB3ZSBjYW4gc3RhdGUKdGhhdCBtZWRpYSBzZXBhcmF0ZXMgdGhlIGRhdGEgaW4gYSBmYXNoaW9uIHdoaWNoIGlzIG1vcmUgaW50ZXJlc3RpbmcKdGhhbiBzdHJhaW4uICBHaXZlbiB0aGUgbnVtYmVyIG9mICh3aGF0IEkgYXNzdW1lIGFyZSkgY2xvc2VseSByZWxhdGVkCnN0cmFpbnMsIEkgYW0gdGhpbmtpbmcgaXQgbWlnaHQgcHJvdmUgdG8gYmUgYSBnb29kIGlkZWEgdG8gcGVyZm9ybSBteQp2YXJpYW50IHNlYXJjaCB0b29sIG9uIHRoaXMgZGF0YSBhbmQgc2VlIGhvdyB3ZWxsIHRoZXkgaGVsZCB1cCB3aXRoCnJlc3BlY3QgdG8gdGhlIHJlZmVyZW5jZSBzdHJhaW4uCgojIFNlcGFyYXRlIHRoZSBleHBlcmltZW50cwoKSSBoYXZlIGJlZW4gdG9sZCByZXBlYXRlZGx5IHRoYXQgdGhlcmUgYXJlIG11bHRpcGxlIGV4cGVyaW1lbnRzIGluCnRoaXMgZGF0YSwgYnV0IGFwcGFyZW50bHkgSSBoYXZlIG5vdCBwYWlkIHByb3BlciBhdHRlbnRpb24gYmVjYXVzZSBJCmNhbm5vdCByZW1lbWJlciB3aGljaCBpcyB3aGljaCwgYW5kIHRvIG15IGV5ZXMgaXQgaXMgbm90IG9idmlvdXMgaW4KdGhlIHNhbXBsZSBzaGVldC4KCldpdGggdGhpcyBpbiBtaW5kLCBJIHNwb2tlIHdpdGggU29sb21vbiBicmllZmx5IGFuZCBoYXZlIGFuIGlkZWEgb2YKdGhlIDMgbG9naWNhbCBncm91cHMgaW4gaGlzIGRhdGEuICBMZXQgdXMgdGhlcmVmb3JlIHNlcGFyYXRlIGFuZApleGFtaW5lIHRob3NlIGZpcnN0LgoKIyMgTWV0YWJvbGlzbSBhbmQgaW5mZWN0aW9uCgpGb3IgdGhlIG1vbWVudCwgSSBhbSBnb2luZyB0byBjYWxsIFNvbG9tb24ncyBzYW1wbGVzICdtZXRhYm9saXNtIGFuZAppbmZlY3Rpb24uJyAgSSB3aWxsIGFsc28gY29tcGxpY2F0ZSB0aGUgJ2NvbmRpdGlvbicgb2YgdGhlIGRhdGEgYnkKY29tYmluaW5nIHRoZSBtZWRpYSBhbmQgc3RyYWluLCBidXQgc2hvcnRseSB0aGVyZWFmdGVyIHdpbGwgc3BsaXQgdGhhdApiYWNrLiAgSSB0aGluayB0aGUgcmVhc29uIHdoeSB3aWxsIGJlY29tZSBjbGVhci4KCmBgYHtyIG1ldGFib2xpc219CmluaXRpYWxzX2ZhY3RvciA8LSBnc3ViKHg9cm93bmFtZXMocERhdGEocGExNF9leHB0KSksIHBhdHRlcm49Il4oLi4pLiokIiwgcmVwbGFjZW1lbnQ9IlxcMSIpCnBEYXRhKHBhMTRfZXhwdClbWyJpbml0aWFscyJdXSA8LSBhcy5mYWN0b3IoaW5pdGlhbHNfZmFjdG9yKQpzdHJhaW5fbWVkaWEgPC0gcGFzdGUwKHBEYXRhKHBhMTRfZXhwdClbWyJzdHJhaW5zIl1dLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgcERhdGEocGExNF9leHB0KVtbIm1lZGlhIl1dKQpwRGF0YShwYTE0X2V4cHQpW1sic3RyYWluX21lZGlhIl1dIDwtIHN0cmFpbl9tZWRpYQoKIyMgTGV0cyBzZXQgc29tZSBjb2xvcnMKIyMgV1Q6IGdyYXlzY2FsZSwgZWRhOiBibHVlLCBlZGQ6IGdyZWVuLCBnY2Q6IHB1cnBsZSwgcGdsOiByZWQsIHp3ZjogeWVsbG93CmNvbG9yc19ieV9zdHJhaW4gPC0gbGlzdCgKICAgICJQQTE0IFdUIiA9ICIjMDAwMDAwIiwKICAgICJQQTE0IGVkYSIgPSAiIzAwMDBkZCIsCiAgICAiUEExNCBlZGQiID0gIiMwMGRkMDAiLAogICAgIlBBMTQgZ2NkIiA9ICIjZGQwMGRkIiwKICAgICJQQTE0IHBnbCIgPSAiI2RkMDAwMCIsCiAgICAiUEExNCB6d2YiID0gIiNkZGRkMDAiKQoKaW5mZWN0X21ldGFib2xpc20gPC0gc3Vic2V0X2V4cHQocGExNF9leHB0LCBzdWJzZXQ9ImluaXRpYWxzPT0nU00nIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0PSJzdHJhaW5zIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0PSJtZWRpYSIpCnBsb3RfbGVnZW5kKGluZmVjdF9tZXRhYm9saXNtKQoKbWV0YWJvbGlzbV9jb250cm9sIDwtIHN1YnNldF9leHB0KGluZmVjdF9tZXRhYm9saXNtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0PSJtZWRpYT09J0xCJ3xtZWRpYT09J0xCICsgMC41IE0gdXJlYSciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9Im1lZGlhIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcygiYmlvcmVwbGljYXRlIikKCm1ldGFib2xpc21fc3RhcnZhdGlvbiA8LSBzdWJzZXRfZXhwdChpbmZlY3RfbWV0YWJvbGlzbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldD0ibWVkaWE9PSdQQlNUJ3xtZWRpYT09J01pY2UgVXJpbmUnIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycz1jb2xvcnNfYnlfc3RyYWluKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9Im1lZGlhIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0PSJzdHJhaW5zIikKCm1ldGFib2xpc21fc3RhcnZhdGlvbl9zdHJhaW4gPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtZXRhYm9saXNtX3N0YXJ2YXRpb24sIGZhY3Q9InN0cmFpbnMiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9Im1lZGlhIikKCm1ldGFib2xpc21fZXh1ZGF0ZSA8LSBzdWJzZXRfZXhwdChpbmZlY3RfbWV0YWJvbGlzbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldD0ibWVkaWE9PSdNaWNlIGluc3RpbGVkJyIpCmBgYAoKIyMgR2xhbmNlIGF0IHRoZXNlIDQgc3Vic2V0cwoKQXMgYSB3aG9sZSBncm91cCwgdGhlc2Ugc2FtcGxlcyBhcmUgYSBiaXQgY29uZnVzaW5nLiAgVGhlIG1vdXNlCmluc3RpbGVkIHNhbXBsZXMgYXJlIHByZXR5IG9idmlvdXMsIGJ1dCB0aGUgb3RoZXIgc291cmNlcyBvZiB2YXJpYW5jZQpyZW1haW4gYSBiaXQgb2YgYSBteXN0ZXJ5IHRvIG1lLgoKYGBge3IgbWV0YWJvbGlzbV9zdWJzZXRzfQpnbG9iYWxfbm9ybSA8LSBub3JtYWxpemVfZXhwdChpbmZlY3RfbWV0YWJvbGlzbSwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgdHJhbnNmb3JtPSJsb2cyIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0PSJtZWRpYSIpCnBsb3RfcGNhKGdsb2JhbF9ub3JtKSRwbG90Cgp0bXAgPC0gZ2xvYmFsX25vcm0gJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0PSJzdHJhaW5zIikKcGxvdF9wY2EodG1wKSRwbG90CmBgYAoKIyBUaGUgc21hbGxlc3QgZXhwZXJpbWVudDogTEIgdnMuIExCK3VyZWEKClRoaXMgaXMgYSBncm91cCBvZiA2IHNhbXBsZXMsIDMgaW4gTEIgYW5kIHRocmVlIGluIExCK3VyZWEuICBUaGlzCnNob3VsZCB0aGVyZWZvcmUgYmUgdGhlIG1vc3Qgc3RyYWlnaHQgZm9yd2FyZCBjb21wYXJpc29uLgoKYGBge3IgY29udHJvbH0KbWNfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtZXRhYm9saXNtX2NvbnRyb2wsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSkKcGxvdF9wY2EobWNfbm9ybSkkcGxvdApgYGAKCiMjIE1ldGFib2xpc20gY29udHJvbCBleHBlcmltZW50LCBERQoKYGBge3IgbWNfZGV9Cm1jX3NhbiA8LSBzYW5pdGl6ZV9leHB0KG1ldGFib2xpc21fY29udHJvbCkKbWNfZGUgPC0gYWxsX3BhaXJ3aXNlKG1jX3NhbiwgbW9kZWxfYmF0Y2g9VFJVRSwgZmlsdGVyPVRSVUUpCm1jX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIG1jX2RlLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbWV0YWJvbGlzbV9jb250cm9sX3RhYmxlcy12e3Zlcn0ueGxzeCIpLAogICAgc2lnX2V4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21ldGFib2xpc21fY29udHJvbF9zaWctdnt2ZXJ9Lnhsc3giKSkKYGBgCgpobW0sIGlzIHRoZXJlIGFueSBjaGFuY2UgdGhhdCBTTTAwMSBhbmQgU00wMDUgYXJlIGZsaXBwZWQ/ICBJZiB0aGV5CndlcmUsIHRoZW4gYm90aCBjbGFkZXMgd291bGQgaGF2ZSAxIG9mIGVhY2ggYmlvcmVwbGljYXRlLgoKIyBTdGFydmluZyBzdHJhaW5zCgpUaGUgc2Vjb25kIGdyb3VwIGlzIGEgbGl0dGxlIG1vcmUgY29tcGxleCwgaXQgc2Vla3MgdG8gc2ltdWx0YW5lb3VzbHkKY29tcGFyZSB0aGUgc3RyYWlucyAoV1QgdnMuIG11dGFudHMpIGFuZCB0aGUgZW52aXJvbm1lbnQgKFBCUwp2cy4gdXJpbmUpLgoKVGhpcyBkZXNpZ24gaXMgY29tcGxleCBlbm91Z2ggdGhhdCBJIHRoaW5rIHdlIG5lZWQgdG8gY2hvb3NlIGNvbG9ycwptb3JlIGNhcmVmdWxseS4KCmBgYHtyIHN0YXJ2aW5nX3N0cmFpbnN9Cm1zX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobWV0YWJvbGlzbV9zdGFydmF0aW9uLCBmaWx0ZXI9VFJVRSwgbm9ybT0icXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKG1zX25vcm0pJHBsb3QKCm1zX2RlIDwtIGFsbF9wYWlyd2lzZShtZXRhYm9saXNtX3N0YXJ2YXRpb24sIG1vZGVsX2JhdGNoPVRSVUUpCm1zX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIG1zX2RlLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbWV0YWJvbGlzbV9zdGFydmF0aW9uX3RhYmxlcy12e3Zlcn0ueGxzeCIpLAogICAgc2lnX2V4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21ldGFib2xpc21fc3RhcnZhdGlvbl9zaWctdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIE1ldGFib2xpc20gU3RhcnZhdGlvbiBHTwoKYGBge3IgbXNfZ299Cm1zX3VwIDwtIG1zX3RhYmxlc1tbInNpZ25pZmljYW50Il1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQptc19kb3duIDwtIG1zX3RhYmxlc1tbInNpZ25pZmljYW50Il1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dCgojIyBUaGUgZ28gZGF0YSBmcm9tIG1pY3JvYmVzb25saW5lIGlzIGtleWVkIGJ5IHRoZSBnZW5lIG5hbWUKIyMgKGUuZy4gZG5hQSksIG5vdCBnZW5lIElEIG9yIFBBIGlkIG9yIHdoYXRldmVyLgpwYTE0X2xlbmd0aHMgPC0gcGExNF9hbm5vdFssIGMoIm5hbWUueCIsICJ3aWR0aCIpXQpjb2xuYW1lcyhwYTE0X2xlbmd0aHMpIDwtIGMoIklEIiwgIndpZHRoIikKCnJvd25hbWVzKG1zX3VwKSA8LSBtYWtlLm5hbWVzKG1zX3VwW1sibmFtZXgiXV0sIHVuaXF1ZT1UUlVFKQptc191cF9nb3NlcSA8LSBzaW1wbGVfZ29zZXEobXNfdXAsIGdvX2RiPXBhMTRfZ28sIGxlbmd0aF9kYj1wYTE0X2xlbmd0aHMpCm1zX3VwX2dvc2VxW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQptc191cF9nb3NlcVtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCnJvd25hbWVzKG1zX2Rvd24pIDwtIG1ha2UubmFtZXMobXNfZG93bltbIm5hbWV4Il1dLCB1bmlxdWU9VFJVRSkKbXNfZG93bl9nb3NlcSA8LSBzaW1wbGVfZ29zZXEobXNfZG93biwgZ29fZGI9cGExNF9nbywgbGVuZ3RoX2RiPXBhMTRfbGVuZ3RocykKbXNfZG93bl9nb3NlcVtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KbXNfZG93bl9nb3NlcVtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KYGBgCgojIyBDb21wYXJlIHN0cmFpbnMKClRoaXMgdGltZSBsZXQgdXMgY29tcGFyZSB0aGUgc3RyYWlucyBhbmQgbG93ZXIgdGhlIHZhcmlhbmNlIGZyb20KbWVkaWEuCgpgYGB7ciBzdGFydmF0aW9uX2J5X3N0cmFpbn0KbXNzX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobWV0YWJvbGlzbV9zdGFydmF0aW9uX3N0cmFpbiwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKG1zc19ub3JtKSRwbG90Cgptc3NfdXJpbmUgPC0gc3Vic2V0X2V4cHQobWV0YWJvbGlzbV9zdGFydmF0aW9uX3N0cmFpbiwgc3Vic2V0PSJiYXRjaD09J01pY2UgVXJpbmUnIikKCmludGVyZXN0aW5nIDwtIGxpc3QoCiAgICAiZWRhX3ZzX3d0IiA9IGMoIlBBMTRlZGEiLCAiUEExNFdUIiksCiAgICAiZWRkX3ZzX3d0IiA9IGMoIlBBMTRlZGQiLCAiUEExNFdUIiksCiAgICAiZ2NkX3ZzX3d0IiA9IGMoIlBBMTRnY2QiLCAiUEExNFdUIiksCiAgICAicGdsX3ZzX3d0IiA9IGMoIlBBMTRwZ2wiLCAiUEExNFdUIiksCiAgICAiemZ3X3ZzX3d0IiA9IGMoIlBBMTR6d2YiLCAiUEExNFdUIikpCgptc3NfdXJpbmVfZGUgPC0gYWxsX3BhaXJ3aXNlKG1zc191cmluZSwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQoKbXNzX3VyaW5lX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbXNzX3VyaW5lX2RlLCBrZWVwZXJzPWludGVyZXN0aW5nLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbWV0YWJvbGlzbV9zdGFydmF0aW9uX3N0cmFpbl90YWJsZXMtdnt2ZXJ9Lnhsc3giKSwKICAgIHNpZ19leGNlbD1nbHVlOjpnbHVlKCJleGNlbC9tZXRhYm9saXNtX3N0YXJ2YXRpb25fc3RyYWluX3NpZy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgRXh1ZGF0ZQoKQ29tYXByZSB0aGUgc3RyYWlucyBkdXJpbmcgdGhlIGluc3RpbGxhdGlvbiBwcm9jZXNzCgpgYGB7ciBleHVkYXRlX2V4cGVyaW1lbnR9CmV4dWRhdGVfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtZXRhYm9saXNtX2V4dWRhdGUsIGZpbHRlcj1UUlVFLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCB0cmFuc2Zvcm09ImxvZzIiKQpwbG90X3BjYShleHVkYXRlX25vcm0pJHBsb3QKYGBgCgojIyBFeHVkYXRlIERFCgpgYGB7ciBleHVkYXRlX2RlfQpleHVkYXRlX2RlIDwtIGFsbF9wYWlyd2lzZShtZXRhYm9saXNtX2V4dWRhdGUsIG1vZGVsX2JhdGNoPVRSVUUsIGZpbHRlcj1UUlVFKQoKZXh1ZGF0ZV90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBleHVkYXRlX2RlLCBrZWVwZXJzPWludGVyZXN0aW5nLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvZXh1ZGF0ZV90YWJsZXMtdnt2ZXJ9Lnhsc3giKSwKICAgIHNpZ19leGNlbD1nbHVlOjpnbHVlKCJleGNlbC9leHVkYXRlX3NpZy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgQ2hlY2sgbW91c2UgY291bnRzCgpgYGB7ciBtb3VzZV9jb3VudHN9Cm1tX2V4cHQgPC0gY3JlYXRlX2V4cHQoInNhbXBsZV9zaGVldHMvYWxsX3NhbXBsZXNfbW9kaWZpZWQyLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1wYTE0X2Fubm90LCBmaWxlX2NvbHVtbj0ibW91c2V0YWJsZSIpCnBsb3RfbGlic2l6ZShtbV9leHB0KSRwbG90CmBgYAoKCmBgYHtyIHNhdmVtZSwgZXZhbD1GQUxTRX0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCnRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCm1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZT10aGlzX3NhdmUpKQpgYGAK