1 Load necessary libraries

# IMPORTANT: Replace this with the actual path and command to load your object
SS <- readRDS("../../1-Seurat_RDS_OBJECT_FINAL/Seurat_Object_With_TF_Activity.rds")
# Placeholder:
if (!exists("SS")) {
  stop("The 'All_samples_Merged' Seurat object is not loaded. Please load your data.")
}

# Check the object structure
print(SS)
An object of class Seurat 
63171 features across 49305 samples within 7 assays 
Active assay: RNA (36601 features, 0 variable features)
 2 layers present: data, counts
 6 other assays present: ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT, dorothea
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony

2 Adapting Your Dorothea Assay for SeuratExtend Visualizations

2.1 Rename or Copy Dorothea Assay to “TF”

library(SeuratExtend)
library(Seurat)

# Option 1: Copy dorothea assay to "TF" (recommended - keeps both)
SS[["TF"]] <- SS[["dorothea"]]
DefaultAssay(SS) <- "TF"

3 WaterfallPlot - Top 200 TFs (Main Interest)


library(SeuratExtend)
library(Seurat)

# Copy dorothea to TF assay
SS[["TF"]] <- SS[["dorothea"]]
DefaultAssay(SS) <- "TF"

# Correct way to get data in Seurat v5
tf_data <- GetAssayData(SS, layer = "data", assay = "TF")  # Changed slot to layer

# Calculate variance for top 200 TFs
tf_var <- apply(tf_data, 1, var)
top200_tfs <- names(sort(tf_var, decreasing = TRUE)[1:200])

cat("Top 200 TFs selected:\n")
Top 200 TFs selected:
print(head(top200_tfs, 20))
 [1] "RFX5"   "MYC"    "E2F4"   "FOXM1"  "MYCN"   "E2F1"   "STAT4"  "TBX21"  "E2F2"   "STAT6"  "NFKB1"  "HIF1A"  "ATF6"   "TFDP1"  "LYL1"   "SREBF2"
[17] "TCF7L2" "MEF2C"  "THAP11" "NFYA"  
# WaterfallPlot: Malignant vs Normal
Idents(SS) <- SS$Condition  # Set your condition column

WaterfallPlot(
  SS,
  features = top200_tfs,  # Top 200 TFs
  ident.1 = "MalignantCD4T",
  ident.2 = "NormalCD4T",
  exp.transform = FALSE,  # Important: dorothea scores are already normalized
  top.n = 50  # Show top 50 in the plot
)

NA
NA

3.1 Rename or Copy Dorothea Assay to “TF”

library(SeuratExtend)

DefaultAssay(SS) <- "TF"

# This is the CORRECT syntax - no transpose parameter exists
tf_zscore1 <- CalcStats(
  SS, 
  features = rownames(SS[["TF"]]),
  group.by = "orig.ident",
  method = "zscore",
  order = "p",
  n = 4  # Top 4 TFs per cell line
)

# This is the CORRECT syntax - no transpose parameter exists
tf_zscore2 <- CalcStats(
  SS, 
  features = rownames(SS[["TF"]]),
  group.by = "seurat_clusters",
  method = "zscore",
  order = "p",
  n = 4  # Top 4 TFs per cell line
)

# Create heatmap - the output is already in the right format
Heatmap(tf_zscore1, lab_fill = "zscore", color_scheme = "RdBu")


# Create heatmap - the output is already in the right format
Heatmap(tf_zscore2, lab_fill = "zscore", color_scheme = "RdBu")

4 DimPlot2 - Show Key TFs on UMAP


# Select top 20 most differential TFs for visualization
top20_tfs <- top200_tfs[1:20]

DimPlot2(
  SS,
  features = top20_tfs[1:20],reduction = "umap",  # Show first 6 TFs
  cols = "RdYlBu",
  theme = NoAxes(),
  ncol = 3
)


# Compare gene expression vs TF activity
DimPlot2(
  SS,
  features = c("STAT3", "tf_STAT3", "NFKB1", "tf_NFKB1"), reduction = "umap",  # If you have gene expression too
  cols = list("tf_STAT3" = "D", "tf_NFKB1" = "D"),
  theme = NoAxes()
)

5 VlnPlot2 - Distribution of Top TFs

# Top 10 differential TFs
VlnPlot2(
  SS,
  features = top20_tfs[1:20],
  group.by = "orig.ident",
  ncol = 5
)


# Compare Malignant vs Normal
Idents(SS) <- SS$Condition
VlnPlot2(
  SS,
  features = top20_tfs[1:20],
  group.by = "Condition",
  ncol = 3
)

6 DotPlot2 - Top TFs Activity


DotPlot2(
  SS,
  features = top20_tfs,
  group.by = "orig.ident"
)


# Split by condition
DotPlot2(
  SS,
  features = top20_tfs,
  group.by = "orig.ident",
  split.by = "Condition"
)

7 Custom Waterfall Plot with ggplot2


library(Seurat)
library(ggplot2)
library(dplyr)
library(ggrepel)

# Step 1: Find differential TF activity
DefaultAssay(SS) <- "dorothea"
Idents(SS) <- SS$Condition

tf_markers <- FindMarkers(
  SS,
  ident.1 = "MalignantCD4T",
  ident.2 = "NormalCD4T",
  assay = "dorothea",
  logfc.threshold = 0,
  min.pct = 0,
  test.use = "wilcox"
)

# Step 2: Prepare data for waterfall plot
tf_markers$TF <- rownames(tf_markers)
tf_markers <- tf_markers %>%
  arrange(avg_log2FC) %>%
  mutate(rank = row_number(),
         significance = case_when(
           p_val_adj < 0.05 & avg_log2FC > 0 ~ "Up in Malignant",
           p_val_adj < 0.05 & avg_log2FC < 0 ~ "Up in Normal",
           TRUE ~ "Not Significant"
         ))

# Step 3: Select top N TFs for labeling
top_n <- 20
top_tfs <- tf_markers %>%
  arrange(desc(abs(avg_log2FC))) %>%
  head(top_n)

# Step 4: Create waterfall plot
ggplot(tf_markers, aes(x = rank, y = avg_log2FC, fill = significance)) +
  geom_bar(stat = "identity", width = 1) +
  scale_fill_manual(
    values = c("Up in Malignant" = "#D62728", 
               "Up in Normal" = "#2166AC", 
               "Not Significant" = "grey70"),
    name = "TF Activity"
  ) +
  geom_text_repel(
    data = top_tfs,
    aes(x = rank, y = avg_log2FC, label = TF),
    size = 3,
    max.overlaps = 20,
    box.padding = 0.5,
    segment.color = "grey50"
  ) +
  geom_hline(yintercept = 0, linetype = "solid", color = "black", linewidth = 0.5) +
  labs(
    title = "Differential TF Activity: Malignant vs Normal",
    subtitle = paste0("Top ", top_n, " TFs labeled"),
    x = "Ranked Transcription Factors",
    y = "log2 Fold Change (TF Activity)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 14, face = "bold"),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    legend.position = "right"
  )

NA
NA

8 Enhanced Version - Top 50 TFs Only

library(Seurat)
library(ggplot2)
library(dplyr)
library(ggrepel)

DefaultAssay(SS) <- "dorothea"
Idents(SS) <- SS$Condition

# Find differential TFs
tf_markers <- FindMarkers(
  SS,
  ident.1 = "MalignantCD4T",
  ident.2 = "NormalCD4T",
  assay = "dorothea",
  logfc.threshold = 0,
  min.pct = 0
)

# Select top 50 by absolute log2FC
tf_markers$TF <- rownames(tf_markers)
top50_tfs <- tf_markers %>%
  arrange(desc(abs(avg_log2FC))) %>%
  head(50)

# Prepare for waterfall plot
top50_tfs <- top50_tfs %>%
  arrange(avg_log2FC) %>%
  mutate(
    rank = row_number(),
    color_cat = case_when(
      p_val_adj < 0.05 & avg_log2FC > 0.5 ~ "Highly Up (Malignant)",
      p_val_adj < 0.05 & avg_log2FC > 0 ~ "Up (Malignant)",
      p_val_adj < 0.05 & avg_log2FC < -0.5 ~ "Highly Down (Normal)",
      p_val_adj < 0.05 & avg_log2FC < 0 ~ "Down (Normal)",
      TRUE ~ "Not Significant"
    )
  )

# Label top 20
top20_labels <- top50_tfs %>%
  arrange(desc(abs(avg_log2FC))) %>%
  head(20)

# Waterfall plot
ggplot(top50_tfs, aes(x = rank, y = avg_log2FC, fill = color_cat)) +
  geom_bar(stat = "identity", width = 1, color = "black", linewidth = 0.1) +
  scale_fill_manual(
    values = c(
      "Highly Up (Malignant)" = "#B2182B",
      "Up (Malignant)" = "#EF8A62",
      "Not Significant" = "grey70",
      "Down (Normal)" = "#67A9CF",
      "Highly Down (Normal)" = "#2166AC"
    ),
    name = "TF Activity Change"
  ) +
  geom_text_repel(
    data = top20_labels,
    aes(label = TF),
    size = 3.5,
    fontface = "bold",
    max.overlaps = 25,
    box.padding = 0.5,
    point.padding = 0.3,
    segment.size = 0.3,
    segment.color = "grey40"
  ) +
  geom_hline(yintercept = 0, linetype = "solid", color = "black", linewidth = 0.8) +
  geom_hline(yintercept = c(-0.5, 0.5), linetype = "dashed", color = "grey30", alpha = 0.5) +
  annotate("text", x = 5, y = 0.5, label = "logFC = 0.5", size = 3, color = "grey30", vjust = -0.5) +
  annotate("text", x = 5, y = -0.5, label = "logFC = -0.5", size = 3, color = "grey30", vjust = 1.5) +
  labs(
    title = "Differential Transcription Factor Activity",
    subtitle = "Malignant Sézary CD4+ T cells vs Normal CD4+ T cells (Top 50 TFs)",
    x = "Ranked Transcription Factors (by log2FC)",
    y = "log2 Fold Change (TF Activity)",
    caption = paste0("p-adjusted < 0.05, Top 20 labeled | Total TFs analyzed: ", nrow(tf_markers))
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = 12, hjust = 0.5),
    axis.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 10),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    legend.position = "right",
    legend.title = element_text(size = 10, face = "bold"),
    plot.caption = element_text(size = 9, hjust = 0.5, color = "grey40")
  )


# Save the plot
ggsave("TF_waterfall_plot.pdf", width = 12, height = 8, dpi = 300)

9 Waterfall Plot for Each Cell Line


library(Seurat)
library(ggplot2)
library(dplyr)
library(cowplot)
library(ggrepel)

DefaultAssay(SS) <- "dorothea"

# Simpler function using group.by
create_waterfall_cellline_v2 <- function(seurat_obj, cell_line, top_n = 30) {
  
  # Find markers using group.by
  markers <- FindMarkers(
    seurat_obj,
    ident.1 = cell_line,
    ident.2 = c("CD4T_lab", "CD4T_10x"),  # Your normal controls from orig.ident
    group.by = "orig.ident",
    assay = "dorothea",
    logfc.threshold = 0,
    min.pct = 0,
    verbose = FALSE
  )
  
  if (nrow(markers) == 0) {
    warning(paste("No markers found for", cell_line))
    return(NULL)
  }
  
  # Prepare data
  markers$TF <- rownames(markers)
  markers_top <- markers %>%
    arrange(desc(abs(avg_log2FC))) %>%
    head(top_n) %>%
    arrange(avg_log2FC) %>%
    mutate(
      rank = row_number(),
      significant = ifelse(p_val_adj < 0.05, "Significant", "Not Significant")
    )
  
  # Top 15 for labels
  top_labels <- markers_top %>%
    arrange(desc(abs(avg_log2FC))) %>%
    head(15)
  
  # Plot
  p <- ggplot(markers_top, aes(x = rank, y = avg_log2FC, fill = significant)) +
    geom_bar(stat = "identity", width = 1, color = "black", linewidth = 0.1) +
    scale_fill_manual(
      values = c("Significant" = "#D62728", "Not Significant" = "grey70")
    ) +
    geom_text_repel(
      data = top_labels,
      aes(label = TF),
      size = 2.5,
      max.overlaps = 15,
      box.padding = 0.3
    ) +
    geom_hline(yintercept = 0, color = "black", linewidth = 0.5) +
    labs(
      title = paste0(cell_line, " vs Normal Controls"),
      x = "Ranked TFs",
      y = "log2FC (TF Activity)"
    ) +
    theme_minimal() +
    theme(
      axis.text.x = element_blank(),
      axis.ticks.x = element_blank(),
      legend.position = "none",
      plot.title = element_text(face = "bold", hjust = 0.5, size = 12)
    )
  
  return(p)
}

# Create waterfall plots
cell_lines <- c("L1", "L2", "L3", "L4", "L5", "L6", "L7")
plots <- lapply(cell_lines, function(x) create_waterfall_cellline_v2(SS, x, top_n = 30))

# Remove NULL plots
plots <- plots[!sapply(plots, is.null)]

# Combine
combined_plot <- plot_grid(plotlist = plots, ncol = 3, nrow = 3)

# Save
ggsave("TF_waterfall_celllines.pdf", 
       plot = combined_plot, 
       width = 16, height = 16, dpi = 300)

combined_plot

10 Export Results Table


# Export differential TF activity results
DefaultAssay(SS) <- "dorothea"
Idents(SS) <- SS$Condition

tf_markers <- FindMarkers(
  SS,
  ident.1 = "MalignantCD4T",
  ident.2 = "NormalCD4T",
  assay = "dorothea",
  logfc.threshold = 0,
  min.pct = 0
)

tf_markers$TF <- rownames(tf_markers)

# Export full results
write.csv(tf_markers, 
          "TF_differential_activity_MalignantVsNormal.csv", 
          row.names = FALSE)

# Export top 50
top50 <- tf_markers %>%
  arrange(desc(abs(avg_log2FC))) %>%
  head(50)

write.csv(top50, 
          "TF_differential_activity_top50.csv", 
          row.names = FALSE)

cat("Analysis complete!\n")
Analysis complete!
cat("Total TFs analyzed:", nrow(tf_markers), "\n")
Total TFs analyzed: 114 
cat("Significant TFs (p-adj < 0.05):", sum(tf_markers$p_val_adj < 0.05), "\n")
Significant TFs (p-adj < 0.05): 106 
LS0tCnRpdGxlOiAiVmlzdWFsaXphdGlvbiBvZiBURiBhY3Rpdml0eSIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAotLS0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoU2V1cmF0RXh0ZW5kKQpsaWJyYXJ5KHNjcGxvdHRlcikKCiMgSU1QT1JUQU5UOiBSZXBsYWNlIHRoaXMgd2l0aCB0aGUgYWN0dWFsIHBhdGggYW5kIGNvbW1hbmQgdG8gbG9hZCB5b3VyIG9iamVjdApTUyA8LSByZWFkUkRTKCIuLi8uLi8xLVNldXJhdF9SRFNfT0JKRUNUX0ZJTkFML1NldXJhdF9PYmplY3RfV2l0aF9URl9BY3Rpdml0eS5yZHMiKQojIFBsYWNlaG9sZGVyOgppZiAoIWV4aXN0cygiU1MiKSkgewogIHN0b3AoIlRoZSAnQWxsX3NhbXBsZXNfTWVyZ2VkJyBTZXVyYXQgb2JqZWN0IGlzIG5vdCBsb2FkZWQuIFBsZWFzZSBsb2FkIHlvdXIgZGF0YS4iKQp9CgojIENoZWNrIHRoZSBvYmplY3Qgc3RydWN0dXJlCnByaW50KFNTKQpgYGAKIyBBZGFwdGluZyBZb3VyIERvcm90aGVhIEFzc2F5IGZvciBTZXVyYXRFeHRlbmQgVmlzdWFsaXphdGlvbnMKIyMgUmVuYW1lIG9yIENvcHkgRG9yb3RoZWEgQXNzYXkgdG8gIlRGIgpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CmxpYnJhcnkoU2V1cmF0RXh0ZW5kKQpsaWJyYXJ5KFNldXJhdCkKCiMgT3B0aW9uIDE6IENvcHkgZG9yb3RoZWEgYXNzYXkgdG8gIlRGIiAocmVjb21tZW5kZWQgLSBrZWVwcyBib3RoKQpTU1tbIlRGIl1dIDwtIFNTW1siZG9yb3RoZWEiXV0KRGVmYXVsdEFzc2F5KFNTKSA8LSAiVEYiCgoKYGBgCiMgV2F0ZXJmYWxsUGxvdCAtIFRvcCAyMDAgVEZzIChNYWluIEludGVyZXN0KQpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEzfQoKbGlicmFyeShTZXVyYXRFeHRlbmQpCmxpYnJhcnkoU2V1cmF0KQoKIyBDb3B5IGRvcm90aGVhIHRvIFRGIGFzc2F5ClNTW1siVEYiXV0gPC0gU1NbWyJkb3JvdGhlYSJdXQpEZWZhdWx0QXNzYXkoU1MpIDwtICJURiIKCiMgQ29ycmVjdCB3YXkgdG8gZ2V0IGRhdGEgaW4gU2V1cmF0IHY1CnRmX2RhdGEgPC0gR2V0QXNzYXlEYXRhKFNTLCBsYXllciA9ICJkYXRhIiwgYXNzYXkgPSAiVEYiKSAgIyBDaGFuZ2VkIHNsb3QgdG8gbGF5ZXIKCiMgQ2FsY3VsYXRlIHZhcmlhbmNlIGZvciB0b3AgMjAwIFRGcwp0Zl92YXIgPC0gYXBwbHkodGZfZGF0YSwgMSwgdmFyKQp0b3AyMDBfdGZzIDwtIG5hbWVzKHNvcnQodGZfdmFyLCBkZWNyZWFzaW5nID0gVFJVRSlbMToyMDBdKQoKY2F0KCJUb3AgMjAwIFRGcyBzZWxlY3RlZDpcbiIpCnByaW50KGhlYWQodG9wMjAwX3RmcywgMjApKQoKCgojIFdhdGVyZmFsbFBsb3Q6IE1hbGlnbmFudCB2cyBOb3JtYWwKSWRlbnRzKFNTKSA8LSBTUyRDb25kaXRpb24gICMgU2V0IHlvdXIgY29uZGl0aW9uIGNvbHVtbgoKV2F0ZXJmYWxsUGxvdCgKICBTUywKICBmZWF0dXJlcyA9IHRvcDIwMF90ZnMsICAjIFRvcCAyMDAgVEZzCiAgaWRlbnQuMSA9ICJNYWxpZ25hbnRDRDRUIiwKICBpZGVudC4yID0gIk5vcm1hbENENFQiLAogIGV4cC50cmFuc2Zvcm0gPSBGQUxTRSwgICMgSW1wb3J0YW50OiBkb3JvdGhlYSBzY29yZXMgYXJlIGFscmVhZHkgbm9ybWFsaXplZAogIHRvcC5uID0gNTAgICMgU2hvdyB0b3AgNTAgaW4gdGhlIHBsb3QKKQoKCmBgYAoKIyMgUmVuYW1lIG9yIENvcHkgRG9yb3RoZWEgQXNzYXkgdG8gIlRGIgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9CmxpYnJhcnkoU2V1cmF0RXh0ZW5kKQoKRGVmYXVsdEFzc2F5KFNTKSA8LSAiVEYiCgojIFRoaXMgaXMgdGhlIENPUlJFQ1Qgc3ludGF4IC0gbm8gdHJhbnNwb3NlIHBhcmFtZXRlciBleGlzdHMKdGZfenNjb3JlMSA8LSBDYWxjU3RhdHMoCiAgU1MsIAogIGZlYXR1cmVzID0gcm93bmFtZXMoU1NbWyJURiJdXSksCiAgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIsCiAgbWV0aG9kID0gInpzY29yZSIsCiAgb3JkZXIgPSAicCIsCiAgbiA9IDQgICMgVG9wIDQgVEZzIHBlciBjZWxsIGxpbmUKKQoKIyBUaGlzIGlzIHRoZSBDT1JSRUNUIHN5bnRheCAtIG5vIHRyYW5zcG9zZSBwYXJhbWV0ZXIgZXhpc3RzCnRmX3pzY29yZTIgPC0gQ2FsY1N0YXRzKAogIFNTLCAKICBmZWF0dXJlcyA9IHJvd25hbWVzKFNTW1siVEYiXV0pLAogIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgbWV0aG9kID0gInpzY29yZSIsCiAgb3JkZXIgPSAicCIsCiAgbiA9IDQgICMgVG9wIDQgVEZzIHBlciBjZWxsIGxpbmUKKQoKIyBDcmVhdGUgaGVhdG1hcCAtIHRoZSBvdXRwdXQgaXMgYWxyZWFkeSBpbiB0aGUgcmlnaHQgZm9ybWF0CkhlYXRtYXAodGZfenNjb3JlMSwgbGFiX2ZpbGwgPSAienNjb3JlIiwgY29sb3Jfc2NoZW1lID0gIlJkQnUiKQoKIyBDcmVhdGUgaGVhdG1hcCAtIHRoZSBvdXRwdXQgaXMgYWxyZWFkeSBpbiB0aGUgcmlnaHQgZm9ybWF0CkhlYXRtYXAodGZfenNjb3JlMiwgbGFiX2ZpbGwgPSAienNjb3JlIiwgY29sb3Jfc2NoZW1lID0gIlJkQnUiKQoKYGBgCgoKCgojIERpbVBsb3QyIC0gU2hvdyBLZXkgVEZzIG9uIFVNQVAKYGBge3IgLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9CgojIFNlbGVjdCB0b3AgMjAgbW9zdCBkaWZmZXJlbnRpYWwgVEZzIGZvciB2aXN1YWxpemF0aW9uCnRvcDIwX3RmcyA8LSB0b3AyMDBfdGZzWzE6MjBdCgpEaW1QbG90MigKICBTUywKICBmZWF0dXJlcyA9IHRvcDIwX3Rmc1sxOjIwXSxyZWR1Y3Rpb24gPSAidW1hcCIsICAjIFNob3cgZmlyc3QgNiBURnMKICBjb2xzID0gIlJkWWxCdSIsCiAgdGhlbWUgPSBOb0F4ZXMoKSwKICBuY29sID0gMwopCgojIENvbXBhcmUgZ2VuZSBleHByZXNzaW9uIHZzIFRGIGFjdGl2aXR5CkRpbVBsb3QyKAogIFNTLAogIGZlYXR1cmVzID0gYygiU1RBVDMiLCAidGZfU1RBVDMiLCAiTkZLQjEiLCAidGZfTkZLQjEiKSwgcmVkdWN0aW9uID0gInVtYXAiLCAgIyBJZiB5b3UgaGF2ZSBnZW5lIGV4cHJlc3Npb24gdG9vCiAgY29scyA9IGxpc3QoInRmX1NUQVQzIiA9ICJEIiwgInRmX05GS0IxIiA9ICJEIiksCiAgdGhlbWUgPSBOb0F4ZXMoKQopCmBgYAoKIyBWbG5QbG90MiAtIERpc3RyaWJ1dGlvbiBvZiBUb3AgVEZzCmBgYHtyICwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQojIFRvcCAxMCBkaWZmZXJlbnRpYWwgVEZzClZsblBsb3QyKAogIFNTLAogIGZlYXR1cmVzID0gdG9wMjBfdGZzWzE6MjBdLAogIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLAogIG5jb2wgPSA1CikKCiMgQ29tcGFyZSBNYWxpZ25hbnQgdnMgTm9ybWFsCklkZW50cyhTUykgPC0gU1MkQ29uZGl0aW9uClZsblBsb3QyKAogIFNTLAogIGZlYXR1cmVzID0gdG9wMjBfdGZzWzE6MjBdLAogIGdyb3VwLmJ5ID0gIkNvbmRpdGlvbiIsCiAgbmNvbCA9IDMKKQoKYGBgCiMgRG90UGxvdDIgLSBUb3AgVEZzIEFjdGl2aXR5CmBgYHtyICwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCkRvdFBsb3QyKAogIFNTLAogIGZlYXR1cmVzID0gdG9wMjBfdGZzLAogIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiCikKCiMgU3BsaXQgYnkgY29uZGl0aW9uCkRvdFBsb3QyKAogIFNTLAogIGZlYXR1cmVzID0gdG9wMjBfdGZzLAogIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLAogIHNwbGl0LmJ5ID0gIkNvbmRpdGlvbiIKKQpgYGAKCiMgQ3VzdG9tIFdhdGVyZmFsbCBQbG90IHdpdGggZ2dwbG90MgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3JlcGVsKQoKIyBTdGVwIDE6IEZpbmQgZGlmZmVyZW50aWFsIFRGIGFjdGl2aXR5CkRlZmF1bHRBc3NheShTUykgPC0gImRvcm90aGVhIgpJZGVudHMoU1MpIDwtIFNTJENvbmRpdGlvbgoKdGZfbWFya2VycyA8LSBGaW5kTWFya2VycygKICBTUywKICBpZGVudC4xID0gIk1hbGlnbmFudENENFQiLAogIGlkZW50LjIgPSAiTm9ybWFsQ0Q0VCIsCiAgYXNzYXkgPSAiZG9yb3RoZWEiLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgbWluLnBjdCA9IDAsCiAgdGVzdC51c2UgPSAid2lsY294IgopCgojIFN0ZXAgMjogUHJlcGFyZSBkYXRhIGZvciB3YXRlcmZhbGwgcGxvdAp0Zl9tYXJrZXJzJFRGIDwtIHJvd25hbWVzKHRmX21hcmtlcnMpCnRmX21hcmtlcnMgPC0gdGZfbWFya2VycyAlPiUKICBhcnJhbmdlKGF2Z19sb2cyRkMpICU+JQogIG11dGF0ZShyYW5rID0gcm93X251bWJlcigpLAogICAgICAgICBzaWduaWZpY2FuY2UgPSBjYXNlX3doZW4oCiAgICAgICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPiAwIH4gIlVwIGluIE1hbGlnbmFudCIsCiAgICAgICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPCAwIH4gIlVwIGluIE5vcm1hbCIsCiAgICAgICAgICAgVFJVRSB+ICJOb3QgU2lnbmlmaWNhbnQiCiAgICAgICAgICkpCgojIFN0ZXAgMzogU2VsZWN0IHRvcCBOIFRGcyBmb3IgbGFiZWxpbmcKdG9wX24gPC0gMjAKdG9wX3RmcyA8LSB0Zl9tYXJrZXJzICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoYXZnX2xvZzJGQykpKSAlPiUKICBoZWFkKHRvcF9uKQoKIyBTdGVwIDQ6IENyZWF0ZSB3YXRlcmZhbGwgcGxvdApnZ3Bsb3QodGZfbWFya2VycywgYWVzKHggPSByYW5rLCB5ID0gYXZnX2xvZzJGQywgZmlsbCA9IHNpZ25pZmljYW5jZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKCJVcCBpbiBNYWxpZ25hbnQiID0gIiNENjI3MjgiLCAKICAgICAgICAgICAgICAgIlVwIGluIE5vcm1hbCIgPSAiIzIxNjZBQyIsIAogICAgICAgICAgICAgICAiTm90IFNpZ25pZmljYW50IiA9ICJncmV5NzAiKSwKICAgIG5hbWUgPSAiVEYgQWN0aXZpdHkiCiAgKSArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YSA9IHRvcF90ZnMsCiAgICBhZXMoeCA9IHJhbmssIHkgPSBhdmdfbG9nMkZDLCBsYWJlbCA9IFRGKSwKICAgIHNpemUgPSAzLAogICAgbWF4Lm92ZXJsYXBzID0gMjAsCiAgICBib3gucGFkZGluZyA9IDAuNSwKICAgIHNlZ21lbnQuY29sb3IgPSAiZ3JleTUwIgogICkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjUpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlmZmVyZW50aWFsIFRGIEFjdGl2aXR5OiBNYWxpZ25hbnQgdnMgTm9ybWFsIiwKICAgIHN1YnRpdGxlID0gcGFzdGUwKCJUb3AgIiwgdG9wX24sICIgVEZzIGxhYmVsZWQiKSwKICAgIHggPSAiUmFua2VkIFRyYW5zY3JpcHRpb24gRmFjdG9ycyIsCiAgICB5ID0gImxvZzIgRm9sZCBDaGFuZ2UgKFRGIEFjdGl2aXR5KSIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiCiAgKQoKCmBgYAoKIyBFbmhhbmNlZCBWZXJzaW9uIC0gVG9wIDUwIFRGcyBPbmx5CmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKCkRlZmF1bHRBc3NheShTUykgPC0gImRvcm90aGVhIgpJZGVudHMoU1MpIDwtIFNTJENvbmRpdGlvbgoKIyBGaW5kIGRpZmZlcmVudGlhbCBURnMKdGZfbWFya2VycyA8LSBGaW5kTWFya2VycygKICBTUywKICBpZGVudC4xID0gIk1hbGlnbmFudENENFQiLAogIGlkZW50LjIgPSAiTm9ybWFsQ0Q0VCIsCiAgYXNzYXkgPSAiZG9yb3RoZWEiLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgbWluLnBjdCA9IDAKKQoKIyBTZWxlY3QgdG9wIDUwIGJ5IGFic29sdXRlIGxvZzJGQwp0Zl9tYXJrZXJzJFRGIDwtIHJvd25hbWVzKHRmX21hcmtlcnMpCnRvcDUwX3RmcyA8LSB0Zl9tYXJrZXJzICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoYXZnX2xvZzJGQykpKSAlPiUKICBoZWFkKDUwKQoKIyBQcmVwYXJlIGZvciB3YXRlcmZhbGwgcGxvdAp0b3A1MF90ZnMgPC0gdG9wNTBfdGZzICU+JQogIGFycmFuZ2UoYXZnX2xvZzJGQykgJT4lCiAgbXV0YXRlKAogICAgcmFuayA9IHJvd19udW1iZXIoKSwKICAgIGNvbG9yX2NhdCA9IGNhc2Vfd2hlbigKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPiAwLjUgfiAiSGlnaGx5IFVwIChNYWxpZ25hbnQpIiwKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPiAwIH4gIlVwIChNYWxpZ25hbnQpIiwKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPCAtMC41IH4gIkhpZ2hseSBEb3duIChOb3JtYWwpIiwKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPCAwIH4gIkRvd24gKE5vcm1hbCkiLAogICAgICBUUlVFIH4gIk5vdCBTaWduaWZpY2FudCIKICAgICkKICApCgojIExhYmVsIHRvcCAyMAp0b3AyMF9sYWJlbHMgPC0gdG9wNTBfdGZzICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoYXZnX2xvZzJGQykpKSAlPiUKICBoZWFkKDIwKQoKIyBXYXRlcmZhbGwgcGxvdApnZ3Bsb3QodG9wNTBfdGZzLCBhZXMoeCA9IHJhbmssIHkgPSBhdmdfbG9nMkZDLCBmaWxsID0gY29sb3JfY2F0KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKAogICAgICAiSGlnaGx5IFVwIChNYWxpZ25hbnQpIiA9ICIjQjIxODJCIiwKICAgICAgIlVwIChNYWxpZ25hbnQpIiA9ICIjRUY4QTYyIiwKICAgICAgIk5vdCBTaWduaWZpY2FudCIgPSAiZ3JleTcwIiwKICAgICAgIkRvd24gKE5vcm1hbCkiID0gIiM2N0E5Q0YiLAogICAgICAiSGlnaGx5IERvd24gKE5vcm1hbCkiID0gIiMyMTY2QUMiCiAgICApLAogICAgbmFtZSA9ICJURiBBY3Rpdml0eSBDaGFuZ2UiCiAgKSArCiAgZ2VvbV90ZXh0X3JlcGVsKAogICAgZGF0YSA9IHRvcDIwX2xhYmVscywKICAgIGFlcyhsYWJlbCA9IFRGKSwKICAgIHNpemUgPSAzLjUsCiAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgIG1heC5vdmVybGFwcyA9IDI1LAogICAgYm94LnBhZGRpbmcgPSAwLjUsCiAgICBwb2ludC5wYWRkaW5nID0gMC4zLAogICAgc2VnbWVudC5zaXplID0gMC4zLAogICAgc2VnbWVudC5jb2xvciA9ICJncmV5NDAiCiAgKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuOCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoLTAuNSwgMC41KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleTMwIiwgYWxwaGEgPSAwLjUpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSA1LCB5ID0gMC41LCBsYWJlbCA9ICJsb2dGQyA9IDAuNSIsIHNpemUgPSAzLCBjb2xvciA9ICJncmV5MzAiLCB2anVzdCA9IC0wLjUpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSA1LCB5ID0gLTAuNSwgbGFiZWwgPSAibG9nRkMgPSAtMC41Iiwgc2l6ZSA9IDMsIGNvbG9yID0gImdyZXkzMCIsIHZqdXN0ID0gMS41KSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpZmZlcmVudGlhbCBUcmFuc2NyaXB0aW9uIEZhY3RvciBBY3Rpdml0eSIsCiAgICBzdWJ0aXRsZSA9ICJNYWxpZ25hbnQgU8OpemFyeSBDRDQrIFQgY2VsbHMgdnMgTm9ybWFsIENENCsgVCBjZWxscyAoVG9wIDUwIFRGcykiLAogICAgeCA9ICJSYW5rZWQgVHJhbnNjcmlwdGlvbiBGYWN0b3JzIChieSBsb2cyRkMpIiwKICAgIHkgPSAibG9nMiBGb2xkIENoYW5nZSAoVEYgQWN0aXZpdHkpIiwKICAgIGNhcHRpb24gPSBwYXN0ZTAoInAtYWRqdXN0ZWQgPCAwLjA1LCBUb3AgMjAgbGFiZWxlZCB8IFRvdGFsIFRGcyBhbmFseXplZDogIiwgbnJvdyh0Zl9tYXJrZXJzKSkKICApICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIiksCiAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGhqdXN0ID0gMC41LCBjb2xvciA9ICJncmV5NDAiKQogICkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoIlRGX3dhdGVyZmFsbF9wbG90LnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCkKCmBgYAoKIyBXYXRlcmZhbGwgUGxvdCBmb3IgRWFjaCBDZWxsIExpbmUKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShnZ3JlcGVsKQoKRGVmYXVsdEFzc2F5KFNTKSA8LSAiZG9yb3RoZWEiCgojIFNpbXBsZXIgZnVuY3Rpb24gdXNpbmcgZ3JvdXAuYnkKY3JlYXRlX3dhdGVyZmFsbF9jZWxsbGluZV92MiA8LSBmdW5jdGlvbihzZXVyYXRfb2JqLCBjZWxsX2xpbmUsIHRvcF9uID0gMzApIHsKICAKICAjIEZpbmQgbWFya2VycyB1c2luZyBncm91cC5ieQogIG1hcmtlcnMgPC0gRmluZE1hcmtlcnMoCiAgICBzZXVyYXRfb2JqLAogICAgaWRlbnQuMSA9IGNlbGxfbGluZSwKICAgIGlkZW50LjIgPSBjKCJDRDRUX2xhYiIsICJDRDRUXzEweCIpLCAgIyBZb3VyIG5vcm1hbCBjb250cm9scyBmcm9tIG9yaWcuaWRlbnQKICAgIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiLAogICAgYXNzYXkgPSAiZG9yb3RoZWEiLAogICAgbG9nZmMudGhyZXNob2xkID0gMCwKICAgIG1pbi5wY3QgPSAwLAogICAgdmVyYm9zZSA9IEZBTFNFCiAgKQogIAogIGlmIChucm93KG1hcmtlcnMpID09IDApIHsKICAgIHdhcm5pbmcocGFzdGUoIk5vIG1hcmtlcnMgZm91bmQgZm9yIiwgY2VsbF9saW5lKSkKICAgIHJldHVybihOVUxMKQogIH0KICAKICAjIFByZXBhcmUgZGF0YQogIG1hcmtlcnMkVEYgPC0gcm93bmFtZXMobWFya2VycykKICBtYXJrZXJzX3RvcCA8LSBtYXJrZXJzICU+JQogICAgYXJyYW5nZShkZXNjKGFicyhhdmdfbG9nMkZDKSkpICU+JQogICAgaGVhZCh0b3BfbikgJT4lCiAgICBhcnJhbmdlKGF2Z19sb2cyRkMpICU+JQogICAgbXV0YXRlKAogICAgICByYW5rID0gcm93X251bWJlcigpLAogICAgICBzaWduaWZpY2FudCA9IGlmZWxzZShwX3ZhbF9hZGogPCAwLjA1LCAiU2lnbmlmaWNhbnQiLCAiTm90IFNpZ25pZmljYW50IikKICAgICkKICAKICAjIFRvcCAxNSBmb3IgbGFiZWxzCiAgdG9wX2xhYmVscyA8LSBtYXJrZXJzX3RvcCAlPiUKICAgIGFycmFuZ2UoZGVzYyhhYnMoYXZnX2xvZzJGQykpKSAlPiUKICAgIGhlYWQoMTUpCiAgCiAgIyBQbG90CiAgcCA8LSBnZ3Bsb3QobWFya2Vyc190b3AsIGFlcyh4ID0gcmFuaywgeSA9IGF2Z19sb2cyRkMsIGZpbGwgPSBzaWduaWZpY2FudCkpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygiU2lnbmlmaWNhbnQiID0gIiNENjI3MjgiLCAiTm90IFNpZ25pZmljYW50IiA9ICJncmV5NzAiKQogICAgKSArCiAgICBnZW9tX3RleHRfcmVwZWwoCiAgICAgIGRhdGEgPSB0b3BfbGFiZWxzLAogICAgICBhZXMobGFiZWwgPSBURiksCiAgICAgIHNpemUgPSAyLjUsCiAgICAgIG1heC5vdmVybGFwcyA9IDE1LAogICAgICBib3gucGFkZGluZyA9IDAuMwogICAgKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuNSkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZTAoY2VsbF9saW5lLCAiIHZzIE5vcm1hbCBDb250cm9scyIpLAogICAgICB4ID0gIlJhbmtlZCBURnMiLAogICAgICB5ID0gImxvZzJGQyAoVEYgQWN0aXZpdHkpIgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKQogICAgKQogIAogIHJldHVybihwKQp9CgojIENyZWF0ZSB3YXRlcmZhbGwgcGxvdHMKY2VsbF9saW5lcyA8LSBjKCJMMSIsICJMMiIsICJMMyIsICJMNCIsICJMNSIsICJMNiIsICJMNyIpCnBsb3RzIDwtIGxhcHBseShjZWxsX2xpbmVzLCBmdW5jdGlvbih4KSBjcmVhdGVfd2F0ZXJmYWxsX2NlbGxsaW5lX3YyKFNTLCB4LCB0b3BfbiA9IDMwKSkKCiMgUmVtb3ZlIE5VTEwgcGxvdHMKcGxvdHMgPC0gcGxvdHNbIXNhcHBseShwbG90cywgaXMubnVsbCldCgojIENvbWJpbmUKY29tYmluZWRfcGxvdCA8LSBwbG90X2dyaWQocGxvdGxpc3QgPSBwbG90cywgbmNvbCA9IDMsIG5yb3cgPSAzKQoKIyBTYXZlCmdnc2F2ZSgiVEZfd2F0ZXJmYWxsX2NlbGxsaW5lcy5wZGYiLCAKICAgICAgIHBsb3QgPSBjb21iaW5lZF9wbG90LCAKICAgICAgIHdpZHRoID0gMTYsIGhlaWdodCA9IDE2LCBkcGkgPSAzMDApCgpjb21iaW5lZF9wbG90CgpgYGAKCgojIEV4cG9ydCBSZXN1bHRzIFRhYmxlCmBgYHtyICwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCiMgRXhwb3J0IGRpZmZlcmVudGlhbCBURiBhY3Rpdml0eSByZXN1bHRzCkRlZmF1bHRBc3NheShTUykgPC0gImRvcm90aGVhIgpJZGVudHMoU1MpIDwtIFNTJENvbmRpdGlvbgoKdGZfbWFya2VycyA8LSBGaW5kTWFya2VycygKICBTUywKICBpZGVudC4xID0gIk1hbGlnbmFudENENFQiLAogIGlkZW50LjIgPSAiTm9ybWFsQ0Q0VCIsCiAgYXNzYXkgPSAiZG9yb3RoZWEiLAogIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgbWluLnBjdCA9IDAKKQoKdGZfbWFya2VycyRURiA8LSByb3duYW1lcyh0Zl9tYXJrZXJzKQoKIyBFeHBvcnQgZnVsbCByZXN1bHRzCndyaXRlLmNzdih0Zl9tYXJrZXJzLCAKICAgICAgICAgICJURl9kaWZmZXJlbnRpYWxfYWN0aXZpdHlfTWFsaWduYW50VnNOb3JtYWwuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKCiMgRXhwb3J0IHRvcCA1MAp0b3A1MCA8LSB0Zl9tYXJrZXJzICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoYXZnX2xvZzJGQykpKSAlPiUKICBoZWFkKDUwKQoKd3JpdGUuY3N2KHRvcDUwLCAKICAgICAgICAgICJURl9kaWZmZXJlbnRpYWxfYWN0aXZpdHlfdG9wNTAuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKCmNhdCgiQW5hbHlzaXMgY29tcGxldGUhXG4iKQpjYXQoIlRvdGFsIFRGcyBhbmFseXplZDoiLCBucm93KHRmX21hcmtlcnMpLCAiXG4iKQpjYXQoIlNpZ25pZmljYW50IFRGcyAocC1hZGogPCAwLjA1KToiLCBzdW0odGZfbWFya2VycyRwX3ZhbF9hZGogPCAwLjA1KSwgIlxuIikKCmBgYAo=