1 Libraries Setup

2 Introduction

This is my (atb) first time making any changes to this document. My goals are:

  1. Understand a little better about what is going on in the experiment.
  2. Set the colors for the entire document explicitly.
  3. Add some little extra gene set enrichment/overrepresentation.

my current understanding of the experiment is that RNA was collected from white adipose tissue from strains of mice which were iron deficient (by diet) and strains with an adipose specific knockout of TfR1. In addition, some mice were treated with a mimic of long-term cold stress.

Thus the categories of note:

  • IAD-Saline: Sufficient iron treated with saline (control)
  • IAD-CL: Sufficient iron treated with the cold agonist (CL-316243)
  • IDD-Saline: Deficient iron treated with saline
  • IDD-CL: Deficient iron treated with cold agonist

In the set of figures I see that the original colors were:

IAD-Saline: #808080 IAD-CL: #8a4412 IDD-Saline: #aed8e4 IDD-CL: #6592ef

2.1 Changelog

  • hard-coded the year/month for downloading annotations (atb)
  • removed Theresa’s notes as per Najib’s request
  • minor formatting changes while I read

2.2 Updates

  • CL versus Saline after adjusting for diet effects
  • Added IDD_Saline - IAD_Saline / IDD_CL - IAD_CL contrast
  • Added IDD_Saline-IDD_CL / IAD_Saline-IAD_CL contrast

3 M. musculus

3.1 Annotations

I am using mm38_100.

mm_annot <- load_biomart_annotations(species = "mmusculus", year = "2023", month = "07")
## Using mart: ENSEMBL_MART_ENSEMBL from host: jul2023.archive.ensembl.org.
## Successfully connected to the mmusculus_gene_ensembl database.
## Finished downloading ensembl gene annotations.
## Finished downloading ensembl structure annotations.
## symbol columns is null, pattern matching 'symbol'.
## Including symbols, there are 57550 vs the 149547 gene annotations.
## Not dropping haplotype chromosome annotations, set drop_haplotypes = TRUE if this is bad.
## Saving annotations to mmusculus_biomart_annotations.rda.
## Finished save().
mm_annot <- mm_annot[["annotation"]]
mm_annot[["txid"]] <- paste0(mm_annot[["ensembl_transcript_id"]], ".", mm_annot[["version"]])
rownames(mm_annot) <- make.names(mm_annot[["ensembl_gene_id"]], unique = TRUE)
tx_gene_map <- mm_annot[, c("txid", "ensembl_gene_id")]

3.2 Colors

color_choices <- list(
  "IAD-Saline" = "#808080",
  "IAD-CL" = "#8a4412",
  "IDD-Saline" = "#aed8e4",
  "IDD-CL" = "#6592ef")

So, I now have a table of mouse annotations.

3.3 Hisat2 expressionset

The sample sheet is called ‘Experimental_design_Kim_v1.0.xlsx’ and has a column to point to the names of the count tables to load. Here I combine the metadata, count data, and annotations.

hisat_annot <- mm_annot
##rownames(hisat_annot) <- paste0("gene:", rownames(hisat_annot))
mm38_hisat <- create_expt("sample_sheets/Experimental_design_Kim_v1.0.xlsx",
                          gene_info = hisat_annot) %>%
  set_expt_colors(color_choices) %>%
  sanitize_expt_pData(columns = "treatment", spaces = TRUE)
## Reading the sample metadata.
## Did not find the column: sampleid.
## Setting the ID column to the first column.
## Checking the state of the condition column.
## Checking the state of the batch column.
## Checking the condition factor.
## The sample definitions comprises: 16 rows(samples) and 23 columns(metadata fields).
## Matched 25583 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 25760 features and 16 samples.
plot_legend(mm38_hisat)
## The colors used in the expressionset are: #aed8e4, #6592ef, #808080, #8a4412.

4 Summary Plots

plot_libsize(mm38_hisat)
## Library sizes of 16 samples, 
## ranging from 30,859,887 to 60,727,032.

plot_nonzero(mm38_hisat)
## The following samples have less than 16744 genes.
##  [1] "5214_S1"   "3740_S3"   "3750_S4"   "3772_S5"   "3774_S6"   "3775_S7"  
##  [7] "3766_S9"   "3767_S10"  "3742_S12"  "3747_S13"  "3741b_S14"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
## A non-zero genes plot of 16 samples.
## These samples have an average 48.73 CPM coverage and 16621 genes observed, ranging from 16058 to
## 17079.

5 Normalize Expression

First we will filter out the genes which have low counts across all samples. Then I will normalize without background correction (it was determined there is no need for adjusting for background noise after evaluating the SVA correction).

mm38_filt <- normalize_expt(mm38_hisat, filter = TRUE)
## Removing 13318 low-count genes (12442 remaining).
mm38_norm <- normalize_expt(mm38_filt, convert = "cpm", norm = "quant", transform = "log2")
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
mm38_nb <- normalize_expt(mm38_hisat, filter = TRUE, convert = "cpm",
                          transform = "log2", batch = "svaseq")
## Removing 13318 low-count genes (12442 remaining).
## Setting 128 low elements to zero.
## transform_counts: Found 128 values equal to 0, adding 1 to the matrix.

6 PCA

pca_norm <- plot_pca(mm38_norm, plot_labels = FALSE)
pca_norm
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by IDD-Saline, IDD-CL, IAD-Saline, IAD-CL
## Shapes are defined by 1, 2.

pca_sva <- plot_pca(mm38_nb)
pca_sva
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by IDD-Saline, IDD-CL, IAD-Saline, IAD-CL
## Shapes are defined by 1, 2.

plot_meta_sankey(mm38_hisat, factors = c("diet", "treatment", "batchnumber"))
## A sankey plot describing the metadata of 16 samples,
## including 14 out of 0 nodes and traversing metadata factors:
## .

7 Tables for Number of Samples

How many samples do we have currently for each group?

table(pData(mm38_hisat)[,c( "diet", "treatment")])
##      treatment
## diet  cl salinevehicle
##   IAD  4             4
##   IDD  5             3

8 Differential Expression Analysis

In the conditions column, we have IDD-Saline, IDD-CL, IAD-Saline, and IAD-CL. For the differential expression analysis, we will perform the following contrasts:

Normal Pairwise Contrasts:

  • IDD-CL vs IDD-Saline
  • IAD-CL vs IAD-Saline
  • IDD-CL vs IAD-CL
  • IDD-Saline vs IAD-Saline

Contrasts after adjustment:

  • CL versus Saline after adjusting for diet
  • IDD versus IAD after adjusting for CL/Saline treatment

I will conduct these contrasts below and provide a volcano plot (both interactive and static), as well as a searchable table of the significant DE results for each contrast.

mm_de_normal <- all_pairwise(mm38_filt, do_ebseq = FALSE,
                             model_batch = "svaseq", parallel = FALSE)
## 
## IDD-Saline     IDD-CL IAD-Saline     IAD-CL 
##          3          5          4          4
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Warning in createContrastL(objFlt$formula, objFlt$data, L): Contrasts with only
## a single non-zero term are already evaluated by default.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
mm_de_normal
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 15 comparisons.
keepers <- list("IDDCL_vs_IADCL" = c("IDDCL", "IADCL"),
                "IDDSaline_vs_IADSaline" = c("IDDSaline", "IADSaline"),
                "IDDSaline_vs_IDDCL" = c("IDDSaline", "IDDCL"),
                "IADSaline_vs_IADCL" = c("IADSaline", "IADCL"))
mm_de_tables <- combine_de_tables(mm_de_normal, excel="excel/DE_20221003.xlsx",
                                  keepers = keepers, label_column = "mgi_symbol")
mm_de_tables
## A set of combined differential expression results.
##                    table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1         IDDCL_vs_IADCL         132           115         142           117
## 2 IDDSaline_vs_IADSaline          48            55          53            58
## 3     IDDSaline_vs_IDDCL           4            27           5            40
## 4     IADSaline_vs_IADCL          12             5          12             7
##   limma_sigup limma_sigdown
## 1          84            71
## 2          15             7
## 3           0             0
## 4           1             0
## Plot describing unique/shared genes in a differential expression table.

mm_de_sig <- extract_significant_genes(mm_de_tables,
                                       excel = "excel/DE_sig_20221003.xlsx",
                                       according_to = "deseq")
mm_de_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##                        deseq_up deseq_down
## IDDCL_vs_IADCL              132        115
## IDDSaline_vs_IADSaline       48         55
## IDDSaline_vs_IDDCL            4         27
## IADSaline_vs_IADCL           12          5

res_tbls <- c()
for (t in seq_along(keepers)) {
  tbl <- names(keepers)[t]
  deseq_tbl <- mm_de_normal$deseq$all_tables[[tbl]]
  res_tbls[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls[[tbl]] <- set_sig_limma(res_tbls[[tbl]],
                                   factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                               paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls[[tbl]],
                                                      title = paste("Volcano Plot:", tbl),
                                                      type = "plotly",
                                                      tbl = "limma",
                                                      gene_name_col = "external_gene_name")
  res_tbls[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls[[tbl]],
                                                      title = paste("Volcano Plot:", tbl),
                                                      tbl = "limma")
}

8.0.1 Provide a few svg volcano plots

8.0.1.1 IDDCL vs IADCL

mm_de_tables[["plots"]][["IDDCL_vs_IADCL"]][["deseq_vol_plots"]]

pp(file = "pdf/iddcl_vs_iadcl_volcano.pdf")
## Warning in pp(file = "pdf/iddcl_vs_iadcl_volcano.pdf"): The directory: pdf does
## not exist, will attempt to create it.
mm_de_tables[["plots"]][["IDDCL_vs_IADCL"]][["deseq_vol_plots"]]
dev.off()
## png 
##   2

8.0.1.2 IDDSaline vs IADSaline

mm_de_tables[["plots"]][["IDDSaline_vs_IADSaline"]][["deseq_vol_plots"]]

pp(file = "pdf/iddsaline_vs_iadsaline_volcano.pdf")
mm_de_tables[["plots"]][["IDDSaline_vs_IADSaline"]][["deseq_vol_plots"]]
dev.off()
## png 
##   2

8.0.1.3 IDDSaline_vs_IDDCL

mm_de_tables[["plots"]][["IDDSaline_vs_IDDCL"]][["deseq_vol_plots"]]

pp(file = "pdf/iddsaline_vs_iddcl_volcano.pdf")
mm_de_tables[["plots"]][["IDDSAline_vs_IDDCL"]][["deseq_vol_plots"]]
## NULL
dev.off()
## png 
##   2

8.0.1.4 IADSaline_vs_IADCL

mm_de_tables[["plots"]][["IADSaline_vs_IADCL"]][["deseq_vol_plots"]]
## Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pp(file = "pdf/iadsaline_vs_iadcl_volcano.pdf")
mm_de_tables[["plots"]][["IADSaline_vs_IADCL"]][["deseq_vol_plots"]]
dev.off()
## png 
##   2

8.1 IDD: CL vs Saline

Volcano Plot

res_tbls$IDDSaline_vs_IDDCLvolc_plotly

Table of Significant DE results

This table is significant results with adjusted p-value < 0.05 and log2FC greater than 0.5.

res_tbls$IDDSaline_vs_IDDCL %>%
  filter(abs(logFC) > 0.5 & adj.P.Val < 0.05) %>%
  arrange(desc(logFC)) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "logFC", "adj.P.Val", "Significance") %>%
  DT::datatable(rownames = FALSE)

GSEA

IDD_genes <- res_tbls$IDDSaline_vs_IDDCL %>%
  filter(abs(logFC) >= 0.5 & adj.P.Val <= 0.05) %>%
    arrange(desc(abs(logFC)))
IDD_gost <- gost(query = IDD_genes$ensembl_gene_id,
                organism = "mmusculus", ordered_query = TRUE,
                evcodes = TRUE)
#IDD Saline Enriched
IDD_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: IDD Significant GSEA")
IDD_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  datatable(rownames = FALSE, caption = "REAC: IDD Significant GSEA")
IDD_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "KEGG") %>%
  datatable(rownames = FALSE, caption = "KEGG: IDD Significant GSEA")
##### IDD Enriched
gostplot(IDD_gost, capped = FALSE, interactive = TRUE)

8.2 IAD: CL vs Saline

Volcano Plot

res_tbls$IADSaline_vs_IADCLvolc_plotly

Table of Significant DE results

res_tbls$IADSaline_vs_IADCL %>%
  filter(abs(logFC) > 0.5 & adj.P.Val < 0.05) %>%
  arrange(desc(logFC)) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "logFC", "adj.P.Val", "Significance") %>%
  DT::datatable(rownames = FALSE)

GSEA

IAD_genes <- res_tbls$IADSaline_vs_IADCL %>%
  filter(abs(logFC) >= 0.5 & adj.P.Val <= 0.05) %>%
    arrange(desc(abs(logFC)))
IAD_gost <- gost(query = IAD_genes$ensembl_gene_id,
                organism = "mmusculus", ordered_query = TRUE,
                evcodes = TRUE)
#IAD Saline Enriched
IAD_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: IAD Significant GSEA")
##### IAD Enriched
gostplot(IAD_gost, capped = FALSE, interactive = TRUE)

8.3 CL: IDD vs IAD

Volcano Plot

res_tbls$IDDCL_vs_IADCLvolc_plotly

Table of Significant DE results

res_tbls$IDDCL_vs_IADCL %>%
  filter(abs(logFC) > 0.5 & adj.P.Val < 0.05) %>%
  arrange(desc(logFC)) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "logFC", "adj.P.Val", "Significance") %>%
  DT::datatable(rownames = FALSE)

GSEA

CL_genes <- res_tbls$IDDCL_vs_IADCL %>%
  filter(abs(logFC) >= 0.5 & adj.P.Val <= 0.05) %>%
    arrange(desc(abs(logFC)))
CL_gost <- gost(query = CL_genes$ensembl_gene_id,
                organism = "mmusculus", ordered_query = TRUE,
                evcodes = TRUE)
#CL Saline Enriched
CL_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: CL Significant GSEA")
CL_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  datatable(rownames = FALSE, caption = "REAC: CL Significant GSEA")
CL_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "KEGG") %>%
  datatable(rownames = FALSE, caption = "KEGG: CL Significant GSEA")
##### CL Enriched
gostplot(CL_gost, capped = FALSE, interactive = TRUE)

8.4 Saline: IDD vs IAD

Volcano Plot

res_tbls$IDDSaline_vs_IADSalinevolc_plotly

Table of Significant DE results

res_tbls$IDDSaline_vs_IADSaline %>%
  filter(abs(logFC) > 1 & adj.P.Val < 0.05) %>%
  arrange(desc(logFC)) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "logFC", "adj.P.Val", "Significance") %>%
  DT::datatable(rownames = FALSE)

GSEA

Saline_genes <- res_tbls$IDDSaline_vs_IADSaline %>%
  filter(abs(logFC) >= 0.5 & adj.P.Val <= 0.05) %>%
    arrange(desc(abs(logFC)))
Saline_gost <- gost(query = Saline_genes$ensembl_gene_id,
                organism = "mmusculus", ordered_query = TRUE,
                evcodes = TRUE)
#CL Saline Enriched
Saline_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: Saline Significant GSEA")
Saline_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  datatable(rownames = FALSE, caption = "REAC: Saline Significant GSEA")
Saline_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "KEGG") %>%
  datatable(rownames = FALSE, caption = "KEGG: Saline Significant GSEA")
##### CL Enriched
gostplot(Saline_gost, capped = FALSE, interactive = TRUE)

9 Comparison Between Contrasts

9.1 CL versus Saline after adjusting for diet

countdata <- exprs(mm38_filt)
coldata <- colData(mm38_filt)
ddsMat <- DESeqDataSetFromMatrix(countData = countdata,
                                 colData = coldata,
                                 design = ~ diet + treatment)
## converting counts to integer mode
dds <- DESeq(ddsMat)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
res <- results(dds)
res <- merge(as.data.frame(res), hisat_annot, by = 0)
res <- res[!is.na(res$padj),]
res <- set_sig(res, factors = c("Saline \n Enriched", "CL \n Enriched"))
volc_plot(res_tbl = res, type = "plotly", title = "Saline versus CL after adjusting for Diet")
res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= 1) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "log2FoldChange", "padj", "Significance") %>%
  arrange(desc(log2FoldChange)) %>%
  datatable(rownames = FALSE)

10 Repeat the above in a slightly different fashion

all_pairwise() can do this too!

mm_diet_treatment <- set_expt_conditions(mm38_filt, fact = "diet") %>%
  set_expt_batches(fact = "treatment")
## The numbers of samples by condition are:
## 
## IAD IDD 
##   8   8
## The number of samples by batch are:
## 
##            cl salinevehicle 
##             9             7
mm_diet_treatment_de <- all_pairwise(mm_diet_treatment, model_batch = TRUE)
## 
## IAD IDD 
##   8   8 
## 
##            cl salinevehicle 
##             9             7
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Warning in createContrastL(objFlt$formula, objFlt$data, L): Contrasts with only
## a single non-zero term are already evaluated by default.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
mm_diet_treatment_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: batch in model/limma.
## The primary analysis performed 21 comparisons.
## The logFC agreement among the methods follows:
##                 IDD_vs_IAD
## basic_vs_deseq      0.8709
## basic_vs_dream      0.9748
## basic_vs_ebseq      0.9416
## basic_vs_edger      0.8938
## basic_vs_limma      0.9907
## basic_vs_noiseq     0.9741
## deseq_vs_dream      0.8856
## deseq_vs_ebseq      0.8923
## deseq_vs_edger      0.9966
## deseq_vs_limma      0.8627
## deseq_vs_noiseq     0.9118
## dream_vs_ebseq      0.9644
## dream_vs_edger      0.9083
## dream_vs_limma      0.9835
## dream_vs_noiseq     0.9819
## ebseq_vs_edger      0.9153
## ebseq_vs_limma      0.9492
## ebseq_vs_noiseq     0.9646
## edger_vs_limma      0.8861
## edger_vs_noiseq     0.9317
## limma_vs_noiseq     0.9668
mm_diet_treatment_table <- combine_de_tables(mm_diet_treatment_de, excel = "excel/DE_diet_treatment-table.xlsx",
                                        label_column = "mgi_symbol")
mm_diet_treatment_table
## A set of combined differential expression results.
##        table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup
## 1 IDD_vs_IAD          74            70          77            76          75
##   limma_sigdown
## 1            48
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

mm_diet_treatment_sig <- extract_significant_genes(mm_diet_treatment_table, excel = "excel/DE_diet_treatment-sig.xlsx")
mm_diet_treatment_sig
## A set of genes deemed significant according to limma, edger, deseq, ebseq, basic.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            limma_up limma_down edger_up edger_down deseq_up deseq_down ebseq_up
## IDD_vs_IAD       75         48       77         76       74         70       60
##            ebseq_down basic_up basic_down
## IDD_vs_IAD         36      779          0

GSEA

adj_genes <- res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= 1) %>%
    arrange(desc(abs(log2FoldChange)))
adj_gost <- gost(query = adj_genes$ensembl_gene_id,
                organism = "mmusculus", ordered_query = TRUE,
                evcodes = TRUE)
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: Adjusted for Diet Significant GSEA")
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  datatable(rownames = FALSE, caption = "REAC: Adjusted for Diet Significant GSEA")
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "KEGG") %>%
  datatable(rownames = FALSE, caption = "KEGG: Adjusted for Diet Significant GSEA")
##### CL Enriched
gostplot(adj_gost, capped = FALSE, interactive = TRUE)
library(openxlsx)
res_df <- res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= 0.5) %>%
    arrange(desc(log2FoldChange)) %>%
    select(-Row.names, -lfcSE, -stat, -pvalue, -ensembl_gene_id, -version, -transcript_version, -mgi_symbol)
openxlsx::write.xlsx(res_df, file = "excel/adjdiet_DE.xlsx")

10.1 IDD versus IAD after adjusting for treatment

countdata <- exprs(mm38_filt)
coldata <- colData(mm38_filt)
ddsMat <- DESeqDataSetFromMatrix(countData = countdata,
                                 colData = coldata,
                                 design = ~ treatment + diet)
## converting counts to integer mode
dds <- DESeq(ddsMat)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
res <- results(dds)
res <- merge(as.data.frame(res), hisat_annot, by = 0)
res <- res[!is.na(res$padj),]
res <- set_sig(res, factors = c("IDD \n Enriched", "IAD \n Enriched"))
volc_plot(res_tbl = res, type = "plotly", title = "IDD versus IAD after adjusting for Treatment")
res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= 1) %>%
  select("ensembl_gene_id", "mgi_symbol", "description", "log2FoldChange", "padj", "Significance") %>%
  arrange(desc(log2FoldChange)) %>%
  datatable(rownames = FALSE)
mm_treatment_diet <- set_expt_conditions(mm38_filt, fact = "treatment") %>%
  set_expt_batches(fact = "diet")
## The numbers of samples by condition are:
## 
##            cl salinevehicle 
##             9             7
## The number of samples by batch are:
## 
## IAD IDD 
##   8   8
mm_treatment_diet_de <- all_pairwise(mm_treatment_diet, model_batch = TRUE)
## 
##            cl salinevehicle 
##             9             7 
## 
## IAD IDD 
##   8   8
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Warning in createContrastL(objFlt$formula, objFlt$data, L): Contrasts with only
## a single non-zero term are already evaluated by default.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
mm_treatment_diet_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: batch in model/limma.
## The primary analysis performed 21 comparisons.
## The logFC agreement among the methods follows:
##                 slnvhcl_v_
## basic_vs_deseq      0.8454
## basic_vs_dream      0.9393
## basic_vs_ebseq      0.8910
## basic_vs_edger      0.8614
## basic_vs_limma      0.9733
## basic_vs_noiseq     0.9469
## deseq_vs_dream      0.9152
## deseq_vs_ebseq      0.9611
## deseq_vs_edger      0.9974
## deseq_vs_limma      0.8734
## deseq_vs_noiseq     0.8917
## dream_vs_ebseq      0.9492
## dream_vs_edger      0.9304
## dream_vs_limma      0.9609
## dream_vs_noiseq     0.9742
## ebseq_vs_edger      0.9709
## ebseq_vs_limma      0.9025
## ebseq_vs_noiseq     0.9400
## edger_vs_limma      0.8871
## edger_vs_noiseq     0.9086
## limma_vs_noiseq     0.9272
mm_treatment_diet_table <- combine_de_tables(mm_treatment_diet_de, excel = "excel/DE_treatment_diet-table.xlsx",
                                        label_column = "mgi_symbol")
mm_treatment_diet_table
## A set of combined differential expression results.
##                 table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 salinevehicle_vs_cl          70            27          80            27
##   limma_sigup limma_sigdown
## 1           1            26
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

mm_treatment_diet_sig <- extract_significant_genes(mm_treatment_diet_table, excel = "excel/DE_treatment_diet-sig.xlsx")
mm_treatment_diet_sig
## A set of genes deemed significant according to limma, edger, deseq, ebseq, basic.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##                     limma_up limma_down edger_up edger_down deseq_up deseq_down
## salinevehicle_vs_cl        1         26       80         27       70         27
##                     ebseq_up ebseq_down basic_up basic_down
## salinevehicle_vs_cl        5         11        0          0

GSEA

adj_genes <- res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= 1) %>%
    arrange(desc(abs(log2FoldChange)))
adj_gost <- gost(query = adj_genes$ensembl_gene_id,
                organism = "mmusculus",
                ordered_query = TRUE,
                evcodes = TRUE)
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  datatable(rownames = FALSE, caption = "GO: Diet after Adjusted for Treatment Significant GSEA")
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  datatable(rownames = FALSE, caption = "REAC: Diet after Adjusted for Treatment Significant GSEA")
adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "KEGG") %>%
  datatable(rownames = FALSE, caption = "KEGG: Diet after Adjusted for Treatment Significant GSEA")
##### CL Enriched
gostplot(adj_gost, capped = FALSE, interactive = TRUE)
gseaplot_GO_diet_adjtreat <- adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "GO:BP" | source == "GO:MF" | source == "GO:CC") %>%
  head(n = 10) %>%
    ggplot(aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity")+
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw()+
  ylab("") +
  xlab("GSEA Score")

gseaplot_REAC_diet_adjtreat <- adj_gost$result %>%
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) %>%
  arrange(desc(recall)) %>%
  filter(source == "REAC") %>%
  head(n = 10) %>%
    ggplot(aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity")+
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw()+
  ylab("") +
  xlab("GSEA Score")

gseaplot_GO_diet_adjtreat

gseaplot_REAC_diet_adjtreat

library(openxlsx)
res_df <- res %>%
  filter(padj < 0.05 & abs(log2FoldChange) >= .5) %>%
    arrange(desc(log2FoldChange)) %>%
    select(-Row.names, -lfcSE, -stat, -pvalue, -ensembl_gene_id, -version, -transcript_version, -hgnc_symbol)
openxlsx::write.xlsx(res_df, file = "excel/adjtreatment_DE.xlsx")

11 Perform gProfiler2/clusterProfiler representation/GSEA searches

I am going to use the three data structures I created in order to do the various GO/reactome/etc searches.

  • mm_de_sig
  • mm_diet_treatment_sig
  • mm_treatment_diet_sig

11.1 The 4 tables first: mm_de_sig

mm_de_gp <- all_gprofiler(mm_de_sig, species = "mmusculus")
## There are only, 4 returning null.
## There are only, 5 returning null.
iddcl_vs_iadcl_up_gp <- write_gprofiler_data(
  mm_de_gp[["IDDCL_vs_IADCL_up"]],
  excel = "excel/iddcl_vs_iadcl_up_gp.xlsx")
iddcl_vs_iadcl_down_gp <- write_gprofiler_data(
  mm_de_gp[["IDDCL_vs_IADCL_down"]],
  excel = "excel/iddcl_vs_iadcl_down_gp.xlsx")

iddsaline_vs_iadsaline_up_gp <- write_gprofiler_data(
  mm_de_gp[["IDDSaline_vs_IADSaline_up"]],
  excel = "excel/iddsaline_vs_iadsaline_up_gp.xlsx")
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
iddsaline_vs_iadsaline_down_gp <- write_gprofiler_data(
  mm_de_gp[["IDDSaline_vs_IADSaline_down"]],
  excel = "excel/iddsaline_vs_iadsaline_up_gp.xlsx")
## Deleting the file excel/iddsaline_vs_iadsaline_up_gp.xlsx before writing the tables.
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
iddsaline_vs_iddcl_up_gp <- write_gprofiler_data(
  mm_de_gp[["IDDSaline_vs_IDDCL_up"]],
  excel = "excel/iddsaline_vs_iddcl_up_gp.xlsx")
## Warning: Workbook does not contain any worksheets. A worksheet will be added.
iddsaline_vs_iddcl_down_gp <- write_gprofiler_data(
  mm_de_gp[["IDDSaline_vs_IDDCL_down"]],
  excel = "excel/iddsaline_vs_iddcl_down_gp.xlsx")
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?

The excel files created above have some pictures in them, but we can make some here as well…

11.1.1 Pictures of them

Najib like the tree plots the best, let us try that first.

iddcl_iadcl_up_tree <- enrichplot::pairwise_termsim(
  mm_de_gp[["IDDCL_vs_IADCL_up"]][["BP_enrich"]])
sm(enrichplot::treeplot(iddcl_iadcl_up_tree))

sm(enrichplot::dotplot(iddcl_iadcl_up_tree))

iddsaline_iadsaline_up_tree <- enrichplot::pairwise_termsim(
  mm_de_gp[["IDDSaline_vs_IADSaline_up"]][["BP_enrich"]])
sm(enrichplot::treeplot(iddsaline_iadsaline_up_tree))

sm(enrichplot::dotplot(iddsaline_iadsaline_up_tree))

iddsaline_iddcl_up_tree <- enrichplot::pairwise_termsim(
  mm_de_gp[["IDDSaline_vs_IDDCL_up"]][["BP_enrich"]])
## Error: unable to find an inherited method for function 'pairwise_termsim' for signature 'x = "NULL"'
sm(enrichplot::treeplot(iddcl_iadcl_up_tree))

sm(enrichplot::dotplot(iddcl_iadcl_up_tree))

11.2 Diet controlling for treatment

mm_diet_treatment_gp <- all_gprofiler(mm_diet_treatment_sig, species = "mmusculus")
mm_diet_treatment_up_gp <- write_gprofiler_data(
  mm_diet_treatment_gp[["IDD_vs_IAD_up"]],
  excel = "excel/mm_diet_treatment_idd_vs_iad_up_gp.xlsx")
mm_diet_treatment_down_gp <- write_gprofiler_data(
  mm_diet_treatment_gp[["IDD_vs_IAD_down"]],
  excel = "excel/mm_diet_treatment_idd_vs_iad_down_gp.xlsx")

And some plots!

idd_iad_up_tree <- enrichplot::pairwise_termsim(
  mm_diet_treatment_gp[["IDD_vs_IAD_up"]][["BP_enrich"]])
sm(enrichplot::treeplot(idd_iad_up_tree))

sm(enrichplot::dotplot(idd_iad_up_tree))

idd_iad_down_tree <- enrichplot::pairwise_termsim(
  mm_diet_treatment_gp[["IDD_vs_IAD_down"]][["BP_enrich"]])
sm(enrichplot::treeplot(idd_iad_down_tree))

sm(enrichplot::dotplot(idd_iad_down_tree))

idd_iad_up_tree <- enrichplot::pairwise_termsim(
  mm_diet_treatment_gp[["IDD_vs_IAD_up"]][["REAC_enrich"]])
sm(enrichplot::dotplot(idd_iad_up_tree))

idd_iad_down_tree <- enrichplot::pairwise_termsim(
  mm_diet_treatment_gp[["IDD_vs_IAD_down"]][["REAC_enrich"]])
sm(enrichplot::dotplot(idd_iad_down_tree))

11.3 Treatment controlling for diet

mm_treatment_diet_gp <- all_gprofiler(mm_treatment_diet_sig, species = "mmusculus")
mm_treatment_diet_up_gp <- write_gprofiler_data(
  mm_treatment_diet_gp[["IDD_vs_IAD_up"]],
  excel = "excel/mm_treatment_diet_idd_vs_iad_up_gp.xlsx")
## Warning: Workbook does not contain any worksheets. A worksheet will be added.
mm_treatment_diet_down_gp <- write_gprofiler_data(
  mm_treatment_diet_gp[["IDD_vs_IAD_down"]],
  excel = "excel/mm_treatment_diet_idd_vs_iad_down_gp.xlsx")
## Warning: Workbook does not contain any worksheets. A worksheet will be added.

And some plots!

saline_cl_up_tree <- enrichplot::pairwise_termsim(
  mm_treatment_diet_gp[["salinevehicle_vs_cl_up"]][["BP_enrich"]])
sm(enrichplot::treeplot(idd_iad_up_tree))

sm(enrichplot::dotplot(idd_iad_up_tree))

saline_cl_down_tree <- enrichplot::pairwise_termsim(
  mm_treatment_diet_gp[["salinevehicle_vs_cl_down"]][["BP_enrich"]])
sm(enrichplot::dotplot(idd_iad_down_tree))

12 and GSEA via clusterProfiler

mm_de_cp <- all_cprofiler(mm_de_sig, mm_de_tables, orgdb = "org.Mm.eg.db")
## Error in loadNamespace(orgdb): there is no package called 'org.Mm.eg.db'
iddcl_vs_iadcl_gsea <- plot_topn_gsea(mm_de_cp[["IDDCL_vs_IADCL_up"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'gse' in selecting a method for function 'plot_topn_gsea': object 'mm_de_cp' not found
iddcl_vs_iadcl_gsea[["GO"]][[1]]
## Error in eval(expr, envir, enclos): object 'iddcl_vs_iadcl_gsea' not found
enrichplot::dotplot(mm_de_cp[["IDDCL_vs_IADCL_up"]][["enrich_objects"]][["BP_all"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'dotplot': object 'mm_de_cp' not found
iddsaline_vs_iadsaline_gsea <- plot_topn_gsea(mm_de_cp[["IDDSaline_vs_IADSaline_up"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'gse' in selecting a method for function 'plot_topn_gsea': object 'mm_de_cp' not found
iddsaline_vs_iadsaline_gsea[["GO"]][[1]]
## Error in eval(expr, envir, enclos): object 'iddsaline_vs_iadsaline_gsea' not found
enrichplot::dotplot(mm_de_cp[["IDDSaline_vs_IADSaline_up"]][["enrich_objects"]][["BP_all"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'dotplot': object 'mm_de_cp' not found
iadsaline_vs_iadcl_gsea <- plot_topn_gsea(mm_de_cp[["IADSaline_vs_IADCL_up"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'gse' in selecting a method for function 'plot_topn_gsea': object 'mm_de_cp' not found
iadsaline_vs_iadcl_gsea[["GO"]][[1]]
## Error in eval(expr, envir, enclos): object 'iadsaline_vs_iadcl_gsea' not found
enrichplot::dotplot(mm_de_cp[["IADSaline_vs_IADCL_up"]][["enrich_objects"]][["BP_all"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'dotplot': object 'mm_de_cp' not found
enrichplot::dotplot(mm_de_cp[["IADSaline_vs_IADCL_down"]][["enrich_objects"]][["BP_all"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'dotplot': object 'mm_de_cp' not found
LS0tCnRpdGxlOiAnS2ltIExhYjogSUREIHYgSUFEIChBZGRlZCBHU0VBKScKYXV0aG9yOiAiVGhlcmVzYSBBbGV4YW5kZXIiCmRhdGU6ICIyMDIyLTA5LTI3IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgIHRvY19kZXB0aDogNQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHdpZHRoOiAzMDAKICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCiMgTGlicmFyaWVzIFNldHVwCgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJocGdsdG9vbHMiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgiZ2dyZXBlbCIpCmxpYnJhcnkoInBhdGNod29yayIpCmxpYnJhcnkoInBsb3RseSIpCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpCmxpYnJhcnkoIkRUIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJncHJvZmlsZXIyIikKbGlicmFyeSgiREVTZXEyIikKc291cmNlKCJoZWxwZXJfZnVuY3Rpb25zLlIiKQoKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLCB2ZXJib3NlID0gVFJVRSwgd2lkdGggPSA5MCwgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlcnJvciA9IFRSVUUsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4LCBmaWcucmV0aW5hID0gMiwKICBvdXQud2lkdGggPSAiMTAwJSIsIGRldiA9ICJwbmciLAogIGRldi5hcmdzID0gbGlzdChwbmcgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpKQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cyA9IDQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSkKdmVyIDwtIFN5cy5nZXRlbnYoIlZFUlNJT04iKQpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAiJVklbSVkIikKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBpcyBteSAoYXRiKSBmaXJzdCB0aW1lIG1ha2luZyBhbnkgY2hhbmdlcyB0byB0aGlzIGRvY3VtZW50LiAgTXkgZ29hbHMgYXJlOgoKMS4gIFVuZGVyc3RhbmQgYSBsaXR0bGUgYmV0dGVyIGFib3V0IHdoYXQgaXMgZ29pbmcgb24gaW4gdGhlIGV4cGVyaW1lbnQuCjIuICBTZXQgdGhlIGNvbG9ycyBmb3IgdGhlIGVudGlyZSBkb2N1bWVudCBleHBsaWNpdGx5LgozLiAgQWRkIHNvbWUgbGl0dGxlIGV4dHJhIGdlbmUgc2V0IGVucmljaG1lbnQvb3ZlcnJlcHJlc2VudGF0aW9uLgoKbXkgY3VycmVudCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBleHBlcmltZW50IGlzIHRoYXQgUk5BIHdhcyBjb2xsZWN0ZWQKZnJvbSB3aGl0ZSBhZGlwb3NlIHRpc3N1ZSBmcm9tIHN0cmFpbnMgb2YgbWljZSB3aGljaCB3ZXJlIGlyb24KZGVmaWNpZW50IChieSBkaWV0KSBhbmQgc3RyYWlucyB3aXRoIGFuIGFkaXBvc2Ugc3BlY2lmaWMga25vY2tvdXQgb2YKVGZSMS4gIEluIGFkZGl0aW9uLCBzb21lIG1pY2Ugd2VyZSB0cmVhdGVkIHdpdGggYSBtaW1pYyBvZiBsb25nLXRlcm0KY29sZCBzdHJlc3MuCgpUaHVzIHRoZSBjYXRlZ29yaWVzIG9mIG5vdGU6CgoqIElBRC1TYWxpbmU6IFN1ZmZpY2llbnQgaXJvbiB0cmVhdGVkIHdpdGggc2FsaW5lIChjb250cm9sKQoqIElBRC1DTDogU3VmZmljaWVudCBpcm9uIHRyZWF0ZWQgd2l0aCB0aGUgY29sZCBhZ29uaXN0IChDTC0zMTYyNDMpCiogSURELVNhbGluZTogRGVmaWNpZW50IGlyb24gdHJlYXRlZCB3aXRoIHNhbGluZQoqIElERC1DTDogRGVmaWNpZW50IGlyb24gdHJlYXRlZCB3aXRoIGNvbGQgYWdvbmlzdAoKSW4gdGhlIHNldCBvZiBmaWd1cmVzIEkgc2VlIHRoYXQgdGhlIG9yaWdpbmFsIGNvbG9ycyB3ZXJlOgoKSUFELVNhbGluZTogIzgwODA4MApJQUQtQ0w6ICM4YTQ0MTIKSURELVNhbGluZTogI2FlZDhlNApJREQtQ0w6ICM2NTkyZWYKCiMjIENoYW5nZWxvZwoKLSBoYXJkLWNvZGVkIHRoZSB5ZWFyL21vbnRoIGZvciBkb3dubG9hZGluZyBhbm5vdGF0aW9ucyAoYXRiKQotIHJlbW92ZWQgVGhlcmVzYSdzIG5vdGVzIGFzIHBlciBOYWppYidzIHJlcXVlc3QKLSBtaW5vciBmb3JtYXR0aW5nIGNoYW5nZXMgd2hpbGUgSSByZWFkCgojIyBVcGRhdGVzCgotIENMIHZlcnN1cyBTYWxpbmUgYWZ0ZXIgYWRqdXN0aW5nIGZvciBkaWV0IGVmZmVjdHMKLSBBZGRlZCBJRERfU2FsaW5lIC0gSUFEX1NhbGluZSAvIElERF9DTCAtIElBRF9DTCBjb250cmFzdAotIEFkZGVkIElERF9TYWxpbmUtSUREX0NMIC8gSUFEX1NhbGluZS1JQURfQ0wgY29udHJhc3QKCiMgTS4gbXVzY3VsdXMKCiMjIEFubm90YXRpb25zCgpJIGFtIHVzaW5nIG1tMzhfMTAwLgoKYGBge3J9Cm1tX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyhzcGVjaWVzID0gIm1tdXNjdWx1cyIsIHllYXIgPSAiMjAyMyIsIG1vbnRoID0gIjA3IikKCm1tX2Fubm90IDwtIG1tX2Fubm90W1siYW5ub3RhdGlvbiJdXQptbV9hbm5vdFtbInR4aWQiXV0gPC0gcGFzdGUwKG1tX2Fubm90W1siZW5zZW1ibF90cmFuc2NyaXB0X2lkIl1dLCAiLiIsIG1tX2Fubm90W1sidmVyc2lvbiJdXSkKcm93bmFtZXMobW1fYW5ub3QpIDwtIG1ha2UubmFtZXMobW1fYW5ub3RbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZSA9IFRSVUUpCnR4X2dlbmVfbWFwIDwtIG1tX2Fubm90WywgYygidHhpZCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KYGBgCgojIyBDb2xvcnMKCmBgYHtyfQpjb2xvcl9jaG9pY2VzIDwtIGxpc3QoCiAgIklBRC1TYWxpbmUiID0gIiM4MDgwODAiLAogICJJQUQtQ0wiID0gIiM4YTQ0MTIiLAogICJJREQtU2FsaW5lIiA9ICIjYWVkOGU0IiwKICAiSURELUNMIiA9ICIjNjU5MmVmIikKYGBgCgpTbywgSSBub3cgaGF2ZSBhIHRhYmxlIG9mIG1vdXNlIGFubm90YXRpb25zLgoKIyMgSGlzYXQyIGV4cHJlc3Npb25zZXQKClRoZSBzYW1wbGUgc2hlZXQgaXMgY2FsbGVkICdFeHBlcmltZW50YWxfZGVzaWduX0tpbV92MS4wLnhsc3gnIGFuZCBoYXMKYSBjb2x1bW4gdG8gcG9pbnQgdG8gdGhlIG5hbWVzIG9mIHRoZSBjb3VudCB0YWJsZXMgdG8gbG9hZC4KSGVyZSBJIGNvbWJpbmUgdGhlIG1ldGFkYXRhLCBjb3VudCBkYXRhLCBhbmQgYW5ub3RhdGlvbnMuCgpgYGB7cn0KaGlzYXRfYW5ub3QgPC0gbW1fYW5ub3QKIyNyb3duYW1lcyhoaXNhdF9hbm5vdCkgPC0gcGFzdGUwKCJnZW5lOiIsIHJvd25hbWVzKGhpc2F0X2Fubm90KSkKbW0zOF9oaXNhdCA8LSBjcmVhdGVfZXhwdCgic2FtcGxlX3NoZWV0cy9FeHBlcmltZW50YWxfZGVzaWduX0tpbV92MS4wLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGhpc2F0X2Fubm90KSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JfY2hvaWNlcykgJT4lCiAgc2FuaXRpemVfZXhwdF9wRGF0YShjb2x1bW5zID0gInRyZWF0bWVudCIsIHNwYWNlcyA9IFRSVUUpCgpwbG90X2xlZ2VuZChtbTM4X2hpc2F0KQpgYGAKCiMgU3VtbWFyeSBQbG90cwoKYGBge3J9CnBsb3RfbGlic2l6ZShtbTM4X2hpc2F0KQoKcGxvdF9ub256ZXJvKG1tMzhfaGlzYXQpCmBgYAoKIyBOb3JtYWxpemUgRXhwcmVzc2lvbgoKRmlyc3Qgd2Ugd2lsbCBmaWx0ZXIgb3V0IHRoZSBnZW5lcyB3aGljaCBoYXZlIGxvdyBjb3VudHMgYWNyb3NzIGFsbApzYW1wbGVzLiBUaGVuIEkgd2lsbCBub3JtYWxpemUgd2l0aG91dCBiYWNrZ3JvdW5kIGNvcnJlY3Rpb24gKGl0IHdhcwpkZXRlcm1pbmVkIHRoZXJlIGlzIG5vIG5lZWQgZm9yIGFkanVzdGluZyBmb3IgYmFja2dyb3VuZCBub2lzZSBhZnRlcgpldmFsdWF0aW5nIHRoZSBTVkEgY29ycmVjdGlvbikuCgpgYGB7cn0KbW0zOF9maWx0IDwtIG5vcm1hbGl6ZV9leHB0KG1tMzhfaGlzYXQsIGZpbHRlciA9IFRSVUUpCm1tMzhfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtbTM4X2ZpbHQsIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIsIHRyYW5zZm9ybSA9ICJsb2cyIikKbW0zOF9uYiA8LSBub3JtYWxpemVfZXhwdChtbTM4X2hpc2F0LCBmaWx0ZXIgPSBUUlVFLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBiYXRjaCA9ICJzdmFzZXEiKQpgYGAKCiMgUENBCgpgYGB7cn0KcGNhX25vcm0gPC0gcGxvdF9wY2EobW0zOF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQpwY2Ffbm9ybQoKcGNhX3N2YSA8LSBwbG90X3BjYShtbTM4X25iKQpwY2Ffc3ZhCmBgYAoKYGBge3J9CnBsb3RfbWV0YV9zYW5rZXkobW0zOF9oaXNhdCwgZmFjdG9ycyA9IGMoImRpZXQiLCAidHJlYXRtZW50IiwgImJhdGNobnVtYmVyIikpCmBgYAoKIyBUYWJsZXMgZm9yIE51bWJlciBvZiBTYW1wbGVzCgpIb3cgbWFueSBzYW1wbGVzIGRvIHdlIGhhdmUgY3VycmVudGx5IGZvciBlYWNoIGdyb3VwPwoKYGBge3J9CnRhYmxlKHBEYXRhKG1tMzhfaGlzYXQpWyxjKCAiZGlldCIsICJ0cmVhdG1lbnQiKV0pCmBgYAoKIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcyB7LnRhYnNldH0KCkluIHRoZSBjb25kaXRpb25zIGNvbHVtbiwgd2UgaGF2ZSBJREQtU2FsaW5lLCBJREQtQ0wsIElBRC1TYWxpbmUsIGFuZApJQUQtQ0wuIEZvciB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMsIHdlIHdpbGwgcGVyZm9ybSB0aGUKZm9sbG93aW5nIGNvbnRyYXN0czoKCioqTm9ybWFsIFBhaXJ3aXNlIENvbnRyYXN0czoqKgoKKiBJREQtQ0wgdnMgSURELVNhbGluZQoqIElBRC1DTCB2cyBJQUQtU2FsaW5lCiogSURELUNMIHZzIElBRC1DTAoqIElERC1TYWxpbmUgdnMgSUFELVNhbGluZQoKKipDb250cmFzdHMgYWZ0ZXIgYWRqdXN0bWVudDoqKgoKKiBDTCB2ZXJzdXMgU2FsaW5lIGFmdGVyIGFkanVzdGluZyBmb3IgZGlldAoqIElERCB2ZXJzdXMgSUFEIGFmdGVyIGFkanVzdGluZyBmb3IgQ0wvU2FsaW5lIHRyZWF0bWVudAoKSSB3aWxsIGNvbmR1Y3QgdGhlc2UgY29udHJhc3RzIGJlbG93IGFuZCBwcm92aWRlIGEgdm9sY2FubyBwbG90IChib3RoCmludGVyYWN0aXZlIGFuZCBzdGF0aWMpLCBhcyB3ZWxsIGFzIGEgc2VhcmNoYWJsZSB0YWJsZSBvZiB0aGUKc2lnbmlmaWNhbnQgREUgcmVzdWx0cyBmb3IgZWFjaCBjb250cmFzdC4KCmBgYHtyfQptbV9kZV9ub3JtYWwgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfZmlsdCwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBwYXJhbGxlbCA9IEZBTFNFKQptbV9kZV9ub3JtYWwKCmtlZXBlcnMgPC0gbGlzdCgiSUREQ0xfdnNfSUFEQ0wiID0gYygiSUREQ0wiLCAiSUFEQ0wiKSwKICAgICAgICAgICAgICAgICJJRERTYWxpbmVfdnNfSUFEU2FsaW5lIiA9IGMoIklERFNhbGluZSIsICJJQURTYWxpbmUiKSwKICAgICAgICAgICAgICAgICJJRERTYWxpbmVfdnNfSUREQ0wiID0gYygiSUREU2FsaW5lIiwgIklERENMIiksCiAgICAgICAgICAgICAgICAiSUFEU2FsaW5lX3ZzX0lBRENMIiA9IGMoIklBRFNhbGluZSIsICJJQURDTCIpKQptbV9kZV90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMobW1fZGVfbm9ybWFsLCBleGNlbD0iZXhjZWwvREVfMjAyMjEwMDMueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0ga2VlcGVycywgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiKQptbV9kZV90YWJsZXMKCm1tX2RlX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX2RlX3RhYmxlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSAiZXhjZWwvREVfc2lnXzIwMjIxMDAzLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKQptbV9kZV9zaWcKCnJlc190YmxzIDwtIGMoKQpmb3IgKHQgaW4gc2VxX2Fsb25nKGtlZXBlcnMpKSB7CiAgdGJsIDwtIG5hbWVzKGtlZXBlcnMpW3RdCiAgZGVzZXFfdGJsIDwtIG1tX2RlX25vcm1hbCRkZXNlcSRhbGxfdGFibGVzW1t0YmxdXQogIHJlc190YmxzW1t0YmxdXSA8LSBtZXJnZShkZXNlcV90YmwsIGhpc2F0X2Fubm90LCBieSA9ICJyb3cubmFtZXMiKQogIHJlc190YmxzW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzW1t0YmxdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JzID0gYyhwYXN0ZShnc3ViKCJcXF8uKiIsIiIsdGJsKSwgIlxuRW5yaWNoZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpKQogIHJlc190YmxzW1twYXN0ZTAodGJsLCAidm9sY19wbG90bHkiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc1tbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAiZXh0ZXJuYWxfZ2VuZV9uYW1lIikKICByZXNfdGJsc1tbcGFzdGUwKHRibCwgInZvbGNfZ2dwbG90IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIikKfQpgYGAKCiMjIyBQcm92aWRlIGEgZmV3IHN2ZyB2b2xjYW5vIHBsb3RzCgojIyMjIElERENMIHZzIElBRENMCgpgYGB7cn0KbW1fZGVfdGFibGVzW1sicGxvdHMiXV1bWyJJRERDTF92c19JQURDTCJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXQpwcChmaWxlID0gInBkZi9pZGRjbF92c19pYWRjbF92b2xjYW5vLnBkZiIpCm1tX2RlX3RhYmxlc1tbInBsb3RzIl1dW1siSUREQ0xfdnNfSUFEQ0wiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0KZGV2Lm9mZigpCmBgYAoKIyMjIyBJRERTYWxpbmUgdnMgSUFEU2FsaW5lCgpgYGB7cn0KbW1fZGVfdGFibGVzW1sicGxvdHMiXV1bWyJJRERTYWxpbmVfdnNfSUFEU2FsaW5lIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dCnBwKGZpbGUgPSAicGRmL2lkZHNhbGluZV92c19pYWRzYWxpbmVfdm9sY2Fuby5wZGYiKQptbV9kZV90YWJsZXNbWyJwbG90cyJdXVtbIklERFNhbGluZV92c19JQURTYWxpbmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0KZGV2Lm9mZigpCmBgYAoKIyMjIyBJRERTYWxpbmVfdnNfSUREQ0wKCmBgYHtyfQptbV9kZV90YWJsZXNbWyJwbG90cyJdXVtbIklERFNhbGluZV92c19JRERDTCJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXQpwcChmaWxlID0gInBkZi9pZGRzYWxpbmVfdnNfaWRkY2xfdm9sY2Fuby5wZGYiKQptbV9kZV90YWJsZXNbWyJwbG90cyJdXVtbIklERFNBbGluZV92c19JRERDTCJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXQpkZXYub2ZmKCkKYGBgCgojIyMjIElBRFNhbGluZV92c19JQURDTAoKYGBge3J9Cm1tX2RlX3RhYmxlc1tbInBsb3RzIl1dW1siSUFEU2FsaW5lX3ZzX0lBRENMIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dCnBwKGZpbGUgPSAicGRmL2lhZHNhbGluZV92c19pYWRjbF92b2xjYW5vLnBkZiIpCm1tX2RlX3RhYmxlc1tbInBsb3RzIl1dW1siSUFEU2FsaW5lX3ZzX0lBRENMIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dCmRldi5vZmYoKQpgYGAKCiMjIElERDogQ0wgdnMgU2FsaW5lCgoqKlZvbGNhbm8gUGxvdCoqCgpgYGB7cn0KcmVzX3RibHMkSUREU2FsaW5lX3ZzX0lERENMdm9sY19wbG90bHkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KI1RoaXMgaXMganVzdCBhIHN0YXRpYyB2ZXJzaW9uIG9mIHRoZSBwbG90IGFib3ZlCnJlc190YmxzJElERFNhbGluZV92c19JRERDTHZvbGNfZ2dwbG90CmBgYAoKKipUYWJsZSBvZiBTaWduaWZpY2FudCBERSByZXN1bHRzKioKClRoaXMgdGFibGUgaXMgc2lnbmlmaWNhbnQgcmVzdWx0cyB3aXRoIGFkanVzdGVkIHAtdmFsdWUgPCAwLjA1IGFuZApsb2cyRkMgZ3JlYXRlciB0aGFuICoqMC41KiouCgpgYGB7cn0KcmVzX3RibHMkSUREU2FsaW5lX3ZzX0lERENMICU+JQogIGZpbHRlcihhYnMobG9nRkMpID4gMC41ICYgYWRqLlAuVmFsIDwgMC4wNSkgJT4lCiAgYXJyYW5nZShkZXNjKGxvZ0ZDKSkgJT4lCiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAibWdpX3N5bWJvbCIsICJkZXNjcmlwdGlvbiIsICJsb2dGQyIsICJhZGouUC5WYWwiLCAiU2lnbmlmaWNhbmNlIikgJT4lCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCioqR1NFQSoqCgpgYGB7cn0KSUREX2dlbmVzIDwtIHJlc190YmxzJElERFNhbGluZV92c19JRERDTCAlPiUKICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAwLjUgJiBhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSkpCklERF9nb3N0IDwtIGdvc3QocXVlcnkgPSBJRERfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwgb3JkZXJlZF9xdWVyeSA9IFRSVUUsCiAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSkKYGBgCgpgYGB7cn0KI0lERCBTYWxpbmUgRW5yaWNoZWQKSUREX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJHTzpCUCIgfCBzb3VyY2UgPT0gIkdPOk1GIiB8IHNvdXJjZSA9PSAiR086Q0MiKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJHTzogSUREIFNpZ25pZmljYW50IEdTRUEiKQoKSUREX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJSRUFDIikgJT4lCiAgZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiUkVBQzogSUREIFNpZ25pZmljYW50IEdTRUEiKQoKSUREX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJLRUdHIikgJT4lCiAgZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiS0VHRzogSUREIFNpZ25pZmljYW50IEdTRUEiKQpgYGAKCmBgYHtyfQojIyMjIyBJREQgRW5yaWNoZWQKZ29zdHBsb3QoSUREX2dvc3QsIGNhcHBlZCA9IEZBTFNFLCBpbnRlcmFjdGl2ZSA9IFRSVUUpCmBgYAoKIyMgSUFEOiBDTCB2cyBTYWxpbmUKCioqVm9sY2FubyBQbG90KioKCmBgYHtyfQpyZXNfdGJscyRJQURTYWxpbmVfdnNfSUFEQ0x2b2xjX3Bsb3RseQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQojVGhpcyBpcyBqdXN0IGEgc3RhdGljIHZlcnNpb24gb2YgdGhlIHBsb3QgYWJvdmUKcmVzX3RibHMkSUFEU2FsaW5lX3ZzX0lBRENMdm9sY19nZ3Bsb3QKYGBgCgoqKlRhYmxlIG9mIFNpZ25pZmljYW50IERFIHJlc3VsdHMqKgoKYGBge3J9CnJlc190YmxzJElBRFNhbGluZV92c19JQURDTCAlPiUKICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+IDAuNSAmIGFkai5QLlZhbCA8IDAuMDUpICU+JQogIGFycmFuZ2UoZGVzYyhsb2dGQykpICU+JQogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgIm1naV9zeW1ib2wiLCAiZGVzY3JpcHRpb24iLCAibG9nRkMiLCAiYWRqLlAuVmFsIiwgIlNpZ25pZmljYW5jZSIpICU+JQogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgoqKkdTRUEqKgoKYGBge3J9CklBRF9nZW5lcyA8LSByZXNfdGJscyRJQURTYWxpbmVfdnNfSUFEQ0wgJT4lCiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMC41ICYgYWRqLlAuVmFsIDw9IDAuMDUpICU+JQogICAgYXJyYW5nZShkZXNjKGFicyhsb2dGQykpKQpJQURfZ29zdCA8LSBnb3N0KHF1ZXJ5ID0gSUFEX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsIG9yZGVyZWRfcXVlcnkgPSBUUlVFLAogICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUpCmBgYAoKYGBge3J9CiNJQUQgU2FsaW5lIEVucmljaGVkCklBRF9nb3N0JHJlc3VsdCAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgZmlsdGVyKHNvdXJjZSA9PSAiR086QlAiIHwgc291cmNlID09ICJHTzpNRiIgfCBzb3VyY2UgPT0gIkdPOkNDIikgJT4lCiAgZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiR086IElBRCBTaWduaWZpY2FudCBHU0VBIikKYGBgCgpgYGB7cn0KIyMjIyMgSUFEIEVucmljaGVkCmdvc3RwbG90KElBRF9nb3N0LCBjYXBwZWQgPSBGQUxTRSwgaW50ZXJhY3RpdmUgPSBUUlVFKQpgYGAKCiMjIENMOiBJREQgdnMgSUFECgoqKlZvbGNhbm8gUGxvdCoqCgpgYGB7cn0KcmVzX3RibHMkSUREQ0xfdnNfSUFEQ0x2b2xjX3Bsb3RseQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQojVGhpcyBpcyBqdXN0IGEgc3RhdGljIHZlcnNpb24gb2YgdGhlIHBsb3QgYWJvdmUKcmVzX3RibHMkSUREQ0xfdnNfSUFEQ0x2b2xjX2dncGxvdApgYGAKCioqVGFibGUgb2YgU2lnbmlmaWNhbnQgREUgcmVzdWx0cyoqCgpgYGB7cn0KcmVzX3RibHMkSUREQ0xfdnNfSUFEQ0wgJT4lCiAgZmlsdGVyKGFicyhsb2dGQykgPiAwLjUgJiBhZGouUC5WYWwgPCAwLjA1KSAlPiUKICBhcnJhbmdlKGRlc2MobG9nRkMpKSAlPiUKICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJtZ2lfc3ltYm9sIiwgImRlc2NyaXB0aW9uIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIsICJTaWduaWZpY2FuY2UiKSAlPiUKICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKKipHU0VBKioKCmBgYHtyfQpDTF9nZW5lcyA8LSByZXNfdGJscyRJRERDTF92c19JQURDTCAlPiUKICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAwLjUgJiBhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSkpCkNMX2dvc3QgPC0gZ29zdChxdWVyeSA9IENMX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsIG9yZGVyZWRfcXVlcnkgPSBUUlVFLAogICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUpCmBgYAoKYGBge3J9CiNDTCBTYWxpbmUgRW5yaWNoZWQKQ0xfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIkdPOkJQIiB8IHNvdXJjZSA9PSAiR086TUYiIHwgc291cmNlID09ICJHTzpDQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIkdPOiBDTCBTaWduaWZpY2FudCBHU0VBIikKQ0xfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIlJFQUMiKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJSRUFDOiBDTCBTaWduaWZpY2FudCBHU0VBIikKQ0xfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIktFR0ciKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJLRUdHOiBDTCBTaWduaWZpY2FudCBHU0VBIikKYGBgCgpgYGB7cn0KIyMjIyMgQ0wgRW5yaWNoZWQKZ29zdHBsb3QoQ0xfZ29zdCwgY2FwcGVkID0gRkFMU0UsIGludGVyYWN0aXZlID0gVFJVRSkKYGBgCgojIyBTYWxpbmU6IElERCB2cyBJQUQKCioqVm9sY2FubyBQbG90KioKCmBgYHtyfQpyZXNfdGJscyRJRERTYWxpbmVfdnNfSUFEU2FsaW5ldm9sY19wbG90bHkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KI1RoaXMgaXMganVzdCBhIHN0YXRpYyB2ZXJzaW9uIG9mIHRoZSBwbG90IGFib3ZlCnJlc190YmxzJElERFNhbGluZV92c19JQURTYWxpbmV2b2xjX2dncGxvdApgYGAKCioqVGFibGUgb2YgU2lnbmlmaWNhbnQgREUgcmVzdWx0cyoqCgpgYGB7cn0KcmVzX3RibHMkSUREU2FsaW5lX3ZzX0lBRFNhbGluZSAlPiUKICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+IDEgJiBhZGouUC5WYWwgPCAwLjA1KSAlPiUKICBhcnJhbmdlKGRlc2MobG9nRkMpKSAlPiUKICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJtZ2lfc3ltYm9sIiwgImRlc2NyaXB0aW9uIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIsICJTaWduaWZpY2FuY2UiKSAlPiUKICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKKipHU0VBKioKCmBgYHtyfQpTYWxpbmVfZ2VuZXMgPC0gcmVzX3RibHMkSUREU2FsaW5lX3ZzX0lBRFNhbGluZSAlPiUKICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAwLjUgJiBhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgICBhcnJhbmdlKGRlc2MoYWJzKGxvZ0ZDKSkpClNhbGluZV9nb3N0IDwtIGdvc3QocXVlcnkgPSBTYWxpbmVfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwgb3JkZXJlZF9xdWVyeSA9IFRSVUUsCiAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSkKYGBgCgpgYGB7cn0KI0NMIFNhbGluZSBFbnJpY2hlZApTYWxpbmVfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIkdPOkJQIiB8IHNvdXJjZSA9PSAiR086TUYiIHwgc291cmNlID09ICJHTzpDQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIkdPOiBTYWxpbmUgU2lnbmlmaWNhbnQgR1NFQSIpClNhbGluZV9nb3N0JHJlc3VsdCAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgZmlsdGVyKHNvdXJjZSA9PSAiUkVBQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIlJFQUM6IFNhbGluZSBTaWduaWZpY2FudCBHU0VBIikKU2FsaW5lX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJLRUdHIikgJT4lCiAgZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiS0VHRzogU2FsaW5lIFNpZ25pZmljYW50IEdTRUEiKQpgYGAKCmBgYHtyfQojIyMjIyBDTCBFbnJpY2hlZApnb3N0cGxvdChTYWxpbmVfZ29zdCwgY2FwcGVkID0gRkFMU0UsIGludGVyYWN0aXZlID0gVFJVRSkKYGBgCgojIENvbXBhcmlzb24gQmV0d2VlbiBDb250cmFzdHMKCiMjIENMIHZlcnN1cyBTYWxpbmUgYWZ0ZXIgYWRqdXN0aW5nIGZvciBkaWV0CgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQpjb3VudGRhdGEgPC0gZXhwcnMobW0zOF9maWx0KQpjb2xkYXRhIDwtIGNvbERhdGEobW0zOF9maWx0KQpkZHNNYXQgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IGRpZXQgKyB0cmVhdG1lbnQpCmRkcyA8LSBERVNlcShkZHNNYXQpCnJlcyA8LSByZXN1bHRzKGRkcykKcmVzIDwtIG1lcmdlKGFzLmRhdGEuZnJhbWUocmVzKSwgaGlzYXRfYW5ub3QsIGJ5ID0gMCkKcmVzIDwtIHJlc1shaXMubmEocmVzJHBhZGopLF0KcmVzIDwtIHNldF9zaWcocmVzLCBmYWN0b3JzID0gYygiU2FsaW5lIFxuIEVucmljaGVkIiwgIkNMIFxuIEVucmljaGVkIikpCnZvbGNfcGxvdChyZXNfdGJsID0gcmVzLCB0eXBlID0gInBsb3RseSIsIHRpdGxlID0gIlNhbGluZSB2ZXJzdXMgQ0wgYWZ0ZXIgYWRqdXN0aW5nIGZvciBEaWV0IikKCnJlcyAlPiUKICBmaWx0ZXIocGFkaiA8IDAuMDUgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID49IDEpICU+JQogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgIm1naV9zeW1ib2wiLCAiZGVzY3JpcHRpb24iLCAibG9nMkZvbGRDaGFuZ2UiLCAicGFkaiIsICJTaWduaWZpY2FuY2UiKSAlPiUKICBhcnJhbmdlKGRlc2MobG9nMkZvbGRDaGFuZ2UpKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgojIFJlcGVhdCB0aGUgYWJvdmUgaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZmFzaGlvbgoKYWxsX3BhaXJ3aXNlKCkgY2FuIGRvIHRoaXMgdG9vIQoKYGBge3J9Cm1tX2RpZXRfdHJlYXRtZW50IDwtIHNldF9leHB0X2NvbmRpdGlvbnMobW0zOF9maWx0LCBmYWN0ID0gImRpZXQiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAidHJlYXRtZW50IikKbW1fZGlldF90cmVhdG1lbnRfZGUgPC0gYWxsX3BhaXJ3aXNlKG1tX2RpZXRfdHJlYXRtZW50LCBtb2RlbF9iYXRjaCA9IFRSVUUpCm1tX2RpZXRfdHJlYXRtZW50X2RlCm1tX2RpZXRfdHJlYXRtZW50X3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKG1tX2RpZXRfdHJlYXRtZW50X2RlLCBleGNlbCA9ICJleGNlbC9ERV9kaWV0X3RyZWF0bWVudC10YWJsZS54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIikKbW1fZGlldF90cmVhdG1lbnRfdGFibGUKbW1fZGlldF90cmVhdG1lbnRfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobW1fZGlldF90cmVhdG1lbnRfdGFibGUsIGV4Y2VsID0gImV4Y2VsL0RFX2RpZXRfdHJlYXRtZW50LXNpZy54bHN4IikKbW1fZGlldF90cmVhdG1lbnRfc2lnCmBgYAoKKipHU0VBKioKCmBgYHtyfQphZGpfZ2VuZXMgPC0gcmVzICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSAmIGFicyhsb2cyRm9sZENoYW5nZSkgPj0gMSkgJT4lCiAgICBhcnJhbmdlKGRlc2MoYWJzKGxvZzJGb2xkQ2hhbmdlKSkpCmFkal9nb3N0IDwtIGdvc3QocXVlcnkgPSBhZGpfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwgb3JkZXJlZF9xdWVyeSA9IFRSVUUsCiAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSkKYGBgCgpgYGB7cn0KYWRqX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJHTzpCUCIgfCBzb3VyY2UgPT0gIkdPOk1GIiB8IHNvdXJjZSA9PSAiR086Q0MiKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJHTzogQWRqdXN0ZWQgZm9yIERpZXQgU2lnbmlmaWNhbnQgR1NFQSIpCmFkal9nb3N0JHJlc3VsdCAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgZmlsdGVyKHNvdXJjZSA9PSAiUkVBQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIlJFQUM6IEFkanVzdGVkIGZvciBEaWV0IFNpZ25pZmljYW50IEdTRUEiKQphZGpfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIktFR0ciKSAlPiUKICBkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJLRUdHOiBBZGp1c3RlZCBmb3IgRGlldCBTaWduaWZpY2FudCBHU0VBIikKYGBgCgpgYGB7cn0KIyMjIyMgQ0wgRW5yaWNoZWQKZ29zdHBsb3QoYWRqX2dvc3QsIGNhcHBlZCA9IEZBTFNFLCBpbnRlcmFjdGl2ZSA9IFRSVUUpCmBgYAoKYGBge3J9CmxpYnJhcnkob3Blbnhsc3gpCnJlc19kZiA8LSByZXMgJT4lCiAgZmlsdGVyKHBhZGogPCAwLjA1ICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSAwLjUpICU+JQogICAgYXJyYW5nZShkZXNjKGxvZzJGb2xkQ2hhbmdlKSkgJT4lCiAgICBzZWxlY3QoLVJvdy5uYW1lcywgLWxmY1NFLCAtc3RhdCwgLXB2YWx1ZSwgLWVuc2VtYmxfZ2VuZV9pZCwgLXZlcnNpb24sIC10cmFuc2NyaXB0X3ZlcnNpb24sIC1tZ2lfc3ltYm9sKQpvcGVueGxzeDo6d3JpdGUueGxzeChyZXNfZGYsIGZpbGUgPSAiZXhjZWwvYWRqZGlldF9ERS54bHN4IikKYGBgCgojIyBJREQgdmVyc3VzIElBRCBhZnRlciBhZGp1c3RpbmcgZm9yIHRyZWF0bWVudAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0KY291bnRkYXRhIDwtIGV4cHJzKG1tMzhfZmlsdCkKY29sZGF0YSA8LSBjb2xEYXRhKG1tMzhfZmlsdCkKZGRzTWF0IDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiB0cmVhdG1lbnQgKyBkaWV0KQpkZHMgPC0gREVTZXEoZGRzTWF0KQpyZXMgPC0gcmVzdWx0cyhkZHMpCnJlcyA8LSBtZXJnZShhcy5kYXRhLmZyYW1lKHJlcyksIGhpc2F0X2Fubm90LCBieSA9IDApCnJlcyA8LSByZXNbIWlzLm5hKHJlcyRwYWRqKSxdCnJlcyA8LSBzZXRfc2lnKHJlcywgZmFjdG9ycyA9IGMoIklERCBcbiBFbnJpY2hlZCIsICJJQUQgXG4gRW5yaWNoZWQiKSkKdm9sY19wbG90KHJlc190YmwgPSByZXMsIHR5cGUgPSAicGxvdGx5IiwgdGl0bGUgPSAiSUREIHZlcnN1cyBJQUQgYWZ0ZXIgYWRqdXN0aW5nIGZvciBUcmVhdG1lbnQiKQoKcmVzICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSAmIGFicyhsb2cyRm9sZENoYW5nZSkgPj0gMSkgJT4lCiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAibWdpX3N5bWJvbCIsICJkZXNjcmlwdGlvbiIsICJsb2cyRm9sZENoYW5nZSIsICJwYWRqIiwgIlNpZ25pZmljYW5jZSIpICU+JQogIGFycmFuZ2UoZGVzYyhsb2cyRm9sZENoYW5nZSkpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCmBgYHtyfQptbV90cmVhdG1lbnRfZGlldCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG1tMzhfZmlsdCwgZmFjdCA9ICJ0cmVhdG1lbnQiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZGlldCIpCm1tX3RyZWF0bWVudF9kaWV0X2RlIDwtIGFsbF9wYWlyd2lzZShtbV90cmVhdG1lbnRfZGlldCwgbW9kZWxfYmF0Y2ggPSBUUlVFKQptbV90cmVhdG1lbnRfZGlldF9kZQptbV90cmVhdG1lbnRfZGlldF90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV90cmVhdG1lbnRfZGlldF9kZSwgZXhjZWwgPSAiZXhjZWwvREVfdHJlYXRtZW50X2RpZXQtdGFibGUueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIpCm1tX3RyZWF0bWVudF9kaWV0X3RhYmxlCm1tX3RyZWF0bWVudF9kaWV0X3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX3RyZWF0bWVudF9kaWV0X3RhYmxlLCBleGNlbCA9ICJleGNlbC9ERV90cmVhdG1lbnRfZGlldC1zaWcueGxzeCIpCm1tX3RyZWF0bWVudF9kaWV0X3NpZwpgYGAKCioqR1NFQSoqCgpgYGB7cn0KYWRqX2dlbmVzIDwtIHJlcyAlPiUKICBmaWx0ZXIocGFkaiA8IDAuMDUgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID49IDEpICU+JQogICAgYXJyYW5nZShkZXNjKGFicyhsb2cyRm9sZENoYW5nZSkpKQphZGpfZ29zdCA8LSBnb3N0KHF1ZXJ5ID0gYWRqX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZCwKICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSwKICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFKQpgYGAKCmBgYHtyfQphZGpfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIkdPOkJQIiB8IHNvdXJjZSA9PSAiR086TUYiIHwgc291cmNlID09ICJHTzpDQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIkdPOiBEaWV0IGFmdGVyIEFkanVzdGVkIGZvciBUcmVhdG1lbnQgU2lnbmlmaWNhbnQgR1NFQSIpCmFkal9nb3N0JHJlc3VsdCAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgZmlsdGVyKHNvdXJjZSA9PSAiUkVBQyIpICU+JQogIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIlJFQUM6IERpZXQgYWZ0ZXIgQWRqdXN0ZWQgZm9yIFRyZWF0bWVudCBTaWduaWZpY2FudCBHU0VBIikKYWRqX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJLRUdHIikgJT4lCiAgZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiS0VHRzogRGlldCBhZnRlciBBZGp1c3RlZCBmb3IgVHJlYXRtZW50IFNpZ25pZmljYW50IEdTRUEiKQpgYGAKCmBgYHtyfQojIyMjIyBDTCBFbnJpY2hlZApnb3N0cGxvdChhZGpfZ29zdCwgY2FwcGVkID0gRkFMU0UsIGludGVyYWN0aXZlID0gVFJVRSkKYGBgCgpgYGB7cn0KZ3NlYXBsb3RfR09fZGlldF9hZGp0cmVhdCA8LSBhZGpfZ29zdCRyZXN1bHQgJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGZpbHRlcihzb3VyY2UgPT0gIkdPOkJQIiB8IHNvdXJjZSA9PSAiR086TUYiIHwgc291cmNlID09ICJHTzpDQyIpICU+JQogIGhlYWQobiA9IDEwKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpnc2VhcGxvdF9SRUFDX2RpZXRfYWRqdHJlYXQgPC0gYWRqX2dvc3QkcmVzdWx0ICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBmaWx0ZXIoc291cmNlID09ICJSRUFDIikgJT4lCiAgaGVhZChuID0gMTApICU+JQogICAgZ2dwbG90KGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpKwogIHlsYWIoIiIpICsKICB4bGFiKCJHU0VBIFNjb3JlIikKCmdzZWFwbG90X0dPX2RpZXRfYWRqdHJlYXQKZ3NlYXBsb3RfUkVBQ19kaWV0X2FkanRyZWF0CmBgYAoKYGBge3J9CmxpYnJhcnkob3Blbnhsc3gpCnJlc19kZiA8LSByZXMgJT4lCiAgZmlsdGVyKHBhZGogPCAwLjA1ICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSAuNSkgJT4lCiAgICBhcnJhbmdlKGRlc2MobG9nMkZvbGRDaGFuZ2UpKSAlPiUKICAgIHNlbGVjdCgtUm93Lm5hbWVzLCAtbGZjU0UsIC1zdGF0LCAtcHZhbHVlLCAtZW5zZW1ibF9nZW5lX2lkLCAtdmVyc2lvbiwgLXRyYW5zY3JpcHRfdmVyc2lvbiwgLWhnbmNfc3ltYm9sKQpvcGVueGxzeDo6d3JpdGUueGxzeChyZXNfZGYsIGZpbGUgPSAiZXhjZWwvYWRqdHJlYXRtZW50X0RFLnhsc3giKQpgYGAKCiMgUGVyZm9ybSBnUHJvZmlsZXIyL2NsdXN0ZXJQcm9maWxlciByZXByZXNlbnRhdGlvbi9HU0VBIHNlYXJjaGVzCgpJIGFtIGdvaW5nIHRvIHVzZSB0aGUgdGhyZWUgZGF0YSBzdHJ1Y3R1cmVzIEkgY3JlYXRlZCBpbiBvcmRlciB0byBkbwp0aGUgdmFyaW91cyBHTy9yZWFjdG9tZS9ldGMgc2VhcmNoZXMuCgoqIG1tX2RlX3NpZwoqIG1tX2RpZXRfdHJlYXRtZW50X3NpZwoqIG1tX3RyZWF0bWVudF9kaWV0X3NpZwoKIyMgVGhlIDQgdGFibGVzIGZpcnN0OiBtbV9kZV9zaWcKCmBgYHtyfQptbV9kZV9ncCA8LSBhbGxfZ3Byb2ZpbGVyKG1tX2RlX3NpZywgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQoKaWRkY2xfdnNfaWFkY2xfdXBfZ3AgPC0gd3JpdGVfZ3Byb2ZpbGVyX2RhdGEoCiAgbW1fZGVfZ3BbWyJJRERDTF92c19JQURDTF91cCJdXSwKICBleGNlbCA9ICJleGNlbC9pZGRjbF92c19pYWRjbF91cF9ncC54bHN4IikKaWRkY2xfdnNfaWFkY2xfZG93bl9ncCA8LSB3cml0ZV9ncHJvZmlsZXJfZGF0YSgKICBtbV9kZV9ncFtbIklERENMX3ZzX0lBRENMX2Rvd24iXV0sCiAgZXhjZWwgPSAiZXhjZWwvaWRkY2xfdnNfaWFkY2xfZG93bl9ncC54bHN4IikKCmlkZHNhbGluZV92c19pYWRzYWxpbmVfdXBfZ3AgPC0gd3JpdGVfZ3Byb2ZpbGVyX2RhdGEoCiAgbW1fZGVfZ3BbWyJJRERTYWxpbmVfdnNfSUFEU2FsaW5lX3VwIl1dLAogIGV4Y2VsID0gImV4Y2VsL2lkZHNhbGluZV92c19pYWRzYWxpbmVfdXBfZ3AueGxzeCIpCmlkZHNhbGluZV92c19pYWRzYWxpbmVfZG93bl9ncCA8LSB3cml0ZV9ncHJvZmlsZXJfZGF0YSgKICBtbV9kZV9ncFtbIklERFNhbGluZV92c19JQURTYWxpbmVfZG93biJdXSwKICBleGNlbCA9ICJleGNlbC9pZGRzYWxpbmVfdnNfaWFkc2FsaW5lX3VwX2dwLnhsc3giKQoKaWRkc2FsaW5lX3ZzX2lkZGNsX3VwX2dwIDwtIHdyaXRlX2dwcm9maWxlcl9kYXRhKAogIG1tX2RlX2dwW1siSUREU2FsaW5lX3ZzX0lERENMX3VwIl1dLAogIGV4Y2VsID0gImV4Y2VsL2lkZHNhbGluZV92c19pZGRjbF91cF9ncC54bHN4IikKaWRkc2FsaW5lX3ZzX2lkZGNsX2Rvd25fZ3AgPC0gd3JpdGVfZ3Byb2ZpbGVyX2RhdGEoCiAgbW1fZGVfZ3BbWyJJRERTYWxpbmVfdnNfSUREQ0xfZG93biJdXSwKICBleGNlbCA9ICJleGNlbC9pZGRzYWxpbmVfdnNfaWRkY2xfZG93bl9ncC54bHN4IikKYGBgCgpUaGUgZXhjZWwgZmlsZXMgY3JlYXRlZCBhYm92ZSBoYXZlIHNvbWUgcGljdHVyZXMgaW4gdGhlbSwgYnV0IHdlIGNhbgptYWtlIHNvbWUgaGVyZSBhcyB3ZWxsLi4uCgojIyMgUGljdHVyZXMgb2YgdGhlbQoKTmFqaWIgbGlrZSB0aGUgdHJlZSBwbG90cyB0aGUgYmVzdCwgbGV0IHVzIHRyeSB0aGF0IGZpcnN0LgoKYGBge3J9CmlkZGNsX2lhZGNsX3VwX3RyZWUgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbSgKICBtbV9kZV9ncFtbIklERENMX3ZzX0lBRENMX3VwIl1dW1siQlBfZW5yaWNoIl1dKQpzbShlbnJpY2hwbG90Ojp0cmVlcGxvdChpZGRjbF9pYWRjbF91cF90cmVlKSkKc20oZW5yaWNocGxvdDo6ZG90cGxvdChpZGRjbF9pYWRjbF91cF90cmVlKSkKCmlkZHNhbGluZV9pYWRzYWxpbmVfdXBfdHJlZSA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKAogIG1tX2RlX2dwW1siSUREU2FsaW5lX3ZzX0lBRFNhbGluZV91cCJdXVtbIkJQX2VucmljaCJdXSkKc20oZW5yaWNocGxvdDo6dHJlZXBsb3QoaWRkc2FsaW5lX2lhZHNhbGluZV91cF90cmVlKSkKc20oZW5yaWNocGxvdDo6ZG90cGxvdChpZGRzYWxpbmVfaWFkc2FsaW5lX3VwX3RyZWUpKQoKaWRkc2FsaW5lX2lkZGNsX3VwX3RyZWUgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbSgKICBtbV9kZV9ncFtbIklERFNhbGluZV92c19JRERDTF91cCJdXVtbIkJQX2VucmljaCJdXSkKc20oZW5yaWNocGxvdDo6dHJlZXBsb3QoaWRkY2xfaWFkY2xfdXBfdHJlZSkpCnNtKGVucmljaHBsb3Q6OmRvdHBsb3QoaWRkY2xfaWFkY2xfdXBfdHJlZSkpCmBgYAoKIyMgRGlldCBjb250cm9sbGluZyBmb3IgdHJlYXRtZW50CgpgYGB7cn0KbW1fZGlldF90cmVhdG1lbnRfZ3AgPC0gYWxsX2dwcm9maWxlcihtbV9kaWV0X3RyZWF0bWVudF9zaWcsIHNwZWNpZXMgPSAibW11c2N1bHVzIikKbW1fZGlldF90cmVhdG1lbnRfdXBfZ3AgPC0gd3JpdGVfZ3Byb2ZpbGVyX2RhdGEoCiAgbW1fZGlldF90cmVhdG1lbnRfZ3BbWyJJRERfdnNfSUFEX3VwIl1dLAogIGV4Y2VsID0gImV4Y2VsL21tX2RpZXRfdHJlYXRtZW50X2lkZF92c19pYWRfdXBfZ3AueGxzeCIpCm1tX2RpZXRfdHJlYXRtZW50X2Rvd25fZ3AgPC0gd3JpdGVfZ3Byb2ZpbGVyX2RhdGEoCiAgbW1fZGlldF90cmVhdG1lbnRfZ3BbWyJJRERfdnNfSUFEX2Rvd24iXV0sCiAgZXhjZWwgPSAiZXhjZWwvbW1fZGlldF90cmVhdG1lbnRfaWRkX3ZzX2lhZF9kb3duX2dwLnhsc3giKQpgYGAKCkFuZCBzb21lIHBsb3RzIQoKYGBge3J9CmlkZF9pYWRfdXBfdHJlZSA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKAogIG1tX2RpZXRfdHJlYXRtZW50X2dwW1siSUREX3ZzX0lBRF91cCJdXVtbIkJQX2VucmljaCJdXSkKc20oZW5yaWNocGxvdDo6dHJlZXBsb3QoaWRkX2lhZF91cF90cmVlKSkKc20oZW5yaWNocGxvdDo6ZG90cGxvdChpZGRfaWFkX3VwX3RyZWUpKQoKaWRkX2lhZF9kb3duX3RyZWUgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbSgKICBtbV9kaWV0X3RyZWF0bWVudF9ncFtbIklERF92c19JQURfZG93biJdXVtbIkJQX2VucmljaCJdXSkKc20oZW5yaWNocGxvdDo6dHJlZXBsb3QoaWRkX2lhZF9kb3duX3RyZWUpKQpzbShlbnJpY2hwbG90Ojpkb3RwbG90KGlkZF9pYWRfZG93bl90cmVlKSkKCmlkZF9pYWRfdXBfdHJlZSA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKAogIG1tX2RpZXRfdHJlYXRtZW50X2dwW1siSUREX3ZzX0lBRF91cCJdXVtbIlJFQUNfZW5yaWNoIl1dKQpzbShlbnJpY2hwbG90Ojpkb3RwbG90KGlkZF9pYWRfdXBfdHJlZSkpCgppZGRfaWFkX2Rvd25fdHJlZSA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKAogIG1tX2RpZXRfdHJlYXRtZW50X2dwW1siSUREX3ZzX0lBRF9kb3duIl1dW1siUkVBQ19lbnJpY2giXV0pCnNtKGVucmljaHBsb3Q6OmRvdHBsb3QoaWRkX2lhZF9kb3duX3RyZWUpKQpgYGAKCgojIyBUcmVhdG1lbnQgY29udHJvbGxpbmcgZm9yIGRpZXQKCmBgYHtyfQptbV90cmVhdG1lbnRfZGlldF9ncCA8LSBhbGxfZ3Byb2ZpbGVyKG1tX3RyZWF0bWVudF9kaWV0X3NpZywgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQptbV90cmVhdG1lbnRfZGlldF91cF9ncCA8LSB3cml0ZV9ncHJvZmlsZXJfZGF0YSgKICBtbV90cmVhdG1lbnRfZGlldF9ncFtbIklERF92c19JQURfdXAiXV0sCiAgZXhjZWwgPSAiZXhjZWwvbW1fdHJlYXRtZW50X2RpZXRfaWRkX3ZzX2lhZF91cF9ncC54bHN4IikKbW1fdHJlYXRtZW50X2RpZXRfZG93bl9ncCA8LSB3cml0ZV9ncHJvZmlsZXJfZGF0YSgKICBtbV90cmVhdG1lbnRfZGlldF9ncFtbIklERF92c19JQURfZG93biJdXSwKICBleGNlbCA9ICJleGNlbC9tbV90cmVhdG1lbnRfZGlldF9pZGRfdnNfaWFkX2Rvd25fZ3AueGxzeCIpCmBgYAoKQW5kIHNvbWUgcGxvdHMhCgpgYGB7cn0Kc2FsaW5lX2NsX3VwX3RyZWUgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbSgKICBtbV90cmVhdG1lbnRfZGlldF9ncFtbInNhbGluZXZlaGljbGVfdnNfY2xfdXAiXV1bWyJCUF9lbnJpY2giXV0pCnNtKGVucmljaHBsb3Q6OnRyZWVwbG90KGlkZF9pYWRfdXBfdHJlZSkpCnNtKGVucmljaHBsb3Q6OmRvdHBsb3QoaWRkX2lhZF91cF90cmVlKSkKCnNhbGluZV9jbF9kb3duX3RyZWUgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbSgKICBtbV90cmVhdG1lbnRfZGlldF9ncFtbInNhbGluZXZlaGljbGVfdnNfY2xfZG93biJdXVtbIkJQX2VucmljaCJdXSkKc20oZW5yaWNocGxvdDo6ZG90cGxvdChpZGRfaWFkX2Rvd25fdHJlZSkpCmBgYAoKIyBhbmQgR1NFQSB2aWEgY2x1c3RlclByb2ZpbGVyCgpgYGB7cn0KbW1fZGVfY3AgPC0gYWxsX2Nwcm9maWxlcihtbV9kZV9zaWcsIG1tX2RlX3RhYmxlcywgb3JnZGIgPSAib3JnLk1tLmVnLmRiIikKCmlkZGNsX3ZzX2lhZGNsX2dzZWEgPC0gcGxvdF90b3BuX2dzZWEobW1fZGVfY3BbWyJJRERDTF92c19JQURDTF91cCJdXSkKaWRkY2xfdnNfaWFkY2xfZ3NlYVtbIkdPIl1dW1sxXV0KZW5yaWNocGxvdDo6ZG90cGxvdChtbV9kZV9jcFtbIklERENMX3ZzX0lBRENMX3VwIl1dW1siZW5yaWNoX29iamVjdHMiXV1bWyJCUF9hbGwiXV0pCgppZGRzYWxpbmVfdnNfaWFkc2FsaW5lX2dzZWEgPC0gcGxvdF90b3BuX2dzZWEobW1fZGVfY3BbWyJJRERTYWxpbmVfdnNfSUFEU2FsaW5lX3VwIl1dKQppZGRzYWxpbmVfdnNfaWFkc2FsaW5lX2dzZWFbWyJHTyJdXVtbMV1dCmVucmljaHBsb3Q6OmRvdHBsb3QobW1fZGVfY3BbWyJJRERTYWxpbmVfdnNfSUFEU2FsaW5lX3VwIl1dW1siZW5yaWNoX29iamVjdHMiXV1bWyJCUF9hbGwiXV0pCgppYWRzYWxpbmVfdnNfaWFkY2xfZ3NlYSA8LSBwbG90X3RvcG5fZ3NlYShtbV9kZV9jcFtbIklBRFNhbGluZV92c19JQURDTF91cCJdXSkKaWFkc2FsaW5lX3ZzX2lhZGNsX2dzZWFbWyJHTyJdXVtbMV1dCmVucmljaHBsb3Q6OmRvdHBsb3QobW1fZGVfY3BbWyJJQURTYWxpbmVfdnNfSUFEQ0xfdXAiXV1bWyJlbnJpY2hfb2JqZWN0cyJdXVtbIkJQX2FsbCJdXSkKZW5yaWNocGxvdDo6ZG90cGxvdChtbV9kZV9jcFtbIklBRFNhbGluZV92c19JQURDTF9kb3duIl1dW1siZW5yaWNoX29iamVjdHMiXV1bWyJCUF9hbGwiXV0pCmBgYAo=