1. load libraries
#Differential Expression Analysis
2. load seurat object
#Load Seurat Object L7
load("../../../0-IMP-OBJECTS/Harmony_integrated_All_samples_Merged_with_PBMC10x_with_harmony_clustering.Robj")
All_samples_Merged
An object of class Seurat
64169 features across 59355 samples within 6 assays
Active assay: SCT (27417 features, 3000 variable features)
3 layers present: counts, data, scale.data
5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
6 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony, umap.harmony
DimPlot(All_samples_Merged, reduction = "umap.harmony", group.by = "cell_line",label = T, label.box = T)

DimPlot(All_samples_Merged, reduction = "umap.harmony", group.by = "Harmony_snn_res.0.9",label = T, label.box = T)

3. Dim plots
sample <- All_samples_Merged
# Seurat's DimPlot.
p1 <- Seurat::DimPlot(sample, group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony")
# SCpubr's DimPlot.
p2 <- SCpubr::do_DimPlot(sample = sample, group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony")
p <- p1 | p2
p

SCpubr::do_DimPlot(sample = sample, group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T)

SCpubr::do_DimPlot(sample = sample, group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T, plot.axes = T)

SCpubr::do_DimPlot(sample = sample, group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T, plot.axes = T, legend.position = "none")

SCpubr::do_DimPlot(sample = sample,
idents.keep = c("3", "8", "10", "18"), group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T, plot.axes = T, legend.position = "none")

SCpubr::do_DimPlot(sample = sample,
idents.keep = c("1", "2", "13"), group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T, plot.axes = T, legend.position = "none")

SCpubr::do_DimPlot(sample = sample,
idents.keep = c("4", "7", "9", "6", "16", "19"), group.by = "Harmony_snn_res.0.9", reduction = "umap.harmony", label = T, label.box = T, plot.axes = T, legend.position = "none")

NA
NA
NA
NA
4. Feature Plots
genes <- list("Naive CD4+ T" = c("IL7R", "CCR7"),
"CD14+ Mono" = c("CD14", "LYZ"),
"Memory CD4+" = c("S100A4"),
"B" = c("MS4A1"),
"CD8+ T" = c("CD8A"),
"FCGR3A+ Mono" = c("FCGR3A", "MS4A7"),
"NK" = c("GNLY", "NKG7"),
"DC" = c("FCER1A", "CST3"),
"Platelet" = c("PPBP"))
p1 <- SCpubr::do_DotPlot(sample = sample,
features = genes)
p1

p2 <- SCpubr::do_DotPlot(sample = sample,
features = genes, group.by = "cell_line")
p2

SCpubr::do_BarPlot(sample = sample,
group.by = "Harmony_snn_res.0.9",
legend.position = "none",
plot.title = "Number of cells per cluster",
flip = TRUE)

SCpubr::do_ChordDiagramPlot(sample = sample,
from = "orig.ident",
to = "cell_line",
link.arr.type = "triangle")


NA
NA
NA
5. Group-wise DE analysis plots
# Set the identities correctly.
Seurat::Idents(sample) <- sample$Harmony_snn_res.0.9
# Compute DE genes and transform to a tibble.
de_genes <- tibble::tibble(Seurat::FindAllMarkers(object = sample, min.pct = 0.1, logfc.threshold = 0.1))
Calculating cluster 0
Calculating cluster 1
Calculating cluster 2
Calculating cluster 3
Calculating cluster 4
Calculating cluster 5
Calculating cluster 6
Calculating cluster 7
Calculating cluster 8
Calculating cluster 9
Calculating cluster 10
Calculating cluster 11
Calculating cluster 12
Calculating cluster 13
Calculating cluster 14
Calculating cluster 15
Calculating cluster 16
Calculating cluster 17
Calculating cluster 18
Calculating cluster 19
Calculating cluster 20
Calculating cluster 21
Calculating cluster 22
Calculating cluster 23
Calculating cluster 24
Group-wise DE analysis plots
p <- SCpubr::do_GroupwiseDEPlot(sample = sample,
de_genes = de_genes,
min.cutoff = 1)
p

# Increase the number of top DE genes by cluster.
p <- SCpubr::do_GroupwiseDEPlot(sample = sample,
de_genes = de_genes,
top_genes = 10)
p

# Define list of genes.
genes <- c("KIR3DL2",
"TOX",
"CD7",
"CD26",
"DDP4",
"TWIST1",
"PLS3",
"CD70",
"CCR4",
"CCR7")
# Default parameters.
SCpubr::do_ExpressionHeatmap(sample = sample,
features = genes)
Avis :
! The following features are not found in the row names of the specified assay (default assay if not):
CD26, DDP4

# Define the gene list
genes_to_plot <- c("SPINK2", "PRSS57", "CYTL1", "EGFL7", "GATA2", "CD34", "SMIM24", "AVP", "MYB", "LAPTM4B")
SCpubr::do_ExpressionHeatmap(sample = sample,
features = genes, group.by = "Harmony_snn_res.0.9")
Avis :
! The following features are not found in the row names of the specified assay (default assay if not):
CD26, DDP4

Group-wise DE analysis plots
p <- SCpubr::do_GroupwiseDEPlot(sample = sample,
de_genes = de_genes,
top_genes = 5)
p

# Define list of genes.
genes <- c("KIR3DL2",
"TOX",
"CD7",
"DPP4",
"TWIST1",
"PLS3",
"CD70",
"CCR4",
"CCR7")
# Default parameters.
SCpubr::do_ExpressionHeatmap(sample = sample,
features = genes)

Group-wise DE analysis plots
library(ggplot2)
library(RColorBrewer)
# Step 1: Filter for HSPC cells
hspc_data <- All_samples_Merged@meta.data %>%
filter(predicted.celltype.l2 == "HSPC") # Filter for HSPC cells
# Step 2: Count HSPC cells per cell line
hspc_counts <- as.data.frame(table(hspc_data$cell_line))
colnames(hspc_counts) <- c("cell_line", "nUMI") # Rename columns for clarity
# Step 3: Generate color palette
# Adjust the number (10) to the number of unique cell lines
cell_line_colors <- brewer.pal(min(10, nrow(hspc_counts)), "Set3")
# Step 4: Create bar plot
hspc_plot <- ggplot(hspc_counts, 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)) + # Center the title
ggtitle("HSPC Cells per Cell Line") +
xlab("Cell Lines") +
ylab("Number of HSPC Cells")
# Step 5: Print the plot
print(hspc_plot)

# Filter for HSPC cells
hspc_data <- All_samples_Merged@meta.data %>%
filter(predicted.celltype.l2 == "HSPC")
# Count HSPC cells per cell line
hspc_counts <- as.data.frame(table(hspc_data$cell_line))
colnames(hspc_counts) <- c("cell_line", "nUMI") # Rename columns for clarity
# Exclude "PBMC" and "PBMC 10X" cell lines
hspc_counts <- hspc_counts %>%
filter(!cell_line %in% c("PBMC", "PBMC_10x"))
# Generate a color palette for the remaining cell lines
cell_line_colors <- brewer.pal(min(10, nrow(hspc_counts)), "Set3")
# Create the bar plot
hspc_plot <- ggplot(hspc_counts, 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)) +
ggtitle("HSPC Cells per Cell Line (Excluding PBMC)") +
xlab("Cell Lines") +
ylab("Number of HSPC Cells")
# Print the plot
print(hspc_plot)

NA
NA
NA
NA
NA
NA
Azimuth Barplot
# Count cells for each cell type in predicted.celltype.l2
celltype_counts <- as.data.frame(table(All_samples_Merged$predicted.celltype.l2))
colnames(celltype_counts) <- c("cell_type", "nUMI") # Rename columns appropriately
# Create an extended color palette
celltype_colors <- colorRampPalette(brewer.pal(12, "Set3"))(nrow(celltype_counts))
# Create bar plot
celltype_plot <- ggplot(celltype_counts, aes(x = cell_type, y = nUMI, fill = cell_type)) +
geom_col() +
theme_classic() +
geom_text(aes(label = nUMI),
position = position_dodge(width = 0.9),
vjust = -0.25) +
scale_fill_manual(values = celltype_colors) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(hjust = 0.5)) +
ggtitle("Cell Counts by Predicted Cell Type") +
xlab("Cell Types") +
ylab("Number of Cells (nUMI)")
# Print the plot
print(celltype_plot)

# List of cell types to exclude
exclude_cell_types <- c("pDC", "Plasmablast", "cDC1", "Platelet", "ILC", "ASDC", "cDC2")
# Filter out the unwanted cell types
celltype_counts_filtered <- celltype_counts[!celltype_counts$cell_type %in% exclude_cell_types, ]
# Generate the color palette
celltype_colors <- colorRampPalette(brewer.pal(12, "Set3"))(nrow(celltype_counts_filtered))
# Create the bar plot
celltype_plot <- ggplot(celltype_counts_filtered, aes(x = cell_type, y = nUMI, fill = cell_type)) +
geom_col() +
theme_classic() +
geom_text(aes(label = nUMI),
position = position_dodge(width = 0.9),
vjust = -0.25) +
scale_fill_manual(values = celltype_colors) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(hjust = 0.5)) +
ggtitle("Cell Counts by Predicted Cell Type") +
xlab("Cell Types") +
ylab("Number of Cells (nUMI)")
# Print the plot
print(celltype_plot)

NA
NA
NA
LS0tCnRpdGxlOiAiU8OpemFyeSBTeW5kcm9tZSBTQ3B1YnIgVmlzdWFsaXphdGlvbiIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdAogICMgd29yZF9kb2N1bWVudDogZGVmYXVsdAogICMgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAxLCBpbmNsdWRlPUZBTFNFfQojIyBodHRwczovL2VuYmxhY2FyLmdpdGh1Yi5pby9TQ3B1YnItYm9vay12MS8wNC1GZWF0dXJlUGxvdHMuaHRtbAoKCiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc2NDdXN0b21pemUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShTQ3B1YnIpCgpgYGAKI0RpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzCgojIDIuIGxvYWQgc2V1cmF0IG9iamVjdApgYGB7ciBsb2FkX3NldXJhdH0KI0xvYWQgU2V1cmF0IE9iamVjdCBMNwpsb2FkKCIuLi8uLi8uLi8wLUlNUC1PQkpFQ1RTL0hhcm1vbnlfaW50ZWdyYXRlZF9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9QQk1DMTB4X3dpdGhfaGFybW9ueV9jbHVzdGVyaW5nLlJvYmoiKQoKCkFsbF9zYW1wbGVzX01lcmdlZAoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwLmhhcm1vbnkiLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiLGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICJ1bWFwLmhhcm1vbnkiLCBncm91cC5ieSA9ICJIYXJtb255X3Nubl9yZXMuMC45IixsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCgpgYGAKCgoKIyAzLiBEaW0gcGxvdHMKYGBge3IgRGltcGxvdHMsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0Kc2FtcGxlIDwtIEFsbF9zYW1wbGVzX01lcmdlZAoKIyBTZXVyYXQncyBEaW1QbG90LgpwMSA8LSBTZXVyYXQ6OkRpbVBsb3Qoc2FtcGxlLCBncm91cC5ieSA9ICJIYXJtb255X3Nubl9yZXMuMC45IiwgcmVkdWN0aW9uID0gInVtYXAuaGFybW9ueSIpCgojIFNDcHVicidzIERpbVBsb3QuCnAyIDwtIFNDcHVicjo6ZG9fRGltUGxvdChzYW1wbGUgPSBzYW1wbGUsIGdyb3VwLmJ5ID0gIkhhcm1vbnlfc25uX3Jlcy4wLjkiLCByZWR1Y3Rpb24gPSAidW1hcC5oYXJtb255IikKCnAgPC0gcDEgfCBwMgpwCgpTQ3B1YnI6OmRvX0RpbVBsb3Qoc2FtcGxlID0gc2FtcGxlLCBncm91cC5ieSA9ICJIYXJtb255X3Nubl9yZXMuMC45IiwgcmVkdWN0aW9uID0gInVtYXAuaGFybW9ueSIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKClNDcHVicjo6ZG9fRGltUGxvdChzYW1wbGUgPSBzYW1wbGUsIGdyb3VwLmJ5ID0gIkhhcm1vbnlfc25uX3Jlcy4wLjkiLCByZWR1Y3Rpb24gPSAidW1hcC5oYXJtb255IiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCBwbG90LmF4ZXMgPSBUKQoKU0NwdWJyOjpkb19EaW1QbG90KHNhbXBsZSA9IHNhbXBsZSwgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIsIHJlZHVjdGlvbiA9ICJ1bWFwLmhhcm1vbnkiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQsIHBsb3QuYXhlcyA9IFQsIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpTQ3B1YnI6OmRvX0RpbVBsb3Qoc2FtcGxlID0gc2FtcGxlLAogICAgICAgICAgICAgICAgICAgaWRlbnRzLmtlZXAgPSBjKCIzIiwgIjgiLCAiMTAiLCAiMTgiKSwgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIsIHJlZHVjdGlvbiA9ICJ1bWFwLmhhcm1vbnkiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQsIHBsb3QuYXhlcyA9IFQsIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKClNDcHVicjo6ZG9fRGltUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICBpZGVudHMua2VlcCA9IGMoIjEiLCAiMiIsICIxMyIpLCBncm91cC5ieSA9ICJIYXJtb255X3Nubl9yZXMuMC45IiwgcmVkdWN0aW9uID0gInVtYXAuaGFybW9ueSIsIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCwgcGxvdC5heGVzID0gVCwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKClNDcHVicjo6ZG9fRGltUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICBpZGVudHMua2VlcCA9IGMoIjQiLCAiNyIsICI5IiwgIjYiLCAiMTYiLCAiMTkiKSwgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIsIHJlZHVjdGlvbiA9ICJ1bWFwLmhhcm1vbnkiLCBsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQsIHBsb3QuYXhlcyA9IFQsIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgoKCmBgYAoKIyA0LiBGZWF0dXJlIFBsb3RzCmBgYHtyIEZlYXR1cmVQbG90cywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQoKCgoKZ2VuZXMgPC0gbGlzdCgiTmFpdmUgQ0Q0KyBUIiA9IGMoIklMN1IiLCAiQ0NSNyIpLAogICAgICAgICAgICAgICJDRDE0KyBNb25vIiA9IGMoIkNEMTQiLCAiTFlaIiksCiAgICAgICAgICAgICAgIk1lbW9yeSBDRDQrIiA9IGMoIlMxMDBBNCIpLAogICAgICAgICAgICAgICJCIiA9IGMoIk1TNEExIiksCiAgICAgICAgICAgICAgIkNEOCsgVCIgPSBjKCJDRDhBIiksCiAgICAgICAgICAgICAgIkZDR1IzQSsgTW9ubyIgPSBjKCJGQ0dSM0EiLCAiTVM0QTciKSwKICAgICAgICAgICAgICAiTksiID0gYygiR05MWSIsICJOS0c3IiksCiAgICAgICAgICAgICAgIkRDIiA9IGMoIkZDRVIxQSIsICJDU1QzIiksCiAgICAgICAgICAgICAgIlBsYXRlbGV0IiA9IGMoIlBQQlAiKSkKCnAxIDwtIFNDcHVicjo6ZG9fRG90UGxvdChzYW1wbGUgPSBzYW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVzKQpwMQoKCnAyIDwtIFNDcHVicjo6ZG9fRG90UGxvdChzYW1wbGUgPSBzYW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVzLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiKQpwMgoKClNDcHVicjo6ZG9fQmFyUGxvdChzYW1wbGUgPSBzYW1wbGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9ICJOdW1iZXIgb2YgY2VsbHMgcGVyIGNsdXN0ZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZsaXAgPSBUUlVFKQoKClNDcHVicjo6ZG9fQ2hvcmREaWFncmFtUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tID0gIm9yaWcuaWRlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSAiY2VsbF9saW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmsuYXJyLnR5cGUgPSAidHJpYW5nbGUiKQoKCgpgYGAKCgojIDUuIEdyb3VwLXdpc2UgREUgYW5hbHlzaXMgcGxvdHMKYGBge3IgZ3JvdXBXaXNlLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTJ9CgojIFNldCB0aGUgaWRlbnRpdGllcyBjb3JyZWN0bHkuClNldXJhdDo6SWRlbnRzKHNhbXBsZSkgPC0gc2FtcGxlJEhhcm1vbnlfc25uX3Jlcy4wLjkKCiMgQ29tcHV0ZSBERSBnZW5lcyBhbmQgdHJhbnNmb3JtIHRvIGEgdGliYmxlLgpkZV9nZW5lcyA8LSB0aWJibGU6OnRpYmJsZShTZXVyYXQ6OkZpbmRBbGxNYXJrZXJzKG9iamVjdCA9IHNhbXBsZSwgbWluLnBjdCA9IDAuMSwgbG9nZmMudGhyZXNob2xkID0gMC4xKSkKCmBgYAoKCiMjICBHcm91cC13aXNlIERFIGFuYWx5c2lzIHBsb3RzCmBgYHtyIHRvcDVfSGVhdG1hcF92aXN1YWxpemF0aW9uMywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQoKcCA8LSBTQ3B1YnI6OmRvX0dyb3Vwd2lzZURFUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVfZ2VuZXMgPSBkZV9nZW5lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gMSkKCnAKCiMgSW5jcmVhc2UgdGhlIG51bWJlciBvZiB0b3AgREUgZ2VuZXMgYnkgY2x1c3Rlci4KcCA8LSBTQ3B1YnI6OmRvX0dyb3Vwd2lzZURFUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVfZ2VuZXMgPSBkZV9nZW5lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfZ2VuZXMgPSAxMCkKCnAKCgojIERlZmluZSBsaXN0IG9mIGdlbmVzLgpnZW5lcyA8LSBjKCJLSVIzREwyIiwgCiAgICAgICAgICAgIlRPWCIsIAogICAgICAgICAgICJDRDciLCAKICAgICAgICAgICAiRFBQNCIsIAogICAgICAgICAgICJUV0lTVDEiLAogICAgICAgICAgICJQTFMzIiwKICAgICAgICAgICAiQ0Q3MCIsCiAgICAgICAgICAgIkNDUjQiLCAKICAgICAgICAgICAiQ0NSNyIpCgojIERlZmF1bHQgcGFyYW1ldGVycy4KIFNDcHVicjo6ZG9fRXhwcmVzc2lvbkhlYXRtYXAoc2FtcGxlID0gc2FtcGxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBnZW5lcykKCgoKIyBEZWZpbmUgdGhlIGdlbmUgbGlzdApnZW5lc190b19wbG90IDwtIGMoIlNQSU5LMiIsICJQUlNTNTciLCAiQ1lUTDEiLCAiRUdGTDciLCAiR0FUQTIiLCAiQ0QzNCIsICJTTUlNMjQiLCAiQVZQIiwgIk1ZQiIsICJMQVBUTTRCIikKClNDcHVicjo6ZG9fRXhwcmVzc2lvbkhlYXRtYXAoc2FtcGxlID0gc2FtcGxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBnZW5lcywgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIpCgpgYGAKCgojIyAgR3JvdXAtd2lzZSBERSBhbmFseXNpcyBwbG90cwpgYGB7ciB0b3A1X0hlYXRtYXBfdmlzdWFsaXphdGlvbjQsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KcCA8LSBTQ3B1YnI6OmRvX0dyb3Vwd2lzZURFUGxvdChzYW1wbGUgPSBzYW1wbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVfZ2VuZXMgPSBkZV9nZW5lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfZ2VuZXMgPSA1KQoKcAoKIyBEZWZpbmUgbGlzdCBvZiBnZW5lcy4KZ2VuZXMgPC0gYygiS0lSM0RMMiIsIAogICAgICAgICAgICJUT1giLCAKICAgICAgICAgICAiQ0Q3IiwgCiAgICAgICAgICAgIkRQUDQiLCAKICAgICAgICAgICAiVFdJU1QxIiwKICAgICAgICAgICAiUExTMyIsCiAgICAgICAgICAgIkNENzAiLAogICAgICAgICAgICJDQ1I0IiwgCiAgICAgICAgICAgIkNDUjciKQoKIyBEZWZhdWx0IHBhcmFtZXRlcnMuCiBTQ3B1YnI6OmRvX0V4cHJlc3Npb25IZWF0bWFwKHNhbXBsZSA9IHNhbXBsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZXMpCgpgYGAKCgojIyAgR3JvdXAtd2lzZSBERSBhbmFseXNpcyBwbG90cwpgYGB7ciB0b3A1X0hlYXRtYXBfdmlzdWFsaXphdGlvbjUsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKCiMgU3RlcCAxOiBGaWx0ZXIgZm9yIEhTUEMgY2VsbHMKaHNwY19kYXRhIDwtIEFsbF9zYW1wbGVzX01lcmdlZEBtZXRhLmRhdGEgJT4lCiAgZmlsdGVyKHByZWRpY3RlZC5jZWxsdHlwZS5sMiA9PSAiSFNQQyIpICAjIEZpbHRlciBmb3IgSFNQQyBjZWxscwoKIyBTdGVwIDI6IENvdW50IEhTUEMgY2VsbHMgcGVyIGNlbGwgbGluZQpoc3BjX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGhzcGNfZGF0YSRjZWxsX2xpbmUpKQpjb2xuYW1lcyhoc3BjX2NvdW50cykgPC0gYygiY2VsbF9saW5lIiwgIm5VTUkiKSAgIyBSZW5hbWUgY29sdW1ucyBmb3IgY2xhcml0eQoKIyBTdGVwIDM6IEdlbmVyYXRlIGNvbG9yIHBhbGV0dGUKIyBBZGp1c3QgdGhlIG51bWJlciAoMTApIHRvIHRoZSBudW1iZXIgb2YgdW5pcXVlIGNlbGwgbGluZXMKY2VsbF9saW5lX2NvbG9ycyA8LSBicmV3ZXIucGFsKG1pbigxMCwgbnJvdyhoc3BjX2NvdW50cykpLCAiU2V0MyIpCgojIFN0ZXAgNDogQ3JlYXRlIGJhciBwbG90CmhzcGNfcGxvdCA8LSBnZ3Bsb3QoaHNwY19jb3VudHMsIGFlcyh4ID0gY2VsbF9saW5lLCB5ID0gblVNSSwgZmlsbCA9IGNlbGxfbGluZSkpICsKICBnZW9tX2NvbCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuVU1JKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjZWxsX2xpbmVfY29sb3JzKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgICMgQ2VudGVyIHRoZSB0aXRsZQogIGdndGl0bGUoIkhTUEMgQ2VsbHMgcGVyIENlbGwgTGluZSIpICsKICB4bGFiKCJDZWxsIExpbmVzIikgKwogIHlsYWIoIk51bWJlciBvZiBIU1BDIENlbGxzIikKCiMgU3RlcCA1OiBQcmludCB0aGUgcGxvdApwcmludChoc3BjX3Bsb3QpCgoKCiMgRmlsdGVyIGZvciBIU1BDIGNlbGxzCmhzcGNfZGF0YSA8LSBBbGxfc2FtcGxlc19NZXJnZWRAbWV0YS5kYXRhICU+JQogIGZpbHRlcihwcmVkaWN0ZWQuY2VsbHR5cGUubDIgPT0gIkhTUEMiKQoKIyBDb3VudCBIU1BDIGNlbGxzIHBlciBjZWxsIGxpbmUKaHNwY19jb3VudHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShoc3BjX2RhdGEkY2VsbF9saW5lKSkKY29sbmFtZXMoaHNwY19jb3VudHMpIDwtIGMoImNlbGxfbGluZSIsICJuVU1JIikgICMgUmVuYW1lIGNvbHVtbnMgZm9yIGNsYXJpdHkKCiMgRXhjbHVkZSAiUEJNQyIgYW5kICJQQk1DIDEwWCIgY2VsbCBsaW5lcwpoc3BjX2NvdW50cyA8LSBoc3BjX2NvdW50cyAlPiUKICBmaWx0ZXIoIWNlbGxfbGluZSAlaW4lIGMoIlBCTUMiLCAiUEJNQ18xMHgiKSkKCiMgR2VuZXJhdGUgYSBjb2xvciBwYWxldHRlIGZvciB0aGUgcmVtYWluaW5nIGNlbGwgbGluZXMKY2VsbF9saW5lX2NvbG9ycyA8LSBicmV3ZXIucGFsKG1pbigxMCwgbnJvdyhoc3BjX2NvdW50cykpLCAiU2V0MyIpCgojIENyZWF0ZSB0aGUgYmFyIHBsb3QKaHNwY19wbG90IDwtIGdncGxvdChoc3BjX2NvdW50cywgYWVzKHggPSBjZWxsX2xpbmUsIHkgPSBuVU1JLCBmaWxsID0gY2VsbF9saW5lKSkgKwogIGdlb21fY29sKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG5VTUkpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNlbGxfbGluZV9jb2xvcnMpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGdndGl0bGUoIkhTUEMgQ2VsbHMgcGVyIENlbGwgTGluZSAoRXhjbHVkaW5nIFBCTUMpIikgKwogIHhsYWIoIkNlbGwgTGluZXMiKSArCiAgeWxhYigiTnVtYmVyIG9mIEhTUEMgQ2VsbHMiKQoKIyBQcmludCB0aGUgcGxvdApwcmludChoc3BjX3Bsb3QpCgoKCgoKCmBgYAoKIyMgIEF6aW11dGggQmFycGxvdApgYGB7ciB0b3A1X0hlYXRtYXBfdmlzdWFsaXphdGlvbjYsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KIyBDb3VudCBjZWxscyBmb3IgZWFjaCBjZWxsIHR5cGUgaW4gcHJlZGljdGVkLmNlbGx0eXBlLmwyCmNlbGx0eXBlX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKEFsbF9zYW1wbGVzX01lcmdlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpKQpjb2xuYW1lcyhjZWxsdHlwZV9jb3VudHMpIDwtIGMoImNlbGxfdHlwZSIsICJuVU1JIikgICMgUmVuYW1lIGNvbHVtbnMgYXBwcm9wcmlhdGVseQoKIyBDcmVhdGUgYW4gZXh0ZW5kZWQgY29sb3IgcGFsZXR0ZQpjZWxsdHlwZV9jb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDEyLCAiU2V0MyIpKShucm93KGNlbGx0eXBlX2NvdW50cykpCgojIENyZWF0ZSBiYXIgcGxvdApjZWxsdHlwZV9wbG90IDwtIGdncGxvdChjZWxsdHlwZV9jb3VudHMsIGFlcyh4ID0gY2VsbF90eXBlLCB5ID0gblVNSSwgZmlsbCA9IGNlbGxfdHlwZSkpICsKICBnZW9tX2NvbCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuVU1JKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCAKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNlbGx0eXBlX2NvbG9ycykgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBnZ3RpdGxlKCJDZWxsIENvdW50cyBieSBQcmVkaWN0ZWQgQ2VsbCBUeXBlIikgKwogIHhsYWIoIkNlbGwgVHlwZXMiKSArCiAgeWxhYigiTnVtYmVyIG9mIENlbGxzIChuVU1JKSIpCgojIFByaW50IHRoZSBwbG90CnByaW50KGNlbGx0eXBlX3Bsb3QpCgoKCiMgTGlzdCBvZiBjZWxsIHR5cGVzIHRvIGV4Y2x1ZGUKZXhjbHVkZV9jZWxsX3R5cGVzIDwtIGMoInBEQyIsICJQbGFzbWFibGFzdCIsICJjREMxIiwgIlBsYXRlbGV0IiwgIklMQyIsICJBU0RDIiwgImNEQzIiKQoKIyBGaWx0ZXIgb3V0IHRoZSB1bndhbnRlZCBjZWxsIHR5cGVzCmNlbGx0eXBlX2NvdW50c19maWx0ZXJlZCA8LSBjZWxsdHlwZV9jb3VudHNbIWNlbGx0eXBlX2NvdW50cyRjZWxsX3R5cGUgJWluJSBleGNsdWRlX2NlbGxfdHlwZXMsIF0KCiMgR2VuZXJhdGUgdGhlIGNvbG9yIHBhbGV0dGUKY2VsbHR5cGVfY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlNldDMiKSkobnJvdyhjZWxsdHlwZV9jb3VudHNfZmlsdGVyZWQpKQoKIyBDcmVhdGUgdGhlIGJhciBwbG90CmNlbGx0eXBlX3Bsb3QgPC0gZ2dwbG90KGNlbGx0eXBlX2NvdW50c19maWx0ZXJlZCwgYWVzKHggPSBjZWxsX3R5cGUsIHkgPSBuVU1JLCBmaWxsID0gY2VsbF90eXBlKSkgKwogIGdlb21fY29sKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG5VTUkpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIAogICAgICAgICAgICB2anVzdCA9IC0wLjI1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2VsbHR5cGVfY29sb3JzKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGdndGl0bGUoIkNlbGwgQ291bnRzIGJ5IFByZWRpY3RlZCBDZWxsIFR5cGUiKSArCiAgeGxhYigiQ2VsbCBUeXBlcyIpICsKICB5bGFiKCJOdW1iZXIgb2YgQ2VsbHMgKG5VTUkpIikKCiMgUHJpbnQgdGhlIHBsb3QKcHJpbnQoY2VsbHR5cGVfcGxvdCkKCgoKYGBgCg==