13 clusters
GBMSeurat_cancer_sipsic <- FindClusters(GBMSeurat_cancer_sipsic, resolution = 0.9)
GBMSeurat_cancer_sipsic_cp <- FindClusters(GBMSeurat_cancer_sipsic_cp, resolution = 0.65)
GBM.combined <- FindClusters(GBM.combined, resolution = 0.8)
GBMSeurat_cancer_harmony <- FindClusters(GBMSeurat_cancer_harmony, resolution = 0.5)
GBMSeurat_cancer %<>% FindClusters(resolution = 0.2)
GBMSeurat_cancer@project.name = "GBM_original"
GBMSeurat_cancer_sipsic_cp@project.name = "GBM_sipsic_cp"
GBM.combined@project.name = "GBM_seurat_integration"
GBMSeurat_cancer_harmony@project.name = "GBM_harmony"
all_datasets = list(GBMSeurat_cancer,GBMSeurat_cancer_sipsic,GBMSeurat_cancer_sipsic_cp,GBM.combined,GBMSeurat_cancer_harmony)
UMAPS
for (dataset in all_datasets) {
print_tab(DimPlot(dataset, reduction = "umap",group.by = c("seurat_clusters","orig.ident","cancer_type"),ncol = 2),title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
stacked batplot
for (dataset in all_datasets) {
clusters_and_scores = FetchData(object = dataset,vars= c("cancer_type","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type) %>%
summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
integration_score_sum_cells = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(n_cells) %>% sum() %>%
divide_by(sum(clusters_and_scores$n_cells)) %>% round(digits = 2)
v_factor_levels <-c( "MesLike1", "MesLike2", "NPCLike1", "NPCLike2", "OPCLike","ACLike")
colors = RColorBrewer::brewer.pal(6, "Paired"); colors[5] = "orange"
p2 = 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 = dataset@project.name,subtitle = "integration score=" %s+% integration_score %s+% "%" %s+% "\nintegration sums cells score="
%s+% integration_score_sum_cells)+
ylab("% from cluster")
clusters_and_scores = FetchData(object = dataset,vars= c("orig.ident","seurat_clusters")) %>% group_by(seurat_clusters,orig.ident) %>%
summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
colors = RColorBrewer::brewer.pal(9, "Paired")
p3 = ggplot(data=clusters_and_scores, aes(x=seurat_clusters, y=per, fill=factor(orig.ident))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Patient")+
labs(title = dataset@project.name)+
ylab("% from cluster")
print_tab(p2+p3,title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
Combine cancer subtypes
for (i in seq_along(all_datasets)) {
all_datasets[[i]]$cancer_type_combined = all_datasets[[i]]$"cancer_type" %>% gsub(pattern = "MesLike1|MesLike2",replacement = "MesLike")%>% gsub(pattern = "NPCLike1|NPCLike2",replacement = "NPCLike")
}
for (dataset in all_datasets) {
clusters_and_scores = FetchData(object = dataset,vars= c("cancer_type_combined","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type_combined) %>% summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
integration_score_sum_cells = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(n_cells) %>% sum() %>%
divide_by(sum(clusters_and_scores$n_cells)) %>% 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_combined, levels = v_factor_levels))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Cancer type")+
labs(title = dataset@project.name,subtitle = "integration score=" %s+% integration_score %s+% "%" %s+% "\nintegration sums cells score=" %s+%
integration_score_sum_cells)+ylab("% from cluster")
print_tab(p4,title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
10 clusters
GBMSeurat_cancer_sipsic <- FindClusters(GBMSeurat_cancer_sipsic, resolution = 0.65)
GBMSeurat_cancer_sipsic_cp <- FindClusters(GBMSeurat_cancer_sipsic_cp, resolution = 0.4)
GBM.combined <- FindClusters(GBM.combined, resolution = 0.6)
GBMSeurat_cancer_harmony <- FindClusters(GBMSeurat_cancer_harmony, resolution = 0.19)
GBMSeurat_cancer %<>% FindClusters(resolution = 0.09)
all_datasets = list(GBMSeurat_cancer,GBMSeurat_cancer_sipsic,GBMSeurat_cancer_sipsic_cp,GBM.combined,GBMSeurat_cancer_harmony)
UMAPS
for (dataset in all_datasets) {
print_tab(DimPlot(dataset, reduction = "umap",group.by = c("seurat_clusters","orig.ident","cancer_type"),ncol = 2),title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
stacked batplot
for (dataset in all_datasets) {
clusters_and_scores = FetchData(object = dataset,vars= c("cancer_type","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type) %>%
summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
integration_score_sum_cells = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(n_cells) %>% sum() %>%
divide_by(sum(clusters_and_scores$n_cells)) %>% round(digits = 2)
v_factor_levels <-c( "MesLike1", "MesLike2", "NPCLike1", "NPCLike2", "OPCLike","ACLike")
colors = RColorBrewer::brewer.pal(6, "Paired"); colors[5] = "orange"
p2 = 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 = dataset@project.name,subtitle = "integration score=" %s+% integration_score %s+% "%" %s+% "\nintegration sums cells score="
%s+% integration_score_sum_cells)+
ylab("% from cluster")
clusters_and_scores = FetchData(object = dataset,vars= c("orig.ident","seurat_clusters")) %>% group_by(seurat_clusters,orig.ident) %>%
summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
colors = RColorBrewer::brewer.pal(9, "Paired")
p3 = ggplot(data=clusters_and_scores, aes(x=seurat_clusters, y=per, fill=factor(orig.ident))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Patient")+
labs(title = dataset@project.name)+
ylab("% from cluster")
print_tab(p2+p3,title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
Combine cancer subtypes
for (i in seq_along(all_datasets)) {
all_datasets[[i]]$cancer_type_combined = all_datasets[[i]]$"cancer_type" %>% gsub(pattern = "MesLike1|MesLike2",replacement = "MesLike")%>% gsub(pattern = "NPCLike1|NPCLike2",replacement = "NPCLike")
}
for (dataset in all_datasets) {
clusters_and_scores = FetchData(object = dataset,vars= c("cancer_type_combined","seurat_clusters")) %>% group_by(seurat_clusters,cancer_type_combined) %>% summarise(n_cells = n(), .groups = "drop_last")%>% mutate(per = 100 *n_cells/sum(n_cells))
integration_score = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(per) %>% mean() %>% round(digits = 2)
integration_score_sum_cells = clusters_and_scores %>% group_by(seurat_clusters) %>% filter(n_cells == max(n_cells)) %>% pull(n_cells) %>% sum() %>%
divide_by(sum(clusters_and_scores$n_cells)) %>% 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_combined, levels = v_factor_levels))) +
geom_bar(stat="identity")+theme_minimal() + scale_fill_manual(values = colors,name = "Cancer type")+
labs(title = dataset@project.name,subtitle = "integration score=" %s+% integration_score %s+% "%" %s+% "\nintegration sums cells score=" %s+%
integration_score_sum_cells)+ylab("% from cluster")
print_tab(p4,title = dataset@project.name,subtitle_num = 3)
}
GBM_original

GBM_sipsic

GBM_sipsic_cp

GBM_seurat_integration

GBM_harmony

NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmBgYAoKIyBEYXRhCgpgYGB7cn0KCmBgYAoKIyAxMyBjbHVzdGVycwpgYGB7cn0KR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMgPC0gRmluZENsdXN0ZXJzKEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLCByZXNvbHV0aW9uID0gMC45KQpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY19jcCA8LSBGaW5kQ2x1c3RlcnMoR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNfY3AsIHJlc29sdXRpb24gPSAwLjY1KQpHQk0uY29tYmluZWQgPC0gRmluZENsdXN0ZXJzKEdCTS5jb21iaW5lZCwgcmVzb2x1dGlvbiA9IDAuOCkKR0JNU2V1cmF0X2NhbmNlcl9oYXJtb255IDwtIEZpbmRDbHVzdGVycyhHQk1TZXVyYXRfY2FuY2VyX2hhcm1vbnksIHJlc29sdXRpb24gPSAwLjUpCkdCTVNldXJhdF9jYW5jZXIgICU8PiUgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gID0gMC4yKQoKYGBgCgpgYGB7cn0KR0JNU2V1cmF0X2NhbmNlckBwcm9qZWN0Lm5hbWUgPSAiR0JNX29yaWdpbmFsIgpHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY19jcEBwcm9qZWN0Lm5hbWUgPSAiR0JNX3NpcHNpY19jcCIKR0JNLmNvbWJpbmVkQHByb2plY3QubmFtZSA9ICJHQk1fc2V1cmF0X2ludGVncmF0aW9uIgpHQk1TZXVyYXRfY2FuY2VyX2hhcm1vbnlAcHJvamVjdC5uYW1lID0gIkdCTV9oYXJtb255IgoKYGBgCgpgYGB7cn0KYWxsX2RhdGFzZXRzID0gbGlzdChHQk1TZXVyYXRfY2FuY2VyLEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljLEdCTVNldXJhdF9jYW5jZXJfc2lwc2ljX2NwLEdCTS5jb21iaW5lZCxHQk1TZXVyYXRfY2FuY2VyX2hhcm1vbnkpCmBgYAojIyBVTUFQUyB7LnRhYnNldH0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQpmb3IgKGRhdGFzZXQgaW4gYWxsX2RhdGFzZXRzKSB7CiAgcHJpbnRfdGFiKERpbVBsb3QoZGF0YXNldCwgcmVkdWN0aW9uID0gInVtYXAiLGdyb3VwLmJ5ID0gYygic2V1cmF0X2NsdXN0ZXJzIiwib3JpZy5pZGVudCIsImNhbmNlcl90eXBlIiksbmNvbCA9IDIpLHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGVfbnVtID0gMykKfQpgYGAKCgojIyBzdGFja2VkIGJhdHBsb3QgIHsudGFic2V0fQoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTMsIHJlc3VsdHM9J2FzaXMnfQpmb3IgKGRhdGFzZXQgaW4gYWxsX2RhdGFzZXRzKSB7CiAgCiAgY2x1c3RlcnNfYW5kX3Njb3JlcyA9IEZldGNoRGF0YShvYmplY3QgPSBkYXRhc2V0LHZhcnM9IGMoImNhbmNlcl90eXBlIiwic2V1cmF0X2NsdXN0ZXJzIikpICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzLGNhbmNlcl90eXBlKSAlPiUKICAgIHN1bW1hcmlzZShuX2NlbGxzID0gbigpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpJT4lIG11dGF0ZShwZXIgPSAgMTAwICpuX2NlbGxzL3N1bShuX2NlbGxzKSkKICAKICBpbnRlZ3JhdGlvbl9zY29yZSA9IGNsdXN0ZXJzX2FuZF9zY29yZXMgJT4lICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JSBmaWx0ZXIobl9jZWxscyA9PSBtYXgobl9jZWxscykpICU+JSBwdWxsKHBlcikgJT4lIG1lYW4oKSAlPiUgcm91bmQoZGlnaXRzID0gMikKICBpbnRlZ3JhdGlvbl9zY29yZV9zdW1fY2VsbHMgPSBjbHVzdGVyc19hbmRfc2NvcmVzICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUgZmlsdGVyKG5fY2VsbHMgPT0gbWF4KG5fY2VsbHMpKSAlPiUgcHVsbChuX2NlbGxzKSAlPiUgc3VtKCkgJT4lCiAgICBkaXZpZGVfYnkoc3VtKGNsdXN0ZXJzX2FuZF9zY29yZXMkbl9jZWxscykpICU+JSByb3VuZChkaWdpdHMgPSAyKQogIAogIHZfZmFjdG9yX2xldmVscyA8LWMoICJNZXNMaWtlMSIsICJNZXNMaWtlMiIsICJOUENMaWtlMSIsICJOUENMaWtlMiIsICJPUENMaWtlIiwiQUNMaWtlIikKICBjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoNiwgIlBhaXJlZCIpOyBjb2xvcnNbNV0gPSAib3JhbmdlIgogIHAyID0gZ2dwbG90KGRhdGE9Y2x1c3RlcnNfYW5kX3Njb3JlcywgYWVzKHg9c2V1cmF0X2NsdXN0ZXJzLCB5PXBlciwgZmlsbD1mYWN0b3IoY2FuY2VyX3R5cGUsIGxldmVscyA9IHZfZmFjdG9yX2xldmVscykpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3RoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9ycyxuYW1lICA9ICJDYW5jZXIgdHlwZSIpKyAKICAgIGxhYnModGl0bGUgPSBkYXRhc2V0QHByb2plY3QubmFtZSxzdWJ0aXRsZSA9ICJpbnRlZ3JhdGlvbiBzY29yZT0iICVzKyUgaW50ZWdyYXRpb25fc2NvcmUgJXMrJSAiJSIgJXMrJSAiXG5pbnRlZ3JhdGlvbiBzdW1zIGNlbGxzIHNjb3JlPSIKICAgICAgICAgJXMrJSBpbnRlZ3JhdGlvbl9zY29yZV9zdW1fY2VsbHMpKwogICAgeWxhYigiJSBmcm9tIGNsdXN0ZXIiKQogIAogIAogIGNsdXN0ZXJzX2FuZF9zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gZGF0YXNldCx2YXJzPSBjKCJvcmlnLmlkZW50Iiwic2V1cmF0X2NsdXN0ZXJzIikpICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzLG9yaWcuaWRlbnQpICU+JSAgCiAgICBzdW1tYXJpc2Uobl9jZWxscyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKSU+JSBtdXRhdGUocGVyID0gIDEwMCAqbl9jZWxscy9zdW0obl9jZWxscykpCiAgCiAgY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDksICJQYWlyZWQiKQogIHAzID0gZ2dwbG90KGRhdGE9Y2x1c3RlcnNfYW5kX3Njb3JlcywgYWVzKHg9c2V1cmF0X2NsdXN0ZXJzLCB5PXBlciwgZmlsbD1mYWN0b3Iob3JpZy5pZGVudCkpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3RoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9ycyxuYW1lICA9ICJQYXRpZW50IikrIAogICAgbGFicyh0aXRsZSA9IGRhdGFzZXRAcHJvamVjdC5uYW1lKSsKICAgIHlsYWIoIiUgZnJvbSBjbHVzdGVyIikKICAKICBwcmludF90YWIocDIrcDMsdGl0bGUgPSBkYXRhc2V0QHByb2plY3QubmFtZSxzdWJ0aXRsZV9udW0gPSAzKQp9CmBgYAoKIyMgQ29tYmluZSBjYW5jZXIgc3VidHlwZXMgIHsudGFic2V0fQpgYGB7cn0KZm9yIChpIGluIHNlcV9hbG9uZyhhbGxfZGF0YXNldHMpKSB7CiAgYWxsX2RhdGFzZXRzW1tpXV0kY2FuY2VyX3R5cGVfY29tYmluZWQgPSBhbGxfZGF0YXNldHNbW2ldXSQiY2FuY2VyX3R5cGUiICAlPiUgZ3N1YihwYXR0ZXJuID0gIk1lc0xpa2UxfE1lc0xpa2UyIixyZXBsYWNlbWVudCA9ICJNZXNMaWtlIiklPiUgZ3N1YihwYXR0ZXJuID0gIk5QQ0xpa2UxfE5QQ0xpa2UyIixyZXBsYWNlbWVudCA9ICJOUENMaWtlIikKfQoKYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KZm9yIChkYXRhc2V0IGluIGFsbF9kYXRhc2V0cykgewogIGNsdXN0ZXJzX2FuZF9zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gZGF0YXNldCx2YXJzPSBjKCJjYW5jZXJfdHlwZV9jb21iaW5lZCIsInNldXJhdF9jbHVzdGVycyIpKSAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycyxjYW5jZXJfdHlwZV9jb21iaW5lZCkgJT4lICBzdW1tYXJpc2Uobl9jZWxscyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKSU+JSBtdXRhdGUocGVyID0gIDEwMCAqbl9jZWxscy9zdW0obl9jZWxscykpCiAgCiAgaW50ZWdyYXRpb25fc2NvcmUgPSBjbHVzdGVyc19hbmRfc2NvcmVzICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUgZmlsdGVyKG5fY2VsbHMgPT0gbWF4KG5fY2VsbHMpKSAlPiUgcHVsbChwZXIpICU+JSBtZWFuKCkgJT4lIHJvdW5kKGRpZ2l0cyA9IDIpCiAgCiAgaW50ZWdyYXRpb25fc2NvcmVfc3VtX2NlbGxzID0gY2x1c3RlcnNfYW5kX3Njb3JlcyAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lIGZpbHRlcihuX2NlbGxzID09IG1heChuX2NlbGxzKSkgJT4lIHB1bGwobl9jZWxscykgJT4lIHN1bSgpICU+JSAKICAgIGRpdmlkZV9ieShzdW0oY2x1c3RlcnNfYW5kX3Njb3JlcyRuX2NlbGxzKSkgJT4lIHJvdW5kKGRpZ2l0cyA9IDIpCiAgCiAgdl9mYWN0b3JfbGV2ZWxzIDwtYyggIk1lc0xpa2UiLCAiTlBDTGlrZSIsICJPUENMaWtlIiwiQUNMaWtlIikKICBjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoNiwgIlBhaXJlZCIpW2MoMiw0LDUsNildOyBjb2xvcnNbM10gPSAib3JhbmdlIgogIHA0ID0gZ2dwbG90KGRhdGE9Y2x1c3RlcnNfYW5kX3Njb3JlcywgYWVzKHg9c2V1cmF0X2NsdXN0ZXJzLCB5PXBlciwgZmlsbD1mYWN0b3IoY2FuY2VyX3R5cGVfY29tYmluZWQsIGxldmVscyA9IHZfZmFjdG9yX2xldmVscykpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3RoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9ycyxuYW1lICA9ICJDYW5jZXIgdHlwZSIpKyAKICAgIGxhYnModGl0bGUgPSBkYXRhc2V0QHByb2plY3QubmFtZSxzdWJ0aXRsZSA9ICJpbnRlZ3JhdGlvbiBzY29yZT0iICVzKyUgaW50ZWdyYXRpb25fc2NvcmUgJXMrJSAiJSIgJXMrJSAiXG5pbnRlZ3JhdGlvbiBzdW1zIGNlbGxzIHNjb3JlPSIgJXMrJSAKICAgICAgICAgICBpbnRlZ3JhdGlvbl9zY29yZV9zdW1fY2VsbHMpK3lsYWIoIiUgZnJvbSBjbHVzdGVyIikKICBwcmludF90YWIocDQsdGl0bGUgPSBkYXRhc2V0QHByb2plY3QubmFtZSxzdWJ0aXRsZV9udW0gPSAzKQp9CgpgYGAKCiMgMTAgY2x1c3RlcnMKYGBge3J9CkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljIDwtIEZpbmRDbHVzdGVycyhHQk1TZXVyYXRfY2FuY2VyX3NpcHNpYywgcmVzb2x1dGlvbiA9IDAuNjUpCkdCTVNldXJhdF9jYW5jZXJfc2lwc2ljX2NwIDwtIEZpbmRDbHVzdGVycyhHQk1TZXVyYXRfY2FuY2VyX3NpcHNpY19jcCwgcmVzb2x1dGlvbiA9IDAuNCkKR0JNLmNvbWJpbmVkIDwtIEZpbmRDbHVzdGVycyhHQk0uY29tYmluZWQsIHJlc29sdXRpb24gPSAwLjYpCkdCTVNldXJhdF9jYW5jZXJfaGFybW9ueSA8LSBGaW5kQ2x1c3RlcnMoR0JNU2V1cmF0X2NhbmNlcl9oYXJtb255LCByZXNvbHV0aW9uID0gMC4xOSkKR0JNU2V1cmF0X2NhbmNlciAgJTw+JSBGaW5kQ2x1c3RlcnMocmVzb2x1dGlvbiAgPSAwLjA5KQpgYGAKCmBgYHtyfQphbGxfZGF0YXNldHMgPSBsaXN0KEdCTVNldXJhdF9jYW5jZXIsR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWMsR0JNU2V1cmF0X2NhbmNlcl9zaXBzaWNfY3AsR0JNLmNvbWJpbmVkLEdCTVNldXJhdF9jYW5jZXJfaGFybW9ueSkKYGBgCiMjIFVNQVBTICB7LnRhYnNldH0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAscmVzdWx0cz0nYXNpcyd9Cgpmb3IgKGRhdGFzZXQgaW4gYWxsX2RhdGFzZXRzKSB7CiAgcHJpbnRfdGFiKERpbVBsb3QoZGF0YXNldCwgcmVkdWN0aW9uID0gInVtYXAiLGdyb3VwLmJ5ID0gYygic2V1cmF0X2NsdXN0ZXJzIiwib3JpZy5pZGVudCIsImNhbmNlcl90eXBlIiksbmNvbCA9IDIpLHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGVfbnVtID0gMykKfQpgYGAKCgoKCiMjIHN0YWNrZWQgYmF0cGxvdCAgey50YWJzZXR9CgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMyxyZXN1bHRzPSdhc2lzJ30KZm9yIChkYXRhc2V0IGluIGFsbF9kYXRhc2V0cykgewogIAogIGNsdXN0ZXJzX2FuZF9zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gZGF0YXNldCx2YXJzPSBjKCJjYW5jZXJfdHlwZSIsInNldXJhdF9jbHVzdGVycyIpKSAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycyxjYW5jZXJfdHlwZSkgJT4lCiAgICBzdW1tYXJpc2Uobl9jZWxscyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKSU+JSBtdXRhdGUocGVyID0gIDEwMCAqbl9jZWxscy9zdW0obl9jZWxscykpCiAgCiAgaW50ZWdyYXRpb25fc2NvcmUgPSBjbHVzdGVyc19hbmRfc2NvcmVzICU+JSAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUgZmlsdGVyKG5fY2VsbHMgPT0gbWF4KG5fY2VsbHMpKSAlPiUgcHVsbChwZXIpICU+JSBtZWFuKCkgJT4lIHJvdW5kKGRpZ2l0cyA9IDIpCiAgaW50ZWdyYXRpb25fc2NvcmVfc3VtX2NlbGxzID0gY2x1c3RlcnNfYW5kX3Njb3JlcyAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lIGZpbHRlcihuX2NlbGxzID09IG1heChuX2NlbGxzKSkgJT4lIHB1bGwobl9jZWxscykgJT4lIHN1bSgpICU+JQogICAgZGl2aWRlX2J5KHN1bShjbHVzdGVyc19hbmRfc2NvcmVzJG5fY2VsbHMpKSAlPiUgcm91bmQoZGlnaXRzID0gMikKICAKICB2X2ZhY3Rvcl9sZXZlbHMgPC1jKCAiTWVzTGlrZTEiLCAiTWVzTGlrZTIiLCAiTlBDTGlrZTEiLCAiTlBDTGlrZTIiLCAiT1BDTGlrZSIsIkFDTGlrZSIpCiAgY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJQYWlyZWQiKTsgY29sb3JzWzVdID0gIm9yYW5nZSIKICBwMiA9IGdncGxvdChkYXRhPWNsdXN0ZXJzX2FuZF9zY29yZXMsIGFlcyh4PXNldXJhdF9jbHVzdGVycywgeT1wZXIsIGZpbGw9ZmFjdG9yKGNhbmNlcl90eXBlLCBsZXZlbHMgPSB2X2ZhY3Rvcl9sZXZlbHMpKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSt0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMsbmFtZSAgPSAiQ2FuY2VyIHR5cGUiKSsgCiAgICBsYWJzKHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGUgPSAiaW50ZWdyYXRpb24gc2NvcmU9IiAlcyslIGludGVncmF0aW9uX3Njb3JlICVzKyUgIiUiICVzKyUgIlxuaW50ZWdyYXRpb24gc3VtcyBjZWxscyBzY29yZT0iCiAgICAgICAgICVzKyUgaW50ZWdyYXRpb25fc2NvcmVfc3VtX2NlbGxzKSsKICAgIHlsYWIoIiUgZnJvbSBjbHVzdGVyIikKICAKICAKICBjbHVzdGVyc19hbmRfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IGRhdGFzZXQsdmFycz0gYygib3JpZy5pZGVudCIsInNldXJhdF9jbHVzdGVycyIpKSAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycyxvcmlnLmlkZW50KSAlPiUgIAogICAgc3VtbWFyaXNlKG5fY2VsbHMgPSBuKCksIC5ncm91cHMgPSAiZHJvcF9sYXN0IiklPiUgbXV0YXRlKHBlciA9ICAxMDAgKm5fY2VsbHMvc3VtKG5fY2VsbHMpKQogIAogIGNvbG9ycyA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg5LCAiUGFpcmVkIikKICBwMyA9IGdncGxvdChkYXRhPWNsdXN0ZXJzX2FuZF9zY29yZXMsIGFlcyh4PXNldXJhdF9jbHVzdGVycywgeT1wZXIsIGZpbGw9ZmFjdG9yKG9yaWcuaWRlbnQpKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSt0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMsbmFtZSAgPSAiUGF0aWVudCIpKyAKICAgIGxhYnModGl0bGUgPSBkYXRhc2V0QHByb2plY3QubmFtZSkrCiAgICB5bGFiKCIlIGZyb20gY2x1c3RlciIpCiAgCiAgcHJpbnRfdGFiKHAyK3AzLHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGVfbnVtID0gMykKfQpgYGAKCiMjIENvbWJpbmUgY2FuY2VyIHN1YnR5cGVzICB7LnRhYnNldH0KYGBge3J9CmZvciAoaSBpbiBzZXFfYWxvbmcoYWxsX2RhdGFzZXRzKSkgewogIGFsbF9kYXRhc2V0c1tbaV1dJGNhbmNlcl90eXBlX2NvbWJpbmVkID0gYWxsX2RhdGFzZXRzW1tpXV0kImNhbmNlcl90eXBlIiAgJT4lIGdzdWIocGF0dGVybiA9ICJNZXNMaWtlMXxNZXNMaWtlMiIscmVwbGFjZW1lbnQgPSAiTWVzTGlrZSIpJT4lIGdzdWIocGF0dGVybiA9ICJOUENMaWtlMXxOUENMaWtlMiIscmVwbGFjZW1lbnQgPSAiTlBDTGlrZSIpCn0KCmBgYAoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CmZvciAoZGF0YXNldCBpbiBhbGxfZGF0YXNldHMpIHsKICBjbHVzdGVyc19hbmRfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IGRhdGFzZXQsdmFycz0gYygiY2FuY2VyX3R5cGVfY29tYmluZWQiLCJzZXVyYXRfY2x1c3RlcnMiKSkgJT4lICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMsY2FuY2VyX3R5cGVfY29tYmluZWQpICU+JSAgc3VtbWFyaXNlKG5fY2VsbHMgPSBuKCksIC5ncm91cHMgPSAiZHJvcF9sYXN0IiklPiUgbXV0YXRlKHBlciA9ICAxMDAgKm5fY2VsbHMvc3VtKG5fY2VsbHMpKQogIAogIGludGVncmF0aW9uX3Njb3JlID0gY2x1c3RlcnNfYW5kX3Njb3JlcyAlPiUgIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lIGZpbHRlcihuX2NlbGxzID09IG1heChuX2NlbGxzKSkgJT4lIHB1bGwocGVyKSAlPiUgbWVhbigpICU+JSByb3VuZChkaWdpdHMgPSAyKQogIAogIGludGVncmF0aW9uX3Njb3JlX3N1bV9jZWxscyA9IGNsdXN0ZXJzX2FuZF9zY29yZXMgJT4lICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JSBmaWx0ZXIobl9jZWxscyA9PSBtYXgobl9jZWxscykpICU+JSBwdWxsKG5fY2VsbHMpICU+JSBzdW0oKSAlPiUgCiAgICBkaXZpZGVfYnkoc3VtKGNsdXN0ZXJzX2FuZF9zY29yZXMkbl9jZWxscykpICU+JSByb3VuZChkaWdpdHMgPSAyKQogIAogIHZfZmFjdG9yX2xldmVscyA8LWMoICJNZXNMaWtlIiwgIk5QQ0xpa2UiLCAiT1BDTGlrZSIsIkFDTGlrZSIpCiAgY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJQYWlyZWQiKVtjKDIsNCw1LDYpXTsgY29sb3JzWzNdID0gIm9yYW5nZSIKICBwNCA9IGdncGxvdChkYXRhPWNsdXN0ZXJzX2FuZF9zY29yZXMsIGFlcyh4PXNldXJhdF9jbHVzdGVycywgeT1wZXIsIGZpbGw9ZmFjdG9yKGNhbmNlcl90eXBlX2NvbWJpbmVkLCBsZXZlbHMgPSB2X2ZhY3Rvcl9sZXZlbHMpKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSt0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMsbmFtZSAgPSAiQ2FuY2VyIHR5cGUiKSsgCiAgICBsYWJzKHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGUgPSAiaW50ZWdyYXRpb24gc2NvcmU9IiAlcyslIGludGVncmF0aW9uX3Njb3JlICVzKyUgIiUiICVzKyUgIlxuaW50ZWdyYXRpb24gc3VtcyBjZWxscyBzY29yZT0iICVzKyUgCiAgICAgICAgICAgaW50ZWdyYXRpb25fc2NvcmVfc3VtX2NlbGxzKSt5bGFiKCIlIGZyb20gY2x1c3RlciIpCiAgcHJpbnRfdGFiKHA0LHRpdGxlID0gZGF0YXNldEBwcm9qZWN0Lm5hbWUsc3VidGl0bGVfbnVtID0gMykKfQoKYGBgCjxzY3JpcHQgc3JjPSJodHRwczovL2h5cG90aGVzLmlzL2VtYmVkLmpzIiBhc3luYz48L3NjcmlwdD4KCg==