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
Adapting Your Dorothea
Assay for SeuratExtend Visualizations
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"
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
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")

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

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
)

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

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

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=