1. load libraries

2. Load Seurat Object


#Load Seurat Object merged from cell lines and a control(PBMC) after filtration
SS_All_samples_Merged <- load("/home/bioinfo/Documents/1-SS-STeps/0-imp_OBJ_SS/All_Normal-PBMC_Abnormal-cellLines_T_cells_Merged_Annotated_UMAP_on_Clusters_to_USE.Robj")

All_samples_Merged
An object of class Seurat 
62625 features across 46976 samples within 6 assays 
Active assay: SCT (25901 features, 3000 variable features)
 3 layers present: counts, data, scale.data
 5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 4 dimensional reductions calculated: pca, umap, integrated_dr, ref.umap

3. QC


Idents(All_samples_Merged) <- "cell_line"
VlnPlot(All_samples_Merged, features = c("nFeature_RNA", 
                                    "nCount_RNA", 
                                    "percent.mito"), 
                                      ncol = 3)


VlnPlot(All_samples_Merged, features = c("nFeature_RNA", 
                                         "nCount_RNA", 
                                         "percent.mt",
                                         "percent.rb"), 
                            ncol = 4, pt.size = 0.1) & 
              theme(plot.title = element_text(size=10))


FeatureScatter(All_samples_Merged, 
               feature1 = "nCount_RNA", 
               feature2 = "nFeature_RNA") +
  geom_smooth(method = 'lm')

##FeatureScatter is typically used to visualize feature-feature relationships ##for anything calculated by the object, ##i.e. columns in object metadata, PC scores etc.


FeatureScatter(All_samples_Merged, 
               feature1 = "nCount_RNA", 
               feature2 = "percent.mito")+
  geom_smooth(method = 'lm')


FeatureScatter(All_samples_Merged, 
               feature1 = "nCount_RNA", 
               feature2 = "nFeature_RNA")+
  geom_smooth(method = 'lm')

4. Perform PCA

5. Perform PCA TEST




# TEST-1
# given that the output of RunPCA is "pca"
# replace "so" by the name of your seurat object

pct <- All_samples_Merged[["pca"]]@stdev / sum(All_samples_Merged[["pca"]]@stdev) * 100
cumu <- cumsum(pct) # Calculate cumulative percents for each PC
# Determine the difference between variation of PC and subsequent PC
co2 <- sort(which((pct[-length(pct)] - pct[-1]) > 0.1), decreasing = T)[1] + 1
# last point where change of % of variation is more than 0.1%. -> co2
co2
[1] 13
# TEST-2
# get significant PCs
stdv <- All_samples_Merged[["pca"]]@stdev
sum.stdv <- sum(All_samples_Merged[["pca"]]@stdev)
percent.stdv <- (stdv / sum.stdv) * 100
cumulative <- cumsum(percent.stdv)
co1 <- which(cumulative > 90 & percent.stdv < 5)[1]
co2 <- sort(which((percent.stdv[1:length(percent.stdv) - 1] - 
                       percent.stdv[2:length(percent.stdv)]) > 0.1), 
              decreasing = T)[1] + 1
min.pc <- min(co1, co2)
min.pc
[1] 13
# Create a dataframe with values
plot_df <- data.frame(pct = percent.stdv, 
           cumu = cumulative, 
           rank = 1:length(percent.stdv))

# Elbow plot to visualize 
  ggplot(plot_df, aes(cumulative, percent.stdv, label = rank, color = rank > min.pc)) + 
  geom_text() + 
  geom_vline(xintercept = 90, color = "grey") + 
  geom_hline(yintercept = min(percent.stdv[percent.stdv > 5]), color = "grey") +
  theme_bw()

NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA

6. Harmony TEST


P1 <- DimPlot(object = All_samples_Merged, group.by = "cell_line", label = T, label.box = T) + 
  labs(title = 'Colored by cellline')
P1



P2 <- DimPlot(object = All_samples_Merged, group.by = "predicted.celltype.l2") + 
  labs(title = 'Colored by celltype')
P2



P3 <- DimPlot(object = All_samples_Merged, group.by = "cell_line", reduction = "pca") + 
  labs(title = 'Colored by cellline')
P3



P4 <- DimPlot(object = All_samples_Merged, group.by = "predicted.celltype.l2", reduction = "pca") + 
  labs(title = 'Colored by celltype')
P4


cowplot::plot_grid(P1, P2, P3, P4, nrow = 2)


cell_distribution_table <- table(All_samples_Merged$predicted.celltype.l2, All_samples_Merged$seurat_clusters)

cell_distribution_df <- as.data.frame.matrix(cell_distribution_table)


print(cell_distribution_df)


write.csv(cell_distribution_df, file = "test2.csv", row.names = TRUE)

6. Apply Harmony



All_samples_Merged_integrated <- RunHarmony(All_samples_Merged, "cell_line")
Transposing data matrix
Initializing state using k-means centroids initialization
Harmony 1/10
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Harmony 2/10
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Harmony converged after 2 iterations
# Do UMAP and clustering using ** Harmony embeddings instead of PCA **
All_samples_Merged_integrated <- All_samples_Merged_integrated %>%
   RunUMAP(reduction = 'harmony', dims = 1:13) %>%
   FindNeighbors(reduction = "harmony", dims = 1:13) %>%
   FindClusters(resolution = 0.5)
17:01:56 UMAP embedding parameters a = 0.9922 b = 1.112
17:01:56 Read 46976 rows and found 13 numeric columns
17:01:56 Using Annoy for neighbor search, n_neighbors = 30
17:01:56 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
17:01:59 Writing NN index file to temp file /tmp/RtmplSHSp6/file180302c135d88
17:01:59 Searching Annoy index using 1 thread, search_k = 3000
17:02:11 Annoy recall = 100%
17:02:12 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
17:02:14 Initializing from normalized Laplacian + noise (using RSpectra)
17:02:15 Commencing optimization for 200 epochs, with 1955114 positive edges
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
17:02:30 Optimization finished
Computing nearest neighbor graph
Computing SNN
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 46976
Number of edges: 1404500

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8881
Number of communities: 12
Elapsed time: 11 seconds

DimPlot(object = All_samples_Merged_integrated, group.by = "predicted.celltype.l2", label = T, label.box = T, repel = T, reduction = "umap")


DimPlot(object = All_samples_Merged_integrated, group.by = "predicted.celltype.l2", label = T, label.box = T, repel = T, reduction = "harmony")


DimPlot(object = All_samples_Merged_integrated, group.by = "predicted.celltype.l2", label = T, label.box = T, repel = T, reduction = "integrated_dr")


DimPlot(object = All_samples_Merged_integrated, group.by = "predicted.celltype.l2", label = T, label.box = T, repel = T, reduction = "pca")


DimPlot(object = All_samples_Merged_integrated, group.by = "predicted.celltype.l2", label = T, label.box = T, repel = T, reduction = "ref.umap")



DimPlot(object = All_samples_Merged_integrated, group.by = "cell_line", label = T, label.box = T, repel = T, reduction = "umap")


DimPlot(object = All_samples_Merged_integrated, group.by = "seurat_clusters", label = T, label.box = T, repel = T, reduction = "umap")

7. Cell Distribution



cell_distribution_table <- table(All_samples_Merged_integrated$cell_line, All_samples_Merged_integrated$seurat_clusters)

cell_distribution_df <- as.data.frame.matrix(cell_distribution_table)


print(cell_distribution_df)


write.csv(cell_distribution_df, file = "15-2-integration_table_HARMONY-TEST1.csv", row.names = TRUE)


cell_distribution_table <- table(All_samples_Merged_integrated$predicted.celltype.l2, All_samples_Merged_integrated$seurat_clusters)

cell_distribution_df <- as.data.frame.matrix(cell_distribution_table)


print(cell_distribution_df)


write.csv(cell_distribution_df, file = "15-2-integration_table_HARMONY-TEST1_annotationbased.csv", row.names = TRUE)


cell_distribution_table <- table(All_samples_Merged_integrated$predicted.celltype.l1, All_samples_Merged_integrated$seurat_clusters)

cell_distribution_df <- as.data.frame.matrix(cell_distribution_table)


print(cell_distribution_df)


write.csv(cell_distribution_df, file = "15-2-integration_table_HARMONY-TEST1_annotationbased_l1.csv", row.names = TRUE)

cell_distribution_table <- table(All_samples_Merged_integrated$predicted.celltype.l2, All_samples_Merged_integrated$cell_line)

cell_distribution_df <- as.data.frame.matrix(cell_distribution_table)


print(cell_distribution_df)


write.csv(cell_distribution_df, file = "15-2-integration_table_HARMONY-TEST1_annotationbased_cellline.csv", row.names = TRUE)

Save the Seurat object as an Robj file———————————————————————-



# save
#save(All_samples_Merged_integrated,file = "15-2_All_samples_Merged_integrated.Robj")

```

LS0tCnRpdGxlOiAiUEMgdGVzdCBhbmQgaGFybW9ueSBpbnRlZ3JhdGlvbiBvbiBTQ1QiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogIjIwMjQtMDYtMDUiCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogZGFya2x5Ci0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShBemltdXRoKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeSh0aW55dGV4KQoKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZGl0dG9TZXEpCmxpYnJhcnkoZ2dyZXBlbCkKI2xpYnJhcnkoZ2d0cmVlKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KHBsb3RseSkgICMgM0QgcGxvdApsaWJyYXJ5KFNldXJhdCkgICMgSWRlbnRzKCkKbGlicmFyeShTZXVyYXREaXNrKSAgIyBTYXZlSDVTZXVyYXQoKQpsaWJyYXJ5KHRpYmJsZSkgICMgcm93bm5hbWVzX3RvX2NvbHVtbgpsaWJyYXJ5KGhhcm1vbnkpICMgUnVuSGFybW9ueSgpCiNvcHRpb25zKG1jLmNvcmVzID0gZGV0ZWN0Q29yZXMoKSAtIDEpCgoKCmBgYAoKCiMgMi4gTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7ciBsb2FkX3NldXJhdH0KCiNMb2FkIFNldXJhdCBPYmplY3QgbWVyZ2VkIGZyb20gY2VsbCBsaW5lcyBhbmQgYSBjb250cm9sKFBCTUMpIGFmdGVyIGZpbHRyYXRpb24KU1NfQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIGxvYWQoIi9ob21lL2Jpb2luZm8vRG9jdW1lbnRzLzEtU1MtU1RlcHMvMC1pbXBfT0JKX1NTL0FsbF9Ob3JtYWwtUEJNQ19BYm5vcm1hbC1jZWxsTGluZXNfVF9jZWxsc19NZXJnZWRfQW5ub3RhdGVkX1VNQVBfb25fQ2x1c3RlcnNfdG9fVVNFLlJvYmoiKQoKQWxsX3NhbXBsZXNfTWVyZ2VkCmBgYAojIDMuIFFDCmBgYHtyIFFDLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJjZWxsX2xpbmUiClZsblBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudC5taXRvIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKQoKVmxuUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5Db3VudF9STkEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudC5tdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBlcmNlbnQucmIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNCwgcHQuc2l6ZSA9IDAuMSkgJiAKICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQoKRmVhdHVyZVNjYXR0ZXIoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJuRmVhdHVyZV9STkEiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykKCmBgYAoKIyNGZWF0dXJlU2NhdHRlciBpcyB0eXBpY2FsbHkgdXNlZCB0byB2aXN1YWxpemUgZmVhdHVyZS1mZWF0dXJlIHJlbGF0aW9uc2hpcHMKIyNmb3IgYW55dGhpbmcgY2FsY3VsYXRlZCBieSB0aGUgb2JqZWN0LCAKIyNpLmUuIGNvbHVtbnMgaW4gb2JqZWN0IG1ldGFkYXRhLCBQQyBzY29yZXMgZXRjLgoKYGBge3IgRkMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRmVhdHVyZVNjYXR0ZXIoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJwZXJjZW50Lm1pdG8iKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKRmVhdHVyZVNjYXR0ZXIoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJuRmVhdHVyZV9STkEiKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKYGBgCiMgNC4gUGVyZm9ybSBQQ0EKYGBge3IgUENBLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgpFbGJvd1Bsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBuZGltcyA9IDUwKQoKCmBgYAoKIyA1LiBQZXJmb3JtIFBDQSBURVNUCmBgYHtyIFBDQS1URVNUMiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKCiMgVEVTVC0xCiMgZ2l2ZW4gdGhhdCB0aGUgb3V0cHV0IG9mIFJ1blBDQSBpcyAicGNhIgojIHJlcGxhY2UgInNvIiBieSB0aGUgbmFtZSBvZiB5b3VyIHNldXJhdCBvYmplY3QKCnBjdCA8LSBBbGxfc2FtcGxlc19NZXJnZWRbWyJwY2EiXV1Ac3RkZXYgLyBzdW0oQWxsX3NhbXBsZXNfTWVyZ2VkW1sicGNhIl1dQHN0ZGV2KSAqIDEwMApjdW11IDwtIGN1bXN1bShwY3QpICMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcGVyY2VudHMgZm9yIGVhY2ggUEMKIyBEZXRlcm1pbmUgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB2YXJpYXRpb24gb2YgUEMgYW5kIHN1YnNlcXVlbnQgUEMKY28yIDwtIHNvcnQod2hpY2goKHBjdFstbGVuZ3RoKHBjdCldIC0gcGN0Wy0xXSkgPiAwLjEpLCBkZWNyZWFzaW5nID0gVClbMV0gKyAxCiMgbGFzdCBwb2ludCB3aGVyZSBjaGFuZ2Ugb2YgJSBvZiB2YXJpYXRpb24gaXMgbW9yZSB0aGFuIDAuMSUuIC0+IGNvMgpjbzIKCiMgVEVTVC0yCiMgZ2V0IHNpZ25pZmljYW50IFBDcwpzdGR2IDwtIEFsbF9zYW1wbGVzX01lcmdlZFtbInBjYSJdXUBzdGRldgpzdW0uc3RkdiA8LSBzdW0oQWxsX3NhbXBsZXNfTWVyZ2VkW1sicGNhIl1dQHN0ZGV2KQpwZXJjZW50LnN0ZHYgPC0gKHN0ZHYgLyBzdW0uc3RkdikgKiAxMDAKY3VtdWxhdGl2ZSA8LSBjdW1zdW0ocGVyY2VudC5zdGR2KQpjbzEgPC0gd2hpY2goY3VtdWxhdGl2ZSA+IDkwICYgcGVyY2VudC5zdGR2IDwgNSlbMV0KY28yIDwtIHNvcnQod2hpY2goKHBlcmNlbnQuc3RkdlsxOmxlbmd0aChwZXJjZW50LnN0ZHYpIC0gMV0gLSAKICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50LnN0ZHZbMjpsZW5ndGgocGVyY2VudC5zdGR2KV0pID4gMC4xKSwgCiAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFQpWzFdICsgMQptaW4ucGMgPC0gbWluKGNvMSwgY28yKQptaW4ucGMKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdmFsdWVzCnBsb3RfZGYgPC0gZGF0YS5mcmFtZShwY3QgPSBwZXJjZW50LnN0ZHYsIAogICAgICAgICAgIGN1bXUgPSBjdW11bGF0aXZlLCAKICAgICAgICAgICByYW5rID0gMTpsZW5ndGgocGVyY2VudC5zdGR2KSkKCiMgRWxib3cgcGxvdCB0byB2aXN1YWxpemUgCiAgZ2dwbG90KHBsb3RfZGYsIGFlcyhjdW11bGF0aXZlLCBwZXJjZW50LnN0ZHYsIGxhYmVsID0gcmFuaywgY29sb3IgPSByYW5rID4gbWluLnBjKSkgKyAKICBnZW9tX3RleHQoKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwLCBjb2xvciA9ICJncmV5IikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtaW4ocGVyY2VudC5zdGR2W3BlcmNlbnQuc3RkdiA+IDVdKSwgY29sb3IgPSAiZ3JleSIpICsKICB0aGVtZV9idygpCgogIAoKCgoKCgoKCgoKCmBgYAoKCgojIDYuIEhhcm1vbnkgVEVTVApgYGB7ciBQQ0EtVEVTVCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpQMSA8LSBEaW1QbG90KG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKSArIAogIGxhYnModGl0bGUgPSAnQ29sb3JlZCBieSBjZWxsbGluZScpClAxCgoKUDIgPC0gRGltUGxvdChvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIpICsgCiAgbGFicyh0aXRsZSA9ICdDb2xvcmVkIGJ5IGNlbGx0eXBlJykKUDIKCgpQMyA8LSBEaW1QbG90KG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgcmVkdWN0aW9uID0gInBjYSIpICsgCiAgbGFicyh0aXRsZSA9ICdDb2xvcmVkIGJ5IGNlbGxsaW5lJykKUDMKCgpQNCA8LSBEaW1QbG90KG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgcmVkdWN0aW9uID0gInBjYSIpICsgCiAgbGFicyh0aXRsZSA9ICdDb2xvcmVkIGJ5IGNlbGx0eXBlJykKUDQKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChQMSwgUDIsIFAzLCBQNCwgbnJvdyA9IDIpCgpjZWxsX2Rpc3RyaWJ1dGlvbl90YWJsZSA8LSB0YWJsZShBbGxfc2FtcGxlc19NZXJnZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBBbGxfc2FtcGxlc19NZXJnZWQkc2V1cmF0X2NsdXN0ZXJzKQoKY2VsbF9kaXN0cmlidXRpb25fZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgoY2VsbF9kaXN0cmlidXRpb25fdGFibGUpCgoKcHJpbnQoY2VsbF9kaXN0cmlidXRpb25fZGYpCgoKd3JpdGUuY3N2KGNlbGxfZGlzdHJpYnV0aW9uX2RmLCBmaWxlID0gInRlc3QyLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCgoKYGBgCiMgNi4gQXBwbHkgSGFybW9ueQpgYGB7ciBDMSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQgPC0gUnVuSGFybW9ueShBbGxfc2FtcGxlc19NZXJnZWQsICJjZWxsX2xpbmUiKQojIERvIFVNQVAgYW5kIGNsdXN0ZXJpbmcgdXNpbmcgKiogSGFybW9ueSBlbWJlZGRpbmdzIGluc3RlYWQgb2YgUENBICoqCkFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkIDwtIEFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkICU+JQogICBSdW5VTUFQKHJlZHVjdGlvbiA9ICdoYXJtb255JywgZGltcyA9IDE6MTMpICU+JQogICBGaW5kTmVpZ2hib3JzKHJlZHVjdGlvbiA9ICJoYXJtb255IiwgZGltcyA9IDE6MTMpICU+JQogICBGaW5kQ2x1c3RlcnMocmVzb2x1dGlvbiA9IDAuNSkKYGBgCgoKYGBge3IgQzIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRGltUGxvdChvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikKCkRpbVBsb3Qob2JqZWN0ID0gQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBULCByZWR1Y3Rpb24gPSAiaGFybW9ueSIpCgpEaW1QbG90KG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQsIHJlcGVsID0gVCwgcmVkdWN0aW9uID0gImludGVncmF0ZWRfZHIiKQoKRGltUGxvdChvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQsIHJlZHVjdGlvbiA9ICJwY2EiKQoKRGltUGxvdChvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQsIHJlZHVjdGlvbiA9ICJyZWYudW1hcCIpCgoKRGltUGxvdChvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikKCkRpbVBsb3Qob2JqZWN0ID0gQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBULCByZWR1Y3Rpb24gPSAidW1hcCIpCgpgYGAKCiMgNy4gQ2VsbCBEaXN0cmlidXRpb24KYGBge3IgY2VsbER9CgoKY2VsbF9kaXN0cmlidXRpb25fdGFibGUgPC0gdGFibGUoQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQkY2VsbF9saW5lLCBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpCgpjZWxsX2Rpc3RyaWJ1dGlvbl9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeChjZWxsX2Rpc3RyaWJ1dGlvbl90YWJsZSkKCgpwcmludChjZWxsX2Rpc3RyaWJ1dGlvbl9kZikKCgp3cml0ZS5jc3YoY2VsbF9kaXN0cmlidXRpb25fZGYsIGZpbGUgPSAiMTUtMi1pbnRlZ3JhdGlvbl90YWJsZV9IQVJNT05ZLVRFU1QxLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCgoKY2VsbF9kaXN0cmlidXRpb25fdGFibGUgPC0gdGFibGUoQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBBbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpCgpjZWxsX2Rpc3RyaWJ1dGlvbl9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeChjZWxsX2Rpc3RyaWJ1dGlvbl90YWJsZSkKCgpwcmludChjZWxsX2Rpc3RyaWJ1dGlvbl9kZikKCgp3cml0ZS5jc3YoY2VsbF9kaXN0cmlidXRpb25fZGYsIGZpbGUgPSAiMTUtMi1pbnRlZ3JhdGlvbl90YWJsZV9IQVJNT05ZLVRFU1QxX2Fubm90YXRpb25iYXNlZC5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQoKCmNlbGxfZGlzdHJpYnV0aW9uX3RhYmxlIDwtIHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMSwgQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQkc2V1cmF0X2NsdXN0ZXJzKQoKY2VsbF9kaXN0cmlidXRpb25fZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgoY2VsbF9kaXN0cmlidXRpb25fdGFibGUpCgoKcHJpbnQoY2VsbF9kaXN0cmlidXRpb25fZGYpCgoKd3JpdGUuY3N2KGNlbGxfZGlzdHJpYnV0aW9uX2RmLCBmaWxlID0gIjE1LTItaW50ZWdyYXRpb25fdGFibGVfSEFSTU9OWS1URVNUMV9hbm5vdGF0aW9uYmFzZWRfbDEuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkKCmNlbGxfZGlzdHJpYnV0aW9uX3RhYmxlIDwtIHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwgQWxsX3NhbXBsZXNfTWVyZ2VkX2ludGVncmF0ZWQkY2VsbF9saW5lKQoKY2VsbF9kaXN0cmlidXRpb25fZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgoY2VsbF9kaXN0cmlidXRpb25fdGFibGUpCgoKcHJpbnQoY2VsbF9kaXN0cmlidXRpb25fZGYpCgoKd3JpdGUuY3N2KGNlbGxfZGlzdHJpYnV0aW9uX2RmLCBmaWxlID0gIjE1LTItaW50ZWdyYXRpb25fdGFibGVfSEFSTU9OWS1URVNUMV9hbm5vdGF0aW9uYmFzZWRfY2VsbGxpbmUuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkKCgpgYGAKCiMgU2F2ZSB0aGUgU2V1cmF0IG9iamVjdCBhcyBhbiBSb2JqIGZpbGUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYHtyIHNhdmVSRFN9CgoKIyBzYXZlCiNzYXZlKEFsbF9zYW1wbGVzX01lcmdlZF9pbnRlZ3JhdGVkLGZpbGUgPSAiMTUtMl9BbGxfc2FtcGxlc19NZXJnZWRfaW50ZWdyYXRlZC5Sb2JqIikKCmBgYAoKYGBgCgoKCg==