From ac6a0b0a5c96f0febcd6816da766abca44e981e5 Mon Sep 17 00:00:00 2001 From: igor <6363505+igordot@users.noreply.github.com> Date: Mon, 14 Sep 2020 15:30:35 -0400 Subject: [PATCH] clean up cell types tutorial --- scrna-cell-types-2020-09.Rmd | 18 +++++++--- scrna-cell-types-2020-09.nb.html | 56 ++++++++++++++++---------------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/scrna-cell-types-2020-09.Rmd b/scrna-cell-types-2020-09.Rmd index 0b75140..673c78d 100644 --- a/scrna-cell-types-2020-09.Rmd +++ b/scrna-cell-types-2020-09.Rmd @@ -40,7 +40,7 @@ library(stringr) Load the dataset. ```{r load-seurat-object, message=FALSE, warning=FALSE} -so = readRDS(url("https://osf.io/cvnqb/download", "rb")) +so = readRDS(url("https://osf.io/cvnqb/download")) so ``` @@ -152,7 +152,7 @@ DimPlot(so_labeled, reduction = "tsne", group.by = "labels") + SingleR is able to label cells, but it requires a reference dataset. -A more exploratory and unbiased approach is possible with [clustermole](https://github.com/igordot/clustermole), an R package that provides a collection of cell type markers for thousands of human and mouse cell populations sourced from a variety of databases as well as methods to query them. +A more exploratory and unbiased approach is possible with [clustermole](https://cran.r-project.org/package=clustermole), an R package that provides a collection of cell type markers for thousands of human and mouse cell populations sourced from a variety of databases as well as methods to query them. Load clustermole. @@ -236,7 +236,7 @@ Check the top scoring cell types for the B-cell cluster. head(overlaps_tbl, 10) ``` -find markers for the Adipo-CAR cluster +Find markers for the Adipo-CAR cluster. ```{r} acar_genes = rownames(avg_exp_mat[avg_exp_mat[, "Adipo-CAR"] == rowMaxs(avg_exp_mat), ]) @@ -274,7 +274,7 @@ Check the top scoring cell types for the Adipo-CAR cluster. head(overlaps_tbl, 10) ``` -find markers for the Osteoblasts cluster +Find markers for the Osteoblasts cluster. ```{r} o_genes = rownames(avg_exp_mat[avg_exp_mat[, "Osteoblasts"] == rowMaxs(avg_exp_mat), ]) @@ -320,18 +320,26 @@ Run enrichment of all cell type signatures across all clusters. enrich_tbl = clustermole_enrichment(expr_mat = avg_exp_mat, species = "mm") ``` -top scoring cell types per cluster +Most enriched cell types for the B-cell cluster. ```{r} enrich_tbl %>% filter(cluster == "B-cell") %>% select(-cluster) %>% head(10) ``` +Most enriched cell types for the Adipo-CAR cluster. + ```{r} enrich_tbl %>% filter(cluster == "Adipo-CAR") %>% select(-cluster) %>% head(10) ``` +Most enriched cell types for the Osteoblasts cluster. + ```{r} enrich_tbl %>% filter(cluster == "Osteoblasts") %>% select(-cluster) %>% head(10) ``` +--- + +[previous tutorials](https://igordot.github.io/tutorials/) + diff --git a/scrna-cell-types-2020-09.nb.html b/scrna-cell-types-2020-09.nb.html index 23573c8..28f9f80 100644 --- a/scrna-cell-types-2020-09.nb.html +++ b/scrna-cell-types-2020-09.nb.html @@ -2942,8 +2942,8 @@

Load data

Load the dataset.

- -
so = readRDS(url("https://osf.io/cvnqb/download", "rb"))
+
+
so = readRDS(url("https://osf.io/cvnqb/download"))
 so
@@ -2962,7 +2962,7 @@

Load data

scale_color_nejm()
-

+

@@ -2974,7 +2974,7 @@

Load data

scale_color_nejm() -

+

@@ -2986,7 +2986,7 @@

Load data

scale_color_igv() -

+

@@ -3095,16 +3095,14 @@

MouseRNAseqData cell types

so_labeled@meta.data %>% select(labels) %>% table(useNA = "ifany")
- +
.
-       Adipocytes           B cells    Cardiomyocytes   Dendritic cells 
-                6               400                 3                 1 
-Endothelial cells      Erythrocytes       Fibroblasts      Granulocytes 
-              201               372               815               191 
-      Macrophages         Monocytes          NK cells  Oligodendrocytes 
-                2               534                72                90 
-          T cells 
-              134 
+ Adipocytes B cells Cardiomyocytes Dendritic cells Endothelial cells + 6 400 3 1 201 + Erythrocytes Fibroblasts Granulocytes Macrophages Monocytes + 372 815 191 2 534 + NK cells Oligodendrocytes T cells + 72 90 134 @@ -3114,16 +3112,14 @@

MouseRNAseqData cell types

so_labeled@meta.data %>% select(pruned.labels) %>% table(useNA = "ifany")
- +
.
-       Adipocytes           B cells    Cardiomyocytes   Dendritic cells 
-                6               400                 3                 1 
-Endothelial cells      Erythrocytes       Fibroblasts      Granulocytes 
-              197               372               815               191 
-      Macrophages         Monocytes          NK cells  Oligodendrocytes 
-                2               534                66                88 
-          T cells              <NA> 
-              115                31 
+ Adipocytes B cells Cardiomyocytes Dendritic cells Endothelial cells + 6 400 3 1 197 + Erythrocytes Fibroblasts Granulocytes Macrophages Monocytes + 372 815 191 2 534 + NK cells Oligodendrocytes T cells <NA> + 66 88 115 31 @@ -3144,7 +3140,7 @@

MouseRNAseqData cell types

Annotation using clustermole

SingleR is able to label cells, but it requires a reference dataset.

-

A more exploratory and unbiased approach is possible with clustermole, an R package that provides a collection of cell type markers for thousands of human and mouse cell populations sourced from a variety of databases as well as methods to query them.

+

A more exploratory and unbiased approach is possible with clustermole, an R package that provides a collection of cell type markers for thousands of human and mouse cell populations sourced from a variety of databases as well as methods to query them.

Load clustermole.

@@ -3354,7 +3350,7 @@

Marker gene overlaps

-

find markers for the Adipo-CAR cluster

+

Find markers for the Adipo-CAR cluster.

@@ -3433,7 +3429,7 @@

Marker gene overlaps

-

find markers for the Osteoblasts cluster

+

Find markers for the Osteoblasts cluster.

@@ -3526,7 +3522,7 @@

Enrichment of markers

-

top scoring cell types per cluster

+

Most enriched cell types for the B-cell cluster.

@@ -3541,6 +3537,7 @@

Enrichment of markers

+

Most enriched cell types for the Adipo-CAR cluster.

@@ -3555,6 +3552,7 @@

Enrichment of markers

+

Most enriched cell types for the Osteoblasts cluster.

@@ -3569,11 +3567,13 @@

Enrichment of markers

+
+

previous tutorials

-
LS0tCnRpdGxlOiAiQ2VsbCBUeXBlIEFubm90YXRpb24iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogbm9uZQotLS0KCgojIyBJbnRyb2R1Y3Rpb24KClRoaXMgaXMgYSBicmllZiB0dXRvcmlhbCBvbiBhdXRvbWF0aWMgY2VsbCB0eXBlIGFubm90YXRpb24gb2Ygc2luZ2xlLWNlbGwgUk5BIHNlcXVlbmNpbmcgKHNjUk5BLXNlcSkgZGF0YS4gVGhlIHByaW1hcnkgZGF0YXNldCB1c2VkIGhlcmUgY29udGFpbnMgaGVtYXRvcG9pZXRpYyBhbmQgc3Ryb21hbCBib25lIG1hcnJvdyBwb3B1bGF0aW9ucyAoW0JhY2NpbiBldCBhbC5dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L3M0MTU1Ni0wMTktMDQzOS02KSkuIFRoZSB2ZXJzaW9uIHVzZWQgaGVyZSBpcyBhIHN1YnNldCBvZiB0aGUgb3JpZ2luYWwgZGF0YXNldCB0byBoYXZlIG1vcmUgc2ltaWxhciBwb3B1bGF0aW9uIHNpemVzIGFuZCBzcGVlZCB1cCBwcm9jZXNzaW5nLgoKIyMgTG9hZCBkYXRhCgpUaGlzIHR1dG9yaWFsIGluY2x1ZGVzIHNvbWUgQmlvY29uZHVjdG9yIGRlcGVuZGVuY2llcy4gQmVmb3JlIHByb2NlZWRpbmcsIGNvbmZpcm0gdGhhdCBCaW9jb25kdWN0b3IgaXMgaW5zdGFsbGVkIGFuZCBpdHMgdmVyc2lvbiBpcyBhdCBsZWFzdCAzLjEwLgoKYGBge3IgYmlvYy12ZXJzaW9ufQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQp9CkJpb2NNYW5hZ2VyOjp2ZXJzaW9uKCkKYGBgCgpJZiB0aGlzIGlzIG5vdCB0aGUgY2FzZSwgcmVtb3ZlIGFsbCB2ZXJzaW9ucyBvZiBCaW9jVmVyc2lvbiB3aXRoIGByZW1vdmUucGFja2FnZXMoIkJpb2NWZXJzaW9uIilgLiBUaGVuIHVwZGF0ZSBCaW9jb25kdWN0b3IgcGFja2FnZXMgdXNpbmcgYEJpb2NNYW5hZ2VyOjppbnN0YWxsKClgLgoKU2luY2Ugd2UgYXJlIHVzaW5nIGEgU2V1cmF0IG9iamVjdCwgbG9hZCBTZXVyYXQgYW5kIHJlbGF0ZWQgcGFja2FnZXMuCgpgYGB7ciBsb2FkLWxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdnc2NpKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmBgYAoKTG9hZCB0aGUgZGF0YXNldC4KCmBgYHtyIGxvYWQtc2V1cmF0LW9iamVjdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc28gPSByZWFkUkRTKHVybCgiaHR0cHM6Ly9vc2YuaW8vY3ZucWIvZG93bmxvYWQiLCAicmIiKSkKc28KYGBgCgpDaGVjayB0aGUgZXhwZXJpbWVudCBsYWJlbHMgb3ZlcmxhaWQgb250byB0aGUgVU1BUCB2aXN1YWxpemF0aW9uLgoKYGBge3IgdW1hcC1leHB9CkRpbVBsb3Qoc28sIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiZXhwZXJpbWVudCIsIGNlbGxzID0gc2FtcGxlKGNvbG5hbWVzKHNvKSkpICsKICBzY2FsZV9jb2xvcl9uZWptKCkKYGBgCgpDaGVjayB0aGUgZXhwZXJpbWVudCBsYWJlbHMgb3ZlcmxhaWQgb250byB0aGUgdFNORSB2aXN1YWxpemF0aW9uLCBhcyBzaG93biBpbiB0aGUgb3JpZ2luYWwgcHVibGljYXRpb24gKFtvcmlnaW5hbCBmaWd1cmVdKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTU2LTAxOS0wNDM5LTYvZmlndXJlcy8xKSkuCgpgYGB7ciB0c25lLWV4cH0KRGltUGxvdChzbywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJleHBlcmltZW50IiwgY2VsbHMgPSBzYW1wbGUoY29sbmFtZXMoc28pKSkgKwogIHNjYWxlX2NvbG9yX25lam0oKQpgYGAKCkNoZWNrIHRoZSBjZWxsIHR5cGUgbGFiZWxzIG92ZXJsYWlkIG9udG8gdGhlIHRTTkUgdmlzdWFsaXphdGlvbi4KCmBgYHtyIHRzbmUtY2VsbHR5cGV9CkRpbVBsb3Qoc28sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiY2VsbHR5cGUiLCBjZWxscyA9IHNhbXBsZShjb2xuYW1lcyhzbykpKSArCiAgc2NhbGVfY29sb3JfaWd2KCkKYGBgCgojIyBBbm5vdGF0aW9uIHVzaW5nIFNpbmdsZVIKCkxvYWQgU2luZ2xlUiAoaW5zdGFsbCB3aXRoIGBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiU2luZ2xlUiIpYCkuCgpgYGB7ciBsb2FkLXNpbmdsZXIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoU2luZ2xlUikKYGBgCgpTaW5nbGVSIGV4cGVjdHMgdGhlIGlucHV0IGFzIGEgbWF0cml4IG9yIGEgU3VtbWFyaXplZEV4cGVyaW1lbnQgb2JqZWN0LgoKYGBge3IgZXhwLW1hdH0KZXhwX21hdCA9IEdldEFzc2F5RGF0YShzbywgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikKZXhwX21hdCA9IGFzLm1hdHJpeChleHBfbWF0KQpkaW0oZXhwX21hdCkKYGBgCgojIyMgTW91c2VSTkFzZXFEYXRhIGNlbGwgdHlwZXMKClRoZSBTaW5nbGVSIHBhY2thZ2UgcHJvdmlkZXMgbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcyBhbmQgY2VsbCB0eXBlcyBsYWJlbHMgYmFzZWQgb24gYnVsayBSTkEtc2VxLCBtaWNyb2FycmF5LCBhbmQgc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhIGZyb20gc2V2ZXJhbCBkaWZmZXJlbnQgZGF0YXNldHMuIFNlZSB0aGUgW1NpbmdsZVIgdmlnbmV0dGVdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjEwL2Jpb2MvdmlnbmV0dGVzL1NpbmdsZVIvaW5zdC9kb2MvU2luZ2xlUi5odG1sIzVfYXZhaWxhYmxlX3JlZmVyZW5jZXMpIGZvciB0aGUgZGVzY3JpcHRpb24uCgpXZSB3aWxsIHRyeSB0aGUgbW91c2UgZGF0YXNldCBmcm9tIDM1OCBidWxrIFJOQS1zZXEgc2FtcGxlcyBvZiBzb3J0ZWQgY2VsbCBwb3B1bGF0aW9ucyBhcyB0aGUgcmVmZXJlbmNlLiBJdCBwcm92aWRlcyBub3JtYWxpemVkIGV4cHJlc3Npb24gdmFsdWVzIGZvciBzYW1wbGVzIHRoYXQgaGF2ZSBiZWVuIGFzc2lnbmVkIHRvIG9uZSBvZiAxOCBtYWluIGNlbGwgdHlwZXMgYW5kIDI4IHN1YnR5cGVzLgoKYGBge3IgbW91c2VybmFzZXEtc2UtbG9hZCwgaW5jbHVkZT1GQUxTRX0Kc2luZ2xlcl9zZSA9IE1vdXNlUk5Bc2VxRGF0YSgpCmBgYAoKSXQgaXMgcG9zc2libGUgdGhhdCB0aGlzIGZhaWxzIHdpdGggYSBgTm8gaW50ZXJuZXQgY29ubmVjdGlvbiB1c2luZyAnbG9jYWxIdWI9VFJVRSdgIGVycm9yLiBUaGlzIG1heSBiZSByZXNvbHZlZCBieSBydW5uaW5nIGBFeHBlcmltZW50SHViOjpzZXRFeHBlcmltZW50SHViT3B0aW9uKCJQUk9YWSIsICJodHRwOi8vMTI3LjAuMC4xOjEwODAxIilgLgoKYGBge3IgbW91c2VybmFzZXEtc2Utc2hvd30Kc2luZ2xlcl9zZQpgYGAKClJlc3RyaWN0IHRvIGNvbW1vbiBnZW5lcyBiZXR3ZWVuIHRoZSB0ZXN0IGFuZCByZWZlcmVuY2UgZGF0YXNldHMuCgpgYGB7ciBtb3VzZXJuYXNlcS1jb21tb24tZ2VuZXN9CmNvbW1vbl9nZW5lcyA9IGludGVyc2VjdChyb3duYW1lcyhleHBfbWF0KSwgcm93bmFtZXMoc2luZ2xlcl9zZSkpCmNvbW1vbl9nZW5lcyA9IHNvcnQoY29tbW9uX2dlbmVzKQpleHBfY29tbW9uX21hdCA9IGV4cF9tYXRbY29tbW9uX2dlbmVzLCBdCnNpbmdsZXJfc2UgPSBzaW5nbGVyX3NlW2NvbW1vbl9nZW5lcywgXQpsZW5ndGgoY29tbW9uX2dlbmVzKQpgYGAKClBlcmZvcm0gU2luZ2xlUiBhbm5vdGF0aW9uLgoKYGBge3IgbW91c2VybmFzZXEtc2luZ2xlcn0Kc2luZ2xlcl9wcmVkID0gU2luZ2xlUigKICB0ZXN0ID0gZXhwX2NvbW1vbl9tYXQsCiAgcmVmID0gc2luZ2xlcl9zZSwKICBsYWJlbHMgPSBzaW5nbGVyX3NlJGxhYmVsLm1haW4KKQpgYGAKCkVhY2ggcm93IG9mIHRoZSBvdXRwdXQgZGF0YSBmcmFtZSBjb250YWlucyBwcmVkaWN0aW9uIHJlc3VsdHMgZm9yIGEgc2luZ2xlIGNlbGwuCgpgYGB7ciBtb3VzZXJuYXNlcS1kZn0KaGVhZChhcy5kYXRhLmZyYW1lKHNpbmdsZXJfcHJlZCkpCmBgYAoKQWRkIHRoZSBhc3NpZ25lZCBsYWJlbHMgdG8gdGhlIFNldXJhdCBvYmplY3QuCgpgYGB7ciBtb3VzZXJuYXNlcS1hZGRtZXRhZGF0YX0Kc29fbGFiZWxlZCA9IEFkZE1ldGFEYXRhKHNvLCBhcy5kYXRhLmZyYW1lKHNpbmdsZXJfcHJlZCkpCmBgYAoKQ2hlY2sgdGhlIGFzc2lnbmVkIGxhYmVscyB0byB0aGUgb3JpZ2luYWwgbGFiZWxzLgoKYGBge3IgbW91c2VybmFzZXEtdGFibGV9CnNvX2xhYmVsZWRAbWV0YS5kYXRhICU+JSBzZWxlY3QobGFiZWxzKSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQpgYGAKClNpbmdsZVIgYWxzbyBhdHRlbXB0cyB0byByZW1vdmUgbG93IHF1YWxpdHkgb3IgYW1iaWd1b3VzIGFzc2lnbm1lbnRzLiBBbWJpZ3VvdXMgYXNzaWdubWVudHMgYXJlIGJhc2VkIG9uIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNjb3JlIGZvciB0aGUgYXNzaWduZWQgbGFiZWwgYW5kIHRoZSBtZWRpYW4gYWNyb3NzIGFsbCBsYWJlbHMgZm9yIGVhY2ggY2VsbC4gVHVuaW5nIHBhcmFtZXRlcnMgY2FuIGJlIGFkanVzdGVkIHdpdGggYHBydW5lU2NvcmVzKClgLiBXZSBjYW4gY2hlY2sgaG93IG1hbnkgY2VsbHMgYXJlIGNvbnNpZGVyZWQgYW1iaWd1b3VzIGFuZCB3aGljaCBwb3B1bGF0aW9ucyB0aGV5IHBvdGVudGlhbGx5IGJlbG9uZyB0by4KCmBgYHtyIG1vdXNlcm5hc2VxLXBydW5lZC10YWJsZX0Kc29fbGFiZWxlZEBtZXRhLmRhdGEgJT4lIHNlbGVjdChwcnVuZWQubGFiZWxzKSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQpgYGAKClZpc3VhbGl6ZSBNb3VzZVJOQXNlcURhdGEgY2VsbCB0eXBlIGxhYmVscy4KCmBgYHtyIG1vdXNlcm5hc2VxLXRzbmV9CkRpbVBsb3Qoc29fbGFiZWxlZCwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJsYWJlbHMiKSArCiAgc2NhbGVfY29sb3JfaWd2KCkKYGBgCgojIyBBbm5vdGF0aW9uIHVzaW5nIGNsdXN0ZXJtb2xlCgpTaW5nbGVSIGlzIGFibGUgdG8gbGFiZWwgY2VsbHMsIGJ1dCBpdCByZXF1aXJlcyBhIHJlZmVyZW5jZSBkYXRhc2V0LgoKQSBtb3JlIGV4cGxvcmF0b3J5IGFuZCB1bmJpYXNlZCBhcHByb2FjaCBpcyBwb3NzaWJsZSB3aXRoIFtjbHVzdGVybW9sZV0oaHR0cHM6Ly9naXRodWIuY29tL2lnb3Jkb3QvY2x1c3Rlcm1vbGUpLCBhbiBSIHBhY2thZ2UgdGhhdCBwcm92aWRlcyBhIGNvbGxlY3Rpb24gb2YgY2VsbCB0eXBlIG1hcmtlcnMgZm9yIHRob3VzYW5kcyBvZiBodW1hbiBhbmQgbW91c2UgY2VsbCBwb3B1bGF0aW9ucyBzb3VyY2VkIGZyb20gYSB2YXJpZXR5IG9mIGRhdGFiYXNlcyBhcyB3ZWxsIGFzIG1ldGhvZHMgdG8gcXVlcnkgdGhlbS4KCkxvYWQgY2x1c3Rlcm1vbGUuCgpgYGB7ciBsb2FkLWNsdXN0ZXJtb2xlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGNsdXN0ZXJtb2xlKQpgYGAKCiMjIyBBdmFpbGFibGUgY2VsbCB0eXBlcwoKV2UgY2FuIHJldHJpZXZlIGEgbGlzdCBvZiBhbGwgbWFya2VycyBpbiB0aGUgY2x1c3Rlcm1vbGUgZGF0YWJhc2UgdG8gc2VlIGFsbCB0aGUgYXZhaWxhYmxlIG9wdGlvbnMuIEVhY2ggcm93IGluIHRoZSByZXR1cm5lZCBkYXRhIGZyYW1lIGlzIGEgY29tYmluYXRpb24gb2YgZWFjaCBjZWxsIHR5cGUgYW5kIGl0cyBnZW5lcy4KCmBgYHtyIGNsdXN0ZXJtb2xlLW1hcmtlcnMtdGFibGV9Cm1hcmtlcnNfdGJsID0gY2x1c3Rlcm1vbGVfbWFya2VycygpCmhlYWQobWFya2Vyc190YmwpCmBgYAoKQ2hlY2sgdGhlIGF2YWlsYWJsZSBjZWxsIHR5cGVzIChpZ25vcmUgZ2VuZSBjb2x1bW5zKS4KCmBgYHtyIGNsdXN0ZXJtb2xlLW1hcmtlcnMtc3VtbWFyeX0KbWFya2Vyc190YmwgJT4lIGRpc3RpbmN0KGNlbGx0eXBlLCBvcmdhbiwgZGIpCmBgYAoKIyMjIE1hcmtlciBnZW5lIG92ZXJsYXBzCgpDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgZXhwcmVzc2lvbiBsZXZlbHMgZm9yIHRoZSBjbHVzdGVycyBmb3IgZW5yaWNobWVudCBhbmFseXNpcyB1c2luZyBTZXVyYXQncyBgQXZlcmFnZUV4cHJlc3Npb25gIGZ1bmN0aW9uLCBjb252ZXJ0IHRvIGEgbWF0cml4LCBhbmQgbG9nLXRyYW5zZm9ybS4KCmBgYHtyIGF2Zy1leHB9CklkZW50cyhzbykgPSAiY2VsbHR5cGUiCmF2Z19leHBfbWF0ID0gQXZlcmFnZUV4cHJlc3Npb24oc28sIGFzc2F5cyA9ICJSTkEiLCBzbG90ID0gImRhdGEiKQphdmdfZXhwX21hdCA9IGFzLm1hdHJpeChhdmdfZXhwX21hdCRSTkEpCmF2Z19leHBfbWF0ID0gbG9nMXAoYXZnX2V4cF9tYXQpCmBgYAoKQ2hlY2sgdGhlIGF2ZXJhZ2UgZXhwcmVzc2lvbiBtYXRyaXguCgpgYGB7ciBhdmctZXhwLWhlYWR9CmF2Z19leHBfbWF0WzE6NSwgMTo1XQpgYGAKCkNoZWNrIHRoZSBjZWxsIHR5cGUgbmFtZXMuCgpgYGB7cn0KbGV2ZWxzKElkZW50cyhzbykpCmBgYAoKRmluZCBtYXJrZXJzIGZvciB0aGUgQi1jZWxsIGNsdXN0ZXIuCgpgYGB7cn0KYl9nZW5lcyA9IHJvd25hbWVzKGF2Z19leHBfbWF0W2F2Z19leHBfbWF0WywgIkItY2VsbCJdID09IHJvd01heHMoYXZnX2V4cF9tYXQpLCBdKQpsZW5ndGgoYl9nZW5lcykKYGBgCgpgYGB7ciBmaW5kLW1hcmtlcnMtYn0KYl9tYXJrZXJzX2RmID0gRmluZE1hcmtlcnMoc28sIGlkZW50LjEgPSAiQi1jZWxsIiwgZmVhdHVyZXMgPSBiX2dlbmVzLCB2ZXJib3NlID0gRkFMU0UpCm5yb3coYl9tYXJrZXJzX2RmKQpgYGAKCkNoZWNrIHRoZSBtYXJrZXJzIHRhYmxlLgoKYGBge3IgZmluZC1tYXJrZXJzLWItaGVhZH0KaGVhZChiX21hcmtlcnNfZGYpCmBgYAoKV2l0aCB0aGUgZGVmYXVsdCBjdXRvZmZzLCB0aGlzIGdpdmVzIHVzIGEgZGF0YSBmcmFtZSB3aXRoIGh1bmRyZWRzIG9mIGdlbmVzLiBMZXQncyBzdWJzZXQgdG8ganVzdCB0aGUgdG9wIDIwIGdlbmVzLgoKYGBge3IgbWFya2Vycy10b3AtZ2VuZXN9CmJfbWFya2VycyA9IHJvd25hbWVzKGJfbWFya2Vyc19kZikKYl9tYXJrZXJzID0gaGVhZChiX21hcmtlcnMsIDIwKQpiX21hcmtlcnMKYGBgCgpDaGVjayBvdmVybGFwIG9mIG91ciBCLWNlbGwgbWFya2VycyB3aXRoIGFsbCBjZWxsIHR5cGUgc2lnbmF0dXJlcy4KCmBgYHtyIGNsdXN0ZXJtb2xlLW92ZXJsYXBzfQpvdmVybGFwc190YmwgPSBjbHVzdGVybW9sZV9vdmVybGFwcyhnZW5lcyA9IGJfbWFya2Vycywgc3BlY2llcyA9ICJtbSIpCmBgYAoKQ2hlY2sgdGhlIHRvcCBzY29yaW5nIGNlbGwgdHlwZXMgZm9yIHRoZSBCLWNlbGwgY2x1c3Rlci4KCmBgYHtyIGNsdXN0ZXJtb2xlLW92ZXJsYXBzLXJlc3VsdH0KaGVhZChvdmVybGFwc190YmwsIDEwKQpgYGAKCmZpbmQgbWFya2VycyBmb3IgdGhlIEFkaXBvLUNBUiBjbHVzdGVyCgpgYGB7cn0KYWNhcl9nZW5lcyA9IHJvd25hbWVzKGF2Z19leHBfbWF0W2F2Z19leHBfbWF0WywgIkFkaXBvLUNBUiJdID09IHJvd01heHMoYXZnX2V4cF9tYXQpLCBdKQpsZW5ndGgoYWNhcl9nZW5lcykKYGBgCgpgYGB7cn0KYWNhcl9tYXJrZXJzX2RmID0gRmluZE1hcmtlcnMoc28sIGlkZW50LjEgPSAiQWRpcG8tQ0FSIiwgZmVhdHVyZXMgPSBhY2FyX2dlbmVzLCB2ZXJib3NlID0gRkFMU0UpCm5yb3coYWNhcl9tYXJrZXJzX2RmKQpgYGAKCkNoZWNrIHRoZSBtYXJrZXJzIHRhYmxlLgoKYGBge3J9CmhlYWQoYWNhcl9tYXJrZXJzX2RmKQpgYGAKCldpdGggdGhlIGRlZmF1bHQgY3V0b2ZmcywgdGhpcyBnaXZlcyB1cyBhIGRhdGEgZnJhbWUgd2l0aCBodW5kcmVkcyBvZiBnZW5lcy4gTGV0J3Mgc3Vic2V0IHRvIGp1c3QgdGhlIHRvcCAyMCBnZW5lcy4KCmBgYHtyfQphY2FyX21hcmtlcnMgPSByb3duYW1lcyhhY2FyX21hcmtlcnNfZGYpCmFjYXJfbWFya2VycyA9IGhlYWQoYWNhcl9tYXJrZXJzLCAyMCkKYWNhcl9tYXJrZXJzCmBgYAoKQ2hlY2sgb3ZlcmxhcCBvZiBvdXIgQWRpcG8tQ0FSIG1hcmtlcnMgd2l0aCBhbGwgY2VsbCB0eXBlIHNpZ25hdHVyZXMuCgpgYGB7cn0Kb3ZlcmxhcHNfdGJsID0gY2x1c3Rlcm1vbGVfb3ZlcmxhcHMoZ2VuZXMgPSBhY2FyX21hcmtlcnMsIHNwZWNpZXMgPSAibW0iKQpgYGAKCkNoZWNrIHRoZSB0b3Agc2NvcmluZyBjZWxsIHR5cGVzIGZvciB0aGUgQWRpcG8tQ0FSIGNsdXN0ZXIuCgpgYGB7cn0KaGVhZChvdmVybGFwc190YmwsIDEwKQpgYGAKCmZpbmQgbWFya2VycyBmb3IgdGhlIE9zdGVvYmxhc3RzIGNsdXN0ZXIKCmBgYHtyfQpvX2dlbmVzID0gcm93bmFtZXMoYXZnX2V4cF9tYXRbYXZnX2V4cF9tYXRbLCAiT3N0ZW9ibGFzdHMiXSA9PSByb3dNYXhzKGF2Z19leHBfbWF0KSwgXSkKbGVuZ3RoKG9fZ2VuZXMpCmBgYAoKYGBge3J9Cm9fbWFya2Vyc19kZiA9IEZpbmRNYXJrZXJzKHNvLCBpZGVudC4xID0gIk9zdGVvYmxhc3RzIiwgZmVhdHVyZXMgPSBvX2dlbmVzLCB2ZXJib3NlID0gRkFMU0UpCm5yb3cob19tYXJrZXJzX2RmKQpgYGAKCkNoZWNrIHRoZSBtYXJrZXJzIHRhYmxlLgoKYGBge3J9CmhlYWQob19tYXJrZXJzX2RmKQpgYGAKCldpdGggdGhlIGRlZmF1bHQgY3V0b2ZmcywgdGhpcyBnaXZlcyB1cyBhIGRhdGEgZnJhbWUgd2l0aCBodW5kcmVkcyBvZiBnZW5lcy4gTGV0J3Mgc3Vic2V0IHRvIGp1c3QgdGhlIHRvcCAyMCBnZW5lcy4KCmBgYHtyfQpvX21hcmtlcnMgPSByb3duYW1lcyhvX21hcmtlcnNfZGYpCm9fbWFya2VycyA9IGhlYWQob19tYXJrZXJzLCAyMCkKb19tYXJrZXJzCmBgYAoKQ2hlY2sgb3ZlcmxhcCBvZiBvdXIgT3N0ZW9ibGFzdHMgbWFya2VycyB3aXRoIGFsbCBjZWxsIHR5cGUgc2lnbmF0dXJlcy4KCmBgYHtyfQpvdmVybGFwc190YmwgPSBjbHVzdGVybW9sZV9vdmVybGFwcyhnZW5lcyA9IG9fbWFya2Vycywgc3BlY2llcyA9ICJtbSIpCmBgYAoKQ2hlY2sgdGhlIHRvcCBzY29yaW5nIGNlbGwgdHlwZXMgZm9yIHRoZSBPc3Rlb2JsYXN0cyBjbHVzdGVyLgoKYGBge3J9CmhlYWQob3ZlcmxhcHNfdGJsLCAxMCkKYGBgCgojIyMgRW5yaWNobWVudCBvZiBtYXJrZXJzCgpSdW4gZW5yaWNobWVudCBvZiBhbGwgY2VsbCB0eXBlIHNpZ25hdHVyZXMgYWNyb3NzIGFsbCBjbHVzdGVycy4KCmBgYHtyfQplbnJpY2hfdGJsID0gY2x1c3Rlcm1vbGVfZW5yaWNobWVudChleHByX21hdCA9IGF2Z19leHBfbWF0LCBzcGVjaWVzID0gIm1tIikKYGBgCgp0b3Agc2NvcmluZyBjZWxsIHR5cGVzIHBlciBjbHVzdGVyCgpgYGB7cn0KZW5yaWNoX3RibCAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gIkItY2VsbCIpICU+JSBzZWxlY3QoLWNsdXN0ZXIpICU+JSBoZWFkKDEwKQpgYGAKCmBgYHtyfQplbnJpY2hfdGJsICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAiQWRpcG8tQ0FSIikgJT4lIHNlbGVjdCgtY2x1c3RlcikgJT4lIGhlYWQoMTApCmBgYAoKYGBge3J9CmVucmljaF90YmwgJT4lIGZpbHRlcihjbHVzdGVyID09ICJPc3Rlb2JsYXN0cyIpICU+JSBzZWxlY3QoLWNsdXN0ZXIpICU+JSBoZWFkKDEwKQpgYGAKCgo=
+
LS0tCnRpdGxlOiAiQ2VsbCBUeXBlIEFubm90YXRpb24iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogbm9uZQotLS0KCgojIyBJbnRyb2R1Y3Rpb24KClRoaXMgaXMgYSBicmllZiB0dXRvcmlhbCBvbiBhdXRvbWF0aWMgY2VsbCB0eXBlIGFubm90YXRpb24gb2Ygc2luZ2xlLWNlbGwgUk5BIHNlcXVlbmNpbmcgKHNjUk5BLXNlcSkgZGF0YS4gVGhlIHByaW1hcnkgZGF0YXNldCB1c2VkIGhlcmUgY29udGFpbnMgaGVtYXRvcG9pZXRpYyBhbmQgc3Ryb21hbCBib25lIG1hcnJvdyBwb3B1bGF0aW9ucyAoW0JhY2NpbiBldCBhbC5dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L3M0MTU1Ni0wMTktMDQzOS02KSkuIFRoZSB2ZXJzaW9uIHVzZWQgaGVyZSBpcyBhIHN1YnNldCBvZiB0aGUgb3JpZ2luYWwgZGF0YXNldCB0byBoYXZlIG1vcmUgc2ltaWxhciBwb3B1bGF0aW9uIHNpemVzIGFuZCBzcGVlZCB1cCBwcm9jZXNzaW5nLgoKIyMgTG9hZCBkYXRhCgpUaGlzIHR1dG9yaWFsIGluY2x1ZGVzIHNvbWUgQmlvY29uZHVjdG9yIGRlcGVuZGVuY2llcy4gQmVmb3JlIHByb2NlZWRpbmcsIGNvbmZpcm0gdGhhdCBCaW9jb25kdWN0b3IgaXMgaW5zdGFsbGVkIGFuZCBpdHMgdmVyc2lvbiBpcyBhdCBsZWFzdCAzLjEwLgoKYGBge3IgYmlvYy12ZXJzaW9ufQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQp9CkJpb2NNYW5hZ2VyOjp2ZXJzaW9uKCkKYGBgCgpJZiB0aGlzIGlzIG5vdCB0aGUgY2FzZSwgcmVtb3ZlIGFsbCB2ZXJzaW9ucyBvZiBCaW9jVmVyc2lvbiB3aXRoIGByZW1vdmUucGFja2FnZXMoIkJpb2NWZXJzaW9uIilgLiBUaGVuIHVwZGF0ZSBCaW9jb25kdWN0b3IgcGFja2FnZXMgdXNpbmcgYEJpb2NNYW5hZ2VyOjppbnN0YWxsKClgLgoKU2luY2Ugd2UgYXJlIHVzaW5nIGEgU2V1cmF0IG9iamVjdCwgbG9hZCBTZXVyYXQgYW5kIHJlbGF0ZWQgcGFja2FnZXMuCgpgYGB7ciBsb2FkLWxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdnc2NpKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmBgYAoKTG9hZCB0aGUgZGF0YXNldC4KCmBgYHtyIGxvYWQtc2V1cmF0LW9iamVjdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc28gPSByZWFkUkRTKHVybCgiaHR0cHM6Ly9vc2YuaW8vY3ZucWIvZG93bmxvYWQiKSkKc28KYGBgCgpDaGVjayB0aGUgZXhwZXJpbWVudCBsYWJlbHMgb3ZlcmxhaWQgb250byB0aGUgVU1BUCB2aXN1YWxpemF0aW9uLgoKYGBge3IgdW1hcC1leHB9CkRpbVBsb3Qoc28sIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiZXhwZXJpbWVudCIsIGNlbGxzID0gc2FtcGxlKGNvbG5hbWVzKHNvKSkpICsKICBzY2FsZV9jb2xvcl9uZWptKCkKYGBgCgpDaGVjayB0aGUgZXhwZXJpbWVudCBsYWJlbHMgb3ZlcmxhaWQgb250byB0aGUgdFNORSB2aXN1YWxpemF0aW9uLCBhcyBzaG93biBpbiB0aGUgb3JpZ2luYWwgcHVibGljYXRpb24gKFtvcmlnaW5hbCBmaWd1cmVdKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTU2LTAxOS0wNDM5LTYvZmlndXJlcy8xKSkuCgpgYGB7ciB0c25lLWV4cH0KRGltUGxvdChzbywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJleHBlcmltZW50IiwgY2VsbHMgPSBzYW1wbGUoY29sbmFtZXMoc28pKSkgKwogIHNjYWxlX2NvbG9yX25lam0oKQpgYGAKCkNoZWNrIHRoZSBjZWxsIHR5cGUgbGFiZWxzIG92ZXJsYWlkIG9udG8gdGhlIHRTTkUgdmlzdWFsaXphdGlvbi4KCmBgYHtyIHRzbmUtY2VsbHR5cGV9CkRpbVBsb3Qoc28sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiY2VsbHR5cGUiLCBjZWxscyA9IHNhbXBsZShjb2xuYW1lcyhzbykpKSArCiAgc2NhbGVfY29sb3JfaWd2KCkKYGBgCgojIyBBbm5vdGF0aW9uIHVzaW5nIFNpbmdsZVIKCkxvYWQgU2luZ2xlUiAoaW5zdGFsbCB3aXRoIGBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiU2luZ2xlUiIpYCkuCgpgYGB7ciBsb2FkLXNpbmdsZXIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoU2luZ2xlUikKYGBgCgpTaW5nbGVSIGV4cGVjdHMgdGhlIGlucHV0IGFzIGEgbWF0cml4IG9yIGEgU3VtbWFyaXplZEV4cGVyaW1lbnQgb2JqZWN0LgoKYGBge3IgZXhwLW1hdH0KZXhwX21hdCA9IEdldEFzc2F5RGF0YShzbywgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikKZXhwX21hdCA9IGFzLm1hdHJpeChleHBfbWF0KQpkaW0oZXhwX21hdCkKYGBgCgojIyMgTW91c2VSTkFzZXFEYXRhIGNlbGwgdHlwZXMKClRoZSBTaW5nbGVSIHBhY2thZ2UgcHJvdmlkZXMgbm9ybWFsaXplZCBleHByZXNzaW9uIHZhbHVlcyBhbmQgY2VsbCB0eXBlcyBsYWJlbHMgYmFzZWQgb24gYnVsayBSTkEtc2VxLCBtaWNyb2FycmF5LCBhbmQgc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhIGZyb20gc2V2ZXJhbCBkaWZmZXJlbnQgZGF0YXNldHMuIFNlZSB0aGUgW1NpbmdsZVIgdmlnbmV0dGVdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy8zLjEwL2Jpb2MvdmlnbmV0dGVzL1NpbmdsZVIvaW5zdC9kb2MvU2luZ2xlUi5odG1sIzVfYXZhaWxhYmxlX3JlZmVyZW5jZXMpIGZvciB0aGUgZGVzY3JpcHRpb24uCgpXZSB3aWxsIHRyeSB0aGUgbW91c2UgZGF0YXNldCBmcm9tIDM1OCBidWxrIFJOQS1zZXEgc2FtcGxlcyBvZiBzb3J0ZWQgY2VsbCBwb3B1bGF0aW9ucyBhcyB0aGUgcmVmZXJlbmNlLiBJdCBwcm92aWRlcyBub3JtYWxpemVkIGV4cHJlc3Npb24gdmFsdWVzIGZvciBzYW1wbGVzIHRoYXQgaGF2ZSBiZWVuIGFzc2lnbmVkIHRvIG9uZSBvZiAxOCBtYWluIGNlbGwgdHlwZXMgYW5kIDI4IHN1YnR5cGVzLgoKYGBge3IgbW91c2VybmFzZXEtc2UtbG9hZCwgaW5jbHVkZT1GQUxTRX0Kc2luZ2xlcl9zZSA9IE1vdXNlUk5Bc2VxRGF0YSgpCmBgYAoKSXQgaXMgcG9zc2libGUgdGhhdCB0aGlzIGZhaWxzIHdpdGggYSBgTm8gaW50ZXJuZXQgY29ubmVjdGlvbiB1c2luZyAnbG9jYWxIdWI9VFJVRSdgIGVycm9yLiBUaGlzIG1heSBiZSByZXNvbHZlZCBieSBydW5uaW5nIGBFeHBlcmltZW50SHViOjpzZXRFeHBlcmltZW50SHViT3B0aW9uKCJQUk9YWSIsICJodHRwOi8vMTI3LjAuMC4xOjEwODAxIilgLgoKYGBge3IgbW91c2VybmFzZXEtc2Utc2hvd30Kc2luZ2xlcl9zZQpgYGAKClJlc3RyaWN0IHRvIGNvbW1vbiBnZW5lcyBiZXR3ZWVuIHRoZSB0ZXN0IGFuZCByZWZlcmVuY2UgZGF0YXNldHMuCgpgYGB7ciBtb3VzZXJuYXNlcS1jb21tb24tZ2VuZXN9CmNvbW1vbl9nZW5lcyA9IGludGVyc2VjdChyb3duYW1lcyhleHBfbWF0KSwgcm93bmFtZXMoc2luZ2xlcl9zZSkpCmNvbW1vbl9nZW5lcyA9IHNvcnQoY29tbW9uX2dlbmVzKQpleHBfY29tbW9uX21hdCA9IGV4cF9tYXRbY29tbW9uX2dlbmVzLCBdCnNpbmdsZXJfc2UgPSBzaW5nbGVyX3NlW2NvbW1vbl9nZW5lcywgXQpsZW5ndGgoY29tbW9uX2dlbmVzKQpgYGAKClBlcmZvcm0gU2luZ2xlUiBhbm5vdGF0aW9uLgoKYGBge3IgbW91c2VybmFzZXEtc2luZ2xlcn0Kc2luZ2xlcl9wcmVkID0gU2luZ2xlUigKICB0ZXN0ID0gZXhwX2NvbW1vbl9tYXQsCiAgcmVmID0gc2luZ2xlcl9zZSwKICBsYWJlbHMgPSBzaW5nbGVyX3NlJGxhYmVsLm1haW4KKQpgYGAKCkVhY2ggcm93IG9mIHRoZSBvdXRwdXQgZGF0YSBmcmFtZSBjb250YWlucyBwcmVkaWN0aW9uIHJlc3VsdHMgZm9yIGEgc2luZ2xlIGNlbGwuCgpgYGB7ciBtb3VzZXJuYXNlcS1kZn0KaGVhZChhcy5kYXRhLmZyYW1lKHNpbmdsZXJfcHJlZCkpCmBgYAoKQWRkIHRoZSBhc3NpZ25lZCBsYWJlbHMgdG8gdGhlIFNldXJhdCBvYmplY3QuCgpgYGB7ciBtb3VzZXJuYXNlcS1hZGRtZXRhZGF0YX0Kc29fbGFiZWxlZCA9IEFkZE1ldGFEYXRhKHNvLCBhcy5kYXRhLmZyYW1lKHNpbmdsZXJfcHJlZCkpCmBgYAoKQ2hlY2sgdGhlIGFzc2lnbmVkIGxhYmVscyB0byB0aGUgb3JpZ2luYWwgbGFiZWxzLgoKYGBge3IgbW91c2VybmFzZXEtdGFibGV9CnNvX2xhYmVsZWRAbWV0YS5kYXRhICU+JSBzZWxlY3QobGFiZWxzKSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQpgYGAKClNpbmdsZVIgYWxzbyBhdHRlbXB0cyB0byByZW1vdmUgbG93IHF1YWxpdHkgb3IgYW1iaWd1b3VzIGFzc2lnbm1lbnRzLiBBbWJpZ3VvdXMgYXNzaWdubWVudHMgYXJlIGJhc2VkIG9uIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNjb3JlIGZvciB0aGUgYXNzaWduZWQgbGFiZWwgYW5kIHRoZSBtZWRpYW4gYWNyb3NzIGFsbCBsYWJlbHMgZm9yIGVhY2ggY2VsbC4gVHVuaW5nIHBhcmFtZXRlcnMgY2FuIGJlIGFkanVzdGVkIHdpdGggYHBydW5lU2NvcmVzKClgLiBXZSBjYW4gY2hlY2sgaG93IG1hbnkgY2VsbHMgYXJlIGNvbnNpZGVyZWQgYW1iaWd1b3VzIGFuZCB3aGljaCBwb3B1bGF0aW9ucyB0aGV5IHBvdGVudGlhbGx5IGJlbG9uZyB0by4KCmBgYHtyIG1vdXNlcm5hc2VxLXBydW5lZC10YWJsZX0Kc29fbGFiZWxlZEBtZXRhLmRhdGEgJT4lIHNlbGVjdChwcnVuZWQubGFiZWxzKSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQpgYGAKClZpc3VhbGl6ZSBNb3VzZVJOQXNlcURhdGEgY2VsbCB0eXBlIGxhYmVscy4KCmBgYHtyIG1vdXNlcm5hc2VxLXRzbmV9CkRpbVBsb3Qoc29fbGFiZWxlZCwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJsYWJlbHMiKSArCiAgc2NhbGVfY29sb3JfaWd2KCkKYGBgCgojIyBBbm5vdGF0aW9uIHVzaW5nIGNsdXN0ZXJtb2xlCgpTaW5nbGVSIGlzIGFibGUgdG8gbGFiZWwgY2VsbHMsIGJ1dCBpdCByZXF1aXJlcyBhIHJlZmVyZW5jZSBkYXRhc2V0LgoKQSBtb3JlIGV4cGxvcmF0b3J5IGFuZCB1bmJpYXNlZCBhcHByb2FjaCBpcyBwb3NzaWJsZSB3aXRoIFtjbHVzdGVybW9sZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvcGFja2FnZT1jbHVzdGVybW9sZSksIGFuIFIgcGFja2FnZSB0aGF0IHByb3ZpZGVzIGEgY29sbGVjdGlvbiBvZiBjZWxsIHR5cGUgbWFya2VycyBmb3IgdGhvdXNhbmRzIG9mIGh1bWFuIGFuZCBtb3VzZSBjZWxsIHBvcHVsYXRpb25zIHNvdXJjZWQgZnJvbSBhIHZhcmlldHkgb2YgZGF0YWJhc2VzIGFzIHdlbGwgYXMgbWV0aG9kcyB0byBxdWVyeSB0aGVtLgoKTG9hZCBjbHVzdGVybW9sZS4KCmBgYHtyIGxvYWQtY2x1c3Rlcm1vbGUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoY2x1c3Rlcm1vbGUpCmBgYAoKIyMjIEF2YWlsYWJsZSBjZWxsIHR5cGVzCgpXZSBjYW4gcmV0cmlldmUgYSBsaXN0IG9mIGFsbCBtYXJrZXJzIGluIHRoZSBjbHVzdGVybW9sZSBkYXRhYmFzZSB0byBzZWUgYWxsIHRoZSBhdmFpbGFibGUgb3B0aW9ucy4gRWFjaCByb3cgaW4gdGhlIHJldHVybmVkIGRhdGEgZnJhbWUgaXMgYSBjb21iaW5hdGlvbiBvZiBlYWNoIGNlbGwgdHlwZSBhbmQgaXRzIGdlbmVzLgoKYGBge3IgY2x1c3Rlcm1vbGUtbWFya2Vycy10YWJsZX0KbWFya2Vyc190YmwgPSBjbHVzdGVybW9sZV9tYXJrZXJzKCkKaGVhZChtYXJrZXJzX3RibCkKYGBgCgpDaGVjayB0aGUgYXZhaWxhYmxlIGNlbGwgdHlwZXMgKGlnbm9yZSBnZW5lIGNvbHVtbnMpLgoKYGBge3IgY2x1c3Rlcm1vbGUtbWFya2Vycy1zdW1tYXJ5fQptYXJrZXJzX3RibCAlPiUgZGlzdGluY3QoY2VsbHR5cGUsIG9yZ2FuLCBkYikKYGBgCgojIyMgTWFya2VyIGdlbmUgb3ZlcmxhcHMKCkNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBleHByZXNzaW9uIGxldmVscyBmb3IgdGhlIGNsdXN0ZXJzIGZvciBlbnJpY2htZW50IGFuYWx5c2lzIHVzaW5nIFNldXJhdCdzIGBBdmVyYWdlRXhwcmVzc2lvbmAgZnVuY3Rpb24sIGNvbnZlcnQgdG8gYSBtYXRyaXgsIGFuZCBsb2ctdHJhbnNmb3JtLgoKYGBge3IgYXZnLWV4cH0KSWRlbnRzKHNvKSA9ICJjZWxsdHlwZSIKYXZnX2V4cF9tYXQgPSBBdmVyYWdlRXhwcmVzc2lvbihzbywgYXNzYXlzID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpCmF2Z19leHBfbWF0ID0gYXMubWF0cml4KGF2Z19leHBfbWF0JFJOQSkKYXZnX2V4cF9tYXQgPSBsb2cxcChhdmdfZXhwX21hdCkKYGBgCgpDaGVjayB0aGUgYXZlcmFnZSBleHByZXNzaW9uIG1hdHJpeC4KCmBgYHtyIGF2Zy1leHAtaGVhZH0KYXZnX2V4cF9tYXRbMTo1LCAxOjVdCmBgYAoKQ2hlY2sgdGhlIGNlbGwgdHlwZSBuYW1lcy4KCmBgYHtyfQpsZXZlbHMoSWRlbnRzKHNvKSkKYGBgCgpGaW5kIG1hcmtlcnMgZm9yIHRoZSBCLWNlbGwgY2x1c3Rlci4KCmBgYHtyfQpiX2dlbmVzID0gcm93bmFtZXMoYXZnX2V4cF9tYXRbYXZnX2V4cF9tYXRbLCAiQi1jZWxsIl0gPT0gcm93TWF4cyhhdmdfZXhwX21hdCksIF0pCmxlbmd0aChiX2dlbmVzKQpgYGAKCmBgYHtyIGZpbmQtbWFya2Vycy1ifQpiX21hcmtlcnNfZGYgPSBGaW5kTWFya2VycyhzbywgaWRlbnQuMSA9ICJCLWNlbGwiLCBmZWF0dXJlcyA9IGJfZ2VuZXMsIHZlcmJvc2UgPSBGQUxTRSkKbnJvdyhiX21hcmtlcnNfZGYpCmBgYAoKQ2hlY2sgdGhlIG1hcmtlcnMgdGFibGUuCgpgYGB7ciBmaW5kLW1hcmtlcnMtYi1oZWFkfQpoZWFkKGJfbWFya2Vyc19kZikKYGBgCgpXaXRoIHRoZSBkZWZhdWx0IGN1dG9mZnMsIHRoaXMgZ2l2ZXMgdXMgYSBkYXRhIGZyYW1lIHdpdGggaHVuZHJlZHMgb2YgZ2VuZXMuIExldCdzIHN1YnNldCB0byBqdXN0IHRoZSB0b3AgMjAgZ2VuZXMuCgpgYGB7ciBtYXJrZXJzLXRvcC1nZW5lc30KYl9tYXJrZXJzID0gcm93bmFtZXMoYl9tYXJrZXJzX2RmKQpiX21hcmtlcnMgPSBoZWFkKGJfbWFya2VycywgMjApCmJfbWFya2VycwpgYGAKCkNoZWNrIG92ZXJsYXAgb2Ygb3VyIEItY2VsbCBtYXJrZXJzIHdpdGggYWxsIGNlbGwgdHlwZSBzaWduYXR1cmVzLgoKYGBge3IgY2x1c3Rlcm1vbGUtb3ZlcmxhcHN9Cm92ZXJsYXBzX3RibCA9IGNsdXN0ZXJtb2xlX292ZXJsYXBzKGdlbmVzID0gYl9tYXJrZXJzLCBzcGVjaWVzID0gIm1tIikKYGBgCgpDaGVjayB0aGUgdG9wIHNjb3JpbmcgY2VsbCB0eXBlcyBmb3IgdGhlIEItY2VsbCBjbHVzdGVyLgoKYGBge3IgY2x1c3Rlcm1vbGUtb3ZlcmxhcHMtcmVzdWx0fQpoZWFkKG92ZXJsYXBzX3RibCwgMTApCmBgYAoKRmluZCBtYXJrZXJzIGZvciB0aGUgQWRpcG8tQ0FSIGNsdXN0ZXIuCgpgYGB7cn0KYWNhcl9nZW5lcyA9IHJvd25hbWVzKGF2Z19leHBfbWF0W2F2Z19leHBfbWF0WywgIkFkaXBvLUNBUiJdID09IHJvd01heHMoYXZnX2V4cF9tYXQpLCBdKQpsZW5ndGgoYWNhcl9nZW5lcykKYGBgCgpgYGB7cn0KYWNhcl9tYXJrZXJzX2RmID0gRmluZE1hcmtlcnMoc28sIGlkZW50LjEgPSAiQWRpcG8tQ0FSIiwgZmVhdHVyZXMgPSBhY2FyX2dlbmVzLCB2ZXJib3NlID0gRkFMU0UpCm5yb3coYWNhcl9tYXJrZXJzX2RmKQpgYGAKCkNoZWNrIHRoZSBtYXJrZXJzIHRhYmxlLgoKYGBge3J9CmhlYWQoYWNhcl9tYXJrZXJzX2RmKQpgYGAKCldpdGggdGhlIGRlZmF1bHQgY3V0b2ZmcywgdGhpcyBnaXZlcyB1cyBhIGRhdGEgZnJhbWUgd2l0aCBodW5kcmVkcyBvZiBnZW5lcy4gTGV0J3Mgc3Vic2V0IHRvIGp1c3QgdGhlIHRvcCAyMCBnZW5lcy4KCmBgYHtyfQphY2FyX21hcmtlcnMgPSByb3duYW1lcyhhY2FyX21hcmtlcnNfZGYpCmFjYXJfbWFya2VycyA9IGhlYWQoYWNhcl9tYXJrZXJzLCAyMCkKYWNhcl9tYXJrZXJzCmBgYAoKQ2hlY2sgb3ZlcmxhcCBvZiBvdXIgQWRpcG8tQ0FSIG1hcmtlcnMgd2l0aCBhbGwgY2VsbCB0eXBlIHNpZ25hdHVyZXMuCgpgYGB7cn0Kb3ZlcmxhcHNfdGJsID0gY2x1c3Rlcm1vbGVfb3ZlcmxhcHMoZ2VuZXMgPSBhY2FyX21hcmtlcnMsIHNwZWNpZXMgPSAibW0iKQpgYGAKCkNoZWNrIHRoZSB0b3Agc2NvcmluZyBjZWxsIHR5cGVzIGZvciB0aGUgQWRpcG8tQ0FSIGNsdXN0ZXIuCgpgYGB7cn0KaGVhZChvdmVybGFwc190YmwsIDEwKQpgYGAKCkZpbmQgbWFya2VycyBmb3IgdGhlIE9zdGVvYmxhc3RzIGNsdXN0ZXIuCgpgYGB7cn0Kb19nZW5lcyA9IHJvd25hbWVzKGF2Z19leHBfbWF0W2F2Z19leHBfbWF0WywgIk9zdGVvYmxhc3RzIl0gPT0gcm93TWF4cyhhdmdfZXhwX21hdCksIF0pCmxlbmd0aChvX2dlbmVzKQpgYGAKCmBgYHtyfQpvX21hcmtlcnNfZGYgPSBGaW5kTWFya2VycyhzbywgaWRlbnQuMSA9ICJPc3Rlb2JsYXN0cyIsIGZlYXR1cmVzID0gb19nZW5lcywgdmVyYm9zZSA9IEZBTFNFKQpucm93KG9fbWFya2Vyc19kZikKYGBgCgpDaGVjayB0aGUgbWFya2VycyB0YWJsZS4KCmBgYHtyfQpoZWFkKG9fbWFya2Vyc19kZikKYGBgCgpXaXRoIHRoZSBkZWZhdWx0IGN1dG9mZnMsIHRoaXMgZ2l2ZXMgdXMgYSBkYXRhIGZyYW1lIHdpdGggaHVuZHJlZHMgb2YgZ2VuZXMuIExldCdzIHN1YnNldCB0byBqdXN0IHRoZSB0b3AgMjAgZ2VuZXMuCgpgYGB7cn0Kb19tYXJrZXJzID0gcm93bmFtZXMob19tYXJrZXJzX2RmKQpvX21hcmtlcnMgPSBoZWFkKG9fbWFya2VycywgMjApCm9fbWFya2VycwpgYGAKCkNoZWNrIG92ZXJsYXAgb2Ygb3VyIE9zdGVvYmxhc3RzIG1hcmtlcnMgd2l0aCBhbGwgY2VsbCB0eXBlIHNpZ25hdHVyZXMuCgpgYGB7cn0Kb3ZlcmxhcHNfdGJsID0gY2x1c3Rlcm1vbGVfb3ZlcmxhcHMoZ2VuZXMgPSBvX21hcmtlcnMsIHNwZWNpZXMgPSAibW0iKQpgYGAKCkNoZWNrIHRoZSB0b3Agc2NvcmluZyBjZWxsIHR5cGVzIGZvciB0aGUgT3N0ZW9ibGFzdHMgY2x1c3Rlci4KCmBgYHtyfQpoZWFkKG92ZXJsYXBzX3RibCwgMTApCmBgYAoKIyMjIEVucmljaG1lbnQgb2YgbWFya2VycwoKUnVuIGVucmljaG1lbnQgb2YgYWxsIGNlbGwgdHlwZSBzaWduYXR1cmVzIGFjcm9zcyBhbGwgY2x1c3RlcnMuCgpgYGB7cn0KZW5yaWNoX3RibCA9IGNsdXN0ZXJtb2xlX2VucmljaG1lbnQoZXhwcl9tYXQgPSBhdmdfZXhwX21hdCwgc3BlY2llcyA9ICJtbSIpCmBgYAoKTW9zdCBlbnJpY2hlZCBjZWxsIHR5cGVzIGZvciB0aGUgQi1jZWxsIGNsdXN0ZXIuCgpgYGB7cn0KZW5yaWNoX3RibCAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gIkItY2VsbCIpICU+JSBzZWxlY3QoLWNsdXN0ZXIpICU+JSBoZWFkKDEwKQpgYGAKCk1vc3QgZW5yaWNoZWQgY2VsbCB0eXBlcyBmb3IgdGhlIEFkaXBvLUNBUiBjbHVzdGVyLgoKYGBge3J9CmVucmljaF90YmwgJT4lIGZpbHRlcihjbHVzdGVyID09ICJBZGlwby1DQVIiKSAlPiUgc2VsZWN0KC1jbHVzdGVyKSAlPiUgaGVhZCgxMCkKYGBgCgpNb3N0IGVucmljaGVkIGNlbGwgdHlwZXMgZm9yIHRoZSBPc3Rlb2JsYXN0cyBjbHVzdGVyLgoKYGBge3J9CmVucmljaF90YmwgJT4lIGZpbHRlcihjbHVzdGVyID09ICJPc3Rlb2JsYXN0cyIpICU+JSBzZWxlY3QoLWNsdXN0ZXIpICU+JSBoZWFkKDEwKQpgYGAKCi0tLQoKW3ByZXZpb3VzIHR1dG9yaWFsc10oaHR0cHM6Ly9pZ29yZG90LmdpdGh1Yi5pby90dXRvcmlhbHMvKQoKCg==