Functions
Data
calculatePathwayScores <- function(pathwayToScore, countsMatrix)
{
pathwayName <- pathwayToScore@setName
pathwayGenes <- pathwayToScore@geneIds
pathwayScoresObject <- getPathwayScores(countsMatrix, pathwayGenes)
return(pathwayScoresObject$pathwayScores)
}
GBMSeurat_cancer = readRDS("./Data/GSM3828673_10X_GBM_seurat_cancer.RDS")
genesets <- getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")
metaModuleGenes <- read.table(file = "./Data/MetaModuleGenes_CellPaper.tsv", header = TRUE)
# Creating genesets for the meta module markers
MesLike2GeneSet <- GeneSet(metaModuleGenes[,1])
MesLike1GeneSet <- GeneSet(metaModuleGenes[,2])
ACLikeGeneSet <- GeneSet(metaModuleGenes[!is.na(metaModuleGenes[,3]), 3])
OPCLikeGeneSet <- GeneSet(metaModuleGenes[,4])
NPCLike1GeneSet <- GeneSet(metaModuleGenes[,5])
NPCLike2GeneSet <- GeneSet(metaModuleGenes[,6])
MesLike1GeneSet@setName <- "MesLike1"
MesLike2GeneSet@setName <- "MesLike2"
ACLikeGeneSet@setName <- "ACLike"
OPCLikeGeneSet@setName <- "OPCLike"
NPCLike1GeneSet@setName <- "NPCLike1"
NPCLike2GeneSet@setName <- "NPCLike2"
TPMCounts = GBMSeurat_cancer@assays$RNA@counts %>% as.matrix() %>% Matrix(sparse = T)
pathwayScoreLists <- lapply(X = genesets@.Data, calculatePathwayScores, TPMCounts)
pathwayScoresMatrix <- as.data.frame(do.call("rbind", pathwayScoreLists))
## Adding the pathway name to each list of pathway scores, as the names will be used during the clustering pre-processing steps
for(currPathwayIndex in 1:length(pathwayScoreLists))
{
rownames(pathwayScoresMatrix)[currPathwayIndex] <- genesets@.Data[[currPathwayIndex]]@setName
}
GBMSeurat_cancer_sipsic <- CreateSeuratObject(counts = pathwayScoresMatrix)
Warning: Feature names cannot have underscores ('_'), replacing with dashes ('-')
cancer_markers = list(
MesLike1 = MesLike1GeneSet@geneIds,
MesLike2 = MesLike2GeneSet@geneIds,
ACLike = ACLikeGeneSet@geneIds,
OPCLike = OPCLikeGeneSet@geneIds,
NPCLike1 = NPCLike1GeneSet@geneIds,
NPCLike2 = NPCLike2GeneSet@geneIds
)
GBMSeurat_cancer <- AddModuleScore(
object = GBMSeurat_cancer,
features = cancer_markers,ctrl = 50,name = "cancer_markers")
Warning: The following features are not present in the object: ERO1L, not searching for symbol synonyms
Warning: The following features are not present in the object: PPAP2B, not searching for symbol synonyms
Warning: The following features are not present in the object: SOX2-OT, LPPR1, not searching for symbol synonyms
Warning: The following features are not present in the object: CD24, GPR56, not searching for symbol synonyms
Warning: The following features are not present in the object: CD24, HMP19, LOC150568, not searching for symbol synonyms
GBMSeurat_cancer_sipsic[["MesLike1"]] = GBMSeurat_cancer$cancer_markers1
GBMSeurat_cancer_sipsic[["MesLike2"]] = GBMSeurat_cancer$cancer_markers2
GBMSeurat_cancer_sipsic[["ACLike"]] = GBMSeurat_cancer$cancer_markers3
GBMSeurat_cancer_sipsic[["OPCLike"]] = GBMSeurat_cancer$cancer_markers4
GBMSeurat_cancer_sipsic[["NPCLike1"]] = GBMSeurat_cancer$cancer_markers5
GBMSeurat_cancer_sipsic[["NPCLike2"]] = GBMSeurat_cancer$cancer_markers6
cancer_scores = FetchData(object = GBMSeurat_cancer_sipsic,vars = c("MesLike1","MesLike2","ACLike","OPCLike","NPCLike1","NPCLike2"))
cancer_scores$assignment<- colnames(cancer_scores)[max.col(cancer_scores, ties.method = "first")]
GBMSeurat_cancer_sipsic %<>% AddMetaData(metadata = cancer_scores$assignment,col.name = "cancer_type")
# further pre-processing steps before moving on to clustering
# GBMSeurat_cancer_sipsic <- FindVariableFeatures(GBMSeurat_cancer_sipsic, selection.method = "vst", nfeatures = 2000)
GBMSeurat_cancer_sipsic <- ScaleData(GBMSeurat_cancer_sipsic, features = rownames(GBMSeurat_cancer_sipsic))
GBMSeurat_cancer_sipsic <- RunPCA(GBMSeurat_cancer_sipsic, features = rownames(GBMSeurat_cancer_sipsic))
# print(GBMSeurat_cancer_sipsic[["pca"]], dims=1:5, nfeatures = 5)
print(ElbowPlot(GBMSeurat_cancer_sipsic))
# Clustering based on the top principal components
GBMSeurat_cancer_sipsic <- FindNeighbors(GBMSeurat_cancer_sipsic, dims = 1:15)
GBMSeurat_cancer_sipsic <- FindClusters(GBMSeurat_cancer_sipsic, resolution = 0.9)
GBMSeurat_cancer_sipsic <- RunUMAP(GBMSeurat_cancer_sipsic, dims = 1:15)
Feature
plots
# Testing for clusters enriched in markers of the different malignant meta-modules
print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "MesLike1"),title = "MESLike1Scores")
MESLike1Scores

print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "MesLike2"),title = "MESLike2Scores")
MESLike2Scores

print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "ACLike"),title = "ACLikeScores")
ACLikeScores

print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "OPCLike"),title = "OPCLikeScores")
OPCLikeScores

print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "NPCLike1"),title = "NPCLike1Scores")
NPCLike1Scores

print_tab(FeaturePlot(GBMSeurat_cancer_sipsic, features = "NPCLike2"),title = "NPCLike2Scores")
NPCLike2Scores

NA
UMAPS
print_tab(DimPlot(GBMSeurat_cancer_sipsic, reduction = "umap"),title = "clusters")
clusters

print_tab(DimPlot(GBMSeurat_cancer_sipsic, reduction = "umap",group.by = "orig.ident"),title = "by patient")
by patient

print_tab(DimPlot(GBMSeurat_cancer_sipsic, reduction = "umap",group.by = "cancer_type"),title = "by cell types")
by cell types

NA
stacked batplot
clusters_and_scores = FetchData(object = GBMSeurat_cancer_sipsic,vars= c("cancer_type","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type) %>% summarise(n_cells = n())%>% mutate(per = 100 *n_cells/sum(n_cells))
`summarise()` has grouped output by 'seurat_clusters'. You can override using the `.groups` argument.
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
v_factor_levels <-c( "MesLike1", "MesLike2", "NPCLike1", "NPCLike2", "OPCLike","ACLike")
colors = RColorBrewer::brewer.pal(6, "Paired"); colors[5] = "orange"
p1 = ggplot(data=clusters_and_scores, aes(x=seurat_clusters, y=per, fill=factor(cancer_type, levels = v_factor_levels))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Cancer type")+ labs(title = "SiPSiC",subtitle = "integration score=" %s+% integration_score %s+% "%")+ylab("% from cluster")
p1

silhouette score
library(cluster, quietly = TRUE)
dist.matrix <- dist(x = Embeddings(object = GBMSeurat_cancer_sipsic[["umap"]]))
clusters <- GBMSeurat_cancer_sipsic$cancer_type
sil <- silhouette(x = as.numeric(x = as.factor(x = clusters)), dist = dist.matrix)
summary(sil)
Silhouette of 10000 units in 6 clusters from silhouette.default(x = as.numeric(x = as.factor(x = clusters)), from dist = dist.matrix) :
Cluster sizes and average silhouette widths:
2842 2968 1479 1984 537 190
-0.05078936 0.03399211 -0.11382633 -0.17191359 0.21005554 -0.23310521
Individual silhouette widths:
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.76769 -0.24510 -0.01811 -0.04844 0.16534 0.33000
GBMSeurat_cancer_sipsic$sil = sil[,3]
VlnPlot(object = GBMSeurat_cancer_sipsic,features = "sil",group.by = "cancer_type")

Combine cancer
subtypes
GBMSeurat_cancer_sipsic$cancer_type = GBMSeurat_cancer_sipsic$cancer_type %>% gsub(pattern = "MesLike1|MesLike2",replacement = "MesLike")%>% gsub(pattern = "NPCLike1|NPCLike2",replacement = "NPCLike")
clusters_and_scores = FetchData(object = GBMSeurat_cancer_sipsic,vars= c("cancer_type","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type) %>% summarise(n_cells = n())%>% mutate(per = 100 *n_cells/sum(n_cells))
`summarise()` has grouped output by 'seurat_clusters'. You can override using the `.groups` argument.
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
v_factor_levels <-c( "MesLike", "NPCLike", "OPCLike","ACLike")
colors = RColorBrewer::brewer.pal(6, "Paired")[c(2,4,5,6)]; colors[3] = "orange"
p4 = ggplot(data=clusters_and_scores, aes(x=seurat_clusters, y=per, fill=factor(cancer_type, levels = v_factor_levels))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Cancer type")+ labs(title = "SiPSiC",subtitle = "integration score=" %s+% integration_score %s+% "%")+ylab("% from cluster")
p4

library(cluster, quietly = TRUE)
dist.matrix <- dist(x = Embeddings(object = GBMSeurat_cancer_sipsic[["umap"]]))
clusters <- GBMSeurat_cancer_sipsic$cancer_type
sil <- silhouette(x = as.numeric(x = as.factor(x = clusters)), dist = dist.matrix)
summary(sil)
Silhouette of 10000 units in 4 clusters from silhouette.default(x = as.numeric(x = as.factor(x = clusters)), from dist = dist.matrix) :
Cluster sizes and average silhouette widths:
2842 4447 2521 190
0.03706650 -0.01902861 0.33220367 -0.13660378
Individual silhouette widths:
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.68356 -0.10855 0.11759 0.08323 0.30599 0.51275
GBMSeurat_cancer_sipsic$sil = sil[,3]
VlnPlot(object = GBMSeurat_cancer_sipsic,features = "sil",group.by = "cancer_type")

LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmBgYAoKIyBEYXRhCgpgYGB7cn0KY2FsY3VsYXRlUGF0aHdheVNjb3JlcyA8LSBmdW5jdGlvbihwYXRod2F5VG9TY29yZSwgY291bnRzTWF0cml4KQp7CiAgcGF0aHdheU5hbWUgPC0gcGF0aHdheVRvU2NvcmVAc2V0TmFtZQogIHBhdGh3YXlHZW5lcyA8LSBwYXRod2F5VG9TY29yZUBnZW5lSWRzCiAgcGF0aHdheVNjb3Jlc09iamVjdCA8LSBnZXRQYXRod2F5U2NvcmVzKGNvdW50c01hdHJpeCwgcGF0aHdheUdlbmVzKSAKICByZXR1cm4ocGF0aHdheVNjb3Jlc09iamVjdCRwYXRod2F5U2NvcmVzKQp9CkdCTVNldXJhdF9jYW5jZXIgPSByZWFkUkRTKCIuL0RhdGEvR1NNMzgyODY3M18xMFhfR0JNX3NldXJhdF9jYW5jZXIuUkRTIikKZ2VuZXNldHMgPC0gZ2V0R210KCIuL0RhdGEvaC5hbGwudjcuMC5zeW1ib2xzLnBsdXNjYy5nbXQiKQptZXRhTW9kdWxlR2VuZXMgPC0gcmVhZC50YWJsZShmaWxlID0gIi4vRGF0YS9NZXRhTW9kdWxlR2VuZXNfQ2VsbFBhcGVyLnRzdiIsIGhlYWRlciA9IFRSVUUpCgojIENyZWF0aW5nIGdlbmVzZXRzIGZvciB0aGUgbWV0YSBtb2R1bGUgbWFya2VycwpNZXNMaWtlMkdlbmVTZXQgPC0gR2VuZVNldChtZXRhTW9kdWxlR2VuZXNbLDFdKQpNZXNMaWtlMUdlbmVTZXQgPC0gR2VuZVNldChtZXRhTW9kdWxlR2VuZXNbLDJdKQpBQ0xpa2VHZW5lU2V0IDwtIEdlbmVTZXQobWV0YU1vZHVsZUdlbmVzWyFpcy5uYShtZXRhTW9kdWxlR2VuZXNbLDNdKSwgM10pCk9QQ0xpa2VHZW5lU2V0IDwtIEdlbmVTZXQobWV0YU1vZHVsZUdlbmVzWyw0XSkKTlBDTGlrZTFHZW5lU2V0IDwtIEdlbmVTZXQobWV0YU1vZHVsZUdlbmVzWyw1XSkKTlBDTGlrZTJHZW5lU2V0IDwtIEdlbmVTZXQobWV0YU1vZHVsZUdlbmVzWyw2XSkKCk1lc0xpa2UxR2VuZVNldEBzZXROYW1lIDwtICJNZXNMaWtlMSIKTWVzTGlrZTJHZW5lU2V0QHNldE5hbWUgPC0gIk1lc0xpa2UyIgpBQ0xpa2VHZW5lU2V0QHNldE5hbWUgPC0gIkFDTGlrZSIKT1BDTGlrZUdlbmVTZXRAc2V0TmFtZSA8LSAiT1BDTGlrZSIKTlBDTGlrZTFHZW5lU2V0QHNldE5hbWUgPC0gIk5QQ0xpa2UxIgpOUENMaWtlMkdlbmVTZXRAc2V0TmFtZSA8LSAiTlBDTGlrZTIiCgpgYGAKCmBgYHtyfQpUUE1Db3VudHMgPSBHQk1TZXVyYXRfY2FuY2VyQGFzc2F5cyRSTkFAY291bnRzICU+JSBhcy5tYXRyaXgoKSAlPiUgTWF0cml4KHNwYXJzZSA9IFQpCgpwYXRod2F5U2NvcmVMaXN0cyA8LSBsYXBwbHkoWCA9IGdlbmVzZXRzQC5EYXRhLCBjYWxjdWxhdGVQYXRod2F5U2NvcmVzLCBUUE1Db3VudHMpCnBhdGh3YXlTY29yZXNNYXRyaXggPC0gYXMuZGF0YS5mcmFtZShkby5jYWxsKCJyYmluZCIsIHBhdGh3YXlTY29yZUxpc3RzKSkKCmBgYAoKYGBge3J9CiMjIEFkZGluZyB0aGUgcGF0aHdheSBuYW1lIHRvIGVhY2ggbGlzdCBvZiBwYXRod2F5IHNjb3JlcywgYXMgdGhlIG5hbWVzIHdpbGwgYmUgdXNlZCBkdXJpbmcgdGhlIGNsdXN0ZXJpbmcgcHJlLXByb2Nlc3Npbmcgc3RlcHMKZm9yKGN1cnJQYXRod2F5SW5kZXggaW4gMTpsZW5ndGgocGF0aHdheVNjb3JlTGlzdHMpKQp7CiAgcm93bmFtZXMocGF0aHdheVNjb3Jlc01hdHJpeClbY3VyclBhdGh3YXlJbmRleF0gPC0gZ2VuZXNldHNALkRhdGFbW2N1cnJQYXRod2F5SW5kZXhdXUBzZXROYW1lCn0KCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBwYXRod2F5U2NvcmVzTWF0cml4KQoKY2FuY2VyX21hcmtlcnMgPSBsaXN0KAogIE1lc0xpa2UxID0gTWVzTGlrZTFHZW5lU2V0QGdlbmVJZHMsCiAgTWVzTGlrZTIgPSBNZXNMaWtlMkdlbmVTZXRAZ2VuZUlkcywKICBBQ0xpa2UgPSBBQ0xpa2VHZW5lU2V0QGdlbmVJZHMsCiAgT1BDTGlrZSA9IE9QQ0xpa2VHZW5lU2V0QGdlbmVJZHMsCiAgTlBDTGlrZTEgPSBOUENMaWtlMUdlbmVTZXRAZ2VuZUlkcywKICBOUENMaWtlMiA9IE5QQ0xpa2UyR2VuZVNldEBnZW5lSWRzCikKCkdCTVNldXJhdF9jYW5jZXIgPC0gQWRkTW9kdWxlU2NvcmUoCiAgb2JqZWN0ID0gR0JNU2V1cmF0X2NhbmNlciwKICBmZWF0dXJlcyA9IGNhbmNlcl9tYXJrZXJzLGN0cmwgPSA1MCxuYW1lID0gImNhbmNlcl9tYXJrZXJzIikKCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljW1siTWVzTGlrZTEiXV0gPSBHQk1TZXVyYXRfY2FuY2VyJGNhbmNlcl9tYXJrZXJzMQpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY1tbIk1lc0xpa2UyIl1dID0gR0JNU2V1cmF0X2NhbmNlciRjYW5jZXJfbWFya2VyczIKR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNbWyJBQ0xpa2UiXV0gPSBHQk1TZXVyYXRfY2FuY2VyJGNhbmNlcl9tYXJrZXJzMwpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY1tbIk9QQ0xpa2UiXV0gPSBHQk1TZXVyYXRfY2FuY2VyJGNhbmNlcl9tYXJrZXJzNApHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY1tbIk5QQ0xpa2UxIl1dID0gR0JNU2V1cmF0X2NhbmNlciRjYW5jZXJfbWFya2VyczUKR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNbWyJOUENMaWtlMiJdXSA9IEdCTVNldXJhdF9jYW5jZXIkY2FuY2VyX21hcmtlcnM2CgpjYW5jZXJfc2NvcmVzICA9IEZldGNoRGF0YShvYmplY3QgPSBHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYyx2YXJzID0gYygiTWVzTGlrZTEiLCJNZXNMaWtlMiIsIkFDTGlrZSIsIk9QQ0xpa2UiLCJOUENMaWtlMSIsIk5QQ0xpa2UyIikpCmNhbmNlcl9zY29yZXMkYXNzaWdubWVudDwtIGNvbG5hbWVzKGNhbmNlcl9zY29yZXMpW21heC5jb2woY2FuY2VyX3Njb3JlcywgdGllcy5tZXRob2QgPSAiZmlyc3QiKV0KCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljICU8PiUgQWRkTWV0YURhdGEobWV0YWRhdGEgPSBjYW5jZXJfc2NvcmVzJGFzc2lnbm1lbnQsY29sLm5hbWUgPSAiY2FuY2VyX3R5cGUiKQoKCgpgYGAKCgpgYGB7cn0KIyBmdXJ0aGVyIHByZS1wcm9jZXNzaW5nIHN0ZXBzIGJlZm9yZSBtb3Zpbmcgb24gdG8gY2x1c3RlcmluZwojIEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljIDwtIFNjYWxlRGF0YShHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSByb3duYW1lcyhHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYykpCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljIDwtIFJ1blBDQShHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSByb3duYW1lcyhHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYykpCiMgcHJpbnQoR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNbWyJwY2EiXV0sIGRpbXM9MTo1LCBuZmVhdHVyZXMgPSA1KQpwcmludChFbGJvd1Bsb3QoR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMpKQpgYGAKCmBgYHtyfQojIENsdXN0ZXJpbmcgYmFzZWQgb24gdGhlIHRvcCBwcmluY2lwYWwgY29tcG9uZW50cwpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYyA8LSBGaW5kTmVpZ2hib3JzKEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCBkaW1zID0gMToxNSkKR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMgPC0gRmluZENsdXN0ZXJzKEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCByZXNvbHV0aW9uID0gMC45KQpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYyA8LSBSdW5VTUFQKEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCBkaW1zID0gMToxNSkKYGBgCgojIEZlYXR1cmUgcGxvdHMgey50YWJzZXR9CmBgYHtyIHJlc3VsdHM9J2FzaXMnfQojIFRlc3RpbmcgZm9yIGNsdXN0ZXJzIGVucmljaGVkIGluIG1hcmtlcnMgb2YgdGhlIGRpZmZlcmVudCBtYWxpZ25hbnQgbWV0YS1tb2R1bGVzCnByaW50X3RhYihGZWF0dXJlUGxvdChHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSAiTWVzTGlrZTEiKSx0aXRsZSA9ICJNRVNMaWtlMVNjb3JlcyIpCnByaW50X3RhYihGZWF0dXJlUGxvdChHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSAiTWVzTGlrZTIiKSx0aXRsZSA9ICJNRVNMaWtlMlNjb3JlcyIpCnByaW50X3RhYihGZWF0dXJlUGxvdChHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSAiQUNMaWtlIiksdGl0bGUgPSAiQUNMaWtlU2NvcmVzIikKcHJpbnRfdGFiKEZlYXR1cmVQbG90KEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCBmZWF0dXJlcyA9ICJPUENMaWtlIiksdGl0bGUgPSAiT1BDTGlrZVNjb3JlcyIpCnByaW50X3RhYihGZWF0dXJlUGxvdChHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSAiTlBDTGlrZTEiKSx0aXRsZSA9ICJOUENMaWtlMVNjb3JlcyIpCnByaW50X3RhYihGZWF0dXJlUGxvdChHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgZmVhdHVyZXMgPSAiTlBDTGlrZTIiKSx0aXRsZSA9ICJOUENMaWtlMlNjb3JlcyIpCmBgYAoKIyBVTUFQUyB7LnRhYnNldH0KYGBge3IgcmVzdWx0cz0nYXNpcyd9CnByaW50X3RhYihEaW1QbG90KEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCByZWR1Y3Rpb24gPSAidW1hcCIpLHRpdGxlID0gImNsdXN0ZXJzIikKcHJpbnRfdGFiKERpbVBsb3QoR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMsIHJlZHVjdGlvbiA9ICJ1bWFwIixncm91cC5ieSA9ICJvcmlnLmlkZW50IiksdGl0bGUgPSAiYnkgcGF0aWVudCIpCnByaW50X3RhYihEaW1QbG90KEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCByZWR1Y3Rpb24gPSAidW1hcCIsZ3JvdXAuYnkgPSAiY2FuY2VyX3R5cGUiKSx0aXRsZSA9ICJieSBjZWxsIHR5cGVzIikKCmBgYAoKCgojIHN0YWNrZWQgYmF0cGxvdApgYGB7cn0KY2x1c3RlcnNfYW5kX3Njb3JlcyA9IEZldGNoRGF0YShvYmplY3QgPSBHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYyx2YXJzPSBjKCJjYW5jZXJfdHlwZSIsInNldXJhdF9jbHVzdGVycyIpKSAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycyxjYW5jZXJfdHlwZSkgJT4lICBzdW1tYXJpc2Uobl9jZWxscyA9IG4oKSklPiUgbXV0YXRlKHBlciA9ICAxMDAgKm5fY2VsbHMvc3VtKG5fY2VsbHMpKQoKaW50ZWdyYXRpb25fc2NvcmUgPSBjbHVzdGVyc19hbmRfc2NvcmVzICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUgZmlsdGVyKG5fY2VsbHMgPT0gbWF4KG5fY2VsbHMpKSAlPiUgcHVsbChwZXIpICU+JSBtZWFuKCkgJT4lIHJvdW5kKGRpZ2l0cyA9IDIpCgp2X2ZhY3Rvcl9sZXZlbHMgPC1jKCAiTWVzTGlrZTEiLCAiTWVzTGlrZTIiLCAiTlBDTGlrZTEiLCAiTlBDTGlrZTIiLCAiT1BDTGlrZSIsIkFDTGlrZSIpCmNvbG9ycyA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg2LCAiUGFpcmVkIik7IGNvbG9yc1s1XSA9ICJvcmFuZ2UiCnAxID0gZ2dwbG90KGRhdGE9Y2x1c3RlcnNfYW5kX3Njb3JlcywgYWVzKHg9c2V1cmF0X2NsdXN0ZXJzLCB5PXBlciwgZmlsbD1mYWN0b3IoY2FuY2VyX3R5cGUsIGxldmVscyA9IHZfZmFjdG9yX2xldmVscykpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSt0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMsbmFtZSAgPSAiQ2FuY2VyIHR5cGUiKSsgbGFicyh0aXRsZSA9ICJTaVBTaUMiLHN1YnRpdGxlID0gImludGVncmF0aW9uIHNjb3JlPSIgJXMrJSBpbnRlZ3JhdGlvbl9zY29yZSAlcyslICIlIikreWxhYigiJSBmcm9tIGNsdXN0ZXIiKQpwMQpgYGAKCgoKIyBzaWxob3VldHRlIHNjb3JlCmBgYHtyfQpsaWJyYXJ5KGNsdXN0ZXIsIHF1aWV0bHkgPSBUUlVFKQpkaXN0Lm1hdHJpeCA8LSBkaXN0KHggPSBFbWJlZGRpbmdzKG9iamVjdCA9IEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljW1sidW1hcCJdXSkpCmNsdXN0ZXJzIDwtIEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljJGNhbmNlcl90eXBlCnNpbCA8LSBzaWxob3VldHRlKHggPSBhcy5udW1lcmljKHggPSBhcy5mYWN0b3IoeCA9IGNsdXN0ZXJzKSksIGRpc3QgPSBkaXN0Lm1hdHJpeCkKc3VtbWFyeShzaWwpCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljJHNpbCA9IHNpbFssM10KVmxuUGxvdChvYmplY3QgPSBHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYyxmZWF0dXJlcyA9ICJzaWwiLGdyb3VwLmJ5ID0gImNhbmNlcl90eXBlIikKYGBgCiMgQ29tYmluZSBjYW5jZXIgc3VidHlwZXMKYGBge3J9CkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljJGNhbmNlcl90eXBlID0gR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMkY2FuY2VyX3R5cGUgJT4lIGdzdWIocGF0dGVybiA9ICJNZXNMaWtlMXxNZXNMaWtlMiIscmVwbGFjZW1lbnQgPSAiTWVzTGlrZSIpJT4lIGdzdWIocGF0dGVybiA9ICJOUENMaWtlMXxOUENMaWtlMiIscmVwbGFjZW1lbnQgPSAiTlBDTGlrZSIpCmBgYAoKYGBge3J9CmNsdXN0ZXJzX2FuZF9zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMsdmFycz0gYygiY2FuY2VyX3R5cGUiLCJzZXVyYXRfY2x1c3RlcnMiKSkgJT4lICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMsY2FuY2VyX3R5cGUpICU+JSAgc3VtbWFyaXNlKG5fY2VsbHMgPSBuKCkpJT4lIG11dGF0ZShwZXIgPSAgMTAwICpuX2NlbGxzL3N1bShuX2NlbGxzKSkKCmludGVncmF0aW9uX3Njb3JlID0gY2x1c3RlcnNfYW5kX3Njb3JlcyAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lIGZpbHRlcihuX2NlbGxzID09IG1heChuX2NlbGxzKSkgJT4lIHB1bGwocGVyKSAlPiUgbWVhbigpICU+JSByb3VuZChkaWdpdHMgPSAyKQoKdl9mYWN0b3JfbGV2ZWxzIDwtYyggIk1lc0xpa2UiLCAiTlBDTGlrZSIsICJPUENMaWtlIiwiQUNMaWtlIikKY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJQYWlyZWQiKVtjKDIsNCw1LDYpXTsgY29sb3JzWzNdID0gIm9yYW5nZSIKcDQgPSBnZ3Bsb3QoZGF0YT1jbHVzdGVyc19hbmRfc2NvcmVzLCBhZXMoeD1zZXVyYXRfY2x1c3RlcnMsIHk9cGVyLCBmaWxsPWZhY3RvcihjYW5jZXJfdHlwZSwgbGV2ZWxzID0gdl9mYWN0b3JfbGV2ZWxzKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3RoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9ycyxuYW1lICA9ICJDYW5jZXIgdHlwZSIpKyBsYWJzKHRpdGxlID0gIlNpUFNpQyIsc3VidGl0bGUgPSAiaW50ZWdyYXRpb24gc2NvcmU9IiAlcyslIGludGVncmF0aW9uX3Njb3JlICVzKyUgIiUiKSt5bGFiKCIlIGZyb20gY2x1c3RlciIpCnA0CmBgYAoKYGBge3J9CmxpYnJhcnkoY2x1c3RlciwgcXVpZXRseSA9IFRSVUUpCmRpc3QubWF0cml4IDwtIGRpc3QoeCA9IEVtYmVkZGluZ3Mob2JqZWN0ID0gR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNbWyJ1bWFwIl1dKSkKY2x1c3RlcnMgPC0gR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMkY2FuY2VyX3R5cGUKc2lsIDwtIHNpbGhvdWV0dGUoeCA9IGFzLm51bWVyaWMoeCA9IGFzLmZhY3Rvcih4ID0gY2x1c3RlcnMpKSwgZGlzdCA9IGRpc3QubWF0cml4KQpzdW1tYXJ5KHNpbCkKR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMkc2lsID0gc2lsWywzXQpWbG5QbG90KG9iamVjdCA9IEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLGZlYXR1cmVzID0gInNpbCIsZ3JvdXAuYnkgPSAiY2FuY2VyX3R5cGUiKQpgYGAKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0PgoK