diff --git a/session3_solutions.Rmd b/session3_solutions.Rmd index e37b46b..71dddc5 100644 --- a/session3_solutions.Rmd +++ b/session3_solutions.Rmd @@ -54,6 +54,8 @@ results_tgf %>% The tricky part of making a heatmap is deciding which genes to include. The gene names have to be in ENSEMBL format, as the count matrix we will be plotting has ENSEMBL names in the rows. +In the following example, we chose the genes with most extreme log2 fold-change + ```{r} # The pheatmap library is needed to make the heatmap @@ -64,42 +66,32 @@ library(pheatmap) vsd <- vst(dds) sampleInfo <- as.data.frame(colData(dds)[,c("condition","Treated")]) -# create a new table that includes gene variability - -res_with_var <- mutate(results_tgf, GeneVar = rowSds(assay(vsd))) %>% - filter(!is.na(padj)) - -# arrange by the new column and extract ENSEMBL ID of the first 100 rows +## Order results by log2FoldChange and get the most extreme -genes_to_plot <- arrange(res_with_var, desc(GeneVar)) %>% - dplyr::slice(1:100) %>% +top_genes_logFC <- results_tgf %>% + arrange(desc(abs(log2FoldChange))) %>% + slice(1:30) %>% pull(ENSEMBL) +top_genes_logFC_labels <- results_tgf %>% + arrange(desc(abs(log2FoldChange))) %>% + slice(1:30) %>% + pull(SYMBOL) -``` +## get the corresponding geen symbols -```{r fig.width=12} +pheatmap(assay(vsd)[top_genes_logFC,], + scale = "row", + labels_row = top_genes_logFC_labels) -pheatmap(assay(vsd)[genes_to_plot,], - annotation_col = sampleInfo, - scale="row") ``` -```{r fig.width=12} -gene_labels <- arrange(res_with_var, desc(GeneVar)) %>% - dplyr::slice(1:100) %>% - pull(SYMBOL) -pheatmap(assay(vsd)[genes_to_plot,], - annotation_col = sampleInfo, - labels_row = gene_labels, - scale="row") -``` + # Exercise: Pathways -**Need to fix, as currently this doesn't return anything!** In order to use the `enrichKEGG` function, we will have to define a set of enriched genes in terms of their `ENTREZID` (instead of `ENSEMBL`) diff --git a/session3_solutions.nb.html b/session3_solutions.nb.html index c527630..dee47c7 100644 --- a/session3_solutions.nb.html +++ b/session3_solutions.nb.html @@ -1511,7 +1511,7 @@ $(this).detach().appendTo(div); // add a show code button right above - var showCodeText = $('' + (showThis ? 'Hide' : 'Code') + ''); + var showCodeText = $('' + (showThis ? 'Hide' : 'Show') + ''); var showCodeButton = $(''); showCodeButton.append(showCodeText); showCodeButton @@ -1537,7 +1537,7 @@ // * Change text // * add a class for intermediate states styling div.on('hide.bs.collapse', function () { - showCodeText.text('Code'); + showCodeText.text('Show'); showCodeButton.addClass('btn-collapsing'); }); div.on('hidden.bs.collapse', function () { @@ -1755,10 +1755,12 @@

R Notebook

We start by loading our results from the previous week

+
library(DESeq2)
- + +
Loading required package: S4Vectors
 Loading required package: stats4
 Loading required package: BiocGenerics
@@ -1771,29 +1773,28 @@ 

R Notebook

The following objects are masked from ‘package:base’: - anyDuplicated, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, - eval, evalq, Filter, Find, get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply, - match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, - rownames, sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max, which.min + anyDuplicated, aperm, append, as.data.frame, basename, cbind, + colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, + get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply, + match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, + Position, rank, rbind, Reduce, rownames, sapply, setdiff, table, + tapply, union, unique, unsplit, which.max, which.min Attaching package: ‘S4Vectors’ +The following object is masked from ‘package:utils’: + + findMatches + The following objects are masked from ‘package:base’: expand.grid, I, unname Loading required package: IRanges - -Attaching package: ‘IRanges’ - -The following object is masked from ‘package:grDevices’: - - windows - Loading required package: GenomicRanges Loading required package: GenomeInfoDb -Warning: package ‘GenomeInfoDb’ was built under R version 4.2.1Loading required package: SummarizedExperiment +Loading required package: SummarizedExperiment Loading required package: MatrixGenerics Loading required package: matrixStats @@ -1801,22 +1802,28 @@

R Notebook

The following objects are masked from ‘package:matrixStats’: - colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, colCounts, colCummaxs, colCummins, - colCumprods, colCumsums, colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs, colMads, - colMaxs, colMeans2, colMedians, colMins, colOrderStats, colProds, colQuantiles, colRanges, - colRanks, colSdDiffs, colSds, colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads, - colWeightedMeans, colWeightedMedians, colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs, - rowAnys, rowAvgsPerColSet, rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods, - rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, rowMadDiffs, rowMads, rowMaxs, - rowMeans2, rowMedians, rowMins, rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, - rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars, rowWeightedMads, - rowWeightedMeans, rowWeightedMedians, rowWeightedSds, rowWeightedVars + colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, + colCounts, colCummaxs, colCummins, colCumprods, colCumsums, + colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs, + colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats, + colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds, + colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads, + colWeightedMeans, colWeightedMedians, colWeightedSds, + colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet, + rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods, + rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, + rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins, + rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, + rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars, + rowWeightedMads, rowWeightedMeans, rowWeightedMedians, + rowWeightedSds, rowWeightedVars Loading required package: Biobase Welcome to Bioconductor - Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, - see 'citation("Biobase")', and for packages 'citation("pkgname")'. + Vignettes contain introductory material; view with + 'browseVignettes()'. To cite Bioconductor, see + 'citation("Biobase")', and for packages 'citation("pkgname")'. Attaching package: ‘Biobase’ @@ -1829,9 +1836,11 @@

R Notebook

anyMissing, rowMedians
+
library(dplyr)
+

 Attaching package: ‘dplyr’
@@ -1872,12 +1881,14 @@ 

R Notebook

intersect, setdiff, setequal, union
+
## Read the annotated results
 results_tgf <- readRDS("Robjects/results_TGF_vs_CTR_annotated_BACKUP.rds")
 ## Read the counts that we produced previously
 dds <- readRDS("Robjects/dds_BACKUP.rds")
+
@@ -1886,27 +1897,28 @@

Exercise: Volcano plot

ggplot2 package

- + +

-library(ggplot2)
- - -
Warning: package ‘ggplot2’ was built under R version 4.2.2
- - -
results_tgf %>% 
+library(ggplot2)
+results_tgf %>% 
   ggplot(aes(x = log2FoldChange, y = -log10(padj))) + geom_point()
- -

+ + + +

+ +
library(org.Hs.eg.db)
+
Loading required package: AnnotationDbi
 
@@ -1916,44 +1928,56 @@ 

Exercise: Volcano plot

select
+
ecm_anno <- AnnotationDbi::select(org.Hs.eg.db,
                                  keys = "GO:0030198",
                                  keytype = "GO",
                                  columns=c("ENSEMBL","SYMBOL"))
+
'select()' returned 1:many mapping between keys and columns
+
ecm_anno
- + + +
+ +
ecm_ids <- pull(ecm_anno, "ENSEMBL")
+ +
results_tgf %>% 
   mutate(ECM_Gene = ENSEMBL %in% ecm_ids) %>% 
   ggplot(aes(x = log2FoldChange, y = -log10(padj),col=ECM_Gene)) + geom_point()
- -

+ + + +

+

The default colouring does not distinguish the ECM genes as much as @@ -1962,14 +1986,18 @@

Exercise: Volcano plot

(alpha) can also be adjusted. Below is a suggestion.

+
results_tgf %>% 
   mutate(ECM_Gene = ENSEMBL %in% ecm_ids) %>% 
   ggplot(aes(x = log2FoldChange, y = -log10(padj),col=ECM_Gene,alpha=ECM_Gene)) + geom_point() + scale_color_manual(values=c("black","red")) + scale_alpha_manual(values=c(0.2,1))
- -

+ + + +

+
@@ -1978,8 +2006,11 @@

Exercise: Heatmap

The tricky part of making a heatmap is deciding which genes to include. The gene names have to be in ENSEMBL format, as the count matrix we will be plotting has ENSEMBL names in the rows.

+

In the following example, we chose the genes with most extreme log2 +fold-change

+
# The pheatmap library is needed to make the heatmap
 
@@ -1989,120 +2020,209 @@ 

Exercise: Heatmap

vsd <- vst(dds)
+
using 'avgTxLength' from assays(dds), correcting for library size
- + +
sampleInfo <- as.data.frame(colData(dds)[,c("condition","Treated")])
 
-# create a new table that includes gene variability
-
-res_with_var <- mutate(results_tgf, GeneVar = rowSds(assay(vsd))) %>% 
-  filter(!is.na(padj))
+## Order results by log2FoldChange and get the most extreme
 
-# arrange by the new column and extract ENSEMBL ID of the first 100 rows
-
-genes_to_plot <- arrange(res_with_var, desc(GeneVar)) %>% 
-  dplyr::slice(1:100) %>% 
+top_genes_logFC <- results_tgf %>% 
+  arrange(desc(abs(log2FoldChange))) %>% 
+  slice(1:30) %>% 
   pull(ENSEMBL)
-
- - - - - - -

-pheatmap(assay(vsd)[genes_to_plot,],
-         annotation_col = sampleInfo,
-         scale="row")
- - -

- - - - - - -
gene_labels <- arrange(res_with_var, desc(GeneVar)) %>% 
-  dplyr::slice(1:100) %>% 
+
+top_genes_logFC_labels <- results_tgf %>% 
+  arrange(desc(abs(log2FoldChange))) %>% 
+  slice(1:30) %>% 
   pull(SYMBOL)
 
-pheatmap(assay(vsd)[genes_to_plot,],
-         annotation_col = sampleInfo,
-         labels_row = gene_labels,
-         scale="row")
+## get the corresponding geen symbols
+
+pheatmap(assay(vsd)[top_genes_logFC,],
+         scale = "row",
+         labels_row = top_genes_logFC_labels)
 
- -

+ + + +

+

Exercise: Pathways

-

Need to fix, as currently this doesn’t return -anything!

In order to use the enrichKEGG function, we will have to define a set of enriched genes in terms of their ENTREZID (instead of ENSEMBL)

+
sigGenesEntrez <- results_tgf %>% 
   filter(padj < 0.05, !is.na(ENTREZID)) %>% pull(ENTREZID)
 
+

Make sure you check the help for enrichKEGG, as it uses different argument names

- + + +
library(clusterProfiler)
+ + + +

+Registered S3 method overwritten by 'data.table':
+  method           from
+  print.data.table     
+clusterProfiler v4.12.6 Learn more at https://yulab-smu.top/contribution-knowledge-mining/
+
+Please cite:
+
+S Xu, E Hu, Y Cai, Z Xie, X Luo, L Zhan, W Tang, Q Wang, B Liu, R Wang,
+W Xie, T Wu, L Xie, G Yu. Using clusterProfiler to characterize
+multiomics data. Nature Protocols. 2024, doi:10.1038/s41596-024-01020-z
+
+Attaching package: ‘clusterProfiler’
+
+The following object is masked from ‘package:AnnotationDbi’:
+
+    select
+
+The following object is masked from ‘package:IRanges’:
+
+    slice
+
+The following object is masked from ‘package:S4Vectors’:
+
+    rename
+
+The following object is masked from ‘package:stats’:
+
+    filter
+ + + +
enrich_kegg <- enrichKEGG(gene = sigGenesEntrez,
+                       organism = "hsa",)
+ + + +
Reading KEGG annotation online: "https://rest.kegg.jp/link/hsa/pathway"...
+Reading KEGG annotation online: "https://rest.kegg.jp/list/pathway/hsa"...
+ + + +
as.data.frame(enrich_kegg)
+ + + +
+

The same plots can be created from the results. Here is the dot plot.

+
dotplot(enrich_kegg)
- -
Error in (function (classes, fdef, mtable)  : 
-  unable to find an inherited method for function ‘dotplot’ for signature ‘"NULL"’
+ + + +

+

and the upset plot.

+ + +
enrichplot::upsetplot(enrich_kegg)
+ + + + +

+ +

For the GSEA analysis using KEGG we can use the same set of ranked statistics, but make sure to name them according to ENTREZID

+ + +
ranked_genes <- results_tgf %>% 
+  arrange(desc(stat)) %>% 
+  filter(!is.na(stat))
+  
+geneList <- pull(ranked_genes, stat)
+names(geneList) <- pull(ranked_genes, ENTREZID)
+ +

Again, make sure to check the arguments for gseKEGG.

+ + +
gse_kegg <- gseKEGG(geneList = geneList,
+                    organism = "hsa")
+ + + +
using 'fgsea' for GSEA analysis, please cite Korotkevich et al (2019).
+
+preparing geneSet collections...
+GSEA analysis...
+Warning: There are ties in the preranked stats (11.21% of the list).
+The order of those tied genes will be arbitrary, which may produce unexpected results.Warning: There are duplicate gene names, fgsea may produce unexpected results.Warning: For some pathways, in reality P-values are less than 1e-10. You can set the `eps` argument to zero for better estimation.leading edge analysis...
+done...
+ + + +
as.data.frame(gse_kegg)
+ + + + +
+ +
+ +
-
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpXZSBzdGFydCBieSBsb2FkaW5nIG91ciByZXN1bHRzIGZyb20gdGhlIHByZXZpb3VzIHdlZWsNCg0KYGBge3J9DQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkoZHBseXIpDQojIyBSZWFkIHRoZSBhbm5vdGF0ZWQgcmVzdWx0cw0KcmVzdWx0c190Z2YgPC0gcmVhZFJEUygiUm9iamVjdHMvcmVzdWx0c19UR0ZfdnNfQ1RSX2Fubm90YXRlZF9CQUNLVVAucmRzIikNCiMjIFJlYWQgdGhlIGNvdW50cyB0aGF0IHdlIHByb2R1Y2VkIHByZXZpb3VzbHkNCmRkcyA8LSByZWFkUkRTKCJSb2JqZWN0cy9kZHNfQkFDS1VQLnJkcyIpDQpgYGANCg0KIyBFeGVyY2lzZTogVm9sY2FubyBwbG90DQoNClRoZSBzdGFuZGFyZCB2b2xjYW5vIHBsb3QgY2FuIGJlIHByb2R1Y2VkIHdpdGggdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQpyZXN1bHRzX3RnZiAlPiUgDQogIGdncGxvdChhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLCB5ID0gLWxvZzEwKHBhZGopKSkgKyBnZW9tX3BvaW50KCkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkob3JnLkhzLmVnLmRiKQ0KZWNtX2Fubm8gPC0gQW5ub3RhdGlvbkRiaTo6c2VsZWN0KG9yZy5Icy5lZy5kYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleXMgPSAiR086MDAzMDE5OCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXl0eXBlID0gIkdPIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbnM9YygiRU5TRU1CTCIsIlNZTUJPTCIpKQ0KZWNtX2Fubm8NCmBgYA0KDQpgYGB7cn0NCmVjbV9pZHMgPC0gcHVsbChlY21fYW5ubywgIkVOU0VNQkwiKQ0KYGBgDQoNCmBgYHtyfQ0KcmVzdWx0c190Z2YgJT4lIA0KICBtdXRhdGUoRUNNX0dlbmUgPSBFTlNFTUJMICVpbiUgZWNtX2lkcykgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSxjb2w9RUNNX0dlbmUpKSArIGdlb21fcG9pbnQoKQ0KYGBgDQpUaGUgZGVmYXVsdCBjb2xvdXJpbmcgZG9lcyBub3QgZGlzdGluZ3Vpc2ggdGhlIEVDTSBnZW5lcyBhcyBtdWNoIGFzIHdlIG1pZ2h0IGxpa2UuIFdlIGNvdWxkIG1hbnVhbGx5IGFkanVzdCBpdCBzbyB0aGF0IGdlbmVzIGJlbG9uZ2luZyB0byB0aGUgcGF0aHdheSBhcmUgY29sb3VyZWQgaW4gcmVkLCBhbmQgdGhlIHJlc3QgaW4gYmxhY2suIFRoZSB0cmFuc3BhcmVuY3kgKGBhbHBoYWApIGNhbiBhbHNvIGJlIGFkanVzdGVkLiBCZWxvdyBpcyBhIHN1Z2dlc3Rpb24uDQoNCmBgYHtyfQ0KcmVzdWx0c190Z2YgJT4lIA0KICBtdXRhdGUoRUNNX0dlbmUgPSBFTlNFTUJMICVpbiUgZWNtX2lkcykgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSxjb2w9RUNNX0dlbmUsYWxwaGE9RUNNX0dlbmUpKSArIGdlb21fcG9pbnQoKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCJyZWQiKSkgKyBzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzPWMoMC4yLDEpKQ0KYGBgDQojIEV4ZXJjaXNlOiBIZWF0bWFwDQoNClRoZSB0cmlja3kgcGFydCBvZiBtYWtpbmcgYSBoZWF0bWFwIGlzIGRlY2lkaW5nIHdoaWNoIGdlbmVzIHRvIGluY2x1ZGUuIFRoZSBnZW5lIG5hbWVzIGhhdmUgdG8gYmUgaW4gRU5TRU1CTCBmb3JtYXQsIGFzIHRoZSBjb3VudCBtYXRyaXggd2Ugd2lsbCBiZSBwbG90dGluZyBoYXMgRU5TRU1CTCBuYW1lcyBpbiB0aGUgcm93cy4NCg0KYGBge3J9DQojIFRoZSBwaGVhdG1hcCBsaWJyYXJ5IGlzIG5lZWRlZCB0byBtYWtlIHRoZSBoZWF0bWFwDQoNCmxpYnJhcnkocGhlYXRtYXApDQoNCiNmaXJzdCwgZ2V0IHZhcmlhbmNlLXN0YWJsaXNlZCBjb3VudHMNCg0KdnNkIDwtIHZzdChkZHMpDQpzYW1wbGVJbmZvIDwtIGFzLmRhdGEuZnJhbWUoY29sRGF0YShkZHMpWyxjKCJjb25kaXRpb24iLCJUcmVhdGVkIildKQ0KDQojIGNyZWF0ZSBhIG5ldyB0YWJsZSB0aGF0IGluY2x1ZGVzIGdlbmUgdmFyaWFiaWxpdHkNCg0KcmVzX3dpdGhfdmFyIDwtIG11dGF0ZShyZXN1bHRzX3RnZiwgR2VuZVZhciA9IHJvd1Nkcyhhc3NheSh2c2QpKSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHBhZGopKQ0KDQojIGFycmFuZ2UgYnkgdGhlIG5ldyBjb2x1bW4gYW5kIGV4dHJhY3QgRU5TRU1CTCBJRCBvZiB0aGUgZmlyc3QgMTAwIHJvd3MNCg0KZ2VuZXNfdG9fcGxvdCA8LSBhcnJhbmdlKHJlc193aXRoX3ZhciwgZGVzYyhHZW5lVmFyKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMDApICU+JSANCiAgcHVsbChFTlNFTUJMKQ0KDQoNCmBgYA0KDQpgYGB7ciBmaWcud2lkdGg9MTJ9DQoNCnBoZWF0bWFwKGFzc2F5KHZzZClbZ2VuZXNfdG9fcGxvdCxdLA0KICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBzYW1wbGVJbmZvLA0KICAgICAgICAgc2NhbGU9InJvdyIpDQpgYGANCg0KYGBge3IgZmlnLndpZHRoPTEyfQ0KZ2VuZV9sYWJlbHMgPC0gYXJyYW5nZShyZXNfd2l0aF92YXIsIGRlc2MoR2VuZVZhcikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTAwKSAlPiUgDQogIHB1bGwoU1lNQk9MKQ0KDQpwaGVhdG1hcChhc3NheSh2c2QpW2dlbmVzX3RvX3Bsb3QsXSwNCiAgICAgICAgIGFubm90YXRpb25fY29sID0gc2FtcGxlSW5mbywNCiAgICAgICAgIGxhYmVsc19yb3cgPSBnZW5lX2xhYmVscywNCiAgICAgICAgIHNjYWxlPSJyb3ciKQ0KDQpgYGANCg0KIyBFeGVyY2lzZTogUGF0aHdheXMNCg0KKipOZWVkIHRvIGZpeCwgYXMgY3VycmVudGx5IHRoaXMgZG9lc24ndCByZXR1cm4gYW55dGhpbmchKioNCg0KSW4gb3JkZXIgdG8gdXNlIHRoZSBgZW5yaWNoS0VHR2AgZnVuY3Rpb24sIHdlIHdpbGwgaGF2ZSB0byBkZWZpbmUgYSBzZXQgb2YgZW5yaWNoZWQgZ2VuZXMgaW4gdGVybXMgb2YgdGhlaXIgYEVOVFJFWklEYCAoaW5zdGVhZCBvZiBgRU5TRU1CTGApDQoNCmBgYHtyfQ0Kc2lnR2VuZXNFbnRyZXogPC0gcmVzdWx0c190Z2YgJT4lIA0KICBmaWx0ZXIocGFkaiA8IDAuMDUsICFpcy5uYShFTlRSRVpJRCkpICU+JSBwdWxsKEVOVFJFWklEKQ0KDQpgYGANCg0KTWFrZSBzdXJlIHlvdSBjaGVjayB0aGUgaGVscCBmb3IgYGVucmljaEtFR0dgLCBhcyBpdCB1c2VzIGRpZmZlcmVudCBhcmd1bWVudCBuYW1lcw0KDQpgYGB7cn0NCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQ0KZW5yaWNoX2tlZ2cgPC0gZW5yaWNoS0VHRyhnZW5lID0gc2lnR2VuZXNFbnRyZXosDQogICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYSIsKQ0KYXMuZGF0YS5mcmFtZShlbnJpY2hfa2VnZykNCmBgYA0KVGhlIHNhbWUgcGxvdHMgY2FuIGJlIGNyZWF0ZWQgZnJvbSB0aGUgcmVzdWx0cy4gSGVyZSBpcyB0aGUgZG90IHBsb3QuDQoNCmBgYHtyIGZpZy53aWR0aD0xMn0NCmRvdHBsb3QoZW5yaWNoX2tlZ2cpDQpgYGANCmFuZCB0aGUgdXBzZXQgcGxvdC4NCg0KYGBge3IgZmlnLndpZHRoPTEyfQ0KZW5yaWNocGxvdDo6dXBzZXRwbG90KGVucmljaF9rZWdnKQ0KYGBgDQoNCkZvciB0aGUgR1NFQSBhbmFseXNpcyB1c2luZyBLRUdHIHdlIGNhbiB1c2UgdGhlIHNhbWUgc2V0IG9mIHJhbmtlZCBzdGF0aXN0aWNzLCBidXQgbWFrZSBzdXJlIHRvIG5hbWUgdGhlbSBhY2NvcmRpbmcgdG8gRU5UUkVaSUQNCg0KYGBge3J9DQpyYW5rZWRfZ2VuZXMgPC0gcmVzdWx0c190Z2YgJT4lIA0KICBhcnJhbmdlKGRlc2Moc3RhdCkpICU+JSANCiAgZmlsdGVyKCFpcy5uYShzdGF0KSkNCiAgDQpnZW5lTGlzdCA8LSBwdWxsKHJhbmtlZF9nZW5lcywgc3RhdCkNCm5hbWVzKGdlbmVMaXN0KSA8LSBwdWxsKHJhbmtlZF9nZW5lcywgRU5UUkVaSUQpDQpgYGANCg0KQWdhaW4sIG1ha2Ugc3VyZSB0byBjaGVjayB0aGUgYXJndW1lbnRzIGZvciBgZ3NlS0VHR2AuIA0KDQpgYGB7cn0NCmdzZV9rZWdnIDwtIGdzZUtFR0coZ2VuZUxpc3QgPSBnZW5lTGlzdCwNCiAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhIikNCmFzLmRhdGEuZnJhbWUoZ3NlX2tlZ2cpDQpgYGANCg0KDQo=
+
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKV2Ugc3RhcnQgYnkgbG9hZGluZyBvdXIgcmVzdWx0cyBmcm9tIHRoZSBwcmV2aW91cyB3ZWVrCgpgYGB7cn0KbGlicmFyeShERVNlcTIpCmxpYnJhcnkoZHBseXIpCiMjIFJlYWQgdGhlIGFubm90YXRlZCByZXN1bHRzCnJlc3VsdHNfdGdmIDwtIHJlYWRSRFMoIlJvYmplY3RzL3Jlc3VsdHNfVEdGX3ZzX0NUUl9hbm5vdGF0ZWRfQkFDS1VQLnJkcyIpCiMjIFJlYWQgdGhlIGNvdW50cyB0aGF0IHdlIHByb2R1Y2VkIHByZXZpb3VzbHkKZGRzIDwtIHJlYWRSRFMoIlJvYmplY3RzL2Rkc19CQUNLVVAucmRzIikKYGBgCgojIEV4ZXJjaXNlOiBWb2xjYW5vIHBsb3QKClRoZSBzdGFuZGFyZCB2b2xjYW5vIHBsb3QgY2FuIGJlIHByb2R1Y2VkIHdpdGggdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlCgpgYGB7cn0KCmxpYnJhcnkoZ2dwbG90MikKcmVzdWx0c190Z2YgJT4lIAogIGdncGxvdChhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLCB5ID0gLWxvZzEwKHBhZGopKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpgYGB7cn0KbGlicmFyeShvcmcuSHMuZWcuZGIpCmVjbV9hbm5vIDwtIEFubm90YXRpb25EYmk6OnNlbGVjdChvcmcuSHMuZWcuZGIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleXMgPSAiR086MDAzMDE5OCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleXR5cGUgPSAiR08iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5zPWMoIkVOU0VNQkwiLCJTWU1CT0wiKSkKZWNtX2Fubm8KYGBgCgpgYGB7cn0KZWNtX2lkcyA8LSBwdWxsKGVjbV9hbm5vLCAiRU5TRU1CTCIpCmBgYAoKYGBge3J9CnJlc3VsdHNfdGdmICU+JSAKICBtdXRhdGUoRUNNX0dlbmUgPSBFTlNFTUJMICVpbiUgZWNtX2lkcykgJT4lIAogIGdncGxvdChhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLCB5ID0gLWxvZzEwKHBhZGopLGNvbD1FQ01fR2VuZSkpICsgZ2VvbV9wb2ludCgpCmBgYApUaGUgZGVmYXVsdCBjb2xvdXJpbmcgZG9lcyBub3QgZGlzdGluZ3Vpc2ggdGhlIEVDTSBnZW5lcyBhcyBtdWNoIGFzIHdlIG1pZ2h0IGxpa2UuIFdlIGNvdWxkIG1hbnVhbGx5IGFkanVzdCBpdCBzbyB0aGF0IGdlbmVzIGJlbG9uZ2luZyB0byB0aGUgcGF0aHdheSBhcmUgY29sb3VyZWQgaW4gcmVkLCBhbmQgdGhlIHJlc3QgaW4gYmxhY2suIFRoZSB0cmFuc3BhcmVuY3kgKGBhbHBoYWApIGNhbiBhbHNvIGJlIGFkanVzdGVkLiBCZWxvdyBpcyBhIHN1Z2dlc3Rpb24uCgpgYGB7cn0KcmVzdWx0c190Z2YgJT4lIAogIG11dGF0ZShFQ01fR2VuZSA9IEVOU0VNQkwgJWluJSBlY21faWRzKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9nMkZvbGRDaGFuZ2UsIHkgPSAtbG9nMTAocGFkaiksY29sPUVDTV9HZW5lLGFscGhhPUVDTV9HZW5lKSkgKyBnZW9tX3BvaW50KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwicmVkIikpICsgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcz1jKDAuMiwxKSkKYGBgCiMgRXhlcmNpc2U6IEhlYXRtYXAKClRoZSB0cmlja3kgcGFydCBvZiBtYWtpbmcgYSBoZWF0bWFwIGlzIGRlY2lkaW5nIHdoaWNoIGdlbmVzIHRvIGluY2x1ZGUuIFRoZSBnZW5lIG5hbWVzIGhhdmUgdG8gYmUgaW4gRU5TRU1CTCBmb3JtYXQsIGFzIHRoZSBjb3VudCBtYXRyaXggd2Ugd2lsbCBiZSBwbG90dGluZyBoYXMgRU5TRU1CTCBuYW1lcyBpbiB0aGUgcm93cy4KCkluIHRoZSBmb2xsb3dpbmcgZXhhbXBsZSwgd2UgY2hvc2UgdGhlIGdlbmVzIHdpdGggbW9zdCBleHRyZW1lIGxvZzIgZm9sZC1jaGFuZ2UKCmBgYHtyfQojIFRoZSBwaGVhdG1hcCBsaWJyYXJ5IGlzIG5lZWRlZCB0byBtYWtlIHRoZSBoZWF0bWFwCgpsaWJyYXJ5KHBoZWF0bWFwKQoKI2ZpcnN0LCBnZXQgdmFyaWFuY2Utc3RhYmxpc2VkIGNvdW50cwoKdnNkIDwtIHZzdChkZHMpCnNhbXBsZUluZm8gPC0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGRkcylbLGMoImNvbmRpdGlvbiIsIlRyZWF0ZWQiKV0pCgojIyBPcmRlciByZXN1bHRzIGJ5IGxvZzJGb2xkQ2hhbmdlIGFuZCBnZXQgdGhlIG1vc3QgZXh0cmVtZQoKdG9wX2dlbmVzX2xvZ0ZDIDwtIHJlc3VsdHNfdGdmICU+JSAKICBhcnJhbmdlKGRlc2MoYWJzKGxvZzJGb2xkQ2hhbmdlKSkpICU+JSAKICBzbGljZSgxOjMwKSAlPiUgCiAgcHVsbChFTlNFTUJMKQoKdG9wX2dlbmVzX2xvZ0ZDX2xhYmVscyA8LSByZXN1bHRzX3RnZiAlPiUgCiAgYXJyYW5nZShkZXNjKGFicyhsb2cyRm9sZENoYW5nZSkpKSAlPiUgCiAgc2xpY2UoMTozMCkgJT4lIAogIHB1bGwoU1lNQk9MKQoKIyMgZ2V0IHRoZSBjb3JyZXNwb25kaW5nIGdlZW4gc3ltYm9scwoKcGhlYXRtYXAoYXNzYXkodnNkKVt0b3BfZ2VuZXNfbG9nRkMsXSwKICAgICAgICAgc2NhbGUgPSAicm93IiwKICAgICAgICAgbGFiZWxzX3JvdyA9IHRvcF9nZW5lc19sb2dGQ19sYWJlbHMpCgpgYGAKCgoKCgojIEV4ZXJjaXNlOiBQYXRod2F5cwoKCkluIG9yZGVyIHRvIHVzZSB0aGUgYGVucmljaEtFR0dgIGZ1bmN0aW9uLCB3ZSB3aWxsIGhhdmUgdG8gZGVmaW5lIGEgc2V0IG9mIGVucmljaGVkIGdlbmVzIGluIHRlcm1zIG9mIHRoZWlyIGBFTlRSRVpJRGAgKGluc3RlYWQgb2YgYEVOU0VNQkxgKQoKYGBge3J9CnNpZ0dlbmVzRW50cmV6IDwtIHJlc3VsdHNfdGdmICU+JSAKICBmaWx0ZXIocGFkaiA8IDAuMDUsICFpcy5uYShFTlRSRVpJRCkpICU+JSBwdWxsKEVOVFJFWklEKQoKYGBgCgpNYWtlIHN1cmUgeW91IGNoZWNrIHRoZSBoZWxwIGZvciBgZW5yaWNoS0VHR2AsIGFzIGl0IHVzZXMgZGlmZmVyZW50IGFyZ3VtZW50IG5hbWVzCgpgYGB7cn0KbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmVucmljaF9rZWdnIDwtIGVucmljaEtFR0coZ2VuZSA9IHNpZ0dlbmVzRW50cmV6LAogICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYSIsKQphcy5kYXRhLmZyYW1lKGVucmljaF9rZWdnKQpgYGAKVGhlIHNhbWUgcGxvdHMgY2FuIGJlIGNyZWF0ZWQgZnJvbSB0aGUgcmVzdWx0cy4gSGVyZSBpcyB0aGUgZG90IHBsb3QuCgpgYGB7ciBmaWcud2lkdGg9MTJ9CmRvdHBsb3QoZW5yaWNoX2tlZ2cpCmBgYAphbmQgdGhlIHVwc2V0IHBsb3QuCgpgYGB7ciBmaWcud2lkdGg9MTJ9CmVucmljaHBsb3Q6OnVwc2V0cGxvdChlbnJpY2hfa2VnZykKYGBgCgpGb3IgdGhlIEdTRUEgYW5hbHlzaXMgdXNpbmcgS0VHRyB3ZSBjYW4gdXNlIHRoZSBzYW1lIHNldCBvZiByYW5rZWQgc3RhdGlzdGljcywgYnV0IG1ha2Ugc3VyZSB0byBuYW1lIHRoZW0gYWNjb3JkaW5nIHRvIEVOVFJFWklECgpgYGB7cn0KcmFua2VkX2dlbmVzIDwtIHJlc3VsdHNfdGdmICU+JSAKICBhcnJhbmdlKGRlc2Moc3RhdCkpICU+JSAKICBmaWx0ZXIoIWlzLm5hKHN0YXQpKQogIApnZW5lTGlzdCA8LSBwdWxsKHJhbmtlZF9nZW5lcywgc3RhdCkKbmFtZXMoZ2VuZUxpc3QpIDwtIHB1bGwocmFua2VkX2dlbmVzLCBFTlRSRVpJRCkKYGBgCgpBZ2FpbiwgbWFrZSBzdXJlIHRvIGNoZWNrIHRoZSBhcmd1bWVudHMgZm9yIGBnc2VLRUdHYC4gCgpgYGB7cn0KZ3NlX2tlZ2cgPC0gZ3NlS0VHRyhnZW5lTGlzdCA9IGdlbmVMaXN0LAogICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYSIpCmFzLmRhdGEuZnJhbWUoZ3NlX2tlZ2cpCmBgYAoKCg==