1. load libraries

Load your objects


combined_merged <- readRDS("Poglio_Gaydosik_combined_merged_QCfiltered.rds")

2. QC


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


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

# Add percent ribosomal and mitochondrial content
combined_merged[["percent.rb"]] <- PercentageFeatureSet(combined_merged, pattern = "^RP[SL]")
combined_merged$percent.rb <- replace(as.numeric(combined_merged$percent.rb), is.na(combined_merged$percent.rb), 0)

combined_merged[["percent.mt"]] <- PercentageFeatureSet(combined_merged, pattern = "^MT-")
combined_merged$percent.mt <- replace(as.numeric(combined_merged$percent.mt), is.na(combined_merged$percent.mt), 0)

# ----------------------------
# Filter high `nCount_RNA` cells
# ----------------------------

# Define an upper threshold (e.g., top 0.5% or absolute cutoff)
ncount_thresh <- quantile(combined_merged$nCount_RNA, 0.995)  # top 0.5% outliers
message("Removing cells with nCount_RNA > ", round(ncount_thresh))

# Subset the object to remove both types of outliers
combined_merged <- subset(combined_merged, 
                          subset = nCount_RNA < ncount_thresh & percent.mt < 10)

# ----------------------------
# QC Plots (after filtering)
# ----------------------------

VlnPlot(combined_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(combined_merged, feature1 = "percent.mt", feature2 = "percent.rb")

FeatureScatter(combined_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(combined_merged, 
               feature1 = "nCount_RNA", 
               feature2 = "percent.mt")+
  geom_smooth(method = 'lm')

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

JoinLayers

Assign Cell-Cycle Scores

3. Normalize data

# Apply SCTransform
combined_merged <- SCTransform(combined_merged, 
                                  vars.to.regress = c("percent.rb","percent.mt","CC.Difference", "nCount_RNA"),
                                  assay = "RNA", 
                                  do.scale=TRUE, 
                                  do.center=TRUE, 
                                  verbose = TRUE)

4. Perform PCA


Variables_genes <- combined_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)]

# Set the seed for clustering steps
set.seed(123)

# These are now standard steps in the Seurat workflow for visualization and clustering
combined_merged <- RunPCA(combined_merged,
                        features = Variables_genes_after_exclusion,
                        do.print = TRUE, 
                        pcs.print = 1:5, 
                        genes.print = 15,
                        npcs = 50)

# determine dimensionality of the data
ElbowPlot(combined_merged, ndims = 50)

5. Perform PCA TEST



library(ggplot2)
library(RColorBrewer)  

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

# Assuming combined_merged$cell_line is a factor or character vector containing cell line names
data <- as.data.frame(table(combined_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 <- combined_merged[["pca"]]@stdev / sum(combined_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

# TEST-2
# get significant PCs
stdv <- combined_merged[["pca"]]@stdev
sum.stdv <- sum(combined_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

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

  

6. Clustering


# Set the seed for clustering steps
set.seed(123)

combined_merged <- FindNeighbors(combined_merged, 
                                dims = 1:min.pc, 
                                verbose = FALSE)

# understanding resolution
combined_merged <- FindClusters(combined_merged, 
                                    resolution = c(0.3, 0.4, 0.5, 0.6, 0.7,0.8, 0.9, 1, 1.2,1.5))

UMAP Visualization

# Set the seed for clustering steps
set.seed(123)

# non-linear dimensionality reduction --------------
combined_merged <- RunUMAP(combined_merged, 
                          dims = 1:min.pc,
                          verbose = FALSE)
                                  

# Define resolution values to plot
resolutions <- c(0.3, 0.4, 0.5, 0.6, 0.7,0.8, 0.9, 1, 1.2,1.5)

# Loop through and generate DimPlots
for (res in resolutions) {
  res_col <- paste0("SCT_snn_res.", res)
  
  p <- DimPlot(combined_merged,
               group.by = res_col,
               reduction = "umap",
               label.size = 3,
               repel = TRUE,
               label = TRUE,
               label.box = TRUE) +
       ggtitle(paste("Clustering resolution:", res))
  
  print(p)
}


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

cluster_table <- table(Idents(combined_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)

Save the Seurat object as an Robj file


saveRDS(combined_merged, file = "Poglio_Gaydosik_combined_merged_SCT_Normalized.rds")

7. clusTree

library(clustree)
clustree(combined_merged, prefix = "SCT_snn_res.")

8. Azimuth Annotation

InstallData("pbmcref")

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

9. Azimuth Visualization

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

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

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

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


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



table(combined_merged$predicted.celltype.l2, combined_merged$SCT_snn_res.0.4)

10. Harmony Integration



# Load required libraries
library(Seurat)
library(harmony)
library(ggplot2)

# Run Harmony, adjusting for batch effect using "cell_line" or another grouping variable
combined_merged <- RunHarmony(
  combined_merged,
  group.by.vars = c("batch"),  # Replace with the metadata column specifying batch or cell line
  assay.use="SCT")

# Check results in harmony embeddings
harmony_embeddings <- Embeddings(combined_merged, reduction = "harmony")
head(harmony_embeddings)

# Set the seed for clustering steps
set.seed(123)

# Run UMAP on Harmony embeddings
combined_merged <- RunUMAP(combined_merged, reduction = "harmony", dims = 1:16)

# Set the seed for clustering steps
set.seed(123)

# Optionally, find neighbors and clusters (if you plan to do clustering analysis)
combined_merged <- FindNeighbors(combined_merged, reduction = "harmony", dims = 1:16)
combined_merged <- FindClusters(combined_merged, reduction = "harmony", resolution = 0.5)  # Adjust resolution as needed

# Visualize UMAP
DimPlot(combined_merged, reduction = "umap", group.by = "batch", label = TRUE, pt.size = 0.5) +
    ggtitle("UMAP of Harmony-Integrated Data")


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


# Visualize UMAP with clusters
DimPlot(combined_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(combined_merged, reduction = "umap", group.by = "predicted.celltype.l2", label = TRUE, pt.size = 0.5) +
#     ggtitle("UMAP - Cell Types After Harmony Integration")

Save the Seurat object as an Robj file


saveRDS(combined_merged, file = "Poglio_Gaydosik_combined_merged_Harmonized.rds")
LS0tCnRpdGxlOiAiTWVyZ2luZyBQb2dsaW8gYW5kIEdheWRvc2lrIERhdGEiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCgotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3IgLCBpbmNsdWRlPUZBTFNFfQoKIyBBdCB0aGUgdG9wIG9mIHlvdXIgc2NyaXB0LCBjb21iaW5lIHBhY2thZ2VzIGxpa2UgdGhpczoKbGlicmFyeSh0aWR5dmVyc2UpICAgICAgIyBpbmNsdWRlcyBkcGx5ciwgZ2dwbG90MiwgdGliYmxlLCByZWFkciwgZXRjLgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGRpdHRvU2VxKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShTZXVyYXREaXNrKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodGlueXRleCkKbGlicmFyeShBemltdXRoKQpsaWJyYXJ5KFNUQUNBUykKbGlicmFyeShQcm9qZWNUSUxzKQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQoKYGBgCgoKIyMgTG9hZCB5b3VyIG9iamVjdHMKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQoKY29tYmluZWRfbWVyZ2VkIDwtIHJlYWRSRFMoIlBvZ2xpb19HYXlkb3Npa19jb21iaW5lZF9tZXJnZWRfUUNmaWx0ZXJlZC5yZHMiKQpgYGAKCiMgMi4gUUMKYGBge3IgUUMsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0fQoKIyBSZW1vdmUgdGhlIHBlcmNlbnQubWl0byBjb2x1bW4KY29tYmluZWRfbWVyZ2VkJHBlcmNlbnQubWl0byA8LSBOVUxMCgoKIyBTZXQgaWRlbnRpdHkgY2xhc3NlcyB0byBhbiBleGlzdGluZyBjb2x1bW4gaW4gbWV0YSBkYXRhCklkZW50cyhvYmplY3QgPSBjb21iaW5lZF9tZXJnZWQpIDwtICJiYXRjaCIKCiMgQWRkIHBlcmNlbnQgcmlib3NvbWFsIGFuZCBtaXRvY2hvbmRyaWFsIGNvbnRlbnQKY29tYmluZWRfbWVyZ2VkW1sicGVyY2VudC5yYiJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChjb21iaW5lZF9tZXJnZWQsIHBhdHRlcm4gPSAiXlJQW1NMXSIpCmNvbWJpbmVkX21lcmdlZCRwZXJjZW50LnJiIDwtIHJlcGxhY2UoYXMubnVtZXJpYyhjb21iaW5lZF9tZXJnZWQkcGVyY2VudC5yYiksIGlzLm5hKGNvbWJpbmVkX21lcmdlZCRwZXJjZW50LnJiKSwgMCkKCmNvbWJpbmVkX21lcmdlZFtbInBlcmNlbnQubXQiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoY29tYmluZWRfbWVyZ2VkLCBwYXR0ZXJuID0gIl5NVC0iKQpjb21iaW5lZF9tZXJnZWQkcGVyY2VudC5tdCA8LSByZXBsYWNlKGFzLm51bWVyaWMoY29tYmluZWRfbWVyZ2VkJHBlcmNlbnQubXQpLCBpcy5uYShjb21iaW5lZF9tZXJnZWQkcGVyY2VudC5tdCksIDApCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBGaWx0ZXIgaGlnaCBgbkNvdW50X1JOQWAgY2VsbHMKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIERlZmluZSBhbiB1cHBlciB0aHJlc2hvbGQgKGUuZy4sIHRvcCAwLjUlIG9yIGFic29sdXRlIGN1dG9mZikKbmNvdW50X3RocmVzaCA8LSBxdWFudGlsZShjb21iaW5lZF9tZXJnZWQkbkNvdW50X1JOQSwgMC45OTUpICAjIHRvcCAwLjUlIG91dGxpZXJzCm1lc3NhZ2UoIlJlbW92aW5nIGNlbGxzIHdpdGggbkNvdW50X1JOQSA+ICIsIHJvdW5kKG5jb3VudF90aHJlc2gpKQoKIyBTdWJzZXQgdGhlIG9iamVjdCB0byByZW1vdmUgYm90aCB0eXBlcyBvZiBvdXRsaWVycwpjb21iaW5lZF9tZXJnZWQgPC0gc3Vic2V0KGNvbWJpbmVkX21lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0ID0gbkNvdW50X1JOQSA8IG5jb3VudF90aHJlc2ggJiBwZXJjZW50Lm10IDwgMTApCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBRQyBQbG90cyAoYWZ0ZXIgZmlsdGVyaW5nKQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KClZsblBsb3QoY29tYmluZWRfbWVyZ2VkLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuQ291bnRfUk5BIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBlcmNlbnQubXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50LnJiIiksIAogICAgICAgIG5jb2wgPSA0LCBwdC5zaXplID0gMC4xKSAmIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpCgpGZWF0dXJlU2NhdHRlcihjb21iaW5lZF9tZXJnZWQsIGZlYXR1cmUxID0gInBlcmNlbnQubXQiLCBmZWF0dXJlMiA9ICJwZXJjZW50LnJiIikKCkZlYXR1cmVTY2F0dGVyKGNvbWJpbmVkX21lcmdlZCwgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKYGBgCgojI0ZlYXR1cmVTY2F0dGVyIGlzIHR5cGljYWxseSB1c2VkIHRvIHZpc3VhbGl6ZSBmZWF0dXJlLWZlYXR1cmUgcmVsYXRpb25zaGlwcwojI2ZvciBhbnl0aGluZyBjYWxjdWxhdGVkIGJ5IHRoZSBvYmplY3QsIAojI2kuZS4gY29sdW1ucyBpbiBvYmplY3QgbWV0YWRhdGEsIFBDIHNjb3JlcyBldGMuCgpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRmVhdHVyZVNjYXR0ZXIoY29tYmluZWRfbWVyZ2VkLCAKICAgICAgICAgICAgICAgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIAogICAgICAgICAgICAgICBmZWF0dXJlMiA9ICJwZXJjZW50Lm10IikrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykKCkZlYXR1cmVTY2F0dGVyKGNvbWJpbmVkX21lcmdlZCwgCiAgICAgICAgICAgICAgIGZlYXR1cmUxID0gIm5Db3VudF9STkEiLCAKICAgICAgICAgICAgICAgZmVhdHVyZTIgPSAibkZlYXR1cmVfUk5BIikrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykKCmBgYAoKIyMgIEpvaW5MYXllcnMKYGBge3IgLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgpEZWZhdWx0QXNzYXkoY29tYmluZWRfbWVyZ2VkKSA8LSAiUk5BIgoKIyBNZXJnZSBhbGwgY291bnRzLiogbGF5ZXJzIGludG8gYSBzaW5nbGUgY291bnRzIGxheWVyCmNvbWJpbmVkX21lcmdlZCA8LSBKb2luTGF5ZXJzKGNvbWJpbmVkX21lcmdlZCwgYXNzYXkgPSAiUk5BIikKCiMgQ29uZmlybSBsYXllcnMgbm93CkxheWVycyhjb21iaW5lZF9tZXJnZWRbWyJSTkEiXV0pCmBgYAoKIyMgIEFzc2lnbiBDZWxsLUN5Y2xlIFNjb3JlcwpgYGB7ciAsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKb3B0aW9ucyhmdXR1cmUuZ2xvYmFscy5tYXhTaXplID0gODAwMCAqIDEwMjReMikgICMgU2V0IHRvIDgwMDAgTWlCIChhYm91dCA4IEdCKQoKCmNvbWJpbmVkX21lcmdlZCA8LSBTQ1RyYW5zZm9ybShjb21iaW5lZF9tZXJnZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvLnNjYWxlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvLmNlbnRlciA9IEZBTFNFKSAgIyBSZWR1Y2UgdG8gMTAwMCB2YXJpYWJsZSBmZWF0dXJlcwoKCiMgQSBsaXN0IG9mIGNlbGwgY3ljbGUgbWFya2VycywgZnJvbSBUaXJvc2ggZXQgYWwsIDIwMTUsIGlzIGxvYWRlZCB3aXRoIFNldXJhdC4gIFdlIGNhbgojIHNlZ3JlZ2F0ZSB0aGlzIGxpc3QgaW50byBtYXJrZXJzIG9mIEcyL00gcGhhc2UgYW5kIG1hcmtlcnMgb2YgUyBwaGFzZQpzLmdlbmVzIDwtIGNjLmdlbmVzJHMuZ2VuZXMKZzJtLmdlbmVzIDwtIGNjLmdlbmVzJGcybS5nZW5lcwoKCmNvbWJpbmVkX21lcmdlZCA8LSBDZWxsQ3ljbGVTY29yaW5nKGNvbWJpbmVkX21lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMuZmVhdHVyZXMgPSBzLmdlbmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZzJtLmZlYXR1cmVzID0gZzJtLmdlbmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0LmlkZW50ID0gVFJVRSkKCkRlZmF1bHRBc3NheShjb21iaW5lZF9tZXJnZWQpIDwtICJSTkEiCmNvbWJpbmVkX21lcmdlZCRDQy5EaWZmZXJlbmNlIDwtIGNvbWJpbmVkX21lcmdlZCRTLlNjb3JlIC0gY29tYmluZWRfbWVyZ2VkJEcyTS5TY29yZQoKYGBgCgoKIyAzLiBOb3JtYWxpemUgZGF0YQpgYGB7ciBTQ1ROb3JtYWxpemUsIGluY2x1ZGU9VFJVRX0KIyBBcHBseSBTQ1RyYW5zZm9ybQpjb21iaW5lZF9tZXJnZWQgPC0gU0NUcmFuc2Zvcm0oY29tYmluZWRfbWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcnMudG8ucmVncmVzcyA9IGMoInBlcmNlbnQucmIiLCJwZXJjZW50Lm10IiwiQ0MuRGlmZmVyZW5jZSIsICJuQ291bnRfUk5BIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJSTkEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvLnNjYWxlPVRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG8uY2VudGVyPVRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUpCmBgYAoKCiMgNC4gUGVyZm9ybSBQQ0EKYGBge3IgUENBLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KClZhcmlhYmxlc19nZW5lcyA8LSBjb21iaW5lZF9tZXJnZWRAYXNzYXlzJFNDVEB2YXIuZmVhdHVyZXMKCiMgRXhjbHVkZSBnZW5lcyBzdGFydGluZyB3aXRoICJITEEtIiBBTkQgIlhpc3QiIEFORCAiVFJCViwgVFJBViIKVmFyaWFibGVzX2dlbmVzX2FmdGVyX2V4Y2x1c2lvbiA8LSBWYXJpYWJsZXNfZ2VuZXNbIWdyZXBsKCJeSExBLXxeWElTVHxeVFJCVnxeVFJBViIsIFZhcmlhYmxlc19nZW5lcyldCgojIFNldCB0aGUgc2VlZCBmb3IgY2x1c3RlcmluZyBzdGVwcwpzZXQuc2VlZCgxMjMpCgojIFRoZXNlIGFyZSBub3cgc3RhbmRhcmQgc3RlcHMgaW4gdGhlIFNldXJhdCB3b3JrZmxvdyBmb3IgdmlzdWFsaXphdGlvbiBhbmQgY2x1c3RlcmluZwpjb21iaW5lZF9tZXJnZWQgPC0gUnVuUENBKGNvbWJpbmVkX21lcmdlZCwKICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBWYXJpYWJsZXNfZ2VuZXNfYWZ0ZXJfZXhjbHVzaW9uLAogICAgICAgICAgICAgICAgICAgICAgICBkby5wcmludCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBwY3MucHJpbnQgPSAxOjUsIAogICAgICAgICAgICAgICAgICAgICAgICBnZW5lcy5wcmludCA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICBucGNzID0gNTApCgojIGRldGVybWluZSBkaW1lbnNpb25hbGl0eSBvZiB0aGUgZGF0YQpFbGJvd1Bsb3QoY29tYmluZWRfbWVyZ2VkLCBuZGltcyA9IDUwKQpgYGAKCiMgNS4gUGVyZm9ybSBQQ0EgVEVTVApgYGB7ciBQQ0EtVEVTVCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikgIAoKIyBBc3N1bWluZyB5b3UgaGF2ZSAxMCBkaWZmZXJlbnQgY2VsbCBsaW5lcywgZ2VuZXJhdGluZyBhIGNvbG9yIHBhbGV0dGUgd2l0aCAxMCBjb2xvcnMKY2VsbF9saW5lX2NvbG9ycyA8LSBicmV3ZXIucGFsKDEwLCAiU2V0MyIpCgojIEFzc3VtaW5nIGNvbWJpbmVkX21lcmdlZCRjZWxsX2xpbmUgaXMgYSBmYWN0b3Igb3IgY2hhcmFjdGVyIHZlY3RvciBjb250YWluaW5nIGNlbGwgbGluZSBuYW1lcwpkYXRhIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoY29tYmluZWRfbWVyZ2VkJGNlbGxfbGluZSkpCmNvbG5hbWVzKGRhdGEpIDwtIGMoImNlbGxfbGluZSIsICJuVU1JIikgICMgQ2hhbmdlIGNvbHVtbiBuYW1lIHRvIG5VTUkKCm5jZWxscyA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBjZWxsX2xpbmUsIHkgPSBuVU1JLCBmaWxsID0gY2VsbF9saW5lKSkgKyAKICBnZW9tX2NvbCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuVU1JKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCAKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNlbGxfbGluZV9jb2xvcnMpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKyAgIyBBZGp1c3QgdGhlIHRpdGxlIHBvc2l0aW9uCiAgZ2d0aXRsZSgiRmlsdGVyZWQgY2VsbHMgcGVyIHNhbXBsZSIpICsKICB4bGFiKCJDZWxsIGxpbmVzIikgKyAgIyBBZGp1c3QgeC1heGlzIGxhYmVsCiAgeWxhYigiRnJlcXVlbmN5IikgICAgIyBBZGp1c3QgeS1heGlzIGxhYmVsCgpwcmludChuY2VsbHMpCgoKCiMgVEVTVC0xCiMgZ2l2ZW4gdGhhdCB0aGUgb3V0cHV0IG9mIFJ1blBDQSBpcyAicGNhIgojIHJlcGxhY2UgInNvIiBieSB0aGUgbmFtZSBvZiB5b3VyIHNldXJhdCBvYmplY3QKCnBjdCA8LSBjb21iaW5lZF9tZXJnZWRbWyJwY2EiXV1Ac3RkZXYgLyBzdW0oY29tYmluZWRfbWVyZ2VkW1sicGNhIl1dQHN0ZGV2KSAqIDEwMApjdW11IDwtIGN1bXN1bShwY3QpICMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcGVyY2VudHMgZm9yIGVhY2ggUEMKIyBEZXRlcm1pbmUgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB2YXJpYXRpb24gb2YgUEMgYW5kIHN1YnNlcXVlbnQgUEMKY28yIDwtIHNvcnQod2hpY2goKHBjdFstbGVuZ3RoKHBjdCldIC0gcGN0Wy0xXSkgPiAwLjEpLCBkZWNyZWFzaW5nID0gVClbMV0gKyAxCiMgbGFzdCBwb2ludCB3aGVyZSBjaGFuZ2Ugb2YgJSBvZiB2YXJpYXRpb24gaXMgbW9yZSB0aGFuIDAuMSUuIC0+IGNvMgpjbzIKCiMgVEVTVC0yCiMgZ2V0IHNpZ25pZmljYW50IFBDcwpzdGR2IDwtIGNvbWJpbmVkX21lcmdlZFtbInBjYSJdXUBzdGRldgpzdW0uc3RkdiA8LSBzdW0oY29tYmluZWRfbWVyZ2VkW1sicGNhIl1dQHN0ZGV2KQpwZXJjZW50LnN0ZHYgPC0gKHN0ZHYgLyBzdW0uc3RkdikgKiAxMDAKY3VtdWxhdGl2ZSA8LSBjdW1zdW0ocGVyY2VudC5zdGR2KQpjbzEgPC0gd2hpY2goY3VtdWxhdGl2ZSA+IDkwICYgcGVyY2VudC5zdGR2IDwgNSlbMV0KY28yIDwtIHNvcnQod2hpY2goKHBlcmNlbnQuc3RkdlsxOmxlbmd0aChwZXJjZW50LnN0ZHYpIC0gMV0gLSAKICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50LnN0ZHZbMjpsZW5ndGgocGVyY2VudC5zdGR2KV0pID4gMC4xKSwgCiAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFQpWzFdICsgMQptaW4ucGMgPC0gbWluKGNvMSwgY28yKQptaW4ucGMKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdmFsdWVzCnBsb3RfZGYgPC0gZGF0YS5mcmFtZShwY3QgPSBwZXJjZW50LnN0ZHYsIAogICAgICAgICAgIGN1bXUgPSBjdW11bGF0aXZlLCAKICAgICAgICAgICByYW5rID0gMTpsZW5ndGgocGVyY2VudC5zdGR2KSkKCiMgRWxib3cgcGxvdCB0byB2aXN1YWxpemUgCiAgZ2dwbG90KHBsb3RfZGYsIGFlcyhjdW11bGF0aXZlLCBwZXJjZW50LnN0ZHYsIGxhYmVsID0gcmFuaywgY29sb3IgPSByYW5rID4gbWluLnBjKSkgKyAKICBnZW9tX3RleHQoKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwLCBjb2xvciA9ICJncmV5IikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtaW4ocGVyY2VudC5zdGR2W3BlcmNlbnQuc3RkdiA+IDVdKSwgY29sb3IgPSAiZ3JleSIpICsKICB0aGVtZV9idygpCgogIAoKYGBgCgojIDYuIENsdXN0ZXJpbmcKYGBge3IgQzEsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBTZXQgdGhlIHNlZWQgZm9yIGNsdXN0ZXJpbmcgc3RlcHMKc2V0LnNlZWQoMTIzKQoKY29tYmluZWRfbWVyZ2VkIDwtIEZpbmROZWlnaGJvcnMoY29tYmluZWRfbWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gMTptaW4ucGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKCiMgdW5kZXJzdGFuZGluZyByZXNvbHV0aW9uCmNvbWJpbmVkX21lcmdlZCA8LSBGaW5kQ2x1c3RlcnMoY29tYmluZWRfbWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbiA9IGMoMC4zLCAwLjQsIDAuNSwgMC42LCAwLjcsMC44LCAwLjksIDEsIDEuMiwxLjUpKQoKCmBgYAoKIyMgVU1BUCBWaXN1YWxpemF0aW9uCmBgYHtyIEMyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KIyBTZXQgdGhlIHNlZWQgZm9yIGNsdXN0ZXJpbmcgc3RlcHMKc2V0LnNlZWQoMTIzKQoKIyBub24tbGluZWFyIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiAtLS0tLS0tLS0tLS0tLQpjb21iaW5lZF9tZXJnZWQgPC0gUnVuVU1BUChjb21iaW5lZF9tZXJnZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOm1pbi5wYywKICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCiMgRGVmaW5lIHJlc29sdXRpb24gdmFsdWVzIHRvIHBsb3QKcmVzb2x1dGlvbnMgPC0gYygwLjMsIDAuNCwgMC41LCAwLjYsIDAuNywwLjgsIDAuOSwgMSwgMS4yLDEuNSkKCiMgTG9vcCB0aHJvdWdoIGFuZCBnZW5lcmF0ZSBEaW1QbG90cwpmb3IgKHJlcyBpbiByZXNvbHV0aW9ucykgewogIHJlc19jb2wgPC0gcGFzdGUwKCJTQ1Rfc25uX3Jlcy4iLCByZXMpCiAgCiAgcCA8LSBEaW1QbG90KGNvbWJpbmVkX21lcmdlZCwKICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSByZXNfY29sLAogICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgICAgICAgIGxhYmVsID0gVFJVRSwKICAgICAgICAgICAgICAgbGFiZWwuYm94ID0gVFJVRSkgKwogICAgICAgZ2d0aXRsZShwYXN0ZSgiQ2x1c3RlcmluZyByZXNvbHV0aW9uOiIsIHJlcykpCiAgCiAgcHJpbnQocCkKfQoKCiMgU2V0IGlkZW50aXR5IGNsYXNzZXMgdG8gYW4gZXhpc3RpbmcgY29sdW1uIGluIG1ldGEgZGF0YQpJZGVudHMob2JqZWN0ID0gY29tYmluZWRfbWVyZ2VkKSA8LSAiU0NUX3Nubl9yZXMuMC40IgoKY2x1c3Rlcl90YWJsZSA8LSB0YWJsZShJZGVudHMoY29tYmluZWRfbWVyZ2VkKSkKCgpiYXJwbG90KGNsdXN0ZXJfdGFibGUsIG1haW4gPSAiTnVtYmVyIG9mIENlbGxzIGluIEVhY2ggQ2x1c3RlciIsIAogICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJDbHVzdGVyIiwgCiAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gIk51bWJlciBvZiBDZWxscyIsIAogICAgICAgICAgICAgICAgICAgICAgY29sID0gcmFpbmJvdyhsZW5ndGgoY2x1c3Rlcl90YWJsZSkpKQoKcHJpbnQoY2x1c3Rlcl90YWJsZSkKCmBgYAoKCiMjIFNhdmUgdGhlIFNldXJhdCBvYmplY3QgYXMgYW4gUm9iaiBmaWxlCmBgYHtyLCBlY2hvPVRSVUV9CgpzYXZlUkRTKGNvbWJpbmVkX21lcmdlZCwgZmlsZSA9ICJQb2dsaW9fR2F5ZG9zaWtfY29tYmluZWRfbWVyZ2VkX1NDVF9Ob3JtYWxpemVkLnJkcyIpCgpgYGAKCiMgNy4gY2x1c1RyZWUKYGBge3IgY2x1c1RyZWUsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xMH0KbGlicmFyeShjbHVzdHJlZSkKY2x1c3RyZWUoY29tYmluZWRfbWVyZ2VkLCBwcmVmaXggPSAiU0NUX3Nubl9yZXMuIikKYGBgCgojIDguIEF6aW11dGggQW5ub3RhdGlvbgpgYGB7ciBhemltdXRoX0Fubm90YXRpb24yLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KSW5zdGFsbERhdGEoInBibWNyZWYiKQoKIyBUaGUgUnVuQXppbXV0aCBmdW5jdGlvbiBjYW4gdGFrZSBhIFNldXJhdCBvYmplY3QgYXMgaW5wdXQKY29tYmluZWRfbWVyZ2VkIDwtIFJ1bkF6aW11dGgoY29tYmluZWRfbWVyZ2VkLCByZWZlcmVuY2UgPSAicGJtY3JlZiIpCgpgYGAKCiMgOS4gQXppbXV0aCBWaXN1YWxpemF0aW9uCmBgYHtyIGF6aW11dGhfVmlzdWFsaXphdGlvbiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CkRpbVBsb3QoY29tYmluZWRfbWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoY29tYmluZWRfbWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDEiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gRikKCkRpbVBsb3QoY29tYmluZWRfbWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCkRpbVBsb3QoY29tYmluZWRfbWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gRikKCgpEaW1QbG90KGNvbWJpbmVkX21lcmdlZCwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IEYpCgoKCnRhYmxlKGNvbWJpbmVkX21lcmdlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIsIGNvbWJpbmVkX21lcmdlZCRTQ1Rfc25uX3Jlcy4wLjQpCgpgYGAKCgojIDEwLiBIYXJtb255IEludGVncmF0aW9uCmBgYHtyIGhhcm1vbnksIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKCiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoaGFybW9ueSkKbGlicmFyeShnZ3Bsb3QyKQoKIyBSdW4gSGFybW9ueSwgYWRqdXN0aW5nIGZvciBiYXRjaCBlZmZlY3QgdXNpbmcgImNlbGxfbGluZSIgb3IgYW5vdGhlciBncm91cGluZyB2YXJpYWJsZQpjb21iaW5lZF9tZXJnZWQgPC0gUnVuSGFybW9ueSgKICBjb21iaW5lZF9tZXJnZWQsCiAgZ3JvdXAuYnkudmFycyA9IGMoImJhdGNoIiksICAjIFJlcGxhY2Ugd2l0aCB0aGUgbWV0YWRhdGEgY29sdW1uIHNwZWNpZnlpbmcgYmF0Y2ggb3IgY2VsbCBsaW5lCiAgYXNzYXkudXNlPSJTQ1QiKQoKIyBDaGVjayByZXN1bHRzIGluIGhhcm1vbnkgZW1iZWRkaW5ncwpoYXJtb255X2VtYmVkZGluZ3MgPC0gRW1iZWRkaW5ncyhjb21iaW5lZF9tZXJnZWQsIHJlZHVjdGlvbiA9ICJoYXJtb255IikKaGVhZChoYXJtb255X2VtYmVkZGluZ3MpCgojIFNldCB0aGUgc2VlZCBmb3IgY2x1c3RlcmluZyBzdGVwcwpzZXQuc2VlZCgxMjMpCgojIFJ1biBVTUFQIG9uIEhhcm1vbnkgZW1iZWRkaW5ncwpjb21iaW5lZF9tZXJnZWQgPC0gUnVuVU1BUChjb21iaW5lZF9tZXJnZWQsIHJlZHVjdGlvbiA9ICJoYXJtb255IiwgZGltcyA9IDE6MTYpCgojIFNldCB0aGUgc2VlZCBmb3IgY2x1c3RlcmluZyBzdGVwcwpzZXQuc2VlZCgxMjMpCgojIE9wdGlvbmFsbHksIGZpbmQgbmVpZ2hib3JzIGFuZCBjbHVzdGVycyAoaWYgeW91IHBsYW4gdG8gZG8gY2x1c3RlcmluZyBhbmFseXNpcykKY29tYmluZWRfbWVyZ2VkIDwtIEZpbmROZWlnaGJvcnMoY29tYmluZWRfbWVyZ2VkLCByZWR1Y3Rpb24gPSAiaGFybW9ueSIsIGRpbXMgPSAxOjE2KQpjb21iaW5lZF9tZXJnZWQgPC0gRmluZENsdXN0ZXJzKGNvbWJpbmVkX21lcmdlZCwgcmVkdWN0aW9uID0gImhhcm1vbnkiLCByZXNvbHV0aW9uID0gMC41KSAgIyBBZGp1c3QgcmVzb2x1dGlvbiBhcyBuZWVkZWQKCiMgVmlzdWFsaXplIFVNQVAKRGltUGxvdChjb21iaW5lZF9tZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiYmF0Y2giLCBsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUpICsKICAgIGdndGl0bGUoIlVNQVAgb2YgSGFybW9ueS1JbnRlZ3JhdGVkIERhdGEiKQoKCiMgVmlzdWFsaXplIFVNQVAgd2l0aCBiYXRjaC9jZWxsIGxpbmUgaW5mb3JtYXRpb24KRGltUGxvdChjb21iaW5lZF9tZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiYmF0Y2giLCBsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUpICsKICAgIGdndGl0bGUoIlVNQVAgLSBDb2xvcmVkIGJ5IENlbGwgTGluZSAoQWZ0ZXIgSGFybW9ueSBJbnRlZ3JhdGlvbikiKQoKCiMgVmlzdWFsaXplIFVNQVAgd2l0aCBjbHVzdGVycwpEaW1QbG90KGNvbWJpbmVkX21lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUpICsKICAgIGdndGl0bGUoIlVNQVAgLSBDbHVzdGVyZWQgRGF0YSAoQWZ0ZXIgSGFybW9ueSBJbnRlZ3JhdGlvbikiKQoKIyAjIFZpc3VhbGl6ZSBzcGVjaWZpYyBjZWxsIHR5cGVzIG9yIG90aGVyIG1ldGFkYXRhCiMgRGltUGxvdChjb21iaW5lZF9tZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAicHJlZGljdGVkLmNlbGx0eXBlLmwyIiwgbGFiZWwgPSBUUlVFLCBwdC5zaXplID0gMC41KSArCiMgICAgIGdndGl0bGUoIlVNQVAgLSBDZWxsIFR5cGVzIEFmdGVyIEhhcm1vbnkgSW50ZWdyYXRpb24iKQoKCgpgYGAKCgojIyBTYXZlIHRoZSBTZXVyYXQgb2JqZWN0IGFzIGFuIFJvYmogZmlsZQpgYGB7ciwgZWNobz1UUlVFfQoKc2F2ZVJEUyhjb21iaW5lZF9tZXJnZWQsIGZpbGUgPSAiUG9nbGlvX0dheWRvc2lrX2NvbWJpbmVkX21lcmdlZF9IYXJtb25pemVkLnJkcyIpCgpgYGAKCgoKCg==