1 Functions

remotes::install_github(repo = "samuel-marsh/scCustomize")

2 Data

SCC4.data  = Read10X(data.dir = "./Data/cervical_cancer_data/Qiu et al/SCC4//")
SCC4 <- CreateSeuratObject(counts = SCC4.data, project = "scc", min.cells = 3, min.features = 200)
SCC4[["percent.mt"]] <- PercentageFeatureSet(SCC4, pattern = "^MT-")
SCC4 <- subset(SCC4, subset = percent.mt < 10)
SCC4 <- NormalizeData(SCC4)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
SCC5.data  = Read10X(data.dir = "./Data/cervical_cancer_data/Qiu et al/SCC5/")
SCC5 <- CreateSeuratObject(counts = SCC5.data, project = "scc", min.cells = 3, min.features = 200)
SCC5[["percent.mt"]] <- PercentageFeatureSet(SCC5, pattern = "^MT-")
SCC5 <- subset(SCC5, subset = percent.mt < 10)
SCC5 <- NormalizeData(SCC5)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
mtx <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917937_SCC_1_matrix.mtx.gz"
cells <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917937_SCC_1_barcodes.tsv.gz"
features <-  "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917937_SCC_1_features.tsv.gz"
SCC1.data <- ReadMtx(mtx = mtx, cells = cells, features = features)
SCC1 <- CreateSeuratObject(counts = SCC1.data, project = "scc", min.cells = 3, min.features = 200)
SCC1[["percent.mt"]] <- PercentageFeatureSet(SCC1, pattern = "^MT-")
SCC1 <- subset(SCC1, subset = percent.mt < 10)
SCC1 <- NormalizeData(SCC1)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
mtx <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917938_SCC_2_matrix.mtx.gz"
cells <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917938_SCC_2_barcodes.tsv.gz"
features <-  "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917938_SCC_2_features.tsv.gz"
SCC2.data <- ReadMtx(mtx = mtx, cells = cells, features = features)
SCC2 <- CreateSeuratObject(counts = SCC2.data, project = "scc", min.cells = 3, min.features = 200)
SCC2[["percent.mt"]] <- PercentageFeatureSet(SCC2, pattern = "^MT-")
SCC2 <- subset(SCC2, subset = percent.mt < 10)
SCC2 <- NormalizeData(SCC2)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
mtx <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917939_SCC_3_matrix.mtx.gz"
cells <- "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917939_SCC_3_barcodes.tsv.gz"
features <-  "./Data/cervical_cancer_data/Qiu et al/GSE197461/GSM5917939_SCC_3_features.tsv.gz"
SCC3.data <- ReadMtx(mtx = mtx, cells = cells, features = features)
SCC3 <- CreateSeuratObject(counts = SCC3.data, project = "scc", min.cells = 3, min.features = 200)
SCC3[["percent.mt"]] <- PercentageFeatureSet(SCC3, pattern = "^MT-")
SCC3 <- subset(SCC3, subset = percent.mt < 10)
SCC3 <- NormalizeData(SCC3)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
VlnPlot(object = SCC1,features = "MYB")+ggtitle("SCC1")|VlnPlot(object = SCC2,features = "MYB")+ggtitle("SCC2")|VlnPlot(object = SCC3,features = "MYB")+ggtitle("SCC3")|VlnPlot(object = SCC4,features = "MYB")+ggtitle("SCC4")|VlnPlot(object = SCC5,features = "MYB",group.by = "orig.ident")+ggtitle("SCC5")

SCC5[["percent.mt"]] <- PercentageFeatureSet(SCC5, pattern = "^MT-")
SCC5 <- subset(SCC5, subset = percent.mt < 10)

SCC5 <- NormalizeData(SCC5)
SCC5 <- FindVariableFeatures(SCC5,nfeatures = 2000)
SCC5 <- ScaleData(SCC5,features = VariableFeatures(SCC5),vars.to.regress = c("percent.mt","nCount_RNA"))
SCC5  %<>%  RunPCA( features = VariableFeatures(object = SCC5))
ElbowPlot(SCC5,ndims = 50)

SCC5  %<>%  FindNeighbors(dims = 1:20) %>%  FindClusters(resolution = 0.2) %>%  RunUMAP(dims = 1:20)
DimPlot(SCC5,label = T)

FeaturePlot(SCC5,features = "MYB")

library(patchwork)

p1 = FeaturePlot(object = SCC5,features = c("KRT18","EPCAM")) + plot_annotation(
  title = 'epithelial markers')

p2 = FeaturePlot(object = SCC5,features = c("VWF", "PLVAP"))+ plot_annotation(
  title = 'endothelial markers')

p3 = FeaturePlot(object = SCC5,features = c("COL1A1", "LUM"),ncol = 1)+ plot_annotation(
  title = 'fibroblasts  markers')

p4 = FeaturePlot(object = SCC5,features = c("ACTA2", "TAGLN"),ncol = 1)+ plot_annotation(
  title = 'smooth muscle markers')
p5 = FeaturePlot(object = SCC5,features = c("CSF3R"),ncol = 1)+ plot_annotation(
  title = 'neutrophils markers')
p6 = FeaturePlot(object = SCC5,features = c("CPA3"),ncol = 1)+ plot_annotation(
  title = 'mast markers')
p7 = FeaturePlot(object = SCC5,features = c("FCN1"),ncol = 1)+ plot_annotation(
  title = 'monocytes   markers')
p8 = FeaturePlot(object = SCC5,features = c("C1QB","LYZ"),ncol = 1)+ plot_annotation(
  title = 'macrophages    markers')
p9 = FeaturePlot(object = SCC5,features = c("IRF8"),ncol = 1)+ plot_annotation(
  title = 'dendritic markers')
p10 = FeaturePlot(object = SCC5,features = c("JCHAIN","MZB1"),ncol = 1)+ plot_annotation(
  title = 'B/plasma markers')
p11= FeaturePlot(object = SCC5,features = c("CD2","CD3D"),ncol = 1)+ plot_annotation(
  title = 'T markers')

for (p in list(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11)) {
  print_tab(plt = p,title = p$patches$annotation$title)

}

epithelial markers

endothelial markers

fibroblasts markers

smooth muscle markers

neutrophils markers

mast markers

monocytes markers

macrophages markers

dendritic markers

B/plasma markers

T markers

NA

SCC5_cancer <- subset(SCC5, subset = seurat_clusters %in% c(0,10,3))

3 HPV reads

all_reads_per_cell = c()
runs = c("20330695","20330696","20330697","20330698")

for (run in runs) {
hpv_bam = read_tsv(file = "./Data/cervical_cancer_data/Qiu et al/SCC5/HPV/" %s+% run %s+% "_reads.tsv",col_select = 1,col_names = F)
reads_per_cell = str_extract(pattern = "CR:Z:.*$",string = hpv_bam$X1) %>% str_sub( start = 6)
all_reads_per_cell = c(reads_per_cell,all_reads_per_cell)


}
Warning: One or more parsing issues, see `problems()` for details
Rows: 4716 Columns: 1
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): X1

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Warning: One or more parsing issues, see `problems()` for details
Rows: 4656 Columns: 1
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): X1

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Warning: One or more parsing issues, see `problems()` for details
Rows: 5799 Columns: 1
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): X1

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Warning: One or more parsing issues, see `problems()` for details
Rows: 4392 Columns: 1
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): X1

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
all_reads_per_cell = all_reads_per_cell%>% table() %>% as.data.frame() %>% column_to_rownames(".")
rownames(all_reads_per_cell) = paste0(rownames(all_reads_per_cell),"-1")
all_reads_per_cell
zero_cells = colnames(SCC5_cancer)[!colnames(SCC5_cancer) %in% rownames(all_reads_per_cell)]
zero_cells_freq = data.frame(row.names = zero_cells,Freq = rep(0,length(zero_cells)))
reads_per_cell_all_cells = rbind(all_reads_per_cell,zero_cells_freq)
SCC5_cancer %<>% AddMetaData(metadata = reads_per_cell_all_cells,col.name = "HPV_reads")
hpv_reads = FetchData(object = SCC5_cancer,vars = "HPV_reads")
data = hpv_reads %>% mutate("0 reads" = if_else(condition = HPV_reads == 0,true = 1,false = 0))
data = data %>% mutate("1 reads" = if_else(condition = HPV_reads == 1,true = 1,false = 0))
data = data %>% mutate("2 reads" = if_else(condition = HPV_reads == 2,true = 1,false = 0))
data = data %>% mutate("3-23 reads" = if_else(condition = HPV_reads >=3 &HPV_reads  <24,true = 1,false = 0))
data = data %>% mutate("24+ reads" = if_else(condition = HPV_reads >=24,true = 1,false = 0))
data = colSums(data[,2:ncol(data)]) %>% as.data.frame()
names(data)[1] = "count"
data = rownames_to_column(data,var = "bin")
ggplot(data=data, aes(x=factor(bin,levels = c("0 reads","1 reads","2 reads","3-23 reads","24+ reads")), y=count)) +
  geom_bar(stat="identity", fill="steelblue") + xlab("HPV Reads")+ theme_minimal()+
  geom_text(aes(label=count), vjust=-0.5, color="black", size=3.5)


hpv_positive = hpv_reads %>% dplyr::mutate(hpv_positive = case_when(HPV_reads >= 2 ~ "positive",
                                                                    HPV_reads < 2 ~ "negative")
)


SCC5_cancer = AddMetaData(object = SCC5_cancer,metadata = hpv_positive)

myb_data = FetchData(object = SCC5_cancer,vars = ("MYB"))%>% dplyr::mutate(myb_positive = case_when(MYB > 0 ~ "positive",
                                                                    MYB == 0 ~ "negative")) %>% dplyr::select("myb_positive")
SCC5_cancer = AddMetaData(object = SCC5_cancer,metadata = myb_data,col.name = "MYB_positive")
DimPlot(object = SCC5_cancer,group.by  = c("hpv_positive"),pt.size = 0.5)

DimPlot(object = SCC5_cancer,group.by  = c("MYB_positive"),pt.size = 0.5)

FeaturePlot(object = SCC5_cancer,features = c("HPV_reads"),pt.size = 0.5)

library(ggrepel)
data = FetchData(object = SCC5_cancer,vars =  c("MYB","HPV_reads"))


ggplot(data,
           aes(x = MYB, y = HPV_reads)) +  geom_smooth(method = lm) +
  geom_point() + stat_cor(method = "pearson")
`geom_smooth()` using formula 'y ~ x'

4 Boxplot HPV_positive VS MYB

myb_vs_hpv = FetchData(object = SCC5_cancer, vars = c("hpv_positive", "MYB"))
myb_vs_hpv$hpv_positive = paste("HPV", myb_vs_hpv$hpv_positive)
p1 = ggplot(myb_vs_hpv,aes( x = hpv_positive, y = MYB,, fill=hpv_positive))+ 
    geom_violin(trim=FALSE) + theme_minimal()+
  stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV positive","HPV negative")))+
  stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(gene) +
  geom_boxplot(width=.1, outlier.shape=NA) 


print_tab(p1,title = gene)
##   MYB {.unnumbered }  

NA
myb_vs_hpv = FetchData(object = SCC5_cancer, vars = c("HPV_reads", "MYB_positive"))

p2 = ggplot(myb_vs_hpv,aes( x = MYB_positive, y =HPV_reads ,  fill=MYB_positive))+ 
    geom_violin(trim=FALSE) + theme_minimal()+
  stat_compare_means(method = "wilcox.test",comparisons = list(c("positive","negative")))+
  stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text")+
  geom_boxplot(width=.1, outlier.shape=NA) 


print_tab(p2,title = gene)
##   MYB {.unnumbered }  

NA
p1+p2 +plt
library(ggstatsplot)
df  = FetchData(object = SCC5_cancer,vars = c("hpv_positive","MYB_positive")) %>% droplevels() 
test = fisher.test(table(df))
plt = ggbarstats(
  df,
  MYB_positive,
  hpv_positive,
  results.subtitle = FALSE,
  subtitle = paste0("Fisher's exact test", ", p-value = ",
                    round(test$p.value, 13))
)

print_tab(plt = plt,title = "fisher")
##   fisher {.unnumbered }  

NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKCiMgRnVuY3Rpb25zCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpgYGAKCmBgYHtyfQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YihyZXBvID0gInNhbXVlbC1tYXJzaC9zY0N1c3RvbWl6ZSIpCmBgYAoKIyBEYXRhCgpgYGB7cn0KU0NDNC5kYXRhICA9IFJlYWQxMFgoZGF0YS5kaXIgPSAiLi9EYXRhL2NlcnZpY2FsX2NhbmNlcl9kYXRhL1FpdSBldCBhbC9TQ0M0Ly8iKQpTQ0M0IDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBTQ0M0LmRhdGEsIHByb2plY3QgPSAic2NjIiwgbWluLmNlbGxzID0gMywgbWluLmZlYXR1cmVzID0gMjAwKQpTQ0M0W1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTQ0M0LCBwYXR0ZXJuID0gIl5NVC0iKQpTQ0M0IDwtIHN1YnNldChTQ0M0LCBzdWJzZXQgPSBwZXJjZW50Lm10IDwgMTApClNDQzQgPC0gTm9ybWFsaXplRGF0YShTQ0M0KQoKClNDQzUuZGF0YSAgPSBSZWFkMTBYKGRhdGEuZGlyID0gIi4vRGF0YS9jZXJ2aWNhbF9jYW5jZXJfZGF0YS9RaXUgZXQgYWwvU0NDNS8iKQpTQ0M1IDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBTQ0M1LmRhdGEsIHByb2plY3QgPSAic2NjIiwgbWluLmNlbGxzID0gMywgbWluLmZlYXR1cmVzID0gMjAwKQpTQ0M1W1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTQ0M1LCBwYXR0ZXJuID0gIl5NVC0iKQpTQ0M1IDwtIHN1YnNldChTQ0M1LCBzdWJzZXQgPSBwZXJjZW50Lm10IDwgMTApClNDQzUgPC0gTm9ybWFsaXplRGF0YShTQ0M1KQoKbXR4IDwtICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM3X1NDQ18xX21hdHJpeC5tdHguZ3oiCmNlbGxzIDwtICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM3X1NDQ18xX2JhcmNvZGVzLnRzdi5neiIKZmVhdHVyZXMgPC0gICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM3X1NDQ18xX2ZlYXR1cmVzLnRzdi5neiIKU0NDMS5kYXRhIDwtIFJlYWRNdHgobXR4ID0gbXR4LCBjZWxscyA9IGNlbGxzLCBmZWF0dXJlcyA9IGZlYXR1cmVzKQpTQ0MxIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBTQ0MxLmRhdGEsIHByb2plY3QgPSAic2NjIiwgbWluLmNlbGxzID0gMywgbWluLmZlYXR1cmVzID0gMjAwKQpTQ0MxW1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTQ0MxLCBwYXR0ZXJuID0gIl5NVC0iKQpTQ0MxIDwtIHN1YnNldChTQ0MxLCBzdWJzZXQgPSBwZXJjZW50Lm10IDwgMTApClNDQzEgPC0gTm9ybWFsaXplRGF0YShTQ0MxKQoKbXR4IDwtICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM4X1NDQ18yX21hdHJpeC5tdHguZ3oiCmNlbGxzIDwtICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM4X1NDQ18yX2JhcmNvZGVzLnRzdi5neiIKZmVhdHVyZXMgPC0gICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL0dTRTE5NzQ2MS9HU001OTE3OTM4X1NDQ18yX2ZlYXR1cmVzLnRzdi5neiIKU0NDMi5kYXRhIDwtIFJlYWRNdHgobXR4ID0gbXR4LCBjZWxscyA9IGNlbGxzLCBmZWF0dXJlcyA9IGZlYXR1cmVzKQpTQ0MyIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBTQ0MyLmRhdGEsIHByb2plY3QgPSAic2NjIiwgbWluLmNlbGxzID0gMywgbWluLmZlYXR1cmVzID0gMjAwKQpTQ0MyW1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTQ0MyLCBwYXR0ZXJuID0gIl5NVC0iKQpTQ0MyIDwtIHN1YnNldChTQ0MyLCBzdWJzZXQgPSBwZXJjZW50Lm10IDwgMTApClNDQzIgPC0gTm9ybWFsaXplRGF0YShTQ0MyKQoKCm10eCA8LSAiLi9EYXRhL2NlcnZpY2FsX2NhbmNlcl9kYXRhL1FpdSBldCBhbC9HU0UxOTc0NjEvR1NNNTkxNzkzOV9TQ0NfM19tYXRyaXgubXR4Lmd6IgpjZWxscyA8LSAiLi9EYXRhL2NlcnZpY2FsX2NhbmNlcl9kYXRhL1FpdSBldCBhbC9HU0UxOTc0NjEvR1NNNTkxNzkzOV9TQ0NfM19iYXJjb2Rlcy50c3YuZ3oiCmZlYXR1cmVzIDwtICAiLi9EYXRhL2NlcnZpY2FsX2NhbmNlcl9kYXRhL1FpdSBldCBhbC9HU0UxOTc0NjEvR1NNNTkxNzkzOV9TQ0NfM19mZWF0dXJlcy50c3YuZ3oiClNDQzMuZGF0YSA8LSBSZWFkTXR4KG10eCA9IG10eCwgY2VsbHMgPSBjZWxscywgZmVhdHVyZXMgPSBmZWF0dXJlcykKU0NDMyA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gU0NDMy5kYXRhLCBwcm9qZWN0ID0gInNjYyIsIG1pbi5jZWxscyA9IDMsIG1pbi5mZWF0dXJlcyA9IDIwMCkKU0NDM1tbInBlcmNlbnQubXQiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoU0NDMywgcGF0dGVybiA9ICJeTVQtIikKU0NDMyA8LSBzdWJzZXQoU0NDMywgc3Vic2V0ID0gcGVyY2VudC5tdCA8IDEwKQpTQ0MzIDwtIE5vcm1hbGl6ZURhdGEoU0NDMykKCgpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMn0KVmxuUGxvdChvYmplY3QgPSBTQ0MxLGZlYXR1cmVzID0gIk1ZQiIpK2dndGl0bGUoIlNDQzEiKXxWbG5QbG90KG9iamVjdCA9IFNDQzIsZmVhdHVyZXMgPSAiTVlCIikrZ2d0aXRsZSgiU0NDMiIpfFZsblBsb3Qob2JqZWN0ID0gU0NDMyxmZWF0dXJlcyA9ICJNWUIiKStnZ3RpdGxlKCJTQ0MzIil8VmxuUGxvdChvYmplY3QgPSBTQ0M0LGZlYXR1cmVzID0gIk1ZQiIpK2dndGl0bGUoIlNDQzQiKXxWbG5QbG90KG9iamVjdCA9IFNDQzUsZmVhdHVyZXMgPSAiTVlCIixncm91cC5ieSA9ICJvcmlnLmlkZW50IikrZ2d0aXRsZSgiU0NDNSIpCmBgYAoKCmBgYHtyfQpTQ0M1W1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTQ0M1LCBwYXR0ZXJuID0gIl5NVC0iKQpTQ0M1IDwtIHN1YnNldChTQ0M1LCBzdWJzZXQgPSBwZXJjZW50Lm10IDwgMTApCgpTQ0M1IDwtIE5vcm1hbGl6ZURhdGEoU0NDNSkKU0NDNSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhTQ0M1LG5mZWF0dXJlcyA9IDIwMDApClNDQzUgPC0gU2NhbGVEYXRhKFNDQzUsZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKFNDQzUpLHZhcnMudG8ucmVncmVzcyA9IGMoInBlcmNlbnQubXQiLCJuQ291bnRfUk5BIikpClNDQzUgICU8PiUgIFJ1blBDQSggZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IFNDQzUpKQpgYGAKCmBgYHtyfQpFbGJvd1Bsb3QoU0NDNSxuZGltcyA9IDUwKQoKYGBgCmBgYHtyfQpTQ0M1ICAlPD4lICBGaW5kTmVpZ2hib3JzKGRpbXMgPSAxOjIwKSAlPiUgIEZpbmRDbHVzdGVycyhyZXNvbHV0aW9uID0gMC4yKSAlPiUgIFJ1blVNQVAoZGltcyA9IDE6MjApCmBgYAoKYGBge3J9CkRpbVBsb3QoU0NDNSxsYWJlbCA9IFQpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KFNDQzUsZmVhdHVyZXMgPSAiTVlCIikKCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03LHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KHBhdGNod29yaykKCnAxID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gU0NDNSxmZWF0dXJlcyA9IGMoIktSVDE4IiwiRVBDQU0iKSkgKyBwbG90X2Fubm90YXRpb24oCiAgdGl0bGUgPSAnZXBpdGhlbGlhbCBtYXJrZXJzJykKCnAyID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gU0NDNSxmZWF0dXJlcyA9IGMoIlZXRiIsICJQTFZBUCIpKSsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ2VuZG90aGVsaWFsIG1hcmtlcnMnKQoKcDMgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1LGZlYXR1cmVzID0gYygiQ09MMUExIiwgIkxVTSIpLG5jb2wgPSAxKSsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ2ZpYnJvYmxhc3RzICBtYXJrZXJzJykKCnA0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gU0NDNSxmZWF0dXJlcyA9IGMoIkFDVEEyIiwgIlRBR0xOIiksbmNvbCA9IDEpKyBwbG90X2Fubm90YXRpb24oCiAgdGl0bGUgPSAnc21vb3RoIG11c2NsZSBtYXJrZXJzJykKcDUgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1LGZlYXR1cmVzID0gYygiQ1NGM1IiKSxuY29sID0gMSkrIHBsb3RfYW5ub3RhdGlvbigKICB0aXRsZSA9ICduZXV0cm9waGlscyBtYXJrZXJzJykKcDYgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1LGZlYXR1cmVzID0gYygiQ1BBMyIpLG5jb2wgPSAxKSsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ21hc3QgbWFya2VycycpCnA3ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gU0NDNSxmZWF0dXJlcyA9IGMoIkZDTjEiKSxuY29sID0gMSkrIHBsb3RfYW5ub3RhdGlvbigKICB0aXRsZSA9ICdtb25vY3l0ZXMgICBtYXJrZXJzJykKcDggPSBGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1LGZlYXR1cmVzID0gYygiQzFRQiIsIkxZWiIpLG5jb2wgPSAxKSsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ21hY3JvcGhhZ2VzICAgIG1hcmtlcnMnKQpwOSA9IEZlYXR1cmVQbG90KG9iamVjdCA9IFNDQzUsZmVhdHVyZXMgPSBjKCJJUkY4IiksbmNvbCA9IDEpKyBwbG90X2Fubm90YXRpb24oCiAgdGl0bGUgPSAnZGVuZHJpdGljIG1hcmtlcnMnKQpwMTAgPSBGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1LGZlYXR1cmVzID0gYygiSkNIQUlOIiwiTVpCMSIpLG5jb2wgPSAxKSsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ0IvcGxhc21hIG1hcmtlcnMnKQpwMTE9IEZlYXR1cmVQbG90KG9iamVjdCA9IFNDQzUsZmVhdHVyZXMgPSBjKCJDRDIiLCJDRDNEIiksbmNvbCA9IDEpKyBwbG90X2Fubm90YXRpb24oCiAgdGl0bGUgPSAnVCBtYXJrZXJzJykKCmZvciAocCBpbiBsaXN0KHAxLHAyLHAzLHA0LHA1LHA2LHA3LHA4LHA5LHAxMCxwMTEpKSB7CiAgcHJpbnRfdGFiKHBsdCA9IHAsdGl0bGUgPSBwJHBhdGNoZXMkYW5ub3RhdGlvbiR0aXRsZSkKCn0KYGBgCgpgYGB7cn0KU0NDNV9jYW5jZXIgPC0gc3Vic2V0KFNDQzUsIHN1YnNldCA9IHNldXJhdF9jbHVzdGVycyAlaW4lIGMoMCwxMCwzKSkKYGBgCgojIEhQViByZWFkcwoKYGBge3J9CmFsbF9yZWFkc19wZXJfY2VsbCA9IGMoKQpydW5zID0gYygiMjAzMzA2OTUiLCIyMDMzMDY5NiIsIjIwMzMwNjk3IiwiMjAzMzA2OTgiKQoKZm9yIChydW4gaW4gcnVucykgewpocHZfYmFtID0gcmVhZF90c3YoZmlsZSA9ICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL1NDQzUvSFBWLyIgJXMrJSBydW4gJXMrJSAiX3JlYWRzLnRzdiIsY29sX3NlbGVjdCA9IDEsY29sX25hbWVzID0gRikKcmVhZHNfcGVyX2NlbGwgPSBzdHJfZXh0cmFjdChwYXR0ZXJuID0gIkNSOlo6LiokIixzdHJpbmcgPSBocHZfYmFtJFgxKSAlPiUgc3RyX3N1Yiggc3RhcnQgPSA2KQphbGxfcmVhZHNfcGVyX2NlbGwgPSBjKHJlYWRzX3Blcl9jZWxsLGFsbF9yZWFkc19wZXJfY2VsbCkKCgp9CgphbGxfcmVhZHNfcGVyX2NlbGwgPSBhbGxfcmVhZHNfcGVyX2NlbGwlPiUgdGFibGUoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIi4iKQpyb3duYW1lcyhhbGxfcmVhZHNfcGVyX2NlbGwpID0gcGFzdGUwKHJvd25hbWVzKGFsbF9yZWFkc19wZXJfY2VsbCksIi0xIikKYWxsX3JlYWRzX3Blcl9jZWxsCmBgYAoKYGBge3J9Cnplcm9fY2VsbHMgPSBjb2xuYW1lcyhTQ0M1X2NhbmNlcilbIWNvbG5hbWVzKFNDQzVfY2FuY2VyKSAlaW4lIHJvd25hbWVzKGFsbF9yZWFkc19wZXJfY2VsbCldCnplcm9fY2VsbHNfZnJlcSA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gemVyb19jZWxscyxGcmVxID0gcmVwKDAsbGVuZ3RoKHplcm9fY2VsbHMpKSkKcmVhZHNfcGVyX2NlbGxfYWxsX2NlbGxzID0gcmJpbmQoYWxsX3JlYWRzX3Blcl9jZWxsLHplcm9fY2VsbHNfZnJlcSkKU0NDNV9jYW5jZXIgJTw+JSBBZGRNZXRhRGF0YShtZXRhZGF0YSA9IHJlYWRzX3Blcl9jZWxsX2FsbF9jZWxscyxjb2wubmFtZSA9ICJIUFZfcmVhZHMiKQpocHZfcmVhZHMgPSBGZXRjaERhdGEob2JqZWN0ID0gU0NDNV9jYW5jZXIsdmFycyA9ICJIUFZfcmVhZHMiKQpgYGAKCmBgYHtyfQpkYXRhID0gaHB2X3JlYWRzICU+JSBtdXRhdGUoIjAgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFZfcmVhZHMgPT0gMCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIxIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWX3JlYWRzID09IDEsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMiByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVl9yZWFkcyA9PSAyLHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjMtMjMgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFZfcmVhZHMgPj0zICZIUFZfcmVhZHMgIDwyNCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIyNCsgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFZfcmVhZHMgPj0yNCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gY29sU3VtcyhkYXRhWywyOm5jb2woZGF0YSldKSAlPiUgYXMuZGF0YS5mcmFtZSgpCm5hbWVzKGRhdGEpWzFdID0gImNvdW50IgpkYXRhID0gcm93bmFtZXNfdG9fY29sdW1uKGRhdGEsdmFyID0gImJpbiIpCmdncGxvdChkYXRhPWRhdGEsIGFlcyh4PWZhY3RvcihiaW4sbGV2ZWxzID0gYygiMCByZWFkcyIsIjEgcmVhZHMiLCIyIHJlYWRzIiwiMy0yMyByZWFkcyIsIjI0KyByZWFkcyIpKSwgeT1jb3VudCkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9InN0ZWVsYmx1ZSIpICsgeGxhYigiSFBWIFJlYWRzIikrIHRoZW1lX21pbmltYWwoKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50KSwgdmp1c3Q9LTAuNSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjUpCmBgYAoKCmBgYHtyfQoKaHB2X3Bvc2l0aXZlID0gaHB2X3JlYWRzICU+JSBkcGx5cjo6bXV0YXRlKGhwdl9wb3NpdGl2ZSA9IGNhc2Vfd2hlbihIUFZfcmVhZHMgPj0gMiB+ICJwb3NpdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSFBWX3JlYWRzIDwgMiB+ICJuZWdhdGl2ZSIpCikKCgpTQ0M1X2NhbmNlciA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IFNDQzVfY2FuY2VyLG1ldGFkYXRhID0gaHB2X3Bvc2l0aXZlKQoKbXliX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gU0NDNV9jYW5jZXIsdmFycyA9ICgiTVlCIikpJT4lIGRwbHlyOjptdXRhdGUobXliX3Bvc2l0aXZlID0gY2FzZV93aGVuKE1ZQiA+IDAgfiAicG9zaXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1ZQiA9PSAwIH4gIm5lZ2F0aXZlIikpICU+JSBkcGx5cjo6c2VsZWN0KCJteWJfcG9zaXRpdmUiKQpTQ0M1X2NhbmNlciA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IFNDQzVfY2FuY2VyLG1ldGFkYXRhID0gbXliX2RhdGEsY29sLm5hbWUgPSAiTVlCX3Bvc2l0aXZlIikKCmBgYAoKYGBge3J9CkRpbVBsb3Qob2JqZWN0ID0gU0NDNV9jYW5jZXIsZ3JvdXAuYnkgID0gYygiaHB2X3Bvc2l0aXZlIikscHQuc2l6ZSA9IDAuNSkKRGltUGxvdChvYmplY3QgPSBTQ0M1X2NhbmNlcixncm91cC5ieSAgPSBjKCJNWUJfcG9zaXRpdmUiKSxwdC5zaXplID0gMC41KQpGZWF0dXJlUGxvdChvYmplY3QgPSBTQ0M1X2NhbmNlcixmZWF0dXJlcyA9IGMoIkhQVl9yZWFkcyIpLHB0LnNpemUgPSAwLjUpCgpgYGAKCgpgYGB7cn0KbGlicmFyeShnZ3JlcGVsKQpkYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IFNDQzVfY2FuY2VyLHZhcnMgPSAgYygiTVlCIiwiSFBWX3JlYWRzIikpCgoKZ2dwbG90KGRhdGEsCiAgICAgICAgICAgYWVzKHggPSBNWUIsIHkgPSBIUFZfcmVhZHMpKSArICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkgKwogIGdlb21fcG9pbnQoKSArIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikKYGBgCgojIEJveHBsb3QgSFBWX3Bvc2l0aXZlIFZTIE1ZQgoKYGBge3J9Cm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gU0NDNV9jYW5jZXIsIHZhcnMgPSBjKCJocHZfcG9zaXRpdmUiLCAiTVlCIikpCm15Yl92c19ocHYkaHB2X3Bvc2l0aXZlID0gcGFzdGUoIkhQViIsIG15Yl92c19ocHYkaHB2X3Bvc2l0aXZlKQpwMSA9IGdncGxvdChteWJfdnNfaHB2LGFlcyggeCA9IGhwdl9wb3NpdGl2ZSwgeSA9IE1ZQiwsIGZpbGw9aHB2X3Bvc2l0aXZlKSkrIAogICAgZ2VvbV92aW9saW4odHJpbT1GQUxTRSkgKyB0aGVtZV9taW5pbWFsKCkrCiAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoIkhQViBwb3NpdGl2ZSIsIkhQViBuZWdhdGl2ZSIpKSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PW1heCh4KSoxLjIsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihnZW5lKSIpK2dndGl0bGUoZ2VuZSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0uMSwgb3V0bGllci5zaGFwZT1OQSkgCgoKcHJpbnRfdGFiKHAxLHRpdGxlID0gZ2VuZSkKCmBgYAoKYGBge3J9Cm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gU0NDNV9jYW5jZXIsIHZhcnMgPSBjKCJIUFZfcmVhZHMiLCAiTVlCX3Bvc2l0aXZlIikpCgpwMiA9IGdncGxvdChteWJfdnNfaHB2LGFlcyggeCA9IE1ZQl9wb3NpdGl2ZSwgeSA9SFBWX3JlYWRzICwgIGZpbGw9TVlCX3Bvc2l0aXZlKSkrIAogICAgZ2VvbV92aW9saW4odHJpbT1GQUxTRSkgKyB0aGVtZV9taW5pbWFsKCkrCiAgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoInBvc2l0aXZlIiwibmVnYXRpdmUiKSkpKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIGRhdGEuZnJhbWUoeT1tYXgoeCkqMS4yLCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikrCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4xLCBvdXRsaWVyLnNoYXBlPU5BKSAKCgpwcmludF90YWIocDIsdGl0bGUgPSBnZW5lKQoKYGBgCgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9CnAxK3AyICtwbHQKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3N0YXRzcGxvdCkKZGYgID0gRmV0Y2hEYXRhKG9iamVjdCA9IFNDQzVfY2FuY2VyLHZhcnMgPSBjKCJocHZfcG9zaXRpdmUiLCJNWUJfcG9zaXRpdmUiKSkgJT4lIGRyb3BsZXZlbHMoKSAKdGVzdCA9IGZpc2hlci50ZXN0KHRhYmxlKGRmKSkKcGx0ID0gZ2diYXJzdGF0cygKICBkZiwKICBNWUJfcG9zaXRpdmUsCiAgaHB2X3Bvc2l0aXZlLAogIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwKICBzdWJ0aXRsZSA9IHBhc3RlMCgiRmlzaGVyJ3MgZXhhY3QgdGVzdCIsICIsIHAtdmFsdWUgPSAiLAogICAgICAgICAgICAgICAgICAgIHJvdW5kKHRlc3QkcC52YWx1ZSwgMTMpKQopCgpwcmludF90YWIocGx0ID0gcGx0LHRpdGxlID0gImZpc2hlciIpCmBgYAoKCgoKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0PgoK