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("SS_All_Sample_Merged_Azimuth_ProjectTils_singleR_ANNOTATION_on_My_UMAP0.7_HPC.Robj")

All_samples_Merged
An object of class Seurat 
63193 features across 49193 samples within 6 assays 
Active assay: SCT (26469 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)


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. Normalize data



# # Apply SCTransform
# All_samples_Merged <- SCTransform(All_samples_Merged, verbose = TRUE)
#                                       

5. Perform PCA


# Variables_genes <- All_samples_Merged@assays$SCT@var.features
# 
# # Exclude genes starting with "HLA-" or "Xist"
# Variables_genes_after_exclusion <- Variables_genes[!grepl("^HLA-|^Xist", Variables_genes)]
# 
# 
# # These are now standard steps in the Seurat workflow for visualization and clustering
# All_samples_Merged <- RunPCA(All_samples_Merged,
#                         features = Variables_genes_after_exclusion,
#                         do.print = TRUE, 
#                         pcs.print = 1:5, 
#                         genes.print = 15)

# determine dimensionality of the data
ElbowPlot(All_samples_Merged)

NA
NA

5. Perform PCA TEST



library(ggplot2)
library(RColorBrewer)  

# Assuming you have 10 different cell lines, generating a color palette with 10 colors
cell_line_colors <- brewer.pal(10, "Set3")

# Assuming All_samples_Merged$cell_line is a factor or character vector containing cell line names
data <- as.data.frame(table(All_samples_Merged$cell_line))
colnames(data) <- c("cell_line", "nUMI")  # Change column name to nUMI

ncells <- ggplot(data, aes(x = cell_line, y = nUMI, fill = cell_line)) + 
  geom_col() +
  theme_classic() +
  geom_text(aes(label = nUMI), 
            position = position_dodge(width = 0.9), 
            vjust = -0.25) +
  scale_fill_manual(values = cell_line_colors) + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5)) +  # Adjust the title position
  ggtitle("Filtered cells per sample") +
  xlab("Cell lines") +  # Adjust x-axis label
  ylab("Frequency")    # Adjust y-axis label

print(ncells)



cell_lines <- FindVariableFeatures(All_samples_Merged,
                                   selection.method = "vst",  # default vst
                                   nfeatures = 2000,  # default 2000
                                   verbose = FALSE)

# view top variable genes
top40 <- head(VariableFeatures(cell_lines), 40)
top40
 [1] "CCL17"    "CXCL8"    "CXCL5"    "THBS1"    "S100A8"   "TYROBP"   "S100A9"   "CCL1"     "CXCL1"   
[10] "IL1B"     "SERPINB2" "PID1"     "CCL4"     "FTH1"     "CXCL3"    "MMP9"     "SOD2"     "CD14"    
[19] "C15orf48" "CCL3"     "EREG"     "IGKV3-20" "FCER1G"   "LYZ"      "CCL22"    "GNLY"     "PPBP"    
[28] "OASL"     "IGKV3-11" "IGLV2-14" "CXCL2"    "DOCK4"    "IFIT2"    "CD79A"    "VMO1"     "IGKV1-5" 
[37] "XCL1"     "GZMB"     "SPI1"     "IGHV4-34"
# plot variable features with labels
VarFeatPlot <- VariableFeaturePlot(cell_lines, cols = c("gray47","red"))
VarFeatPlotLabel <- LabelPoints(plot = VarFeatPlot, 
                    points = top40, repel = TRUE, fontface="italic", 
                    xnudge = 0, ynudge = 0, max.overlaps = 12)
VarFeatPlotLabel



df <- data.frame(row.names = rownames(cell_lines))
df$rsum <- rowSums(x = cell_lines, slot = "counts")
df$gene_name <- rownames(df)
df <- df[order(df$rsum,decreasing = TRUE),]
head(df, 10)

# 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] 20
# 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] 20
# 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

6. Clustering


# run umap
#celllines.nointergration <- RunUMAP(All_samples_Merged, dims = 1:min.pc, reduction = "pca")


# cluster
#celllines.nointergration <- FindNeighbors(object = celllines.nointergration, dims = 1:min.pc)   



# Determine the clusters for various resolutions                                
#celllines.nointergration <- FindClusters(object = celllines.nointergration, resolution = seq(0.1,1.2,by=0.1))



Idents(celllines.nointergration) <- "SCT_snn_res.0.7"
celllines.nointergration$seurat_clusters <- celllines.nointergration$SCT_snn_res.0.7



u1 <- DimPlot(object = celllines.nointergration, group.by = "seurat_clusters", label = TRUE, label.box = TRUE)

u1



u2 <- DimPlot(object = celllines.nointergration, 
         group.by = "seurat_clusters", 
         reduction = "umap", 
         label = TRUE, 
         label.box = TRUE, 
         split.by = "cell_line")

u2



u3 <- DimPlot(object = celllines.nointergration, 
         group.by = "seurat_clusters", 
         reduction = "umap", 
         label = TRUE, 
         label.box = TRUE, 
         split.by = "Patient_origin")

u3



u4 <- DimPlot(object = celllines.nointergration, 
         group.by = "seurat_clusters", 
         reduction = "umap", 
         label = TRUE, 
         label.box = TRUE, 
         split.by = "Treatments_analysis")

u4



u5 <- dittoDimPlot(object = celllines.nointergration,
             var = "seurat_clusters",
             reduction.use = "umap",
             do.label = TRUE,
             labels.highlight = FALSE)
u5




u6 <- dittoDimPlot(object = celllines.nointergration,
             var = "seurat_clusters",
             reduction.use = "umap",
             do.label = TRUE,
             split.by = "Treatments_analysis",
             labels.highlight = FALSE)
u6






#Integrate with harmony
# Run harmony to harmonize over samples 
# celllines.intergration <- RunHarmony(
#                               celllines.nointergration, 
#                               group.by.vars = "orig.ident", 
#                               assay.use = "SCT",
#                               reduction.use = "pca", 
#                               plot_convergence = TRUE)






#Find significant PCs
#First metric

# Determine percent of variation associated with each PC
stdv <- celllines.intergration[["pca"]]@stdev
sum.stdv <- sum(celllines.intergration[["pca"]]@stdev)
percent.stdv <- (stdv / sum.stdv) * 100

# Calculate cumulative percents for each PC
cumulative <- cumsum(percent.stdv)

# Determine which PC exhibits cumulative percent greater than 90% and
# and % variation associated with the PC as less than 5
co1 <- which(cumulative > 90 & percent.stdv < 5)[1]
co1
[1] 41
# Determine the difference between variation of PC and subsequent PC
co2 <- sort(which(
  (percent.stdv[1:length(percent.stdv) - 1] - 
     percent.stdv[2:length(percent.stdv)]) > 0.1), 
  decreasing = T)[1] + 1

# last point where change of % of variation is more than 0.1%.
co2
[1] 20
# Minimum of the two calculation
min.pc <- min(co1, co2)
min.pc
[1] 20
 
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()


# Run UMAP
# celllines.intergration <- RunUMAP(celllines.intergration,
#                            dims = 1:min.pc,
#                            reduction.use = "pca",
#                            n.components = 3) # set to 3 to use with VR


# Determine the K-nearest neighbor graph
#celllines.intergration <- FindNeighbors(object = celllines.intergration,dims = 1:min.pc)


# Determine the clusters for various resolutions                                
#cell_line.unannotated <- FindClusters(object = celllines.intergration,resolution = seq(0.1,1.2,by=0.1))



# Neurons after re-cluster
# UMAP
DefaultAssay(cell_line.unannotated) <- "SCT"
#neuron.unannotated <- NormalizeData(neuron.unannotated, verbose = FALSE)
cell_line.unannotated$seurat_clusters <- cell_line.unannotated$SCT_snn_res.0.7

u1 <- dittoDimPlot(object = cell_line.unannotated,
             var = "seurat_clusters",
             reduction.use = "umap",
             do.label = TRUE,
             labels.highlight = FALSE)
u1


u2 <- dittoDimPlot(object = cell_line.unannotated,
             var = "seurat_clusters",
             reduction.use = "umap",
             do.label = TRUE,
             split.by = "Treatments_analysis",
             labels.highlight = FALSE)
u2

NA
NA

# #Cluster tree
# cluster_colors <- c("gold","firebrick1","dodgerblue","green",
#                     "cyan","chocolate4","gray40","purple", "blue")
# 
# celllines.nointergration <- BuildClusterTree(object = celllines.nointergration,
#                                      dims = 1:min.pc,
#                                      reorder = FALSE,
#                                      reorder.numeric = FALSE)
# 
# tree <- celllines.nointergration@tools$BuildClusterTree
# tree$tip.label <- paste0("Cluster ", tree$tip.label)
# 
# p <- ggtree::ggtree(tree, aes(x, y)) +
#   scale_y_reverse() +
#   ggtree::geom_tree() +
#   ggtree::theme_tree() +
#   ggtree::geom_tiplab(offset = 1) +
#   ggtree::geom_tippoint(color = cluster_colors[1:length(tree$tip.label)], shape = 16, size = 5) +
#   coord_cartesian(clip = 'off') +
#   theme(plot.margin = unit(c(0,2.5,0,0), 'cm'))

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

```

LS0tCnRpdGxlOiAiUEMgdGVzdCBxbmQgaGFybW9ueSBpbnRlZ3JhdGlvbiBvbiBTQ1QiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogIjIwMjQtMDUtMTIiCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogZGFya2x5Ci0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShBemltdXRoKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeSh0aW55dGV4KQoKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZGl0dG9TZXEpCmxpYnJhcnkoZ2dyZXBlbCkKI2xpYnJhcnkoZ2d0cmVlKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KHBsb3RseSkgICMgM0QgcGxvdApsaWJyYXJ5KFNldXJhdCkgICMgSWRlbnRzKCkKbGlicmFyeShTZXVyYXREaXNrKSAgIyBTYXZlSDVTZXVyYXQoKQpsaWJyYXJ5KHRpYmJsZSkgICMgcm93bm5hbWVzX3RvX2NvbHVtbgpsaWJyYXJ5KGhhcm1vbnkpICMgUnVuSGFybW9ueSgpCiNvcHRpb25zKG1jLmNvcmVzID0gZGV0ZWN0Q29yZXMoKSAtIDEpCgoKCmBgYAoKCiMgMi4gTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7ciBsb2FkX3NldXJhdH0KCiNMb2FkIFNldXJhdCBPYmplY3QgbWVyZ2VkIGZyb20gY2VsbCBsaW5lcyBhbmQgYSBjb250cm9sKFBCTUMpIGFmdGVyIGZpbHRyYXRpb24KU1NfQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIGxvYWQoIlNTX0FsbF9TYW1wbGVfTWVyZ2VkX0F6aW11dGhfUHJvamVjdFRpbHNfc2luZ2xlUl9BTk5PVEFUSU9OX29uX015X1VNQVAwLjdfSFBDLlJvYmoiKQoKQWxsX3NhbXBsZXNfTWVyZ2VkCmBgYAoKCiMgMy4gUUMKYGBge3IgUUMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKSWRlbnRzKEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gImNlbGxfbGluZSIKVmxuUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50Lm1pdG8iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKYGBgCgojI0ZlYXR1cmVTY2F0dGVyIGlzIHR5cGljYWxseSB1c2VkIHRvIHZpc3VhbGl6ZSBmZWF0dXJlLWZlYXR1cmUgcmVsYXRpb25zaGlwcwojI2ZvciBhbnl0aGluZyBjYWxjdWxhdGVkIGJ5IHRoZSBvYmplY3QsIAojI2kuZS4gY29sdW1ucyBpbiBvYmplY3QgbWV0YWRhdGEsIFBDIHNjb3JlcyBldGMuCgpgYGB7ciBGQywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gInBlcmNlbnQubWl0byIpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpgYGAKCgoKIyA0LiBOb3JtYWxpemUgZGF0YQpgYGB7ciBOb3JtYWxpemUsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CgoKIyAjIEFwcGx5IFNDVHJhbnNmb3JtCiMgQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFNDVHJhbnNmb3JtKEFsbF9zYW1wbGVzX01lcmdlZCwgdmVyYm9zZSA9IFRSVUUpCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgoKIyA1LiBQZXJmb3JtIFBDQQpgYGB7ciBQQ0EsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBWYXJpYWJsZXNfZ2VuZXMgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkQGFzc2F5cyRTQ1RAdmFyLmZlYXR1cmVzCiMgCiMgIyBFeGNsdWRlIGdlbmVzIHN0YXJ0aW5nIHdpdGggIkhMQS0iIG9yICJYaXN0IgojIFZhcmlhYmxlc19nZW5lc19hZnRlcl9leGNsdXNpb24gPC0gVmFyaWFibGVzX2dlbmVzWyFncmVwbCgiXkhMQS18Xlhpc3QiLCBWYXJpYWJsZXNfZ2VuZXMpXQojIAojIAojICMgVGhlc2UgYXJlIG5vdyBzdGFuZGFyZCBzdGVwcyBpbiB0aGUgU2V1cmF0IHdvcmtmbG93IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjbHVzdGVyaW5nCiMgQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFJ1blBDQShBbGxfc2FtcGxlc19NZXJnZWQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBWYXJpYWJsZXNfZ2VuZXNfYWZ0ZXJfZXhjbHVzaW9uLAojICAgICAgICAgICAgICAgICAgICAgICAgIGRvLnByaW50ID0gVFJVRSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgcGNzLnByaW50ID0gMTo1LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lcy5wcmludCA9IDE1KQoKIyBkZXRlcm1pbmUgZGltZW5zaW9uYWxpdHkgb2YgdGhlIGRhdGEKRWxib3dQbG90KEFsbF9zYW1wbGVzX01lcmdlZCkKCgpgYGAKCgojIDUuIFBlcmZvcm0gUENBIFRFU1QKYGBge3IgUENBLVRFU1QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSQ29sb3JCcmV3ZXIpICAKCiMgQXNzdW1pbmcgeW91IGhhdmUgMTAgZGlmZmVyZW50IGNlbGwgbGluZXMsIGdlbmVyYXRpbmcgYSBjb2xvciBwYWxldHRlIHdpdGggMTAgY29sb3JzCmNlbGxfbGluZV9jb2xvcnMgPC0gYnJld2VyLnBhbCgxMCwgIlNldDMiKQoKIyBBc3N1bWluZyBBbGxfc2FtcGxlc19NZXJnZWQkY2VsbF9saW5lIGlzIGEgZmFjdG9yIG9yIGNoYXJhY3RlciB2ZWN0b3IgY29udGFpbmluZyBjZWxsIGxpbmUgbmFtZXMKZGF0YSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZCRjZWxsX2xpbmUpKQpjb2xuYW1lcyhkYXRhKSA8LSBjKCJjZWxsX2xpbmUiLCAiblVNSSIpICAjIENoYW5nZSBjb2x1bW4gbmFtZSB0byBuVU1JCgpuY2VsbHMgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gblVNSSwgZmlsbCA9IGNlbGxfbGluZSkpICsgCiAgZ2VvbV9jb2woKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gblVNSSksIAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjZWxsX2xpbmVfY29sb3JzKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgICMgQWRqdXN0IHRoZSB0aXRsZSBwb3NpdGlvbgogIGdndGl0bGUoIkZpbHRlcmVkIGNlbGxzIHBlciBzYW1wbGUiKSArCiAgeGxhYigiQ2VsbCBsaW5lcyIpICsgICMgQWRqdXN0IHgtYXhpcyBsYWJlbAogIHlsYWIoIkZyZXF1ZW5jeSIpICAgICMgQWRqdXN0IHktYXhpcyBsYWJlbAoKcHJpbnQobmNlbGxzKQoKCmNlbGxfbGluZXMgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgICMgZGVmYXVsdCB2c3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZmVhdHVyZXMgPSAyMDAwLCAgIyBkZWZhdWx0IDIwMDAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCgojIHZpZXcgdG9wIHZhcmlhYmxlIGdlbmVzCnRvcDQwIDwtIGhlYWQoVmFyaWFibGVGZWF0dXJlcyhjZWxsX2xpbmVzKSwgNDApCnRvcDQwCgoKCiMgcGxvdCB2YXJpYWJsZSBmZWF0dXJlcyB3aXRoIGxhYmVscwpWYXJGZWF0UGxvdCA8LSBWYXJpYWJsZUZlYXR1cmVQbG90KGNlbGxfbGluZXMsIGNvbHMgPSBjKCJncmF5NDciLCJyZWQiKSkKVmFyRmVhdFBsb3RMYWJlbCA8LSBMYWJlbFBvaW50cyhwbG90ID0gVmFyRmVhdFBsb3QsIAogICAgICAgICAgICAgICAgICAgIHBvaW50cyA9IHRvcDQwLCByZXBlbCA9IFRSVUUsIGZvbnRmYWNlPSJpdGFsaWMiLCAKICAgICAgICAgICAgICAgICAgICB4bnVkZ2UgPSAwLCB5bnVkZ2UgPSAwLCBtYXgub3ZlcmxhcHMgPSAxMikKVmFyRmVhdFBsb3RMYWJlbAoKCmRmIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzID0gcm93bmFtZXMoY2VsbF9saW5lcykpCmRmJHJzdW0gPC0gcm93U3Vtcyh4ID0gY2VsbF9saW5lcywgc2xvdCA9ICJjb3VudHMiKQpkZiRnZW5lX25hbWUgPC0gcm93bmFtZXMoZGYpCmRmIDwtIGRmW29yZGVyKGRmJHJzdW0sZGVjcmVhc2luZyA9IFRSVUUpLF0KaGVhZChkZiwgMTApCgojIFRFU1QtMQojIGdpdmVuIHRoYXQgdGhlIG91dHB1dCBvZiBSdW5QQ0EgaXMgInBjYSIKIyByZXBsYWNlICJzbyIgYnkgdGhlIG5hbWUgb2YgeW91ciBzZXVyYXQgb2JqZWN0CgpwY3QgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkW1sicGNhIl1dQHN0ZGV2IC8gc3VtKEFsbF9zYW1wbGVzX01lcmdlZFtbInBjYSJdXUBzdGRldikgKiAxMDAKY3VtdSA8LSBjdW1zdW0ocGN0KSAjIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBlcmNlbnRzIGZvciBlYWNoIFBDCiMgRGV0ZXJtaW5lIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdmFyaWF0aW9uIG9mIFBDIGFuZCBzdWJzZXF1ZW50IFBDCmNvMiA8LSBzb3J0KHdoaWNoKChwY3RbLWxlbmd0aChwY3QpXSAtIHBjdFstMV0pID4gMC4xKSwgZGVjcmVhc2luZyA9IFQpWzFdICsgMQojIGxhc3QgcG9pbnQgd2hlcmUgY2hhbmdlIG9mICUgb2YgdmFyaWF0aW9uIGlzIG1vcmUgdGhhbiAwLjElLiAtPiBjbzIKY28yCgojIFRFU1QtMgojIGdldCBzaWduaWZpY2FudCBQQ3MKc3RkdiA8LSBBbGxfc2FtcGxlc19NZXJnZWRbWyJwY2EiXV1Ac3RkZXYKc3VtLnN0ZHYgPC0gc3VtKEFsbF9zYW1wbGVzX01lcmdlZFtbInBjYSJdXUBzdGRldikKcGVyY2VudC5zdGR2IDwtIChzdGR2IC8gc3VtLnN0ZHYpICogMTAwCmN1bXVsYXRpdmUgPC0gY3Vtc3VtKHBlcmNlbnQuc3RkdikKY28xIDwtIHdoaWNoKGN1bXVsYXRpdmUgPiA5MCAmIHBlcmNlbnQuc3RkdiA8IDUpWzFdCmNvMiA8LSBzb3J0KHdoaWNoKChwZXJjZW50LnN0ZHZbMTpsZW5ndGgocGVyY2VudC5zdGR2KSAtIDFdIC0gCiAgICAgICAgICAgICAgICAgICAgICAgcGVyY2VudC5zdGR2WzI6bGVuZ3RoKHBlcmNlbnQuc3RkdildKSA+IDAuMSksIAogICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBUKVsxXSArIDEKbWluLnBjIDwtIG1pbihjbzEsIGNvMikKbWluLnBjCgojIENyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIHZhbHVlcwpwbG90X2RmIDwtIGRhdGEuZnJhbWUocGN0ID0gcGVyY2VudC5zdGR2LCAKICAgICAgICAgICBjdW11ID0gY3VtdWxhdGl2ZSwgCiAgICAgICAgICAgcmFuayA9IDE6bGVuZ3RoKHBlcmNlbnQuc3RkdikpCgojIEVsYm93IHBsb3QgdG8gdmlzdWFsaXplIAogIGdncGxvdChwbG90X2RmLCBhZXMoY3VtdWxhdGl2ZSwgcGVyY2VudC5zdGR2LCBsYWJlbCA9IHJhbmssIGNvbG9yID0gcmFuayA+IG1pbi5wYykpICsgCiAgZ2VvbV90ZXh0KCkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA5MCwgY29sb3IgPSAiZ3JleSIpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWluKHBlcmNlbnQuc3RkdltwZXJjZW50LnN0ZHYgPiA1XSksIGNvbG9yID0gImdyZXkiKSArCiAgdGhlbWVfYncoKQoKCmBgYAoKCiMgNi4gQ2x1c3RlcmluZwpgYGB7ciBDMSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgojIHJ1biB1bWFwCiNjZWxsbGluZXMubm9pbnRlcmdyYXRpb24gPC0gUnVuVU1BUChBbGxfc2FtcGxlc19NZXJnZWQsIGRpbXMgPSAxOm1pbi5wYywgcmVkdWN0aW9uID0gInBjYSIpCgoKIyBjbHVzdGVyCiNjZWxsbGluZXMubm9pbnRlcmdyYXRpb24gPC0gRmluZE5laWdoYm9ycyhvYmplY3QgPSBjZWxsbGluZXMubm9pbnRlcmdyYXRpb24sIGRpbXMgPSAxOm1pbi5wYykgICAKCgoKIyBEZXRlcm1pbmUgdGhlIGNsdXN0ZXJzIGZvciB2YXJpb3VzIHJlc29sdXRpb25zICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKI2NlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiA8LSBGaW5kQ2x1c3RlcnMob2JqZWN0ID0gY2VsbGxpbmVzLm5vaW50ZXJncmF0aW9uLCByZXNvbHV0aW9uID0gc2VxKDAuMSwxLjIsYnk9MC4xKSkKCgoKSWRlbnRzKGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbikgPC0gIlNDVF9zbm5fcmVzLjAuNyIKY2VsbGxpbmVzLm5vaW50ZXJncmF0aW9uJHNldXJhdF9jbHVzdGVycyA8LSBjZWxsbGluZXMubm9pbnRlcmdyYXRpb24kU0NUX3Nubl9yZXMuMC43CgoKCnUxIDwtIERpbVBsb3Qob2JqZWN0ID0gY2VsbGxpbmVzLm5vaW50ZXJncmF0aW9uLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFRSVUUpCgp1MQoKCnUyIDwtIERpbVBsb3Qob2JqZWN0ID0gY2VsbGxpbmVzLm5vaW50ZXJncmF0aW9uLCAKICAgICAgICAgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgCiAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgIGxhYmVsID0gVFJVRSwgCiAgICAgICAgIGxhYmVsLmJveCA9IFRSVUUsIAogICAgICAgICBzcGxpdC5ieSA9ICJjZWxsX2xpbmUiKQoKdTIKCgp1MyA8LSBEaW1QbG90KG9iamVjdCA9IGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiwgCiAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIAogICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICBsYWJlbCA9IFRSVUUsIAogICAgICAgICBsYWJlbC5ib3ggPSBUUlVFLCAKICAgICAgICAgc3BsaXQuYnkgPSAiUGF0aWVudF9vcmlnaW4iKQoKdTMKCgp1NCA8LSBEaW1QbG90KG9iamVjdCA9IGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiwgCiAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIAogICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICBsYWJlbCA9IFRSVUUsIAogICAgICAgICBsYWJlbC5ib3ggPSBUUlVFLCAKICAgICAgICAgc3BsaXQuYnkgPSAiVHJlYXRtZW50c19hbmFseXNpcyIpCgp1NAoKCnU1IDwtIGRpdHRvRGltUGxvdChvYmplY3QgPSBjZWxsbGluZXMubm9pbnRlcmdyYXRpb24sCiAgICAgICAgICAgICB2YXIgPSAic2V1cmF0X2NsdXN0ZXJzIiwKICAgICAgICAgICAgIHJlZHVjdGlvbi51c2UgPSAidW1hcCIsCiAgICAgICAgICAgICBkby5sYWJlbCA9IFRSVUUsCiAgICAgICAgICAgICBsYWJlbHMuaGlnaGxpZ2h0ID0gRkFMU0UpCnU1CgoKCnU2IDwtIGRpdHRvRGltUGxvdChvYmplY3QgPSBjZWxsbGluZXMubm9pbnRlcmdyYXRpb24sCiAgICAgICAgICAgICB2YXIgPSAic2V1cmF0X2NsdXN0ZXJzIiwKICAgICAgICAgICAgIHJlZHVjdGlvbi51c2UgPSAidW1hcCIsCiAgICAgICAgICAgICBkby5sYWJlbCA9IFRSVUUsCiAgICAgICAgICAgICBzcGxpdC5ieSA9ICJUcmVhdG1lbnRzX2FuYWx5c2lzIiwKICAgICAgICAgICAgIGxhYmVscy5oaWdobGlnaHQgPSBGQUxTRSkKdTYKCgoKCgojSW50ZWdyYXRlIHdpdGggaGFybW9ueQojIFJ1biBoYXJtb255IHRvIGhhcm1vbml6ZSBvdmVyIHNhbXBsZXMgCiMgY2VsbGxpbmVzLmludGVyZ3JhdGlvbiA8LSBSdW5IYXJtb255KAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkudmFycyA9ICJvcmlnLmlkZW50IiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkudXNlID0gIlNDVCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJwY2EiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2NvbnZlcmdlbmNlID0gVFJVRSkKCgoKCgoKI0ZpbmQgc2lnbmlmaWNhbnQgUENzCiNGaXJzdCBtZXRyaWMKCiMgRGV0ZXJtaW5lIHBlcmNlbnQgb2YgdmFyaWF0aW9uIGFzc29jaWF0ZWQgd2l0aCBlYWNoIFBDCnN0ZHYgPC0gY2VsbGxpbmVzLmludGVyZ3JhdGlvbltbInBjYSJdXUBzdGRldgpzdW0uc3RkdiA8LSBzdW0oY2VsbGxpbmVzLmludGVyZ3JhdGlvbltbInBjYSJdXUBzdGRldikKcGVyY2VudC5zdGR2IDwtIChzdGR2IC8gc3VtLnN0ZHYpICogMTAwCgojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBlcmNlbnRzIGZvciBlYWNoIFBDCmN1bXVsYXRpdmUgPC0gY3Vtc3VtKHBlcmNlbnQuc3RkdikKCiMgRGV0ZXJtaW5lIHdoaWNoIFBDIGV4aGliaXRzIGN1bXVsYXRpdmUgcGVyY2VudCBncmVhdGVyIHRoYW4gOTAlIGFuZAojIGFuZCAlIHZhcmlhdGlvbiBhc3NvY2lhdGVkIHdpdGggdGhlIFBDIGFzIGxlc3MgdGhhbiA1CmNvMSA8LSB3aGljaChjdW11bGF0aXZlID4gOTAgJiBwZXJjZW50LnN0ZHYgPCA1KVsxXQpjbzEKCgojIERldGVybWluZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHZhcmlhdGlvbiBvZiBQQyBhbmQgc3Vic2VxdWVudCBQQwpjbzIgPC0gc29ydCh3aGljaCgKICAocGVyY2VudC5zdGR2WzE6bGVuZ3RoKHBlcmNlbnQuc3RkdikgLSAxXSAtIAogICAgIHBlcmNlbnQuc3RkdlsyOmxlbmd0aChwZXJjZW50LnN0ZHYpXSkgPiAwLjEpLCAKICBkZWNyZWFzaW5nID0gVClbMV0gKyAxCgojIGxhc3QgcG9pbnQgd2hlcmUgY2hhbmdlIG9mICUgb2YgdmFyaWF0aW9uIGlzIG1vcmUgdGhhbiAwLjElLgpjbzIKCiMgTWluaW11bSBvZiB0aGUgdHdvIGNhbGN1bGF0aW9uCm1pbi5wYyA8LSBtaW4oY28xLCBjbzIpCm1pbi5wYwoKCiAKcGxvdF9kZiA8LSBkYXRhLmZyYW1lKHBjdCA9IHBlcmNlbnQuc3RkdiwgCiAgICAgICAgICAgY3VtdSA9IGN1bXVsYXRpdmUsIAogICAgICAgICAgIHJhbmsgPSAxOmxlbmd0aChwZXJjZW50LnN0ZHYpKQoKIyBFbGJvdyBwbG90IHRvIHZpc3VhbGl6ZSAKICBnZ3Bsb3QocGxvdF9kZiwgYWVzKGN1bXVsYXRpdmUsIHBlcmNlbnQuc3RkdiwgbGFiZWwgPSByYW5rLCBjb2xvciA9IHJhbmsgPiBtaW4ucGMpKSArIAogIGdlb21fdGV4dCgpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGNvbG9yID0gImdyZXkiKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1pbihwZXJjZW50LnN0ZHZbcGVyY2VudC5zdGR2ID4gNV0pLCBjb2xvciA9ICJncmV5IikgKwogIHRoZW1lX2J3KCkKCiMgUnVuIFVNQVAKIyBjZWxsbGluZXMuaW50ZXJncmF0aW9uIDwtIFJ1blVNQVAoY2VsbGxpbmVzLmludGVyZ3JhdGlvbiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gMTptaW4ucGMsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJwY2EiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uY29tcG9uZW50cyA9IDMpICMgc2V0IHRvIDMgdG8gdXNlIHdpdGggVlIKCgojIERldGVybWluZSB0aGUgSy1uZWFyZXN0IG5laWdoYm9yIGdyYXBoCiNjZWxsbGluZXMuaW50ZXJncmF0aW9uIDwtIEZpbmROZWlnaGJvcnMob2JqZWN0ID0gY2VsbGxpbmVzLmludGVyZ3JhdGlvbixkaW1zID0gMTptaW4ucGMpCgoKIyBEZXRlcm1pbmUgdGhlIGNsdXN0ZXJzIGZvciB2YXJpb3VzIHJlc29sdXRpb25zICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKI2NlbGxfbGluZS51bmFubm90YXRlZCA8LSBGaW5kQ2x1c3RlcnMob2JqZWN0ID0gY2VsbGxpbmVzLmludGVyZ3JhdGlvbixyZXNvbHV0aW9uID0gc2VxKDAuMSwxLjIsYnk9MC4xKSkKCgoKIyBOZXVyb25zIGFmdGVyIHJlLWNsdXN0ZXIKIyBVTUFQCkRlZmF1bHRBc3NheShjZWxsX2xpbmUudW5hbm5vdGF0ZWQpIDwtICJTQ1QiCiNuZXVyb24udW5hbm5vdGF0ZWQgPC0gTm9ybWFsaXplRGF0YShuZXVyb24udW5hbm5vdGF0ZWQsIHZlcmJvc2UgPSBGQUxTRSkKY2VsbF9saW5lLnVuYW5ub3RhdGVkJHNldXJhdF9jbHVzdGVycyA8LSBjZWxsX2xpbmUudW5hbm5vdGF0ZWQkU0NUX3Nubl9yZXMuMC43Cgp1MSA8LSBkaXR0b0RpbVBsb3Qob2JqZWN0ID0gY2VsbF9saW5lLnVuYW5ub3RhdGVkLAogICAgICAgICAgICAgdmFyID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgICByZWR1Y3Rpb24udXNlID0gInVtYXAiLAogICAgICAgICAgICAgZG8ubGFiZWwgPSBUUlVFLAogICAgICAgICAgICAgbGFiZWxzLmhpZ2hsaWdodCA9IEZBTFNFKQp1MQoKdTIgPC0gZGl0dG9EaW1QbG90KG9iamVjdCA9IGNlbGxfbGluZS51bmFubm90YXRlZCwKICAgICAgICAgICAgIHZhciA9ICJzZXVyYXRfY2x1c3RlcnMiLAogICAgICAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJ1bWFwIiwKICAgICAgICAgICAgIGRvLmxhYmVsID0gVFJVRSwKICAgICAgICAgICAgIHNwbGl0LmJ5ID0gIlRyZWF0bWVudHNfYW5hbHlzaXMiLAogICAgICAgICAgICAgbGFiZWxzLmhpZ2hsaWdodCA9IEZBTFNFKQp1MgoKCmBgYAoKCmBgYHtyIEMyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKIyAjQ2x1c3RlciB0cmVlCiMgY2x1c3Rlcl9jb2xvcnMgPC0gYygiZ29sZCIsImZpcmVicmljazEiLCJkb2RnZXJibHVlIiwiZ3JlZW4iLAojICAgICAgICAgICAgICAgICAgICAgImN5YW4iLCJjaG9jb2xhdGU0IiwiZ3JheTQwIiwicHVycGxlIiwgImJsdWUiKQojIAojIGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiA8LSBCdWlsZENsdXN0ZXJUcmVlKG9iamVjdCA9IGNlbGxsaW5lcy5ub2ludGVyZ3JhdGlvbiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6bWluLnBjLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW9yZGVyID0gRkFMU0UsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlb3JkZXIubnVtZXJpYyA9IEZBTFNFKQojIAojIHRyZWUgPC0gY2VsbGxpbmVzLm5vaW50ZXJncmF0aW9uQHRvb2xzJEJ1aWxkQ2x1c3RlclRyZWUKIyB0cmVlJHRpcC5sYWJlbCA8LSBwYXN0ZTAoIkNsdXN0ZXIgIiwgdHJlZSR0aXAubGFiZWwpCiMgCiMgcCA8LSBnZ3RyZWU6OmdndHJlZSh0cmVlLCBhZXMoeCwgeSkpICsKIyAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKIyAgIGdndHJlZTo6Z2VvbV90cmVlKCkgKwojICAgZ2d0cmVlOjp0aGVtZV90cmVlKCkgKwojICAgZ2d0cmVlOjpnZW9tX3RpcGxhYihvZmZzZXQgPSAxKSArCiMgICBnZ3RyZWU6Omdlb21fdGlwcG9pbnQoY29sb3IgPSBjbHVzdGVyX2NvbG9yc1sxOmxlbmd0aCh0cmVlJHRpcC5sYWJlbCldLCBzaGFwZSA9IDE2LCBzaXplID0gNSkgKwojICAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAnb2ZmJykgKwojICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwyLjUsMCwwKSwgJ2NtJykpCgpgYGAKCgojIFNhdmUgdGhlIFNldXJhdCBvYmplY3QgYXMgYW4gUm9iaiBmaWxlLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpgYGB7ciBzYXZlUkRTfQoKCiMgc2F2ZQojc2F2ZShjZWxsX2xpbmUudW5hbm5vdGF0ZWQsZmlsZSA9ICIxNS1jZWxsX2xpbmUudW5hbm5vdGF0ZWRfMS5Sb2JqIikKCmBgYAoKYGBgCgoKCg==