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

2 Load Seurat Object

library(Seurat)
library(reticulate)
library(ggplot2)

# 1. Load Object
seurat_obj <- readRDS("temp_seurat_obj.rds")

3 SUPPLEMENTARY FIGURE: PAGA Trajectory Analysis (via Reticulate/Scanpy)

# Display in notebook
if(file.exists(output_file)){
  knitr::include_graphics(output_file)
}

4 SUPPLEMENTARY FIGURE: PAGA on Gene Expression (SCT Assay)

5 SUPPLEMENTARY FIGURE: Quick Code to Generate Malignant-Only PAGA

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

7 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/

8 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