1. load libraries

2. Load Seurat Object


All_samples_Merged <- readRDS("../../0-Seurat_RDS_OBJECT_FINAL/Seurat_object_Final_changes/All_samples_Merged_with_STCAT_Annotation_final-5-09-2025.rds")

DefaultAssay(All_samples_Merged) <- "RNA"

All_samples_Merged <- NormalizeData(
    All_samples_Merged,
    normalization.method = "LogNormalize",
    scale.factor = 1e4,
    verbose = TRUE
  )
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

3.find Top markers

Idents(All_samples_Merged) <- "seurat_clusters"

# ---------------------------------------------------------
# 2️⃣ Find marker genes per cluster
SS_markers <- FindAllMarkers(
  All_samples_Merged,
  only.pos = TRUE,
  min.pct = 0.4,
  logfc.threshold = 1,
  min.pct.diff = 0.3
  
)

library(dplyr)

# Precise blacklist for uninformative genes
blacklist_patterns <- c(
  "^TRAV", "^TRBV", "^TRGV", "^TRDV", "^TRBC", "^TRAC", "^TRDC", "^TRGC", # TCR
  "^IGH", "^IGK", "^IGL", "^IGJ",                                         # Ig genes
  "^RPL", "^RPS",                                                         # ribosomal
  "^MT-",                                                                 # mitochondria
  "^HBA", "^HBB", "^HB[ABZ]",                                             # hemoglobins
  "^NEAT1$", "^MALAT1$",                                                  # optional lncRNAs
  "^XIST$"                              )

blacklist_regex <- paste(blacklist_patterns, collapse = "|")

# Preview which markers will be removed
to_remove <- SS_markers %>%
  filter(grepl(blacklist_regex, gene, ignore.case = TRUE))
message("Rows to remove: ", nrow(to_remove))
head(to_remove$gene)
[1] "TRAV17"      "TRAV9-2"     "RPL22L1"     "TRAV38-2DV8" "TRGV2"       "TRGV4"      
# Filter markers (keep important metabolic/proliferation genes)
SS_markers_filtered <- SS_markers %>%
  filter(!grepl(blacklist_regex, gene, ignore.case = TRUE))

4. Top5 Markers


library(dplyr)

# ---------------------------------------------------------
# Save filtered markers
#write.csv(SS_markers_filtered, file = "SS_markers_filtered.csv", row.names = FALSE)

# ---------------------------------------------------------
# Extract top 25 markers per cluster
top25_markers <- SS_markers_filtered %>%
  filter(p_val_adj < 0.05) %>%  # ensure statistical significance
  group_by(cluster) %>%
  slice_max(order_by = avg_log2FC, n = 25) %>%
  ungroup()

#write.csv(top25_markers, file = "SS_markers_top25.csv", row.names = FALSE)

# ---------------------------------------------------------
# Extract top 5 markers per cluster
top5_markers <- SS_markers_filtered %>%
  filter(p_val_adj < 0.05) %>%  # ensure statistical significance
  group_by(cluster) %>%
  slice_max(order_by = avg_log2FC, n = 5) %>%
  ungroup()

#write.csv(top5_markers, file = "SS_markers_top5.csv", row.names = FALSE)

#message("Filtered markers, top25, and top5 markers saved successfully.")

nbiSweden Approach-Top25

DefaultAssay(All_samples_Merged) <- "SCT"

par(mfrow = c(2, 5), mar = c(4, 6, 3, 1))
for (i in unique(top25_markers$cluster)) {
    barplot(sort(setNames(top25_markers$avg_log2FC, top25_markers$gene)[top25_markers$cluster == i], F),
        horiz = T, las = 1, main = paste0(i, " vs. rest"), border = "white", yaxs = "i"
    )
    abline(v = c(0, 0.25), lty = c(1, 2))
}

NA

nbiSweden Approach-Top5


par(mfrow = c(2, 5), mar = c(4, 6, 3, 1))
for (i in unique(top5_markers$cluster)) {
    barplot(sort(setNames(top5_markers$avg_log2FC, top5_markers$gene)[top5_markers$cluster == i], F),
        horiz = T, las = 1, main = paste0(i, " vs. rest"), border = "white", yaxs = "i"
    )
    abline(v = c(0, 0.25), lty = c(1, 2))
}

NA

Chatomics approach

library(dplyr)
library(Seurat)
library(ComplexHeatmap)
library(magick)


DefaultAssay(All_samples_Merged) <- "SCT"
data_mat <- GetAssayData(All_samples_Merged, assay = "SCT", slot = "data")

# Convert sparse matrix to dense matrix (beware memory use)
mat <- as.matrix(data_mat)

# Clean top5_markers: unlist and keep only valid gene names present in data_mat
top5_markers_clean <- unlist(top5_markers)
top5_markers_clean <- top5_markers_clean[top5_markers_clean %in% rownames(mat)]

# Subset the matrix using only valid markers
mat_subset <- mat[top5_markers_clean, , drop = FALSE]

# Scale rows
mat_scaled <- t(scale(t(mat_subset)))

# Now proceed with heatmap plotting etc.



cluster_anno<- All_samples_Merged@meta.data$seurat_clusters


# what's the value range in the matrix
quantile(mat, c(0.1, 0.95))
     10%      95% 
0.000000 1.098612 
Seurat::PurpleAndYellow()
 [1] "#FF00FF" "#F400F4" "#EA00EA" "#DF00DF" "#D500D5" "#CA00CA" "#BF00BF" "#B500B5" "#AA00AA" "#9F009F" "#950095"
[12] "#8A008A" "#800080" "#750075" "#6A006A" "#600060" "#550055" "#4A004A" "#400040" "#350035" "#2B002B" "#200020"
[23] "#150015" "#0B000B" "#000000" "#000000" "#0B0B00" "#151500" "#202000" "#2B2B00" "#353500" "#404000" "#4A4A00"
[34] "#555500" "#606000" "#6A6A00" "#757500" "#808000" "#8A8A00" "#959500" "#9F9F00" "#AAAA00" "#B5B500" "#BFBF00"
[45] "#CACA00" "#D4D400" "#DFDF00" "#EAEA00" "#F4F400" "#FFFF00"
## make the black color map to 0. the yellow map to highest and the purle map to the lowest
col_fun = circlize::colorRamp2(c(-1, 0, 3), c("#FF00FF", "black", "#FFFF00"))

Heatmap(mat_scaled, name = "Expression",  
        column_split = factor(cluster_anno),
        cluster_columns = TRUE,
        show_column_dend = FALSE,
        cluster_column_slices = TRUE,
        column_title_gp = gpar(fontsize = 8),
        column_gap = unit(0.5, "mm"),
        cluster_rows = TRUE,
        show_row_dend = FALSE,
        col = col_fun,
        row_names_gp = gpar(fontsize = 8),
        column_title_rot = 90,
        top_annotation = HeatmapAnnotation(foo = anno_block(gp = gpar(fill = scales::hue_pal()(9)))),
        show_column_names = FALSE,
        use_raster = TRUE,
        raster_quality = 8)

nbiSweden Approach


DotPlot(All_samples_Merged, features = rev(as.character(unique(top5_markers$gene))), group.by = "seurat_clusters", assay = "RNA") + coord_flip()

scCustomize Dotplot

library(scCustomize)
Clustered_DotPlot(seurat_object = All_samples_Merged, features = top5_markers$gene, k = 6)
[[1]]

[[2]]

scCustomize::Clustered_DotPlot(All_samples_Merged, features = top5_markers$gene,
                               plot_km_elbow = FALSE)

LS0tCnRpdGxlOiAiSWRlbnRpZnkgVG9wNSBNYXJrZXJzIGFuZCBkbyBDbHVzdGVyIEFubm90YXRpb24iCmF1dGhvcjogIk5hc2lyIE1haG1vb2QgQWJiYXNpIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgTG9hZCBiZWxvdyBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCgoKbGlicmFyeShTQ3B1YnIpCmxpYnJhcnkoZHBseXIpCmBgYAoKCiMgMi4gTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7cn0KCkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi8uLi8wLVNldXJhdF9SRFNfT0JKRUNUX0ZJTkFML1NldXJhdF9vYmplY3RfRmluYWxfY2hhbmdlcy9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9TVENBVF9Bbm5vdGF0aW9uX2ZpbmFsLTUtMDktMjAyNS5yZHMiKQoKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlJOQSIKCkFsbF9zYW1wbGVzX01lcmdlZCA8LSBOb3JtYWxpemVEYXRhKAogICAgQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwKICAgIHNjYWxlLmZhY3RvciA9IDFlNCwKICAgIHZlcmJvc2UgPSBUUlVFCiAgKQoKCmBgYAoKIyAzLmZpbmQgVG9wIG1hcmtlcnMKYGBge3J9CklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIDLvuI/ig6MgRmluZCBtYXJrZXIgZ2VuZXMgcGVyIGNsdXN0ZXIKU1NfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycygKICBBbGxfc2FtcGxlc19NZXJnZWQsCiAgb25seS5wb3MgPSBUUlVFLAogIG1pbi5wY3QgPSAwLjQsCiAgbG9nZmMudGhyZXNob2xkID0gMSwKICBtaW4ucGN0LmRpZmYgPSAwLjMKICAKKQoKbGlicmFyeShkcGx5cikKCiMgUHJlY2lzZSBibGFja2xpc3QgZm9yIHVuaW5mb3JtYXRpdmUgZ2VuZXMKYmxhY2tsaXN0X3BhdHRlcm5zIDwtIGMoCiAgIl5UUkFWIiwgIl5UUkJWIiwgIl5UUkdWIiwgIl5UUkRWIiwgIl5UUkJDIiwgIl5UUkFDIiwgIl5UUkRDIiwgIl5UUkdDIiwgIyBUQ1IKICAiXklHSCIsICJeSUdLIiwgIl5JR0wiLCAiXklHSiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElnIGdlbmVzCiAgIl5SUEwiLCAiXlJQUyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByaWJvc29tYWwKICAiXk1ULSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pdG9jaG9uZHJpYQogICJeSEJBIiwgIl5IQkIiLCAiXkhCW0FCWl0iLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaGVtb2dsb2JpbnMKICAiXk5FQVQxJCIsICJeTUFMQVQxJCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9wdGlvbmFsIGxuY1JOQXMKICAiXlhJU1QkIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCmJsYWNrbGlzdF9yZWdleCA8LSBwYXN0ZShibGFja2xpc3RfcGF0dGVybnMsIGNvbGxhcHNlID0gInwiKQoKIyBQcmV2aWV3IHdoaWNoIG1hcmtlcnMgd2lsbCBiZSByZW1vdmVkCnRvX3JlbW92ZSA8LSBTU19tYXJrZXJzICU+JQogIGZpbHRlcihncmVwbChibGFja2xpc3RfcmVnZXgsIGdlbmUsIGlnbm9yZS5jYXNlID0gVFJVRSkpCm1lc3NhZ2UoIlJvd3MgdG8gcmVtb3ZlOiAiLCBucm93KHRvX3JlbW92ZSkpCmhlYWQodG9fcmVtb3ZlJGdlbmUpCgojIEZpbHRlciBtYXJrZXJzIChrZWVwIGltcG9ydGFudCBtZXRhYm9saWMvcHJvbGlmZXJhdGlvbiBnZW5lcykKU1NfbWFya2Vyc19maWx0ZXJlZCA8LSBTU19tYXJrZXJzICU+JQogIGZpbHRlcighZ3JlcGwoYmxhY2tsaXN0X3JlZ2V4LCBnZW5lLCBpZ25vcmUuY2FzZSA9IFRSVUUpKQoKCmBgYAoKCiMgNC4gVG9wNSBNYXJrZXJzCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nn0KCmxpYnJhcnkoZHBseXIpCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFNhdmUgZmlsdGVyZWQgbWFya2Vycwojd3JpdGUuY3N2KFNTX21hcmtlcnNfZmlsdGVyZWQsIGZpbGUgPSAiU1NfbWFya2Vyc19maWx0ZXJlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgRXh0cmFjdCB0b3AgMjUgbWFya2VycyBwZXIgY2x1c3Rlcgp0b3AyNV9tYXJrZXJzIDwtIFNTX21hcmtlcnNfZmlsdGVyZWQgJT4lCiAgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JSAgIyBlbnN1cmUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYXZnX2xvZzJGQywgbiA9IDI1KSAlPiUKICB1bmdyb3VwKCkKCiN3cml0ZS5jc3YodG9wMjVfbWFya2VycywgZmlsZSA9ICJTU19tYXJrZXJzX3RvcDI1LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBFeHRyYWN0IHRvcCA1IG1hcmtlcnMgcGVyIGNsdXN0ZXIKdG9wNV9tYXJrZXJzIDwtIFNTX21hcmtlcnNfZmlsdGVyZWQgJT4lCiAgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JSAgIyBlbnN1cmUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYXZnX2xvZzJGQywgbiA9IDUpICU+JQogIHVuZ3JvdXAoKQoKI3dyaXRlLmNzdih0b3A1X21hcmtlcnMsIGZpbGUgPSAiU1NfbWFya2Vyc190b3A1LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKI21lc3NhZ2UoIkZpbHRlcmVkIG1hcmtlcnMsIHRvcDI1LCBhbmQgdG9wNSBtYXJrZXJzIHNhdmVkIHN1Y2Nlc3NmdWxseS4iKQoKYGBgCgoKIyMgbmJpU3dlZGVuIEFwcHJvYWNoLVRvcDI1CmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nn0KRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVCIKCnBhcihtZnJvdyA9IGMoMiwgNSksIG1hciA9IGMoNCwgNiwgMywgMSkpCmZvciAoaSBpbiB1bmlxdWUodG9wMjVfbWFya2VycyRjbHVzdGVyKSkgewogICAgYmFycGxvdChzb3J0KHNldE5hbWVzKHRvcDI1X21hcmtlcnMkYXZnX2xvZzJGQywgdG9wMjVfbWFya2VycyRnZW5lKVt0b3AyNV9tYXJrZXJzJGNsdXN0ZXIgPT0gaV0sIEYpLAogICAgICAgIGhvcml6ID0gVCwgbGFzID0gMSwgbWFpbiA9IHBhc3RlMChpLCAiIHZzLiByZXN0IiksIGJvcmRlciA9ICJ3aGl0ZSIsIHlheHMgPSAiaSIKICAgICkKICAgIGFibGluZSh2ID0gYygwLCAwLjI1KSwgbHR5ID0gYygxLCAyKSkKfQoKYGBgCgojIyBuYmlTd2VkZW4gQXBwcm9hY2gtVG9wNQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CgpwYXIobWZyb3cgPSBjKDIsIDUpLCBtYXIgPSBjKDQsIDYsIDMsIDEpKQpmb3IgKGkgaW4gdW5pcXVlKHRvcDVfbWFya2VycyRjbHVzdGVyKSkgewogICAgYmFycGxvdChzb3J0KHNldE5hbWVzKHRvcDVfbWFya2VycyRhdmdfbG9nMkZDLCB0b3A1X21hcmtlcnMkZ2VuZSlbdG9wNV9tYXJrZXJzJGNsdXN0ZXIgPT0gaV0sIEYpLAogICAgICAgIGhvcml6ID0gVCwgbGFzID0gMSwgbWFpbiA9IHBhc3RlMChpLCAiIHZzLiByZXN0IiksIGJvcmRlciA9ICJ3aGl0ZSIsIHlheHMgPSAiaSIKICAgICkKICAgIGFibGluZSh2ID0gYygwLCAwLjI1KSwgbHR5ID0gYygxLCAyKSkKfQoKYGBgCgojIyBDaGF0b21pY3MgYXBwcm9hY2ggCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0KbGlicmFyeShkcGx5cikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkobWFnaWNrKQoKCkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJTQ1QiCmRhdGFfbWF0IDwtIEdldEFzc2F5RGF0YShBbGxfc2FtcGxlc19NZXJnZWQsIGFzc2F5ID0gIlNDVCIsIHNsb3QgPSAiZGF0YSIpCgojIENvbnZlcnQgc3BhcnNlIG1hdHJpeCB0byBkZW5zZSBtYXRyaXggKGJld2FyZSBtZW1vcnkgdXNlKQptYXQgPC0gYXMubWF0cml4KGRhdGFfbWF0KQoKIyBDbGVhbiB0b3A1X21hcmtlcnM6IHVubGlzdCBhbmQga2VlcCBvbmx5IHZhbGlkIGdlbmUgbmFtZXMgcHJlc2VudCBpbiBkYXRhX21hdAp0b3A1X21hcmtlcnNfY2xlYW4gPC0gdW5saXN0KHRvcDVfbWFya2VycykKdG9wNV9tYXJrZXJzX2NsZWFuIDwtIHRvcDVfbWFya2Vyc19jbGVhblt0b3A1X21hcmtlcnNfY2xlYW4gJWluJSByb3duYW1lcyhtYXQpXQoKIyBTdWJzZXQgdGhlIG1hdHJpeCB1c2luZyBvbmx5IHZhbGlkIG1hcmtlcnMKbWF0X3N1YnNldCA8LSBtYXRbdG9wNV9tYXJrZXJzX2NsZWFuLCAsIGRyb3AgPSBGQUxTRV0KCiMgU2NhbGUgcm93cwptYXRfc2NhbGVkIDwtIHQoc2NhbGUodChtYXRfc3Vic2V0KSkpCgojIE5vdyBwcm9jZWVkIHdpdGggaGVhdG1hcCBwbG90dGluZyBldGMuCgoKCmNsdXN0ZXJfYW5ubzwtIEFsbF9zYW1wbGVzX01lcmdlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzCgoKIyB3aGF0J3MgdGhlIHZhbHVlIHJhbmdlIGluIHRoZSBtYXRyaXgKcXVhbnRpbGUobWF0LCBjKDAuMSwgMC45NSkpCgpTZXVyYXQ6OlB1cnBsZUFuZFllbGxvdygpCgojIyBtYWtlIHRoZSBibGFjayBjb2xvciBtYXAgdG8gMC4gdGhlIHllbGxvdyBtYXAgdG8gaGlnaGVzdCBhbmQgdGhlIHB1cmxlIG1hcCB0byB0aGUgbG93ZXN0CmNvbF9mdW4gPSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKC0xLCAwLCAzKSwgYygiI0ZGMDBGRiIsICJibGFjayIsICIjRkZGRjAwIikpCgpIZWF0bWFwKG1hdF9zY2FsZWQsIG5hbWUgPSAiRXhwcmVzc2lvbiIsICAKICAgICAgICBjb2x1bW5fc3BsaXQgPSBmYWN0b3IoY2x1c3Rlcl9hbm5vKSwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX2NvbHVtbl9zbGljZXMgPSBUUlVFLAogICAgICAgIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA4KSwKICAgICAgICBjb2x1bW5fZ2FwID0gdW5pdCgwLjUsICJtbSIpLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IEZBTFNFLAogICAgICAgIGNvbCA9IGNvbF9mdW4sCiAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDgpLAogICAgICAgIGNvbHVtbl90aXRsZV9yb3QgPSA5MCwKICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IEhlYXRtYXBBbm5vdGF0aW9uKGZvbyA9IGFubm9fYmxvY2soZ3AgPSBncGFyKGZpbGwgPSBzY2FsZXM6Omh1ZV9wYWwoKSg5KSkpKSwKICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLAogICAgICAgIHVzZV9yYXN0ZXIgPSBUUlVFLAogICAgICAgIHJhc3Rlcl9xdWFsaXR5ID0gOCkKYGBgCgojIyBuYmlTd2VkZW4gQXBwcm9hY2gKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0KCkRvdFBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IHJldihhcy5jaGFyYWN0ZXIodW5pcXVlKHRvcDVfbWFya2VycyRnZW5lKSkpLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBhc3NheSA9ICJSTkEiKSArIGNvb3JkX2ZsaXAoKQoKYGBgCgojIyBzY0N1c3RvbWl6ZSBEb3RwbG90CmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9CmxpYnJhcnkoc2NDdXN0b21pemUpCkNsdXN0ZXJlZF9Eb3RQbG90KHNldXJhdF9vYmplY3QgPSBBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gdG9wNV9tYXJrZXJzJGdlbmUsIGsgPSA2KQoKCnNjQ3VzdG9taXplOjpDbHVzdGVyZWRfRG90UGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gdG9wNV9tYXJrZXJzJGdlbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2ttX2VsYm93ID0gRkFMU0UpCmBgYAoKCgoKCgo=