1. load libraries

Loading required package: SeuratObject
Loading required package: sp

Attaching package: 'SeuratObject'
The following objects are masked from 'package:base':

    intersect, t
── Installed datasets ──────────────────────────────── SeuratData v0.2.2.9001 ──
✔ pbmcref 1.0.0                         ✔ pbmcsca 3.0.0
────────────────────────────────────── Key ─────────────────────────────────────
✔ Dataset loaded successfully
❯ Dataset built with a newer version of Seurat than installed
❓ Unknown version of Seurat installed

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ readr     2.1.5
✔ ggplot2   3.5.1     ✔ stringr   1.5.1
✔ lubridate 1.9.3     ✔ tibble    3.2.1
✔ purrr     1.0.2     ✔ tidyr     1.3.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Attaching package: 'magrittr'


The following object is masked from 'package:purrr':

    set_names


The following object is masked from 'package:tidyr':

    extract



Attaching package: 'dbplyr'


The following objects are masked from 'package:dplyr':

    ident, sql


Registered S3 method overwritten by 'SeuratDisk':
  method            from  
  as.sparse.H5Group Seurat



Attaching shinyBS

Loading required package: ggraph


Attaching package: 'ggraph'


The following object is masked from 'package:sp':

    geometry

2. Load Seurat Object

#Load Seurat Object merged from cell lines and a control(PBMC) after filtration
load("../../../0-IMP-OBJECTS/All_Samples_Merged_with_10x_Azitmuth_Annotated.robj")

All_samples_Merged
An object of class Seurat 
36752 features across 59355 samples within 5 assays 
Active assay: RNA (36601 features, 0 variable features)
 2 layers present: data, counts
 4 other assays present: ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 2 dimensional reductions calculated: integrated_dr, ref.umap

Summarizing Seurat Object

# Load necessary libraries
library(Seurat)

# Display basic metadata summary
head(All_samples_Merged@meta.data)
# Check if columns such as `orig.ident`, `nCount_RNA`, `nFeature_RNA`, `nUMI`, `ngene`, and any other necessary columns exist
required_columns <- c("orig.ident", "nCount_RNA", "nFeature_RNA", "nUMI", "ngene")
missing_columns <- setdiff(required_columns, colnames(All_samples_Merged@meta.data))

if (length(missing_columns) > 0) {
    cat("Missing columns:", paste(missing_columns, collapse = ", "), "\n")
} else {
    cat("All required columns are present.\n")
}
All required columns are present.
# Check cell counts and features
cat("Number of cells:", ncol(All_samples_Merged), "\n")
Number of cells: 59355 
cat("Number of features:", nrow(All_samples_Merged), "\n")
Number of features: 36601 
# Verify that each `orig.ident` label has the correct number of cells
cat("Cell counts per group:\n")
Cell counts per group:
print(table(All_samples_Merged$orig.ident))

     L1      L2      L3      L4      L5      L6      L7    PBMC PBMC10x 
   5825    5935    6428    6150    6022    5148    5331    8354   10162 
# Check that the cell IDs are unique (which ensures no issues from merging)
if (any(duplicated(colnames(All_samples_Merged)))) {
    cat("Warning: There are duplicated cell IDs.\n")
} else {
    cat("Cell IDs are unique.\n")
}
Cell IDs are unique.
# Check the assay consistency for RNA
DefaultAssay(All_samples_Merged) <- "RNA"

# Check dimensions of the RNA counts layer using the new method
cat("Dimensions of the RNA counts layer:", dim(GetAssayData(All_samples_Merged, layer = "counts")), "\n")
Dimensions of the RNA counts layer: 36601 59355 
cat("Dimensions of the RNA data layer:", dim(GetAssayData(All_samples_Merged, layer = "data")), "\n")
Dimensions of the RNA data layer: 36601 59355 
# Check the ADT assay (optional)
if ("ADT" %in% names(All_samples_Merged@assays)) {
    cat("ADT assay is present.\n")
    cat("Dimensions of the ADT counts layer:", dim(GetAssayData(All_samples_Merged, assay = "ADT", layer = "counts")), "\n")
} else {
    cat("ADT assay is not present.\n")
}
ADT assay is present.
Dimensions of the ADT counts layer: 56 59355 

Azimuth Annotation

# InstallData("pbmcref")
# 
# # The RunAzimuth function can take a Seurat object as input
# All_samples_Merged <- RunAzimuth(All_samples_Merged, reference = "pbmcref")

3. QC

# Remove the percent.mito column
All_samples_Merged$percent.mito <- NULL


# Set identity classes to an existing column in meta data
Idents(object = All_samples_Merged) <- "cell_line"

All_samples_Merged[["percent.rb"]] <- PercentageFeatureSet(All_samples_Merged, 
                                                           pattern = "^RP[SL]")
# Convert 'percent.mt' to numeric, replacing "NaN" with 0
All_samples_Merged$percent.rb <- replace(as.numeric(All_samples_Merged$percent.rb), is.na(All_samples_Merged$percent.rb), 0)



# The [[ operator can add columns to object metadata. This is a great place to stash QC stats
All_samples_Merged[["percent.mt"]] <- PercentageFeatureSet(All_samples_Merged, pattern = "^MT-")

# Convert 'percent.mt' to numeric, replacing "NaN" with 0
All_samples_Merged$percent.mt <- replace(as.numeric(All_samples_Merged$percent.mt), is.na(All_samples_Merged$percent.mt), 0)





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 = "percent.mt", 
                                  feature2 = "percent.rb")

VlnPlot(All_samples_Merged, features = c("nFeature_RNA", 
                                    "nCount_RNA", 
                                    "percent.mt"), 
                                      ncol = 3)

FeatureScatter(All_samples_Merged, 
               feature1 = "percent.mt", 
               feature2 = "percent.rb") +
        geom_smooth(method = 'lm')
`geom_smooth()` using formula = 'y ~ x'

FeatureScatter(All_samples_Merged, 
               feature1 = "nCount_RNA", 
               feature2 = "nFeature_RNA") +
        geom_smooth(method = 'lm')
`geom_smooth()` using formula = 'y ~ x'

##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.mt")+
  geom_smooth(method = 'lm')
`geom_smooth()` using formula = 'y ~ x'

FeatureScatter(All_samples_Merged, 
               feature1 = "nCount_RNA", 
               feature2 = "nFeature_RNA")+
  geom_smooth(method = 'lm')
`geom_smooth()` using formula = 'y ~ x'

Assign Cell-Cycle Scores

Running SCTransform on assay: RNA
Running SCTransform on layer: counts
vst.flavor='v2' set. Using model with fixed slope and excluding poisson genes.
Variance stabilizing transformation of count matrix of size 27417 by 59355
Model formula is y ~ log_umi
Get Negative Binomial regression parameters per gene
Using 2000 genes, 5000 cells
Found 453 outliers - those will be ignored in fitting/regularization step
Second step: Get residuals using fitted parameters for 27417 genes
Computing corrected count matrix for 27417 genes
Calculating gene attributes
Wall clock passed: Time difference of 10.70591 mins
Determine variable features
Getting residuals for block 1(of 12) for counts dataset
Getting residuals for block 2(of 12) for counts dataset
Getting residuals for block 3(of 12) for counts dataset
Getting residuals for block 4(of 12) for counts dataset
Getting residuals for block 5(of 12) for counts dataset
Getting residuals for block 6(of 12) for counts dataset
Getting residuals for block 7(of 12) for counts dataset
Getting residuals for block 8(of 12) for counts dataset
Getting residuals for block 9(of 12) for counts dataset
Getting residuals for block 10(of 12) for counts dataset
Getting residuals for block 11(of 12) for counts dataset
Getting residuals for block 12(of 12) for counts dataset
Finished calculating residuals for counts
Set default assay to SCT
Warning: The following features are not present in the object: MLF1IP, not
searching for symbol synonyms
Warning: The following features are not present in the object: FAM64A, HN1, not
searching for symbol synonyms

4. Normalize data

# Apply SCTransform
All_samples_Merged <- SCTransform(All_samples_Merged, 
                                  vars.to.regress = c("percent.rb","percent.mt", "CC.Difference"), 
                                  do.scale=TRUE, 
                                  do.center=TRUE, 
                                  verbose = TRUE)
Running SCTransform on assay: RNA
Running SCTransform on layer: counts
vst.flavor='v2' set. Using model with fixed slope and excluding poisson genes.
Variance stabilizing transformation of count matrix of size 27417 by 59355
Model formula is y ~ log_umi
Get Negative Binomial regression parameters per gene
Using 2000 genes, 5000 cells
Found 453 outliers - those will be ignored in fitting/regularization step
Second step: Get residuals using fitted parameters for 27417 genes
Computing corrected count matrix for 27417 genes
Calculating gene attributes
Wall clock passed: Time difference of 8.43049 mins
Determine variable features
Regressing out percent.rb, percent.mt, CC.Difference
Centering and scaling data matrix
Getting residuals for block 1(of 12) for counts dataset
Getting residuals for block 2(of 12) for counts dataset
Getting residuals for block 3(of 12) for counts dataset
Getting residuals for block 4(of 12) for counts dataset
Getting residuals for block 5(of 12) for counts dataset
Getting residuals for block 6(of 12) for counts dataset
Getting residuals for block 7(of 12) for counts dataset
Getting residuals for block 8(of 12) for counts dataset
Getting residuals for block 9(of 12) for counts dataset
Getting residuals for block 10(of 12) for counts dataset
Getting residuals for block 11(of 12) for counts dataset
Getting residuals for block 12(of 12) for counts dataset
Regressing out percent.rb, percent.mt, CC.Difference
Centering and scaling data matrix
Finished calculating residuals for counts
Set default assay to SCT

5. Perform PCA

Variables_genes <- All_samples_Merged@assays$SCT@var.features

# Exclude genes starting with "HLA-" AND "Xist" AND "TRBV, TRAV"
Variables_genes_after_exclusion <- Variables_genes[!grepl("^HLA-|^XIST|^TRBV|^TRAV", 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,
                        npcs = 50)
PC_ 1 
Positive:  PPIA, RAN, TUBA1B, H2AFZ, NPM1, PRDX1, TPI1, HSPD1, MIF, ATP5F1B 
       COX5A, GAPDH, HSP90AB1, NME2, PRELID1, UBE2S, VDAC1, TUBB, ATP5MC3, RANBP1 
       NME1, HMGA1, CHCHD2, CYC1, ENO1, SLC25A5, HSPE1, JPT1, SNRPD1, RPS2 
Negative:  TYROBP, S100A9, S100A8, LYZ, CTSS, DPYD, VCAN, CYBB, PSAP, SPI1 
       CST3, FCN1, ZEB2, FOS, GABARAP, AIF1, FCER1G, RNF130, PLXDC2, PTPRE 
       ARHGAP26, HCK, AKAP13, FGR, LYN, LRMDA, PFDN5, MNDA, RPL39, SYK 
PC_ 2 
Positive:  FCN1, LYZ, S100A9, CST3, VCAN, S100A8, NME2, MNDA, PLXDC2, RPS2 
       FOS, IFI30, LRMDA, CTSS, CD36, GRN, CSF3R, RPS4X, TSPO, AIF1 
       CEBPD, SERPINA1, TYROBP, MS4A6A, LRP1, S100A12, RPLP0, CSTA, FPR1, LST1 
Negative:  B2M, SARAF, MALAT1, RPS27, TCF7, EVL, RPS29, LINC00861, TRBC2, ETS1 
       BTG1, RPS4Y1, PCED1B-AS1, LBH, CD3E, ITK, IL7R, PIK3IP1, ABLIM1, STK17A 
       TLE5, CD247, CLEC2D, LEF1, FCMR, GIMAP5, SELL, RPL30, PTPRC, RPL34 
PC_ 3 
Positive:  SEC11C, HDGFL3, YBX3, IL2RA, FAM107B, KRT7, CTSH, RPL30, MTHFD2, MINDY3 
       PPDPF, RAD21, EGFL6, HINT2, HTATIP2, BATF3, NCF4, ATP8B4, ELL2, TNFRSF4 
       EPB41L2, MIIP, CD74, TNFRSF11A, SPATS2L, RDH10, SYT4, RBM17, CD58, TIGIT 
Negative:  KIR3DL1, KIR3DL2, EPCAM, KIR2DL3, TRGV2, CST7, DAD1, XCL1, MATK, RAB25 
       RPL27A, CD7, ESYT2, KLRC1, KIR2DL4, GZMM, CXCR3, PFN1, C1QBP, RCBTB2 
       KRT86, XCL2, TRGV4, SRRT, EIF4A1, MYO1E, ZBTB16, RPS15, KRT81, TRGC2 
PC_ 4 
Positive:  C12orf75, HACD1, EGFL6, TNFRSF4, LY6E, TIGIT, BACE2, SYT4, PTP4A3, GGH 
       ARPC2, NET1, CCL17, PARK7, PXYLP1, ATP5MC1, CYBA, GRIA4, ADGRB3, UBE2D2 
       GYPC, MAP1B, PLEKHH2, PLPP1, ONECUT2, ENO1, FAM216A, ACTN1, DBN1, ACAA2 
Negative:  PAGE5, LMNA, RPL35A, ANXA5, RBPMS, CDKN2A, NDUFV2, RPL22L1, TENM3, GPX4 
       MSC-AS1, KIF2A, CD74, PLD1, TALDO1, ANXA2, SLC7A11, NEURL1, FAM241A, MT2A 
       STAT1, PPP2R2B, FAM50B, LGALS3, PSMB9, SPOCK1, IQCG, PPBP, RPS3A, EEF2 
PC_ 5 
Positive:  CXCL8, SOD2, C15orf48, DOCK4, KYNU, THBS1, EREG, SLC7A11, MMP9, AC025580.2 
       SDC2, MMP14, CXCL5, FTH1, CXCL3, GLIS3, CXCL1, SERPINB2, IL1B, CXCL16 
       CTSL, VMO1, RAB13, CYP27A1, MARCKS, NRP1, ABCA1, CXCL2, NINJ1, EPB41L3 
Negative:  PAGE5, RPL35A, MNDA, FCN1, NDUFV2, TSPO, RPS14, RBPMS, FOS, CSF3R 
       C1orf162, CST3, LYST, STMN1, CD36, JAML, MS4A6A, TMSB4X, KIF2A, AC007952.4 
       RPL11, CD302, CDKN2A, PSMB2, BLVRB, PSMB9, TENM3, RPS3A, PRAM1, VCAN 
# determine dimensionality of the data
ElbowPlot(All_samples_Merged, ndims = 50)

6. 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)

# 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] 22
# 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] 22
# 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()

7. Clustering

All_samples_Merged <- FindNeighbors(All_samples_Merged, 
                                dims = 1:13, 
                                verbose = FALSE)

# understanding resolution
All_samples_Merged <- FindClusters(All_samples_Merged, 
                                    resolution = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,0.8, 0.9, 1,1.2,1.5,2))
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9868
Number of communities: 15
Elapsed time: 21 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9781
Number of communities: 16
Elapsed time: 22 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9695
Number of communities: 17
Elapsed time: 21 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9617
Number of communities: 20
Elapsed time: 22 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9538
Number of communities: 20
Elapsed time: 21 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9462
Number of communities: 22
Elapsed time: 21 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9388
Number of communities: 23
Elapsed time: 21 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9316
Number of communities: 25
Elapsed time: 22 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9256
Number of communities: 27
Elapsed time: 20 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9195
Number of communities: 27
Elapsed time: 24 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9084
Number of communities: 31
Elapsed time: 28 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.8946
Number of communities: 33
Elapsed time: 28 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1881247

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.8740
Number of communities: 40
Elapsed time: 29 seconds
# non-linear dimensionality reduction --------------
All_samples_Merged <- RunUMAP(All_samples_Merged, 
                          dims = 1:13,
                          verbose = FALSE)
Warning: The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session
# note that you can set `label = TRUE` or use the Label Clusters function to help label
# individual clusters
DimPlot(All_samples_Merged,group.by = "cell_line", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,group.by = "predicted.celltype.l2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)
Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider
increasing max.overlaps

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.1",
        reduction = "umap",
        label.size = 3,
        repel = T, 
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.2",
        reduction = "umap",
        label.size = 3,
        repel = T, 
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.3",
        reduction = "umap",
        label.size = 3,
        repel = T, 
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.4", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.5", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.6", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.7", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.8", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.0.9", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.1", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.1.2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.1.5", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged,
        group.by = "SCT_snn_res.2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

# Set identity classes to an existing column in meta data
Idents(object = All_samples_Merged) <- "SCT_snn_res.0.7"

cluster_table <- table(Idents(All_samples_Merged))


barplot(cluster_table, main = "Number of Cells in Each Cluster", 
                      xlab = "Cluster", 
                      ylab = "Number of Cells", 
                      col = rainbow(length(cluster_table)))

print(cluster_table)

   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
6400 5923 5823 5624 5496 5476 5077 4611 3422 3005 2310 1336 1333  922  827  450 
  16   17   18   19   20   21   22 
 281  278  230  219  193   88   31 
table(All_samples_Merged$predicted.celltype.l2, All_samples_Merged$SCT_snn_res.0.2)
                   
                       0    1    2    3    4    5    6    7    8    9   10   11
  ASDC                 0    0    0    0    0    0    0    0    0    2    0    0
  B intermediate       0    1    0    0    0    0    2    2    0    6  663   19
  B memory             9    0    2    0    0  137   20   83    1    1  263    4
  B naive              0    0    0    0    0    0    0    0    0   14 1174    0
  CD14 Mono            0    1    2    0    0   11    0    0    0 3042    0  761
  CD16 Mono            0    0    0    0    0    0    0    0    0  124    0    2
  CD4 CTL              0   15    0    0    0    0    0    0    1    1    0    0
  CD4 Naive            0  521    0    0    0    0    0    0 1481    1    7    0
  CD4 Proliferating 5453    0 5390 2849 2461 4412 4345 4093    5    0    0    0
  CD4 TCM            883 4518  523  267 3319  567   77  608 1811   20   76   36
  CD4 TEM              0   69    0    0    1    0    0    0   24    0    0    0
  CD8 Naive            0  342    0    0    0    0    0    0 1011    2    3    1
  CD8 Proliferating    0    0    0    0    0    1    0    1    0    0    0    0
  CD8 TCM              0  277    0   16    1    0    0    0  179    0    2    0
  CD8 TEM              0  179    0    6    1    2    1    3  184    1    1    0
  cDC1                 0    0    0    0    0    0    2    6    0   13    0    0
  cDC2                 0    0    2    0    0   41    5    3    0  124    1    0
  dnT                  0   32    1    0    1    6    0    4   16    1    4    2
  gdT                  0   26    0    0    0    0    0    0   67    0    0    0
  HSPC                57    1    1    0    0  504 1020  214    0    1   35    0
  ILC                  1    1    0    0    0    0    0    0    3    0    2    0
  MAIT                 0   15    0    0    0    0    0    0  223    2    0    0
  NK                   0   87    0    0    0    0    0    0   19    9    0    1
  NK Proliferating     7    0   23 2786   38   35    9  265    1    0    1    0
  NK_CD56bright        0    1    0    0    0    0    0    0    5    0    0    0
  pDC                  0    0    0    0    0    0    0    0    0    0    1    0
  Plasmablast          0    0    0    0    0    0    0    0    0    0   19    0
  Platelet             0    0    0    0    0    0    0    0    0    1    0    1
  Treg                14  210    2    0    1   10    0   13   86    1    6    0
                   
                      12   13   14   15
  ASDC                 1    0    0    0
  B intermediate       1    0    2    0
  B memory             0    0    3    0
  B naive              4    0    0    0
  CD14 Mono            0    0    5    1
  CD16 Mono            0    0    0    0
  CD4 CTL              0    0    0    0
  CD4 Naive            0   33    0    0
  CD4 Proliferating    0    3    0    0
  CD4 TCM              0  171    2    0
  CD4 TEM              0    0    0    0
  CD8 Naive            0   14    0    0
  CD8 Proliferating    0    0    0    0
  CD8 TCM              0    2    0    0
  CD8 TEM             10    3    0    0
  cDC1                 0    0   21    0
  cDC2                 0    0   53    0
  dnT                  0   15    0    0
  gdT                  0    0    0    0
  HSPC                 0    0    1    0
  ILC                  0    0    0    0
  MAIT                 0    2    0    0
  NK                 416    2    0    0
  NK Proliferating     2    0    0    0
  NK_CD56bright        8    2    0    0
  pDC                 55    0    0    0
  Plasmablast          0    0    0    0
  Platelet             0    0    0   30
  Treg                 0    9    1    0

8. clusTree

clustree(All_samples_Merged, prefix = "SCT_snn_res.")

9. Azimuth Annotation

# InstallData("pbmcref")
# 
# # The RunAzimuth function can take a Seurat object as input
# All_samples_Merged <- RunAzimuth(All_samples_Merged, reference = "pbmcref")

10. Azimuth Visualization

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l1", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l1", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = F)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)
Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider
increasing max.overlaps

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = F)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2", 
        reduction = "umap",
        label.size = 3,
        repel = T,
        label = T, label.box = T)
Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider
increasing max.overlaps

table(All_samples_Merged$predicted.celltype.l2, All_samples_Merged$SCT_snn_res.0.7)
                   
                       0    1    2    3    4    5    6    7    8    9   10   11
  ASDC                 0    0    0    0    0    0    0    0    0    0    0    0
  B intermediate       0    0    0    1    0    2    0    0    0    0    0  481
  B memory             9    0    0    0    0   20   80    1    0    0  137  197
  B naive              0    0    0    0    0    0    0    0    0    0    0  504
  CD14 Mono            0    0    0    1    0    0    0    0    0 2840   11    0
  CD16 Mono            0    0    0    0    0    0    0    0    0  121    0    0
  CD4 CTL              0    0    0    0    0    0    0    0    0    0    0    0
  CD4 Naive            0    0    0  517    0    0    0 1481    0    0    0    7
  CD4 Proliferating 5452 2849 2461    0 5316 4340 3981    4 2890    0 1525    0
  CD4 TCM            876  266 3319 4242  156   78  554 1799   24    0  544   74
  CD4 TEM              0    0    1   61    0    0    0   17    0    0    0    0
  CD8 Naive            0    0    0  334    0    0    0 1010    0    0    0    2
  CD8 Proliferating    0    0    0    0    0    0    1    0    0    0    1    0
  CD8 TCM              0   16    1  225    0    0    0  150    0    0    0    2
  CD8 TEM              0    6    1   29    0    1    3   27    0    0    2    1
  cDC1                 0    0    0    0    0    2    5    0    0    0    0    0
  cDC2                 0    0    0    0    0    5    3    0    0   41   41    1
  dnT                  0    0    1   23    1    0    1   16    0    1    7    4
  gdT                  0    0    0    1    0    0    0   15    0    0    0    0
  HSPC                55    0    0    1    1 1019  212    0  497    1    8   35
  ILC                  0    0    0    0    0    0    0    0    0    0    0    2
  MAIT                 0    0    0    1    0    0    0    5    0    0    0    0
  NK                   0    0    0    0    0    0    0    0    0    0    0    0
  NK Proliferating     6 2786   38    0   21    9  236    0   11    0   24    1
  NK_CD56bright        0    0    0    0    0    0    0    0    0    0    0    0
  pDC                  0    0    0    0    0    0    0    0    0    0    0    0
  Plasmablast          0    0    0    0    0    0    0    0    0    0    0   19
  Platelet             0    0    0    0    0    0    0    0    0    1    0    0
  Treg                 2    0    1  188    1    0    1   86    0    0   10    6
                   
                      12   13   14   15   16   17   18   19   20   21   22
  ASDC                 0    0    0    0    0    0    0    0    3    0    0
  B intermediate       0  182   19    0    0    0    0    2    7    2    0
  B memory             0   66    4    2    0    0    0    3    1    3    0
  B naive              0  670    0    0    0    0    0    0   18    0    0
  CD14 Mono            0    0  761    2    0    0  187    0   15    5    1
  CD16 Mono            0    0    2    0    0    0    3    0    0    0    0
  CD4 CTL             16    0    0    0    0    0    1    0    0    0    0
  CD4 Naive            0    0    0    0   33    4    1    0    0    0    0
  CD4 Proliferating    1    0    0   74    4    0    0  114    0    0    0
  CD4 TCM             50    2   36  367  178  238   20   53    0    2    0
  CD4 TEM             15    0    0    0    0    0    0    0    0    0    0
  CD8 Naive            1    1    1    0   14    8    2    0    0    0    0
  CD8 Proliferating    0    0    0    0    0    0    0    0    0    0    0
  CD8 TCM             79    0    0    0    2    2    0    0    0    0    0
  CD8 TEM            317    0    0    0    3    0    1    0    0    0    0
  cDC1                 0    0    0    0    0    0    0    1   13   21    0
  cDC2                 0    0    0    2    0    0    3    0   80   53    0
  dnT                  1    0    2    0   16    6    0    3    0    0    0
  gdT                 77    0    0    0    0    0    0    0    0    0    0
  HSPC                 0    0    0    0    2    0    0    2    0    1    0
  ILC                  4    0    0    0    1    0    0    0    0    0    0
  MAIT               232    0    0    0    2    0    2    0    0    0    0
  NK                 521    0    1    0    2    0    9    0    1    0    0
  NK Proliferating     3    0    0    2    1    0    0   29    0    0    0
  NK_CD56bright       14    0    0    0    2    0    0    0    0    0    0
  pDC                  0    1    0    0    0    0    0    0   55    0    0
  Plasmablast          0    0    0    0    0    0    0    0    0    0    0
  Platelet             0    0    1    0    0    0    0    0    0    0   30
  Treg                 2    0    0    1   21   20    1   12    0    1    0

11.Harmony Integration

# Load required libraries
library(Seurat)
library(harmony)
Loading required package: Rcpp
library(ggplot2)

# Run Harmony, adjusting for batch effect using "cell_line" or another grouping variable
All_samples_Merged <- RunHarmony(
  object = All_samples_Merged,
  group.by.vars = "cell_line",  # Replace with the metadata column specifying batch or cell line
  dims.use = 1:22  # Use the same dimensions as PCA
)
Transposing data matrix
Initializing state using k-means centroids initialization
Harmony 1/10
Harmony 2/10
Harmony 3/10
Harmony converged after 3 iterations
# Check results in harmony embeddings
harmony_embeddings <- Embeddings(All_samples_Merged, reduction = "harmony")
head(harmony_embeddings)
                       harmony_1 harmony_2 harmony_3  harmony_4  harmony_5
L1_AAACCTGAGGGCTTCC-1 -9.1829758  1.963191 -1.918213 -2.6439503  5.2090589
L1_AAACCTGGTGCAGGTA-1 -2.0181314 -1.959992 -6.630212 -0.6095339  2.4711615
L1_AAACCTGGTTAAAGTG-1  2.9577096 -3.100137 -7.965495  1.3714850 -1.8113084
L1_AAACCTGTCAGGTAAA-1  5.5391691  2.079810 -3.930100 -2.6739791  2.9035729
L1_AAACCTGTCCCTGACT-1 -5.9452052 -2.490022 -1.093192 -2.3334026  5.3740374
L1_AAACCTGTCCTTCAAT-1  0.6440283 -3.066060 -6.719512  1.0522677  0.5062576
                      harmony_6 harmony_7    harmony_8  harmony_9  harmony_10
L1_AAACCTGAGGGCTTCC-1  1.942551 7.5160215  1.590007728 -1.6905939  2.25899415
L1_AAACCTGGTGCAGGTA-1  2.082405 9.2696845  0.170642540 -0.3150174  5.06578933
L1_AAACCTGGTTAAAGTG-1  2.089400 5.7529230  1.740593023 -2.0960111  0.60816445
L1_AAACCTGTCAGGTAAA-1  1.087311 0.5767162  5.328467887  0.8787689 -0.03566803
L1_AAACCTGTCCCTGACT-1  3.290703 2.9443345  1.647116518 -0.2437256  1.83756606
L1_AAACCTGTCCTTCAAT-1  1.894603 5.1840153 -0.004641828 -2.8198796  1.83086508
                      harmony_11 harmony_12  harmony_13 harmony_14 harmony_15
L1_AAACCTGAGGGCTTCC-1 -0.6705618 -15.821885  0.01758632 -1.0042047 -3.1817639
L1_AAACCTGGTGCAGGTA-1  0.6516908  -9.727728 -1.79718451  1.4884099 -0.3023961
L1_AAACCTGGTTAAAGTG-1 -0.2784375  -4.331778 -2.35365317 -1.8970786  4.4020402
L1_AAACCTGTCAGGTAAA-1  2.4349602  -7.389665 -1.43931257  0.1163356 -0.1042223
L1_AAACCTGTCCCTGACT-1  1.0582357 -16.896482 -0.33692269 -0.3218589 -3.5518742
L1_AAACCTGTCCTTCAAT-1 -0.7462167  -8.431887 -1.57728399  0.1007814  0.6195831
                      harmony_16 harmony_17 harmony_18 harmony_19 harmony_20
L1_AAACCTGAGGGCTTCC-1  6.1639263 -0.8775208 -1.0145176  0.5309521 -0.6053158
L1_AAACCTGGTGCAGGTA-1  2.7239952  0.5881924 -1.4079552 -1.3660352  0.5972989
L1_AAACCTGGTTAAAGTG-1 -0.3734147  4.2548894  2.6650620  1.4432665 -2.7793401
L1_AAACCTGTCAGGTAAA-1  0.9545364  0.8569197  1.0572318 -0.8463755 -0.7375956
L1_AAACCTGTCCCTGACT-1  4.6672031 -0.3968514  0.3944571  0.9812218 -1.3131569
L1_AAACCTGTCCTTCAAT-1  1.6501552  0.9518280 -0.1556663  0.5601416 -0.3584055
                       harmony_21 harmony_22
L1_AAACCTGAGGGCTTCC-1 -1.13059949  -1.275543
L1_AAACCTGGTGCAGGTA-1 -1.42605510  -1.701459
L1_AAACCTGGTTAAAGTG-1  3.66049873  -1.524969
L1_AAACCTGTCAGGTAAA-1 -0.06630109  -1.217809
L1_AAACCTGTCCCTGACT-1 -1.13165681  -1.400442
L1_AAACCTGTCCTTCAAT-1 -1.77846391  -1.537383
# Run UMAP on Harmony embeddings
All_samples_Merged <- RunUMAP(All_samples_Merged, reduction = "harmony", dims = 1:22)
19:09:40 UMAP embedding parameters a = 0.9922 b = 1.112
19:09:40 Read 59355 rows and found 22 numeric columns
19:09:40 Using Annoy for neighbor search, n_neighbors = 30
19:09:40 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
19:09:47 Writing NN index file to temp file /tmp/RtmprI0jPe/file30ec7679da9d
19:09:47 Searching Annoy index using 1 thread, search_k = 3000
19:10:08 Annoy recall = 100%
19:10:10 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
19:10:15 Initializing from normalized Laplacian + noise (using RSpectra)
19:10:22 Commencing optimization for 200 epochs, with 2552746 positive edges
19:11:43 Optimization finished
# Optionally, find neighbors and clusters (if you plan to do clustering analysis)
All_samples_Merged <- FindNeighbors(All_samples_Merged, reduction = "harmony", dims = 1:22)
Computing nearest neighbor graph
Computing SNN
All_samples_Merged <- FindClusters(All_samples_Merged, resolution = 0.5)  # Adjust resolution as needed
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 59355
Number of edges: 1783585

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.8996
Number of communities: 18
Elapsed time: 24 seconds
# Visualize UMAP
DimPlot(All_samples_Merged, reduction = "umap", group.by = "cell_line", label = TRUE, pt.size = 0.5) + 
    ggtitle("UMAP of Harmony-Integrated Data")

# Visualize UMAP with batch/cell line information
DimPlot(All_samples_Merged, reduction = "umap", group.by = "cell_line", label = TRUE, pt.size = 0.5) + 
    ggtitle("UMAP - Colored by Cell Line (After Harmony Integration)")

# Visualize UMAP with clusters
DimPlot(All_samples_Merged, reduction = "umap", group.by = "seurat_clusters", label = TRUE, pt.size = 0.5) + 
    ggtitle("UMAP - Clustered Data (After Harmony Integration)")

# Visualize specific cell types or other metadata
DimPlot(All_samples_Merged, reduction = "umap", group.by = "predicted.celltype.l2", label = TRUE, pt.size = 0.5) + 
    ggtitle("UMAP - Cell Types After Harmony Integration")

12.Save the Seurat object as an Robj file

save(All_samples_Merged, file = "../../../0-IMP-OBJECTS/All_Samples_Merged_with_10x_Azitmuth_Annotated_SCT_HPC.robj")
LS0tCnRpdGxlOiAiTWVyZ2VkIEFsbCBzYW1wbGVzIHdpdGggUEJNQ18xMHgiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgZWNobz1GQUxTRX0KCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KHBhdGNod29yaykKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGRicGx5cikKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodGlueXRleCkKI0F6aW11dGggQW5ub3RhdGlvbiBsaWJyYXJpZXMKbGlicmFyeShBemltdXRoKQoKbGlicmFyeShjbHVzdHJlZSkKCgpgYGAKCgojIDIuIExvYWQgU2V1cmF0IE9iamVjdCAKYGBge3IgbG9hZF9zZXVyYXR9CgojTG9hZCBTZXVyYXQgT2JqZWN0IG1lcmdlZCBmcm9tIGNlbGwgbGluZXMgYW5kIGEgY29udHJvbChQQk1DKSBhZnRlciBmaWx0cmF0aW9uCmxvYWQoIi4uLy4uLy4uLzAtSU1QLU9CSkVDVFMvQWxsX1NhbXBsZXNfTWVyZ2VkX3dpdGhfMTB4X0F6aXRtdXRoX0Fubm90YXRlZC5yb2JqIikKCkFsbF9zYW1wbGVzX01lcmdlZAogCmBgYAoKIyMgU3VtbWFyaXppbmcgU2V1cmF0IE9iamVjdApgYGB7ciBzdW1tYXJ5LCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoU2V1cmF0KQoKIyBEaXNwbGF5IGJhc2ljIG1ldGFkYXRhIHN1bW1hcnkKaGVhZChBbGxfc2FtcGxlc19NZXJnZWRAbWV0YS5kYXRhKQoKIyBDaGVjayBpZiBjb2x1bW5zIHN1Y2ggYXMgYG9yaWcuaWRlbnRgLCBgbkNvdW50X1JOQWAsIGBuRmVhdHVyZV9STkFgLCBgblVNSWAsIGBuZ2VuZWAsIGFuZCBhbnkgb3RoZXIgbmVjZXNzYXJ5IGNvbHVtbnMgZXhpc3QKcmVxdWlyZWRfY29sdW1ucyA8LSBjKCJvcmlnLmlkZW50IiwgIm5Db3VudF9STkEiLCAibkZlYXR1cmVfUk5BIiwgIm5VTUkiLCAibmdlbmUiKQptaXNzaW5nX2NvbHVtbnMgPC0gc2V0ZGlmZihyZXF1aXJlZF9jb2x1bW5zLCBjb2xuYW1lcyhBbGxfc2FtcGxlc19NZXJnZWRAbWV0YS5kYXRhKSkKCmlmIChsZW5ndGgobWlzc2luZ19jb2x1bW5zKSA+IDApIHsKICAgIGNhdCgiTWlzc2luZyBjb2x1bW5zOiIsIHBhc3RlKG1pc3NpbmdfY29sdW1ucywgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikKfSBlbHNlIHsKICAgIGNhdCgiQWxsIHJlcXVpcmVkIGNvbHVtbnMgYXJlIHByZXNlbnQuXG4iKQp9CgojIENoZWNrIGNlbGwgY291bnRzIGFuZCBmZWF0dXJlcwpjYXQoIk51bWJlciBvZiBjZWxsczoiLCBuY29sKEFsbF9zYW1wbGVzX01lcmdlZCksICJcbiIpCmNhdCgiTnVtYmVyIG9mIGZlYXR1cmVzOiIsIG5yb3coQWxsX3NhbXBsZXNfTWVyZ2VkKSwgIlxuIikKCiMgVmVyaWZ5IHRoYXQgZWFjaCBgb3JpZy5pZGVudGAgbGFiZWwgaGFzIHRoZSBjb3JyZWN0IG51bWJlciBvZiBjZWxscwpjYXQoIkNlbGwgY291bnRzIHBlciBncm91cDpcbiIpCnByaW50KHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZCRvcmlnLmlkZW50KSkKCiMgQ2hlY2sgdGhhdCB0aGUgY2VsbCBJRHMgYXJlIHVuaXF1ZSAod2hpY2ggZW5zdXJlcyBubyBpc3N1ZXMgZnJvbSBtZXJnaW5nKQppZiAoYW55KGR1cGxpY2F0ZWQoY29sbmFtZXMoQWxsX3NhbXBsZXNfTWVyZ2VkKSkpKSB7CiAgICBjYXQoIldhcm5pbmc6IFRoZXJlIGFyZSBkdXBsaWNhdGVkIGNlbGwgSURzLlxuIikKfSBlbHNlIHsKICAgIGNhdCgiQ2VsbCBJRHMgYXJlIHVuaXF1ZS5cbiIpCn0KCiMgQ2hlY2sgdGhlIGFzc2F5IGNvbnNpc3RlbmN5IGZvciBSTkEKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlJOQSIKCiMgQ2hlY2sgZGltZW5zaW9ucyBvZiB0aGUgUk5BIGNvdW50cyBsYXllciB1c2luZyB0aGUgbmV3IG1ldGhvZApjYXQoIkRpbWVuc2lvbnMgb2YgdGhlIFJOQSBjb3VudHMgbGF5ZXI6IiwgZGltKEdldEFzc2F5RGF0YShBbGxfc2FtcGxlc19NZXJnZWQsIGxheWVyID0gImNvdW50cyIpKSwgIlxuIikKY2F0KCJEaW1lbnNpb25zIG9mIHRoZSBSTkEgZGF0YSBsYXllcjoiLCBkaW0oR2V0QXNzYXlEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgbGF5ZXIgPSAiZGF0YSIpKSwgIlxuIikKCiMgQ2hlY2sgdGhlIEFEVCBhc3NheSAob3B0aW9uYWwpCmlmICgiQURUIiAlaW4lIG5hbWVzKEFsbF9zYW1wbGVzX01lcmdlZEBhc3NheXMpKSB7CiAgICBjYXQoIkFEVCBhc3NheSBpcyBwcmVzZW50LlxuIikKICAgIGNhdCgiRGltZW5zaW9ucyBvZiB0aGUgQURUIGNvdW50cyBsYXllcjoiLCBkaW0oR2V0QXNzYXlEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgYXNzYXkgPSAiQURUIiwgbGF5ZXIgPSAiY291bnRzIikpLCAiXG4iKQp9IGVsc2UgewogICAgY2F0KCJBRFQgYXNzYXkgaXMgbm90IHByZXNlbnQuXG4iKQp9CgoKYGBgCgojIyBBemltdXRoIEFubm90YXRpb24KYGBge3IgYXppbXV0aF9Bbm5vdGF0aW9uMSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CiMgSW5zdGFsbERhdGEoInBibWNyZWYiKQojIAojICMgVGhlIFJ1bkF6aW11dGggZnVuY3Rpb24gY2FuIHRha2UgYSBTZXVyYXQgb2JqZWN0IGFzIGlucHV0CiMgQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFJ1bkF6aW11dGgoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWZlcmVuY2UgPSAicGJtY3JlZiIpCgpgYGAKCiMgMy4gUUMKYGBge3IgUUMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBSZW1vdmUgdGhlIHBlcmNlbnQubWl0byBjb2x1bW4KQWxsX3NhbXBsZXNfTWVyZ2VkJHBlcmNlbnQubWl0byA8LSBOVUxMCgoKIyBTZXQgaWRlbnRpdHkgY2xhc3NlcyB0byBhbiBleGlzdGluZyBjb2x1bW4gaW4gbWV0YSBkYXRhCklkZW50cyhvYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJjZWxsX2xpbmUiCgpBbGxfc2FtcGxlc19NZXJnZWRbWyJwZXJjZW50LnJiIl1dIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJeUlBbU0xdIikKIyBDb252ZXJ0ICdwZXJjZW50Lm10JyB0byBudW1lcmljLCByZXBsYWNpbmcgIk5hTiIgd2l0aCAwCkFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50LnJiIDwtIHJlcGxhY2UoYXMubnVtZXJpYyhBbGxfc2FtcGxlc19NZXJnZWQkcGVyY2VudC5yYiksIGlzLm5hKEFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50LnJiKSwgMCkKCgoKIyBUaGUgW1sgb3BlcmF0b3IgY2FuIGFkZCBjb2x1bW5zIHRvIG9iamVjdCBtZXRhZGF0YS4gVGhpcyBpcyBhIGdyZWF0IHBsYWNlIHRvIHN0YXNoIFFDIHN0YXRzCkFsbF9zYW1wbGVzX01lcmdlZFtbInBlcmNlbnQubXQiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoQWxsX3NhbXBsZXNfTWVyZ2VkLCBwYXR0ZXJuID0gIl5NVC0iKQoKIyBDb252ZXJ0ICdwZXJjZW50Lm10JyB0byBudW1lcmljLCByZXBsYWNpbmcgIk5hTiIgd2l0aCAwCkFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50Lm10IDwtIHJlcGxhY2UoYXMubnVtZXJpYyhBbGxfc2FtcGxlc19NZXJnZWQkcGVyY2VudC5tdCksIGlzLm5hKEFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50Lm10KSwgMCkKCgoKCgpWbG5QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50Lm10IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudC5yYiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSA0LCBwdC5zaXplID0gMC4xKSAmIAogICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmUxID0gInBlcmNlbnQubXQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmUyID0gInBlcmNlbnQucmIiKQoKVmxuUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50Lm10IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKQoKRmVhdHVyZVNjYXR0ZXIoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAicGVyY2VudC5tdCIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJwZXJjZW50LnJiIikgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKYGBgCgojI0ZlYXR1cmVTY2F0dGVyIGlzIHR5cGljYWxseSB1c2VkIHRvIHZpc3VhbGl6ZSBmZWF0dXJlLWZlYXR1cmUgcmVsYXRpb25zaGlwcwojI2ZvciBhbnl0aGluZyBjYWxjdWxhdGVkIGJ5IHRoZSBvYmplY3QsIAojI2kuZS4gY29sdW1ucyBpbiBvYmplY3QgbWV0YWRhdGEsIFBDIHNjb3JlcyBldGMuCgpgYGB7ciBGQywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gInBlcmNlbnQubXQiKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKRmVhdHVyZVNjYXR0ZXIoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJuRmVhdHVyZV9STkEiKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKYGBgCgoKIyMgQXNzaWduIENlbGwtQ3ljbGUgU2NvcmVzCmBgYHtyIFJlZ3Jlc3MsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQpvcHRpb25zKGZ1dHVyZS5nbG9iYWxzLm1heFNpemUgPSA4MDAwICogMTAyNF4yKSAgIyBTZXQgdG8gODAwMCBNaUIgKGFib3V0IDggR0IpCgoKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFNDVHJhbnNmb3JtKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG8uc2NhbGUgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG8uY2VudGVyID0gRkFMU0UpICAjIFJlZHVjZSB0byAxMDAwIHZhcmlhYmxlIGZlYXR1cmVzCgoKIyBBIGxpc3Qgb2YgY2VsbCBjeWNsZSBtYXJrZXJzLCBmcm9tIFRpcm9zaCBldCBhbCwgMjAxNSwgaXMgbG9hZGVkIHdpdGggU2V1cmF0LiAgV2UgY2FuCiMgc2VncmVnYXRlIHRoaXMgbGlzdCBpbnRvIG1hcmtlcnMgb2YgRzIvTSBwaGFzZSBhbmQgbWFya2VycyBvZiBTIHBoYXNlCnMuZ2VuZXMgPC0gY2MuZ2VuZXMkcy5nZW5lcwpnMm0uZ2VuZXMgPC0gY2MuZ2VuZXMkZzJtLmdlbmVzCgoKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIENlbGxDeWNsZVNjb3JpbmcoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcy5mZWF0dXJlcyA9IHMuZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnMm0uZmVhdHVyZXMgPSBnMm0uZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXQuaWRlbnQgPSBUUlVFKQoKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlJOQSIKQWxsX3NhbXBsZXNfTWVyZ2VkJENDLkRpZmZlcmVuY2UgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkJFMuU2NvcmUgLSBBbGxfc2FtcGxlc19NZXJnZWQkRzJNLlNjb3JlCgpgYGAKCgojIDQuIE5vcm1hbGl6ZSBkYXRhCmBgYHtyIE5vcm1hbGl6ZSwgaW5jbHVkZT1UUlVFfQoKCiMgQXBwbHkgU0NUcmFuc2Zvcm0KQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFNDVHJhbnNmb3JtKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJwZXJjZW50LnJiIiwicGVyY2VudC5tdCIsICJDQy5EaWZmZXJlbmNlIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG8uc2NhbGU9VFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkby5jZW50ZXI9VFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgoKIyA1LiBQZXJmb3JtIFBDQQpgYGB7ciBQQ0EsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKVmFyaWFibGVzX2dlbmVzIDwtIEFsbF9zYW1wbGVzX01lcmdlZEBhc3NheXMkU0NUQHZhci5mZWF0dXJlcwoKIyBFeGNsdWRlIGdlbmVzIHN0YXJ0aW5nIHdpdGggIkhMQS0iIEFORCAiWGlzdCIgQU5EICJUUkJWLCBUUkFWIgpWYXJpYWJsZXNfZ2VuZXNfYWZ0ZXJfZXhjbHVzaW9uIDwtIFZhcmlhYmxlc19nZW5lc1shZ3JlcGwoIl5ITEEtfF5YSVNUfF5UUkJWfF5UUkFWIiwgVmFyaWFibGVzX2dlbmVzKV0KCgojIFRoZXNlIGFyZSBub3cgc3RhbmRhcmQgc3RlcHMgaW4gdGhlIFNldXJhdCB3b3JrZmxvdyBmb3IgdmlzdWFsaXphdGlvbiBhbmQgY2x1c3RlcmluZwpBbGxfc2FtcGxlc19NZXJnZWQgPC0gUnVuUENBKEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBWYXJpYWJsZXNfZ2VuZXNfYWZ0ZXJfZXhjbHVzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICBkby5wcmludCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBwY3MucHJpbnQgPSAxOjUsIAogICAgICAgICAgICAgICAgICAgICAgICBnZW5lcy5wcmludCA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICBucGNzID0gNTApCgojIGRldGVybWluZSBkaW1lbnNpb25hbGl0eSBvZiB0aGUgZGF0YQpFbGJvd1Bsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBuZGltcyA9IDUwKQoKCmBgYAoKIyA2LiBQZXJmb3JtIFBDQSBURVNUCmBgYHtyIFBDQS1URVNULCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKSAgCgojIEFzc3VtaW5nIHlvdSBoYXZlIDEwIGRpZmZlcmVudCBjZWxsIGxpbmVzLCBnZW5lcmF0aW5nIGEgY29sb3IgcGFsZXR0ZSB3aXRoIDEwIGNvbG9ycwpjZWxsX2xpbmVfY29sb3JzIDwtIGJyZXdlci5wYWwoMTAsICJTZXQzIikKCiMgQXNzdW1pbmcgQWxsX3NhbXBsZXNfTWVyZ2VkJGNlbGxfbGluZSBpcyBhIGZhY3RvciBvciBjaGFyYWN0ZXIgdmVjdG9yIGNvbnRhaW5pbmcgY2VsbCBsaW5lIG5hbWVzCmRhdGEgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShBbGxfc2FtcGxlc19NZXJnZWQkY2VsbF9saW5lKSkKY29sbmFtZXMoZGF0YSkgPC0gYygiY2VsbF9saW5lIiwgIm5VTUkiKSAgIyBDaGFuZ2UgY29sdW1uIG5hbWUgdG8gblVNSQoKbmNlbGxzIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGNlbGxfbGluZSwgeSA9IG5VTUksIGZpbGwgPSBjZWxsX2xpbmUpKSArIAogIGdlb21fY29sKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG5VTUkpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIAogICAgICAgICAgICB2anVzdCA9IC0wLjI1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2VsbF9saW5lX2NvbG9ycykgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArICAjIEFkanVzdCB0aGUgdGl0bGUgcG9zaXRpb24KICBnZ3RpdGxlKCJGaWx0ZXJlZCBjZWxscyBwZXIgc2FtcGxlIikgKwogIHhsYWIoIkNlbGwgbGluZXMiKSArICAjIEFkanVzdCB4LWF4aXMgbGFiZWwKICB5bGFiKCJGcmVxdWVuY3kiKSAgICAjIEFkanVzdCB5LWF4aXMgbGFiZWwKCnByaW50KG5jZWxscykKCgoKIyBURVNULTEKIyBnaXZlbiB0aGF0IHRoZSBvdXRwdXQgb2YgUnVuUENBIGlzICJwY2EiCiMgcmVwbGFjZSAic28iIGJ5IHRoZSBuYW1lIG9mIHlvdXIgc2V1cmF0IG9iamVjdAoKcGN0IDwtIEFsbF9zYW1wbGVzX01lcmdlZFtbInBjYSJdXUBzdGRldiAvIHN1bShBbGxfc2FtcGxlc19NZXJnZWRbWyJwY2EiXV1Ac3RkZXYpICogMTAwCmN1bXUgPC0gY3Vtc3VtKHBjdCkgIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwZXJjZW50cyBmb3IgZWFjaCBQQwojIERldGVybWluZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHZhcmlhdGlvbiBvZiBQQyBhbmQgc3Vic2VxdWVudCBQQwpjbzIgPC0gc29ydCh3aGljaCgocGN0Wy1sZW5ndGgocGN0KV0gLSBwY3RbLTFdKSA+IDAuMSksIGRlY3JlYXNpbmcgPSBUKVsxXSArIDEKIyBsYXN0IHBvaW50IHdoZXJlIGNoYW5nZSBvZiAlIG9mIHZhcmlhdGlvbiBpcyBtb3JlIHRoYW4gMC4xJS4gLT4gY28yCmNvMgoKIyBURVNULTIKIyBnZXQgc2lnbmlmaWNhbnQgUENzCnN0ZHYgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkW1sicGNhIl1dQHN0ZGV2CnN1bS5zdGR2IDwtIHN1bShBbGxfc2FtcGxlc19NZXJnZWRbWyJwY2EiXV1Ac3RkZXYpCnBlcmNlbnQuc3RkdiA8LSAoc3RkdiAvIHN1bS5zdGR2KSAqIDEwMApjdW11bGF0aXZlIDwtIGN1bXN1bShwZXJjZW50LnN0ZHYpCmNvMSA8LSB3aGljaChjdW11bGF0aXZlID4gOTAgJiBwZXJjZW50LnN0ZHYgPCA1KVsxXQpjbzIgPC0gc29ydCh3aGljaCgocGVyY2VudC5zdGR2WzE6bGVuZ3RoKHBlcmNlbnQuc3RkdikgLSAxXSAtIAogICAgICAgICAgICAgICAgICAgICAgIHBlcmNlbnQuc3RkdlsyOmxlbmd0aChwZXJjZW50LnN0ZHYpXSkgPiAwLjEpLCAKICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gVClbMV0gKyAxCm1pbi5wYyA8LSBtaW4oY28xLCBjbzIpCm1pbi5wYwoKIyBDcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCB2YWx1ZXMKcGxvdF9kZiA8LSBkYXRhLmZyYW1lKHBjdCA9IHBlcmNlbnQuc3RkdiwgCiAgICAgICAgICAgY3VtdSA9IGN1bXVsYXRpdmUsIAogICAgICAgICAgIHJhbmsgPSAxOmxlbmd0aChwZXJjZW50LnN0ZHYpKQoKIyBFbGJvdyBwbG90IHRvIHZpc3VhbGl6ZSAKICBnZ3Bsb3QocGxvdF9kZiwgYWVzKGN1bXVsYXRpdmUsIHBlcmNlbnQuc3RkdiwgbGFiZWwgPSByYW5rLCBjb2xvciA9IHJhbmsgPiBtaW4ucGMpKSArIAogIGdlb21fdGV4dCgpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGNvbG9yID0gImdyZXkiKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1pbihwZXJjZW50LnN0ZHZbcGVyY2VudC5zdGR2ID4gNV0pLCBjb2xvciA9ICJncmV5IikgKwogIHRoZW1lX2J3KCkKCiAgCgpgYGAKCiMgNy4gQ2x1c3RlcmluZwpgYGB7ciBDMSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CkFsbF9zYW1wbGVzX01lcmdlZCA8LSBGaW5kTmVpZ2hib3JzKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6MTMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKCiMgdW5kZXJzdGFuZGluZyByZXNvbHV0aW9uCkFsbF9zYW1wbGVzX01lcmdlZCA8LSBGaW5kQ2x1c3RlcnMoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbiA9IGMoMC4xLCAwLjIsIDAuMywgMC40LCAwLjUsIDAuNiwgMC43LDAuOCwgMC45LCAxLDEuMiwxLjUsMikpCgoKYGBgCgoKYGBge3IgQzIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBub24tbGluZWFyIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiAtLS0tLS0tLS0tLS0tLQpBbGxfc2FtcGxlc19NZXJnZWQgPC0gUnVuVU1BUChBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOjEzLAogICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoKIyBub3RlIHRoYXQgeW91IGNhbiBzZXQgYGxhYmVsID0gVFJVRWAgb3IgdXNlIHRoZSBMYWJlbCBDbHVzdGVycyBmdW5jdGlvbiB0byBoZWxwIGxhYmVsCiMgaW5kaXZpZHVhbCBjbHVzdGVycwpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCxncm91cC5ieSA9ICJjZWxsX2xpbmUiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4wLjEiLAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsIAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMC4yIiwKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULCAKICAgICAgICBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgIGdyb3VwLmJ5ID0gIlNDVF9zbm5fcmVzLjAuMyIsCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwgCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgIGdyb3VwLmJ5ID0gIlNDVF9zbm5fcmVzLjAuNCIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgIGdyb3VwLmJ5ID0gIlNDVF9zbm5fcmVzLjAuNSIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMC42IiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4wLjciLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgICAgIGdyb3VwLmJ5ID0gIlNDVF9zbm5fcmVzLjAuOCIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4wLjkiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMSIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4xLjIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMS41IiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwKICAgICAgICBncm91cC5ieSA9ICJTQ1Rfc25uX3Jlcy4yIiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgojIFNldCBpZGVudGl0eSBjbGFzc2VzIHRvIGFuIGV4aXN0aW5nIGNvbHVtbiBpbiBtZXRhIGRhdGEKSWRlbnRzKG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVF9zbm5fcmVzLjAuNyIKCmNsdXN0ZXJfdGFibGUgPC0gdGFibGUoSWRlbnRzKEFsbF9zYW1wbGVzX01lcmdlZCkpCgoKYmFycGxvdChjbHVzdGVyX3RhYmxlLCBtYWluID0gIk51bWJlciBvZiBDZWxscyBpbiBFYWNoIENsdXN0ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQ2x1c3RlciIsIAogICAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJOdW1iZXIgb2YgQ2VsbHMiLCAKICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHJhaW5ib3cobGVuZ3RoKGNsdXN0ZXJfdGFibGUpKSkKCnByaW50KGNsdXN0ZXJfdGFibGUpCgp0YWJsZShBbGxfc2FtcGxlc19NZXJnZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBBbGxfc2FtcGxlc19NZXJnZWQkU0NUX3Nubl9yZXMuMC4yKQpgYGAKCiMgOC4gY2x1c1RyZWUKYGBge3IgY2x1c1RyZWUsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xMH0KY2x1c3RyZWUoQWxsX3NhbXBsZXNfTWVyZ2VkLCBwcmVmaXggPSAiU0NUX3Nubl9yZXMuIikKYGBgCgojIDkuIEF6aW11dGggQW5ub3RhdGlvbgpgYGB7ciBhemltdXRoX0Fubm90YXRpb24yLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KIyBJbnN0YWxsRGF0YSgicGJtY3JlZiIpCiMgCiMgIyBUaGUgUnVuQXppbXV0aCBmdW5jdGlvbiBjYW4gdGFrZSBhIFNldXJhdCBvYmplY3QgYXMgaW5wdXQKIyBBbGxfc2FtcGxlc19NZXJnZWQgPC0gUnVuQXppbXV0aChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZmVyZW5jZSA9ICJwYm1jcmVmIikKCmBgYAoKIyAxMC4gQXppbXV0aCBWaXN1YWxpemF0aW9uCmBgYHtyIGF6aW11dGhfVmlzdWFsaXphdGlvbiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gRikKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gRikKCgpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgoKCnRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIsIEFsbF9zYW1wbGVzX01lcmdlZCRTQ1Rfc25uX3Jlcy4wLjcpCmBgYAoKIyAxMS5IYXJtb255IEludGVncmF0aW9uCmBgYHtyIGhhcm1vbnksIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdncGxvdDIpCgojIFJ1biBIYXJtb255LCBhZGp1c3RpbmcgZm9yIGJhdGNoIGVmZmVjdCB1c2luZyAiY2VsbF9saW5lIiBvciBhbm90aGVyIGdyb3VwaW5nIHZhcmlhYmxlCkFsbF9zYW1wbGVzX01lcmdlZCA8LSBSdW5IYXJtb255KAogIG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCwKICBncm91cC5ieS52YXJzID0gImNlbGxfbGluZSIsICAjIFJlcGxhY2Ugd2l0aCB0aGUgbWV0YWRhdGEgY29sdW1uIHNwZWNpZnlpbmcgYmF0Y2ggb3IgY2VsbCBsaW5lCiAgZGltcy51c2UgPSAxOjIyICAjIFVzZSB0aGUgc2FtZSBkaW1lbnNpb25zIGFzIFBDQQopCgojIENoZWNrIHJlc3VsdHMgaW4gaGFybW9ueSBlbWJlZGRpbmdzCmhhcm1vbnlfZW1iZWRkaW5ncyA8LSBFbWJlZGRpbmdzKEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gImhhcm1vbnkiKQpoZWFkKGhhcm1vbnlfZW1iZWRkaW5ncykKCgojIFJ1biBVTUFQIG9uIEhhcm1vbnkgZW1iZWRkaW5ncwpBbGxfc2FtcGxlc19NZXJnZWQgPC0gUnVuVU1BUChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJoYXJtb255IiwgZGltcyA9IDE6MjIpCgojIE9wdGlvbmFsbHksIGZpbmQgbmVpZ2hib3JzIGFuZCBjbHVzdGVycyAoaWYgeW91IHBsYW4gdG8gZG8gY2x1c3RlcmluZyBhbmFseXNpcykKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIEZpbmROZWlnaGJvcnMoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAiaGFybW9ueSIsIGRpbXMgPSAxOjIyKQpBbGxfc2FtcGxlc19NZXJnZWQgPC0gRmluZENsdXN0ZXJzKEFsbF9zYW1wbGVzX01lcmdlZCwgcmVzb2x1dGlvbiA9IDAuNSkgICMgQWRqdXN0IHJlc29sdXRpb24gYXMgbmVlZGVkCgojIFZpc3VhbGl6ZSBVTUFQCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImNlbGxfbGluZSIsIGxhYmVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuNSkgKyAKICAgIGdndGl0bGUoIlVNQVAgb2YgSGFybW9ueS1JbnRlZ3JhdGVkIERhdGEiKQoKCiMgVmlzdWFsaXplIFVNQVAgd2l0aCBiYXRjaC9jZWxsIGxpbmUgaW5mb3JtYXRpb24KRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwgbGFiZWwgPSBUUlVFLCBwdC5zaXplID0gMC41KSArIAogICAgZ2d0aXRsZSgiVU1BUCAtIENvbG9yZWQgYnkgQ2VsbCBMaW5lIChBZnRlciBIYXJtb255IEludGVncmF0aW9uKSIpCgoKIyBWaXN1YWxpemUgVU1BUCB3aXRoIGNsdXN0ZXJzCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuNSkgKyAKICAgIGdndGl0bGUoIlVNQVAgLSBDbHVzdGVyZWQgRGF0YSAoQWZ0ZXIgSGFybW9ueSBJbnRlZ3JhdGlvbikiKQoKIyBWaXN1YWxpemUgc3BlY2lmaWMgY2VsbCB0eXBlcyBvciBvdGhlciBtZXRhZGF0YQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUpICsgCiAgICBnZ3RpdGxlKCJVTUFQIC0gQ2VsbCBUeXBlcyBBZnRlciBIYXJtb255IEludGVncmF0aW9uIikKCgpgYGAKCgoKCiMgMTIuU2F2ZSB0aGUgU2V1cmF0IG9iamVjdCBhcyBhbiBSb2JqIGZpbGUKYGBge3Igc2F2ZVJPQkosIGVjaG89VFJVRX0KCnNhdmUoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmaWxlID0gIi4uLy4uLy4uLzAtSU1QLU9CSkVDVFMvQWxsX1NhbXBsZXNfTWVyZ2VkX3dpdGhfMTB4X0F6aXRtdXRoX0Fubm90YXRlZF9TQ1RfSFBDLnJvYmoiKQoKCmBgYAoKCgoKCgoK