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")
## The biomart annotations file already exists, loading from it.
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"   "3766_S9"   "3767_S10" 
##  [9] "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
## Starting basic pairwise comparison.
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Basic step 1/3: Creating mean and variance tables.
## Basic step 2/3: Performing 10 comparisons.
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.
## Basic step 3/3: Creating faux DE Tables.
## Basic: Returning tables.
## The data should be suitable for EdgeR/DESeq/EBSeq.
## If they freak out, check the state of the count table
## and ensure that it is in integer counts.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.
## Starting edgeR pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq.
## If they freak out, check the state of the count table
## and ensure that it is in integer counts.
## EdgeR step 1/9: Importing and normalizing data.
## EdgeR step 2/9: Estimating the common dispersion.
## EdgeR step 3/9: Estimating dispersion across genes.
## EdgeR step 4/9: Estimating GLM Common dispersion.
## EdgeR step 5/9: Estimating GLM Trended dispersion.
## EdgeR step 6/9: Estimating GLM Tagged dispersion.
## EdgeR step 7/9: Running glmFit, switch to glmQLFit by changing the argument 'edger_test'.
## EdgeR step 8/9: Making pairwise contrasts.
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.

## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$best_libsize.
## Limma step 1/6: choosing model.
## Limma step 2/6: running limma::voom(), switch with the argument 'which_voom'.
## Using normalize.method = quantile for voom.

## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.
## Finished make_pairwise_contrasts.
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.
## Limma step 5/6: Running eBayes with robust = FALSE and trend = FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/6: Creating table: IADSaline_vs_IADCL.  Adjust = BH
## Limma step 6/6: 2/6: Creating table: IDDCL_vs_IADCL.  Adjust = BH
## Limma step 6/6: 3/6: Creating table: IDDSaline_vs_IADCL.  Adjust = BH
## Limma step 6/6: 4/6: Creating table: IDDCL_vs_IADSaline.  Adjust = BH
## Limma step 6/6: 5/6: Creating table: IDDSaline_vs_IADSaline.  Adjust = BH
## Limma step 6/6: 6/6: Creating table: IDDSaline_vs_IDDCL.  Adjust = BH
## Limma step 6/6: 1/4: Creating table: IADCL.  Adjust = BH
## Limma step 6/6: 2/4: Creating table: IADSaline.  Adjust = BH
## Limma step 6/6: 3/4: Creating table: IDDCL.  Adjust = BH
## Limma step 6/6: 4/4: Creating table: IDDSaline.  Adjust = BH
## Starting noiseq pairwise comparisons.
## The data should be suitable for EdgeR/DESeq/EBSeq.
## If they freak out, check the state of the count table
## and ensure that it is in integer counts.
## The provided conditions are:
## conditions
##     IADCL IADSaline     IDDCL IDDSaline 
##         4         4         5         3
## Choosing among model matrix columns: conditionIADCL, conditionIADSaline, conditionIDDCL, conditionIDDSaline.

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 10 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")
## Deleting the file excel/DE_20221003.xlsx before writing the tables.
mm_de_tables
## A set of combined differential expression results.
##                    table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1         IDDCL_vs_IADCL         132           115         142           117          84            71
## 2 IDDSaline_vs_IADSaline          48            55          53            58          15             7
## 3     IDDSaline_vs_IDDCL           4            27           5            40           0             0
## 4     IADSaline_vs_IADCL          12             5          12             7           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")
## Deleting the file excel/DE_sig_20221003.xlsx before writing the tables.
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")
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
mm_diet_treatment_de
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: batch in model/limma.
## The primary analysis performed 10 comparisons.
## The logFC agreement among the methods follows:
##                 IDD_vs_IAD
## limma_vs_deseq      0.8627
## limma_vs_edger      0.8861
## limma_vs_basic      0.9907
## limma_vs_noiseq     0.8551
## deseq_vs_edger      0.9966
## deseq_vs_basic      0.8709
## deseq_vs_noiseq     0.7911
## edger_vs_basic      0.8938
## edger_vs_noiseq     0.8102
## basic_vs_noiseq     0.8877
mm_diet_treatment_table <- combine_de_tables(mm_diet_treatment_de, excel = "excel/DE_diet_treatment-table.xlsx",
                                        label_column = "mgi_symbol")
## Deleting the file excel/DE_diet_treatment-table.xlsx before writing the tables.
mm_diet_treatment_table
## A set of combined differential expression results.
##        table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 IDD_vs_IAD          74            70          77            76          75            48
## `geom_line()`: Each group consists of only one observation.
## ℹ 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")
## Deleting the file excel/DE_diet_treatment-sig.xlsx before writing the tables.
mm_diet_treatment_sig
## A set of genes deemed significant according to limma, edger, deseq, 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 basic_up basic_down
## IDD_vs_IAD       75         48       77         76       74         70       66         29

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
mm_treatment_diet_de
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: batch in model/limma.
## The primary analysis performed 10 comparisons.
## The logFC agreement among the methods follows:
##                 slnvhcl_v_
## limma_vs_deseq      0.8734
## limma_vs_edger      0.8871
## limma_vs_basic      0.9733
## limma_vs_noiseq     0.8583
## deseq_vs_edger      0.9974
## deseq_vs_basic      0.8454
## deseq_vs_noiseq     0.7202
## edger_vs_basic      0.8614
## edger_vs_noiseq     0.7421
## basic_vs_noiseq     0.8916
mm_treatment_diet_table <- combine_de_tables(mm_treatment_diet_de, excel = "excel/DE_treatment_diet-table.xlsx",
                                        label_column = "mgi_symbol")
## Deleting the file excel/DE_treatment_diet-table.xlsx before writing the tables.
mm_treatment_diet_table
## A set of combined differential expression results.
##                 table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 salinevehicle_vs_cl          70            27          80            27           1            26
## `geom_line()`: Each group consists of only one observation.
## ℹ 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")
## Deleting the file excel/DE_treatment_diet-sig.xlsx before writing the tables.
mm_treatment_diet_sig
## A set of genes deemed significant according to limma, edger, deseq, 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 basic_up basic_down
## salinevehicle_vs_cl        1         26       80         27       70         27        0          1

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")
## Deleting the file excel/iddcl_vs_iadcl_up_gp.xlsx before writing the tables.
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")
## Deleting the file excel/iddsaline_vs_iadsaline_up_gp.xlsx before writing the tables.
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ 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.
## ℹ Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?`geom_line()`: Each group consists of only one observation.
## ℹ 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.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ 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 in (function (classes, fdef, mtable) : unable to find an inherited method for function 'pairwise_termsim' for signature '"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")
## Deleting the file excel/mm_diet_treatment_idd_vs_iad_up_gp.xlsx before writing the tables.
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")
## Deleting the file excel/mm_diet_treatment_idd_vs_iad_down_gp.xlsx before writing the tables.

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")
## Deleting the file excel/mm_treatment_diet_idd_vs_iad_up_gp.xlsx before writing the tables.
## 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")
## Deleting the file excel/mm_treatment_diet_idd_vs_iad_down_gp.xlsx before writing the tables.
## 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")
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Reading KEGG annotation online: "https://rest.kegg.jp/link/mmu/pathway"...
## Reading KEGG annotation online: "https://rest.kegg.jp/list/pathway/mmu"...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## No gene sets have size between 5 and 500 ...
## 
## --> return NULL...
## 
## No gene sets have size between 5 and 500 ...
## 
## --> return NULL...
## 
## No gene sets have size between 5 and 500 ...
## 
## --> return NULL...
## 
## No gene sets have size between 5 and 500 ...
## 
## --> return NULL...
## 
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## --> No gene can be mapped....
## 
## --> Expected input gene ID: 30963,14120,78625,56752,69983,74246
## 
## --> return NULL...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## preparing geneSet collections...
## 
## GSEA analysis...
## 
## leading edge analysis...
## 
## done...
## 
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
iddcl_vs_iadcl_gsea <- plot_topn_gsea(mm_de_cp[["IDDCL_vs_IADCL_up"]])
iddcl_vs_iadcl_gsea[["GO"]][[1]]

enrichplot::dotplot(mm_de_cp[["IDDCL_vs_IADCL_up"]][["enrich_objects"]][["BP_all"]])

iddsaline_vs_iadsaline_gsea <- plot_topn_gsea(mm_de_cp[["IDDSaline_vs_IADSaline_up"]])
iddsaline_vs_iadsaline_gsea[["GO"]][[1]]

enrichplot::dotplot(mm_de_cp[["IDDSaline_vs_IADSaline_up"]][["enrich_objects"]][["BP_all"]])

iadsaline_vs_iadcl_gsea <- plot_topn_gsea(mm_de_cp[["IADSaline_vs_IADCL_up"]])
iadsaline_vs_iadcl_gsea[["GO"]][[1]]

enrichplot::dotplot(mm_de_cp[["IADSaline_vs_IADCL_up"]][["enrich_objects"]][["BP_all"]])

enrichplot::dotplot(mm_de_cp[["IADSaline_vs_IADCL_down"]][["enrich_objects"]][["BP_all"]])

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=