1 Functions

source_from_github(repositoy = "cNMF_functions",version = "0.3.87",script_name = "cnmf_function_Harmony.R")
ℹ SHA-1 hash of file is e4b1a5e086d635d32ada87c261558383601de712
source_from_github(repositoy = "HMSC_functions",version = "0.1.14",script_name = "functions.R")
ℹ SHA-1 hash of file is 9ec21e2e1fdc9a7b465400b3111b50804a136cf3

2 Data

acc1_cancer_cells = readRDS("./Data/acc1_cancer_cells_15KnCount_V4.RDS")

3 Original UMAP

DimPlot(object = acc1_cancer_cells,pt.size = 2)


comparisons <- list(c("ACC.plate2", "ACC1.P3"))


plt2 = VlnPlot(object = acc1_cancer_cells,group.by= "orig.ident",features = "nFeature_RNA")+ stat_compare_means(comparisons = comparisons, label = "p.signif",label.y = 10000)

plt1+plt2
Warning: Removed 3 rows containing missing values (geom_signif).

4 Seurat intergration

acc1_cancer_cells.list <- SplitObject(acc1_cancer_cells, split.by = "plate")

# normalize and identify variable features for each dataset independently
acc1_cancer_cells.list <- lapply(X = acc1_cancer_cells.list, FUN = function(x) {
    # x <- NormalizeData(x)
    x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 1000)
})

# select features that are repeatedly variable across datasets for integration
features <- SelectIntegrationFeatures(object.list = acc1_cancer_cells.list,nfeatures = 1000)
acc.anchors <- FindIntegrationAnchors(object.list = acc1_cancer_cells.list, anchor.features = features,k.filter = 50)
acc.combined <- IntegrateData(anchorset = acc.anchors,k.weight = 50,features.to.integrate = rownames(acc1_cancer_cells),preserve.order = F)
Merging dataset 1 into 2
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
DefaultAssay(acc.combined) <- "integrated"
acc.combined <- ScaleData(acc.combined, verbose = FALSE)
acc.combined <- RunPCA(acc.combined, npcs = 30, verbose = FALSE)
ElbowPlot(acc.combined)

acc.combined <- RunUMAP(acc.combined, reduction = "pca", dims = 1:10)
acc.combined <- FindNeighbors(acc.combined, reduction = "pca", dims = 1:10)
acc.combined <- FindClusters(acc.combined, resolution = 0.5)

5 UMAPS

DimPlot(acc.combined, reduction = "umap", group.by = "plate")

6 clusters DEG

acc_deg <- FindMarkers(acc.combined, ident.1 = "0",ident.2 = "1",features = VariableFeatures(acc.combined),densify = T)
enrichment_analysis(acc_deg,background = VariableFeatures(acc.combined),fdr_Cutoff = 0.01,ident.1 = "0",ident.2 = "1",show_by = 1)

7 MYB-HPV

myb_vs_hpv = FetchData(object = acc.combined,vars = c("hpv33_positive","MYB"))
myb_vs_hpv $hpv33_positive = as.character(myb_vs_hpv $hpv33_positive )

ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "MYB",
          palette = "jco",
          add = "jitter")+ stat_compare_means(method = "t.test",comparisons = list(c("positive","negative")))+ stat_summary(fun.data = function(x) data.frame(y=12, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(MYB)")

8 HPV-MYB per plate

plate_1 = subset(acc.combined,subset = plate == "ACC.plate2")
myb_vs_hpv = FetchData(object = plate_1,vars = c("hpv33_positive","MYB"))
myb_vs_hpv $hpv33_positive = as.character(myb_vs_hpv $hpv33_positive )

p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "MYB",
          palette = "jco",
          add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("positive","negative")))+ stat_summary(fun.data = function(x) data.frame(y=15, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(MYB)")+ggtitle("ACC.plate2")

plate_2 = subset(acc.combined,subset = plate == "ACC1.P3")
myb_vs_hpv = FetchData(object = plate_2,vars = c("hpv33_positive","MYB"))
myb_vs_hpv $hpv33_positive = as.character(myb_vs_hpv $hpv33_positive )

p+ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "MYB",
          palette = "jco",
          add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("positive","negative")))+ stat_summary(fun.data = function(x) data.frame(y=15, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(MYB)")+ggtitle("ACC1.P3")

8.1 myo-lum score

original_myo_genes = c( "TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI" )
calculate_score(dataset = acc.combined,myo_genes = original_myo_genes,lum_genes = original_lum_genes)
correlation of lum score and myo score: -0.07
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

myo_protein_markers = c("CNN1", "TP63","ACTA2")
top_myo  = top_correlated(dataset = acc.combined, genes = myo_protein_markers,threshold = 0.35)
1
[1] 1
print("Number of genes = " %>% paste(length(top_myo)))
[1] "Number of genes =  15"
message("Names of genes:")
Names of genes:
top_myo %>% head(30)
 [1] "COL16A1"     "RP1-39G22.4" "CD200"       "MYLK"        "TP63"        "KCNMB1"      "ADAMTS2"     "CLIC3"       "SNCG"        "ACTA2"      
[11] "TAGLN"       "MIR7974"     "CNN1"        "MYL9"        "POM121L9P"  
message("Genes that also apeared in the original score:")
Genes that also apeared in the original score:
base::intersect(top_myo,original_myo_genes) 
[1] "MYLK"  "TP63"  "ACTA2" "TAGLN"
lum_protein_markers = c("KIT")
top_lum  = top_correlated(dataset = acc.combined, genes = lum_protein_markers,threshold = 0.35)
Warning in cor(expression %>% t(), markers_average) :
  the standard deviation is zero
print("Number of genes = " %>% paste(length(top_lum)))
[1] "Number of genes =  8"
message("Names of genes:")
Names of genes:
top_lum %>% head(30)
[1] "MAP2"    "KIT"     "GLRB"    "SLC29A1" "SASH1"   "ALDH3B2" "CCND1"   "NDFIP2" 
message("Genes that also apeared in the original score:")
Genes that also apeared in the original score:
base::intersect(top_lum,original_lum_genes) 
[1] "KIT"
cd_features <- list(c("MYLK" ,"TP63" , "ACTA2" ,"TAGLN","CNN1", "TP63","ACTA2"))
pbmc_small <- AddModuleScore(
  object = acc.combined,
  features = cd_features,
  ctrl = 5,
  name = 'myo_Features'
)

FeaturePlot(object = pbmc_small,features = "myo_Features1")

cd_features <- list(top_lum)
pbmc_small <- AddModuleScore(
  object = pbmc_small,
  features = cd_features,
  ctrl = 5,
  name = 'lum_Features'
)

FeaturePlot(object = pbmc_small,features = "lum_Features1")

cor(pbmc_small$lum_Features1,pbmc_small$myo_Features1)
[1] -0.118548

9 Harmony + cNMF

from cnmf import cNMF
ModuleNotFoundError: No module named 'cnmf'
selected_k = 3
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm

10 Harmony results

# Make metagene names
for (i in 1:ncol(all_metagenes)) {
  colnames(all_metagenes)[i] = "metagene." %>% paste0(i)
}

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}
print_tab(plt = 
            FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression")

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  lung_corr_nonneg = AddMetaData(object = lung_corr_nonneg,metadata = metage_metadata)
}
print_tab(plt = 
            FeaturePlot(object = lung_corr_nonneg,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression")
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiY05NRl9mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4zLjg3IixzY3JpcHRfbmFtZSA9ICJjbm1mX2Z1bmN0aW9uX0hhcm1vbnkuUiIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiSE1TQ19mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4xLjE0IixzY3JpcHRfbmFtZSA9ICJmdW5jdGlvbnMuUiIpCmBgYAoKIyBEYXRhCgpgYGB7cn0KYWNjMV9jYW5jZXJfY2VsbHMgPSByZWFkUkRTKCIuL0RhdGEvYWNjMV9jYW5jZXJfY2VsbHNfMTVLbkNvdW50X1Y0LlJEUyIpCmBgYAoKCgojIE9yaWdpbmFsIFVNQVAKYGBge3J9CkRpbVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMscHQuc2l6ZSA9IDIpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9Cgpjb21wYXJpc29ucyA8LSBsaXN0KGMoIkFDQy5wbGF0ZTIiLCAiQUNDMS5QMyIpKQoKCnBsdDIgPSBWbG5QbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGdyb3VwLmJ5PSAib3JpZy5pZGVudCIsZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIikrIHN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9IGNvbXBhcmlzb25zLCBsYWJlbCA9ICJwLnNpZ25pZiIsbGFiZWwueSA9IDEwMDAwKQoKcGx0MStwbHQyCmBgYAoKIyBTZXVyYXQgaW50ZXJncmF0aW9uCmBgYHtyfQphY2MxX2NhbmNlcl9jZWxscy5saXN0IDwtIFNwbGl0T2JqZWN0KGFjYzFfY2FuY2VyX2NlbGxzLCBzcGxpdC5ieSA9ICJwbGF0ZSIpCgojIG5vcm1hbGl6ZSBhbmQgaWRlbnRpZnkgdmFyaWFibGUgZmVhdHVyZXMgZm9yIGVhY2ggZGF0YXNldCBpbmRlcGVuZGVudGx5CmFjYzFfY2FuY2VyX2NlbGxzLmxpc3QgPC0gbGFwcGx5KFggPSBhY2MxX2NhbmNlcl9jZWxscy5saXN0LCBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAjIHggPC0gTm9ybWFsaXplRGF0YSh4KQogICAgeCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyh4LCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDEwMDApCn0pCgojIHNlbGVjdCBmZWF0dXJlcyB0aGF0IGFyZSByZXBlYXRlZGx5IHZhcmlhYmxlIGFjcm9zcyBkYXRhc2V0cyBmb3IgaW50ZWdyYXRpb24KZmVhdHVyZXMgPC0gU2VsZWN0SW50ZWdyYXRpb25GZWF0dXJlcyhvYmplY3QubGlzdCA9IGFjYzFfY2FuY2VyX2NlbGxzLmxpc3QsbmZlYXR1cmVzID0gMTAwMCkKYWNjLmFuY2hvcnMgPC0gRmluZEludGVncmF0aW9uQW5jaG9ycyhvYmplY3QubGlzdCA9IGFjYzFfY2FuY2VyX2NlbGxzLmxpc3QsIGFuY2hvci5mZWF0dXJlcyA9IGZlYXR1cmVzLGsuZmlsdGVyID0gNTApCgpgYGAKCmBgYHtyfQphY2MuY29tYmluZWQgPC0gSW50ZWdyYXRlRGF0YShhbmNob3JzZXQgPSBhY2MuYW5jaG9ycyxrLndlaWdodCA9IDUwLGZlYXR1cmVzLnRvLmludGVncmF0ZSA9IHJvd25hbWVzKGFjYzFfY2FuY2VyX2NlbGxzKSxwcmVzZXJ2ZS5vcmRlciA9IEYpCkRlZmF1bHRBc3NheShhY2MuY29tYmluZWQpIDwtICJpbnRlZ3JhdGVkIgoKYGBgCgpgYGB7cn0KYWNjLmNvbWJpbmVkIDwtIFNjYWxlRGF0YShhY2MuY29tYmluZWQsIHZlcmJvc2UgPSBGQUxTRSkKYWNjLmNvbWJpbmVkIDwtIFJ1blBDQShhY2MuY29tYmluZWQsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQpFbGJvd1Bsb3QoYWNjLmNvbWJpbmVkKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFjYy5jb21iaW5lZCA8LSBSdW5VTUFQKGFjYy5jb21iaW5lZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjEwKQphY2MuY29tYmluZWQgPC0gRmluZE5laWdoYm9ycyhhY2MuY29tYmluZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCkKYWNjLmNvbWJpbmVkIDwtIEZpbmRDbHVzdGVycyhhY2MuY29tYmluZWQsIHJlc29sdXRpb24gPSAwLjUpCmBgYAoKIyBVTUFQUwpgYGB7cn0KRGltUGxvdChhY2MuY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAicGxhdGUiKQpgYGAKIyBjbHVzdGVycyBERUcKYGBge3J9CmFjY19kZWcgPC0gRmluZE1hcmtlcnMoYWNjLmNvbWJpbmVkLCBpZGVudC4xID0gIjAiLGlkZW50LjIgPSAiMSIsZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFjYy5jb21iaW5lZCksZGVuc2lmeSA9IFQpCmBgYAoKYGBge3J9CmVucmljaG1lbnRfYW5hbHlzaXMoYWNjX2RlZyxiYWNrZ3JvdW5kID0gVmFyaWFibGVGZWF0dXJlcyhhY2MuY29tYmluZWQpLGZkcl9DdXRvZmYgPSAwLjAxLGlkZW50LjEgPSAiMCIsaWRlbnQuMiA9ICIxIixzaG93X2J5ID0gMSkKYGBgCgoKCgojIE1ZQi1IUFYKYGBge3J9Cm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjLmNvbWJpbmVkLHZhcnMgPSBjKCJocHYzM19wb3NpdGl2ZSIsIk1ZQiIpKQpteWJfdnNfaHB2ICRocHYzM19wb3NpdGl2ZSA9IGFzLmNoYXJhY3RlcihteWJfdnNfaHB2ICRocHYzM19wb3NpdGl2ZSApCgpnZ2JveHBsb3QobXliX3ZzX2hwdiwgeCA9ICJocHYzM19wb3NpdGl2ZSIsIHkgPSAiTVlCIiwKICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLGNvbXBhcmlzb25zID0gbGlzdChjKCJwb3NpdGl2ZSIsIm5lZ2F0aXZlIikpKSsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PTEyLCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikgK3lsYWIoImxvZzIoTVlCKSIpCgpgYGAKIyBIUFYtTVlCIHBlciBwbGF0ZQpgYGB7cn0KcGxhdGVfMSA9IHN1YnNldChhY2MuY29tYmluZWQsc3Vic2V0ID0gcGxhdGUgPT0gIkFDQy5wbGF0ZTIiKQpteWJfdnNfaHB2ID0gRmV0Y2hEYXRhKG9iamVjdCA9IHBsYXRlXzEsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIiwiTVlCIikpCm15Yl92c19ocHYgJGhwdjMzX3Bvc2l0aXZlID0gYXMuY2hhcmFjdGVyKG15Yl92c19ocHYgJGhwdjMzX3Bvc2l0aXZlICkKCnAgPSBnZ2JveHBsb3QobXliX3ZzX2hwdiwgeCA9ICJocHYzM19wb3NpdGl2ZSIsIHkgPSAiTVlCIiwKICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoInBvc2l0aXZlIiwibmVnYXRpdmUiKSkpKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBmdW5jdGlvbih4KSBkYXRhLmZyYW1lKHk9MTUsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihNWUIpIikrZ2d0aXRsZSgiQUNDLnBsYXRlMiIpCgpwbGF0ZV8yID0gc3Vic2V0KGFjYy5jb21iaW5lZCxzdWJzZXQgPSBwbGF0ZSA9PSAiQUNDMS5QMyIpCm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gcGxhdGVfMix2YXJzID0gYygiaHB2MzNfcG9zaXRpdmUiLCJNWUIiKSkKbXliX3ZzX2hwdiAkaHB2MzNfcG9zaXRpdmUgPSBhcy5jaGFyYWN0ZXIobXliX3ZzX2hwdiAkaHB2MzNfcG9zaXRpdmUgKQoKcCtnZ2JveHBsb3QobXliX3ZzX2hwdiwgeCA9ICJocHYzM19wb3NpdGl2ZSIsIHkgPSAiTVlCIiwKICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoInBvc2l0aXZlIiwibmVnYXRpdmUiKSkpKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBmdW5jdGlvbih4KSBkYXRhLmZyYW1lKHk9MTUsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihNWUIpIikrZ2d0aXRsZSgiQUNDMS5QMyIpCmBgYAoKIyMgbXlvLWx1bSBzY29yZQpgYGB7cn0Kb3JpZ2luYWxfbXlvX2dlbmVzID0gYyggIlRQNjMiLCAiVFA3MyIsICJDQVYxIiwgIkNESDMiLCAiS1JUNSIsICJLUlQxNCIsICJBQ1RBMiIsICJUQUdMTiIsICJNWUxLIiwgIkRLSzMiKQpvcmlnaW5hbF9sdW1fZ2VuZXMgPSBjKCJLSVQiLCAiRUhGIiwgIkVMRjUiLCAiS1JUNyIsICJDTEROMyIsICJDTERONCIsICJDRDI0IiwgIkxHQUxTMyIsICJMQ04yIiwgIlNMUEkiICkKYGBgCgoKYGBge3J9CmNhbGN1bGF0ZV9zY29yZShkYXRhc2V0ID0gYWNjLmNvbWJpbmVkLG15b19nZW5lcyA9IG9yaWdpbmFsX215b19nZW5lcyxsdW1fZ2VuZXMgPSBvcmlnaW5hbF9sdW1fZ2VuZXMpCmBgYApgYGB7ciB3YXJuaW5nPUZBTFNFLCBjb2xsYXBzZT1UfQpteW9fcHJvdGVpbl9tYXJrZXJzID0gYygiQ05OMSIsICJUUDYzIiwiQUNUQTIiKQp0b3BfbXlvICA9IHRvcF9jb3JyZWxhdGVkKGRhdGFzZXQgPSBhY2MuY29tYmluZWQsIGdlbmVzID0gbXlvX3Byb3RlaW5fbWFya2Vycyx0aHJlc2hvbGQgPSAwLjM1KQpwcmludCgiTnVtYmVyIG9mIGdlbmVzID0gIiAlPiUgcGFzdGUobGVuZ3RoKHRvcF9teW8pKSkKbWVzc2FnZSgiTmFtZXMgb2YgZ2VuZXM6IikKdG9wX215byAlPiUgaGVhZCgzMCkKbWVzc2FnZSgiR2VuZXMgdGhhdCBhbHNvIGFwZWFyZWQgaW4gdGhlIG9yaWdpbmFsIHNjb3JlOiIpCmJhc2U6OmludGVyc2VjdCh0b3BfbXlvLG9yaWdpbmFsX215b19nZW5lcykgCmBgYApgYGB7cn0KbHVtX3Byb3RlaW5fbWFya2VycyA9IGMoIktJVCIpCnRvcF9sdW0gID0gdG9wX2NvcnJlbGF0ZWQoZGF0YXNldCA9IGFjYy5jb21iaW5lZCwgZ2VuZXMgPSBsdW1fcHJvdGVpbl9tYXJrZXJzLHRocmVzaG9sZCA9IDAuMzUpCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgPSAiICU+JSBwYXN0ZShsZW5ndGgodG9wX2x1bSkpKQptZXNzYWdlKCJOYW1lcyBvZiBnZW5lczoiKQp0b3BfbHVtICU+JSBoZWFkKDMwKQptZXNzYWdlKCJHZW5lcyB0aGF0IGFsc28gYXBlYXJlZCBpbiB0aGUgb3JpZ2luYWwgc2NvcmU6IikKYmFzZTo6aW50ZXJzZWN0KHRvcF9sdW0sb3JpZ2luYWxfbHVtX2dlbmVzKSAKYGBgCmBgYHtyfQpjZF9mZWF0dXJlcyA8LSBsaXN0KGMoIk1ZTEsiICwiVFA2MyIgLCAiQUNUQTIiICwiVEFHTE4iLCJDTk4xIiwgIlRQNjMiLCJBQ1RBMiIpKQpwYm1jX3NtYWxsIDwtIEFkZE1vZHVsZVNjb3JlKAogIG9iamVjdCA9IGFjYy5jb21iaW5lZCwKICBmZWF0dXJlcyA9IGNkX2ZlYXR1cmVzLAogIGN0cmwgPSA1LAogIG5hbWUgPSAnbXlvX0ZlYXR1cmVzJwopCgpGZWF0dXJlUGxvdChvYmplY3QgPSBwYm1jX3NtYWxsLGZlYXR1cmVzID0gIm15b19GZWF0dXJlczEiKQpgYGAKCmBgYHtyfQpjZF9mZWF0dXJlcyA8LSBsaXN0KHRvcF9sdW0pCnBibWNfc21hbGwgPC0gQWRkTW9kdWxlU2NvcmUoCiAgb2JqZWN0ID0gcGJtY19zbWFsbCwKICBmZWF0dXJlcyA9IGNkX2ZlYXR1cmVzLAogIGN0cmwgPSA1LAogIG5hbWUgPSAnbHVtX0ZlYXR1cmVzJwopCgpGZWF0dXJlUGxvdChvYmplY3QgPSBwYm1jX3NtYWxsLGZlYXR1cmVzID0gImx1bV9GZWF0dXJlczEiKQpgYGAKIApgYGB7cn0KY29yKHBibWNfc21hbGwkbHVtX0ZlYXR1cmVzMSxwYm1jX3NtYWxsJG15b19GZWF0dXJlczEpCmBgYAoKYGBge3J9CmEgPSBtZXJnZShhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxQGFzc2F5cyRSTkFAZGF0YSxhY2MuY29tYmluZWRAYXNzYXlzJGludGVncmF0ZWRAZGF0YSkKYGBgCgoKCgoKIyBIYXJtb255ICsgY05NRgpgYGB7cHl0aG9ufQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKaW1wb3J0IHBpY2tsZQpuZmVhdHVyZXMgPSAiMksiCmYgPSBvcGVuKCcuL0RhdGEvY05NRi9ITVNDX2NOTUZfaGFybW9ueV8yS3ZhcmdlbmVzL2NubWZfb2JqLnBja2wnLCAncmInKQpjbm1mX29iaiA9IHBpY2tsZS5sb2FkKGYpCmYuY2xvc2UoKQpgYGAKCgpgYGB7cHl0aG9ufQpzZWxlY3RlZF9rID0gMwpkZW5zaXR5X3RocmVzaG9sZCA9IDAuMQpjbm1mX29iai5jb25zZW5zdXMoaz1zZWxlY3RlZF9rLCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCxzaG93X2NsdXN0ZXJpbmc9VHJ1ZSkKdXNhZ2Vfbm9ybSwgZ2VwX3Njb3JlcywgZ2VwX3RwbSwgdG9wZ2VuZXMgPSBjbm1mX29iai5sb2FkX3Jlc3VsdHMoSz1zZWxlY3RlZF9rLCBkZW5zaXR5X3RocmVzaG9sZD1kZW5zaXR5X3RocmVzaG9sZCkKYGBgCgpgYGB7cn0KZ2VwX3Njb3JlcyA9IHB5JGdlcF9zY29yZXMKZ2VwX3RwbSA9IHB5JGdlcF90cG0KYWxsX21ldGFnZW5lcz0gcHkkdXNhZ2Vfbm9ybQpgYGAKCiMgSGFybW9ueSByZXN1bHRzIHsudGFic2V0fQpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQojIE1ha2UgbWV0YWdlbmUgbmFtZXMKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldID0gIm1ldGFnZW5lLiIgJT4lIHBhc3RlMChpKQp9CgojYWRkIGVhY2ggbWV0YWdlbmUgdG8gbWV0YWRhdGEKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IGFsbF9tZXRhZ2VuZXMgJT4lIHNlbGVjdChpKQogIGFjYzFfY2FuY2VyX2NlbGxzID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLGNvbWJpbmUgPSBUKSwKICAgICAgICAgIHRpdGxlID0gIm1ldGFnZW5lcyBleHByZXNzaW9uIikKCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgc2VsZWN0KGkpCiAgbHVuZ19jb3JyX25vbm5lZyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGx1bmdfY29ycl9ub25uZWcsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBsdW5nX2NvcnJfbm9ubmVnLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcyksY29tYmluZSA9IFQpLAogICAgICAgICAgdGl0bGUgPSAibWV0YWdlbmVzIGV4cHJlc3Npb24iKQpgYGAKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9oeXBvdGhlcy5pcy9lbWJlZC5qcyIgYXN5bmM+PC9zY3JpcHQ+Cgo=