1. load libraries

2. Load Seurat Object


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

All_samples_Merged <- filtered_seurat

All_samples_Merged
An object of class Seurat 
36752 features across 49372 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: 49372 
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    6007    6022    5148    5331    5171    3505 
# 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 49372 
cat("Dimensions of the RNA data layer:", dim(GetAssayData(All_samples_Merged, layer = "data")), "\n")
Dimensions of the RNA data layer: 36601 49372 
# 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 49372 

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')


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.mt")+
  geom_smooth(method = 'lm')


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

4. Data PREPARATION

options(future.globals.maxSize = 8000 * 1024^2)  # Set to 8000 MiB (about 8 GB)
# Data Preparation for Seurat v5
alldata <- All_samples_Merged

# Split the object by 'orig.ident' for individual dataset processing
alldata.list <- SplitObject(alldata, split.by = "orig.ident")

# Normalize and identify variable features for each dataset in the list
for (i in 1:length(alldata.list)) {
    alldata.list[[i]] <- SCTransform(alldata.list[[i]], vars.to.regress = c("percent.rb","percent.mt", "nCount_RNA"), verbose = FALSE)
    alldata.list[[i]] <- FindVariableFeatures(alldata.list[[i]], selection.method = "vst", nfeatures = 3000, verbose = FALSE)
}

# Get the variable genes for each dataset
hvgs_per_dataset <- lapply(alldata.list, VariableFeatures)

# Include the variable genes selected on the whole dataset
hvgs_per_dataset$all <- VariableFeatures(alldata)

# Create a heatmap to show overlap across datasets
temp <- unique(unlist(hvgs_per_dataset))
overlap <- sapply(hvgs_per_dataset, function(x) temp %in% x)
pheatmap::pheatmap(t(overlap * 1), cluster_rows = FALSE,
                   color = c("grey90", "grey20"))


# Select integration features across datasets
hvgs_all <- SelectIntegrationFeatures(alldata.list)
# Exclude specific genes
hvgs_all <- hvgs_all[!grepl("^HLA-|^XIST|^TRBV|^TRAV", hvgs_all)]

hvgs_per_dataset$all_ranks <- hvgs_all

# Generate the overlap heatmap for all selected integration features
temp <- unique(unlist(hvgs_per_dataset))
overlap <- sapply(hvgs_per_dataset, function(x) temp %in% x)
pheatmap::pheatmap(t(overlap * 1), cluster_rows = FALSE,
                   color = c("grey90", "grey20"))


# Scale and PCA on each dataset using selected integration features
alldata.list <- lapply(alldata.list, function(x) {
    x <- RunPCA(x, features = hvgs_all, verbose = FALSE)
})

5. rpca-integration


alldata.anchors <- FindIntegrationAnchors(object.list = alldata.list, dims = 1:20, reduction = "rpca", anchor.features = hvgs_all)
Scaling features for provided objects

  |                                                  | 0 % ~calculating  
  |++++++                                            | 11% ~04s          
  |++++++++++++                                      | 22% ~03s          
  |+++++++++++++++++                                 | 33% ~03s          
  |+++++++++++++++++++++++                           | 44% ~02s          
  |++++++++++++++++++++++++++++                      | 56% ~02s          
  |++++++++++++++++++++++++++++++++++                | 67% ~01s          
  |+++++++++++++++++++++++++++++++++++++++           | 78% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=04s  
Computing within dataset neighborhoods

  |                                                  | 0 % ~calculating  
  |++++++                                            | 11% ~10s          
  |++++++++++++                                      | 22% ~09s          
  |+++++++++++++++++                                 | 33% ~08s          
  |+++++++++++++++++++++++                           | 44% ~06s          
  |++++++++++++++++++++++++++++                      | 56% ~05s          
  |++++++++++++++++++++++++++++++++++                | 67% ~04s          
  |+++++++++++++++++++++++++++++++++++++++           | 78% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=10s  
Finding all pairwise anchors

  |                                                  | 0 % ~calculating  
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 463 anchors

  |++                                                | 3 % ~02m 57s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 326 anchors

  |+++                                               | 6 % ~02m 53s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 534 anchors

  |+++++                                             | 8 % ~02m 50s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 290 anchors

  |++++++                                            | 11% ~02m 45s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 561 anchors

  |+++++++                                           | 14% ~02m 41s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 840 anchors

  |+++++++++                                         | 17% ~02m 37s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 327 anchors

  |++++++++++                                        | 19% ~02m 31s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 538 anchors

  |++++++++++++                                      | 22% ~02m 26s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 847 anchors

  |+++++++++++++                                     | 25% ~02m 21s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1119 anchors

  |++++++++++++++                                    | 28% ~02m 16s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 351 anchors

  |++++++++++++++++                                  | 31% ~02m 10s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 470 anchors

  |+++++++++++++++++                                 | 33% ~02m 04s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 886 anchors

  |+++++++++++++++++++                               | 36% ~01m 59s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 588 anchors

  |++++++++++++++++++++                              | 39% ~01m 54s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 767 anchors

  |+++++++++++++++++++++                             | 42% ~01m 49s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 334 anchors

  |+++++++++++++++++++++++                           | 44% ~01m 43s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 505 anchors

  |++++++++++++++++++++++++                          | 47% ~01m 38s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 685 anchors

  |+++++++++++++++++++++++++                         | 50% ~01m 32s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 995 anchors

  |+++++++++++++++++++++++++++                       | 53% ~01m 27s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 1302 anchors

  |++++++++++++++++++++++++++++                      | 56% ~01m 22s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 899 anchors

  |++++++++++++++++++++++++++++++                    | 58% ~01m 17s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 201 anchors

  |+++++++++++++++++++++++++++++++                   | 61% ~01m 12s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 170 anchors

  |++++++++++++++++++++++++++++++++                  | 64% ~01m 06s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 164 anchors

  |++++++++++++++++++++++++++++++++++                | 67% ~01m 01s      
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 176 anchors

  |+++++++++++++++++++++++++++++++++++               | 69% ~56s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 224 anchors

  |+++++++++++++++++++++++++++++++++++++             | 72% ~50s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 246 anchors

  |++++++++++++++++++++++++++++++++++++++            | 75% ~45s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 183 anchors

  |+++++++++++++++++++++++++++++++++++++++           | 78% ~40s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 86 anchors

  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~35s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 119 anchors

  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~30s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 90 anchors

  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~25s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 65 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~20s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 103 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~15s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 66 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++  | 94% ~10s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 80 anchors

  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~05s          
Projecting new data onto SVD
Projecting new data onto SVD
Finding neighborhoods
Finding anchors
    Found 301 anchors

  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=02m 52s
alldata.int <- IntegrateData(anchorset = alldata.anchors, dims = 1:20, new.assay.name = "rpca")
Merging dataset 7 into 5
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 4 into 5 7
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 6 into 3
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 3 6 into 5 7 4
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 2 into 5 7 4 3 6
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 9 into 8
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 1 into 5 7 4 3 6 2
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULLMerging dataset 8 9 into 5 7 4 3 6 2 1
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Warning: Layer counts isn't present in the assay object; returning NULL
names(alldata.int@assays)
[1] "RNA"                          "ADT"                          "prediction.score.celltype.l1" "prediction.score.celltype.l2" "prediction.score.celltype.l3"
[6] "SCT"                          "rpca"                        
alldata.int@active.assay
[1] "rpca"
DefaultAssay(alldata.int) <- "rpca"

#Run Dimensionality reduction on integrated space
alldata.int <- ScaleData(alldata.int, verbose = FALSE)
alldata.int <- RunPCA(alldata.int, features = hvgs_all, reduction.name = "pca_rpca", do.print = TRUE, pcs.print = 1:5, genes.print = 15, verbose = FALSE)
alldata.int <- RunUMAP(alldata.int, reduction = "pca_rpca", reduction.name = "umap_rpca", dims = 1:20, 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
alldata.int <- RunTSNE(alldata.int, reduction = "pca_rpca", reduction.name = "tsne_rpca", dims = 1:20, verbose = FALSE)
alldata.int <- FindNeighbors(alldata.int, reduction = "pca_rpca", dims = 1:20, verbose = FALSE)
alldata.int <- FindClusters(alldata.int, resolution = 1.2, verbose = FALSE)



wrap_plots(

    DimPlot(alldata.int, reduction = "pca_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated"),

    DimPlot(alldata.int, reduction = "pca_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated"),
    ncol = 3) + plot_layout(guides = "collect")


    DimPlot(alldata.int, reduction = "pca_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated")

    DimPlot(alldata.int, reduction = "tsne_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated")

    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated")

    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")


    DimPlot(alldata.int, reduction = "pca_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated")

    DimPlot(alldata.int, reduction = "tsne_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated")

    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "rpca_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated")

    DimPlot(alldata.int, reduction = "umap_rpca", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")

clean memory

alldata.int@reductions$umap_raw = alldata@reductions$umap

# remove all objects that will not be used
rm(alldata,  alldata.anchors)

gc()

Marker Gene Visualization



# Set marker genes specific to requested immune cell types
myfeatures <- c("CD19", "CD79A", "MS4A1", # B cells
                "CD14", "LYZ", "FCGR3A", # Monocytes
                "CSF1R", "CD68", # Macrophages
                "NKG7", "GNLY", "KIR3DL1", # NK cells
                "MKI67", # Proliferating NK cells
                "CD34", "KIT", # HSPCs
                "CD3E", "CCR7", # T cells
                "SELL", "CD45RO", # Tnaive, Tcm
                "CD44", "CD45RA") # Tem, Temra

# # Visualize marker genes for RPCA
# FeaturePlot(alldata.int, features = myfeatures, reduction = "pca_rpca", ncol = 4) + 
#   ggtitle("Marker Gene Expression - RPCA Integration") +
#   NoLegend()

# Visualize marker genes for CCA
FeaturePlot(alldata.int, features = myfeatures, reduction = "umap_CCA", ncol = 4) + 
  ggtitle("Marker Gene Expression - CCA Integration") +
  NoLegend()

# Visualize marker genes for Harmony
FeaturePlot(alldata.int, features = myfeatures, reduction = "umap_harmony", ncol = 4) + 
  ggtitle("Marker Gene Expression - Harmony Integration") +
  NoLegend()

6. CCA-integration


alldata.anchors <- FindIntegrationAnchors(object.list = alldata.list, dims = 1:20, reduction = "cca", anchor.features = hvgs_all)

alldata.int <- IntegrateData(anchorset = alldata.anchors, dims = 1:20, new.assay.name = "CCA")

names(alldata.int@assays)

alldata.int@active.assay

DefaultAssay(alldata.int) <- "CCA"

#Run Dimensionality reduction on integrated space
alldata.int <- ScaleData(alldata.int, verbose = TRUE)
alldata.int <- RunPCA(alldata.int, features = hvgs_all, reduction.name = "pca_CCA", do.print = TRUE, pcs.print = 1:5, genes.print = 15, verbose = FALSE)
alldata.int <- RunUMAP(alldata.int, reduction = "pca_CCA", reduction.name = "umap_CCA", dims = 1:20, verbose = FALSE)
alldata.int <- RunTSNE(alldata.int, reduction = "pca_CCA",reduction.name = "tsne_CCA",dims = 1:20, verbose = FALSE)
alldata.int <- FindNeighbors(alldata.int, reduction = "pca_CCA", dims = 1:20, verbose = FALSE)
alldata.int <- FindClusters(alldata.int, resolution = 1.2, verbose = FALSE)



wrap_plots(

    DimPlot(alldata.int, reduction = "pca_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated"),

    DimPlot(alldata.int, reduction = "pca_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated"),
    ncol = 3) + plot_layout(guides = "collect")

    DimPlot(alldata.int, reduction = "pca_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated")
    DimPlot(alldata.int, reduction = "tsne_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated")
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated")
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")
    
    DimPlot(alldata.int, reduction = "pca_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated")
    DimPlot(alldata.int, reduction = "tsne_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated")
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "CCA_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated")
    DimPlot(alldata.int, reduction = "umap_CCA", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")

clean memory

# remove all objects that will not be used
rm(alldata.anchors)

gc()

7. Harmony-integration


alldata.int@active.assay = "RNA"
VariableFeatures(alldata.int) = hvgs_all
alldata.int = ScaleData(alldata.int, vars.to.regress = c("percent.mt", "nFeature_RNA"))
alldata.int = RunPCA(alldata.int, reduction.name = "pca_harmony")



alldata.int <- RunHarmony(
  alldata.int,
  group.by.vars = "orig.ident",
  reduction.use = "pca_harmony",
  theta =0.5,
  dims.use = 1:20,
  assay.use = "RNA")


alldata.int <- RunUMAP(alldata.int, dims = 1:20, reduction = "harmony", reduction.name = "umap_harmony")
alldata.int <- RunTSNE(alldata.int, dims = 1:20, reduction = "harmony", reduction.name = "tsne_harmony")
alldata.int <- FindNeighbors(alldata.int, reduction = "pca_harmony", dims = 1:20, verbose = FALSE)
alldata.int <- FindClusters(alldata.int, resolution = 1.2, verbose = FALSE)


 
 
 wrap_plots(

    DimPlot(alldata.int, reduction = "pca_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated"),

    DimPlot(alldata.int, reduction = "pca_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated"),
    DimPlot(alldata.int, reduction = "tsne_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated"),
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated"),
    ncol = 3) + plot_layout(guides = "collect")
 
    DimPlot(alldata.int, reduction = "pca_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("PCA integrated")
    DimPlot(alldata.int, reduction = "tsne_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("tSNE integrated")
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "orig.ident")+NoAxes()+ggtitle("UMAP integrated")
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")
    
    DimPlot(alldata.int, reduction = "pca_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("PCA integrated")
    DimPlot(alldata.int, reduction = "tsne_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("tSNE integrated")
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "RNA_snn_res.1.2")+NoAxes()+ggtitle("UMAP integrated")
    DimPlot(alldata.int, reduction = "umap_harmony", group.by = "predicted.celltype.l2")+NoAxes()+ggtitle("UMAP integrated")
    

8. Marker Gene Visualization



# Set marker genes specific to requested immune cell types
myfeatures <- c("CD19", "CD79A", "MS4A1", # B cells
                "CD14", "LYZ", "FCGR3A", # Monocytes
                "CSF1R", "CD68", # Macrophages
                "NKG7", "GNLY", "KIR3DL1", # NK cells
                "MKI67", # Proliferating NK cells
                "CD34", "KIT", # HSPCs
                "CD3E", "CCR7", # T cells
                "SELL", "CD45RO", # Tnaive, Tcm
                "CD44", "CD45RA") # Tem, Temra

# # Visualize marker genes for RPCA
# FeaturePlot(alldata.int, features = myfeatures, reduction = "pca_rpca", ncol = 4) + 
#   ggtitle("Marker Gene Expression - RPCA Integration") +
#   NoLegend()

# Visualize marker genes for CCA
FeaturePlot(alldata.int, features = myfeatures, reduction = "umap_CCA", ncol = 4) + 
  ggtitle("Marker Gene Expression - CCA Integration") +
  NoLegend()

# Visualize marker genes for Harmony
FeaturePlot(alldata.int, features = myfeatures, reduction = "umap_harmony", ncol = 4) + 
  ggtitle("Marker Gene Expression - Harmony Integration") +
  NoLegend()

9. Save the Seurat object as an Robj file


# save(All_samples_Merged_Harmony_Integrated, file = "All_samples_Merged_Harmony_Integrated.Robj")
LS0tCnRpdGxlOiAiUlBDQS1DQ0EtSGFybW9ueSBJbnRlZ3JhdGlvbiBvZiBQQk1DMTB4IHdpdGggU0NUIG9uIHNhbXBsZXMgcGFydDEiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KFNldXJhdERhdGEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZXRpY3VsYXRlKQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoUnRzbmUpCmxpYnJhcnkoaGFybW9ueSkKCmBgYAoKCgoKIyAyLiBMb2FkIFNldXJhdCBPYmplY3QgCmBgYHtyIGxvYWRfc2V1cmF0fQoKI0xvYWQgU2V1cmF0IE9iamVjdCBtZXJnZWQgZnJvbSBjZWxsIGxpbmVzIGFuZCBhIGNvbnRyb2woUEJNQykgYWZ0ZXIgZmlsdHJhdGlvbgpsb2FkKCIwLVJfT2JqZWN0cy9TU19DRDRfVGNlbGxzX0F6aW11dGhfQW5ub3RhdGVkX1BCTUMxMHhfZmluYWxfZm9yX1NDVF9hbmRfSW50ZWdyYXRpb24ucm9iaiIpCgpBbGxfc2FtcGxlc19NZXJnZWQgPC0gZmlsdGVyZWRfc2V1cmF0CgpBbGxfc2FtcGxlc19NZXJnZWQKCmBgYAojIyBTdW1tYXJpemluZyBTZXVyYXQgT2JqZWN0CmBgYHtyIHN1bW1hcnksIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCgojIERpc3BsYXkgYmFzaWMgbWV0YWRhdGEgc3VtbWFyeQpoZWFkKEFsbF9zYW1wbGVzX01lcmdlZEBtZXRhLmRhdGEpCgojIENoZWNrIGlmIGNvbHVtbnMgc3VjaCBhcyBgb3JpZy5pZGVudGAsIGBuQ291bnRfUk5BYCwgYG5GZWF0dXJlX1JOQWAsIGBuVU1JYCwgYG5nZW5lYCwgYW5kIGFueSBvdGhlciBuZWNlc3NhcnkgY29sdW1ucyBleGlzdApyZXF1aXJlZF9jb2x1bW5zIDwtIGMoIm9yaWcuaWRlbnQiLCAibkNvdW50X1JOQSIsICJuRmVhdHVyZV9STkEiLCAiblVNSSIsICJuZ2VuZSIpCm1pc3NpbmdfY29sdW1ucyA8LSBzZXRkaWZmKHJlcXVpcmVkX2NvbHVtbnMsIGNvbG5hbWVzKEFsbF9zYW1wbGVzX01lcmdlZEBtZXRhLmRhdGEpKQoKaWYgKGxlbmd0aChtaXNzaW5nX2NvbHVtbnMpID4gMCkgewogICAgY2F0KCJNaXNzaW5nIGNvbHVtbnM6IiwgcGFzdGUobWlzc2luZ19jb2x1bW5zLCBjb2xsYXBzZSA9ICIsICIpLCAiXG4iKQp9IGVsc2UgewogICAgY2F0KCJBbGwgcmVxdWlyZWQgY29sdW1ucyBhcmUgcHJlc2VudC5cbiIpCn0KCiMgQ2hlY2sgY2VsbCBjb3VudHMgYW5kIGZlYXR1cmVzCmNhdCgiTnVtYmVyIG9mIGNlbGxzOiIsIG5jb2woQWxsX3NhbXBsZXNfTWVyZ2VkKSwgIlxuIikKY2F0KCJOdW1iZXIgb2YgZmVhdHVyZXM6IiwgbnJvdyhBbGxfc2FtcGxlc19NZXJnZWQpLCAiXG4iKQoKIyBWZXJpZnkgdGhhdCBlYWNoIGBvcmlnLmlkZW50YCBsYWJlbCBoYXMgdGhlIGNvcnJlY3QgbnVtYmVyIG9mIGNlbGxzCmNhdCgiQ2VsbCBjb3VudHMgcGVyIGdyb3VwOlxuIikKcHJpbnQodGFibGUoQWxsX3NhbXBsZXNfTWVyZ2VkJG9yaWcuaWRlbnQpKQoKIyBDaGVjayB0aGF0IHRoZSBjZWxsIElEcyBhcmUgdW5pcXVlICh3aGljaCBlbnN1cmVzIG5vIGlzc3VlcyBmcm9tIG1lcmdpbmcpCmlmIChhbnkoZHVwbGljYXRlZChjb2xuYW1lcyhBbGxfc2FtcGxlc19NZXJnZWQpKSkpIHsKICAgIGNhdCgiV2FybmluZzogVGhlcmUgYXJlIGR1cGxpY2F0ZWQgY2VsbCBJRHMuXG4iKQp9IGVsc2UgewogICAgY2F0KCJDZWxsIElEcyBhcmUgdW5pcXVlLlxuIikKfQoKIyBDaGVjayB0aGUgYXNzYXkgY29uc2lzdGVuY3kgZm9yIFJOQQpEZWZhdWx0QXNzYXkoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAiUk5BIgoKIyBDaGVjayBkaW1lbnNpb25zIG9mIHRoZSBSTkEgY291bnRzIGxheWVyIHVzaW5nIHRoZSBuZXcgbWV0aG9kCmNhdCgiRGltZW5zaW9ucyBvZiB0aGUgUk5BIGNvdW50cyBsYXllcjoiLCBkaW0oR2V0QXNzYXlEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgbGF5ZXIgPSAiY291bnRzIikpLCAiXG4iKQpjYXQoIkRpbWVuc2lvbnMgb2YgdGhlIFJOQSBkYXRhIGxheWVyOiIsIGRpbShHZXRBc3NheURhdGEoQWxsX3NhbXBsZXNfTWVyZ2VkLCBsYXllciA9ICJkYXRhIikpLCAiXG4iKQoKIyBDaGVjayB0aGUgQURUIGFzc2F5IChvcHRpb25hbCkKaWYgKCJBRFQiICVpbiUgbmFtZXMoQWxsX3NhbXBsZXNfTWVyZ2VkQGFzc2F5cykpIHsKICAgIGNhdCgiQURUIGFzc2F5IGlzIHByZXNlbnQuXG4iKQogICAgY2F0KCJEaW1lbnNpb25zIG9mIHRoZSBBRFQgY291bnRzIGxheWVyOiIsIGRpbShHZXRBc3NheURhdGEoQWxsX3NhbXBsZXNfTWVyZ2VkLCBhc3NheSA9ICJBRFQiLCBsYXllciA9ICJjb3VudHMiKSksICJcbiIpCn0gZWxzZSB7CiAgICBjYXQoIkFEVCBhc3NheSBpcyBub3QgcHJlc2VudC5cbiIpCn0KCgpgYGAKIyAzLiBRQwpgYGB7ciBRQywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgojIFJlbW92ZSB0aGUgcGVyY2VudC5taXRvIGNvbHVtbgpBbGxfc2FtcGxlc19NZXJnZWQkcGVyY2VudC5taXRvIDwtIE5VTEwKCgojIFNldCBpZGVudGl0eSBjbGFzc2VzIHRvIGFuIGV4aXN0aW5nIGNvbHVtbiBpbiBtZXRhIGRhdGEKSWRlbnRzKG9iamVjdCA9IEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gImNlbGxfbGluZSIKCkFsbF9zYW1wbGVzX01lcmdlZFtbInBlcmNlbnQucmIiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl5SUFtTTF0iKQojIENvbnZlcnQgJ3BlcmNlbnQubXQnIHRvIG51bWVyaWMsIHJlcGxhY2luZyAiTmFOIiB3aXRoIDAKQWxsX3NhbXBsZXNfTWVyZ2VkJHBlcmNlbnQucmIgPC0gcmVwbGFjZShhcy5udW1lcmljKEFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50LnJiKSwgaXMubmEoQWxsX3NhbXBsZXNfTWVyZ2VkJHBlcmNlbnQucmIpLCAwKQoKCgojIFRoZSBbWyBvcGVyYXRvciBjYW4gYWRkIGNvbHVtbnMgdG8gb2JqZWN0IG1ldGFkYXRhLiBUaGlzIGlzIGEgZ3JlYXQgcGxhY2UgdG8gc3Rhc2ggUUMgc3RhdHMKQWxsX3NhbXBsZXNfTWVyZ2VkW1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChBbGxfc2FtcGxlc19NZXJnZWQsIHBhdHRlcm4gPSAiXk1ULSIpCgojIENvbnZlcnQgJ3BlcmNlbnQubXQnIHRvIG51bWVyaWMsIHJlcGxhY2luZyAiTmFOIiB3aXRoIDAKQWxsX3NhbXBsZXNfTWVyZ2VkJHBlcmNlbnQubXQgPC0gcmVwbGFjZShhcy5udW1lcmljKEFsbF9zYW1wbGVzX01lcmdlZCRwZXJjZW50Lm10KSwgaXMubmEoQWxsX3NhbXBsZXNfTWVyZ2VkJHBlcmNlbnQubXQpLCAwKQoKCgoKClZsblBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBlcmNlbnQubXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50LnJiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDQsIHB0LnNpemUgPSAwLjEpICYgCiAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkKCkZlYXR1cmVTY2F0dGVyKEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZTEgPSAicGVyY2VudC5tdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZTIgPSAicGVyY2VudC5yYiIpCgpWbG5QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5Db3VudF9STkEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBlcmNlbnQubXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJwZXJjZW50Lm10IiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gInBlcmNlbnQucmIiKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykKCkZlYXR1cmVTY2F0dGVyKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgIGZlYXR1cmUxID0gIm5Db3VudF9STkEiLCAKICAgICAgICAgICAgICAgZmVhdHVyZTIgPSAibkZlYXR1cmVfUk5BIikgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpgYGAKCiMjRmVhdHVyZVNjYXR0ZXIgaXMgdHlwaWNhbGx5IHVzZWQgdG8gdmlzdWFsaXplIGZlYXR1cmUtZmVhdHVyZSByZWxhdGlvbnNoaXBzCiMjZm9yIGFueXRoaW5nIGNhbGN1bGF0ZWQgYnkgdGhlIG9iamVjdCwgCiMjaS5lLiBjb2x1bW5zIGluIG9iamVjdCBtZXRhZGF0YSwgUEMgc2NvcmVzIGV0Yy4KCmBgYHtyIEZDLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkZlYXR1cmVTY2F0dGVyKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgIGZlYXR1cmUxID0gIm5Db3VudF9STkEiLCAKICAgICAgICAgICAgICAgZmVhdHVyZTIgPSAicGVyY2VudC5tdCIpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpGZWF0dXJlU2NhdHRlcihBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCgpgYGAKCgojIDQuIERhdGEgUFJFUEFSQVRJT04KYGBge3IgZGF0YSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9Cm9wdGlvbnMoZnV0dXJlLmdsb2JhbHMubWF4U2l6ZSA9IDgwMDAgKiAxMDI0XjIpICAjIFNldCB0byA4MDAwIE1pQiAoYWJvdXQgOCBHQikKIyBEYXRhIFByZXBhcmF0aW9uIGZvciBTZXVyYXQgdjUKYWxsZGF0YSA8LSBBbGxfc2FtcGxlc19NZXJnZWQKCiMgU3BsaXQgdGhlIG9iamVjdCBieSAnb3JpZy5pZGVudCcgZm9yIGluZGl2aWR1YWwgZGF0YXNldCBwcm9jZXNzaW5nCmFsbGRhdGEubGlzdCA8LSBTcGxpdE9iamVjdChhbGxkYXRhLCBzcGxpdC5ieSA9ICJvcmlnLmlkZW50IikKCiMgTm9ybWFsaXplIGFuZCBpZGVudGlmeSB2YXJpYWJsZSBmZWF0dXJlcyBmb3IgZWFjaCBkYXRhc2V0IGluIHRoZSBsaXN0CmZvciAoaSBpbiAxOmxlbmd0aChhbGxkYXRhLmxpc3QpKSB7CiAgICBhbGxkYXRhLmxpc3RbW2ldXSA8LSBTQ1RyYW5zZm9ybShhbGxkYXRhLmxpc3RbW2ldXSwgdmFycy50by5yZWdyZXNzID0gYygicGVyY2VudC5yYiIsInBlcmNlbnQubXQiLCAibkNvdW50X1JOQSIpLCB2ZXJib3NlID0gRkFMU0UpCiAgICBhbGxkYXRhLmxpc3RbW2ldXSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhhbGxkYXRhLmxpc3RbW2ldXSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAzMDAwLCB2ZXJib3NlID0gRkFMU0UpCn0KCiMgR2V0IHRoZSB2YXJpYWJsZSBnZW5lcyBmb3IgZWFjaCBkYXRhc2V0Cmh2Z3NfcGVyX2RhdGFzZXQgPC0gbGFwcGx5KGFsbGRhdGEubGlzdCwgVmFyaWFibGVGZWF0dXJlcykKCiMgSW5jbHVkZSB0aGUgdmFyaWFibGUgZ2VuZXMgc2VsZWN0ZWQgb24gdGhlIHdob2xlIGRhdGFzZXQKaHZnc19wZXJfZGF0YXNldCRhbGwgPC0gVmFyaWFibGVGZWF0dXJlcyhhbGxkYXRhKQoKIyBDcmVhdGUgYSBoZWF0bWFwIHRvIHNob3cgb3ZlcmxhcCBhY3Jvc3MgZGF0YXNldHMKdGVtcCA8LSB1bmlxdWUodW5saXN0KGh2Z3NfcGVyX2RhdGFzZXQpKQpvdmVybGFwIDwtIHNhcHBseShodmdzX3Blcl9kYXRhc2V0LCBmdW5jdGlvbih4KSB0ZW1wICVpbiUgeCkKcGhlYXRtYXA6OnBoZWF0bWFwKHQob3ZlcmxhcCAqIDEpLCBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gYygiZ3JleTkwIiwgImdyZXkyMCIpKQoKIyBTZWxlY3QgaW50ZWdyYXRpb24gZmVhdHVyZXMgYWNyb3NzIGRhdGFzZXRzCmh2Z3NfYWxsIDwtIFNlbGVjdEludGVncmF0aW9uRmVhdHVyZXMoYWxsZGF0YS5saXN0KQojIEV4Y2x1ZGUgc3BlY2lmaWMgZ2VuZXMKaHZnc19hbGwgPC0gaHZnc19hbGxbIWdyZXBsKCJeSExBLXxeWElTVHxeVFJCVnxeVFJBViIsIGh2Z3NfYWxsKV0KCmh2Z3NfcGVyX2RhdGFzZXQkYWxsX3JhbmtzIDwtIGh2Z3NfYWxsCgojIEdlbmVyYXRlIHRoZSBvdmVybGFwIGhlYXRtYXAgZm9yIGFsbCBzZWxlY3RlZCBpbnRlZ3JhdGlvbiBmZWF0dXJlcwp0ZW1wIDwtIHVuaXF1ZSh1bmxpc3QoaHZnc19wZXJfZGF0YXNldCkpCm92ZXJsYXAgPC0gc2FwcGx5KGh2Z3NfcGVyX2RhdGFzZXQsIGZ1bmN0aW9uKHgpIHRlbXAgJWluJSB4KQpwaGVhdG1hcDo6cGhlYXRtYXAodChvdmVybGFwICogMSksIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBjKCJncmV5OTAiLCAiZ3JleTIwIikpCgojIFNjYWxlIGFuZCBQQ0Egb24gZWFjaCBkYXRhc2V0IHVzaW5nIHNlbGVjdGVkIGludGVncmF0aW9uIGZlYXR1cmVzCmFsbGRhdGEubGlzdCA8LSBsYXBwbHkoYWxsZGF0YS5saXN0LCBmdW5jdGlvbih4KSB7CiAgICB4IDwtIFJ1blBDQSh4LCBmZWF0dXJlcyA9IGh2Z3NfYWxsLCB2ZXJib3NlID0gRkFMU0UpCn0pCgpgYGAKCgojIDUuIHJwY2EtaW50ZWdyYXRpb24KYGBge3IgaW50ZWdyYXRpb24tcnBjYSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgphbGxkYXRhLmFuY2hvcnMgPC0gRmluZEludGVncmF0aW9uQW5jaG9ycyhvYmplY3QubGlzdCA9IGFsbGRhdGEubGlzdCwgZGltcyA9IDE6MjAsIHJlZHVjdGlvbiA9ICJycGNhIiwgYW5jaG9yLmZlYXR1cmVzID0gaHZnc19hbGwpCgphbGxkYXRhLmludCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IGFsbGRhdGEuYW5jaG9ycywgZGltcyA9IDE6MjAsIG5ldy5hc3NheS5uYW1lID0gInJwY2EiKQoKbmFtZXMoYWxsZGF0YS5pbnRAYXNzYXlzKQoKYWxsZGF0YS5pbnRAYWN0aXZlLmFzc2F5CgpEZWZhdWx0QXNzYXkoYWxsZGF0YS5pbnQpIDwtICJycGNhIgoKI1J1biBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gb24gaW50ZWdyYXRlZCBzcGFjZQphbGxkYXRhLmludCA8LSBTY2FsZURhdGEoYWxsZGF0YS5pbnQsIHZlcmJvc2UgPSBGQUxTRSkKYWxsZGF0YS5pbnQgPC0gUnVuUENBKGFsbGRhdGEuaW50LCBmZWF0dXJlcyA9IGh2Z3NfYWxsLCByZWR1Y3Rpb24ubmFtZSA9ICJwY2FfcnBjYSIsIGRvLnByaW50ID0gVFJVRSwgcGNzLnByaW50ID0gMTo1LCBnZW5lcy5wcmludCA9IDE1LCB2ZXJib3NlID0gRkFMU0UpCmFsbGRhdGEuaW50IDwtIFJ1blVNQVAoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfcnBjYSIsIHJlZHVjdGlvbi5uYW1lID0gInVtYXBfcnBjYSIsIGRpbXMgPSAxOjIwLCB2ZXJib3NlID0gRkFMU0UpCgphbGxkYXRhLmludCA8LSBGaW5kTmVpZ2hib3JzKGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX3JwY2EiLCBkaW1zID0gMToyMCwgdmVyYm9zZSA9IEZBTFNFKQphbGxkYXRhLmludCA8LSBGaW5kQ2x1c3RlcnMoYWxsZGF0YS5pbnQsIHJlc29sdXRpb24gPSAwLjUsIHZlcmJvc2UgPSBGQUxTRSkKCgoKd3JhcF9wbG90cygKCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhIiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpK05vQXhlcygpK2dndGl0bGUoIlBDQSByYXdfZGF0YSIpLAogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCByYXdfZGF0YSIpLAoKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfcnBjYSIsIGdyb3VwLmJ5ID0gInJwY2Ffc25uX3Jlcy4wLjUiKStOb0F4ZXMoKStnZ3RpdGxlKCJQQ0FfaW50ZWdyYXRlZCIpLAogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfcnBjYSIsIGdyb3VwLmJ5ID0gInJwY2Ffc25uX3Jlcy4wLjUiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQX2ludGVncmF0ZWQiKSwKICAgIG5jb2wgPSAyKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikKCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX3JwY2EiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgiUENBIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfcnBjYSIsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfcnBjYSIsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpK05vQXhlcygpK2dndGl0bGUoIlVNQVAgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9ycGNhIiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX3JwY2EiLCBncm91cC5ieSA9ICJycGNhX3Nubl9yZXMuMC41IikrTm9BeGVzKCkrZ2d0aXRsZSgiUENBIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfcnBjYSIsIGdyb3VwLmJ5ID0gInJwY2Ffc25uX3Jlcy4wLjUiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfcnBjYSIsIGdyb3VwLmJ5ID0gInJwY2Ffc25uX3Jlcy4wLjUiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpK05vQXhlcygpK2dndGl0bGUoIlVNQVAgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9ycGNhIiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKCmBgYAoKIyBjbGVhbiBtZW1vcnkKYGBge3IgY2xlYW5NZW1vcnkxfQphbGxkYXRhLmludEByZWR1Y3Rpb25zJHVtYXBfcmF3ID0gYWxsZGF0YUByZWR1Y3Rpb25zJHVtYXAKCiMgcmVtb3ZlIGFsbCBvYmplY3RzIHRoYXQgd2lsbCBub3QgYmUgdXNlZApybShhbGxkYXRhLCAgYWxsZGF0YS5hbmNob3JzKQoKZ2MoKQpgYGAKCiMjIE1hcmtlciBHZW5lIFZpc3VhbGl6YXRpb24KYGBge3IgZmVhdHVyZXBsb3QtcnBjYSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgoKIyBTZXQgbWFya2VyIGdlbmVzIHNwZWNpZmljIHRvIHJlcXVlc3RlZCBpbW11bmUgY2VsbCB0eXBlcwpteWZlYXR1cmVzIDwtIGMoIkNEMTkiLCAiQ0Q3OUEiLCAiTVM0QTEiLCAjIEIgY2VsbHMKICAgICAgICAgICAgICAgICJDRDE0IiwgIkxZWiIsICJGQ0dSM0EiLCAjIE1vbm9jeXRlcwogICAgICAgICAgICAgICAgIkNTRjFSIiwgIkNENjgiLCAjIE1hY3JvcGhhZ2VzCiAgICAgICAgICAgICAgICAiTktHNyIsICJHTkxZIiwgIktJUjNETDEiLCAjIE5LIGNlbGxzCiAgICAgICAgICAgICAgICAiTUtJNjciLCAjIFByb2xpZmVyYXRpbmcgTksgY2VsbHMKICAgICAgICAgICAgICAgICJDRDM0IiwgIktJVCIsICMgSFNQQ3MKICAgICAgICAgICAgICAgICJDRDNFIiwgIkNDUjciLCAjIFQgY2VsbHMKICAgICAgICAgICAgICAgICJTRUxMIiwgIkNENDVSTyIsICMgVG5haXZlLCBUY20KICAgICAgICAgICAgICAgICJDRDQ0IiwgIkNENDVSQSIpICMgVGVtLCBUZW1yYQoKIyAjIFZpc3VhbGl6ZSBtYXJrZXIgZ2VuZXMgZm9yIFJQQ0EKIyBGZWF0dXJlUGxvdChhbGxkYXRhLmludCwgZmVhdHVyZXMgPSBteWZlYXR1cmVzLCByZWR1Y3Rpb24gPSAicGNhX3JwY2EiLCBuY29sID0gNCkgKyAKIyAgIGdndGl0bGUoIk1hcmtlciBHZW5lIEV4cHJlc3Npb24gLSBSUENBIEludGVncmF0aW9uIikgKwojICAgTm9MZWdlbmQoKQoKIyBWaXN1YWxpemUgbWFya2VyIGdlbmVzIGZvciBDQ0EKRmVhdHVyZVBsb3QoYWxsZGF0YS5pbnQsIGZlYXR1cmVzID0gbXlmZWF0dXJlcywgcmVkdWN0aW9uID0gInVtYXBfQ0NBIiwgbmNvbCA9IDQpICsgCiAgZ2d0aXRsZSgiTWFya2VyIEdlbmUgRXhwcmVzc2lvbiAtIENDQSBJbnRlZ3JhdGlvbiIpICsKICBOb0xlZ2VuZCgpCgojIFZpc3VhbGl6ZSBtYXJrZXIgZ2VuZXMgZm9yIEhhcm1vbnkKRmVhdHVyZVBsb3QoYWxsZGF0YS5pbnQsIGZlYXR1cmVzID0gbXlmZWF0dXJlcywgcmVkdWN0aW9uID0gInVtYXBfaGFybW9ueSIsIG5jb2wgPSA0KSArIAogIGdndGl0bGUoIk1hcmtlciBHZW5lIEV4cHJlc3Npb24gLSBIYXJtb255IEludGVncmF0aW9uIikgKwogIE5vTGVnZW5kKCkKCmBgYAoKCiMgNi4gQ0NBLWludGVncmF0aW9uCmBgYHtyIGludGVncmF0aW9uLUNDQSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgphbGxkYXRhLmFuY2hvcnMgPC0gRmluZEludGVncmF0aW9uQW5jaG9ycyhvYmplY3QubGlzdCA9IGFsbGRhdGEubGlzdCwgZGltcyA9IDE6MjAsIHJlZHVjdGlvbiA9ICJjY2EiLCBhbmNob3IuZmVhdHVyZXMgPSBodmdzX2FsbCkKCmFsbGRhdGEuaW50IDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gYWxsZGF0YS5hbmNob3JzLCBkaW1zID0gMToyMCwgbmV3LmFzc2F5Lm5hbWUgPSAiQ0NBIikKCm5hbWVzKGFsbGRhdGEuaW50QGFzc2F5cykKCmFsbGRhdGEuaW50QGFjdGl2ZS5hc3NheQoKRGVmYXVsdEFzc2F5KGFsbGRhdGEuaW50KSA8LSAiQ0NBIgoKI1J1biBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gb24gaW50ZWdyYXRlZCBzcGFjZQphbGxkYXRhLmludCA8LSBTY2FsZURhdGEoYWxsZGF0YS5pbnQsIHZlcmJvc2UgPSBUUlVFKQphbGxkYXRhLmludCA8LSBSdW5QQ0EoYWxsZGF0YS5pbnQsIGZlYXR1cmVzID0gaHZnc19hbGwsIHJlZHVjdGlvbi5uYW1lID0gInBjYV9DQ0EiLCBkby5wcmludCA9IFRSVUUsIHBjcy5wcmludCA9IDE6NSwgZ2VuZXMucHJpbnQgPSAxNSwgdmVyYm9zZSA9IEZBTFNFKQphbGxkYXRhLmludCA8LSBSdW5VTUFQKGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX0NDQSIsIHJlZHVjdGlvbi5uYW1lID0gInVtYXBfQ0NBIiwgZGltcyA9IDE6MjAsIHZlcmJvc2UgPSBGQUxTRSkKYWxsZGF0YS5pbnQgPC0gUnVuVFNORShhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInBjYV9DQ0EiLHJlZHVjdGlvbi5uYW1lID0gInRzbmVfQ0NBIixkaW1zID0gMToyMCwgdmVyYm9zZSA9IEZBTFNFKQphbGxkYXRhLmludCA8LSBGaW5kTmVpZ2hib3JzKGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX0NDQSIsIGRpbXMgPSAxOjIwLCB2ZXJib3NlID0gRkFMU0UpCmFsbGRhdGEuaW50IDwtIEZpbmRDbHVzdGVycyhhbGxkYXRhLmludCwgcmVzb2x1dGlvbiA9IDEuMiwgdmVyYm9zZSA9IEZBTFNFKQoKCgp3cmFwX3Bsb3RzKAoKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfQ0NBIiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpK05vQXhlcygpK2dndGl0bGUoIlBDQSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidHNuZV9DQ0EiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgidFNORSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9DQ0EiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIiksCgogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInBjYV9DQ0EiLCBncm91cC5ieSA9ICJDQ0Ffc25uX3Jlcy4xLjIiKStOb0F4ZXMoKStnZ3RpdGxlKCJQQ0EgaW50ZWdyYXRlZCIpLAogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInRzbmVfQ0NBIiwgZ3JvdXAuYnkgPSAiQ0NBX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgidFNORSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9DQ0EiLCBncm91cC5ieSA9ICJDQ0Ffc25uX3Jlcy4xLjIiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQIGludGVncmF0ZWQiKSwKICAgIG5jb2wgPSAzKSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikKCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX0NDQSIsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKStOb0F4ZXMoKStnZ3RpdGxlKCJQQ0EgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidHNuZV9DQ0EiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgidFNORSBpbnRlZ3JhdGVkIikKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJ1bWFwX0NDQSIsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfQ0NBIiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKICAgIAogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInBjYV9DQ0EiLCBncm91cC5ieSA9ICJDQ0Ffc25uX3Jlcy4xLjIiKStOb0F4ZXMoKStnZ3RpdGxlKCJQQ0EgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidHNuZV9DQ0EiLCBncm91cC5ieSA9ICJDQ0Ffc25uX3Jlcy4xLjIiKStOb0F4ZXMoKStnZ3RpdGxlKCJ0U05FIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInVtYXBfQ0NBIiwgZ3JvdXAuYnkgPSAiQ0NBX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJ1bWFwX0NDQSIsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIpK05vQXhlcygpK2dndGl0bGUoIlVNQVAgaW50ZWdyYXRlZCIpCmBgYAoKCiMgY2xlYW4gbWVtb3J5CmBgYHtyIGNsZWFuTWVtb3J5Mn0KIyByZW1vdmUgYWxsIG9iamVjdHMgdGhhdCB3aWxsIG5vdCBiZSB1c2VkCnJtKGFsbGRhdGEuYW5jaG9ycykKCmdjKCkKCgoKYGBgCgoKIyA3LiBIYXJtb255LWludGVncmF0aW9uCmBgYHtyIGludGVncmF0aW9uLWhhcm1vbnksIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKYWxsZGF0YS5pbnRAYWN0aXZlLmFzc2F5ID0gIlJOQSIKVmFyaWFibGVGZWF0dXJlcyhhbGxkYXRhLmludCkgPSBodmdzX2FsbAphbGxkYXRhLmludCA9IFNjYWxlRGF0YShhbGxkYXRhLmludCwgdmFycy50by5yZWdyZXNzID0gYygicGVyY2VudC5tdCIsICJuRmVhdHVyZV9STkEiKSkKYWxsZGF0YS5pbnQgPSBSdW5QQ0EoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbi5uYW1lID0gInBjYV9oYXJtb255IikKCgoKYWxsZGF0YS5pbnQgPC0gUnVuSGFybW9ueSgKICBhbGxkYXRhLmludCwKICBncm91cC5ieS52YXJzID0gIm9yaWcuaWRlbnQiLAogIHJlZHVjdGlvbi51c2UgPSAicGNhX2hhcm1vbnkiLAogIHRoZXRhID0wLjUsCiAgZGltcy51c2UgPSAxOjIwLAogIGFzc2F5LnVzZSA9ICJSTkEiKQoKCmFsbGRhdGEuaW50IDwtIFJ1blVNQVAoYWxsZGF0YS5pbnQsIGRpbXMgPSAxOjIwLCByZWR1Y3Rpb24gPSAiaGFybW9ueSIsIHJlZHVjdGlvbi5uYW1lID0gInVtYXBfaGFybW9ueSIpCmFsbGRhdGEuaW50IDwtIFJ1blRTTkUoYWxsZGF0YS5pbnQsIGRpbXMgPSAxOjIwLCByZWR1Y3Rpb24gPSAiaGFybW9ueSIsIHJlZHVjdGlvbi5uYW1lID0gInRzbmVfaGFybW9ueSIpCmFsbGRhdGEuaW50IDwtIEZpbmROZWlnaGJvcnMoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfaGFybW9ueSIsIGRpbXMgPSAxOjIwLCB2ZXJib3NlID0gRkFMU0UpCmFsbGRhdGEuaW50IDwtIEZpbmRDbHVzdGVycyhhbGxkYXRhLmludCwgcmVzb2x1dGlvbiA9IDEuMiwgdmVyYm9zZSA9IEZBTFNFKQoKCiAKIAogd3JhcF9wbG90cygKCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAicGNhX2hhcm1vbnkiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgiUENBIGludGVncmF0ZWQiKSwKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJ0c25lX2hhcm1vbnkiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikrTm9BeGVzKCkrZ2d0aXRsZSgidFNORSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpK05vQXhlcygpK2dndGl0bGUoIlVNQVAgaW50ZWdyYXRlZCIpLAoKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfaGFybW9ueSIsIGdyb3VwLmJ5ID0gIlJOQV9zbm5fcmVzLjEuMiIpK05vQXhlcygpK2dndGl0bGUoIlBDQSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidHNuZV9oYXJtb255IiwgZ3JvdXAuYnkgPSAiUk5BX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgidFNORSBpbnRlZ3JhdGVkIiksCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgZ3JvdXAuYnkgPSAiUk5BX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIiksCiAgICBuY29sID0gMykgKyBwbG90X2xheW91dChndWlkZXMgPSAiY29sbGVjdCIpCiAKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJwY2FfaGFybW9ueSIsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKStOb0F4ZXMoKStnZ3RpdGxlKCJQQ0EgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidHNuZV9oYXJtb255IiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpK05vQXhlcygpK2dndGl0bGUoInRTTkUgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpK05vQXhlcygpK2dndGl0bGUoIlVNQVAgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKICAgIAogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInBjYV9oYXJtb255IiwgZ3JvdXAuYnkgPSAiUk5BX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgiUENBIGludGVncmF0ZWQiKQogICAgRGltUGxvdChhbGxkYXRhLmludCwgcmVkdWN0aW9uID0gInRzbmVfaGFybW9ueSIsIGdyb3VwLmJ5ID0gIlJOQV9zbm5fcmVzLjEuMiIpK05vQXhlcygpK2dndGl0bGUoInRTTkUgaW50ZWdyYXRlZCIpCiAgICBEaW1QbG90KGFsbGRhdGEuaW50LCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgZ3JvdXAuYnkgPSAiUk5BX3Nubl9yZXMuMS4yIikrTm9BeGVzKCkrZ2d0aXRsZSgiVU1BUCBpbnRlZ3JhdGVkIikKICAgIERpbVBsb3QoYWxsZGF0YS5pbnQsIHJlZHVjdGlvbiA9ICJ1bWFwX2hhcm1vbnkiLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiKStOb0F4ZXMoKStnZ3RpdGxlKCJVTUFQIGludGVncmF0ZWQiKQogICAgCmBgYAoKCgoKCgoKCiMgOC4gTWFya2VyIEdlbmUgVmlzdWFsaXphdGlvbgpgYGB7ciBmZWF0dXJlcGxvdC1oYXJtb255LCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgojIFNldCBtYXJrZXIgZ2VuZXMgc3BlY2lmaWMgdG8gcmVxdWVzdGVkIGltbXVuZSBjZWxsIHR5cGVzCm15ZmVhdHVyZXMgPC0gYygiQ0QxOSIsICJDRDc5QSIsICJNUzRBMSIsICMgQiBjZWxscwogICAgICAgICAgICAgICAgIkNEMTQiLCAiTFlaIiwgIkZDR1IzQSIsICMgTW9ub2N5dGVzCiAgICAgICAgICAgICAgICAiQ1NGMVIiLCAiQ0Q2OCIsICMgTWFjcm9waGFnZXMKICAgICAgICAgICAgICAgICJOS0c3IiwgIkdOTFkiLCAiS0lSM0RMMSIsICMgTksgY2VsbHMKICAgICAgICAgICAgICAgICJNS0k2NyIsICMgUHJvbGlmZXJhdGluZyBOSyBjZWxscwogICAgICAgICAgICAgICAgIkNEMzQiLCAiS0lUIiwgIyBIU1BDcwogICAgICAgICAgICAgICAgIkNEM0UiLCAiQ0NSNyIsICMgVCBjZWxscwogICAgICAgICAgICAgICAgIlNFTEwiLCAiQ0Q0NVJPIiwgIyBUbmFpdmUsIFRjbQogICAgICAgICAgICAgICAgIkNENDQiLCAiQ0Q0NVJBIikgIyBUZW0sIFRlbXJhCgojICMgVmlzdWFsaXplIG1hcmtlciBnZW5lcyBmb3IgUlBDQQojIEZlYXR1cmVQbG90KGFsbGRhdGEuaW50LCBmZWF0dXJlcyA9IG15ZmVhdHVyZXMsIHJlZHVjdGlvbiA9ICJwY2FfcnBjYSIsIG5jb2wgPSA0KSArIAojICAgZ2d0aXRsZSgiTWFya2VyIEdlbmUgRXhwcmVzc2lvbiAtIFJQQ0EgSW50ZWdyYXRpb24iKSArCiMgICBOb0xlZ2VuZCgpCgojIFZpc3VhbGl6ZSBtYXJrZXIgZ2VuZXMgZm9yIENDQQpGZWF0dXJlUGxvdChhbGxkYXRhLmludCwgZmVhdHVyZXMgPSBteWZlYXR1cmVzLCByZWR1Y3Rpb24gPSAidW1hcF9DQ0EiLCBuY29sID0gNCkgKyAKICBnZ3RpdGxlKCJNYXJrZXIgR2VuZSBFeHByZXNzaW9uIC0gQ0NBIEludGVncmF0aW9uIikgKwogIE5vTGVnZW5kKCkKCiMgVmlzdWFsaXplIG1hcmtlciBnZW5lcyBmb3IgSGFybW9ueQpGZWF0dXJlUGxvdChhbGxkYXRhLmludCwgZmVhdHVyZXMgPSBteWZlYXR1cmVzLCByZWR1Y3Rpb24gPSAidW1hcF9oYXJtb255IiwgbmNvbCA9IDQpICsgCiAgZ2d0aXRsZSgiTWFya2VyIEdlbmUgRXhwcmVzc2lvbiAtIEhhcm1vbnkgSW50ZWdyYXRpb24iKSArCiAgTm9MZWdlbmQoKQoKYGBgCgoKIyA5LiBTYXZlIHRoZSBTZXVyYXQgb2JqZWN0IGFzIGFuIFJvYmogZmlsZQpgYGB7ciBzYXZlUk9CSn0KCiMgc2F2ZShBbGxfc2FtcGxlc19NZXJnZWRfSGFybW9ueV9JbnRlZ3JhdGVkLCBmaWxlID0gIkFsbF9zYW1wbGVzX01lcmdlZF9IYXJtb255X0ludGVncmF0ZWQuUm9iaiIpCgoKYGBgCgoKCgo=