load libraries
# Data Processing
library(dplyr)
library(Seurat)
library(tibble)
library(tidyr)
library(stringr)
# Visualization
library(ggplot2)
library(ComplexHeatmap)
library(patchwork)
library(SCpubr)
# Regulatory Network Inference
library(decoupleR)
library(dorothea)
data(dorothea_hs, package = "dorothea")
library(tictoc)
Load Seurat Object
library(Seurat)
library(reticulate)
library(ggplot2)
# 1. Load Object
seurat_obj <- readRDS("temp_seurat_obj.rds")
SUPPLEMENTARY FIGURE:
UMAP Biplot Code (Correlation-Based Approach)
library(Seurat)
library(ggplot2)
library(dplyr)
library(ggrepel)
# 1. Extract UMAP Embeddings
DefaultAssay(seurat_obj) <- "dorothea"
umap_data <- Embeddings(seurat_obj, reduction = "umap")[, 1:2] %>%
as.data.frame() %>%
mutate(Cluster = as.factor(seurat_obj$seurat_clusters))
# 2. Get TF Activity Matrix
tf_matrix <- GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
# 3. Compute TF Correlations with UMAP Axes
tf_cors <- data.frame(
TF = rownames(tf_matrix),
UMAP_1_cor = apply(tf_matrix, 1, function(x) cor(x, umap_data$umap_1)),
UMAP_2_cor = apply(tf_matrix, 1, function(x) cor(x, umap_data$umap_2))
)
# 4. Filter Top Drivers (Top 3 per quadrant)
umap1_top <- tf_cors %>% arrange(desc(UMAP_1_cor)) %>% head(3) %>% pull(TF)
umap1_bottom <- tf_cors %>% arrange(UMAP_1_cor) %>% head(3) %>% pull(TF)
umap2_top <- tf_cors %>% arrange(desc(UMAP_2_cor)) %>% head(3) %>% pull(TF)
umap2_bottom <- tf_cors %>% arrange(UMAP_2_cor) %>% head(3) %>% pull(TF)
top_tf_drivers <- unique(c(umap1_top, umap1_bottom, umap2_top, umap2_bottom))
# 5. Prepare Arrow Data
arrow_data <- tf_cors %>% filter(TF %in% top_tf_drivers)
# Scale arrows to fit nicely on the plot
scale_factor <- max(abs(umap_data$umap_1)) / max(abs(arrow_data$UMAP_1_cor)) * 0.7
arrow_data$UMAP_1 <- arrow_data$UMAP_1_cor * scale_factor
arrow_data$UMAP_2 <- arrow_data$UMAP_2_cor * scale_factor
# 6. Calculate Cluster Centroids for Labels
cluster_centroids <- umap_data %>%
group_by(Cluster) %>%
summarise(
umap_1_center = median(umap_1),
umap_2_center = median(umap_2)
)
# 7. Plot UMAP Biplot with Cluster Labels
p_umap_biplot <- ggplot(umap_data, aes(x = umap_1, y = umap_2)) +
# Points (Cells) - larger and more visible
geom_point(aes(color = Cluster), alpha = 0.7, size = 2) +
# Cluster Labels (at centroids)
geom_text(data = cluster_centroids,
aes(x = umap_1_center, y = umap_2_center, label = Cluster),
fontface = "bold", size = 6, color = "black") +
# Arrows (TFs) - from center of UMAP
geom_segment(data = arrow_data,
aes(x = mean(umap_data$umap_1), y = mean(umap_data$umap_2),
xend = mean(umap_data$umap_1) + UMAP_1,
yend = mean(umap_data$umap_2) + UMAP_2),
arrow = arrow(length = unit(0.25, "cm")),
color = "darkred", linewidth = 1) +
# TF Labels (using ggrepel to avoid overlap with cluster labels)
geom_text_repel(data = arrow_data,
aes(x = mean(umap_data$umap_1) + UMAP_1,
y = mean(umap_data$umap_2) + UMAP_2,
label = TF),
fontface = "bold.italic", color = "darkred", size = 4.5,
box.padding = 0.6, point.padding = 0.4,
min.segment.length = 0.2) +
# Styling
scale_color_manual(values = Seurat::DiscretePalette(14)) +
labs(title = "Regulatory Drivers in UMAP Space",
subtitle = "Cluster numbers shown at centroids; TF arrows indicate regulatory associations",
x = "UMAP_1",
y = "UMAP_2") +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 14),
legend.position = "right",
panel.grid.minor = element_blank()
)
# Save
ggsave("Output_Figures/Supplementary_TF_UMAP_Biplot.pdf", p_umap_biplot, width = 12, height = 9)
print(p_umap_biplot)

Check marker expression
to validate root choice
library(Seurat)
library(ggplot2)
library(dplyr)
library(pheatmap)
# Make sure SCT is default
DefaultAssay(seurat_obj) <- "SCT"
# SƩzary-specific markers
sezary_markers <- list(
early_memory = c("CCR7", "SELL", "TCF7", "LEF1"),
malignant = c("TOX", "TWIST1", "DNM3", "STAT5A"),
exhausted = c("PDCD1", "CTLA4", "TIGIT", "LAG3"),
proliferative = c("MKI67", "TOP2A", "PCNA")
)
all_markers <- unlist(sezary_markers)
# ============================================
# 1. DOT PLOT - ALL CLUSTERS
# ============================================
p_dot <- DotPlot(seurat_obj,
features = sezary_markers,
assay = "SCT", # Explicitly specify assay
cols = c("lightgrey", "red"),
dot.scale = 6) +
coord_flip() +
ggtitle("SƩzary Markers Across All Clusters") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
axis.text.y = element_text(size = 10)) +
labs(x = "Markers", y = "Clusters")
print(p_dot)
ggsave("Output_Figures/Sezary_Markers_DotPlot_AllClusters.pdf", p_dot, width = 14, height = 8)
# ============================================
# 2. AVERAGE EXPRESSION (FIXED)
# ============================================
# Use AggregateExpression (recommended in Seurat v5) with correct assay
avg_exp <- AggregateExpression(seurat_obj,
features = all_markers,
assays = "SCT", # Specify SCT only
group.by = "seurat_clusters",
slot = "data",
return.seurat = FALSE)
# Extract the SCT matrix
expr_matrix <- as.matrix(avg_exp$SCT)
# Check dimensions
cat("Expression matrix dimensions:", nrow(expr_matrix), "genes x", ncol(expr_matrix), "clusters\n")
Expression matrix dimensions: 15 genes x 14 clusters
print(head(expr_matrix))
g0 g1 g2 g3 g4 g5 g6 g7 g8 g9 g10 g11 g12 g13
CCR7 14443 1144 11455 17619 12865 5533 9463 4391 7776 5016 8035 3217 4113 8053
SELL 1558 145 657 17789 753 3982 277 2210 1287 2874 9643 1256 409 115
TCF7 125 3808 341 19510 52 3758 402 1011 50 2130 8873 368 207 114
LEF1 687 9412 761 14007 169 9625 771 1806 206 4801 5217 962 326 68
TOX 2074 14642 984 132 784 2792 373 1300 2539 1715 491 675 411 157
TWIST1 3668 3259 2324 0 3893 212 1720 1276 2535 559 28 674 466 496
# ============================================
# 3. HEATMAP - Scaled Expression
# ============================================
# Scale by row (gene) for better visualization
expr_matrix_scaled <- t(scale(t(expr_matrix)))
# Annotation for marker categories
annotation_row <- data.frame(
Category = rep(names(sezary_markers), times = sapply(sezary_markers, length)),
row.names = all_markers
)
annotation_colors <- list(
Category = c(early_memory = "#4DAF4A",
malignant = "#E41A1C",
exhausted = "#377EB8",
proliferative = "#FF7F00")
)
pdf("Output_Figures/Sezary_Markers_Heatmap_AllClusters.pdf", width = 12, height = 8)

pheatmap(expr_matrix_scaled,
cluster_rows = FALSE,
cluster_cols = TRUE,
annotation_row = annotation_row,
annotation_colors = annotation_colors,
color = colorRampPalette(c("navy", "white", "firebrick"))(100),
main = "SƩzary Markers - All Clusters (Scaled)",
fontsize = 10,
angle_col = 0)
dev.off()
pdf
3

# ============================================
# 4. CALCULATE CATEGORY SCORES PER CLUSTER
# ============================================
category_scores <- data.frame()
for(category in names(sezary_markers)) {
markers_in_category <- sezary_markers[[category]]
# Calculate mean expression per cluster for this category
category_mean <- colMeans(expr_matrix[markers_in_category, , drop = FALSE])
temp_df <- data.frame(
Cluster = names(category_mean),
Category = category,
Score = as.numeric(category_mean)
)
category_scores <- rbind(category_scores, temp_df)
}
# Reshape for easier analysis
library(tidyr)
category_scores_wide <- category_scores %>%
pivot_wider(names_from = Category, values_from = Score)
# Remove 'g' prefix if present (Seurat adds this)
category_scores_wide$Cluster <- gsub("^g", "", category_scores_wide$Cluster)
cat("\n=== CATEGORY SCORES BY CLUSTER ===\n")
=== CATEGORY SCORES BY CLUSTER ===
print(category_scores_wide)
# A tibble: 14 Ć 5
Cluster early_memory malignant exhausted proliferative
<chr> <dbl> <dbl> <dbl> <dbl>
1 0 4203. 2576. 382. 16194.
2 1 3627. 4727. 101. 21402.
3 2 3304. 1559 3609. 5791.
4 3 17231. 397. 146. 215.
5 4 3460. 1658. 133 10292
6 5 5724. 1007. 173 6241
7 6 2728. 1211. 2705. 8700.
8 7 2354. 1136. 306. 15908.
9 8 2330. 1832. 4309 12281.
10 9 3705. 720. 220 2966
11 10 7942 390. 442. 272.
12 11 1451. 510. 575 1660.
13 12 1264. 608. 388. 2580.
14 13 2088. 354. 265. 1797.
# ============================================
# 5. IDENTIFY CLUSTER PHENOTYPES
# ============================================
cat("\n=== CLUSTER PHENOTYPE CLASSIFICATION ===\n")
=== CLUSTER PHENOTYPE CLASSIFICATION ===
# Rank clusters by each category
rankings <- category_scores_wide %>%
mutate(
early_memory_rank = rank(-early_memory),
malignant_rank = rank(-malignant),
exhausted_rank = rank(-exhausted),
proliferative_rank = rank(-proliferative)
)
# Identify top 3 clusters per category
cat("\nā Top 3 STEM-LIKE clusters (Early Memory):\n")
ā Top 3 STEM-LIKE clusters (Early Memory):
top_memory <- rankings %>% arrange(early_memory_rank) %>% head(3) %>%
select(Cluster, early_memory, early_memory_rank)
print(top_memory)
# A tibble: 3 Ć 3
Cluster early_memory early_memory_rank
<chr> <dbl> <dbl>
1 3 17231. 1
2 10 7942 2
3 5 5724. 3
cat("\nā Top 3 MALIGNANT clusters:\n")
ā Top 3 MALIGNANT clusters:
top_malignant <- rankings %>% arrange(malignant_rank) %>% head(3) %>%
select(Cluster, malignant, malignant_rank)
print(top_malignant)
# A tibble: 3 Ć 3
Cluster malignant malignant_rank
<chr> <dbl> <dbl>
1 1 4727. 1
2 0 2576. 2
3 8 1832. 3
cat("\nā Top 3 EXHAUSTED/TERMINAL clusters:\n")
ā Top 3 EXHAUSTED/TERMINAL clusters:
top_exhausted <- rankings %>% arrange(exhausted_rank) %>% head(3) %>%
select(Cluster, exhausted, exhausted_rank)
print(top_exhausted)
# A tibble: 3 Ć 3
Cluster exhausted exhausted_rank
<chr> <dbl> <dbl>
1 8 4309 1
2 2 3609. 2
3 6 2705. 3
cat("\nā Top 3 PROLIFERATIVE clusters:\n")
ā Top 3 PROLIFERATIVE clusters:
top_prolif <- rankings %>% arrange(proliferative_rank) %>% head(3) %>%
select(Cluster, proliferative, proliferative_rank)
print(top_prolif)
# A tibble: 3 Ć 3
Cluster proliferative proliferative_rank
<chr> <dbl> <dbl>
1 1 21402. 1
2 0 16194. 2
3 7 15908. 3
# ============================================
# 6. BARPLOT - Category Scores
# ============================================
p_bar <- ggplot(category_scores, aes(x = gsub("^g", "", Cluster), y = Score, fill = Category)) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_manual(values = c(early_memory = "#4DAF4A",
malignant = "#E41A1C",
exhausted = "#377EB8",
proliferative = "#FF7F00")) +
labs(title = "Functional Signatures Across All Clusters",
x = "Cluster", y = "Mean Expression Score") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(face = "bold", size = 14),
legend.position = "right")
print(p_bar)
ggsave("Output_Figures/Sezary_CategoryScores_Barplot.pdf", p_bar, width = 14, height = 6)
# ============================================
# 7. TRAJECTORY ROOT RECOMMENDATION
# ============================================
cat("\n=== TRAJECTORY INFERENCE RECOMMENDATION ===\n")
=== TRAJECTORY INFERENCE RECOMMENDATION ===
trajectory_guide <- category_scores_wide %>%
mutate(
Stemness_Score = early_memory,
Differentiation_Score = (exhausted + malignant) / 2,
Balance = Stemness_Score - Differentiation_Score
) %>%
arrange(desc(Balance))
cat("\nClusters ranked by Stemness Score:\n")
Clusters ranked by Stemness Score:
print(trajectory_guide %>% select(Cluster, Stemness_Score, Differentiation_Score, Balance))
# A tibble: 14 Ć 4
Cluster Stemness_Score Differentiation_Score Balance
<chr> <dbl> <dbl> <dbl>
1 3 17231. 271. 16960
2 10 7942 416 7526
3 5 5724. 590. 5135.
4 9 3705. 470. 3236.
5 0 4203. 1479. 2724.
6 4 3460. 895. 2564.
7 13 2088. 310. 1778.
8 7 2354. 721. 1634.
9 1 3627. 2414 1213.
10 11 1451. 543. 908.
11 6 2728. 1958. 770
12 12 1264. 498. 766.
13 2 3304. 2584. 720.
14 8 2330. 3070. -740.
cat("\nāāā RECOMMENDED ROOT CLUSTER: ",
trajectory_guide$Cluster[1],
" (highest stemness, lowest differentiation)\n\n", sep = "")
āāā RECOMMENDED ROOT CLUSTER: 3 (highest stemness, lowest differentiation)
cat("ā POTENTIAL TERMINAL CLUSTERS: ",
paste(tail(trajectory_guide$Cluster, 3), collapse = ", "),
" (high exhaustion/malignancy)\n\n", sep = "")
ā POTENTIAL TERMINAL CLUSTERS: 12, 2, 8 (high exhaustion/malignancy)
# Save summary tables
write.csv(category_scores_wide, "Output_Figures/Cluster_Phenotype_Scores.csv", row.names = FALSE)
write.csv(trajectory_guide, "Output_Figures/Trajectory_Root_Recommendations.csv", row.names = FALSE)
cat("ā Analysis complete! Tables saved to Output_Figures/\n")
ā Analysis complete! Tables saved to Output_Figures/
ROBUST Entropy Analysis
(No External Dependencies)
library(Seurat)
library(ggplot2)
library(dplyr)
library(patchwork)
DefaultAssay(seurat_obj) <- "SCT"
cat("Computing entropy-based stemness metrics...\n")
Computing entropy-based stemness metrics...
# ============================================
# Function: Shannon Entropy Calculation
# ============================================
calculate_shannon_entropy <- function(expression_vector) {
expr_nonzero <- expression_vector[expression_vector > 0]
if(length(expr_nonzero) == 0) return(0)
probs <- expr_nonzero / sum(expr_nonzero)
entropy <- -sum(probs * log2(probs))
return(entropy)
}
# ============================================
# Function: Gini Coefficient (Specialization)
# ============================================
calculate_gini <- function(x) {
x <- x[x > 0]
if(length(x) == 0) return(0)
n <- length(x)
x_sorted <- sort(x)
gini <- (2 * sum((1:n) * x_sorted)) / (n * sum(x_sorted)) - (n + 1) / n
return(gini)
}
# ============================================
# STEP 1: Calculate Entropy Per Cell
# ============================================
expr_matrix <- GetAssayData(seurat_obj, assay = "SCT", layer = "data")
hvgs <- VariableFeatures(seurat_obj)
expr_hvg <- expr_matrix[hvgs, ]
cat("Calculating entropy for", ncol(expr_hvg), "cells using", length(hvgs), "HVGs...\n")
Calculating entropy for 49305 cells using 3000 HVGs...
# Shannon Entropy
entropy_scores <- apply(expr_hvg, 2, calculate_shannon_entropy)
seurat_obj$Shannon_Entropy <- entropy_scores
# Gini Index
gini_scores <- apply(expr_hvg, 2, calculate_gini)
seurat_obj$Gini_Index <- gini_scores
# Transcriptional Diversity Score
seurat_obj$Diversity_Score <- seurat_obj$nFeature_RNA / max(seurat_obj$nFeature_RNA)
# ============================================
# STEP 2: Combined Stemness Score
# ============================================
# Normalize and combine metrics
seurat_obj$Stemness_Score <-
scales::rescale(seurat_obj$Shannon_Entropy, to = c(0, 1)) * 0.4 +
(1 - scales::rescale(seurat_obj$Gini_Index, to = c(0, 1))) * 0.3 + # Invert Gini
seurat_obj$Diversity_Score * 0.3
# ============================================
# STEP 3: Per-Cluster Analysis
# ============================================
cluster_potency <- seurat_obj@meta.data %>%
group_by(seurat_clusters) %>%
summarize(
n_cells = n(),
mean_entropy = mean(Shannon_Entropy),
mean_gini = mean(Gini_Index),
mean_diversity = mean(Diversity_Score),
mean_stemness = mean(Stemness_Score),
sd_stemness = sd(Stemness_Score)
) %>%
arrange(desc(mean_stemness))
cat("\n=== STEMNESS/POTENCY SCORES BY CLUSTER ===\n")
=== STEMNESS/POTENCY SCORES BY CLUSTER ===
print(cluster_potency)
# A tibble: 14 Ć 7
seurat_clusters n_cells mean_entropy mean_gini mean_diversity mean_stemness sd_stemness
<fct> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 8 3338 9.92 0.318 0.654 0.587 0.0610
2 12 1063 9.74 0.317 0.586 0.536 0.0958
3 1 5275 9.75 0.324 0.609 0.535 0.0642
4 13 691 9.70 0.319 0.524 0.508 0.0750
5 6 3536 9.67 0.316 0.498 0.498 0.0637
6 0 6789 9.66 0.323 0.529 0.496 0.0651
7 7 3409 9.67 0.312 0.472 0.495 0.0693
8 4 4086 9.66 0.328 0.540 0.494 0.0668
9 5 3634 9.59 0.311 0.480 0.485 0.0824
10 2 4663 9.56 0.323 0.467 0.459 0.0709
11 11 1675 9.55 0.306 0.352 0.446 0.0692
12 9 3273 9.33 0.332 0.356 0.375 0.0544
13 10 3212 9.15 0.291 0.281 0.374 0.0785
14 3 4661 8.98 0.304 0.247 0.319 0.0669
# ============================================
# VISUALIZATION 1: Stemness Score Barplot
# ============================================
p1 <- ggplot(cluster_potency,
aes(x = reorder(seurat_clusters, -mean_stemness),
y = mean_stemness,
fill = mean_stemness)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = mean_stemness - sd_stemness,
ymax = mean_stemness + sd_stemness),
width = 0.3, alpha = 0.5) +
scale_fill_gradient(low = "blue", high = "red") +
labs(title = "Entropy-Based Stemness Score by Cluster",
subtitle = "Combined metric: Shannon entropy + Gini + Diversity",
x = "Cluster", y = "Mean Stemness Score",
fill = "Stemness") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, face = "bold", size = 11),
plot.title = element_text(face = "bold", size = 14))
print(p1)

# ============================================
# VISUALIZATION 2: Stemness on UMAP
# ============================================
p2 <- FeaturePlot(seurat_obj,
features = "Stemness_Score",
reduction = "umap",
pt.size = 1.5) +
scale_color_gradient(low = "blue", high = "red") +
labs(title = "Stemness Score in UMAP Space",
subtitle = "Red = High stemness/potency")
print(p2)

# ============================================
# VISUALIZATION 3: Component Scores Heatmap
# ============================================
library(reshape2)
heatmap_data <- cluster_potency %>%
select(seurat_clusters, mean_entropy, mean_gini, mean_diversity) %>%
mutate(mean_gini = 1 - mean_gini) %>% # Invert for consistency
mutate(across(c(mean_entropy, mean_gini, mean_diversity),
~scales::rescale(.x, to = c(0, 1)))) %>%
melt(id.vars = "seurat_clusters")
p3 <- ggplot(heatmap_data, aes(x = variable, y = seurat_clusters, fill = value)) +
geom_tile(color = "white") +
geom_text(aes(label = round(value, 2)), color = "black", size = 3.5) +
scale_fill_gradient2(low = "blue", mid = "white", high = "red",
midpoint = 0.5) +
labs(title = "Component Metrics of Stemness",
x = "Metric", y = "Cluster", fill = "Normalized\nScore") +
scale_x_discrete(labels = c("Entropy", "Specialization", "Diversity")) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p3)

# ============================================
# VISUALIZATION 4: Violin Plot
# ============================================
p4 <- VlnPlot(seurat_obj,
features = "Stemness_Score",
pt.size = 0) +
labs(title = "Stemness Score Distribution",
x = "Cluster", y = "Stemness Score") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p4)

# ============================================
# INTEGRATE WITH SĆZARY MARKERS
# ============================================
sezary_markers <- list(
early_memory = c("CCR7", "SELL", "TCF7", "LEF1"),
exhausted = c("PDCD1", "CTLA4", "TIGIT", "LAG3")
)
seurat_obj <- AddModuleScore(seurat_obj,
features = sezary_markers,
name = c("EarlyMemory", "Exhausted"))
cor_memory <- cor(seurat_obj$Stemness_Score, seurat_obj$EarlyMemory1, use = "complete.obs")
cor_exhausted <- cor(seurat_obj$Stemness_Score, seurat_obj$Exhausted2, use = "complete.obs")
cat("\n=== VALIDATION AGAINST MARKER GENES ===\n")
=== VALIDATION AGAINST MARKER GENES ===
cat("Correlation Stemness vs Early Memory:", round(cor_memory, 3), "\n")
Correlation Stemness vs Early Memory: -0.583
cat("Correlation Stemness vs Exhaustion:", round(cor_exhausted, 3), "\n")
Correlation Stemness vs Exhaustion: 0.063
p5 <- ggplot(seurat_obj@meta.data,
aes(x = Stemness_Score, y = EarlyMemory1, color = seurat_clusters)) +
geom_point(alpha = 0.5) +
geom_smooth(method = "lm", color = "black") +
labs(title = "Stemness Score vs Early Memory Markers",
subtitle = paste0("r = ", round(cor_memory, 3)),
x = "Stemness Score", y = "Early Memory Score") +
theme_minimal()
print(p5)

# ============================================
# ROOT RECOMMENDATION
# ============================================
cat("\n=== TRAJECTORY ROOT RECOMMENDATION ===\n\n")
=== TRAJECTORY ROOT RECOMMENDATION ===
cat("āāā HIGHEST STEMNESS/POTENCY CLUSTER: ", cluster_potency$seurat_clusters, "\n")[1]
āāā HIGHEST STEMNESS/POTENCY CLUSTER: 9 13 2 14 7 1 8 5 6 3 12 10 11 4
NULL
cat(" Stemness Score: ", round(cluster_potency$mean_stemness, 3), "\n\n")[1]
Stemness Score: 0.587 0.536 0.535 0.508 0.498 0.496 0.495 0.494 0.485 0.459 0.446 0.375 0.374 0.319
NULL
cat("ā Top 3 stem-like clusters:\n")
ā Top 3 stem-like clusters:
print(cluster_potency %>% head(3) %>% select(seurat_clusters, mean_stemness))
# A tibble: 3 Ć 2
seurat_clusters mean_stemness
<fct> <dbl>
1 8 0.587
2 12 0.536
3 1 0.535
cat("\nā Top 3 differentiated clusters:\n")
ā Top 3 differentiated clusters:
print(cluster_potency %>% tail(3) %>% select(seurat_clusters, mean_stemness))
# A tibble: 3 Ć 2
seurat_clusters mean_stemness
<fct> <dbl>
1 9 0.375
2 10 0.374
3 3 0.319
# ============================================
# SAVE RESULTS
# ============================================
write.csv(cluster_potency,
"Output_Figures/Stemness_Potency_ByCluster.csv",
row.names = FALSE)
# Combined figure
p_combined <- (p1 | p2) / (p3 | p4) +
plot_annotation(title = "Entropy-Based Stemness Analysis",
subtitle = "Root-free differentiation state assessment",
theme = theme(plot.title = element_text(size = 16, face = "bold")))
print(p_combined)

ggsave("Output_Figures/Stemness_Analysis_Complete.pdf", p_combined,
width = 16, height = 12)
cat("\nā Analysis complete! All results saved to Output_Figures/\n")
ā Analysis complete! All results saved to Output_Figures/
LS0tCnRpdGxlOiAiUEFHQSB1c2luZyBURiBBY3Rpdml0eSIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKCiMgbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0KIyBEYXRhIFByb2Nlc3NpbmcKbGlicmFyeShkcGx5cikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCgojIFZpc3VhbGl6YXRpb24KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShTQ3B1YnIpCgojIFJlZ3VsYXRvcnkgTmV0d29yayBJbmZlcmVuY2UKbGlicmFyeShkZWNvdXBsZVIpCmxpYnJhcnkoZG9yb3RoZWEpCmRhdGEoZG9yb3RoZWFfaHMsIHBhY2thZ2UgPSAiZG9yb3RoZWEiKQpsaWJyYXJ5KHRpY3RvYykKCgpgYGAKCiMgTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkocmV0aWN1bGF0ZSkKbGlicmFyeShnZ3Bsb3QyKQoKIyAxLiBMb2FkIE9iamVjdApzZXVyYXRfb2JqIDwtIHJlYWRSRFMoInRlbXBfc2V1cmF0X29iai5yZHMiKQoKCgpgYGAKCiMgU1VQUExFTUVOVEFSWSBGSUdVUkU6IFBBR0EgVHJhamVjdG9yeSBBbmFseXNpcyAodmlhIFJldGljdWxhdGUvU2NhbnB5KQpgYGB7ciwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTE2fQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShyZXRpY3VsYXRlKQpsaWJyYXJ5KGdncGxvdDIpCgojIDEuIEZPUkNFIFVTRSBvZiB0aGUgc3BlY2lmaWMgcHl0aG9uIGJpbmFyeSB3aGVyZSBzY2FucHkgaXMgaW5zdGFsbGVkCiMgVGhpcyBvdmVycmlkZXMgdGhlIGRlZmF1bHQgImF1dG8iIGRpc2NvdmVyeSB3aGljaCBpcyBmYWlsaW5nIHlvdQpTeXMuc2V0ZW52KFJFVElDVUxBVEVfUFlUSE9OID0gIi9ob21lL2Jpb2luZm8vLnZpcnR1YWxlbnZzL3ItcmV0aWN1bGF0ZS9iaW4vcHl0aG9uIikKdXNlX3B5dGhvbigiL2hvbWUvYmlvaW5mby8udmlydHVhbGVudnMvci1yZXRpY3VsYXRlL2Jpbi9weXRob24iLCByZXF1aXJlZCA9IFRSVUUpCgojIDIuIFZlcmlmeSBpdCdzIHdvcmtpbmcgKE9wdGlvbmFsIGJ1dCBnb29kIGZvciBkZWJ1Z2dpbmcpCmNhdCgiVXNpbmcgUHl0aG9uOiIsIHB5X2NvbmZpZygpJHB5dGhvbiwgIlxuIikKCiMgMy4gSW1wb3J0IExpYnJhcmllcwpzYyA8LSBpbXBvcnQoInNjYW5weSIpCmFkIDwtIGltcG9ydCgiYW5uZGF0YSIpCgpjYXQoIuKckyBQeXRob24gbGlicmFyaWVzIGltcG9ydGVkIHN1Y2Nlc3NmdWxseSFcbiIpCgojIDQuIFByZXBhcmUgRGF0YSBmb3IgUEFHQQpjYXQoIkNvbnZlcnRpbmcgU2V1cmF0IG9iamVjdCB0byBBbm5EYXRhLi4uXG4iKQp0Zl9tYXRyaXggPC0gdChHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJkYXRhIikpCm9icyA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKHNldXJhdF9vYmopLCAKICAgICAgICAgICAgICAgICAgbG91dmFpbiA9IGFzLmNoYXJhY3RlcihzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycykpCgphZGF0YSA8LSBhZCRBbm5EYXRhKFggPSB0Zl9tYXRyaXgsIG9icyA9IG9icykKCiMgNS4gUnVuIFNjYW5weSBXb3JrZmxvdwpjYXQoIlJ1bm5pbmcgUEFHQS4uLlxuIikKc2MkcHAkbmVpZ2hib3JzKGFkYXRhLCB1c2VfcmVwID0gIlgiLCBuX25laWdoYm9ycyA9IDE1TCkKc2MkdGwkcGFnYShhZGF0YSwgZ3JvdXBzID0gImxvdXZhaW4iKQoKIyA2LiBQbG90IGFuZCBTYXZlCm91dHB1dF9maWxlIDwtICJPdXRwdXRfRmlndXJlcy9TdXBwbGVtZW50YXJ5X1BBR0FfVEZfQWN0aXZpdHkucG5nIgppZighZGlyLmV4aXN0cygiT3V0cHV0X0ZpZ3VyZXMiKSkgZGlyLmNyZWF0ZSgiT3V0cHV0X0ZpZ3VyZXMiKQoKIyBDT1JSRUNUIE9SREVSOiBEcmF3IFBBR0EgZmlyc3QgdG8gY29tcHV0ZSBwb3NpdGlvbnMKc2MkcGwkcGFnYShhZGF0YSwgdGhyZXNob2xkID0gMC4xNSwgc2hvdyA9IEZBTFNFKQoKIyBOb3cgVU1BUCBjYW4gdXNlIHRob3NlIHBvc2l0aW9ucwpzYyR0bCR1bWFwKGFkYXRhLCBpbml0X3BvcyA9ICJwYWdhIikKCiMgUGxvdCBQQUdBIHdpdGggY29ubmVjdGl2aXR5IHRocmVzaG9sZApzYyRwbCRwYWdhKGFkYXRhLCB0aHJlc2hvbGQgPSAwLjE1LCBzaG93ID0gRkFMU0UsIHNhdmUgPSAiX1RGX0FjdGl2aXR5LnBuZyIpCgojIFNjYW5weSBzYXZlcyB0byAiZmlndXJlcy8iIGJ5IGRlZmF1bHQKaWYoZmlsZS5leGlzdHMoImZpZ3VyZXMvcGFnYV9URl9BY3Rpdml0eS5wbmciKSl7CiAgZmlsZS5yZW5hbWUoImZpZ3VyZXMvcGFnYV9URl9BY3Rpdml0eS5wbmciLCBvdXRwdXRfZmlsZSkKICBjYXQoc3ByaW50Zigi4pyTIFBBR0EgcGxvdCBzYXZlZCB0bzogJXNcbiIsIG91dHB1dF9maWxlKSkKfSBlbHNlIHsKICBjYXQoIk5vdGU6IENoZWNrICcuL2ZpZ3VyZXMvJyBkaXJlY3RvcnkgZm9yIG91dHB1dFxuIikKfQoKIyBEaXNwbGF5IGluIG5vdGVib29rCmlmKGZpbGUuZXhpc3RzKG91dHB1dF9maWxlKSl7CiAga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3Mob3V0cHV0X2ZpbGUpCn0KCmBgYAoKIyBTVVBQTEVNRU5UQVJZIEZJR1VSRTogUEFHQSBvbiBHZW5lIEV4cHJlc3Npb24gKFNDVCBBc3NheSkKYGBge3IsIGZpZy5oZWlnaHQ9MTYsIGZpZy53aWR0aD0xNn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkocmV0aWN1bGF0ZSkKCiMgVXNlIHNhbWUgcHl0aG9uIGVudmlyb25tZW50ClN5cy5zZXRlbnYoUkVUSUNVTEFURV9QWVRIT04gPSAiL2hvbWUvYmlvaW5mby8udmlydHVhbGVudnMvci1yZXRpY3VsYXRlL2Jpbi9weXRob24iKQp1c2VfcHl0aG9uKCIvaG9tZS9iaW9pbmZvLy52aXJ0dWFsZW52cy9yLXJldGljdWxhdGUvYmluL3B5dGhvbiIsIHJlcXVpcmVkID0gVFJVRSkKCnNjIDwtIGltcG9ydCgic2NhbnB5IikKYWQgPC0gaW1wb3J0KCJhbm5kYXRhIikKCmNhdCgi4pyTIFB5dGhvbiBsaWJyYXJpZXMgaW1wb3J0ZWRcbiIpCgojIDEuIEV4dHJhY3QgU0NULW5vcm1hbGl6ZWQgZ2VuZSBleHByZXNzaW9uCkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiU0NUIgoKIyBVc2UgaGlnaGx5IHZhcmlhYmxlIGZlYXR1cmVzIGZyb20gU0NUCmh2Z3MgPC0gVmFyaWFibGVGZWF0dXJlcyhzZXVyYXRfb2JqKQoKIyBHZXQgbm9ybWFsaXplZCBkYXRhIChsb2cxcCBvZiBjb3JyZWN0ZWQgY291bnRzKQpnZW5lX21hdHJpeCA8LSB0KEdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJTQ1QiLCBsYXllciA9ICJkYXRhIilbaHZncywgXSkKCmNhdChzcHJpbnRmKCJVc2luZyAlZCBoaWdobHkgdmFyaWFibGUgZ2VuZXMgZnJvbSBTQ1QgYXNzYXlcbiIsIGxlbmd0aChodmdzKSkpCgojIDIuIFByZXBhcmUgQW5uRGF0YSBvYmplY3QKb2JzIDwtIGRhdGEuZnJhbWUoCiAgcm93Lm5hbWVzID0gY29sbmFtZXMoc2V1cmF0X29iaiksCiAgbG91dmFpbiA9IGFzLmNoYXJhY3RlcihzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycykKKQoKYWRhdGFfc2N0IDwtIGFkJEFubkRhdGEoWCA9IGdlbmVfbWF0cml4LCBvYnMgPSBvYnMpCgojIDMuIFJ1biBQQUdBIHdvcmtmbG93CmNhdCgiQ29tcHV0aW5nIG5laWdoYm9ycyBhbmQgUEFHQSBvbiBTQ1Qtbm9ybWFsaXplZCBleHByZXNzaW9uLi4uXG4iKQpzYyRwcCRuZWlnaGJvcnMoYWRhdGFfc2N0LCB1c2VfcmVwID0gIlgiLCBuX25laWdoYm9ycyA9IDE1TCkKc2MkdGwkcGFnYShhZGF0YV9zY3QsIGdyb3VwcyA9ICJsb3V2YWluIikKCiMgNC4gUGxvdCBhbmQgc2F2ZQpvdXRwdXRfZmlsZV9zY3QgPC0gIk91dHB1dF9GaWd1cmVzL1N1cHBsZW1lbnRhcnlfUEFHQV9HZW5lRXhwcmVzc2lvbl9TQ1QucG5nIgoKIyBEcmF3IFBBR0EgZmlyc3QgdG8gY29tcHV0ZSBwb3NpdGlvbnMKc2MkcGwkcGFnYShhZGF0YV9zY3QsIHRocmVzaG9sZCA9IDAuMTUsIHNob3cgPSBGQUxTRSkKCiMgQ29tcHV0ZSBVTUFQIGluaXRpYWxpemVkIGJ5IFBBR0EKc2MkdGwkdW1hcChhZGF0YV9zY3QsIGluaXRfcG9zID0gInBhZ2EiKQoKIyBGaW5hbCBQQUdBIHBsb3QKc2MkcGwkcGFnYShhZGF0YV9zY3QsIHRocmVzaG9sZCA9IDAuMTUsIHNob3cgPSBGQUxTRSwgc2F2ZSA9ICJfR2VuZUV4cHJlc3Npb25fU0NULnBuZyIpCgojIE1vdmUgZnJvbSBmaWd1cmVzLyB0byBPdXRwdXRfRmlndXJlcy8KaWYoZmlsZS5leGlzdHMoImZpZ3VyZXMvcGFnYV9HZW5lRXhwcmVzc2lvbl9TQ1QucG5nIikpewogIGZpbGUucmVuYW1lKCJmaWd1cmVzL3BhZ2FfR2VuZUV4cHJlc3Npb25fU0NULnBuZyIsIG91dHB1dF9maWxlX3NjdCkKICBjYXQoc3ByaW50Zigi4pyTIFNDVCBHZW5lIEV4cHJlc3Npb24gUEFHQSBzYXZlZCB0bzogJXNcbiIsIG91dHB1dF9maWxlX3NjdCkpCn0KCiMgRGlzcGxheQppZihmaWxlLmV4aXN0cyhvdXRwdXRfZmlsZV9zY3QpKXsKICBrbml0cjo6aW5jbHVkZV9ncmFwaGljcyhvdXRwdXRfZmlsZV9zY3QpCn0KYGBgCiMgU1VQUExFTUVOVEFSWSBGSUdVUkU6IFF1aWNrIENvZGUgdG8gR2VuZXJhdGUgTWFsaWduYW50LU9ubHkgUEFHQQpgYGB7ciBwYWdhX2FuYWx5c2lzX1NDVCwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTE2fQojIFJ1biBQQUdBIG9uIG1hbGlnbmFudCBjZWxscyBvbmx5CmxpYnJhcnkocmV0aWN1bGF0ZSkKbGlicmFyeShTZXVyYXQpCgojIDEuIFN1YnNldCB0byBtYWxpZ25hbnQgY2VsbHMKbWFsaWduYW50X2NsdXN0ZXJzIDwtIHNldGRpZmYodW5pcXVlKHNldXJhdF9vYmokc2V1cmF0X2NsdXN0ZXJzKSwgYygzLCAxMCkpCnNldXJhdF9tYWxpZ25hbnQgPC0gc3Vic2V0KHNldXJhdF9vYmosIHN1YnNldCA9IHNldXJhdF9jbHVzdGVycyAlaW4lIG1hbGlnbmFudF9jbHVzdGVycykKCiMgMi4gUHJlcGFyZSBmb3IgUEFHQQpzYyA8LSBpbXBvcnQoInNjYW5weSIpCmFkIDwtIGltcG9ydCgiYW5uZGF0YSIpCgojIEdldCBleHByZXNzaW9uIG1hdHJpeCBhbmQgbWV0YWRhdGEgKG1hbGlnbmFudCBvbmx5KQpleHByX21hdHJpeCA8LSB0KEdldEFzc2F5RGF0YShzZXVyYXRfbWFsaWduYW50LCBhc3NheSA9ICJTQ1QiLCBsYXllciA9ICJkYXRhIikpCm9icyA8LSBkYXRhLmZyYW1lKAogIHJvdy5uYW1lcyA9IGNvbG5hbWVzKHNldXJhdF9tYWxpZ25hbnQpLAogIGxvdXZhaW4gPSBhcy5jaGFyYWN0ZXIoc2V1cmF0X21hbGlnbmFudCRzZXVyYXRfY2x1c3RlcnMpCikKCmFkYXRhX21hbGlnbmFudCA8LSBhZCRBbm5EYXRhKFggPSBleHByX21hdHJpeCwgb2JzID0gb2JzKQoKIyAzLiBSdW4gUEFHQQpzYyRwcCRuZWlnaGJvcnMoYWRhdGFfbWFsaWduYW50LCB1c2VfcmVwID0gIlgiLCBuX25laWdoYm9ycyA9IDE1TCkKc2MkdGwkcGFnYShhZGF0YV9tYWxpZ25hbnQsIGdyb3VwcyA9ICJsb3V2YWluIikKCiMgNC4gUGxvdApzYyRwbCRwYWdhKGFkYXRhX21hbGlnbmFudCwgdGhyZXNob2xkID0gMC4xNSwgc2hvdyA9IEZBTFNFKQoKIyBDb21wdXRlIFVNQVAgaW5pdGlhbGl6ZWQgYnkgUEFHQQpzYyR0bCR1bWFwKGFkYXRhX21hbGlnbmFudCwgaW5pdF9wb3MgPSAicGFnYSIpCgojIFNhdmUgZmlndXJlCnBsdCA8LSBpbXBvcnQoIm1hdHBsb3RsaWIucHlwbG90IikKc2MkcGwkcGFnYShhZGF0YV9tYWxpZ25hbnQsIHRocmVzaG9sZCA9IDAuMTUsIHNob3cgPSBGQUxTRSkgICMgRHJhdyB0aGUgcGxvdApwbHQkc2F2ZWZpZygiT3V0cHV0X0ZpZ3VyZXMvUEFHQV9NYWxpZ25hbnRfT25seS5wbmciLCBkcGkgPSAzMDBMLCBiYm94X2luY2hlcyA9ICJ0aWdodCIpCnBsdCRjbG9zZSgpCgpjYXQoIuKckyBNYWxpZ25hbnQtb25seSBQQUdBIHNhdmVkIHRvIE91dHB1dF9GaWd1cmVzL1BBR0FfTWFsaWduYW50X09ubHkucG5nXG4iKQoKCm91dHB1dF9maWxlIDwtICJPdXRwdXRfRmlndXJlcy9QQUdBX01hbGlnbmFudF9Pbmx5LnBuZyIKCmlmIChmaWxlLmV4aXN0cyhvdXRwdXRfZmlsZSkpIHsKICBrbml0cjo6aW5jbHVkZV9ncmFwaGljcyhvdXRwdXRfZmlsZSkKfQoKYGBgCgojIFNVUFBMRU1FTlRBUlkgRklHVVJFOiBVTUFQIEJpcGxvdCBDb2RlIChDb3JyZWxhdGlvbi1CYXNlZCBBcHByb2FjaCkKYGBge3IgLCBmaWcuaGVpZ2h0PTE2LCBmaWcud2lkdGg9MTZ9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKCiMgMS4gRXh0cmFjdCBVTUFQIEVtYmVkZGluZ3MKRGVmYXVsdEFzc2F5KHNldXJhdF9vYmopIDwtICJkb3JvdGhlYSIKdW1hcF9kYXRhIDwtIEVtYmVkZGluZ3Moc2V1cmF0X29iaiwgcmVkdWN0aW9uID0gInVtYXAiKVssIDE6Ml0gJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKENsdXN0ZXIgPSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMpKQoKIyAyLiBHZXQgVEYgQWN0aXZpdHkgTWF0cml4CnRmX21hdHJpeCA8LSBHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJkYXRhIikKCiMgMy4gQ29tcHV0ZSBURiBDb3JyZWxhdGlvbnMgd2l0aCBVTUFQIEF4ZXMKdGZfY29ycyA8LSBkYXRhLmZyYW1lKAogIFRGID0gcm93bmFtZXModGZfbWF0cml4KSwKICBVTUFQXzFfY29yID0gYXBwbHkodGZfbWF0cml4LCAxLCBmdW5jdGlvbih4KSBjb3IoeCwgdW1hcF9kYXRhJHVtYXBfMSkpLAogIFVNQVBfMl9jb3IgPSBhcHBseSh0Zl9tYXRyaXgsIDEsIGZ1bmN0aW9uKHgpIGNvcih4LCB1bWFwX2RhdGEkdW1hcF8yKSkKKQoKIyA0LiBGaWx0ZXIgVG9wIERyaXZlcnMgKFRvcCAzIHBlciBxdWFkcmFudCkKdW1hcDFfdG9wIDwtIHRmX2NvcnMgJT4lIGFycmFuZ2UoZGVzYyhVTUFQXzFfY29yKSkgJT4lIGhlYWQoMykgJT4lIHB1bGwoVEYpCnVtYXAxX2JvdHRvbSA8LSB0Zl9jb3JzICU+JSBhcnJhbmdlKFVNQVBfMV9jb3IpICU+JSBoZWFkKDMpICU+JSBwdWxsKFRGKQp1bWFwMl90b3AgPC0gdGZfY29ycyAlPiUgYXJyYW5nZShkZXNjKFVNQVBfMl9jb3IpKSAlPiUgaGVhZCgzKSAlPiUgcHVsbChURikKdW1hcDJfYm90dG9tIDwtIHRmX2NvcnMgJT4lIGFycmFuZ2UoVU1BUF8yX2NvcikgJT4lIGhlYWQoMykgJT4lIHB1bGwoVEYpCgp0b3BfdGZfZHJpdmVycyA8LSB1bmlxdWUoYyh1bWFwMV90b3AsIHVtYXAxX2JvdHRvbSwgdW1hcDJfdG9wLCB1bWFwMl9ib3R0b20pKQoKIyA1LiBQcmVwYXJlIEFycm93IERhdGEKYXJyb3dfZGF0YSA8LSB0Zl9jb3JzICU+JSBmaWx0ZXIoVEYgJWluJSB0b3BfdGZfZHJpdmVycykKCiMgU2NhbGUgYXJyb3dzIHRvIGZpdCBuaWNlbHkgb24gdGhlIHBsb3QKc2NhbGVfZmFjdG9yIDwtIG1heChhYnModW1hcF9kYXRhJHVtYXBfMSkpIC8gbWF4KGFicyhhcnJvd19kYXRhJFVNQVBfMV9jb3IpKSAqIDAuNwphcnJvd19kYXRhJFVNQVBfMSA8LSBhcnJvd19kYXRhJFVNQVBfMV9jb3IgKiBzY2FsZV9mYWN0b3IKYXJyb3dfZGF0YSRVTUFQXzIgPC0gYXJyb3dfZGF0YSRVTUFQXzJfY29yICogc2NhbGVfZmFjdG9yCgojIDYuIENhbGN1bGF0ZSBDbHVzdGVyIENlbnRyb2lkcyBmb3IgTGFiZWxzCmNsdXN0ZXJfY2VudHJvaWRzIDwtIHVtYXBfZGF0YSAlPiUKICBncm91cF9ieShDbHVzdGVyKSAlPiUKICBzdW1tYXJpc2UoCiAgICB1bWFwXzFfY2VudGVyID0gbWVkaWFuKHVtYXBfMSksCiAgICB1bWFwXzJfY2VudGVyID0gbWVkaWFuKHVtYXBfMikKICApCgojIDcuIFBsb3QgVU1BUCBCaXBsb3Qgd2l0aCBDbHVzdGVyIExhYmVscwpwX3VtYXBfYmlwbG90IDwtIGdncGxvdCh1bWFwX2RhdGEsIGFlcyh4ID0gdW1hcF8xLCB5ID0gdW1hcF8yKSkgKwogICMgUG9pbnRzIChDZWxscykgLSBsYXJnZXIgYW5kIG1vcmUgdmlzaWJsZQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gQ2x1c3RlciksIGFscGhhID0gMC43LCBzaXplID0gMikgKwogIAogICMgQ2x1c3RlciBMYWJlbHMgKGF0IGNlbnRyb2lkcykKICBnZW9tX3RleHQoZGF0YSA9IGNsdXN0ZXJfY2VudHJvaWRzLCAKICAgICAgICAgICAgYWVzKHggPSB1bWFwXzFfY2VudGVyLCB5ID0gdW1hcF8yX2NlbnRlciwgbGFiZWwgPSBDbHVzdGVyKSwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIHNpemUgPSA2LCBjb2xvciA9ICJibGFjayIpICsKICAKICAjIEFycm93cyAoVEZzKSAtIGZyb20gY2VudGVyIG9mIFVNQVAKICBnZW9tX3NlZ21lbnQoZGF0YSA9IGFycm93X2RhdGEsIAogICAgICAgICAgICAgICBhZXMoeCA9IG1lYW4odW1hcF9kYXRhJHVtYXBfMSksIHkgPSBtZWFuKHVtYXBfZGF0YSR1bWFwXzIpLCAKICAgICAgICAgICAgICAgICAgIHhlbmQgPSBtZWFuKHVtYXBfZGF0YSR1bWFwXzEpICsgVU1BUF8xLCAKICAgICAgICAgICAgICAgICAgIHllbmQgPSBtZWFuKHVtYXBfZGF0YSR1bWFwXzIpICsgVU1BUF8yKSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMjUsICJjbSIpKSwgCiAgICAgICAgICAgICAgIGNvbG9yID0gImRhcmtyZWQiLCBsaW5ld2lkdGggPSAxKSArCiAgCiAgIyBURiBMYWJlbHMgKHVzaW5nIGdncmVwZWwgdG8gYXZvaWQgb3ZlcmxhcCB3aXRoIGNsdXN0ZXIgbGFiZWxzKQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gYXJyb3dfZGF0YSwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbWVhbih1bWFwX2RhdGEkdW1hcF8xKSArIFVNQVBfMSwgCiAgICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbih1bWFwX2RhdGEkdW1hcF8yKSArIFVNQVBfMiwgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFRGKSwKICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZC5pdGFsaWMiLCBjb2xvciA9ICJkYXJrcmVkIiwgc2l6ZSA9IDQuNSwgCiAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC42LCBwb2ludC5wYWRkaW5nID0gMC40LAogICAgICAgICAgICAgICAgICBtaW4uc2VnbWVudC5sZW5ndGggPSAwLjIpICsKICAKICAjIFN0eWxpbmcKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gU2V1cmF0OjpEaXNjcmV0ZVBhbGV0dGUoMTQpKSArCiAgbGFicyh0aXRsZSA9ICJSZWd1bGF0b3J5IERyaXZlcnMgaW4gVU1BUCBTcGFjZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJDbHVzdGVyIG51bWJlcnMgc2hvd24gYXQgY2VudHJvaWRzOyBURiBhcnJvd3MgaW5kaWNhdGUgcmVndWxhdG9yeSBhc3NvY2lhdGlvbnMiLAogICAgICAgeCA9ICJVTUFQXzEiLCAKICAgICAgIHkgPSAiVU1BUF8yIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgU2F2ZQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL1N1cHBsZW1lbnRhcnlfVEZfVU1BUF9CaXBsb3QucGRmIiwgcF91bWFwX2JpcGxvdCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOSkKcHJpbnQocF91bWFwX2JpcGxvdCkKYGBgCgoKCiMgQ2hlY2sgbWFya2VyIGV4cHJlc3Npb24gdG8gdmFsaWRhdGUgcm9vdCBjaG9pY2UKYGBge3IgLCBmaWcuaGVpZ2h0PTE2LCBmaWcud2lkdGg9MTZ9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGhlYXRtYXApCgojIE1ha2Ugc3VyZSBTQ1QgaXMgZGVmYXVsdApEZWZhdWx0QXNzYXkoc2V1cmF0X29iaikgPC0gIlNDVCIKCiMgU8OpemFyeS1zcGVjaWZpYyBtYXJrZXJzCnNlemFyeV9tYXJrZXJzIDwtIGxpc3QoCiAgZWFybHlfbWVtb3J5ID0gYygiQ0NSNyIsICJTRUxMIiwgIlRDRjciLCAiTEVGMSIpLAogIG1hbGlnbmFudCA9IGMoIlRPWCIsICJUV0lTVDEiLCAiRE5NMyIsICJTVEFUNUEiKSwKICBleGhhdXN0ZWQgPSBjKCJQRENEMSIsICJDVExBNCIsICJUSUdJVCIsICJMQUczIiksCiAgcHJvbGlmZXJhdGl2ZSA9IGMoIk1LSTY3IiwgIlRPUDJBIiwgIlBDTkEiKQopCgphbGxfbWFya2VycyA8LSB1bmxpc3Qoc2V6YXJ5X21hcmtlcnMpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMS4gRE9UIFBMT1QgLSBBTEwgQ0xVU1RFUlMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpwX2RvdCA8LSBEb3RQbG90KHNldXJhdF9vYmosIAogICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gc2V6YXJ5X21hcmtlcnMsCiAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgICMgRXhwbGljaXRseSBzcGVjaWZ5IGFzc2F5CiAgICAgICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Z3JleSIsICJyZWQiKSwKICAgICAgICAgICAgICAgICBkb3Quc2NhbGUgPSA2KSArCiAgY29vcmRfZmxpcCgpICsKICBnZ3RpdGxlKCJTw6l6YXJ5IE1hcmtlcnMgQWNyb3NzIEFsbCBDbHVzdGVycyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIGxhYnMoeCA9ICJNYXJrZXJzIiwgeSA9ICJDbHVzdGVycyIpCgpwcmludChwX2RvdCkKZ2dzYXZlKCJPdXRwdXRfRmlndXJlcy9TZXphcnlfTWFya2Vyc19Eb3RQbG90X0FsbENsdXN0ZXJzLnBkZiIsIHBfZG90LCB3aWR0aCA9IDE0LCBoZWlnaHQgPSA4KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDIuIEFWRVJBR0UgRVhQUkVTU0lPTiAoRklYRUQpCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBVc2UgQWdncmVnYXRlRXhwcmVzc2lvbiAocmVjb21tZW5kZWQgaW4gU2V1cmF0IHY1KSB3aXRoIGNvcnJlY3QgYXNzYXkKYXZnX2V4cCA8LSBBZ2dyZWdhdGVFeHByZXNzaW9uKHNldXJhdF9vYmosIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYWxsX21hcmtlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXlzID0gIlNDVCIsICAjIFNwZWNpZnkgU0NUIG9ubHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAiZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuLnNldXJhdCA9IEZBTFNFKQoKIyBFeHRyYWN0IHRoZSBTQ1QgbWF0cml4CmV4cHJfbWF0cml4IDwtIGFzLm1hdHJpeChhdmdfZXhwJFNDVCkKCiMgQ2hlY2sgZGltZW5zaW9ucwpjYXQoIkV4cHJlc3Npb24gbWF0cml4IGRpbWVuc2lvbnM6IiwgbnJvdyhleHByX21hdHJpeCksICJnZW5lcyB4IiwgbmNvbChleHByX21hdHJpeCksICJjbHVzdGVyc1xuIikKcHJpbnQoaGVhZChleHByX21hdHJpeCkpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMy4gSEVBVE1BUCAtIFNjYWxlZCBFeHByZXNzaW9uCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTY2FsZSBieSByb3cgKGdlbmUpIGZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbgpleHByX21hdHJpeF9zY2FsZWQgPC0gdChzY2FsZSh0KGV4cHJfbWF0cml4KSkpCgojIEFubm90YXRpb24gZm9yIG1hcmtlciBjYXRlZ29yaWVzCmFubm90YXRpb25fcm93IDwtIGRhdGEuZnJhbWUoCiAgQ2F0ZWdvcnkgPSByZXAobmFtZXMoc2V6YXJ5X21hcmtlcnMpLCB0aW1lcyA9IHNhcHBseShzZXphcnlfbWFya2VycywgbGVuZ3RoKSksCiAgcm93Lm5hbWVzID0gYWxsX21hcmtlcnMKKQoKYW5ub3RhdGlvbl9jb2xvcnMgPC0gbGlzdCgKICBDYXRlZ29yeSA9IGMoZWFybHlfbWVtb3J5ID0gIiM0REFGNEEiLCAKICAgICAgICAgICAgICAgbWFsaWduYW50ID0gIiNFNDFBMUMiLAogICAgICAgICAgICAgICBleGhhdXN0ZWQgPSAiIzM3N0VCOCIsCiAgICAgICAgICAgICAgIHByb2xpZmVyYXRpdmUgPSAiI0ZGN0YwMCIpCikKCnBkZigiT3V0cHV0X0ZpZ3VyZXMvU2V6YXJ5X01hcmtlcnNfSGVhdG1hcF9BbGxDbHVzdGVycy5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4KQpwaGVhdG1hcChleHByX21hdHJpeF9zY2FsZWQsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90YXRpb25fcm93LAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3JzLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygibmF2eSIsICJ3aGl0ZSIsICJmaXJlYnJpY2siKSkoMTAwKSwKICAgICAgICAgbWFpbiA9ICJTw6l6YXJ5IE1hcmtlcnMgLSBBbGwgQ2x1c3RlcnMgKFNjYWxlZCkiLAogICAgICAgICBmb250c2l6ZSA9IDEwLAogICAgICAgICBhbmdsZV9jb2wgPSAwKQpkZXYub2ZmKCkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA0LiBDQUxDVUxBVEUgQ0FURUdPUlkgU0NPUkVTIFBFUiBDTFVTVEVSCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2F0ZWdvcnlfc2NvcmVzIDwtIGRhdGEuZnJhbWUoKQoKZm9yKGNhdGVnb3J5IGluIG5hbWVzKHNlemFyeV9tYXJrZXJzKSkgewogIG1hcmtlcnNfaW5fY2F0ZWdvcnkgPC0gc2V6YXJ5X21hcmtlcnNbW2NhdGVnb3J5XV0KICAKICAjIENhbGN1bGF0ZSBtZWFuIGV4cHJlc3Npb24gcGVyIGNsdXN0ZXIgZm9yIHRoaXMgY2F0ZWdvcnkKICBjYXRlZ29yeV9tZWFuIDwtIGNvbE1lYW5zKGV4cHJfbWF0cml4W21hcmtlcnNfaW5fY2F0ZWdvcnksICwgZHJvcCA9IEZBTFNFXSkKICAKICB0ZW1wX2RmIDwtIGRhdGEuZnJhbWUoCiAgICBDbHVzdGVyID0gbmFtZXMoY2F0ZWdvcnlfbWVhbiksCiAgICBDYXRlZ29yeSA9IGNhdGVnb3J5LAogICAgU2NvcmUgPSBhcy5udW1lcmljKGNhdGVnb3J5X21lYW4pCiAgKQogIAogIGNhdGVnb3J5X3Njb3JlcyA8LSByYmluZChjYXRlZ29yeV9zY29yZXMsIHRlbXBfZGYpCn0KCiMgUmVzaGFwZSBmb3IgZWFzaWVyIGFuYWx5c2lzCmxpYnJhcnkodGlkeXIpCmNhdGVnb3J5X3Njb3Jlc193aWRlIDwtIGNhdGVnb3J5X3Njb3JlcyAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ2F0ZWdvcnksIHZhbHVlc19mcm9tID0gU2NvcmUpCgojIFJlbW92ZSAnZycgcHJlZml4IGlmIHByZXNlbnQgKFNldXJhdCBhZGRzIHRoaXMpCmNhdGVnb3J5X3Njb3Jlc193aWRlJENsdXN0ZXIgPC0gZ3N1YigiXmciLCAiIiwgY2F0ZWdvcnlfc2NvcmVzX3dpZGUkQ2x1c3RlcikKCmNhdCgiXG49PT0gQ0FURUdPUlkgU0NPUkVTIEJZIENMVVNURVIgPT09XG4iKQpwcmludChjYXRlZ29yeV9zY29yZXNfd2lkZSkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA1LiBJREVOVElGWSBDTFVTVEVSIFBIRU5PVFlQRVMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjYXQoIlxuPT09IENMVVNURVIgUEhFTk9UWVBFIENMQVNTSUZJQ0FUSU9OID09PVxuIikKCiMgUmFuayBjbHVzdGVycyBieSBlYWNoIGNhdGVnb3J5CnJhbmtpbmdzIDwtIGNhdGVnb3J5X3Njb3Jlc193aWRlICU+JQogIG11dGF0ZSgKICAgIGVhcmx5X21lbW9yeV9yYW5rID0gcmFuaygtZWFybHlfbWVtb3J5KSwKICAgIG1hbGlnbmFudF9yYW5rID0gcmFuaygtbWFsaWduYW50KSwKICAgIGV4aGF1c3RlZF9yYW5rID0gcmFuaygtZXhoYXVzdGVkKSwKICAgIHByb2xpZmVyYXRpdmVfcmFuayA9IHJhbmsoLXByb2xpZmVyYXRpdmUpCiAgKQoKIyBJZGVudGlmeSB0b3AgMyBjbHVzdGVycyBwZXIgY2F0ZWdvcnkKY2F0KCJcbuKckyBUb3AgMyBTVEVNLUxJS0UgY2x1c3RlcnMgKEVhcmx5IE1lbW9yeSk6XG4iKQp0b3BfbWVtb3J5IDwtIHJhbmtpbmdzICU+JSBhcnJhbmdlKGVhcmx5X21lbW9yeV9yYW5rKSAlPiUgaGVhZCgzKSAlPiUgCiAgc2VsZWN0KENsdXN0ZXIsIGVhcmx5X21lbW9yeSwgZWFybHlfbWVtb3J5X3JhbmspCnByaW50KHRvcF9tZW1vcnkpCgpjYXQoIlxu4pyTIFRvcCAzIE1BTElHTkFOVCBjbHVzdGVyczpcbiIpCnRvcF9tYWxpZ25hbnQgPC0gcmFua2luZ3MgJT4lIGFycmFuZ2UobWFsaWduYW50X3JhbmspICU+JSBoZWFkKDMpICU+JSAKICBzZWxlY3QoQ2x1c3RlciwgbWFsaWduYW50LCBtYWxpZ25hbnRfcmFuaykKcHJpbnQodG9wX21hbGlnbmFudCkKCmNhdCgiXG7inJMgVG9wIDMgRVhIQVVTVEVEL1RFUk1JTkFMIGNsdXN0ZXJzOlxuIikKdG9wX2V4aGF1c3RlZCA8LSByYW5raW5ncyAlPiUgYXJyYW5nZShleGhhdXN0ZWRfcmFuaykgJT4lIGhlYWQoMykgJT4lIAogIHNlbGVjdChDbHVzdGVyLCBleGhhdXN0ZWQsIGV4aGF1c3RlZF9yYW5rKQpwcmludCh0b3BfZXhoYXVzdGVkKQoKY2F0KCJcbuKckyBUb3AgMyBQUk9MSUZFUkFUSVZFIGNsdXN0ZXJzOlxuIikKdG9wX3Byb2xpZiA8LSByYW5raW5ncyAlPiUgYXJyYW5nZShwcm9saWZlcmF0aXZlX3JhbmspICU+JSBoZWFkKDMpICU+JSAKICBzZWxlY3QoQ2x1c3RlciwgcHJvbGlmZXJhdGl2ZSwgcHJvbGlmZXJhdGl2ZV9yYW5rKQpwcmludCh0b3BfcHJvbGlmKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDYuIEJBUlBMT1QgLSBDYXRlZ29yeSBTY29yZXMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpwX2JhciA8LSBnZ3Bsb3QoY2F0ZWdvcnlfc2NvcmVzLCBhZXMoeCA9IGdzdWIoIl5nIiwgIiIsIENsdXN0ZXIpLCB5ID0gU2NvcmUsIGZpbGwgPSBDYXRlZ29yeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhlYXJseV9tZW1vcnkgPSAiIzREQUY0QSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hbGlnbmFudCA9ICIjRTQxQTFDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGhhdXN0ZWQgPSAiIzM3N0VCOCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvbGlmZXJhdGl2ZSA9ICIjRkY3RjAwIikpICsKICBsYWJzKHRpdGxlID0gIkZ1bmN0aW9uYWwgU2lnbmF0dXJlcyBBY3Jvc3MgQWxsIENsdXN0ZXJzIiwKICAgICAgIHggPSAiQ2x1c3RlciIsIHkgPSAiTWVhbiBFeHByZXNzaW9uIFNjb3JlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCnByaW50KHBfYmFyKQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL1NlemFyeV9DYXRlZ29yeVNjb3Jlc19CYXJwbG90LnBkZiIsIHBfYmFyLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSA2KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDcuIFRSQUpFQ1RPUlkgUk9PVCBSRUNPTU1FTkRBVElPTgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNhdCgiXG49PT0gVFJBSkVDVE9SWSBJTkZFUkVOQ0UgUkVDT01NRU5EQVRJT04gPT09XG4iKQoKdHJhamVjdG9yeV9ndWlkZSA8LSBjYXRlZ29yeV9zY29yZXNfd2lkZSAlPiUKICBtdXRhdGUoCiAgICBTdGVtbmVzc19TY29yZSA9IGVhcmx5X21lbW9yeSwKICAgIERpZmZlcmVudGlhdGlvbl9TY29yZSA9IChleGhhdXN0ZWQgKyBtYWxpZ25hbnQpIC8gMiwKICAgIEJhbGFuY2UgPSBTdGVtbmVzc19TY29yZSAtIERpZmZlcmVudGlhdGlvbl9TY29yZQogICkgJT4lCiAgYXJyYW5nZShkZXNjKEJhbGFuY2UpKQoKY2F0KCJcbkNsdXN0ZXJzIHJhbmtlZCBieSBTdGVtbmVzcyBTY29yZTpcbiIpCnByaW50KHRyYWplY3RvcnlfZ3VpZGUgJT4lIHNlbGVjdChDbHVzdGVyLCBTdGVtbmVzc19TY29yZSwgRGlmZmVyZW50aWF0aW9uX1Njb3JlLCBCYWxhbmNlKSkKCmNhdCgiXG7inJPinJPinJMgUkVDT01NRU5ERUQgUk9PVCBDTFVTVEVSOiAiLCAKICAgIHRyYWplY3RvcnlfZ3VpZGUkQ2x1c3RlclsxXSwgCiAgICAiIChoaWdoZXN0IHN0ZW1uZXNzLCBsb3dlc3QgZGlmZmVyZW50aWF0aW9uKVxuXG4iLCBzZXAgPSAiIikKCmNhdCgi4pyTIFBPVEVOVElBTCBURVJNSU5BTCBDTFVTVEVSUzogIiwgCiAgICBwYXN0ZSh0YWlsKHRyYWplY3RvcnlfZ3VpZGUkQ2x1c3RlciwgMyksIGNvbGxhcHNlID0gIiwgIiksCiAgICAiIChoaWdoIGV4aGF1c3Rpb24vbWFsaWduYW5jeSlcblxuIiwgc2VwID0gIiIpCgojIFNhdmUgc3VtbWFyeSB0YWJsZXMKd3JpdGUuY3N2KGNhdGVnb3J5X3Njb3Jlc193aWRlLCAiT3V0cHV0X0ZpZ3VyZXMvQ2x1c3Rlcl9QaGVub3R5cGVfU2NvcmVzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQp3cml0ZS5jc3YodHJhamVjdG9yeV9ndWlkZSwgIk91dHB1dF9GaWd1cmVzL1RyYWplY3RvcnlfUm9vdF9SZWNvbW1lbmRhdGlvbnMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpjYXQoIuKckyBBbmFseXNpcyBjb21wbGV0ZSEgVGFibGVzIHNhdmVkIHRvIE91dHB1dF9GaWd1cmVzL1xuIikKCgpgYGAKCgojIFJPQlVTVCBFbnRyb3B5IEFuYWx5c2lzIChObyBFeHRlcm5hbCBEZXBlbmRlbmNpZXMpCmBgYHtyICwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTE2fQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKCkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiU0NUIgoKY2F0KCJDb21wdXRpbmcgZW50cm9weS1iYXNlZCBzdGVtbmVzcyBtZXRyaWNzLi4uXG4iKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIEZ1bmN0aW9uOiBTaGFubm9uIEVudHJvcHkgQ2FsY3VsYXRpb24KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjYWxjdWxhdGVfc2hhbm5vbl9lbnRyb3B5IDwtIGZ1bmN0aW9uKGV4cHJlc3Npb25fdmVjdG9yKSB7CiAgZXhwcl9ub256ZXJvIDwtIGV4cHJlc3Npb25fdmVjdG9yW2V4cHJlc3Npb25fdmVjdG9yID4gMF0KICBpZihsZW5ndGgoZXhwcl9ub256ZXJvKSA9PSAwKSByZXR1cm4oMCkKICAKICBwcm9icyA8LSBleHByX25vbnplcm8gLyBzdW0oZXhwcl9ub256ZXJvKQogIGVudHJvcHkgPC0gLXN1bShwcm9icyAqIGxvZzIocHJvYnMpKQogIHJldHVybihlbnRyb3B5KQp9CgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgRnVuY3Rpb246IEdpbmkgQ29lZmZpY2llbnQgKFNwZWNpYWxpemF0aW9uKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNhbGN1bGF0ZV9naW5pIDwtIGZ1bmN0aW9uKHgpIHsKICB4IDwtIHhbeCA+IDBdCiAgaWYobGVuZ3RoKHgpID09IDApIHJldHVybigwKQogIAogIG4gPC0gbGVuZ3RoKHgpCiAgeF9zb3J0ZWQgPC0gc29ydCh4KQogIGdpbmkgPC0gKDIgKiBzdW0oKDE6bikgKiB4X3NvcnRlZCkpIC8gKG4gKiBzdW0oeF9zb3J0ZWQpKSAtIChuICsgMSkgLyBuCiAgcmV0dXJuKGdpbmkpCn0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTVEVQIDE6IENhbGN1bGF0ZSBFbnRyb3B5IFBlciBDZWxsCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KZXhwcl9tYXRyaXggPC0gR2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gIlNDVCIsIGxheWVyID0gImRhdGEiKQpodmdzIDwtIFZhcmlhYmxlRmVhdHVyZXMoc2V1cmF0X29iaikKZXhwcl9odmcgPC0gZXhwcl9tYXRyaXhbaHZncywgXQoKY2F0KCJDYWxjdWxhdGluZyBlbnRyb3B5IGZvciIsIG5jb2woZXhwcl9odmcpLCAiY2VsbHMgdXNpbmciLCBsZW5ndGgoaHZncyksICJIVkdzLi4uXG4iKQoKIyBTaGFubm9uIEVudHJvcHkKZW50cm9weV9zY29yZXMgPC0gYXBwbHkoZXhwcl9odmcsIDIsIGNhbGN1bGF0ZV9zaGFubm9uX2VudHJvcHkpCnNldXJhdF9vYmokU2hhbm5vbl9FbnRyb3B5IDwtIGVudHJvcHlfc2NvcmVzCgojIEdpbmkgSW5kZXgKZ2luaV9zY29yZXMgPC0gYXBwbHkoZXhwcl9odmcsIDIsIGNhbGN1bGF0ZV9naW5pKQpzZXVyYXRfb2JqJEdpbmlfSW5kZXggPC0gZ2luaV9zY29yZXMKCiMgVHJhbnNjcmlwdGlvbmFsIERpdmVyc2l0eSBTY29yZQpzZXVyYXRfb2JqJERpdmVyc2l0eV9TY29yZSA8LSBzZXVyYXRfb2JqJG5GZWF0dXJlX1JOQSAvIG1heChzZXVyYXRfb2JqJG5GZWF0dXJlX1JOQSkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTVEVQIDI6IENvbWJpbmVkIFN0ZW1uZXNzIFNjb3JlCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBOb3JtYWxpemUgYW5kIGNvbWJpbmUgbWV0cmljcwpzZXVyYXRfb2JqJFN0ZW1uZXNzX1Njb3JlIDwtIAogIHNjYWxlczo6cmVzY2FsZShzZXVyYXRfb2JqJFNoYW5ub25fRW50cm9weSwgdG8gPSBjKDAsIDEpKSAqIDAuNCArCiAgKDEgLSBzY2FsZXM6OnJlc2NhbGUoc2V1cmF0X29iaiRHaW5pX0luZGV4LCB0byA9IGMoMCwgMSkpKSAqIDAuMyArICAjIEludmVydCBHaW5pCiAgc2V1cmF0X29iaiREaXZlcnNpdHlfU2NvcmUgKiAwLjMKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTVEVQIDM6IFBlci1DbHVzdGVyIEFuYWx5c2lzCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3Rlcl9wb3RlbmN5IDwtIHNldXJhdF9vYmpAbWV0YS5kYXRhICU+JQogIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lCiAgc3VtbWFyaXplKAogICAgbl9jZWxscyA9IG4oKSwKICAgIG1lYW5fZW50cm9weSA9IG1lYW4oU2hhbm5vbl9FbnRyb3B5KSwKICAgIG1lYW5fZ2luaSA9IG1lYW4oR2luaV9JbmRleCksCiAgICBtZWFuX2RpdmVyc2l0eSA9IG1lYW4oRGl2ZXJzaXR5X1Njb3JlKSwKICAgIG1lYW5fc3RlbW5lc3MgPSBtZWFuKFN0ZW1uZXNzX1Njb3JlKSwKICAgIHNkX3N0ZW1uZXNzID0gc2QoU3RlbW5lc3NfU2NvcmUpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MobWVhbl9zdGVtbmVzcykpCgpjYXQoIlxuPT09IFNURU1ORVNTL1BPVEVOQ1kgU0NPUkVTIEJZIENMVVNURVIgPT09XG4iKQpwcmludChjbHVzdGVyX3BvdGVuY3kpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgVklTVUFMSVpBVElPTiAxOiBTdGVtbmVzcyBTY29yZSBCYXJwbG90CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KcDEgPC0gZ2dwbG90KGNsdXN0ZXJfcG90ZW5jeSwgCiAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIoc2V1cmF0X2NsdXN0ZXJzLCAtbWVhbl9zdGVtbmVzcyksIAogICAgICAgICAgICAgICAgIHkgPSBtZWFuX3N0ZW1uZXNzLAogICAgICAgICAgICAgICAgIGZpbGwgPSBtZWFuX3N0ZW1uZXNzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IG1lYW5fc3RlbW5lc3MgLSBzZF9zdGVtbmVzcywKICAgICAgICAgICAgICAgICAgICB5bWF4ID0gbWVhbl9zdGVtbmVzcyArIHNkX3N0ZW1uZXNzKSwKICAgICAgICAgICAgICAgIHdpZHRoID0gMC4zLCBhbHBoYSA9IDAuNSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkVudHJvcHktQmFzZWQgU3RlbW5lc3MgU2NvcmUgYnkgQ2x1c3RlciIsCiAgICAgICBzdWJ0aXRsZSA9ICJDb21iaW5lZCBtZXRyaWM6IFNoYW5ub24gZW50cm9weSArIEdpbmkgKyBEaXZlcnNpdHkiLAogICAgICAgeCA9ICJDbHVzdGVyIiwgeSA9ICJNZWFuIFN0ZW1uZXNzIFNjb3JlIiwKICAgICAgIGZpbGwgPSAiU3RlbW5lc3MiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQpKQoKcHJpbnQocDEpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgVklTVUFMSVpBVElPTiAyOiBTdGVtbmVzcyBvbiBVTUFQCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KcDIgPC0gRmVhdHVyZVBsb3Qoc2V1cmF0X29iaiwgCiAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIlN0ZW1uZXNzX1Njb3JlIiwKICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgICAgICAgICAgICBwdC5zaXplID0gMS41KSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIlN0ZW1uZXNzIFNjb3JlIGluIFVNQVAgU3BhY2UiLAogICAgICAgc3VidGl0bGUgPSAiUmVkID0gSGlnaCBzdGVtbmVzcy9wb3RlbmN5IikKCnByaW50KHAyKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFZJU1VBTElaQVRJT04gMzogQ29tcG9uZW50IFNjb3JlcyBIZWF0bWFwCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KbGlicmFyeShyZXNoYXBlMikKaGVhdG1hcF9kYXRhIDwtIGNsdXN0ZXJfcG90ZW5jeSAlPiUKICBzZWxlY3Qoc2V1cmF0X2NsdXN0ZXJzLCBtZWFuX2VudHJvcHksIG1lYW5fZ2luaSwgbWVhbl9kaXZlcnNpdHkpICU+JQogIG11dGF0ZShtZWFuX2dpbmkgPSAxIC0gbWVhbl9naW5pKSAlPiUgICMgSW52ZXJ0IGZvciBjb25zaXN0ZW5jeQogIG11dGF0ZShhY3Jvc3MoYyhtZWFuX2VudHJvcHksIG1lYW5fZ2luaSwgbWVhbl9kaXZlcnNpdHkpLCAKICAgICAgICAgICAgICAgIH5zY2FsZXM6OnJlc2NhbGUoLngsIHRvID0gYygwLCAxKSkpKSAlPiUKICBtZWx0KGlkLnZhcnMgPSAic2V1cmF0X2NsdXN0ZXJzIikKCnAzIDwtIGdncGxvdChoZWF0bWFwX2RhdGEsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBzZXVyYXRfY2x1c3RlcnMsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMuNSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiQ29tcG9uZW50IE1ldHJpY3Mgb2YgU3RlbW5lc3MiLAogICAgICAgeCA9ICJNZXRyaWMiLCB5ID0gIkNsdXN0ZXIiLCBmaWxsID0gIk5vcm1hbGl6ZWRcblNjb3JlIikgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiRW50cm9weSIsICJTcGVjaWFsaXphdGlvbiIsICJEaXZlcnNpdHkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnByaW50KHAzKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFZJU1VBTElaQVRJT04gNDogVmlvbGluIFBsb3QKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpwNCA8LSBWbG5QbG90KHNldXJhdF9vYmosIAogICAgICAgICAgICAgIGZlYXR1cmVzID0gIlN0ZW1uZXNzX1Njb3JlIiwKICAgICAgICAgICAgICBwdC5zaXplID0gMCkgKwogIGxhYnModGl0bGUgPSAiU3RlbW5lc3MgU2NvcmUgRGlzdHJpYnV0aW9uIiwKICAgICAgIHggPSAiQ2x1c3RlciIsIHkgPSAiU3RlbW5lc3MgU2NvcmUiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnByaW50KHA0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIElOVEVHUkFURSBXSVRIIFPDiVpBUlkgTUFSS0VSUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnNlemFyeV9tYXJrZXJzIDwtIGxpc3QoCiAgZWFybHlfbWVtb3J5ID0gYygiQ0NSNyIsICJTRUxMIiwgIlRDRjciLCAiTEVGMSIpLAogIGV4aGF1c3RlZCA9IGMoIlBEQ0QxIiwgIkNUTEE0IiwgIlRJR0lUIiwgIkxBRzMiKQopCgpzZXVyYXRfb2JqIDwtIEFkZE1vZHVsZVNjb3JlKHNldXJhdF9vYmosIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gc2V6YXJ5X21hcmtlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGMoIkVhcmx5TWVtb3J5IiwgIkV4aGF1c3RlZCIpKQoKY29yX21lbW9yeSA8LSBjb3Ioc2V1cmF0X29iaiRTdGVtbmVzc19TY29yZSwgc2V1cmF0X29iaiRFYXJseU1lbW9yeTEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQpjb3JfZXhoYXVzdGVkIDwtIGNvcihzZXVyYXRfb2JqJFN0ZW1uZXNzX1Njb3JlLCBzZXVyYXRfb2JqJEV4aGF1c3RlZDIsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKY2F0KCJcbj09PSBWQUxJREFUSU9OIEFHQUlOU1QgTUFSS0VSIEdFTkVTID09PVxuIikKY2F0KCJDb3JyZWxhdGlvbiBTdGVtbmVzcyB2cyBFYXJseSBNZW1vcnk6Iiwgcm91bmQoY29yX21lbW9yeSwgMyksICJcbiIpCmNhdCgiQ29ycmVsYXRpb24gU3RlbW5lc3MgdnMgRXhoYXVzdGlvbjoiLCByb3VuZChjb3JfZXhoYXVzdGVkLCAzKSwgIlxuIikKCnA1IDwtIGdncGxvdChzZXVyYXRfb2JqQG1ldGEuZGF0YSwgCiAgICAgICAgICAgICBhZXMoeCA9IFN0ZW1uZXNzX1Njb3JlLCB5ID0gRWFybHlNZW1vcnkxLCBjb2xvciA9IHNldXJhdF9jbHVzdGVycykpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJTdGVtbmVzcyBTY29yZSB2cyBFYXJseSBNZW1vcnkgTWFya2VycyIsCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiciA9ICIsIHJvdW5kKGNvcl9tZW1vcnksIDMpKSwKICAgICAgIHggPSAiU3RlbW5lc3MgU2NvcmUiLCB5ID0gIkVhcmx5IE1lbW9yeSBTY29yZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCnByaW50KHA1KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFJPT1QgUkVDT01NRU5EQVRJT04KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjYXQoIlxuPT09IFRSQUpFQ1RPUlkgUk9PVCBSRUNPTU1FTkRBVElPTiA9PT1cblxuIikKY2F0KCLinJPinJPinJMgSElHSEVTVCBTVEVNTkVTUy9QT1RFTkNZIENMVVNURVI6ICIsIGNsdXN0ZXJfcG90ZW5jeSRzZXVyYXRfY2x1c3RlcnMsICJcbiIpWzFdCmNhdCgiICAgICBTdGVtbmVzcyBTY29yZTogIiwgcm91bmQoY2x1c3Rlcl9wb3RlbmN5JG1lYW5fc3RlbW5lc3MsIDMpLCAiXG5cbiIpWzFdCgpjYXQoIuKckyBUb3AgMyBzdGVtLWxpa2UgY2x1c3RlcnM6XG4iKQpwcmludChjbHVzdGVyX3BvdGVuY3kgJT4lIGhlYWQoMykgJT4lIHNlbGVjdChzZXVyYXRfY2x1c3RlcnMsIG1lYW5fc3RlbW5lc3MpKQoKY2F0KCJcbuKckyBUb3AgMyBkaWZmZXJlbnRpYXRlZCBjbHVzdGVyczpcbiIpCnByaW50KGNsdXN0ZXJfcG90ZW5jeSAlPiUgdGFpbCgzKSAlPiUgc2VsZWN0KHNldXJhdF9jbHVzdGVycywgbWVhbl9zdGVtbmVzcykpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgU0FWRSBSRVNVTFRTCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0Kd3JpdGUuY3N2KGNsdXN0ZXJfcG90ZW5jeSwgCiAgICAgICAgICAiT3V0cHV0X0ZpZ3VyZXMvU3RlbW5lc3NfUG90ZW5jeV9CeUNsdXN0ZXIuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKCiMgQ29tYmluZWQgZmlndXJlCnBfY29tYmluZWQgPC0gKHAxIHwgcDIpIC8gKHAzIHwgcDQpICsgCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkVudHJvcHktQmFzZWQgU3RlbW5lc3MgQW5hbHlzaXMiLAogICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJSb290LWZyZWUgZGlmZmVyZW50aWF0aW9uIHN0YXRlIGFzc2Vzc21lbnQiLAogICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSkpCgpwcmludChwX2NvbWJpbmVkKQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL1N0ZW1uZXNzX0FuYWx5c2lzX0NvbXBsZXRlLnBkZiIsIHBfY29tYmluZWQsIAogICAgICAgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTIpCgpjYXQoIlxu4pyTIEFuYWx5c2lzIGNvbXBsZXRlISBBbGwgcmVzdWx0cyBzYXZlZCB0byBPdXRwdXRfRmlndXJlcy9cbiIpCmBgYAoKCgoKYGBge3IgLCBmaWcuaGVpZ2h0PTE2LCBmaWcud2lkdGg9MTZ9CgoKYGBgCgoK