load libraries
# Data Processing
library(dplyr)
library(Seurat)
library(tibble)
library(tidyr)
library(stringr)
# Visualization
library(ggplot2)
library(ComplexHeatmap)
library(patchwork)
library(SCpubr)
# Regulatory Network Inference
library(decoupleR)
library(dorothea)
data(dorothea_hs, package = "dorothea")
library(tictoc)
Load Seurat Object
# Load your Seurat Object
seurat_obj <- readRDS("../Output_Objects/Seurat_Object_With_TF_Activity.rds")
Idents(seurat_obj) <- "seurat_clusters"
print("Object Loaded.")
[1] "Object Loaded."
Run this code block
to restore activities instantly:
# If 'activities' is missing but 'dorothea' assay exists, reconstruct it:
if (!exists("activities") && "dorothea" %in% names(seurat_obj@assays)) {
print("Reconstructing 'activities' dataframe from Seurat object...")
# Extract the matrix (Seurat v5 uses 'layer' instead of 'slot')
# Since you ran ScaleData, we use 'scale.data'
mat <- GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data")
# Convert to long format (what SCpubr needs)
activities <- as.data.frame(mat) %>%
rownames_to_column("source") %>%
pivot_longer(cols = -source, names_to = "condition", values_to = "score") %>%
mutate(statistic = "norm_wmean") # SCpubr requires this column
print("Activities dataframe restored!")
}
SCpubr Heatmap
Visualization-Heatmap of averaged scores
library(SCpubr)
# General heatmap (Top Variable TFs)
out <- SCpubr::do_TFActivityHeatmap(sample = seurat_obj,
activities = activities)
print(out)
# 1. Save as PDF
pdf("Output_Figures/SCpubr_Heatmap_Default.pdf", width = 10, height = 8)
print(out) # ComplexHeatmap requires explicit print() inside pdf()
dev.off()
# 2. Save as PNG
png("Output_Figures/SCpubr_Heatmap_Default.png", width = 10 * 300, height = 8 * 300, res = 300)
print(out)
dev.off()
print(out)
Set the scale
limits
out <- SCpubr::do_TFActivityHeatmap(sample = seurat_obj,
activities = activities,
min.cutoff = -1.5,
max.cutoff = 1.5)
print(out)
# Save ComplexHeatmap properly
pdf("Output_Figures/SCpubr_Heatmap_Scaled.pdf", width = 10, height = 8)
print(out)
dev.off()
png("Output_Figures/SCpubr_Heatmap_Scaled.png", width = 10 * 300, height = 8 * 300, res = 300)
print(out)
dev.off()
Enforce Symmetry
(Best for Manuscript)
out <- SCpubr::do_TFActivityHeatmap(sample = seurat_obj,
activities = activities,
min.cutoff = -1.5,
max.cutoff = 1.5,
enforce_symmetry = TRUE)
print(out)
pdf("Output_Figures/SCpubr_Heatmap_Symmetric.pdf", width = 10, height = 8)
print(out)
dev.off()
png("Output_Figures/SCpubr_Heatmap_Symmetric.png", width = 10 * 300, height = 8 * 300, res = 300)
print(out)
dev.off()
print(out)
Top 40 TFs
out <- SCpubr::do_TFActivityHeatmap(sample = seurat_obj,
activities = activities,
n_tfs = 40)
print(out)
pdf("Output_Figures/SCpubr_Heatmap_Top40.pdf", width = 14, height = 6)
print(out)
dev.off()
png("Output_Figures/SCpubr_Heatmap_Top40.png", width = 14 * 300, height = 6 * 300, res = 300)
print(out)
dev.off()
Differential TF
Activity (Malignant vs. Normal)
# Define Comparison: Clusters 3 & 10 (Normal) vs Rest (Malignant)
non_malignant_clusters <- c(3, 10)
seurat_obj$Condition <- ifelse(seurat_obj$seurat_clusters %in% non_malignant_clusters, "Non-Malignant", "Malignant")
# Perform Differential Analysis on TF Activity
DefaultAssay(seurat_obj) <- "dorothea"
Idents(seurat_obj) <- "Condition"
print("Running FindMarkers on TF Activity...")
diff_tfs <- FindMarkers(seurat_obj,
ident.1 = "Malignant",
ident.2 = "Non-Malignant",
logfc.threshold = 0, # Get all for volcano
min.pct = 0)
# Add gene column for labeling
diff_tfs$gene <- rownames(diff_tfs)
# Save Results
write.csv(diff_tfs, "Output_Tables/Differential_TF_Activity_Malignant_vs_Normal.csv")
print("Differential analysis complete.")
Figure E
(ComplexHeatmap) chunk
library(ComplexHeatmap)
library(circlize)
library(Matrix)
# Expanded list of state-specific drivers based on your regulon analysis
literature_tfs <- c(
"GATA3", "STAT6", "BATF", "FOXP3", "STAT3", "STAT5B", "TCF7", # Core/Memory
"E2F1", "MYC", "FOXM1", # Proliferation (Cl 7)
"STAT1", "STAT2", "IRF1", "IRF9", # IFN-stimulated (Cl 13)
"RELA", "NFKB1", "REL", "FOS", # Pro-inflammatory (Cl 11, 12)
"TBX21", "RUNX3", # Cytotoxic (Cl 1, 9)
"HIF1A", "SREBF1", # Metabolic shift (Cl 8)
"RFX5", "SPI1" # MHC-II High (Cl 0)
)
# Keep only TFs present in the dorothea assay
available_tfs <- intersect(literature_tfs, rownames(seurat_obj[["dorothea"]]))
if (length(available_tfs) < 5) stop("Too few TFs found in dorothea assay. Check TF naming / assay content.")
# Extract TF activity matrix (TFs x cells)
# Use scale.data if available; otherwise fall back to data layer.
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
mat_use <- mat_use[available_tfs, , drop = FALSE]
# Average per cluster (TF x cluster)
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
# Optional: z-score across clusters (helps readability if you used raw 'data' instead of 'scale.data')
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Colors
col_fun <- circlize::colorRamp2(c(-2, 0, 2), c("#313695", "white", "#A50026"))
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
cluster_rows = TRUE,
cluster_columns = TRUE,
show_row_dend = TRUE,
show_column_dend = TRUE,
row_names_gp = grid::gpar(fontsize = 10),
column_names_gp = grid::gpar(fontsize = 10),
column_title = "Literature-validated Sézary TF modules (DoRothEA/decoupleR)",
heatmap_legend_param = list(direction = "vertical")
)
# Draw to notebook
draw(ht)
# Save PDF (vector)
pdf("Output_Figures/Figure_3.16E_Literature_TF_Heatmap_ComplexHeatmap.pdf", width = 10, height = 8)
draw(ht)
dev.off()
# Save PNG (raster, publication-ready)
png("Output_Figures/Figure_3.16E_Literature_TF_Heatmap_ComplexHeatmap.png",
width = 10 * 300, height = 8 * 300, res = 300)
draw(ht)
dev.off()
Figure F
(ComplexHeatmap) chunk
library(ComplexHeatmap)
library(circlize)
library(Matrix)
# Expanded list including FOXO1 and tumor suppressors
literature_tfs <- c(
# Top Malignant Upregulated (Oncogenic, Stress, Proliferation)
"RFX5", "MYC", "E2F4", "HSF1", "SREBF2", "NFE2L2",
"RELA", "REL", "NFKB1", "IRF1", "NCOA2",
# Malignant Downregulated / Normal Enriched (Tumor Suppressors & Homeostasis)
"FOXO1", "FOXO4", "RUNX3", "TCF3", "BCL11A", "NEUROD1", "MEF2B", "PBX2",
# UMAP State Drivers (Intra-tumoral heterogeneity)
"GATA3", "STAT6", "BATF", "FOXP3", "STAT3", "STAT5B", "TCF7", # Core/Memory
"E2F1", "FOXM1", # Proliferation
"STAT1", "STAT2", "IRF9", # IFN response
"HIF1A", "SREBF1", # Metabolic
"TBX21" # Cytotoxic
)
# Extract TF activity matrix
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
available_tfs <- intersect(literature_tfs, rownames(mat_use))
if (length(available_tfs) < 5) stop("Too few TFs found. Check assay data.")
mat_use <- mat_use[available_tfs, , drop = FALSE]
# Average per cluster and z-score
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Annotate Malignant vs Normal (Clusters 3, 10 = Normal)
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3", "10"),
"Normal CD4 T",
"Malignant CD4 T cells")
# Define annotation
ha <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Colors
col_fun <- circlize::colorRamp2(c(-3, 0, 3), c("#313695", "white", "#A50026"))
# Create heatmap with column split
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha,
column_split = cluster_status, # Physically splits normal and malignant columns
cluster_rows = TRUE,
cluster_columns = TRUE,
show_row_dend = TRUE,
show_column_dend = TRUE,
row_names_gp = grid::gpar(fontsize = 10),
column_names_gp = grid::gpar(fontsize = 10),
column_title = "Differential TF Modules in Sézary Heterogeneity",
heatmap_legend_param = list(direction = "vertical")
)
# Output
pdf("Output_Figures/Figure_3.16E_Differential_TF_Heatmap.pdf", width = 11, height = 9)
draw(ht)
dev.off()
png("Output_Figures/Figure_3.16E_Differential_TF_Heatmap.png",
width = 11 * 300, height = 9 * 300, res = 300)
draw(ht)
dev.off()
draw(ht)
Figure G
(ComplexHeatmap) chunk
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject) # for GetAssayData
# ============================================
# 1. Define TF panel metadata (44-47 TFs)
# ============================================
tf_meta <- data.frame(
TF = c(
"MYC","E2F4","RFX5","TWIST1","JUNB","IRF4","CREB1",
"FOS","FOSL1",
"HSF1","NFE2L2","SREBF2",
"RELA","REL","NFKB1","IRF1","NCOA2",
"NFATC1","NFATC2",
"FOXO1","FOXO4","RUNX3","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6",
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B","TCF7",
"E2F1","FOXM1",
"STAT1","STAT2","IRF9",
"HIF1A","SREBF1",
"EOMES",
"PRDM1"
),
Condition = c(
rep("Malignant", 7), # Oncogenic
rep("Malignant", 2), # AP-1
rep("Malignant", 3), # Stress
rep("Malignant", 5), # NF-kB
rep("Malignant", 2), # NFAT
rep("Normal", 5), # Tumor Suppressor
rep("Normal", 7), # Homeostasis
rep("Malignant", 7), # Th2/Memory Core
rep("Malignant", 2), # Proliferation
rep("Malignant", 3), # IFN
rep("Malignant", 2), # Metabolism
rep("Malignant", 1), # Cytotoxic
rep("Malignant", 1) # Terminal Effector
),
Function = c(
rep("Oncogenic", 7),
rep("AP-1 signaling", 2),
rep("Stress Response", 3),
rep("Inflammatory/NF-kB", 5),
rep("NFAT signaling", 2),
rep("Tumor Suppressor", 5),
rep("Normal Homeostasis", 7),
rep("Th2/Memory Core", 7),
rep("Proliferation", 2),
rep("IFN Response", 3),
rep("Metabolism", 2),
rep("Cytotoxic", 1),
rep("Terminal Effector", 1)
),
stringsAsFactors = FALSE
)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for TFs present in Seurat
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order
tf_meta_filtered <- tf_meta[match(rownames(avg_mat_z), tf_meta$TF), ]
# ============================================
# 4. Column & row annotations
# ============================================
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3","10"), "Normal CD4 T cells", "Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T cells" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Row annotation
function_colors <- c(
"Oncogenic" = "#FF7F00",
"AP-1 signaling" = "#FFA500",
"Stress Response" = "#FFD700",
"Inflammatory/NF-kB" = "#1E90FF",
"NFAT signaling" = "#4169E1",
"Tumor Suppressor" = "#377EB8",
"Normal Homeostasis" = "#4DAF4A",
"Th2/Memory Core" = "#984EA3",
"Proliferation" = "#E41A1C",
"IFN Response" = "#00CED1",
"Metabolism" = "#A65628",
"Cytotoxic" = "#F781BF",
"Terminal Effector" = "#800080"
)
ha_row <- rowAnnotation(
Condition = tf_meta_filtered$Condition,
Function = tf_meta_filtered$Function,
col = list(
Condition = c("Normal"="#4DAF4A","Malignant"="#E41A1C"),
Function = function_colors
),
annotation_name_side = "bottom"
)
# ============================================
# 5. Heatmap colors & plotting
# ============================================
col_fun <- circlize::colorRamp2(c(-3,0,3), c("#313695","white","#A50026"))
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
left_annotation = ha_row,
column_split = cluster_status,
row_split = tf_meta_filtered$Function,
cluster_rows = FALSE, # show biological split
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 10),
column_names_gp = gpar(fontsize = 10),
column_title = "Functional TF Modules in Sézary Syndrome",
row_title_rot = 0,
row_title_gp = gpar(fontsize = 9, fontface = "bold"),
heatmap_legend_param = list(direction = "vertical")
)
# ============================================
# 6. Save plots
# ============================================
pdf("Output_Figures/Figure_TF_Heatmap.pdf", width=12, height=10)
draw(ht, merge_legend=TRUE)
dev.off()
png("Output_Figures/Figure_TF_Heatmap.png", width=12*300, height=10*300, res=300)
draw(ht, merge_legend=TRUE)
dev.off()
draw(ht, merge_legend=TRUE)
Figure Malignant
complex heatmap chunk (with 44-47 TFs, literature-based panel)
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define TF panel metadata (KEGG Aligned)
# ============================================
tf_meta <- data.frame(
TF = c(
# --- 1. General Malignancy & Stress ---
"MYC","E2F4","TWIST1","IRF4",
"HSF1","NFE2L2","SREBF2",
# --- 2. TCR Signaling Triad ---
"JUNB","FOS","FOSL1", # AP-1
"NFATC1","NFATC2", # NFAT
"RELA","REL","NFKB1","IRF1","NCOA2", # NF-kB
# --- 3. Th2 / JAK-STAT Core ---
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B",
# --- 4. Differentiation Hierarchy ---
"TCF7","LEF1","MYB", # Stem-like Progenitor
"E2F1","FOXM1", # Proliferation (Cycling)
"PRDM1", # Terminal Effector
# --- 5. KEGG ALIGNED CATEGORIES (NEW) ---
"EOMES","TBX21","RUNX3", # NK-like Cytotoxicity (Cluster 1,9)
"RFX5","CREB1", # Antigen Presentation / MHC-II (Cluster 0)
"KLF4","ETS1","SMAD3", # Migration / Cell Adhesion (CAMs)
# --- 6. Microenvironment ---
"STAT1","STAT2","IRF9", # IFN Response
"HIF1A","SREBF1", # Metabolism
# --- 7. Normal Baseline / Tumor Suppressors ---
"FOXO1","FOXO4","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6"
),
Condition = c(
rep("Malignant", 4), # Oncogenic
rep("Malignant", 3), # Stress
rep("Malignant", 3), # AP-1
rep("Malignant", 2), # NFAT
rep("Malignant", 5), # NF-kB
rep("Malignant", 6), # Th2 / JAK-STAT Core
rep("Malignant", 3), # Stem-like Progenitor
rep("Malignant", 2), # Proliferation
rep("Malignant", 1), # Terminal Effector
rep("Malignant", 3), # NK-like Cytotoxicity
rep("Malignant", 2), # Antigen Presentation
rep("Malignant", 3), # Migration / Adhesion
rep("Malignant", 3), # IFN
rep("Malignant", 2), # Metabolism
rep("Normal", 4), # Tumor Suppressor
rep("Normal", 7) # Homeostasis
),
Function = c(
rep("Oncogenic", 4),
rep("Stress Response", 3),
rep("AP-1 Signaling", 3),
rep("NFAT Signaling", 2),
rep("Inflammatory/NF-kB", 5),
rep("Th2 / JAK-STAT Core", 6),
rep("Stem-like Progenitor", 3),
rep("Proliferation", 2),
rep("Terminal Effector", 1),
rep("NK-like Cytotoxicity", 3), # KEGG aligned
rep("Antigen Presentation", 2), # KEGG aligned
rep("Migration / Adhesion", 3), # KEGG aligned
rep("IFN Response", 3),
rep("Metabolism", 2),
rep("Tumor Suppressor", 4),
rep("Normal Homeostasis", 7)
),
stringsAsFactors = FALSE
)
# Lock in the precise order of the blocks from top to bottom
desired_order <- c(
"Oncogenic",
"Stress Response",
"AP-1 Signaling",
"NFAT Signaling",
"Inflammatory/NF-kB",
"Th2 / JAK-STAT Core",
"Stem-like Progenitor",
"Proliferation",
"Terminal Effector",
"NK-like Cytotoxicity", # Placed here to show effector state
"Antigen Presentation", # Directly links to MHC-II high cluster
"Migration / Adhesion", # Links to CAMs KEGG pathway
"IFN Response",
"Metabolism",
"Tumor Suppressor",
"Normal Homeostasis"
)
tf_meta$Function <- factor(tf_meta$Function, levels = desired_order)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for TFs present in Seurat
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order to match mat_use precisely
row_order_idx <- match(rownames(avg_mat_z), tf_meta$TF)
tf_meta_filtered <- tf_meta[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_filtered$Function), ]
tf_meta_filtered <- tf_meta_filtered[order(tf_meta_filtered$Function), ]
# ============================================
# 4. Column & row annotations
# ============================================
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3","10"), "Normal CD4 T cells", "Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T cells" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Row annotation colors
function_colors <- c(
"Oncogenic" = "#808080",
"Stress Response" = "#FFD700",
"AP-1 Signaling" = "#FF8C00",
"NFAT Signaling" = "#FF4500",
"Inflammatory/NF-kB" = "#E31A1C",
"Th2 / JAK-STAT Core" = "#984EA3",
"Stem-like Progenitor" = "#FF1493",
"Proliferation" = "#1E90FF",
"Terminal Effector" = "#800080",
# New KEGG categories
"NK-like Cytotoxicity" = "#F781BF", # Pink
"Antigen Presentation" = "#66CDAA", # Medium Aquamarine
"Migration / Adhesion" = "#8A2BE2", # Blue Violet
"IFN Response" = "#00CED1",
"Metabolism" = "#A65628",
"Tumor Suppressor" = "#377EB8",
"Normal Homeostasis" = "#4DAF4A"
)
ha_row <- rowAnnotation(
Condition = tf_meta_filtered$Condition,
Function = tf_meta_filtered$Function,
col = list(
Condition = c("Normal"="#4DAF4A","Malignant"="#E41A1C"),
Function = function_colors
),
annotation_name_side = "bottom"
)
# ============================================
# 5. Heatmap colors & plotting
# ============================================
col_fun <- circlize::colorRamp2(c(-3,0,3), c("#313695","white","#A50026"))
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
left_annotation = ha_row,
column_split = cluster_status,
row_split = tf_meta_filtered$Function,
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 10),
column_names_gp = gpar(fontsize = 10),
column_title = "Functional TF Modules in Sézary Syndrome",
row_title_rot = 0,
row_title_gp = gpar(fontsize = 8, fontface = "bold"),
heatmap_legend_param = list(direction = "vertical")
)
# ============================================
# 6. Save plots
# ============================================
pdf("Output_Figures/Figure_TF_Heatmap_KEGG.pdf", width=14, height=14)
draw(ht, merge_legend=TRUE)
dev.off()
draw(ht, merge_legend=TRUE)
Figure Malignant
complex heatmap chunk (with 44-47 TFs, literature-based panel)
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define TF panel metadata (KEGG Aligned)
# ============================================
tf_meta <- data.frame(
TF = c(
# --- 1. General Malignancy & Stress ---
"MYC","E2F4","TWIST1","IRF4",
"HSF1","NFE2L2","SREBF2",
# --- 2. TCR Signaling Triad ---
"JUNB","FOS","FOSL1", # AP-1
"NFATC1","NFATC2", # NFAT
"RELA","REL","NFKB1","IRF1","NCOA2", # NF-kB
# --- 3. Th2 / JAK-STAT Core ---
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B",
# --- 4. Differentiation Hierarchy ---
"TCF7","LEF1","MYB", # Stem-like Progenitor
"E2F1","FOXM1", # Proliferation (Cycling)
"PRDM1", # Terminal Effector
# --- 5. KEGG ALIGNED CATEGORIES (NEW) ---
"EOMES","TBX21","RUNX3", # NK-like Cytotoxicity (Cluster 1,9)
"RFX5","CREB1", # Antigen Presentation / MHC-II (Cluster 0)
"KLF4","ETS1","SMAD3", # Migration / Cell Adhesion (CAMs)
# --- 6. Microenvironment ---
"STAT1","STAT2","IRF9", # IFN Response
"HIF1A","SREBF1", # Metabolism
# --- 7. Normal Baseline / Tumor Suppressors ---
"FOXO1","FOXO4","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6"
),
Condition = c(
rep("Malignant", 4), # Oncogenic
rep("Malignant", 3), # Stress
rep("Malignant", 3), # AP-1
rep("Malignant", 2), # NFAT
rep("Malignant", 5), # NF-kB
rep("Malignant", 6), # Th2 / JAK-STAT Core
rep("Malignant", 3), # Stem-like Progenitor
rep("Malignant", 2), # Proliferation
rep("Malignant", 1), # Terminal Effector
rep("Malignant", 3), # NK-like Cytotoxicity
rep("Malignant", 2), # Antigen Presentation
rep("Malignant", 3), # Migration / Adhesion
rep("Malignant", 3), # IFN
rep("Malignant", 2), # Metabolism
rep("Normal", 4), # Tumor Suppressor
rep("Normal", 7) # Homeostasis
),
Function = c(
rep("Oncogenic", 4),
rep("Stress Response", 3),
rep("AP-1 Signaling", 3),
rep("NFAT Signaling", 2),
rep("Inflammatory/NF-kB", 5),
rep("Th2 / JAK-STAT Core", 6),
rep("Stem-like Progenitor", 3),
rep("Proliferation", 2),
rep("Terminal Effector", 1),
rep("NK-like Cytotoxicity", 3), # KEGG aligned
rep("Antigen Presentation", 2), # KEGG aligned
rep("Migration / Adhesion", 3), # KEGG aligned
rep("IFN Response", 3),
rep("Metabolism", 2),
rep("Tumor Suppressor", 4),
rep("Normal Homeostasis", 7)
),
stringsAsFactors = FALSE
)
# Lock in the precise order of the blocks from top to bottom
desired_order <- c(
"Oncogenic",
"Stress Response",
"AP-1 Signaling",
"NFAT Signaling",
"Inflammatory/NF-kB",
"Th2 / JAK-STAT Core",
"Stem-like Progenitor",
"Proliferation",
"Terminal Effector",
"NK-like Cytotoxicity", # Placed here to show effector state
"Antigen Presentation", # Directly links to MHC-II high cluster
"Migration / Adhesion", # Links to CAMs KEGG pathway
"IFN Response",
"Metabolism",
"Tumor Suppressor",
"Normal Homeostasis"
)
tf_meta$Function <- factor(tf_meta$Function, levels = desired_order)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for TFs present in Seurat
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order to match mat_use precisely
row_order_idx <- match(rownames(avg_mat_z), tf_meta$TF)
tf_meta_filtered <- tf_meta[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_filtered$Function), ]
tf_meta_filtered <- tf_meta_filtered[order(tf_meta_filtered$Function), ]
# ============================================
# 4. Column & row annotations
# ============================================
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3","10"), "Normal CD4 T cells", "Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T cells" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Row annotation colors
function_colors <- c(
"Oncogenic" = "#808080",
"Stress Response" = "#FFD700",
"AP-1 Signaling" = "#FF8C00",
"NFAT Signaling" = "#FF4500",
"Inflammatory/NF-kB" = "#E31A1C",
"Th2 / JAK-STAT Core" = "#984EA3",
"Stem-like Progenitor" = "#FF1493",
"Proliferation" = "#1E90FF",
"Terminal Effector" = "#800080",
# New KEGG categories
"NK-like Cytotoxicity" = "#F781BF", # Pink
"Antigen Presentation" = "#66CDAA", # Medium Aquamarine
"Migration / Adhesion" = "#8A2BE2", # Blue Violet
"IFN Response" = "#00CED1",
"Metabolism" = "#A65628",
"Tumor Suppressor" = "#377EB8",
"Normal Homeostasis" = "#4DAF4A"
)
ha_row <- rowAnnotation(
Condition = tf_meta_filtered$Condition,
Function = tf_meta_filtered$Function,
col = list(
Condition = c("Normal"="#4DAF4A","Malignant"="#E41A1C"),
Function = function_colors
),
annotation_name_side = "bottom"
)
# ============================================
# 5. Heatmap colors & plotting
# ============================================
col_fun <- circlize::colorRamp2(c(-3,0,3), c("#313695","white","#A50026"))
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
left_annotation = ha_row,
column_split = cluster_status,
row_split = tf_meta_filtered$Function,
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 10),
column_names_gp = gpar(fontsize = 10),
column_title = "Functional TF Modules in Sézary Syndrome",
row_title_rot = 0,
row_title_gp = gpar(fontsize = 8, fontface = "bold"),
heatmap_legend_param = list(direction = "vertical")
)
# ============================================
# 6. Save plots
# ============================================
pdf("Output_Figures/Figure_TF_Heatmap_KEGG.pdf", width=14, height=14)
draw(ht, merge_legend=TRUE)
dev.off()
draw(ht, merge_legend=TRUE)
Figure Malignant
complex heatmap chunk (with 44-47 TFs, literature-based panel)
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define TF panel metadata (1:1 UMAP Aligned)
# ============================================
tf_meta <- data.frame(
TF = c(
# --- Baseline Malignancy ---
"MYC","E2F4","TWIST1","IRF4",
# --- Clusters 2 & 6: Th2-like Core ---
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B",
# --- Clusters 11 & 12: Pro-inflammatory & Stress ---
"JUNB","FOS","FOSL1", # AP-1
"RELA","REL","NFKB1","IRF1","NCOA2", # NF-kB
"NFATC1","NFATC2", # TCR/NFAT
"HSF1","NFE2L2","SREBF2", # Stress
# --- Cluster 4: Inflammatory-Migratory ---
"KLF4","ETS1","SMAD3",
# --- Cluster 5: Stem-like ---
"TCF7","LEF1","MYB",
# --- Cluster 7: Cycling (G2/M) ---
"E2F1","FOXM1",
# --- Clusters 1 & 9: NK-like / Cytotoxic ---
"EOMES","TBX21","RUNX3","PRDM1",
# --- Cluster 0: MHC-II High ---
"RFX5","CREB1",
# --- Cluster 13: IFN Stimulated ---
"STAT1","STAT2","IRF9",
# --- Cluster 8: Glycolytic/Metabolic ---
"HIF1A","SREBF1",
# --- Clusters 3 & 10: Normal CD4 T ---
"FOXO1","FOXO4","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6"
),
Condition = c(
rep("Malignant", 4), # Oncogenic
rep("Malignant", 6), # Th2
rep("Malignant", 13), # Pro-inflammatory (AP1, NFkB, NFAT, Stress)
rep("Malignant", 3), # Migratory
rep("Malignant", 3), # Stem-like
rep("Malignant", 2), # Cycling
rep("Malignant", 4), # NK/Cytotoxic
rep("Malignant", 2), # MHC-II
rep("Malignant", 3), # IFN
rep("Malignant", 2), # Glycolytic
rep("Normal", 11) # Normal
),
Function = c(
rep("Oncogenic Core", 4),
rep("Th2-like Core (Cl. 2, 6)", 6),
rep("Pro-inflammatory (Cl. 11, 12)", 13),
rep("Inflammatory-Migratory (Cl. 4)", 3),
rep("Stem-like (Cl. 5)", 3),
rep("Cycling G2/M (Cl. 7)", 2),
rep("NK-like Cytotoxic (Cl. 1, 9)", 4),
rep("MHC-II High (Cl. 0)", 2),
rep("IFN Stimulated (Cl. 13)", 3),
rep("Glycolytic/Metabolic (Cl. 8)", 2),
rep("Normal Homeostasis (Cl. 3, 10)", 11)
),
stringsAsFactors = FALSE
)
# Lock in the precise order of the blocks
desired_order <- c(
"Oncogenic Core",
"Th2-like Core (Cl. 2, 6)",
"Pro-inflammatory (Cl. 11, 12)",
"Inflammatory-Migratory (Cl. 4)",
"Stem-like (Cl. 5)",
"Cycling G2/M (Cl. 7)",
"NK-like Cytotoxic (Cl. 1, 9)",
"MHC-II High (Cl. 0)",
"IFN Stimulated (Cl. 13)",
"Glycolytic/Metabolic (Cl. 8)",
"Normal Homeostasis (Cl. 3, 10)"
)
tf_meta$Function <- factor(tf_meta$Function, levels = desired_order)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"), error = function(e) NULL)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE]))
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order to match mat_use precisely
row_order_idx <- match(rownames(avg_mat_z), tf_meta$TF)
tf_meta_filtered <- tf_meta[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_filtered$Function), ]
tf_meta_filtered <- tf_meta_filtered[order(tf_meta_filtered$Function), ]
# ============================================
# 4. Column & row annotations
# ============================================
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3","10"), "Normal CD4 T cells", "Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(Cell_State = cluster_status, col = list(Cell_State = c("Normal CD4 T cells" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")), annotation_name_side = "left")
# Harmonized color palette
function_colors <- c(
"Oncogenic Core" = "#808080",
"Th2-like Core (Cl. 2, 6)" = "#984EA3",
"Pro-inflammatory (Cl. 11, 12)" = "#E31A1C",
"Inflammatory-Migratory (Cl. 4)" = "#8A2BE2",
"Stem-like (Cl. 5)" = "#FF1493",
"Cycling G2/M (Cl. 7)" = "#1E90FF",
"NK-like Cytotoxic (Cl. 1, 9)" = "#F781BF",
"MHC-II High (Cl. 0)" = "#66CDAA",
"IFN Stimulated (Cl. 13)" = "#00CED1",
"Glycolytic/Metabolic (Cl. 8)" = "#A65628",
"Normal Homeostasis (Cl. 3, 10)" = "#4DAF4A"
)
ha_row <- rowAnnotation(Condition = tf_meta_filtered$Condition, Function = tf_meta_filtered$Function, col = list(Condition = c("Normal"="#4DAF4A","Malignant"="#E41A1C"), Function = function_colors), annotation_name_side = "bottom")
# ============================================
# 5. Heatmap colors & plotting
# ============================================
col_fun <- circlize::colorRamp2(c(-3,0,3), c("#313695","white","#A50026"))
ht <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
left_annotation = ha_row,
column_split = cluster_status,
row_split = tf_meta_filtered$Function,
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 10),
column_names_gp = gpar(fontsize = 10),
column_title = "Regulatory Drivers of Sézary UMAP Cell States",
row_title_rot = 0,
row_title_gp = gpar(fontsize = 9, fontface = "bold"),
heatmap_legend_param = list(direction = "vertical")
)
# ============================================
# 6. Save plots
# ============================================
pdf("Output_Figures/Figure_TF_Heatmap_UMAP_Final.pdf", width=15, height=13)
draw(ht, merge_legend=TRUE)
dev.off()
draw(ht, merge_legend=TRUE)
TEST
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define TF panel metadata
# ============================================
tf_meta <- data.frame(
TF = c(
# --- 1. General Malignancy ---
"MYC","E2F4","TWIST1","IRF4",
# --- 2. TCR Signaling Triad ---
"JUNB","FOS","FOSL1", # AP-1
"NFATC1","NFATC2", # NFAT
"RELA","REL","NFKB1","IRF1","NCOA2", # NF-kB
# --- 3. Stress Response ---
"HSF1","NFE2L2","SREBF2",
# --- 4. Th2 / JAK-STAT Core ---
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B",
# --- 5. Differentiation Hierarchy ---
"TCF7","LEF1","MYB", # Stem-like
"E2F1","FOXM1", # Proliferation
"PRDM1", # Terminal Effector
# --- 6. KEGG Aligned ---
"EOMES","TBX21","RUNX3", # NK-like Cytotoxicity
"RFX5","CREB1", # Antigen Presentation
"KLF4","ETS1","SMAD3", # Migration / Adhesion
# --- 7. Microenvironment ---
"STAT1","STAT2","IRF9", # IFN Response
"HIF1A","SREBF1", # Metabolism
# --- 8. Tumor Suppressors / Normal ---
"FOXO1","FOXO4","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6"
),
Condition = c(
rep("Malignant", 4), # Oncogenic
rep("Malignant", 3), # AP-1
rep("Malignant", 2), # NFAT
rep("Malignant", 5), # NF-kB
rep("Malignant", 3), # Stress Response
rep("Malignant", 6), # Th2/JAK-STAT
rep("Malignant", 3), # Stem-like
rep("Malignant", 2), # Proliferation
rep("Malignant", 1), # Terminal Effector
rep("Malignant", 3), # NK-like
rep("Malignant", 2), # Antigen Presentation
rep("Malignant", 3), # Migration
rep("Malignant", 3), # IFN Response
rep("Malignant", 2), # Metabolism
rep("Normal", 4), # Tumor Suppressor
rep("Normal", 7) # Normal Homeostasis
),
Function = c(
rep("Oncogenic", 4),
rep("AP-1 Signaling", 3),
rep("NFAT Signaling", 2),
rep("NF-\u03baB Signaling", 5), # RENAMED from Inflammatory/NF-kB
rep("Stress Response", 3),
rep("Th2 / JAK-STAT Core", 6),
rep("Stem-like Progenitor", 3),
rep("Proliferation", 2),
rep("Terminal Effector", 1),
rep("NK-like Cytotoxicity", 3),
rep("Antigen Presentation", 2),
rep("Migration / Adhesion", 3),
rep("IFN Response", 3),
rep("Metabolism", 2),
rep("Tumor Suppressor", 4),
rep("Normal Homeostasis", 7)
),
stringsAsFactors = FALSE
)
# Lock in order
desired_order <- c(
"Oncogenic",
"AP-1 Signaling",
"NFAT Signaling",
"NF-\u03baB Signaling",
"Stress Response",
"Th2 / JAK-STAT Core",
"Stem-like Progenitor",
"Proliferation",
"Terminal Effector",
"NK-like Cytotoxicity",
"Antigen Presentation",
"Migration / Adhesion",
"IFN Response",
"Metabolism",
"Tumor Suppressor",
"Normal Homeostasis"
)
tf_meta$Function <- factor(tf_meta$Function, levels = desired_order)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj,
assay = "dorothea",
layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj,
assay = "dorothea",
layer = "data")
mat_use <- if (!is.null(mat_scaled) &&
nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for TFs present in Seurat
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) {
Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE])
})
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order to match mat_use precisely
row_order_idx <- match(rownames(avg_mat_z), tf_meta$TF)
tf_meta_filtered <- tf_meta[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_filtered$Function), ]
tf_meta_filtered <- tf_meta_filtered[order(tf_meta_filtered$Function), ]
# ============================================
# 4. Cluster status & labels
# ============================================
cluster_status <- ifelse(
colnames(avg_mat_z) %in% c("3", "10"),
"Normal CD4 T cells",
"Malignant CD4 T cells"
)
# Cluster biological annotations
cluster_labels <- c(
"0" = "MHC-II High",
"1" = "NK-like",
"2" = "Th2-like",
"3" = "Naive/TCM",
"4" = "Inflammatory",
"5" = "Stem-like",
"6" = "Th2 Activated",
"7" = "Cycling",
"8" = "Glycolytic",
"9" = "Cytotoxic",
"10" = "Central Memory",
"11" = "Pro-inflammatory",
"12" = "GZMB-high",
"13" = "IFN Stimulated"
)
cluster_annotation <- cluster_labels[colnames(avg_mat_z)]
# ============================================
# 5. Column annotation (top)
# ============================================
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
Cluster_Type = cluster_annotation,
col = list(
Cell_State = c(
"Normal CD4 T cells" = "#4DAF4A",
"Malignant CD4 T cells" = "#C00000"
),
Cluster_Type = c(
"MHC-II High" = "#66CDAA",
"NK-like" = "#F781BF",
"Th2-like" = "#984EA3",
"Naive/TCM" = "#4DAF4A",
"Inflammatory" = "#8A2BE2",
"Stem-like" = "#FF1493",
"Th2 Activated" = "#DA70D6",
"Cycling" = "#1E90FF",
"Glycolytic" = "#A65628",
"Cytotoxic" = "#E41A1C",
"Central Memory" = "#32CD32",
"Pro-inflammatory" = "#FF4500",
"GZMB-high" = "#B22222",
"IFN Stimulated" = "#00CED1"
)
),
annotation_name_side = "left",
annotation_name_gp = gpar(fontsize = 8,
fontface = "bold"),
simple_anno_size = unit(4, "mm"),
border = TRUE
)
# ============================================
# 6. Row annotation colors
# ============================================
function_colors <- c(
"Oncogenic" = "#808080",
# TCR Signaling Triad — related but distinct
"AP-1 Signaling" = "#FF8C00",
"NFAT Signaling" = "#FF4500",
"NF-\u03baB Signaling" = "#E31A1C",
"Stress Response" = "#FFD700",
"Th2 / JAK-STAT Core" = "#984EA3",
"Stem-like Progenitor" = "#FF1493",
"Proliferation" = "#1E90FF",
"Terminal Effector" = "#800080",
"NK-like Cytotoxicity" = "#F781BF",
"Antigen Presentation" = "#66CDAA",
"Migration / Adhesion" = "#8A2BE2",
"IFN Response" = "#00CED1",
"Metabolism" = "#A65628",
"Tumor Suppressor" = "#377EB8",
"Normal Homeostasis" = "#4DAF4A"
)
# ============================================
# 7. Row annotation (left)
# ============================================
ha_row <- rowAnnotation(
Condition = tf_meta_filtered$Condition,
Function = tf_meta_filtered$Function,
col = list(
Condition = c(
"Normal" = "#4DAF4A",
"Malignant" = "#C00000"
),
Function = function_colors
),
annotation_name_side = "bottom",
annotation_name_gp = gpar(fontsize = 8,
fontface = "bold"),
simple_anno_size = unit(5, "mm"),
border = TRUE,
gap = unit(1, "mm")
)
# ============================================
# 8. Heatmap color scale — 5 point gradient
# ============================================
col_fun <- circlize::colorRamp2(
c(-3, -1.5, 0, 1.5, 3),
c("#2166AC", # Deep blue
"#92C5DE", # Light blue
"#F7F7F7", # Off-white
"#F4A582", # Light red
"#B2182B") # Deep red
)
# ============================================
# 9. Build heatmap
# ============================================
ht <- Heatmap(
avg_mat_z,
name = "TF activity\n(z-score)",
col = col_fun,
# Annotations
top_annotation = ha_col,
left_annotation = ha_row,
# Splitting
column_split = cluster_status,
row_split = tf_meta_filtered$Function,
# Clustering
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
column_dend_height = unit(15, "mm"),
# Cell appearance
rect_gp = gpar(col = "white", lwd = 0.8),
# Row names
row_names_gp = gpar(fontsize = 8.5,
fontface = "italic",
col = "grey20"),
row_names_side = "right",
# Column names
column_names_gp = gpar(fontsize = 10,
fontface = "bold",
col = "grey10"),
column_names_rot = 0,
# Row title (functional block labels on left)
row_title_rot = 0,
row_title_gp = gpar(fontsize = 8,
fontface = "bold",
col = "grey10"),
row_title_side = "left",
# Gaps between blocks
row_gap = unit(2.5, "mm"),
column_gap = unit(4, "mm"),
# Main title
column_title = "Functional TF Modules in Sézary Syndrome",
column_title_gp = gpar(fontsize = 13,
fontface = "bold",
col = "grey5"),
# Legend
heatmap_legend_param = list(
direction = "vertical",
title = "TF activity\n(z-score)",
title_gp = gpar(fontsize = 9,
fontface = "bold"),
labels_gp = gpar(fontsize = 8),
legend_height = unit(4, "cm"),
border = "grey50",
at = c(-3, -1.5, 0, 1.5, 3),
labels = c("-3", "-1.5", "0", "1.5", "3")
)
)
# ============================================
# 10. Save
# ============================================
# PDF — vector quality for publication
pdf("Output_Figures/Figure_TF_Heatmap_Final.pdf",
width = 16,
height = 15,
useDingbats = FALSE)
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))
dev.off()
null device
1
# PNG — high resolution for presentations
png("Output_Figures/Figure_TF_Heatmap_Final.png",
width = 16 * 300,
height = 15 * 300,
res = 300)
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))
dev.off()
null device
1
# Draw in notebook
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))

Test2

Test3
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define TF panel metadata
# ============================================
tf_meta <- data.frame(
TF = c(
# --- 1. General Malignancy ---
"MYC","E2F4","TWIST1","IRF4",
# --- 2. TCR Signaling Triad ---
"JUNB","FOS","FOSL1", # AP-1
"NFATC1","NFATC2", # NFAT
"RELA","REL","NFKB1","IRF1","NCOA2", # NF-kB
# --- 3. Stress Response ---
"HSF1","NFE2L2","SREBF2",
# --- 4. Th2 / JAK-STAT Core ---
"GATA3","STAT6","BATF","FOXP3","STAT3","STAT5B",
# --- 5. Differentiation Hierarchy ---
"TCF7","LEF1","MYB", # Stem-like
"E2F1","FOXM1", # Proliferation
"PRDM1", # Terminal Effector
# --- 6. KEGG Aligned ---
"EOMES","TBX21","RUNX3", # NK-like Cytotoxicity
"RFX5","CREB1", # Antigen Presentation
"KLF4","ETS1","SMAD3", # Migration / Adhesion
# --- 7. Microenvironment ---
"STAT1","STAT2","IRF9", # IFN Response
"HIF1A","SREBF1", # Metabolism
# --- 8. Tumor Suppressors / Normal ---
"FOXO1","FOXO4","ZEB1","BACH2",
"TCF3","BCL11A","NEUROD1","MEF2B","PBX2","IRF3","BCL6"
),
Condition = c(
rep("Malignant", 4), # Oncogenic
rep("Malignant", 3), # AP-1
rep("Malignant", 2), # NFAT
rep("Malignant", 5), # NF-kB
rep("Malignant", 3), # Stress Response
rep("Malignant", 6), # Th2/JAK-STAT
rep("Malignant", 3), # Stem-like
rep("Malignant", 2), # Proliferation
rep("Malignant", 1), # Terminal Effector
rep("Malignant", 3), # NK-like
rep("Malignant", 2), # Antigen Presentation
rep("Malignant", 3), # Migration
rep("Malignant", 3), # IFN Response
rep("Malignant", 2), # Metabolism
rep("Normal", 4), # Tumor Suppressor
rep("Normal", 7) # Normal Homeostasis
),
Function = c(
rep("Oncogenic", 4),
rep("AP-1 Signaling", 3),
rep("NFAT Signaling", 2),
rep("NF-\u03baB Signaling", 5),
rep("Stress Response", 3),
rep("Th2 / JAK-STAT Core", 6),
rep("Stem-like Progenitor", 3),
rep("Proliferation", 2),
rep("Terminal Effector", 1),
rep("NK-like Cytotoxicity", 3),
rep("Antigen Presentation", 2),
rep("Migration / Adhesion", 3),
rep("IFN Response", 3),
rep("Metabolism", 2),
rep("Tumor Suppressor", 4),
rep("Normal Homeostasis", 7)
),
stringsAsFactors = FALSE
)
# Lock in order
desired_order <- c(
"Oncogenic",
"AP-1 Signaling",
"NFAT Signaling",
"NF-\u03baB Signaling",
"Stress Response",
"Th2 / JAK-STAT Core",
"Stem-like Progenitor",
"Proliferation",
"Terminal Effector",
"NK-like Cytotoxicity",
"Antigen Presentation",
"Migration / Adhesion",
"IFN Response",
"Metabolism",
"Tumor Suppressor",
"Normal Homeostasis"
)
tf_meta$Function <- factor(tf_meta$Function,
levels = desired_order)
# ============================================
# 2. Extract TF activity matrix from Seurat
# ============================================
mat_scaled <- tryCatch(
SeuratObject::GetAssayData(seurat_obj,
assay = "dorothea",
layer = "scale.data"),
error = function(e) NULL
)
mat_data <- SeuratObject::GetAssayData(seurat_obj,
assay = "dorothea",
layer = "data")
mat_use <- if (!is.null(mat_scaled) &&
nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for TFs present in Seurat
available_tfs <- intersect(tf_meta$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per orig.ident & z-score
# ============================================
orig_ident <- as.factor(seurat_obj$orig.ident)
avg_mat <- sapply(levels(orig_ident), function(id) {
Matrix::rowMeans(mat_use[, orig_ident == id,
drop = FALSE])
})
colnames(avg_mat) <- levels(orig_ident)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align tf_meta order to match mat_use precisely
row_order_idx <- match(rownames(avg_mat_z), tf_meta$TF)
tf_meta_filtered <- tf_meta[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_filtered$Function), ]
tf_meta_filtered <- tf_meta_filtered[order(tf_meta_filtered$Function), ]
# ============================================
# 4. Define sample metadata
# FIXED: names match actual orig.ident levels
# ============================================
sample_to_patient <- c(
"L1" = "Patient 1",
"L2" = "Patient 1",
"L3" = "Patient 2",
"L4" = "Patient 2",
"L5" = "Patient 3",
"L6" = "Patient 3",
"L7" = "Patient 3",
"CD4T_lab" = "Normal",
"CD4T_10x" = "Normal"
)
sample_to_type <- c(
"L1" = "Malignant",
"L2" = "Malignant",
"L3" = "Malignant",
"L4" = "Malignant",
"L5" = "Malignant",
"L6" = "Malignant",
"L7" = "Malignant",
"CD4T_lab" = "Normal",
"CD4T_10x" = "Normal"
)
# Extract annotations
patient_annotation <- sample_to_patient[colnames(avg_mat_z)]
celltype_annotation <- sample_to_type[colnames(avg_mat_z)]
# Verify no NAs — should print character(0) for both
cat("Patient NAs:", colnames(avg_mat_z)[is.na(patient_annotation)], "\n")
Patient NAs:
cat("Type NAs:", colnames(avg_mat_z)[is.na(celltype_annotation)], "\n")
Type NAs:
# ============================================
# 5. Column annotation (top)
# ============================================
ha_col <- HeatmapAnnotation(
Cell_Type = celltype_annotation,
Patient = patient_annotation,
col = list(
Cell_Type = c(
"Normal" = "#4DAF4A",
"Malignant" = "#C00000"
),
Patient = c(
"Patient 1" = "#E41A1C",
"Patient 2" = "#377EB8",
"Patient 3" = "#FF7F00",
"Normal" = "#4DAF4A"
)
),
annotation_name_side = "left",
annotation_name_gp = gpar(fontsize = 9,
fontface = "bold",
col = "black"),
simple_anno_size = unit(5, "mm"),
border = TRUE
)
# ============================================
# 6. Row annotation colors
# ============================================
function_colors <- c(
"Oncogenic" = "#808080",
"AP-1 Signaling" = "#FF8C00",
"NFAT Signaling" = "#FF4500",
"NF-\u03baB Signaling" = "#E31A1C",
"Stress Response" = "#FFD700",
"Th2 / JAK-STAT Core" = "#984EA3",
"Stem-like Progenitor" = "#FF1493",
"Proliferation" = "#1E90FF",
"Terminal Effector" = "#800080",
"NK-like Cytotoxicity" = "#F781BF",
"Antigen Presentation" = "#66CDAA",
"Migration / Adhesion" = "#8A2BE2",
"IFN Response" = "#00CED1",
"Metabolism" = "#A65628",
"Tumor Suppressor" = "#377EB8",
"Normal Homeostasis" = "#4DAF4A"
)
# ============================================
# 7. Row annotation (left)
# ============================================
ha_row <- rowAnnotation(
Condition = tf_meta_filtered$Condition,
Function = tf_meta_filtered$Function,
col = list(
Condition = c(
"Normal" = "#4DAF4A",
"Malignant" = "#C00000"
),
Function = function_colors
),
annotation_name_side = "bottom",
annotation_name_gp = gpar(fontsize = 9,
fontface = "bold",
col = "black"),
simple_anno_size = unit(5, "mm"),
border = TRUE,
gap = unit(1, "mm")
)
# ============================================
# 8. Heatmap color scale — 5 point gradient
# ============================================
col_fun <- circlize::colorRamp2(
c(-3, -1.5, 0, 1.5, 3),
c("#2166AC", # Deep blue
"#92C5DE", # Light blue
"#F7F7F7", # Off-white
"#F4A582", # Light red
"#B2182B") # Deep red
)
# ============================================
# 9. Build heatmap
# ============================================
ht <- Heatmap(
avg_mat_z,
name = "TF activity\n(z-score)",
col = col_fun,
# Annotations
top_annotation = ha_col,
left_annotation = ha_row,
# Splitting — columns by patient, rows by function
column_split = patient_annotation,
row_split = tf_meta_filtered$Function,
# Clustering
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
column_dend_height = unit(15, "mm"),
# Cell appearance
rect_gp = gpar(col = "white", lwd = 0.8),
# Row names — BOLD for slide visibility
row_names_gp = gpar(fontsize = 12,
fontface = "bold",
col = "black"),
row_names_side = "right",
# Column names — BOLD for slide visibility
column_names_gp = gpar(fontsize = 12,
fontface = "bold",
col = "black"),
column_names_rot = 45,
# Row title
row_title_rot = 0,
row_title_gp = gpar(fontsize = 11,
fontface = "bold",
col = "black"),
row_title_side = "left",
# Gaps
row_gap = unit(2.5, "mm"),
column_gap = unit(6, "mm"),
# Main title — defined only once
column_title = "Functional TF Modules per Cell Line — Sézary Syndrome",
column_title_gp = gpar(fontsize = 14,
fontface = "bold",
col = "black"),
# Legend — at/labels removed to avoid version errors
heatmap_legend_param = list(
direction = "vertical",
title = "TF activity\n(z-score)",
title_gp = gpar(fontsize = 10,
fontface = "bold",
col = "black"),
labels_gp = gpar(fontsize = 9,
col = "black"),
legend_height = unit(4, "cm"),
border = "grey50"
)
)
# ============================================
# 10. Save
# ============================================
# PDF — vector quality for publication
pdf("Output_Figures/Figure_TF_Heatmap_OrigIdent_Final.pdf",
width = 18,
height = 16,
useDingbats = FALSE)
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))
dev.off()
null device
1
# PNG — high resolution for presentations
png("Output_Figures/Figure_TF_Heatmap_OrigIdent_Final.png",
width = 18 * 300,
height = 16 * 300,
res = 300)
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))
dev.off()
null device
1
# Draw in notebook
draw(ht,
merge_legend = TRUE,
heatmap_legend_side = "right",
annotation_legend_side = "right",
padding = unit(c(5, 5, 5, 5), "mm"))

Define
Th1/Th2/Th17/Th22/Treg Master Regulator Panel
# ============================================
# LIBRARIES
# ============================================
library(ComplexHeatmap)
library(circlize)
library(Matrix)
library(grid)
library(SeuratObject)
# ============================================
# 1. Define Th1/Th2/Th17/Th22/Treg Master Regulator Panel
# ============================================
tf_meta_thelper <- data.frame(
TF = c(
# Th1 Master Regulators
"TBX21", "STAT1", "STAT4", "IRF1",
# Th2 Master Regulators
"GATA3", "STAT6", "BATF", "IRF4",
# Th17 / Th22 Master Regulators
"RORC", "STAT3", "AHR", "MAF",
# Treg Master Regulators
"FOXP3", "FOXO1", "CTLA4" # CTLA4 regulon as Treg proxy
),
Function = c(
rep("Th1", 4),
rep("Th2", 4),
rep("Th17/Th22", 4),
rep("Treg", 3)
),
stringsAsFactors = FALSE
)
# Lock in canonical order: Th1 → Th2 → Th17/Th22 → Treg
tf_meta_thelper$Function <- factor(tf_meta_thelper$Function,
levels = c("Th1", "Th2", "Th17/Th22", "Treg"))
# ============================================
# 2. Extract TF activity matrix
# ============================================
mat_scaled <- tryCatch(SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "scale.data"), error = function(e) NULL)
mat_data <- SeuratObject::GetAssayData(seurat_obj, assay = "dorothea", layer = "data")
mat_use <- if (!is.null(mat_scaled) && nrow(mat_scaled) > 0) mat_scaled else mat_data
# Filter for available TFs
available_tfs <- intersect(tf_meta_thelper$TF, rownames(mat_use))
mat_use <- mat_use[available_tfs, , drop = FALSE]
# ============================================
# 3. Average per cluster & z-score
# ============================================
clusters <- as.factor(seurat_obj$seurat_clusters)
avg_mat <- sapply(levels(clusters), function(cl) Matrix::rowMeans(mat_use[, clusters == cl, drop = FALSE]))
colnames(avg_mat) <- levels(clusters)
avg_mat_z <- t(scale(t(avg_mat)))
avg_mat_z[is.na(avg_mat_z)] <- 0
# Align to our defined helper T panel order
row_order_idx <- match(rownames(avg_mat_z), tf_meta_thelper$TF)
tf_meta_thelper_filtered <- tf_meta_thelper[row_order_idx, ]
avg_mat_z <- avg_mat_z[order(tf_meta_thelper_filtered$Function), ]
tf_meta_thelper_filtered <- tf_meta_thelper_filtered[order(tf_meta_thelper_filtered$Function), ]
# ============================================
# 4. Column & row annotations
# ============================================
cluster_status <- ifelse(colnames(avg_mat_z) %in% c("3","10"), "Normal CD4 T cells", "Malignant CD4 T cells")
ha_col <- HeatmapAnnotation(
Cell_State = cluster_status,
col = list(Cell_State = c("Normal CD4 T cells" = "#4DAF4A", "Malignant CD4 T cells" = "#E41A1C")),
annotation_name_side = "left"
)
# Classical T helper color scheme
helper_colors <- c(
"Th1" = "#E31A1C", # Red
"Th2" = "#1F78B4", # Blue
"Th17/Th22" = "#FF7F00", # Orange
"Treg" = "#33A02C" # Green
)
ha_row <- rowAnnotation(
Function = tf_meta_thelper_filtered$Function,
col = list(Function = helper_colors),
annotation_name_side = "bottom"
)
# ============================================
# 5. Heatmap colors & plotting
# ============================================
col_fun <- circlize::colorRamp2(c(-3,0,3), c("#313695","white","#A50026"))
ht_thelper <- Heatmap(
avg_mat_z,
name = "TF activity (z)",
col = col_fun,
top_annotation = ha_col,
left_annotation = ha_row,
column_split = cluster_status,
row_split = tf_meta_thelper_filtered$Function,
cluster_row_slices = FALSE,
cluster_rows = FALSE,
cluster_columns = TRUE,
show_row_dend = FALSE,
show_column_dend = TRUE,
row_names_gp = gpar(fontsize = 11, fontface = "bold"),
column_names_gp = gpar(fontsize = 11),
column_title = "CD4+ T Helper Lineage Transcription Factors",
row_title_rot = 0,
row_title_gp = gpar(fontsize = 10, fontface = "bold"),
heatmap_legend_param = list(direction = "vertical")
)
# ============================================
# 6. Save plots
# ============================================
pdf("Output_Figures/Figure_TF_Heatmap_THelper_Lineages.pdf", width=12, height=8)
draw(ht_thelper, merge_legend=TRUE)
dev.off()
png("Output_Figures/Figure_TF_Heatmap_THelper_Lineages.png", width=12*300, height=8*300, res=300)
draw(ht_thelper, merge_legend=TRUE)
dev.off()
draw(ht_thelper, merge_legend=TRUE)
Final Save
print("Analysis pipeline complete. All figures and objects saved in Output_Figures folder.")
LS0tCnRpdGxlOiAiVEYgQWN0aXZpdHkgSW5mZXJlbmNlIEFuYWx5c2lzIEhlYXRtYXBzIgphdXRob3I6ICJOYXNpciBNYWhtb29kIEFiYmFzaSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgoKIyBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFfQojIERhdGEgUHJvY2Vzc2luZwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KFNDcHVicikKCiMgUmVndWxhdG9yeSBOZXR3b3JrIEluZmVyZW5jZQpsaWJyYXJ5KGRlY291cGxlUikKbGlicmFyeShkb3JvdGhlYSkKZGF0YShkb3JvdGhlYV9ocywgcGFja2FnZSA9ICJkb3JvdGhlYSIpCmxpYnJhcnkodGljdG9jKQoKCmBgYAoKIyBMb2FkIFNldXJhdCBPYmplY3QgCmBgYHtyfQoKIyBMb2FkIHlvdXIgU2V1cmF0IE9iamVjdApzZXVyYXRfb2JqIDwtIHJlYWRSRFMoIi4uL091dHB1dF9PYmplY3RzL1NldXJhdF9PYmplY3RfV2l0aF9URl9BY3Rpdml0eS5yZHMiKQoKSWRlbnRzKHNldXJhdF9vYmopIDwtICJzZXVyYXRfY2x1c3RlcnMiCnByaW50KCJPYmplY3QgTG9hZGVkLiIpCmBgYAoKIyMgUnVuIHRoaXMgY29kZSBibG9jayB0byByZXN0b3JlIGFjdGl2aXRpZXMgaW5zdGFudGx5OgpgYGB7cn0KCiMgSWYgJ2FjdGl2aXRpZXMnIGlzIG1pc3NpbmcgYnV0ICdkb3JvdGhlYScgYXNzYXkgZXhpc3RzLCByZWNvbnN0cnVjdCBpdDoKaWYgKCFleGlzdHMoImFjdGl2aXRpZXMiKSAmJiAiZG9yb3RoZWEiICVpbiUgbmFtZXMoc2V1cmF0X29iakBhc3NheXMpKSB7CiAgCiAgcHJpbnQoIlJlY29uc3RydWN0aW5nICdhY3Rpdml0aWVzJyBkYXRhZnJhbWUgZnJvbSBTZXVyYXQgb2JqZWN0Li4uIikKICAKICAjIEV4dHJhY3QgdGhlIG1hdHJpeCAoU2V1cmF0IHY1IHVzZXMgJ2xheWVyJyBpbnN0ZWFkIG9mICdzbG90JykKICAjIFNpbmNlIHlvdSByYW4gU2NhbGVEYXRhLCB3ZSB1c2UgJ3NjYWxlLmRhdGEnCiAgbWF0IDwtIEdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJkb3JvdGhlYSIsIGxheWVyID0gInNjYWxlLmRhdGEiKQogIAogICMgQ29udmVydCB0byBsb25nIGZvcm1hdCAod2hhdCBTQ3B1YnIgbmVlZHMpCiAgYWN0aXZpdGllcyA8LSBhcy5kYXRhLmZyYW1lKG1hdCkgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oInNvdXJjZSIpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc291cmNlLCBuYW1lc190byA9ICJjb25kaXRpb24iLCB2YWx1ZXNfdG8gPSAic2NvcmUiKSAlPiUKICAgIG11dGF0ZShzdGF0aXN0aWMgPSAibm9ybV93bWVhbiIpICMgU0NwdWJyIHJlcXVpcmVzIHRoaXMgY29sdW1uCiAgICAKICBwcmludCgiQWN0aXZpdGllcyBkYXRhZnJhbWUgcmVzdG9yZWQhIikKfQpgYGAKCgojIyBTQ3B1YnIgSGVhdG1hcCBWaXN1YWxpemF0aW9uLUhlYXRtYXAgb2YgYXZlcmFnZWQgc2NvcmVzCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KbGlicmFyeShTQ3B1YnIpCiMgR2VuZXJhbCBoZWF0bWFwIChUb3AgVmFyaWFibGUgVEZzKQpvdXQgPC0gU0NwdWJyOjpkb19URkFjdGl2aXR5SGVhdG1hcChzYW1wbGUgPSBzZXVyYXRfb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpdml0aWVzID0gYWN0aXZpdGllcykKCnByaW50KG91dCkKCiMgMS4gU2F2ZSBhcyBQREYKcGRmKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9EZWZhdWx0LnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgpCnByaW50KG91dCkgIyBDb21wbGV4SGVhdG1hcCByZXF1aXJlcyBleHBsaWNpdCBwcmludCgpIGluc2lkZSBwZGYoKQpkZXYub2ZmKCkKCiMgMi4gU2F2ZSBhcyBQTkcKcG5nKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9EZWZhdWx0LnBuZyIsIHdpZHRoID0gMTAgKiAzMDAsIGhlaWdodCA9IDggKiAzMDAsIHJlcyA9IDMwMCkKcHJpbnQob3V0KQpkZXYub2ZmKCkKCgpwcmludChvdXQpCgpgYGAKCgojIyBTZXQgdGhlIHNjYWxlIGxpbWl0cwpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CgpvdXQgPC0gU0NwdWJyOjpkb19URkFjdGl2aXR5SGVhdG1hcChzYW1wbGUgPSBzZXVyYXRfb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpdml0aWVzID0gYWN0aXZpdGllcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmN1dG9mZiA9IC0xLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heC5jdXRvZmYgPSAxLjUpCgpwcmludChvdXQpCgojIFNhdmUgQ29tcGxleEhlYXRtYXAgcHJvcGVybHkKcGRmKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9TY2FsZWQucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCkKcHJpbnQob3V0KQpkZXYub2ZmKCkKCnBuZygiT3V0cHV0X0ZpZ3VyZXMvU0NwdWJyX0hlYXRtYXBfU2NhbGVkLnBuZyIsIHdpZHRoID0gMTAgKiAzMDAsIGhlaWdodCA9IDggKiAzMDAsIHJlcyA9IDMwMCkKcHJpbnQob3V0KQpkZXYub2ZmKCkKCgpgYGAKCiMjIEVuZm9yY2UgU3ltbWV0cnkgKEJlc3QgZm9yIE1hbnVzY3JpcHQpCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCm91dCA8LSBTQ3B1YnI6OmRvX1RGQWN0aXZpdHlIZWF0bWFwKHNhbXBsZSA9IHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2aXRpZXMgPSBhY3Rpdml0aWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gLTEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmN1dG9mZiA9IDEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5mb3JjZV9zeW1tZXRyeSA9IFRSVUUpCgpwcmludChvdXQpCgpwZGYoIk91dHB1dF9GaWd1cmVzL1NDcHVicl9IZWF0bWFwX1N5bW1ldHJpYy5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQpwcmludChvdXQpCmRldi5vZmYoKQoKcG5nKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9TeW1tZXRyaWMucG5nIiwgd2lkdGggPSAxMCAqIDMwMCwgaGVpZ2h0ID0gOCAqIDMwMCwgcmVzID0gMzAwKQpwcmludChvdXQpCmRldi5vZmYoKQoKCnByaW50KG91dCkKCmBgYAoKIyMgVG9wIDQwIFRGcwpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTR9Cm91dCA8LSBTQ3B1YnI6OmRvX1RGQWN0aXZpdHlIZWF0bWFwKHNhbXBsZSA9IHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2aXRpZXMgPSBhY3Rpdml0aWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3RmcyA9IDQwKQoKcHJpbnQob3V0KQoKcGRmKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9Ub3A0MC5wZGYiLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSA2KQpwcmludChvdXQpCmRldi5vZmYoKQoKcG5nKCJPdXRwdXRfRmlndXJlcy9TQ3B1YnJfSGVhdG1hcF9Ub3A0MC5wbmciLCB3aWR0aCA9IDE0ICogMzAwLCBoZWlnaHQgPSA2ICogMzAwLCByZXMgPSAzMDApCnByaW50KG91dCkKZGV2Lm9mZigpCmBgYAoKCiMjIFRvcCAxMDAgVEZzIChGaWd1cmUgQSBmb3IgTWFudXNjcmlwdCkKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0zMn0KCm91dCA8LSBTQ3B1YnI6OmRvX1RGQWN0aXZpdHlIZWF0bWFwKHNhbXBsZSA9IHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2aXRpZXMgPSBhY3Rpdml0aWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl90ZnMgPSAxMDApCgpwcmludChvdXQpCgpwZGYoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2QV9HbG9iYWxfVEZfSGVhdG1hcF9Ub3AxMDAucGRmIiwgd2lkdGggPSAzMiwgaGVpZ2h0ID0gMTIpCnByaW50KG91dCkKZGV2Lm9mZigpCgpwbmcoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2QV9HbG9iYWxfVEZfSGVhdG1hcF9Ub3AxMDAucG5nIiwgd2lkdGggPSAzMiAqIDMwMCwgaGVpZ2h0ID0gMTIgKiAzMDAsIHJlcyA9IDMwMCkKcHJpbnQob3V0KQpkZXYub2ZmKCkKYGBgCiMjIFRvcCAxMDAgVEZzIChGaWd1cmUgQSBmb3IgTWFudXNjcmlwdCkKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0zMn0KCm91dCA8LSBTQ3B1YnI6OmRvX1RGQWN0aXZpdHlIZWF0bWFwKHNhbXBsZSA9IHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2aXRpZXMgPSBhY3Rpdml0aWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gLTEuNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmN1dG9mZiA9IDEuNywgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl90ZnMgPSAxMDApCgpwcmludChvdXQpCgpwZGYoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV9Ub3AxMDAucGRmIiwgd2lkdGggPSAzMiwgaGVpZ2h0ID0gMTIpCnByaW50KG91dCkKZGV2Lm9mZigpCgpwbmcoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV9Ub3AxMDAucG5nIiwgd2lkdGggPSAzMiAqIDMwMCwgaGVpZ2h0ID0gMTIgKiAzMDAsIHJlcyA9IDMwMCkKcHJpbnQob3V0KQpkZXYub2ZmKCkKYGBgCgojIERpZmZlcmVudGlhbCBURiBBY3Rpdml0eSAoTWFsaWduYW50IHZzLiBOb3JtYWwpCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgojIERlZmluZSBDb21wYXJpc29uOiBDbHVzdGVycyAzICYgMTAgKE5vcm1hbCkgdnMgUmVzdCAoTWFsaWduYW50KQpub25fbWFsaWduYW50X2NsdXN0ZXJzIDwtIGMoMywgMTApCnNldXJhdF9vYmokQ29uZGl0aW9uIDwtIGlmZWxzZShzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycyAlaW4lIG5vbl9tYWxpZ25hbnRfY2x1c3RlcnMsICJOb24tTWFsaWduYW50IiwgIk1hbGlnbmFudCIpCgojIFBlcmZvcm0gRGlmZmVyZW50aWFsIEFuYWx5c2lzIG9uIFRGIEFjdGl2aXR5CkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiZG9yb3RoZWEiCklkZW50cyhzZXVyYXRfb2JqKSA8LSAiQ29uZGl0aW9uIgoKcHJpbnQoIlJ1bm5pbmcgRmluZE1hcmtlcnMgb24gVEYgQWN0aXZpdHkuLi4iKQpkaWZmX3RmcyA8LSBGaW5kTWFya2VycyhzZXVyYXRfb2JqLCAKICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMSA9ICJNYWxpZ25hbnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMiA9ICJOb24tTWFsaWduYW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAsICMgR2V0IGFsbCBmb3Igdm9sY2FubwogICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMCkKCiMgQWRkIGdlbmUgY29sdW1uIGZvciBsYWJlbGluZwpkaWZmX3RmcyRnZW5lIDwtIHJvd25hbWVzKGRpZmZfdGZzKQoKIyBTYXZlIFJlc3VsdHMKd3JpdGUuY3N2KGRpZmZfdGZzLCAiT3V0cHV0X1RhYmxlcy9EaWZmZXJlbnRpYWxfVEZfQWN0aXZpdHlfTWFsaWduYW50X3ZzX05vcm1hbC5jc3YiKQpwcmludCgiRGlmZmVyZW50aWFsIGFuYWx5c2lzIGNvbXBsZXRlLiIpCgpgYGAKCgojIEZpZ3VyZSBDOiBWb2xjYW5vIFBsb3QgKExvc3Mgb2YgSG9tZW9zdGFzaXMpCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQojIEhpZ2hsaWdodCBrZXkgZHJpdmVycyBtZW50aW9uZWQgaW4gdGV4dApoaWdobGlnaHRfdGZzIDwtIGMoIkZPWE8xIiwgIk1ZQyIsICJFMkYxIiwgIkUyRjQiLCAiRk9YTTEiLCAiUkVMQSIsICJJUkYxIiwgIlNUQVQxIikKCnBfdm9sY2FubyA8LSBTQ3B1YnI6OmRvX1ZvbGNhbm9QbG90KHNhbXBsZSA9IHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlX2dlbmVzID0gZGlmZl90ZnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2Q19Wb2xjYW5vX1RGX0FjdGl2aXR5LnBkZiIsIHBsb3QgPSBwX3ZvbGNhbm8sIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKZ2dzYXZlKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfMy4xNkNfVm9sY2Fub19URl9BY3Rpdml0eS5wbmciLCBwbG90ID0gcF92b2xjYW5vLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKcHJpbnQocF92b2xjYW5vKQpgYGAKCgojIFVwZGF0ZWQgRmlndXJlIEM6IEVuaGFuY2VkVm9sY2FubwpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiMgSGlnaGxpZ2h0IGtleSBkcml2ZXJzIG1lbnRpb25lZCBpbiB0ZXh0CmhpZ2hsaWdodF90ZnMgPC0gYygiRk9YTzEiLCAiTVlDIiwgIkUyRjEiLCAiRTJGNCIsICJGT1hNMSIsICJSRUxBIiwgIklSRjEiLCAiU1RBVDEiLCAiVE9YIiwgIkdBVEEzIikKCiMgQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gUGxvdApwX3ZvbGNhbm8gPC0gRW5oYW5jZWRWb2xjYW5vKGRpZmZfdGZzLAogICAgbGFiID0gcm93bmFtZXMoZGlmZl90ZnMpLAogICAgeCA9ICdhdmdfbG9nMkZDJywKICAgIHkgPSAncF92YWxfYWRqJywKICAgIAogICAgdGl0bGUgPSAnRGlmZmVyZW50aWFsIFRGIEFjdGl2aXR5OiBNYWxpZ25hbnQgdnMuIE5vbi1NYWxpZ25hbnQnLAogICAgc3VidGl0bGUgPSAnRGVjb3VwbGVSIEluZmVycmVkIEFjdGl2aXR5JywKICAgIHBDdXRvZmYgPSAxZS01LAogICAgRkNjdXRvZmYgPSAwLjUsCiAgICBwb2ludFNpemUgPSAzLjAsCiAgICBsYWJTaXplID0gNS4wLAogICAgY29sQWxwaGEgPSAwLjgsCiAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICBsZWdlbmRMYWJTaXplID0gMTIsCiAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwgIyBEcmF3IGxpbmVzIHRvIGxhYmVscyB0byBhdm9pZCBvdmVybGFwCiAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjUsCiAgICBjb2xDb25uZWN0b3JzID0gJ2dyZXkzMCcsCiAgICAjIEN1c3RvbSBDb2xvcnM6IERvd24gKEJsdWUpLCBVcCAoUmVkKSwgTlMgKEdyZXkpCiAgICBjb2wgPSBjKCJncmV5MzAiLCAiZm9yZXN0Z3JlZW4iLCAicm95YWxibHVlIiwgImZpcmVicmljazIiKQopCgojIFByaW50CnByaW50KHBfdm9sY2FubykKCiMgU2F2ZQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2Q19FbmhhbmNlZFZvbGNhbm9fVEZfQWN0aXZpdHkucGRmIiwgcGxvdCA9IHBfdm9sY2Fubywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCkKZ2dzYXZlKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfMy4xNkNfRW5oYW5jZWRWb2xjYW5vX1RGX0FjdGl2aXR5LnBuZyIsIHBsb3QgPSBwX3ZvbGNhbm8sIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IDMwMCkKYGBgCgoKCgoKCgoKIyBGaWd1cmUgRDogTWl4ZWQgRmVhdHVyZSBQbG90cyAoQWN0aXZpdHkgdnMgRXhwcmVzc2lvbikKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KCiMgV2UgbWFudWFsbHkgY29uc3RydWN0IHRoaXMgdG8gbWl4IEFzc2F5cwoKIyBQYXJ0IDE6IFRGIEFjdGl2aXR5IFBsb3RzIChBc3NheTogZG9yb3RoZWEpCkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiZG9yb3RoZWEiCgpwMSA8LSBGZWF0dXJlUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJGT1hPMSIsIG9yZGVyID0gVCwgcmVkdWN0aW9uID0gInVtYXAiKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gYygiZ3JleTkwIiwgImZpcmVicmljayIpKSArIGdndGl0bGUoIkZPWE8xIEFjdGl2aXR5IChIb21lb3N0YXNpcykiKQpwMiA8LSBGZWF0dXJlUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJSRUxBIiwgb3JkZXIgPSBULCByZWR1Y3Rpb24gPSAidW1hcCIpICsgCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKCJncmV5OTAiLCAiZmlyZWJyaWNrIikpICsgZ2d0aXRsZSgiUkVMQSBBY3Rpdml0eSAoSW5mbGFtbWF0b3J5KSIpCnAzIDwtIEZlYXR1cmVQbG90KHNldXJhdF9vYmosIGZlYXR1cmVzID0gIklSRjEiLCBvcmRlciA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGMoImdyZXk5MCIsICJmaXJlYnJpY2siKSkgKyBnZ3RpdGxlKCJJUkYxIEFjdGl2aXR5IChJRk4tUmVzcG9uc2UpIikKcDQgPC0gRmVhdHVyZVBsb3Qoc2V1cmF0X29iaiwgZmVhdHVyZXMgPSAiRk9YTTEiLCBvcmRlciA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGMoImdyZXk5MCIsICJmaXJlYnJpY2siKSkgKyBnZ3RpdGxlKCJGT1hNMSBBY3Rpdml0eSAoUHJvbGlmZXJhdGlvbikiKQoKIyBQYXJ0IDI6IEdlbmUgRXhwcmVzc2lvbiBQbG90cyAoQXNzYXk6IFNDVC9STkEpCkRlZmF1bHRBc3NheShzZXVyYXRfb2JqKSA8LSAiU0NUIgoKcDUgPC0gRmVhdHVyZVBsb3Qoc2V1cmF0X29iaiwgZmVhdHVyZXMgPSAiSE1HQTIiLCBvcmRlciA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGMoImdyZXk5MCIsICJkYXJrYmx1ZSIpKSArIGdndGl0bGUoIkhNR0EyIEV4cHJlc3Npb24gKFN0ZW0tbGlrZSkiKQpwNiA8LSBGZWF0dXJlUGxvdChzZXVyYXRfb2JqLCBmZWF0dXJlcyA9ICJTT1g0Iiwgb3JkZXIgPSBULCByZWR1Y3Rpb24gPSAidW1hcCIpICsgCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKCJncmV5OTAiLCAiZGFya2JsdWUiKSkgKyBnZ3RpdGxlKCJTT1g0IEV4cHJlc3Npb24gKFN0ZW0tbGlrZSkiKQoKIyBDb21iaW5lCmZpbmFsX2ZpZ3VyZV9EIDwtIChwMSB8IHAyIHwgcDMpIC8gKHA0IHwgcDUgfCBwNikgKyAKICAgICAgICAgICAgICAgICAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkZpZ3VyZSAzLjE2RDogS2V5IERyaXZlcnMgKFJlZD1BY3Rpdml0eSwgQmx1ZT1FeHByZXNzaW9uKSIpCgpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2RF9NaXhlZF9GZWF0dXJlcy5wZGYiLCBwbG90ID0gZmluYWxfZmlndXJlX0QsIHdpZHRoID0gMTQsIGhlaWdodCA9IDEwKQpnZ3NhdmUoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV8zLjE2RF9NaXhlZF9GZWF0dXJlcy5wbmciLCBwbG90ID0gZmluYWxfZmlndXJlX0QsIHdpZHRoID0gMTQsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCnByaW50KGZpbmFsX2ZpZ3VyZV9EKQpgYGAKCgoKCiMgRmlndXJlIEUgKENvbXBsZXhIZWF0bWFwKSBjaHVuawpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KE1hdHJpeCkKCiMgRXhwYW5kZWQgbGlzdCBvZiBzdGF0ZS1zcGVjaWZpYyBkcml2ZXJzIGJhc2VkIG9uIHlvdXIgcmVndWxvbiBhbmFseXNpcwpsaXRlcmF0dXJlX3RmcyA8LSBjKAogICJHQVRBMyIsICJTVEFUNiIsICJCQVRGIiwgIkZPWFAzIiwgIlNUQVQzIiwgIlNUQVQ1QiIsICJUQ0Y3IiwgIyBDb3JlL01lbW9yeQogICJFMkYxIiwgIk1ZQyIsICJGT1hNMSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBQcm9saWZlcmF0aW9uIChDbCA3KQogICJTVEFUMSIsICJTVEFUMiIsICJJUkYxIiwgIklSRjkiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBJRk4tc3RpbXVsYXRlZCAoQ2wgMTMpCiAgIlJFTEEiLCAiTkZLQjEiLCAiUkVMIiwgIkZPUyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFByby1pbmZsYW1tYXRvcnkgKENsIDExLCAxMikKICAiVEJYMjEiLCAiUlVOWDMiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ3l0b3RveGljIChDbCAxLCA5KQogICJISUYxQSIsICJTUkVCRjEiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNZXRhYm9saWMgc2hpZnQgKENsIDgpCiAgIlJGWDUiLCAiU1BJMSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE1IQy1JSSBIaWdoIChDbCAwKQopCgoKIyBLZWVwIG9ubHkgVEZzIHByZXNlbnQgaW4gdGhlIGRvcm90aGVhIGFzc2F5CmF2YWlsYWJsZV90ZnMgPC0gaW50ZXJzZWN0KGxpdGVyYXR1cmVfdGZzLCByb3duYW1lcyhzZXVyYXRfb2JqW1siZG9yb3RoZWEiXV0pKQppZiAobGVuZ3RoKGF2YWlsYWJsZV90ZnMpIDwgNSkgc3RvcCgiVG9vIGZldyBURnMgZm91bmQgaW4gZG9yb3RoZWEgYXNzYXkuIENoZWNrIFRGIG5hbWluZyAvIGFzc2F5IGNvbnRlbnQuIikKCiMgRXh0cmFjdCBURiBhY3Rpdml0eSBtYXRyaXggKFRGcyB4IGNlbGxzKQojIFVzZSBzY2FsZS5kYXRhIGlmIGF2YWlsYWJsZTsgb3RoZXJ3aXNlIGZhbGwgYmFjayB0byBkYXRhIGxheWVyLgptYXRfc2NhbGVkIDwtIHRyeUNhdGNoKAogIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAic2NhbGUuZGF0YSIpLAogIGVycm9yID0gZnVuY3Rpb24oZSkgTlVMTAopCm1hdF9kYXRhIDwtIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAiZGF0YSIpCgptYXRfdXNlIDwtIGlmICghaXMubnVsbChtYXRfc2NhbGVkKSAmJiBucm93KG1hdF9zY2FsZWQpID4gMCkgbWF0X3NjYWxlZCBlbHNlIG1hdF9kYXRhCm1hdF91c2UgPC0gbWF0X3VzZVthdmFpbGFibGVfdGZzLCAsIGRyb3AgPSBGQUxTRV0KCiMgQXZlcmFnZSBwZXIgY2x1c3RlciAoVEYgeCBjbHVzdGVyKQpjbHVzdGVycyA8LSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMpCmF2Z19tYXQgPC0gc2FwcGx5KGxldmVscyhjbHVzdGVycyksIGZ1bmN0aW9uKGNsKSB7CiAgTWF0cml4Ojpyb3dNZWFucyhtYXRfdXNlWywgY2x1c3RlcnMgPT0gY2wsIGRyb3AgPSBGQUxTRV0pCn0pCmNvbG5hbWVzKGF2Z19tYXQpIDwtIGxldmVscyhjbHVzdGVycykKCiMgT3B0aW9uYWw6IHotc2NvcmUgYWNyb3NzIGNsdXN0ZXJzIChoZWxwcyByZWFkYWJpbGl0eSBpZiB5b3UgdXNlZCByYXcgJ2RhdGEnIGluc3RlYWQgb2YgJ3NjYWxlLmRhdGEnKQphdmdfbWF0X3ogPC0gdChzY2FsZSh0KGF2Z19tYXQpKSkKYXZnX21hdF96W2lzLm5hKGF2Z19tYXRfeildIDwtIDAKCiMgQ29sb3JzCmNvbF9mdW4gPC0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYygtMiwgMCwgMiksIGMoIiMzMTM2OTUiLCAid2hpdGUiLCAiI0E1MDAyNiIpKQoKaHQgPC0gSGVhdG1hcCgKICBhdmdfbWF0X3osCiAgbmFtZSA9ICJURiBhY3Rpdml0eSAoeikiLAogIGNvbCA9IGNvbF9mdW4sCiAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogIHNob3dfcm93X2RlbmQgPSBUUlVFLAogIHNob3dfY29sdW1uX2RlbmQgPSBUUlVFLAogIHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxMCksCiAgY29sdW1uX25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDEwKSwKICBjb2x1bW5fdGl0bGUgPSAiTGl0ZXJhdHVyZS12YWxpZGF0ZWQgU8OpemFyeSBURiBtb2R1bGVzIChEb1JvdGhFQS9kZWNvdXBsZVIpIiwKICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoZGlyZWN0aW9uID0gInZlcnRpY2FsIikKKQoKIyBEcmF3IHRvIG5vdGVib29rCmRyYXcoaHQpCgojIFNhdmUgUERGICh2ZWN0b3IpCnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlXzMuMTZFX0xpdGVyYXR1cmVfVEZfSGVhdG1hcF9Db21wbGV4SGVhdG1hcC5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQpkcmF3KGh0KQpkZXYub2ZmKCkKCiMgU2F2ZSBQTkcgKHJhc3RlciwgcHVibGljYXRpb24tcmVhZHkpCnBuZygiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlXzMuMTZFX0xpdGVyYXR1cmVfVEZfSGVhdG1hcF9Db21wbGV4SGVhdG1hcC5wbmciLAogICAgd2lkdGggPSAxMCAqIDMwMCwgaGVpZ2h0ID0gOCAqIDMwMCwgcmVzID0gMzAwKQpkcmF3KGh0KQpkZXYub2ZmKCkKYGBgCgojIEZpZ3VyZSBGIChDb21wbGV4SGVhdG1hcCkgY2h1bmsKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShNYXRyaXgpCgojIEV4cGFuZGVkIGxpc3QgaW5jbHVkaW5nIEZPWE8xIGFuZCB0dW1vciBzdXBwcmVzc29ycwpsaXRlcmF0dXJlX3RmcyA8LSBjKAogICMgVG9wIE1hbGlnbmFudCBVcHJlZ3VsYXRlZCAoT25jb2dlbmljLCBTdHJlc3MsIFByb2xpZmVyYXRpb24pCiAgIlJGWDUiLCAiTVlDIiwgIkUyRjQiLCAiSFNGMSIsICJTUkVCRjIiLCAiTkZFMkwyIiwgCiAgIlJFTEEiLCAiUkVMIiwgIk5GS0IxIiwgIklSRjEiLCAiTkNPQTIiLAogIAogICMgTWFsaWduYW50IERvd25yZWd1bGF0ZWQgLyBOb3JtYWwgRW5yaWNoZWQgKFR1bW9yIFN1cHByZXNzb3JzICYgSG9tZW9zdGFzaXMpCiAgIkZPWE8xIiwgIkZPWE80IiwgIlJVTlgzIiwgIlRDRjMiLCAiQkNMMTFBIiwgIk5FVVJPRDEiLCAiTUVGMkIiLCAiUEJYMiIsCiAgCiAgIyBVTUFQIFN0YXRlIERyaXZlcnMgKEludHJhLXR1bW9yYWwgaGV0ZXJvZ2VuZWl0eSkKICAiR0FUQTMiLCAiU1RBVDYiLCAiQkFURiIsICJGT1hQMyIsICJTVEFUMyIsICJTVEFUNUIiLCAiVENGNyIsICMgQ29yZS9NZW1vcnkKICAiRTJGMSIsICJGT1hNMSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUHJvbGlmZXJhdGlvbgogICJTVEFUMSIsICJTVEFUMiIsICJJUkY5IiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBJRk4gcmVzcG9uc2UKICAiSElGMUEiLCAiU1JFQkYxIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTWV0YWJvbGljCiAgIlRCWDIxIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEN5dG90b3hpYwopCgojIEV4dHJhY3QgVEYgYWN0aXZpdHkgbWF0cml4Cm1hdF9zY2FsZWQgPC0gdHJ5Q2F0Y2goCiAgU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJzY2FsZS5kYXRhIiksCiAgZXJyb3IgPSBmdW5jdGlvbihlKSBOVUxMCikKbWF0X2RhdGEgPC0gU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJkYXRhIikKCm1hdF91c2UgPC0gaWYgKCFpcy5udWxsKG1hdF9zY2FsZWQpICYmIG5yb3cobWF0X3NjYWxlZCkgPiAwKSBtYXRfc2NhbGVkIGVsc2UgbWF0X2RhdGEKYXZhaWxhYmxlX3RmcyA8LSBpbnRlcnNlY3QobGl0ZXJhdHVyZV90ZnMsIHJvd25hbWVzKG1hdF91c2UpKQppZiAobGVuZ3RoKGF2YWlsYWJsZV90ZnMpIDwgNSkgc3RvcCgiVG9vIGZldyBURnMgZm91bmQuIENoZWNrIGFzc2F5IGRhdGEuIikKbWF0X3VzZSA8LSBtYXRfdXNlW2F2YWlsYWJsZV90ZnMsICwgZHJvcCA9IEZBTFNFXQoKIyBBdmVyYWdlIHBlciBjbHVzdGVyIGFuZCB6LXNjb3JlCmNsdXN0ZXJzIDwtIGFzLmZhY3RvcihzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycykKYXZnX21hdCA8LSBzYXBwbHkobGV2ZWxzKGNsdXN0ZXJzKSwgZnVuY3Rpb24oY2wpIHsKICBNYXRyaXg6OnJvd01lYW5zKG1hdF91c2VbLCBjbHVzdGVycyA9PSBjbCwgZHJvcCA9IEZBTFNFXSkKfSkKY29sbmFtZXMoYXZnX21hdCkgPC0gbGV2ZWxzKGNsdXN0ZXJzKQoKYXZnX21hdF96IDwtIHQoc2NhbGUodChhdmdfbWF0KSkpCmF2Z19tYXRfeltpcy5uYShhdmdfbWF0X3opXSA8LSAwCgojIEFubm90YXRlIE1hbGlnbmFudCB2cyBOb3JtYWwgKENsdXN0ZXJzIDMsIDEwID0gTm9ybWFsKQpjbHVzdGVyX3N0YXR1cyA8LSBpZmVsc2UoY29sbmFtZXMoYXZnX21hdF96KSAlaW4lIGMoIjMiLCAiMTAiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ybWFsIENENCBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsaWduYW50IENENCBUIGNlbGxzIikKCiMgRGVmaW5lIGFubm90YXRpb24KaGEgPC0gSGVhdG1hcEFubm90YXRpb24oCiAgQ2VsbF9TdGF0ZSA9IGNsdXN0ZXJfc3RhdHVzLAogIGNvbCA9IGxpc3QoQ2VsbF9TdGF0ZSA9IGMoIk5vcm1hbCBDRDQgVCIgPSAiIzREQUY0QSIsICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiID0gIiNFNDFBMUMiKSksCiAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAibGVmdCIKKQoKIyBDb2xvcnMKY29sX2Z1biA8LSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKC0zLCAwLCAzKSwgYygiIzMxMzY5NSIsICJ3aGl0ZSIsICIjQTUwMDI2IikpCgojIENyZWF0ZSBoZWF0bWFwIHdpdGggY29sdW1uIHNwbGl0Cmh0IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LAogIG5hbWUgPSAiVEYgYWN0aXZpdHkgKHopIiwKICBjb2wgPSBjb2xfZnVuLAogIHRvcF9hbm5vdGF0aW9uID0gaGEsCiAgY29sdW1uX3NwbGl0ID0gY2x1c3Rlcl9zdGF0dXMsICMgUGh5c2ljYWxseSBzcGxpdHMgbm9ybWFsIGFuZCBtYWxpZ25hbnQgY29sdW1ucwogIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgY2x1c3Rlcl9jb2x1bW5zID0gVFJVRSwKICBzaG93X3Jvd19kZW5kID0gVFJVRSwKICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICByb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gMTApLAogIGNvbHVtbl9uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxMCksCiAgY29sdW1uX3RpdGxlID0gIkRpZmZlcmVudGlhbCBURiBNb2R1bGVzIGluIFPDqXphcnkgSGV0ZXJvZ2VuZWl0eSIsCiAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpCikKCiMgT3V0cHV0CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlXzMuMTZFX0RpZmZlcmVudGlhbF9URl9IZWF0bWFwLnBkZiIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDkpCmRyYXcoaHQpCmRldi5vZmYoKQoKcG5nKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfMy4xNkVfRGlmZmVyZW50aWFsX1RGX0hlYXRtYXAucG5nIiwKICAgIHdpZHRoID0gMTEgKiAzMDAsIGhlaWdodCA9IDkgKiAzMDAsIHJlcyA9IDMwMCkKZHJhdyhodCkKZGV2Lm9mZigpCmRyYXcoaHQpCmBgYAojIEZpZ3VyZSBHIChDb21wbGV4SGVhdG1hcCkgY2h1bmsKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBMSUJSQVJJRVMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShncmlkKQpsaWJyYXJ5KFNldXJhdE9iamVjdCkgICMgZm9yIEdldEFzc2F5RGF0YQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDEuIERlZmluZSBURiBwYW5lbCBtZXRhZGF0YSAoNDQtNDcgVEZzKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAiTVlDIiwiRTJGNCIsIlJGWDUiLCJUV0lTVDEiLCJKVU5CIiwiSVJGNCIsIkNSRUIxIiwKICAgICJGT1MiLCJGT1NMMSIsCiAgICAiSFNGMSIsIk5GRTJMMiIsIlNSRUJGMiIsCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwKICAgICJORkFUQzEiLCJORkFUQzIiLAogICAgIkZPWE8xIiwiRk9YTzQiLCJSVU5YMyIsIlpFQjEiLCJCQUNIMiIsCiAgICAiVENGMyIsIkJDTDExQSIsIk5FVVJPRDEiLCJNRUYyQiIsIlBCWDIiLCJJUkYzIiwiQkNMNiIsCiAgICAiR0FUQTMiLCJTVEFUNiIsIkJBVEYiLCJGT1hQMyIsIlNUQVQzIiwiU1RBVDVCIiwiVENGNyIsCiAgICAiRTJGMSIsIkZPWE0xIiwKICAgICJTVEFUMSIsIlNUQVQyIiwiSVJGOSIsCiAgICAiSElGMUEiLCJTUkVCRjEiLAogICAgIkVPTUVTIiwKICAgICJQUkRNMSIKICApLAogIENvbmRpdGlvbiA9IGMoCiAgICByZXAoIk1hbGlnbmFudCIsIDcpLCAgIyBPbmNvZ2VuaWMKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAjIEFQLTEKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAjIFN0cmVzcwogICAgcmVwKCJNYWxpZ25hbnQiLCA1KSwgICMgTkYta0IKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAjIE5GQVQKICAgIHJlcCgiTm9ybWFsIiwgNSksICAgICAjIFR1bW9yIFN1cHByZXNzb3IKICAgIHJlcCgiTm9ybWFsIiwgNyksICAgICAjIEhvbWVvc3Rhc2lzCiAgICByZXAoIk1hbGlnbmFudCIsIDcpLCAgIyBUaDIvTWVtb3J5IENvcmUKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAjIFByb2xpZmVyYXRpb24KICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAjIElGTgogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICMgTWV0YWJvbGlzbQogICAgcmVwKCJNYWxpZ25hbnQiLCAxKSwgICMgQ3l0b3RveGljCiAgICByZXAoIk1hbGlnbmFudCIsIDEpICAgIyBUZXJtaW5hbCBFZmZlY3RvcgogICksCiAgRnVuY3Rpb24gPSBjKAogICAgcmVwKCJPbmNvZ2VuaWMiLCA3KSwKICAgIHJlcCgiQVAtMSBzaWduYWxpbmciLCAyKSwKICAgIHJlcCgiU3RyZXNzIFJlc3BvbnNlIiwgMyksCiAgICByZXAoIkluZmxhbW1hdG9yeS9ORi1rQiIsIDUpLAogICAgcmVwKCJORkFUIHNpZ25hbGluZyIsIDIpLAogICAgcmVwKCJUdW1vciBTdXBwcmVzc29yIiwgNSksCiAgICByZXAoIk5vcm1hbCBIb21lb3N0YXNpcyIsIDcpLAogICAgcmVwKCJUaDIvTWVtb3J5IENvcmUiLCA3KSwKICAgIHJlcCgiUHJvbGlmZXJhdGlvbiIsIDIpLAogICAgcmVwKCJJRk4gUmVzcG9uc2UiLCAzKSwKICAgIHJlcCgiTWV0YWJvbGlzbSIsIDIpLAogICAgcmVwKCJDeXRvdG94aWMiLCAxKSwKICAgIHJlcCgiVGVybWluYWwgRWZmZWN0b3IiLCAxKQogICksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAyLiBFeHRyYWN0IFRGIGFjdGl2aXR5IG1hdHJpeCBmcm9tIFNldXJhdAojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Cm1hdF9zY2FsZWQgPC0gdHJ5Q2F0Y2goCiAgU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJzY2FsZS5kYXRhIiksCiAgZXJyb3IgPSBmdW5jdGlvbihlKSBOVUxMCikKbWF0X2RhdGEgPC0gU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJkYXRhIikKbWF0X3VzZSA8LSBpZiAoIWlzLm51bGwobWF0X3NjYWxlZCkgJiYgbnJvdyhtYXRfc2NhbGVkKSA+IDApIG1hdF9zY2FsZWQgZWxzZSBtYXRfZGF0YQoKIyBGaWx0ZXIgZm9yIFRGcyBwcmVzZW50IGluIFNldXJhdAphdmFpbGFibGVfdGZzIDwtIGludGVyc2VjdCh0Zl9tZXRhJFRGLCByb3duYW1lcyhtYXRfdXNlKSkKbWF0X3VzZSA8LSBtYXRfdXNlW2F2YWlsYWJsZV90ZnMsICwgZHJvcCA9IEZBTFNFXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDMuIEF2ZXJhZ2UgcGVyIGNsdXN0ZXIgJiB6LXNjb3JlCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3RlcnMgPC0gYXMuZmFjdG9yKHNldXJhdF9vYmokc2V1cmF0X2NsdXN0ZXJzKQphdmdfbWF0IDwtIHNhcHBseShsZXZlbHMoY2x1c3RlcnMpLCBmdW5jdGlvbihjbCkgewogIE1hdHJpeDo6cm93TWVhbnMobWF0X3VzZVssIGNsdXN0ZXJzID09IGNsLCBkcm9wID0gRkFMU0VdKQp9KQpjb2xuYW1lcyhhdmdfbWF0KSA8LSBsZXZlbHMoY2x1c3RlcnMpCgphdmdfbWF0X3ogPC0gdChzY2FsZSh0KGF2Z19tYXQpKSkKYXZnX21hdF96W2lzLm5hKGF2Z19tYXRfeildIDwtIDAKCiMgQWxpZ24gdGZfbWV0YSBvcmRlcgp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFbbWF0Y2gocm93bmFtZXMoYXZnX21hdF96KSwgdGZfbWV0YSRURiksIF0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA0LiBDb2x1bW4gJiByb3cgYW5ub3RhdGlvbnMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbHVzdGVyX3N0YXR1cyA8LSBpZmVsc2UoY29sbmFtZXMoYXZnX21hdF96KSAlaW4lIGMoIjMiLCIxMCIpLCAiTm9ybWFsIENENCBUIGNlbGxzIiwgIk1hbGlnbmFudCBDRDQgVCBjZWxscyIpCmhhX2NvbCA8LSBIZWF0bWFwQW5ub3RhdGlvbigKICBDZWxsX1N0YXRlID0gY2x1c3Rlcl9zdGF0dXMsCiAgY29sID0gbGlzdChDZWxsX1N0YXRlID0gYygiTm9ybWFsIENENCBUIGNlbGxzIiA9ICIjNERBRjRBIiwgIk1hbGlnbmFudCBDRDQgVCBjZWxscyIgPSAiI0U0MUExQyIpKSwKICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJsZWZ0IgopCgojIFJvdyBhbm5vdGF0aW9uCmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMiID0gIiNGRjdGMDAiLAogICJBUC0xIHNpZ25hbGluZyIgPSAiI0ZGQTUwMCIsCiAgIlN0cmVzcyBSZXNwb25zZSIgPSAiI0ZGRDcwMCIsCiAgIkluZmxhbW1hdG9yeS9ORi1rQiIgPSAiIzFFOTBGRiIsCiAgIk5GQVQgc2lnbmFsaW5nIiA9ICIjNDE2OUUxIiwKICAiVHVtb3IgU3VwcHJlc3NvciIgPSAiIzM3N0VCOCIsCiAgIk5vcm1hbCBIb21lb3N0YXNpcyIgPSAiIzREQUY0QSIsCiAgIlRoMi9NZW1vcnkgQ29yZSIgPSAiIzk4NEVBMyIsCiAgIlByb2xpZmVyYXRpb24iID0gIiNFNDFBMUMiLAogICJJRk4gUmVzcG9uc2UiID0gIiMwMENFRDEiLAogICJNZXRhYm9saXNtIiA9ICIjQTY1NjI4IiwKICAiQ3l0b3RveGljIiA9ICIjRjc4MUJGIiwKICAiVGVybWluYWwgRWZmZWN0b3IiID0gIiM4MDAwODAiCikKCmhhX3JvdyA8LSByb3dBbm5vdGF0aW9uKAogIENvbmRpdGlvbiA9IHRmX21ldGFfZmlsdGVyZWQkQ29uZGl0aW9uLAogIEZ1bmN0aW9uID0gdGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiwKICBjb2wgPSBsaXN0KAogICAgQ29uZGl0aW9uID0gYygiTm9ybWFsIj0iIzREQUY0QSIsIk1hbGlnbmFudCI9IiNFNDFBMUMiKSwKICAgIEZ1bmN0aW9uID0gZnVuY3Rpb25fY29sb3JzCiAgKSwKICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJib3R0b20iCikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA1LiBIZWF0bWFwIGNvbG9ycyAmIHBsb3R0aW5nCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY29sX2Z1biA8LSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKC0zLDAsMyksIGMoIiMzMTM2OTUiLCJ3aGl0ZSIsIiNBNTAwMjYiKSkKCmh0IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LAogIG5hbWUgPSAiVEYgYWN0aXZpdHkgKHopIiwKICBjb2wgPSBjb2xfZnVuLAogIHRvcF9hbm5vdGF0aW9uID0gaGFfY29sLAogIGxlZnRfYW5ub3RhdGlvbiA9IGhhX3JvdywKICBjb2x1bW5fc3BsaXQgPSBjbHVzdGVyX3N0YXR1cywKICByb3dfc3BsaXQgPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLAogIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCAgICAgIyBzaG93IGJpb2xvZ2ljYWwgc3BsaXQKICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksCiAgY29sdW1uX3RpdGxlID0gIkZ1bmN0aW9uYWwgVEYgTW9kdWxlcyBpbiBTw6l6YXJ5IFN5bmRyb21lIiwKICByb3dfdGl0bGVfcm90ID0gMCwKICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gOSwgZm9udGZhY2UgPSAiYm9sZCIpLAogIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAidmVydGljYWwiKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNi4gU2F2ZSBwbG90cwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXAucGRmIiwgd2lkdGg9MTIsIGhlaWdodD0xMCkKZHJhdyhodCwgbWVyZ2VfbGVnZW5kPVRSVUUpCmRldi5vZmYoKQoKcG5nKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfVEZfSGVhdG1hcC5wbmciLCB3aWR0aD0xMiozMDAsIGhlaWdodD0xMCozMDAsIHJlcz0zMDApCmRyYXcoaHQsIG1lcmdlX2xlZ2VuZD1UUlVFKQpkZXYub2ZmKCkKCmRyYXcoaHQsIG1lcmdlX2xlZ2VuZD1UUlVFKQoKYGBgCgoKCiMgRmlndXJlIE1hbGlnbmFudCBjb21wbGV4IGhlYXRtYXAgY2h1bmsgKHdpdGggNDQtNDcgVEZzLCBsaXRlcmF0dXJlLWJhc2VkIHBhbmVsKQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIExJQlJBUklFUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDEuIERlZmluZSBURiBwYW5lbCBtZXRhZGF0YSAoS0VHRyBBbGlnbmVkKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAjIC0tLSAxLiBHZW5lcmFsIE1hbGlnbmFuY3kgJiBTdHJlc3MgLS0tCiAgICAiTVlDIiwiRTJGNCIsIlRXSVNUMSIsIklSRjQiLAogICAgIkhTRjEiLCJORkUyTDIiLCJTUkVCRjIiLAogICAgCiAgICAjIC0tLSAyLiBUQ1IgU2lnbmFsaW5nIFRyaWFkIC0tLQogICAgIkpVTkIiLCJGT1MiLCJGT1NMMSIsICAgICAgICAgICAjIEFQLTEKICAgICJORkFUQzEiLCJORkFUQzIiLCAgICAgICAgICAgICAgIyBORkFUCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwgIyBORi1rQgogICAgCiAgICAjIC0tLSAzLiBUaDIgLyBKQUstU1RBVCBDb3JlIC0tLQogICAgIkdBVEEzIiwiU1RBVDYiLCJCQVRGIiwiRk9YUDMiLCJTVEFUMyIsIlNUQVQ1QiIsCiAgICAKICAgICMgLS0tIDQuIERpZmZlcmVudGlhdGlvbiBIaWVyYXJjaHkgLS0tCiAgICAiVENGNyIsIkxFRjEiLCJNWUIiLCAgICAgICAgICAgICMgU3RlbS1saWtlIFByb2dlbml0b3IKICAgICJFMkYxIiwiRk9YTTEiLCAgICAgICAgICAgICAgICAgIyBQcm9saWZlcmF0aW9uIChDeWNsaW5nKQogICAgIlBSRE0xIiwgICAgICAgICAgICAgICAgICAgICAgICAjIFRlcm1pbmFsIEVmZmVjdG9yCiAgICAKICAgICMgLS0tIDUuIEtFR0cgQUxJR05FRCBDQVRFR09SSUVTIChORVcpIC0tLQogICAgIkVPTUVTIiwiVEJYMjEiLCJSVU5YMyIsICAgICAgICAjIE5LLWxpa2UgQ3l0b3RveGljaXR5IChDbHVzdGVyIDEsOSkKICAgICJSRlg1IiwiQ1JFQjEiLCAgICAgICAgICAgICAgICAgIyBBbnRpZ2VuIFByZXNlbnRhdGlvbiAvIE1IQy1JSSAoQ2x1c3RlciAwKQogICAgIktMRjQiLCJFVFMxIiwiU01BRDMiLCAgICAgICAgICAjIE1pZ3JhdGlvbiAvIENlbGwgQWRoZXNpb24gKENBTXMpCiAgICAKICAgICMgLS0tIDYuIE1pY3JvZW52aXJvbm1lbnQgLS0tCiAgICAiU1RBVDEiLCJTVEFUMiIsIklSRjkiLCAgICAgICAgICMgSUZOIFJlc3BvbnNlCiAgICAiSElGMUEiLCJTUkVCRjEiLCAgICAgICAgICAgICAgICMgTWV0YWJvbGlzbQogICAgCiAgICAjIC0tLSA3LiBOb3JtYWwgQmFzZWxpbmUgLyBUdW1vciBTdXBwcmVzc29ycyAtLS0KICAgICJGT1hPMSIsIkZPWE80IiwiWkVCMSIsIkJBQ0gyIiwKICAgICJUQ0YzIiwiQkNMMTFBIiwiTkVVUk9EMSIsIk1FRjJCIiwiUEJYMiIsIklSRjMiLCJCQ0w2IgogICksCiAgQ29uZGl0aW9uID0gYygKICAgIHJlcCgiTWFsaWduYW50IiwgNCksICAgIyBPbmNvZ2VuaWMKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBTdHJlc3MKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIEFQLTEKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBORkFUCiAgICByZXAoIk1hbGlnbmFudCIsIDUpLCAgICMgTkYta0IKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCA2KSwgICAjIFRoMiAvIEpBSy1TVEFUIENvcmUKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIFN0ZW0tbGlrZSBQcm9nZW5pdG9yCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgUHJvbGlmZXJhdGlvbgogICAgcmVwKCJNYWxpZ25hbnQiLCAxKSwgICAjIFRlcm1pbmFsIEVmZmVjdG9yCiAgICAKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBOSy1saWtlIEN5dG90b3hpY2l0eQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIEFudGlnZW4gUHJlc2VudGF0aW9uCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgTWlncmF0aW9uIC8gQWRoZXNpb24KICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIElGTgogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIE1ldGFib2xpc20KICAgIAogICAgcmVwKCJOb3JtYWwiLCA0KSwgICAgICAjIFR1bW9yIFN1cHByZXNzb3IKICAgIHJlcCgiTm9ybWFsIiwgNykgICAgICAgIyBIb21lb3N0YXNpcwogICksCiAgRnVuY3Rpb24gPSBjKAogICAgcmVwKCJPbmNvZ2VuaWMiLCA0KSwKICAgIHJlcCgiU3RyZXNzIFJlc3BvbnNlIiwgMyksCiAgICAKICAgIHJlcCgiQVAtMSBTaWduYWxpbmciLCAzKSwKICAgIHJlcCgiTkZBVCBTaWduYWxpbmciLCAyKSwKICAgIHJlcCgiSW5mbGFtbWF0b3J5L05GLWtCIiwgNSksCiAgICAKICAgIHJlcCgiVGgyIC8gSkFLLVNUQVQgQ29yZSIsIDYpLAogICAgCiAgICByZXAoIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiwgMyksCiAgICByZXAoIlByb2xpZmVyYXRpb24iLCAyKSwKICAgIHJlcCgiVGVybWluYWwgRWZmZWN0b3IiLCAxKSwKICAgIAogICAgcmVwKCJOSy1saWtlIEN5dG90b3hpY2l0eSIsIDMpLCAgICMgS0VHRyBhbGlnbmVkCiAgICByZXAoIkFudGlnZW4gUHJlc2VudGF0aW9uIiwgMiksICAgIyBLRUdHIGFsaWduZWQKICAgIHJlcCgiTWlncmF0aW9uIC8gQWRoZXNpb24iLCAzKSwgICAjIEtFR0cgYWxpZ25lZAogICAgCiAgICByZXAoIklGTiBSZXNwb25zZSIsIDMpLAogICAgcmVwKCJNZXRhYm9saXNtIiwgMiksCiAgICAKICAgIHJlcCgiVHVtb3IgU3VwcHJlc3NvciIsIDQpLAogICAgcmVwKCJOb3JtYWwgSG9tZW9zdGFzaXMiLCA3KQogICksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgTG9jayBpbiB0aGUgcHJlY2lzZSBvcmRlciBvZiB0aGUgYmxvY2tzIGZyb20gdG9wIHRvIGJvdHRvbQpkZXNpcmVkX29yZGVyIDwtIGMoCiAgIk9uY29nZW5pYyIsIAogICJTdHJlc3MgUmVzcG9uc2UiLAogICJBUC0xIFNpZ25hbGluZyIsIAogICJORkFUIFNpZ25hbGluZyIsIAogICJJbmZsYW1tYXRvcnkvTkYta0IiLAogICJUaDIgLyBKQUstU1RBVCBDb3JlIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiLCAKICAiUHJvbGlmZXJhdGlvbiIsICAgICAgICAKICAiVGVybWluYWwgRWZmZWN0b3IiLAogICJOSy1saWtlIEN5dG90b3hpY2l0eSIsICAgIyBQbGFjZWQgaGVyZSB0byBzaG93IGVmZmVjdG9yIHN0YXRlCiAgIkFudGlnZW4gUHJlc2VudGF0aW9uIiwgICAjIERpcmVjdGx5IGxpbmtzIHRvIE1IQy1JSSBoaWdoIGNsdXN0ZXIKICAiTWlncmF0aW9uIC8gQWRoZXNpb24iLCAgICMgTGlua3MgdG8gQ0FNcyBLRUdHIHBhdGh3YXkKICAiSUZOIFJlc3BvbnNlIiwKICAiTWV0YWJvbGlzbSIsCiAgIlR1bW9yIFN1cHByZXNzb3IiLAogICJOb3JtYWwgSG9tZW9zdGFzaXMiCikKCnRmX21ldGEkRnVuY3Rpb24gPC0gZmFjdG9yKHRmX21ldGEkRnVuY3Rpb24sIGxldmVscyA9IGRlc2lyZWRfb3JkZXIpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMi4gRXh0cmFjdCBURiBhY3Rpdml0eSBtYXRyaXggZnJvbSBTZXVyYXQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQptYXRfc2NhbGVkIDwtIHRyeUNhdGNoKAogIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAic2NhbGUuZGF0YSIpLAogIGVycm9yID0gZnVuY3Rpb24oZSkgTlVMTAopCm1hdF9kYXRhIDwtIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAiZGF0YSIpCm1hdF91c2UgPC0gaWYgKCFpcy5udWxsKG1hdF9zY2FsZWQpICYmIG5yb3cobWF0X3NjYWxlZCkgPiAwKSBtYXRfc2NhbGVkIGVsc2UgbWF0X2RhdGEKCiMgRmlsdGVyIGZvciBURnMgcHJlc2VudCBpbiBTZXVyYXQKYXZhaWxhYmxlX3RmcyA8LSBpbnRlcnNlY3QodGZfbWV0YSRURiwgcm93bmFtZXMobWF0X3VzZSkpCm1hdF91c2UgPC0gbWF0X3VzZVthdmFpbGFibGVfdGZzLCAsIGRyb3AgPSBGQUxTRV0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAzLiBBdmVyYWdlIHBlciBjbHVzdGVyICYgei1zY29yZQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNsdXN0ZXJzIDwtIGFzLmZhY3RvcihzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycykKYXZnX21hdCA8LSBzYXBwbHkobGV2ZWxzKGNsdXN0ZXJzKSwgZnVuY3Rpb24oY2wpIHsKICBNYXRyaXg6OnJvd01lYW5zKG1hdF91c2VbLCBjbHVzdGVycyA9PSBjbCwgZHJvcCA9IEZBTFNFXSkKfSkKY29sbmFtZXMoYXZnX21hdCkgPC0gbGV2ZWxzKGNsdXN0ZXJzKQoKYXZnX21hdF96IDwtIHQoc2NhbGUodChhdmdfbWF0KSkpCmF2Z19tYXRfeltpcy5uYShhdmdfbWF0X3opXSA8LSAwCgojIEFsaWduIHRmX21ldGEgb3JkZXIgdG8gbWF0Y2ggbWF0X3VzZSBwcmVjaXNlbHkKcm93X29yZGVyX2lkeCA8LSBtYXRjaChyb3duYW1lcyhhdmdfbWF0X3opLCB0Zl9tZXRhJFRGKQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFbcm93X29yZGVyX2lkeCwgXQphdmdfbWF0X3ogPC0gYXZnX21hdF96W29yZGVyKHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24pLCBdCnRmX21ldGFfZmlsdGVyZWQgPC0gdGZfbWV0YV9maWx0ZXJlZFtvcmRlcih0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uKSwgXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDQuIENvbHVtbiAmIHJvdyBhbm5vdGF0aW9ucwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNsdXN0ZXJfc3RhdHVzIDwtIGlmZWxzZShjb2xuYW1lcyhhdmdfbWF0X3opICVpbiUgYygiMyIsIjEwIiksICJOb3JtYWwgQ0Q0IFQgY2VsbHMiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIikKaGFfY29sIDwtIEhlYXRtYXBBbm5vdGF0aW9uKAogIENlbGxfU3RhdGUgPSBjbHVzdGVyX3N0YXR1cywKICBjb2wgPSBsaXN0KENlbGxfU3RhdGUgPSBjKCJOb3JtYWwgQ0Q0IFQgY2VsbHMiID0gIiM0REFGNEEiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIiA9ICIjRTQxQTFDIikpLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImxlZnQiCikKCiMgUm93IGFubm90YXRpb24gY29sb3JzCmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMiID0gIiM4MDgwODAiLAogICJTdHJlc3MgUmVzcG9uc2UiID0gIiNGRkQ3MDAiLAogIAogICJBUC0xIFNpZ25hbGluZyIgPSAiI0ZGOEMwMCIsCiAgIk5GQVQgU2lnbmFsaW5nIiA9ICIjRkY0NTAwIiwKICAiSW5mbGFtbWF0b3J5L05GLWtCIiA9ICIjRTMxQTFDIiwKICAKICAiVGgyIC8gSkFLLVNUQVQgQ29yZSIgPSAiIzk4NEVBMyIsCiAgCiAgIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiA9ICIjRkYxNDkzIiwKICAiUHJvbGlmZXJhdGlvbiIgPSAiIzFFOTBGRiIsCiAgIlRlcm1pbmFsIEVmZmVjdG9yIiA9ICIjODAwMDgwIiwKICAKICAjIE5ldyBLRUdHIGNhdGVnb3JpZXMKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiID0gIiNGNzgxQkYiLCAgICMgUGluawogICJBbnRpZ2VuIFByZXNlbnRhdGlvbiIgPSAiIzY2Q0RBQSIsICAgIyBNZWRpdW0gQXF1YW1hcmluZQogICJNaWdyYXRpb24gLyBBZGhlc2lvbiIgPSAiIzhBMkJFMiIsICAgIyBCbHVlIFZpb2xldAogIAogICJJRk4gUmVzcG9uc2UiID0gIiMwMENFRDEiLAogICJNZXRhYm9saXNtIiA9ICIjQTY1NjI4IiwKICAKICAiVHVtb3IgU3VwcHJlc3NvciIgPSAiIzM3N0VCOCIsCiAgIk5vcm1hbCBIb21lb3N0YXNpcyIgPSAiIzREQUY0QSIKKQoKaGFfcm93IDwtIHJvd0Fubm90YXRpb24oCiAgQ29uZGl0aW9uID0gdGZfbWV0YV9maWx0ZXJlZCRDb25kaXRpb24sCiAgRnVuY3Rpb24gPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLAogIGNvbCA9IGxpc3QoCiAgICBDb25kaXRpb24gPSBjKCJOb3JtYWwiPSIjNERBRjRBIiwiTWFsaWduYW50Ij0iI0U0MUExQyIpLAogICAgRnVuY3Rpb24gPSBmdW5jdGlvbl9jb2xvcnMKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDUuIEhlYXRtYXAgY29sb3JzICYgcGxvdHRpbmcKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKGMoLTMsMCwzKSwgYygiIzMxMzY5NSIsIndoaXRlIiwiI0E1MDAyNiIpKQoKaHQgPC0gSGVhdG1hcCgKICBhdmdfbWF0X3osCiAgbmFtZSA9ICJURiBhY3Rpdml0eSAoeikiLAogIGNvbCA9IGNvbF9mdW4sCiAgdG9wX2Fubm90YXRpb24gPSBoYV9jb2wsCiAgbGVmdF9hbm5vdGF0aW9uID0gaGFfcm93LAogIGNvbHVtbl9zcGxpdCA9IGNsdXN0ZXJfc3RhdHVzLAogIHJvd19zcGxpdCA9IHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24sCiAgY2x1c3Rlcl9yb3dfc2xpY2VzID0gRkFMU0UsICAgIAogIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCAgICAgICAgICAKICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksCiAgY29sdW1uX3RpdGxlID0gIkZ1bmN0aW9uYWwgVEYgTW9kdWxlcyBpbiBTw6l6YXJ5IFN5bmRyb21lIiwKICByb3dfdGl0bGVfcm90ID0gMCwKICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gOCwgZm9udGZhY2UgPSAiYm9sZCIpLAogIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAidmVydGljYWwiKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNi4gU2F2ZSBwbG90cwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfS0VHRy5wZGYiLCB3aWR0aD0xNCwgaGVpZ2h0PTE0KQpkcmF3KGh0LCBtZXJnZV9sZWdlbmQ9VFJVRSkKZGV2Lm9mZigpCmRyYXcoaHQsIG1lcmdlX2xlZ2VuZD1UUlVFKQpgYGAKCiMgRmlndXJlIE1hbGlnbmFudCBjb21wbGV4IGhlYXRtYXAgY2h1bmsgKHdpdGggNDQtNDcgVEZzLCBsaXRlcmF0dXJlLWJhc2VkIHBhbmVsKQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIExJQlJBUklFUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDEuIERlZmluZSBURiBwYW5lbCBtZXRhZGF0YSAoS0VHRyBBbGlnbmVkKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAjIC0tLSAxLiBHZW5lcmFsIE1hbGlnbmFuY3kgJiBTdHJlc3MgLS0tCiAgICAiTVlDIiwiRTJGNCIsIlRXSVNUMSIsIklSRjQiLAogICAgIkhTRjEiLCJORkUyTDIiLCJTUkVCRjIiLAogICAgCiAgICAjIC0tLSAyLiBUQ1IgU2lnbmFsaW5nIFRyaWFkIC0tLQogICAgIkpVTkIiLCJGT1MiLCJGT1NMMSIsICAgICAgICAgICAjIEFQLTEKICAgICJORkFUQzEiLCJORkFUQzIiLCAgICAgICAgICAgICAgIyBORkFUCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwgIyBORi1rQgogICAgCiAgICAjIC0tLSAzLiBUaDIgLyBKQUstU1RBVCBDb3JlIC0tLQogICAgIkdBVEEzIiwiU1RBVDYiLCJCQVRGIiwiRk9YUDMiLCJTVEFUMyIsIlNUQVQ1QiIsCiAgICAKICAgICMgLS0tIDQuIERpZmZlcmVudGlhdGlvbiBIaWVyYXJjaHkgLS0tCiAgICAiVENGNyIsIkxFRjEiLCJNWUIiLCAgICAgICAgICAgICMgU3RlbS1saWtlIFByb2dlbml0b3IKICAgICJFMkYxIiwiRk9YTTEiLCAgICAgICAgICAgICAgICAgIyBQcm9saWZlcmF0aW9uIChDeWNsaW5nKQogICAgIlBSRE0xIiwgICAgICAgICAgICAgICAgICAgICAgICAjIFRlcm1pbmFsIEVmZmVjdG9yCiAgICAKICAgICMgLS0tIDUuIEtFR0cgQUxJR05FRCBDQVRFR09SSUVTIChORVcpIC0tLQogICAgIkVPTUVTIiwiVEJYMjEiLCJSVU5YMyIsICAgICAgICAjIE5LLWxpa2UgQ3l0b3RveGljaXR5IChDbHVzdGVyIDEsOSkKICAgICJSRlg1IiwiQ1JFQjEiLCAgICAgICAgICAgICAgICAgIyBBbnRpZ2VuIFByZXNlbnRhdGlvbiAvIE1IQy1JSSAoQ2x1c3RlciAwKQogICAgIktMRjQiLCJFVFMxIiwiU01BRDMiLCAgICAgICAgICAjIE1pZ3JhdGlvbiAvIENlbGwgQWRoZXNpb24gKENBTXMpCiAgICAKICAgICMgLS0tIDYuIE1pY3JvZW52aXJvbm1lbnQgLS0tCiAgICAiU1RBVDEiLCJTVEFUMiIsIklSRjkiLCAgICAgICAgICMgSUZOIFJlc3BvbnNlCiAgICAiSElGMUEiLCJTUkVCRjEiLCAgICAgICAgICAgICAgICMgTWV0YWJvbGlzbQogICAgCiAgICAjIC0tLSA3LiBOb3JtYWwgQmFzZWxpbmUgLyBUdW1vciBTdXBwcmVzc29ycyAtLS0KICAgICJGT1hPMSIsIkZPWE80IiwiWkVCMSIsIkJBQ0gyIiwKICAgICJUQ0YzIiwiQkNMMTFBIiwiTkVVUk9EMSIsIk1FRjJCIiwiUEJYMiIsIklSRjMiLCJCQ0w2IgogICksCiAgQ29uZGl0aW9uID0gYygKICAgIHJlcCgiTWFsaWduYW50IiwgNCksICAgIyBPbmNvZ2VuaWMKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBTdHJlc3MKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIEFQLTEKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBORkFUCiAgICByZXAoIk1hbGlnbmFudCIsIDUpLCAgICMgTkYta0IKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCA2KSwgICAjIFRoMiAvIEpBSy1TVEFUIENvcmUKICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIFN0ZW0tbGlrZSBQcm9nZW5pdG9yCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgUHJvbGlmZXJhdGlvbgogICAgcmVwKCJNYWxpZ25hbnQiLCAxKSwgICAjIFRlcm1pbmFsIEVmZmVjdG9yCiAgICAKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBOSy1saWtlIEN5dG90b3hpY2l0eQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIEFudGlnZW4gUHJlc2VudGF0aW9uCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgTWlncmF0aW9uIC8gQWRoZXNpb24KICAgIAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIElGTgogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIE1ldGFib2xpc20KICAgIAogICAgcmVwKCJOb3JtYWwiLCA0KSwgICAgICAjIFR1bW9yIFN1cHByZXNzb3IKICAgIHJlcCgiTm9ybWFsIiwgNykgICAgICAgIyBIb21lb3N0YXNpcwogICksCiAgRnVuY3Rpb24gPSBjKAogICAgcmVwKCJPbmNvZ2VuaWMiLCA0KSwKICAgIHJlcCgiU3RyZXNzIFJlc3BvbnNlIiwgMyksCiAgICAKICAgIHJlcCgiQVAtMSBTaWduYWxpbmciLCAzKSwKICAgIHJlcCgiTkZBVCBTaWduYWxpbmciLCAyKSwKICAgIHJlcCgiSW5mbGFtbWF0b3J5L05GLWtCIiwgNSksCiAgICAKICAgIHJlcCgiVGgyIC8gSkFLLVNUQVQgQ29yZSIsIDYpLAogICAgCiAgICByZXAoIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiwgMyksCiAgICByZXAoIlByb2xpZmVyYXRpb24iLCAyKSwKICAgIHJlcCgiVGVybWluYWwgRWZmZWN0b3IiLCAxKSwKICAgIAogICAgcmVwKCJOSy1saWtlIEN5dG90b3hpY2l0eSIsIDMpLCAgICMgS0VHRyBhbGlnbmVkCiAgICByZXAoIkFudGlnZW4gUHJlc2VudGF0aW9uIiwgMiksICAgIyBLRUdHIGFsaWduZWQKICAgIHJlcCgiTWlncmF0aW9uIC8gQWRoZXNpb24iLCAzKSwgICAjIEtFR0cgYWxpZ25lZAogICAgCiAgICByZXAoIklGTiBSZXNwb25zZSIsIDMpLAogICAgcmVwKCJNZXRhYm9saXNtIiwgMiksCiAgICAKICAgIHJlcCgiVHVtb3IgU3VwcHJlc3NvciIsIDQpLAogICAgcmVwKCJOb3JtYWwgSG9tZW9zdGFzaXMiLCA3KQogICksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgTG9jayBpbiB0aGUgcHJlY2lzZSBvcmRlciBvZiB0aGUgYmxvY2tzIGZyb20gdG9wIHRvIGJvdHRvbQpkZXNpcmVkX29yZGVyIDwtIGMoCiAgIk9uY29nZW5pYyIsIAogICJTdHJlc3MgUmVzcG9uc2UiLAogICJBUC0xIFNpZ25hbGluZyIsIAogICJORkFUIFNpZ25hbGluZyIsIAogICJJbmZsYW1tYXRvcnkvTkYta0IiLAogICJUaDIgLyBKQUstU1RBVCBDb3JlIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiLCAKICAiUHJvbGlmZXJhdGlvbiIsICAgICAgICAKICAiVGVybWluYWwgRWZmZWN0b3IiLAogICJOSy1saWtlIEN5dG90b3hpY2l0eSIsICAgIyBQbGFjZWQgaGVyZSB0byBzaG93IGVmZmVjdG9yIHN0YXRlCiAgIkFudGlnZW4gUHJlc2VudGF0aW9uIiwgICAjIERpcmVjdGx5IGxpbmtzIHRvIE1IQy1JSSBoaWdoIGNsdXN0ZXIKICAiTWlncmF0aW9uIC8gQWRoZXNpb24iLCAgICMgTGlua3MgdG8gQ0FNcyBLRUdHIHBhdGh3YXkKICAiSUZOIFJlc3BvbnNlIiwKICAiTWV0YWJvbGlzbSIsCiAgIlR1bW9yIFN1cHByZXNzb3IiLAogICJOb3JtYWwgSG9tZW9zdGFzaXMiCikKCnRmX21ldGEkRnVuY3Rpb24gPC0gZmFjdG9yKHRmX21ldGEkRnVuY3Rpb24sIGxldmVscyA9IGRlc2lyZWRfb3JkZXIpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMi4gRXh0cmFjdCBURiBhY3Rpdml0eSBtYXRyaXggZnJvbSBTZXVyYXQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQptYXRfc2NhbGVkIDwtIHRyeUNhdGNoKAogIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAic2NhbGUuZGF0YSIpLAogIGVycm9yID0gZnVuY3Rpb24oZSkgTlVMTAopCm1hdF9kYXRhIDwtIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosIGFzc2F5ID0gImRvcm90aGVhIiwgbGF5ZXIgPSAiZGF0YSIpCm1hdF91c2UgPC0gaWYgKCFpcy5udWxsKG1hdF9zY2FsZWQpICYmIG5yb3cobWF0X3NjYWxlZCkgPiAwKSBtYXRfc2NhbGVkIGVsc2UgbWF0X2RhdGEKCiMgRmlsdGVyIGZvciBURnMgcHJlc2VudCBpbiBTZXVyYXQKYXZhaWxhYmxlX3RmcyA8LSBpbnRlcnNlY3QodGZfbWV0YSRURiwgcm93bmFtZXMobWF0X3VzZSkpCm1hdF91c2UgPC0gbWF0X3VzZVthdmFpbGFibGVfdGZzLCAsIGRyb3AgPSBGQUxTRV0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAzLiBBdmVyYWdlIHBlciBjbHVzdGVyICYgei1zY29yZQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNsdXN0ZXJzIDwtIGFzLmZhY3RvcihzZXVyYXRfb2JqJHNldXJhdF9jbHVzdGVycykKYXZnX21hdCA8LSBzYXBwbHkobGV2ZWxzKGNsdXN0ZXJzKSwgZnVuY3Rpb24oY2wpIHsKICBNYXRyaXg6OnJvd01lYW5zKG1hdF91c2VbLCBjbHVzdGVycyA9PSBjbCwgZHJvcCA9IEZBTFNFXSkKfSkKY29sbmFtZXMoYXZnX21hdCkgPC0gbGV2ZWxzKGNsdXN0ZXJzKQoKYXZnX21hdF96IDwtIHQoc2NhbGUodChhdmdfbWF0KSkpCmF2Z19tYXRfeltpcy5uYShhdmdfbWF0X3opXSA8LSAwCgojIEFsaWduIHRmX21ldGEgb3JkZXIgdG8gbWF0Y2ggbWF0X3VzZSBwcmVjaXNlbHkKcm93X29yZGVyX2lkeCA8LSBtYXRjaChyb3duYW1lcyhhdmdfbWF0X3opLCB0Zl9tZXRhJFRGKQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFbcm93X29yZGVyX2lkeCwgXQphdmdfbWF0X3ogPC0gYXZnX21hdF96W29yZGVyKHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24pLCBdCnRmX21ldGFfZmlsdGVyZWQgPC0gdGZfbWV0YV9maWx0ZXJlZFtvcmRlcih0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uKSwgXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDQuIENvbHVtbiAmIHJvdyBhbm5vdGF0aW9ucwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNsdXN0ZXJfc3RhdHVzIDwtIGlmZWxzZShjb2xuYW1lcyhhdmdfbWF0X3opICVpbiUgYygiMyIsIjEwIiksICJOb3JtYWwgQ0Q0IFQgY2VsbHMiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIikKaGFfY29sIDwtIEhlYXRtYXBBbm5vdGF0aW9uKAogIENlbGxfU3RhdGUgPSBjbHVzdGVyX3N0YXR1cywKICBjb2wgPSBsaXN0KENlbGxfU3RhdGUgPSBjKCJOb3JtYWwgQ0Q0IFQgY2VsbHMiID0gIiM0REFGNEEiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIiA9ICIjRTQxQTFDIikpLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImxlZnQiCikKCiMgUm93IGFubm90YXRpb24gY29sb3JzCmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMiID0gIiM4MDgwODAiLAogICJTdHJlc3MgUmVzcG9uc2UiID0gIiNGRkQ3MDAiLAogIAogICJBUC0xIFNpZ25hbGluZyIgPSAiI0ZGOEMwMCIsCiAgIk5GQVQgU2lnbmFsaW5nIiA9ICIjRkY0NTAwIiwKICAiSW5mbGFtbWF0b3J5L05GLWtCIiA9ICIjRTMxQTFDIiwKICAKICAiVGgyIC8gSkFLLVNUQVQgQ29yZSIgPSAiIzk4NEVBMyIsCiAgCiAgIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiA9ICIjRkYxNDkzIiwKICAiUHJvbGlmZXJhdGlvbiIgPSAiIzFFOTBGRiIsCiAgIlRlcm1pbmFsIEVmZmVjdG9yIiA9ICIjODAwMDgwIiwKICAKICAjIE5ldyBLRUdHIGNhdGVnb3JpZXMKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiID0gIiNGNzgxQkYiLCAgICMgUGluawogICJBbnRpZ2VuIFByZXNlbnRhdGlvbiIgPSAiIzY2Q0RBQSIsICAgIyBNZWRpdW0gQXF1YW1hcmluZQogICJNaWdyYXRpb24gLyBBZGhlc2lvbiIgPSAiIzhBMkJFMiIsICAgIyBCbHVlIFZpb2xldAogIAogICJJRk4gUmVzcG9uc2UiID0gIiMwMENFRDEiLAogICJNZXRhYm9saXNtIiA9ICIjQTY1NjI4IiwKICAKICAiVHVtb3IgU3VwcHJlc3NvciIgPSAiIzM3N0VCOCIsCiAgIk5vcm1hbCBIb21lb3N0YXNpcyIgPSAiIzREQUY0QSIKKQoKaGFfcm93IDwtIHJvd0Fubm90YXRpb24oCiAgQ29uZGl0aW9uID0gdGZfbWV0YV9maWx0ZXJlZCRDb25kaXRpb24sCiAgRnVuY3Rpb24gPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLAogIGNvbCA9IGxpc3QoCiAgICBDb25kaXRpb24gPSBjKCJOb3JtYWwiPSIjNERBRjRBIiwiTWFsaWduYW50Ij0iI0U0MUExQyIpLAogICAgRnVuY3Rpb24gPSBmdW5jdGlvbl9jb2xvcnMKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDUuIEhlYXRtYXAgY29sb3JzICYgcGxvdHRpbmcKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKGMoLTMsMCwzKSwgYygiIzMxMzY5NSIsIndoaXRlIiwiI0E1MDAyNiIpKQoKaHQgPC0gSGVhdG1hcCgKICBhdmdfbWF0X3osCiAgbmFtZSA9ICJURiBhY3Rpdml0eSAoeikiLAogIGNvbCA9IGNvbF9mdW4sCiAgdG9wX2Fubm90YXRpb24gPSBoYV9jb2wsCiAgbGVmdF9hbm5vdGF0aW9uID0gaGFfcm93LAogIGNvbHVtbl9zcGxpdCA9IGNsdXN0ZXJfc3RhdHVzLAogIHJvd19zcGxpdCA9IHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24sCiAgY2x1c3Rlcl9yb3dfc2xpY2VzID0gRkFMU0UsICAgIAogIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCAgICAgICAgICAKICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwKICBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApLAogIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksCiAgY29sdW1uX3RpdGxlID0gIkZ1bmN0aW9uYWwgVEYgTW9kdWxlcyBpbiBTw6l6YXJ5IFN5bmRyb21lIiwKICByb3dfdGl0bGVfcm90ID0gMCwKICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gOCwgZm9udGZhY2UgPSAiYm9sZCIpLAogIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAidmVydGljYWwiKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNi4gU2F2ZSBwbG90cwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfS0VHRy5wZGYiLCB3aWR0aD0xNCwgaGVpZ2h0PTE0KQpkcmF3KGh0LCBtZXJnZV9sZWdlbmQ9VFJVRSkKZGV2Lm9mZigpCgpkcmF3KGh0LCBtZXJnZV9sZWdlbmQ9VFJVRSkKCmBgYAoKIyBGaWd1cmUgTWFsaWduYW50IGNvbXBsZXggaGVhdG1hcCBjaHVuayAod2l0aCA0NC00NyBURnMsIGxpdGVyYXR1cmUtYmFzZWQgcGFuZWwpCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTJ9CgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTElCUkFSSUVTCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShTZXVyYXRPYmplY3QpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMS4gRGVmaW5lIFRGIHBhbmVsIG1ldGFkYXRhICgxOjEgVU1BUCBBbGlnbmVkKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAjIC0tLSBCYXNlbGluZSBNYWxpZ25hbmN5IC0tLSAKICAgICJNWUMiLCJFMkY0IiwiVFdJU1QxIiwiSVJGNCIsCiAgICAKICAgICMgLS0tIENsdXN0ZXJzIDIgJiA2OiBUaDItbGlrZSBDb3JlIC0tLSAKICAgICJHQVRBMyIsIlNUQVQ2IiwiQkFURiIsIkZPWFAzIiwiU1RBVDMiLCJTVEFUNUIiLAogICAgCiAgICAjIC0tLSBDbHVzdGVycyAxMSAmIDEyOiBQcm8taW5mbGFtbWF0b3J5ICYgU3RyZXNzIC0tLSAKICAgICJKVU5CIiwiRk9TIiwiRk9TTDEiLCAgICAgICAgICAgIyBBUC0xCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwgIyBORi1rQgogICAgIk5GQVRDMSIsIk5GQVRDMiIsICAgICAgICAgICAgICAjIFRDUi9ORkFUCiAgICAiSFNGMSIsIk5GRTJMMiIsIlNSRUJGMiIsICAgICAgICMgU3RyZXNzCiAgICAKICAgICMgLS0tIENsdXN0ZXIgNDogSW5mbGFtbWF0b3J5LU1pZ3JhdG9yeSAtLS0KICAgICJLTEY0IiwiRVRTMSIsIlNNQUQzIiwKICAgIAogICAgIyAtLS0gQ2x1c3RlciA1OiBTdGVtLWxpa2UgLS0tIAogICAgIlRDRjciLCJMRUYxIiwiTVlCIiwgICAgICAgICAgICAKICAgIAogICAgIyAtLS0gQ2x1c3RlciA3OiBDeWNsaW5nIChHMi9NKSAtLS0gCiAgICAiRTJGMSIsIkZPWE0xIiwgICAgICAgICAgICAgICAgIAogICAgCiAgICAjIC0tLSBDbHVzdGVycyAxICYgOTogTkstbGlrZSAvIEN5dG90b3hpYyAtLS0gCiAgICAiRU9NRVMiLCJUQlgyMSIsIlJVTlgzIiwiUFJETTEiLCAgICAgICAgCiAgICAKICAgICMgLS0tIENsdXN0ZXIgMDogTUhDLUlJIEhpZ2ggLS0tIAogICAgIlJGWDUiLCJDUkVCMSIsICAgICAgICAgICAgICAgICAKICAgIAogICAgIyAtLS0gQ2x1c3RlciAxMzogSUZOIFN0aW11bGF0ZWQgLS0tIAogICAgIlNUQVQxIiwiU1RBVDIiLCJJUkY5IiwgICAgICAgICAKICAgIAogICAgIyAtLS0gQ2x1c3RlciA4OiBHbHljb2x5dGljL01ldGFib2xpYyAtLS0gCiAgICAiSElGMUEiLCJTUkVCRjEiLCAgICAgICAgICAgICAgIAogICAgCiAgICAjIC0tLSBDbHVzdGVycyAzICYgMTA6IE5vcm1hbCBDRDQgVCAtLS0gCiAgICAiRk9YTzEiLCJGT1hPNCIsIlpFQjEiLCJCQUNIMiIsCiAgICAiVENGMyIsIkJDTDExQSIsIk5FVVJPRDEiLCJNRUYyQiIsIlBCWDIiLCJJUkYzIiwiQkNMNiIKICApLAogIENvbmRpdGlvbiA9IGMoCiAgICByZXAoIk1hbGlnbmFudCIsIDQpLCAgICMgT25jb2dlbmljCiAgICByZXAoIk1hbGlnbmFudCIsIDYpLCAgICMgVGgyCiAgICByZXAoIk1hbGlnbmFudCIsIDEzKSwgICMgUHJvLWluZmxhbW1hdG9yeSAoQVAxLCBORmtCLCBORkFULCBTdHJlc3MpCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgTWlncmF0b3J5CiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgU3RlbS1saWtlCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgQ3ljbGluZwogICAgcmVwKCJNYWxpZ25hbnQiLCA0KSwgICAjIE5LL0N5dG90b3hpYwogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIE1IQy1JSQogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIElGTgogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIEdseWNvbHl0aWMKICAgIHJlcCgiTm9ybWFsIiwgMTEpICAgICAgIyBOb3JtYWwKICApLAogIEZ1bmN0aW9uID0gYygKICAgIHJlcCgiT25jb2dlbmljIENvcmUiLCA0KSwKICAgIHJlcCgiVGgyLWxpa2UgQ29yZSAoQ2wuIDIsIDYpIiwgNiksCiAgICByZXAoIlByby1pbmZsYW1tYXRvcnkgKENsLiAxMSwgMTIpIiwgMTMpLAogICAgcmVwKCJJbmZsYW1tYXRvcnktTWlncmF0b3J5IChDbC4gNCkiLCAzKSwKICAgIHJlcCgiU3RlbS1saWtlIChDbC4gNSkiLCAzKSwKICAgIHJlcCgiQ3ljbGluZyBHMi9NIChDbC4gNykiLCAyKSwKICAgIHJlcCgiTkstbGlrZSBDeXRvdG94aWMgKENsLiAxLCA5KSIsIDQpLCAgIAogICAgcmVwKCJNSEMtSUkgSGlnaCAoQ2wuIDApIiwgMiksICAgCiAgICByZXAoIklGTiBTdGltdWxhdGVkIChDbC4gMTMpIiwgMyksCiAgICByZXAoIkdseWNvbHl0aWMvTWV0YWJvbGljIChDbC4gOCkiLCAyKSwKICAgIHJlcCgiTm9ybWFsIEhvbWVvc3Rhc2lzIChDbC4gMywgMTApIiwgMTEpCiAgKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKIyBMb2NrIGluIHRoZSBwcmVjaXNlIG9yZGVyIG9mIHRoZSBibG9ja3MKZGVzaXJlZF9vcmRlciA8LSBjKAogICJPbmNvZ2VuaWMgQ29yZSIsIAogICJUaDItbGlrZSBDb3JlIChDbC4gMiwgNikiLAogICJQcm8taW5mbGFtbWF0b3J5IChDbC4gMTEsIDEyKSIsIAogICJJbmZsYW1tYXRvcnktTWlncmF0b3J5IChDbC4gNCkiLCAKICAiU3RlbS1saWtlIChDbC4gNSkiLCAKICAiQ3ljbGluZyBHMi9NIChDbC4gNykiLCAgICAgICAgCiAgIk5LLWxpa2UgQ3l0b3RveGljIChDbC4gMSwgOSkiLCAgIAogICJNSEMtSUkgSGlnaCAoQ2wuIDApIiwgICAKICAiSUZOIFN0aW11bGF0ZWQgKENsLiAxMykiLAogICJHbHljb2x5dGljL01ldGFib2xpYyAoQ2wuIDgpIiwKICAiTm9ybWFsIEhvbWVvc3Rhc2lzIChDbC4gMywgMTApIgopCgp0Zl9tZXRhJEZ1bmN0aW9uIDwtIGZhY3Rvcih0Zl9tZXRhJEZ1bmN0aW9uLCBsZXZlbHMgPSBkZXNpcmVkX29yZGVyKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDIuIEV4dHJhY3QgVEYgYWN0aXZpdHkgbWF0cml4IGZyb20gU2V1cmF0CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KbWF0X3NjYWxlZCA8LSB0cnlDYXRjaChTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJkb3JvdGhlYSIsIGxheWVyID0gInNjYWxlLmRhdGEiKSwgZXJyb3IgPSBmdW5jdGlvbihlKSBOVUxMKQptYXRfZGF0YSA8LSBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLCBhc3NheSA9ICJkb3JvdGhlYSIsIGxheWVyID0gImRhdGEiKQptYXRfdXNlIDwtIGlmICghaXMubnVsbChtYXRfc2NhbGVkKSAmJiBucm93KG1hdF9zY2FsZWQpID4gMCkgbWF0X3NjYWxlZCBlbHNlIG1hdF9kYXRhCgphdmFpbGFibGVfdGZzIDwtIGludGVyc2VjdCh0Zl9tZXRhJFRGLCByb3duYW1lcyhtYXRfdXNlKSkKbWF0X3VzZSA8LSBtYXRfdXNlW2F2YWlsYWJsZV90ZnMsICwgZHJvcCA9IEZBTFNFXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDMuIEF2ZXJhZ2UgcGVyIGNsdXN0ZXIgJiB6LXNjb3JlCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3RlcnMgPC0gYXMuZmFjdG9yKHNldXJhdF9vYmokc2V1cmF0X2NsdXN0ZXJzKQphdmdfbWF0IDwtIHNhcHBseShsZXZlbHMoY2x1c3RlcnMpLCBmdW5jdGlvbihjbCkgTWF0cml4Ojpyb3dNZWFucyhtYXRfdXNlWywgY2x1c3RlcnMgPT0gY2wsIGRyb3AgPSBGQUxTRV0pKQpjb2xuYW1lcyhhdmdfbWF0KSA8LSBsZXZlbHMoY2x1c3RlcnMpCgphdmdfbWF0X3ogPC0gdChzY2FsZSh0KGF2Z19tYXQpKSkKYXZnX21hdF96W2lzLm5hKGF2Z19tYXRfeildIDwtIDAKCiMgQWxpZ24gdGZfbWV0YSBvcmRlciB0byBtYXRjaCBtYXRfdXNlIHByZWNpc2VseQpyb3dfb3JkZXJfaWR4IDwtIG1hdGNoKHJvd25hbWVzKGF2Z19tYXRfeiksIHRmX21ldGEkVEYpCnRmX21ldGFfZmlsdGVyZWQgPC0gdGZfbWV0YVtyb3dfb3JkZXJfaWR4LCBdCmF2Z19tYXRfeiA8LSBhdmdfbWF0X3pbb3JkZXIodGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiksIF0KdGZfbWV0YV9maWx0ZXJlZCA8LSB0Zl9tZXRhX2ZpbHRlcmVkW29yZGVyKHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24pLCBdCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNC4gQ29sdW1uICYgcm93IGFubm90YXRpb25zCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3Rlcl9zdGF0dXMgPC0gaWZlbHNlKGNvbG5hbWVzKGF2Z19tYXRfeikgJWluJSBjKCIzIiwiMTAiKSwgIk5vcm1hbCBDRDQgVCBjZWxscyIsICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiKQpoYV9jb2wgPC0gSGVhdG1hcEFubm90YXRpb24oQ2VsbF9TdGF0ZSA9IGNsdXN0ZXJfc3RhdHVzLCBjb2wgPSBsaXN0KENlbGxfU3RhdGUgPSBjKCJOb3JtYWwgQ0Q0IFQgY2VsbHMiID0gIiM0REFGNEEiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIiA9ICIjRTQxQTFDIikpLCBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJsZWZ0IikKCiMgSGFybW9uaXplZCBjb2xvciBwYWxldHRlCmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMgQ29yZSIgPSAiIzgwODA4MCIsCiAgIlRoMi1saWtlIENvcmUgKENsLiAyLCA2KSIgPSAiIzk4NEVBMyIsCiAgIlByby1pbmZsYW1tYXRvcnkgKENsLiAxMSwgMTIpIiA9ICIjRTMxQTFDIiwKICAiSW5mbGFtbWF0b3J5LU1pZ3JhdG9yeSAoQ2wuIDQpIiA9ICIjOEEyQkUyIiwKICAiU3RlbS1saWtlIChDbC4gNSkiID0gIiNGRjE0OTMiLAogICJDeWNsaW5nIEcyL00gKENsLiA3KSIgPSAiIzFFOTBGRiIsCiAgIk5LLWxpa2UgQ3l0b3RveGljIChDbC4gMSwgOSkiID0gIiNGNzgxQkYiLCAgIAogICJNSEMtSUkgSGlnaCAoQ2wuIDApIiA9ICIjNjZDREFBIiwgICAKICAiSUZOIFN0aW11bGF0ZWQgKENsLiAxMykiID0gIiMwMENFRDEiLAogICJHbHljb2x5dGljL01ldGFib2xpYyAoQ2wuIDgpIiA9ICIjQTY1NjI4IiwKICAiTm9ybWFsIEhvbWVvc3Rhc2lzIChDbC4gMywgMTApIiA9ICIjNERBRjRBIgopCgpoYV9yb3cgPC0gcm93QW5ub3RhdGlvbihDb25kaXRpb24gPSB0Zl9tZXRhX2ZpbHRlcmVkJENvbmRpdGlvbiwgRnVuY3Rpb24gPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLCBjb2wgPSBsaXN0KENvbmRpdGlvbiA9IGMoIk5vcm1hbCI9IiM0REFGNEEiLCJNYWxpZ25hbnQiPSIjRTQxQTFDIiksIEZ1bmN0aW9uID0gZnVuY3Rpb25fY29sb3JzKSwgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAiYm90dG9tIikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA1LiBIZWF0bWFwIGNvbG9ycyAmIHBsb3R0aW5nCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY29sX2Z1biA8LSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKC0zLDAsMyksIGMoIiMzMTM2OTUiLCJ3aGl0ZSIsIiNBNTAwMjYiKSkKCmh0IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LCAKICBuYW1lID0gIlRGIGFjdGl2aXR5ICh6KSIsIAogIGNvbCA9IGNvbF9mdW4sIAogIHRvcF9hbm5vdGF0aW9uID0gaGFfY29sLCAKICBsZWZ0X2Fubm90YXRpb24gPSBoYV9yb3csIAogIGNvbHVtbl9zcGxpdCA9IGNsdXN0ZXJfc3RhdHVzLCAKICByb3dfc3BsaXQgPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLCAKICBjbHVzdGVyX3Jvd19zbGljZXMgPSBGQUxTRSwgCiAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIAogIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsIAogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwgCiAgc2hvd19jb2x1bW5fZGVuZCA9IFRSVUUsIAogIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksIAogIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksIAogIGNvbHVtbl90aXRsZSA9ICJSZWd1bGF0b3J5IERyaXZlcnMgb2YgU8OpemFyeSBVTUFQIENlbGwgU3RhdGVzIiwgCiAgcm93X3RpdGxlX3JvdCA9IDAsIAogIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA5LCBmb250ZmFjZSA9ICJib2xkIiksIAogIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAidmVydGljYWwiKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNi4gU2F2ZSBwbG90cwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfVU1BUF9GaW5hbC5wZGYiLCB3aWR0aD0xNSwgaGVpZ2h0PTEzKQpkcmF3KGh0LCBtZXJnZV9sZWdlbmQ9VFJVRSkKZGV2Lm9mZigpCgpkcmF3KGh0LCBtZXJnZV9sZWdlbmQ9VFJVRSkKYGBgCgoKCgoKCgoKCiMgVEVTVApgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTElCUkFSSUVTCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShTZXVyYXRPYmplY3QpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMS4gRGVmaW5lIFRGIHBhbmVsIG1ldGFkYXRhCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KdGZfbWV0YSA8LSBkYXRhLmZyYW1lKAogIFRGID0gYygKICAgICMgLS0tIDEuIEdlbmVyYWwgTWFsaWduYW5jeSAtLS0KICAgICJNWUMiLCJFMkY0IiwiVFdJU1QxIiwiSVJGNCIsCgogICAgIyAtLS0gMi4gVENSIFNpZ25hbGluZyBUcmlhZCAtLS0KICAgICJKVU5CIiwiRk9TIiwiRk9TTDEiLCAgICAgICAgICAgICAgICAjIEFQLTEKICAgICJORkFUQzEiLCJORkFUQzIiLCAgICAgICAgICAgICAgICAgICAjIE5GQVQKICAgICJSRUxBIiwiUkVMIiwiTkZLQjEiLCJJUkYxIiwiTkNPQTIiLCAjIE5GLWtCCgogICAgIyAtLS0gMy4gU3RyZXNzIFJlc3BvbnNlIC0tLQogICAgIkhTRjEiLCJORkUyTDIiLCJTUkVCRjIiLAoKICAgICMgLS0tIDQuIFRoMiAvIEpBSy1TVEFUIENvcmUgLS0tCiAgICAiR0FUQTMiLCJTVEFUNiIsIkJBVEYiLCJGT1hQMyIsIlNUQVQzIiwiU1RBVDVCIiwKCiAgICAjIC0tLSA1LiBEaWZmZXJlbnRpYXRpb24gSGllcmFyY2h5IC0tLQogICAgIlRDRjciLCJMRUYxIiwiTVlCIiwgICAgICAgICAgICAgICAgICMgU3RlbS1saWtlCiAgICAiRTJGMSIsIkZPWE0xIiwgICAgICAgICAgICAgICAgICAgICAgIyBQcm9saWZlcmF0aW9uCiAgICAiUFJETTEiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUZXJtaW5hbCBFZmZlY3RvcgoKICAgICMgLS0tIDYuIEtFR0cgQWxpZ25lZCAtLS0KICAgICJFT01FUyIsIlRCWDIxIiwiUlVOWDMiLCAgICAgICAgICAgICAjIE5LLWxpa2UgQ3l0b3RveGljaXR5CiAgICAiUkZYNSIsIkNSRUIxIiwgICAgICAgICAgICAgICAgICAgICAgIyBBbnRpZ2VuIFByZXNlbnRhdGlvbgogICAgIktMRjQiLCJFVFMxIiwiU01BRDMiLCAgICAgICAgICAgICAgIyBNaWdyYXRpb24gLyBBZGhlc2lvbgoKICAgICMgLS0tIDcuIE1pY3JvZW52aXJvbm1lbnQgLS0tCiAgICAiU1RBVDEiLCJTVEFUMiIsIklSRjkiLCAgICAgICAgICAgICAgIyBJRk4gUmVzcG9uc2UKICAgICJISUYxQSIsIlNSRUJGMSIsICAgICAgICAgICAgICAgICAgICAjIE1ldGFib2xpc20KCiAgICAjIC0tLSA4LiBUdW1vciBTdXBwcmVzc29ycyAvIE5vcm1hbCAtLS0KICAgICJGT1hPMSIsIkZPWE80IiwiWkVCMSIsIkJBQ0gyIiwKICAgICJUQ0YzIiwiQkNMMTFBIiwiTkVVUk9EMSIsIk1FRjJCIiwiUEJYMiIsIklSRjMiLCJCQ0w2IgogICksCiAgQ29uZGl0aW9uID0gYygKICAgIHJlcCgiTWFsaWduYW50IiwgNCksICAgIyBPbmNvZ2VuaWMKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBBUC0xCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgTkZBVAogICAgcmVwKCJNYWxpZ25hbnQiLCA1KSwgICAjIE5GLWtCCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgU3RyZXNzIFJlc3BvbnNlCiAgICByZXAoIk1hbGlnbmFudCIsIDYpLCAgICMgVGgyL0pBSy1TVEFUCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgU3RlbS1saWtlCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgUHJvbGlmZXJhdGlvbgogICAgcmVwKCJNYWxpZ25hbnQiLCAxKSwgICAjIFRlcm1pbmFsIEVmZmVjdG9yCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgTkstbGlrZQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIEFudGlnZW4gUHJlc2VudGF0aW9uCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgTWlncmF0aW9uCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgSUZOIFJlc3BvbnNlCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgTWV0YWJvbGlzbQogICAgcmVwKCJOb3JtYWwiLCA0KSwgICAgICAjIFR1bW9yIFN1cHByZXNzb3IKICAgIHJlcCgiTm9ybWFsIiwgNykgICAgICAgIyBOb3JtYWwgSG9tZW9zdGFzaXMKICApLAogIEZ1bmN0aW9uID0gYygKICAgIHJlcCgiT25jb2dlbmljIiwgNCksCiAgICByZXAoIkFQLTEgU2lnbmFsaW5nIiwgMyksCiAgICByZXAoIk5GQVQgU2lnbmFsaW5nIiwgMiksCiAgICByZXAoIk5GLVx1MDNiYUIgU2lnbmFsaW5nIiwgNSksICAjIFJFTkFNRUQgZnJvbSBJbmZsYW1tYXRvcnkvTkYta0IKICAgIHJlcCgiU3RyZXNzIFJlc3BvbnNlIiwgMyksCiAgICByZXAoIlRoMiAvIEpBSy1TVEFUIENvcmUiLCA2KSwKICAgIHJlcCgiU3RlbS1saWtlIFByb2dlbml0b3IiLCAzKSwKICAgIHJlcCgiUHJvbGlmZXJhdGlvbiIsIDIpLAogICAgcmVwKCJUZXJtaW5hbCBFZmZlY3RvciIsIDEpLAogICAgcmVwKCJOSy1saWtlIEN5dG90b3hpY2l0eSIsIDMpLAogICAgcmVwKCJBbnRpZ2VuIFByZXNlbnRhdGlvbiIsIDIpLAogICAgcmVwKCJNaWdyYXRpb24gLyBBZGhlc2lvbiIsIDMpLAogICAgcmVwKCJJRk4gUmVzcG9uc2UiLCAzKSwKICAgIHJlcCgiTWV0YWJvbGlzbSIsIDIpLAogICAgcmVwKCJUdW1vciBTdXBwcmVzc29yIiwgNCksCiAgICByZXAoIk5vcm1hbCBIb21lb3N0YXNpcyIsIDcpCiAgKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKIyBMb2NrIGluIG9yZGVyCmRlc2lyZWRfb3JkZXIgPC0gYygKICAiT25jb2dlbmljIiwKICAiQVAtMSBTaWduYWxpbmciLAogICJORkFUIFNpZ25hbGluZyIsCiAgIk5GLVx1MDNiYUIgU2lnbmFsaW5nIiwKICAiU3RyZXNzIFJlc3BvbnNlIiwKICAiVGgyIC8gSkFLLVNUQVQgQ29yZSIsCiAgIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiwKICAiUHJvbGlmZXJhdGlvbiIsCiAgIlRlcm1pbmFsIEVmZmVjdG9yIiwKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiLAogICJBbnRpZ2VuIFByZXNlbnRhdGlvbiIsCiAgIk1pZ3JhdGlvbiAvIEFkaGVzaW9uIiwKICAiSUZOIFJlc3BvbnNlIiwKICAiTWV0YWJvbGlzbSIsCiAgIlR1bW9yIFN1cHByZXNzb3IiLAogICJOb3JtYWwgSG9tZW9zdGFzaXMiCikKCnRmX21ldGEkRnVuY3Rpb24gPC0gZmFjdG9yKHRmX21ldGEkRnVuY3Rpb24sIGxldmVscyA9IGRlc2lyZWRfb3JkZXIpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMi4gRXh0cmFjdCBURiBhY3Rpdml0eSBtYXRyaXggZnJvbSBTZXVyYXQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQptYXRfc2NhbGVkIDwtIHRyeUNhdGNoKAogIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiZG9yb3RoZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gInNjYWxlLmRhdGEiKSwKICBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwKKQptYXRfZGF0YSA8LSBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJkb3JvdGhlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gImRhdGEiKQptYXRfdXNlIDwtIGlmICghaXMubnVsbChtYXRfc2NhbGVkKSAmJgogICAgICAgICAgICAgICBucm93KG1hdF9zY2FsZWQpID4gMCkgbWF0X3NjYWxlZCBlbHNlIG1hdF9kYXRhCgojIEZpbHRlciBmb3IgVEZzIHByZXNlbnQgaW4gU2V1cmF0CmF2YWlsYWJsZV90ZnMgPC0gaW50ZXJzZWN0KHRmX21ldGEkVEYsIHJvd25hbWVzKG1hdF91c2UpKQptYXRfdXNlICAgICAgIDwtIG1hdF91c2VbYXZhaWxhYmxlX3RmcywgLCBkcm9wID0gRkFMU0VdCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMy4gQXZlcmFnZSBwZXIgY2x1c3RlciAmIHotc2NvcmUKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbHVzdGVycyA8LSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMpCmF2Z19tYXQgIDwtIHNhcHBseShsZXZlbHMoY2x1c3RlcnMpLCBmdW5jdGlvbihjbCkgewogIE1hdHJpeDo6cm93TWVhbnMobWF0X3VzZVssIGNsdXN0ZXJzID09IGNsLCBkcm9wID0gRkFMU0VdKQp9KQpjb2xuYW1lcyhhdmdfbWF0KSA8LSBsZXZlbHMoY2x1c3RlcnMpCgphdmdfbWF0X3ogICAgICAgICAgICAgIDwtIHQoc2NhbGUodChhdmdfbWF0KSkpCmF2Z19tYXRfeltpcy5uYShhdmdfbWF0X3opXSA8LSAwCgojIEFsaWduIHRmX21ldGEgb3JkZXIgdG8gbWF0Y2ggbWF0X3VzZSBwcmVjaXNlbHkKcm93X29yZGVyX2lkeCAgICA8LSBtYXRjaChyb3duYW1lcyhhdmdfbWF0X3opLCB0Zl9tZXRhJFRGKQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFbcm93X29yZGVyX2lkeCwgXQphdmdfbWF0X3ogICAgICAgIDwtIGF2Z19tYXRfeltvcmRlcih0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uKSwgXQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFfZmlsdGVyZWRbb3JkZXIodGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiksIF0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA0LiBDbHVzdGVyIHN0YXR1cyAmIGxhYmVscwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmNsdXN0ZXJfc3RhdHVzIDwtIGlmZWxzZSgKICBjb2xuYW1lcyhhdmdfbWF0X3opICVpbiUgYygiMyIsICIxMCIpLAogICJOb3JtYWwgQ0Q0IFQgY2VsbHMiLAogICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiCikKCiMgQ2x1c3RlciBiaW9sb2dpY2FsIGFubm90YXRpb25zCmNsdXN0ZXJfbGFiZWxzIDwtIGMoCiAgIjAiICA9ICJNSEMtSUkgSGlnaCIsCiAgIjEiICA9ICJOSy1saWtlIiwKICAiMiIgID0gIlRoMi1saWtlIiwKICAiMyIgID0gIk5haXZlL1RDTSIsCiAgIjQiICA9ICJJbmZsYW1tYXRvcnkiLAogICI1IiAgPSAiU3RlbS1saWtlIiwKICAiNiIgID0gIlRoMiBBY3RpdmF0ZWQiLAogICI3IiAgPSAiQ3ljbGluZyIsCiAgIjgiICA9ICJHbHljb2x5dGljIiwKICAiOSIgID0gIkN5dG90b3hpYyIsCiAgIjEwIiA9ICJDZW50cmFsIE1lbW9yeSIsCiAgIjExIiA9ICJQcm8taW5mbGFtbWF0b3J5IiwKICAiMTIiID0gIkdaTUItaGlnaCIsCiAgIjEzIiA9ICJJRk4gU3RpbXVsYXRlZCIKKQpjbHVzdGVyX2Fubm90YXRpb24gPC0gY2x1c3Rlcl9sYWJlbHNbY29sbmFtZXMoYXZnX21hdF96KV0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA1LiBDb2x1bW4gYW5ub3RhdGlvbiAodG9wKQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmhhX2NvbCA8LSBIZWF0bWFwQW5ub3RhdGlvbigKICBDZWxsX1N0YXRlICAgPSBjbHVzdGVyX3N0YXR1cywKICBDbHVzdGVyX1R5cGUgPSBjbHVzdGVyX2Fubm90YXRpb24sCiAgY29sID0gbGlzdCgKICAgIENlbGxfU3RhdGUgPSBjKAogICAgICAiTm9ybWFsIENENCBUIGNlbGxzIiAgICA9ICIjNERBRjRBIiwKICAgICAgIk1hbGlnbmFudCBDRDQgVCBjZWxscyIgPSAiI0MwMDAwMCIKICAgICksCiAgICBDbHVzdGVyX1R5cGUgPSBjKAogICAgICAiTUhDLUlJIEhpZ2giICAgICAgPSAiIzY2Q0RBQSIsCiAgICAgICJOSy1saWtlIiAgICAgICAgICA9ICIjRjc4MUJGIiwKICAgICAgIlRoMi1saWtlIiAgICAgICAgID0gIiM5ODRFQTMiLAogICAgICAiTmFpdmUvVENNIiAgICAgICAgPSAiIzREQUY0QSIsCiAgICAgICJJbmZsYW1tYXRvcnkiICAgICA9ICIjOEEyQkUyIiwKICAgICAgIlN0ZW0tbGlrZSIgICAgICAgID0gIiNGRjE0OTMiLAogICAgICAiVGgyIEFjdGl2YXRlZCIgICAgPSAiI0RBNzBENiIsCiAgICAgICJDeWNsaW5nIiAgICAgICAgICA9ICIjMUU5MEZGIiwKICAgICAgIkdseWNvbHl0aWMiICAgICAgID0gIiNBNjU2MjgiLAogICAgICAiQ3l0b3RveGljIiAgICAgICAgPSAiI0U0MUExQyIsCiAgICAgICJDZW50cmFsIE1lbW9yeSIgICA9ICIjMzJDRDMyIiwKICAgICAgIlByby1pbmZsYW1tYXRvcnkiID0gIiNGRjQ1MDAiLAogICAgICAiR1pNQi1oaWdoIiAgICAgICAgPSAiI0IyMjIyMiIsCiAgICAgICJJRk4gU3RpbXVsYXRlZCIgICA9ICIjMDBDRUQxIgogICAgKQogICksCiAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAibGVmdCIsCiAgYW5ub3RhdGlvbl9uYW1lX2dwICAgPSBncGFyKGZvbnRzaXplICA9IDgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiksCiAgc2ltcGxlX2Fubm9fc2l6ZSAgICAgPSB1bml0KDQsICJtbSIpLAogIGJvcmRlciAgICAgICAgICAgICAgID0gVFJVRQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNi4gUm93IGFubm90YXRpb24gY29sb3JzCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KZnVuY3Rpb25fY29sb3JzIDwtIGMoCiAgIk9uY29nZW5pYyIgICAgICAgICAgICAgID0gIiM4MDgwODAiLAogICMgVENSIFNpZ25hbGluZyBUcmlhZCDigJQgcmVsYXRlZCBidXQgZGlzdGluY3QKICAiQVAtMSBTaWduYWxpbmciICAgICAgICAgPSAiI0ZGOEMwMCIsCiAgIk5GQVQgU2lnbmFsaW5nIiAgICAgICAgID0gIiNGRjQ1MDAiLAogICJORi1cdTAzYmFCIFNpZ25hbGluZyIgID0gIiNFMzFBMUMiLAogICJTdHJlc3MgUmVzcG9uc2UiICAgICAgICA9ICIjRkZENzAwIiwKICAiVGgyIC8gSkFLLVNUQVQgQ29yZSIgICA9ICIjOTg0RUEzIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiICAgPSAiI0ZGMTQ5MyIsCiAgIlByb2xpZmVyYXRpb24iICAgICAgICAgID0gIiMxRTkwRkYiLAogICJUZXJtaW5hbCBFZmZlY3RvciIgICAgICA9ICIjODAwMDgwIiwKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiICAgPSAiI0Y3ODFCRiIsCiAgIkFudGlnZW4gUHJlc2VudGF0aW9uIiAgID0gIiM2NkNEQUEiLAogICJNaWdyYXRpb24gLyBBZGhlc2lvbiIgICA9ICIjOEEyQkUyIiwKICAiSUZOIFJlc3BvbnNlIiAgICAgICAgICAgPSAiIzAwQ0VEMSIsCiAgIk1ldGFib2xpc20iICAgICAgICAgICAgID0gIiNBNjU2MjgiLAogICJUdW1vciBTdXBwcmVzc29yIiAgICAgICA9ICIjMzc3RUI4IiwKICAiTm9ybWFsIEhvbWVvc3Rhc2lzIiAgICAgPSAiIzREQUY0QSIKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDcuIFJvdyBhbm5vdGF0aW9uIChsZWZ0KQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmhhX3JvdyA8LSByb3dBbm5vdGF0aW9uKAogIENvbmRpdGlvbiA9IHRmX21ldGFfZmlsdGVyZWQkQ29uZGl0aW9uLAogIEZ1bmN0aW9uICA9IHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24sCiAgY29sID0gbGlzdCgKICAgIENvbmRpdGlvbiA9IGMoCiAgICAgICJOb3JtYWwiICAgID0gIiM0REFGNEEiLAogICAgICAiTWFsaWduYW50IiA9ICIjQzAwMDAwIgogICAgKSwKICAgIEZ1bmN0aW9uID0gZnVuY3Rpb25fY29sb3JzCiAgKSwKICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJib3R0b20iLAogIGFubm90YXRpb25fbmFtZV9ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSA4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIpLAogIHNpbXBsZV9hbm5vX3NpemUgICAgID0gdW5pdCg1LCAibW0iKSwKICBib3JkZXIgICAgICAgICAgICAgICA9IFRSVUUsCiAgZ2FwICAgICAgICAgICAgICAgICAgPSB1bml0KDEsICJtbSIpCikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA4LiBIZWF0bWFwIGNvbG9yIHNjYWxlIOKAlCA1IHBvaW50IGdyYWRpZW50CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY29sX2Z1biA8LSBjaXJjbGl6ZTo6Y29sb3JSYW1wMigKICBjKC0zLCAtMS41LCAwLCAxLjUsIDMpLAogIGMoIiMyMTY2QUMiLCAgICMgRGVlcCBibHVlCiAgICAiIzkyQzVERSIsICAgIyBMaWdodCBibHVlCiAgICAiI0Y3RjdGNyIsICAgIyBPZmYtd2hpdGUKICAgICIjRjRBNTgyIiwgICAjIExpZ2h0IHJlZAogICAgIiNCMjE4MkIiKSAgICMgRGVlcCByZWQKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDkuIEJ1aWxkIGhlYXRtYXAKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpodCA8LSBIZWF0bWFwKAogIGF2Z19tYXRfeiwKICBuYW1lID0gIlRGIGFjdGl2aXR5XG4oei1zY29yZSkiLAogIGNvbCAgPSBjb2xfZnVuLAoKICAjIEFubm90YXRpb25zCiAgdG9wX2Fubm90YXRpb24gID0gaGFfY29sLAogIGxlZnRfYW5ub3RhdGlvbiA9IGhhX3JvdywKCiAgIyBTcGxpdHRpbmcKICBjb2x1bW5fc3BsaXQgPSBjbHVzdGVyX3N0YXR1cywKICByb3dfc3BsaXQgICAgPSB0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uLAoKICAjIENsdXN0ZXJpbmcKICBjbHVzdGVyX3Jvd19zbGljZXMgPSBGQUxTRSwKICBjbHVzdGVyX3Jvd3MgICAgICAgPSBGQUxTRSwKICBjbHVzdGVyX2NvbHVtbnMgICAgPSBUUlVFLAogIHNob3dfcm93X2RlbmQgICAgICA9IEZBTFNFLAogIHNob3dfY29sdW1uX2RlbmQgICA9IFRSVUUsCiAgY29sdW1uX2RlbmRfaGVpZ2h0ID0gdW5pdCgxNSwgIm1tIiksCgogICMgQ2VsbCBhcHBlYXJhbmNlCiAgcmVjdF9ncCA9IGdwYXIoY29sID0gIndoaXRlIiwgbHdkID0gMC44KSwKCiAgIyBSb3cgbmFtZXMKICByb3dfbmFtZXNfZ3AgICA9IGdwYXIoZm9udHNpemUgID0gOC41LAogICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gIml0YWxpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sICAgICAgPSAiZ3JleTIwIiksCiAgcm93X25hbWVzX3NpZGUgPSAicmlnaHQiLAoKICAjIENvbHVtbiBuYW1lcwogIGNvbHVtbl9uYW1lc19ncCAgPSBncGFyKGZvbnRzaXplICA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJncmV5MTAiKSwKICBjb2x1bW5fbmFtZXNfcm90ID0gMCwKCiAgIyBSb3cgdGl0bGUgKGZ1bmN0aW9uYWwgYmxvY2sgbGFiZWxzIG9uIGxlZnQpCiAgcm93X3RpdGxlX3JvdCAgPSAwLAogIHJvd190aXRsZV9ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSA4LAogICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImdyZXkxMCIpLAogIHJvd190aXRsZV9zaWRlID0gImxlZnQiLAoKICAjIEdhcHMgYmV0d2VlbiBibG9ja3MKICByb3dfZ2FwICAgID0gdW5pdCgyLjUsICJtbSIpLAogIGNvbHVtbl9nYXAgPSB1bml0KDQsICAgIm1tIiksCgogICMgTWFpbiB0aXRsZQogIGNvbHVtbl90aXRsZSAgICA9ICJGdW5jdGlvbmFsIFRGIE1vZHVsZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIsCiAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSAgPSAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImdyZXk1IiksCgogICMgTGVnZW5kCiAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KAogICAgZGlyZWN0aW9uICAgICA9ICJ2ZXJ0aWNhbCIsCiAgICB0aXRsZSAgICAgICAgID0gIlRGIGFjdGl2aXR5XG4oei1zY29yZSkiLAogICAgdGl0bGVfZ3AgICAgICA9IGdwYXIoZm9udHNpemUgID0gOSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIpLAogICAgbGFiZWxzX2dwICAgICA9IGdwYXIoZm9udHNpemUgID0gOCksCiAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCg0LCAiY20iKSwKICAgIGJvcmRlciAgICAgICAgPSAiZ3JleTUwIiwKICAgIGF0ICAgICAgICAgICAgPSBjKC0zLCAtMS41LCAwLCAxLjUsIDMpLAogICAgbGFiZWxzICAgICAgICA9IGMoIi0zIiwgIi0xLjUiLCAiMCIsICIxLjUiLCAiMyIpCiAgKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMTAuIFNhdmUKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFBERiDigJQgdmVjdG9yIHF1YWxpdHkgZm9yIHB1YmxpY2F0aW9uCnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfRmluYWwucGRmIiwKICAgIHdpZHRoICAgICAgID0gMTYsCiAgICBoZWlnaHQgICAgICA9IDE1LAogICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKZHJhdyhodCwKICAgICBtZXJnZV9sZWdlbmQgICAgICAgICAgID0gVFJVRSwKICAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlICAgID0gInJpZ2h0IiwKICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gInJpZ2h0IiwKICAgICBwYWRkaW5nID0gdW5pdChjKDUsIDUsIDUsIDUpLCAibW0iKSkKZGV2Lm9mZigpCgojIFBORyDigJQgaGlnaCByZXNvbHV0aW9uIGZvciBwcmVzZW50YXRpb25zCnBuZygiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfRmluYWwucG5nIiwKICAgIHdpZHRoICA9IDE2ICogMzAwLAogICAgaGVpZ2h0ID0gMTUgKiAzMDAsCiAgICByZXMgICAgPSAzMDApCmRyYXcoaHQsCiAgICAgbWVyZ2VfbGVnZW5kICAgICAgICAgICA9IFRSVUUsCiAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSAgICA9ICJyaWdodCIsCiAgICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJyaWdodCIsCiAgICAgcGFkZGluZyA9IHVuaXQoYyg1LCA1LCA1LCA1KSwgIm1tIikpCmRldi5vZmYoKQoKIyBEcmF3IGluIG5vdGVib29rCmRyYXcoaHQsCiAgICAgbWVyZ2VfbGVnZW5kICAgICAgICAgICA9IFRSVUUsCiAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSAgICA9ICJyaWdodCIsCiAgICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJyaWdodCIsCiAgICAgcGFkZGluZyA9IHVuaXQoYyg1LCA1LCA1LCA1KSwgIm1tIikpCmBgYAojIFRlc3QyCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIExJQlJBUklFUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDEuIERlZmluZSBURiBwYW5lbCBtZXRhZGF0YQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAjIC0tLSAxLiBHZW5lcmFsIE1hbGlnbmFuY3kgLS0tCiAgICAiTVlDIiwiRTJGNCIsIlRXSVNUMSIsIklSRjQiLAoKICAgICMgLS0tIDIuIFRDUiBTaWduYWxpbmcgVHJpYWQgLS0tCiAgICAiSlVOQiIsIkZPUyIsIkZPU0wxIiwgICAgICAgICAgICAgICAgIyBBUC0xCiAgICAiTkZBVEMxIiwiTkZBVEMyIiwgICAgICAgICAgICAgICAgICAgIyBORkFUCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwgIyBORi1rQgoKICAgICMgLS0tIDMuIFN0cmVzcyBSZXNwb25zZSAtLS0KICAgICJIU0YxIiwiTkZFMkwyIiwiU1JFQkYyIiwKCiAgICAjIC0tLSA0LiBUaDIgLyBKQUstU1RBVCBDb3JlIC0tLQogICAgIkdBVEEzIiwiU1RBVDYiLCJCQVRGIiwiRk9YUDMiLCJTVEFUMyIsIlNUQVQ1QiIsCgogICAgIyAtLS0gNS4gRGlmZmVyZW50aWF0aW9uIEhpZXJhcmNoeSAtLS0KICAgICJUQ0Y3IiwiTEVGMSIsIk1ZQiIsICAgICAgICAgICAgICAgICAjIFN0ZW0tbGlrZQogICAgIkUyRjEiLCJGT1hNMSIsICAgICAgICAgICAgICAgICAgICAgICMgUHJvbGlmZXJhdGlvbgogICAgIlBSRE0xIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGVybWluYWwgRWZmZWN0b3IKCiAgICAjIC0tLSA2LiBLRUdHIEFsaWduZWQgLS0tCiAgICAiRU9NRVMiLCJUQlgyMSIsIlJVTlgzIiwgICAgICAgICAgICAgIyBOSy1saWtlIEN5dG90b3hpY2l0eQogICAgIlJGWDUiLCJDUkVCMSIsICAgICAgICAgICAgICAgICAgICAgICMgQW50aWdlbiBQcmVzZW50YXRpb24KICAgICJLTEY0IiwiRVRTMSIsIlNNQUQzIiwgICAgICAgICAgICAgICMgTWlncmF0aW9uIC8gQWRoZXNpb24KCiAgICAjIC0tLSA3LiBNaWNyb2Vudmlyb25tZW50IC0tLQogICAgIlNUQVQxIiwiU1RBVDIiLCJJUkY5IiwgICAgICAgICAgICAgICMgSUZOIFJlc3BvbnNlCiAgICAiSElGMUEiLCJTUkVCRjEiLCAgICAgICAgICAgICAgICAgICAgIyBNZXRhYm9saXNtCgogICAgIyAtLS0gOC4gVHVtb3IgU3VwcHJlc3NvcnMgLyBOb3JtYWwgLS0tCiAgICAiRk9YTzEiLCJGT1hPNCIsIlpFQjEiLCJCQUNIMiIsCiAgICAiVENGMyIsIkJDTDExQSIsIk5FVVJPRDEiLCJNRUYyQiIsIlBCWDIiLCJJUkYzIiwiQkNMNiIKICApLAogIENvbmRpdGlvbiA9IGMoCiAgICByZXAoIk1hbGlnbmFudCIsIDQpLCAgICMgT25jb2dlbmljCiAgICByZXAoIk1hbGlnbmFudCIsIDMpLCAgICMgQVAtMQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIE5GQVQKICAgIHJlcCgiTWFsaWduYW50IiwgNSksICAgIyBORi1rQgogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIFN0cmVzcyBSZXNwb25zZQogICAgcmVwKCJNYWxpZ25hbnQiLCA2KSwgICAjIFRoMi9KQUstU1RBVAogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIFN0ZW0tbGlrZQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIFByb2xpZmVyYXRpb24KICAgIHJlcCgiTWFsaWduYW50IiwgMSksICAgIyBUZXJtaW5hbCBFZmZlY3RvcgogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIE5LLWxpa2UKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBBbnRpZ2VuIFByZXNlbnRhdGlvbgogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIE1pZ3JhdGlvbgogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIElGTiBSZXNwb25zZQogICAgcmVwKCJNYWxpZ25hbnQiLCAyKSwgICAjIE1ldGFib2xpc20KICAgIHJlcCgiTm9ybWFsIiwgNCksICAgICAgIyBUdW1vciBTdXBwcmVzc29yCiAgICByZXAoIk5vcm1hbCIsIDcpICAgICAgICMgTm9ybWFsIEhvbWVvc3Rhc2lzCiAgKSwKICBGdW5jdGlvbiA9IGMoCiAgICByZXAoIk9uY29nZW5pYyIsIDQpLAogICAgcmVwKCJBUC0xIFNpZ25hbGluZyIsIDMpLAogICAgcmVwKCJORkFUIFNpZ25hbGluZyIsIDIpLAogICAgcmVwKCJORi1cdTAzYmFCIFNpZ25hbGluZyIsIDUpLAogICAgcmVwKCJTdHJlc3MgUmVzcG9uc2UiLCAzKSwKICAgIHJlcCgiVGgyIC8gSkFLLVNUQVQgQ29yZSIsIDYpLAogICAgcmVwKCJTdGVtLWxpa2UgUHJvZ2VuaXRvciIsIDMpLAogICAgcmVwKCJQcm9saWZlcmF0aW9uIiwgMiksCiAgICByZXAoIlRlcm1pbmFsIEVmZmVjdG9yIiwgMSksCiAgICByZXAoIk5LLWxpa2UgQ3l0b3RveGljaXR5IiwgMyksCiAgICByZXAoIkFudGlnZW4gUHJlc2VudGF0aW9uIiwgMiksCiAgICByZXAoIk1pZ3JhdGlvbiAvIEFkaGVzaW9uIiwgMyksCiAgICByZXAoIklGTiBSZXNwb25zZSIsIDMpLAogICAgcmVwKCJNZXRhYm9saXNtIiwgMiksCiAgICByZXAoIlR1bW9yIFN1cHByZXNzb3IiLCA0KSwKICAgIHJlcCgiTm9ybWFsIEhvbWVvc3Rhc2lzIiwgNykKICApLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgojIExvY2sgaW4gb3JkZXIKZGVzaXJlZF9vcmRlciA8LSBjKAogICJPbmNvZ2VuaWMiLAogICJBUC0xIFNpZ25hbGluZyIsCiAgIk5GQVQgU2lnbmFsaW5nIiwKICAiTkYtXHUwM2JhQiBTaWduYWxpbmciLAogICJTdHJlc3MgUmVzcG9uc2UiLAogICJUaDIgLyBKQUstU1RBVCBDb3JlIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiLAogICJQcm9saWZlcmF0aW9uIiwKICAiVGVybWluYWwgRWZmZWN0b3IiLAogICJOSy1saWtlIEN5dG90b3hpY2l0eSIsCiAgIkFudGlnZW4gUHJlc2VudGF0aW9uIiwKICAiTWlncmF0aW9uIC8gQWRoZXNpb24iLAogICJJRk4gUmVzcG9uc2UiLAogICJNZXRhYm9saXNtIiwKICAiVHVtb3IgU3VwcHJlc3NvciIsCiAgIk5vcm1hbCBIb21lb3N0YXNpcyIKKQoKdGZfbWV0YSRGdW5jdGlvbiA8LSBmYWN0b3IodGZfbWV0YSRGdW5jdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGRlc2lyZWRfb3JkZXIpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMi4gRXh0cmFjdCBURiBhY3Rpdml0eSBtYXRyaXggZnJvbSBTZXVyYXQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQptYXRfc2NhbGVkIDwtIHRyeUNhdGNoKAogIFNldXJhdE9iamVjdDo6R2V0QXNzYXlEYXRhKHNldXJhdF9vYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiZG9yb3RoZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gInNjYWxlLmRhdGEiKSwKICBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwKKQptYXRfZGF0YSA8LSBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJkb3JvdGhlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gImRhdGEiKQptYXRfdXNlIDwtIGlmICghaXMubnVsbChtYXRfc2NhbGVkKSAmJgogICAgICAgICAgICAgICBucm93KG1hdF9zY2FsZWQpID4gMCkgbWF0X3NjYWxlZCBlbHNlIG1hdF9kYXRhCgojIEZpbHRlciBmb3IgVEZzIHByZXNlbnQgaW4gU2V1cmF0CmF2YWlsYWJsZV90ZnMgPC0gaW50ZXJzZWN0KHRmX21ldGEkVEYsIHJvd25hbWVzKG1hdF91c2UpKQptYXRfdXNlICAgICAgIDwtIG1hdF91c2VbYXZhaWxhYmxlX3RmcywgLCBkcm9wID0gRkFMU0VdCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMy4gQXZlcmFnZSBwZXIgY2x1c3RlciAmIHotc2NvcmUKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbHVzdGVycyA8LSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRzZXVyYXRfY2x1c3RlcnMpCmF2Z19tYXQgIDwtIHNhcHBseShsZXZlbHMoY2x1c3RlcnMpLCBmdW5jdGlvbihjbCkgewogIE1hdHJpeDo6cm93TWVhbnMobWF0X3VzZVssIGNsdXN0ZXJzID09IGNsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcCA9IEZBTFNFXSkKfSkKY29sbmFtZXMoYXZnX21hdCkgPC0gbGV2ZWxzKGNsdXN0ZXJzKQoKYXZnX21hdF96ICAgICAgICAgICAgICAgPC0gdChzY2FsZSh0KGF2Z19tYXQpKSkKYXZnX21hdF96W2lzLm5hKGF2Z19tYXRfeildIDwtIDAKCiMgQWxpZ24gdGZfbWV0YSBvcmRlciB0byBtYXRjaCBtYXRfdXNlIHByZWNpc2VseQpyb3dfb3JkZXJfaWR4ICAgIDwtIG1hdGNoKHJvd25hbWVzKGF2Z19tYXRfeiksIHRmX21ldGEkVEYpCnRmX21ldGFfZmlsdGVyZWQgPC0gdGZfbWV0YVtyb3dfb3JkZXJfaWR4LCBdCmF2Z19tYXRfeiAgICAgICAgPC0gYXZnX21hdF96W29yZGVyKHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24pLCBdCnRmX21ldGFfZmlsdGVyZWQgPC0gdGZfbWV0YV9maWx0ZXJlZFtvcmRlcih0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uKSwgXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDQuIENsdXN0ZXIgc3RhdHVzICYgYmlvbG9naWNhbCBsYWJlbHMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjbHVzdGVyX3N0YXR1cyA8LSBpZmVsc2UoCiAgY29sbmFtZXMoYXZnX21hdF96KSAlaW4lIGMoIjMiLCAiMTAiKSwKICAiTm9ybWFsIENENCBUIGNlbGxzIiwKICAiTWFsaWduYW50IENENCBUIGNlbGxzIgopCgpjbHVzdGVyX2xhYmVscyA8LSBjKAogICIwIiAgPSAiTUhDLUlJIEhpZ2giLAogICIxIiAgPSAiTkstbGlrZSIsCiAgIjIiICA9ICJUaDItbGlrZSIsCiAgIjMiICA9ICJOYWl2ZS9UQ00iLAogICI0IiAgPSAiSW5mbGFtbWF0b3J5IiwKICAiNSIgID0gIlN0ZW0tbGlrZSIsCiAgIjYiICA9ICJUaDIgQWN0aXZhdGVkIiwKICAiNyIgID0gIkN5Y2xpbmciLAogICI4IiAgPSAiR2x5Y29seXRpYyIsCiAgIjkiICA9ICJDeXRvdG94aWMiLAogICIxMCIgPSAiQ2VudHJhbCBNZW1vcnkiLAogICIxMSIgPSAiUHJvLWluZmxhbW1hdG9yeSIsCiAgIjEyIiA9ICJHWk1CLWhpZ2giLAogICIxMyIgPSAiSUZOIFN0aW11bGF0ZWQiCikKY2x1c3Rlcl9hbm5vdGF0aW9uIDwtIGNsdXN0ZXJfbGFiZWxzW2NvbG5hbWVzKGF2Z19tYXRfeildCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNS4gQ29sdW1uIGFubm90YXRpb24gKHRvcCkKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpoYV9jb2wgPC0gSGVhdG1hcEFubm90YXRpb24oCiAgQ2VsbF9TdGF0ZSAgID0gY2x1c3Rlcl9zdGF0dXMsCiAgQ2x1c3Rlcl9UeXBlID0gY2x1c3Rlcl9hbm5vdGF0aW9uLAogIGNvbCA9IGxpc3QoCiAgICBDZWxsX1N0YXRlID0gYygKICAgICAgIk5vcm1hbCBDRDQgVCBjZWxscyIgICAgPSAiIzREQUY0QSIsCiAgICAgICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiID0gIiNDMDAwMDAiCiAgICApLAogICAgQ2x1c3Rlcl9UeXBlID0gYygKICAgICAgIk1IQy1JSSBIaWdoIiAgICAgID0gIiM2NkNEQUEiLAogICAgICAiTkstbGlrZSIgICAgICAgICAgPSAiI0Y3ODFCRiIsCiAgICAgICJUaDItbGlrZSIgICAgICAgICA9ICIjOTg0RUEzIiwKICAgICAgIk5haXZlL1RDTSIgICAgICAgID0gIiM0REFGNEEiLAogICAgICAiSW5mbGFtbWF0b3J5IiAgICAgPSAiIzhBMkJFMiIsCiAgICAgICJTdGVtLWxpa2UiICAgICAgICA9ICIjRkYxNDkzIiwKICAgICAgIlRoMiBBY3RpdmF0ZWQiICAgID0gIiNEQTcwRDYiLAogICAgICAiQ3ljbGluZyIgICAgICAgICAgPSAiIzFFOTBGRiIsCiAgICAgICJHbHljb2x5dGljIiAgICAgICA9ICIjQTY1NjI4IiwKICAgICAgIkN5dG90b3hpYyIgICAgICAgID0gIiNFNDFBMUMiLAogICAgICAiQ2VudHJhbCBNZW1vcnkiICAgPSAiIzMyQ0QzMiIsCiAgICAgICJQcm8taW5mbGFtbWF0b3J5IiA9ICIjRkY0NTAwIiwKICAgICAgIkdaTUItaGlnaCIgICAgICAgID0gIiNCMjIyMjIiLAogICAgICAiSUZOIFN0aW11bGF0ZWQiICAgPSAiIzAwQ0VEMSIKICAgICkKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImxlZnQiLAogIGFubm90YXRpb25fbmFtZV9ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAogIHNpbXBsZV9hbm5vX3NpemUgICAgID0gdW5pdCg1LCAibW0iKSwKICBib3JkZXIgICAgICAgICAgICAgICA9IFRSVUUKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDYuIFJvdyBhbm5vdGF0aW9uIGNvbG9ycwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMiICAgICAgICAgICAgID0gIiM4MDgwODAiLAogICJBUC0xIFNpZ25hbGluZyIgICAgICAgID0gIiNGRjhDMDAiLAogICJORkFUIFNpZ25hbGluZyIgICAgICAgID0gIiNGRjQ1MDAiLAogICJORi1cdTAzYmFCIFNpZ25hbGluZyIgPSAiI0UzMUExQyIsCiAgIlN0cmVzcyBSZXNwb25zZSIgICAgICAgPSAiI0ZGRDcwMCIsCiAgIlRoMiAvIEpBSy1TVEFUIENvcmUiICA9ICIjOTg0RUEzIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiICA9ICIjRkYxNDkzIiwKICAiUHJvbGlmZXJhdGlvbiIgICAgICAgICA9ICIjMUU5MEZGIiwKICAiVGVybWluYWwgRWZmZWN0b3IiICAgICA9ICIjODAwMDgwIiwKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiICA9ICIjRjc4MUJGIiwKICAiQW50aWdlbiBQcmVzZW50YXRpb24iICA9ICIjNjZDREFBIiwKICAiTWlncmF0aW9uIC8gQWRoZXNpb24iICA9ICIjOEEyQkUyIiwKICAiSUZOIFJlc3BvbnNlIiAgICAgICAgICA9ICIjMDBDRUQxIiwKICAiTWV0YWJvbGlzbSIgICAgICAgICAgICA9ICIjQTY1NjI4IiwKICAiVHVtb3IgU3VwcHJlc3NvciIgICAgICA9ICIjMzc3RUI4IiwKICAiTm9ybWFsIEhvbWVvc3Rhc2lzIiAgICA9ICIjNERBRjRBIgopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNy4gUm93IGFubm90YXRpb24gKGxlZnQpCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KaGFfcm93IDwtIHJvd0Fubm90YXRpb24oCiAgQ29uZGl0aW9uID0gdGZfbWV0YV9maWx0ZXJlZCRDb25kaXRpb24sCiAgRnVuY3Rpb24gID0gdGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiwKICBjb2wgPSBsaXN0KAogICAgQ29uZGl0aW9uID0gYygKICAgICAgIk5vcm1hbCIgICAgPSAiIzREQUY0QSIsCiAgICAgICJNYWxpZ25hbnQiID0gIiNDMDAwMDAiCiAgICApLAogICAgRnVuY3Rpb24gPSBmdW5jdGlvbl9jb2xvcnMKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIsCiAgYW5ub3RhdGlvbl9uYW1lX2dwICAgPSBncGFyKGZvbnRzaXplICA9IDksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgc2ltcGxlX2Fubm9fc2l6ZSAgICAgPSB1bml0KDUsICJtbSIpLAogIGJvcmRlciAgICAgICAgICAgICAgID0gVFJVRSwKICBnYXAgICAgICAgICAgICAgICAgICA9IHVuaXQoMSwgIm1tIikKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDguIEhlYXRtYXAgY29sb3Igc2NhbGUg4oCUIDUgcG9pbnQgZ3JhZGllbnQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKAogIGMoLTMsIC0xLjUsIDAsIDEuNSwgMyksCiAgYygiIzIxNjZBQyIsICAgIyBEZWVwIGJsdWUKICAgICIjOTJDNURFIiwgICAjIExpZ2h0IGJsdWUKICAgICIjRjdGN0Y3IiwgICAjIE9mZi13aGl0ZQogICAgIiNGNEE1ODIiLCAgICMgTGlnaHQgcmVkCiAgICAiI0IyMTgyQiIpICAgIyBEZWVwIHJlZAopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgOS4gQnVpbGQgaGVhdG1hcAojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Cmh0IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LAogIG5hbWUgPSAiVEYgYWN0aXZpdHlcbih6LXNjb3JlKSIsCiAgY29sICA9IGNvbF9mdW4sCgogICMgQW5ub3RhdGlvbnMKICB0b3BfYW5ub3RhdGlvbiAgPSBoYV9jb2wsCiAgbGVmdF9hbm5vdGF0aW9uID0gaGFfcm93LAoKICAjIFNwbGl0dGluZwogIGNvbHVtbl9zcGxpdCA9IGNsdXN0ZXJfc3RhdHVzLAogIHJvd19zcGxpdCAgICA9IHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24sCgogICMgQ2x1c3RlcmluZwogIGNsdXN0ZXJfcm93X3NsaWNlcyA9IEZBTFNFLAogIGNsdXN0ZXJfcm93cyAgICAgICA9IEZBTFNFLAogIGNsdXN0ZXJfY29sdW1ucyAgICA9IFRSVUUsCiAgc2hvd19yb3dfZGVuZCAgICAgID0gRkFMU0UsCiAgc2hvd19jb2x1bW5fZGVuZCAgID0gVFJVRSwKICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDE1LCAibW0iKSwKCiAgIyBDZWxsIGFwcGVhcmFuY2UKICByZWN0X2dwID0gZ3Bhcihjb2wgPSAid2hpdGUiLCBsd2QgPSAwLjgpLAoKICAjIFJvdyBuYW1lcyDigJQgQk9MRCBhbmQgbGFyZ2VyIGZvciBzbGlkZSB2aXNpYmlsaXR5CiAgcm93X25hbWVzX2dwICAgPSBncGFyKGZvbnRzaXplICA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgcm93X25hbWVzX3NpZGUgPSAicmlnaHQiLAoKICAjIENvbHVtbiBuYW1lcyDigJQgQk9MRCBhbmQgbGFyZ2VyCiAgY29sdW1uX25hbWVzX2dwICA9IGdwYXIoZm9udHNpemUgID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgY29sdW1uX25hbWVzX3JvdCA9IDAsCgogICMgUm93IHRpdGxlIOKAlCBmdW5jdGlvbmFsIGJsb2NrIGxhYmVscwogIHJvd190aXRsZV9yb3QgID0gMCwKICByb3dfdGl0bGVfZ3AgICA9IGdwYXIoZm9udHNpemUgID0gMTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sICAgICAgPSAiYmxhY2siKSwKICByb3dfdGl0bGVfc2lkZSA9ICJsZWZ0IiwKCiAgIyBHYXBzIGJldHdlZW4gYmxvY2tzCiAgcm93X2dhcCAgICA9IHVuaXQoMi41LCAibW0iKSwKICBjb2x1bW5fZ2FwID0gdW5pdCg0LCAgICJtbSIpLAoKICAjIE1haW4gdGl0bGUKICBjb2x1bW5fdGl0bGUgICAgPSAiRnVuY3Rpb25hbCBURiBNb2R1bGVzIGluIFPDqXphcnkgU3luZHJvbWUiLAogIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgID0gMTQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAoKICAjIExlZ2VuZAogIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCgKICAgIGRpcmVjdGlvbiAgICAgPSAidmVydGljYWwiLAogICAgdGl0bGUgICAgICAgICA9ICJURiBhY3Rpdml0eVxuKHotc2NvcmUpIiwKICAgIHRpdGxlX2dwICAgICAgPSBncGFyKGZvbnRzaXplICA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sICAgICAgPSAiYmxhY2siKSwKICAgIGxhYmVsc19ncCAgICAgPSBncGFyKGZvbnRzaXplICA9IDksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgICBsZWdlbmRfaGVpZ2h0ID0gdW5pdCg0LCAiY20iKSwKICAgIGJvcmRlciAgICAgICAgPSAiZ3JleTUwIiwKICAgIGF0ICAgICAgICAgICAgPSBjKC0zLCAtMS41LCAwLCAxLjUsIDMpLAogICAgbGFiZWxzICAgICAgICA9IGMoIi0zIiwgIi0xLjUiLCAiMCIsICIxLjUiLCAiMyIpCiAgKQopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgMTAuIFNhdmUKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFBERiDigJQgdmVjdG9yIHF1YWxpdHkgZm9yIHB1YmxpY2F0aW9uCnBkZigiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfRmluYWwucGRmIiwKICAgIHdpZHRoICAgICAgID0gMTgsCiAgICBoZWlnaHQgICAgICA9IDE2LAogICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKZHJhdyhodCwKICAgICBtZXJnZV9sZWdlbmQgICAgICAgICAgID0gVFJVRSwKICAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlICAgID0gInJpZ2h0IiwKICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gInJpZ2h0IiwKICAgICBwYWRkaW5nID0gdW5pdChjKDUsIDUsIDUsIDUpLCAibW0iKSkKZGV2Lm9mZigpCgojIFBORyDigJQgaGlnaCByZXNvbHV0aW9uIGZvciBwcmVzZW50YXRpb25zCnBuZygiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfRmluYWwucG5nIiwKICAgIHdpZHRoICA9IDE4ICogMzAwLAogICAgaGVpZ2h0ID0gMTYgKiAzMDAsCiAgICByZXMgICAgPSAzMDApCmRyYXcoaHQsCiAgICAgbWVyZ2VfbGVnZW5kICAgICAgICAgICA9IFRSVUUsCiAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSAgICA9ICJyaWdodCIsCiAgICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJyaWdodCIsCiAgICAgcGFkZGluZyA9IHVuaXQoYyg1LCA1LCA1LCA1KSwgIm1tIikpCmRldi5vZmYoKQoKIyBEcmF3IGluIG5vdGVib29rCmRyYXcoaHQsCiAgICAgbWVyZ2VfbGVnZW5kICAgICAgICAgICA9IFRSVUUsCiAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSAgICA9ICJyaWdodCIsCiAgICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJyaWdodCIsCiAgICAgcGFkZGluZyA9IHVuaXQoYyg1LCA1LCA1LCA1KSwgIm1tIikpCgoKCmBgYAoKIyBUZXN0MwpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIExJQlJBUklFUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDEuIERlZmluZSBURiBwYW5lbCBtZXRhZGF0YQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnRmX21ldGEgPC0gZGF0YS5mcmFtZSgKICBURiA9IGMoCiAgICAjIC0tLSAxLiBHZW5lcmFsIE1hbGlnbmFuY3kgLS0tCiAgICAiTVlDIiwiRTJGNCIsIlRXSVNUMSIsIklSRjQiLAoKICAgICMgLS0tIDIuIFRDUiBTaWduYWxpbmcgVHJpYWQgLS0tCiAgICAiSlVOQiIsIkZPUyIsIkZPU0wxIiwgICAgICAgICAgICAgICAgIyBBUC0xCiAgICAiTkZBVEMxIiwiTkZBVEMyIiwgICAgICAgICAgICAgICAgICAgIyBORkFUCiAgICAiUkVMQSIsIlJFTCIsIk5GS0IxIiwiSVJGMSIsIk5DT0EyIiwgIyBORi1rQgoKICAgICMgLS0tIDMuIFN0cmVzcyBSZXNwb25zZSAtLS0KICAgICJIU0YxIiwiTkZFMkwyIiwiU1JFQkYyIiwKCiAgICAjIC0tLSA0LiBUaDIgLyBKQUstU1RBVCBDb3JlIC0tLQogICAgIkdBVEEzIiwiU1RBVDYiLCJCQVRGIiwiRk9YUDMiLCJTVEFUMyIsIlNUQVQ1QiIsCgogICAgIyAtLS0gNS4gRGlmZmVyZW50aWF0aW9uIEhpZXJhcmNoeSAtLS0KICAgICJUQ0Y3IiwiTEVGMSIsIk1ZQiIsICAgICAgICAgICAgICAgICAjIFN0ZW0tbGlrZQogICAgIkUyRjEiLCJGT1hNMSIsICAgICAgICAgICAgICAgICAgICAgICMgUHJvbGlmZXJhdGlvbgogICAgIlBSRE0xIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGVybWluYWwgRWZmZWN0b3IKCiAgICAjIC0tLSA2LiBLRUdHIEFsaWduZWQgLS0tCiAgICAiRU9NRVMiLCJUQlgyMSIsIlJVTlgzIiwgICAgICAgICAgICAgIyBOSy1saWtlIEN5dG90b3hpY2l0eQogICAgIlJGWDUiLCJDUkVCMSIsICAgICAgICAgICAgICAgICAgICAgICMgQW50aWdlbiBQcmVzZW50YXRpb24KICAgICJLTEY0IiwiRVRTMSIsIlNNQUQzIiwgICAgICAgICAgICAgICAjIE1pZ3JhdGlvbiAvIEFkaGVzaW9uCgogICAgIyAtLS0gNy4gTWljcm9lbnZpcm9ubWVudCAtLS0KICAgICJTVEFUMSIsIlNUQVQyIiwiSVJGOSIsICAgICAgICAgICAgICAjIElGTiBSZXNwb25zZQogICAgIkhJRjFBIiwiU1JFQkYxIiwgICAgICAgICAgICAgICAgICAgICMgTWV0YWJvbGlzbQoKICAgICMgLS0tIDguIFR1bW9yIFN1cHByZXNzb3JzIC8gTm9ybWFsIC0tLQogICAgIkZPWE8xIiwiRk9YTzQiLCJaRUIxIiwiQkFDSDIiLAogICAgIlRDRjMiLCJCQ0wxMUEiLCJORVVST0QxIiwiTUVGMkIiLCJQQlgyIiwiSVJGMyIsIkJDTDYiCiAgKSwKICBDb25kaXRpb24gPSBjKAogICAgcmVwKCJNYWxpZ25hbnQiLCA0KSwgICAjIE9uY29nZW5pYwogICAgcmVwKCJNYWxpZ25hbnQiLCAzKSwgICAjIEFQLTEKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBORkFUCiAgICByZXAoIk1hbGlnbmFudCIsIDUpLCAgICMgTkYta0IKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBTdHJlc3MgUmVzcG9uc2UKICAgIHJlcCgiTWFsaWduYW50IiwgNiksICAgIyBUaDIvSkFLLVNUQVQKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBTdGVtLWxpa2UKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBQcm9saWZlcmF0aW9uCiAgICByZXAoIk1hbGlnbmFudCIsIDEpLCAgICMgVGVybWluYWwgRWZmZWN0b3IKICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBOSy1saWtlCiAgICByZXAoIk1hbGlnbmFudCIsIDIpLCAgICMgQW50aWdlbiBQcmVzZW50YXRpb24KICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBNaWdyYXRpb24KICAgIHJlcCgiTWFsaWduYW50IiwgMyksICAgIyBJRk4gUmVzcG9uc2UKICAgIHJlcCgiTWFsaWduYW50IiwgMiksICAgIyBNZXRhYm9saXNtCiAgICByZXAoIk5vcm1hbCIsIDQpLCAgICAgICMgVHVtb3IgU3VwcHJlc3NvcgogICAgcmVwKCJOb3JtYWwiLCA3KSAgICAgICAjIE5vcm1hbCBIb21lb3N0YXNpcwogICksCiAgRnVuY3Rpb24gPSBjKAogICAgcmVwKCJPbmNvZ2VuaWMiLCA0KSwKICAgIHJlcCgiQVAtMSBTaWduYWxpbmciLCAzKSwKICAgIHJlcCgiTkZBVCBTaWduYWxpbmciLCAyKSwKICAgIHJlcCgiTkYtXHUwM2JhQiBTaWduYWxpbmciLCA1KSwKICAgIHJlcCgiU3RyZXNzIFJlc3BvbnNlIiwgMyksCiAgICByZXAoIlRoMiAvIEpBSy1TVEFUIENvcmUiLCA2KSwKICAgIHJlcCgiU3RlbS1saWtlIFByb2dlbml0b3IiLCAzKSwKICAgIHJlcCgiUHJvbGlmZXJhdGlvbiIsIDIpLAogICAgcmVwKCJUZXJtaW5hbCBFZmZlY3RvciIsIDEpLAogICAgcmVwKCJOSy1saWtlIEN5dG90b3hpY2l0eSIsIDMpLAogICAgcmVwKCJBbnRpZ2VuIFByZXNlbnRhdGlvbiIsIDIpLAogICAgcmVwKCJNaWdyYXRpb24gLyBBZGhlc2lvbiIsIDMpLAogICAgcmVwKCJJRk4gUmVzcG9uc2UiLCAzKSwKICAgIHJlcCgiTWV0YWJvbGlzbSIsIDIpLAogICAgcmVwKCJUdW1vciBTdXBwcmVzc29yIiwgNCksCiAgICByZXAoIk5vcm1hbCBIb21lb3N0YXNpcyIsIDcpCiAgKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKIyBMb2NrIGluIG9yZGVyCmRlc2lyZWRfb3JkZXIgPC0gYygKICAiT25jb2dlbmljIiwKICAiQVAtMSBTaWduYWxpbmciLAogICJORkFUIFNpZ25hbGluZyIsCiAgIk5GLVx1MDNiYUIgU2lnbmFsaW5nIiwKICAiU3RyZXNzIFJlc3BvbnNlIiwKICAiVGgyIC8gSkFLLVNUQVQgQ29yZSIsCiAgIlN0ZW0tbGlrZSBQcm9nZW5pdG9yIiwKICAiUHJvbGlmZXJhdGlvbiIsCiAgIlRlcm1pbmFsIEVmZmVjdG9yIiwKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiLAogICJBbnRpZ2VuIFByZXNlbnRhdGlvbiIsCiAgIk1pZ3JhdGlvbiAvIEFkaGVzaW9uIiwKICAiSUZOIFJlc3BvbnNlIiwKICAiTWV0YWJvbGlzbSIsCiAgIlR1bW9yIFN1cHByZXNzb3IiLAogICJOb3JtYWwgSG9tZW9zdGFzaXMiCikKCnRmX21ldGEkRnVuY3Rpb24gPC0gZmFjdG9yKHRmX21ldGEkRnVuY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBkZXNpcmVkX29yZGVyKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDIuIEV4dHJhY3QgVEYgYWN0aXZpdHkgbWF0cml4IGZyb20gU2V1cmF0CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KbWF0X3NjYWxlZCA8LSB0cnlDYXRjaCgKICBTZXVyYXRPYmplY3Q6OkdldEFzc2F5RGF0YShzZXVyYXRfb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gImRvcm90aGVhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXllciA9ICJzY2FsZS5kYXRhIiksCiAgZXJyb3IgPSBmdW5jdGlvbihlKSBOVUxMCikKbWF0X2RhdGEgPC0gU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiZG9yb3RoZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXllciA9ICJkYXRhIikKbWF0X3VzZSA8LSBpZiAoIWlzLm51bGwobWF0X3NjYWxlZCkgJiYKICAgICAgICAgICAgICAgbnJvdyhtYXRfc2NhbGVkKSA+IDApIG1hdF9zY2FsZWQgZWxzZSBtYXRfZGF0YQoKIyBGaWx0ZXIgZm9yIFRGcyBwcmVzZW50IGluIFNldXJhdAphdmFpbGFibGVfdGZzIDwtIGludGVyc2VjdCh0Zl9tZXRhJFRGLCByb3duYW1lcyhtYXRfdXNlKSkKbWF0X3VzZSAgICAgICA8LSBtYXRfdXNlW2F2YWlsYWJsZV90ZnMsICwgZHJvcCA9IEZBTFNFXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDMuIEF2ZXJhZ2UgcGVyIG9yaWcuaWRlbnQgJiB6LXNjb3JlCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0Kb3JpZ19pZGVudCA8LSBhcy5mYWN0b3Ioc2V1cmF0X29iaiRvcmlnLmlkZW50KQoKYXZnX21hdCA8LSBzYXBwbHkobGV2ZWxzKG9yaWdfaWRlbnQpLCBmdW5jdGlvbihpZCkgewogIE1hdHJpeDo6cm93TWVhbnMobWF0X3VzZVssIG9yaWdfaWRlbnQgPT0gaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wID0gRkFMU0VdKQp9KQpjb2xuYW1lcyhhdmdfbWF0KSA8LSBsZXZlbHMob3JpZ19pZGVudCkKCmF2Z19tYXRfeiAgICAgICAgICAgICAgIDwtIHQoc2NhbGUodChhdmdfbWF0KSkpCmF2Z19tYXRfeltpcy5uYShhdmdfbWF0X3opXSA8LSAwCgojIEFsaWduIHRmX21ldGEgb3JkZXIgdG8gbWF0Y2ggbWF0X3VzZSBwcmVjaXNlbHkKcm93X29yZGVyX2lkeCAgICA8LSBtYXRjaChyb3duYW1lcyhhdmdfbWF0X3opLCB0Zl9tZXRhJFRGKQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFbcm93X29yZGVyX2lkeCwgXQphdmdfbWF0X3ogICAgICAgIDwtIGF2Z19tYXRfeltvcmRlcih0Zl9tZXRhX2ZpbHRlcmVkJEZ1bmN0aW9uKSwgXQp0Zl9tZXRhX2ZpbHRlcmVkIDwtIHRmX21ldGFfZmlsdGVyZWRbb3JkZXIodGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiksIF0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA0LiBEZWZpbmUgc2FtcGxlIG1ldGFkYXRhCiMgRklYRUQ6IG5hbWVzIG1hdGNoIGFjdHVhbCBvcmlnLmlkZW50IGxldmVscwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CnNhbXBsZV90b19wYXRpZW50IDwtIGMoCiAgIkwxIiAgICAgICA9ICJQYXRpZW50IDEiLAogICJMMiIgICAgICAgPSAiUGF0aWVudCAxIiwKICAiTDMiICAgICAgID0gIlBhdGllbnQgMiIsCiAgIkw0IiAgICAgICA9ICJQYXRpZW50IDIiLAogICJMNSIgICAgICAgPSAiUGF0aWVudCAzIiwKICAiTDYiICAgICAgID0gIlBhdGllbnQgMyIsCiAgIkw3IiAgICAgICA9ICJQYXRpZW50IDMiLAogICJDRDRUX2xhYiIgPSAiTm9ybWFsIiwKICAiQ0Q0VF8xMHgiID0gIk5vcm1hbCIKKQoKc2FtcGxlX3RvX3R5cGUgPC0gYygKICAiTDEiICAgICAgID0gIk1hbGlnbmFudCIsCiAgIkwyIiAgICAgICA9ICJNYWxpZ25hbnQiLAogICJMMyIgICAgICAgPSAiTWFsaWduYW50IiwKICAiTDQiICAgICAgID0gIk1hbGlnbmFudCIsCiAgIkw1IiAgICAgICA9ICJNYWxpZ25hbnQiLAogICJMNiIgICAgICAgPSAiTWFsaWduYW50IiwKICAiTDciICAgICAgID0gIk1hbGlnbmFudCIsCiAgIkNENFRfbGFiIiA9ICJOb3JtYWwiLAogICJDRDRUXzEweCIgPSAiTm9ybWFsIgopCgojIEV4dHJhY3QgYW5ub3RhdGlvbnMKcGF0aWVudF9hbm5vdGF0aW9uICA8LSBzYW1wbGVfdG9fcGF0aWVudFtjb2xuYW1lcyhhdmdfbWF0X3opXQpjZWxsdHlwZV9hbm5vdGF0aW9uIDwtIHNhbXBsZV90b190eXBlW2NvbG5hbWVzKGF2Z19tYXRfeildCgojIFZlcmlmeSBubyBOQXMg4oCUIHNob3VsZCBwcmludCBjaGFyYWN0ZXIoMCkgZm9yIGJvdGgKY2F0KCJQYXRpZW50IE5BczoiLCBjb2xuYW1lcyhhdmdfbWF0X3opW2lzLm5hKHBhdGllbnRfYW5ub3RhdGlvbildLCAiXG4iKQpjYXQoIlR5cGUgTkFzOiIsICAgIGNvbG5hbWVzKGF2Z19tYXRfeilbaXMubmEoY2VsbHR5cGVfYW5ub3RhdGlvbildLCAiXG4iKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDUuIENvbHVtbiBhbm5vdGF0aW9uICh0b3ApCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KaGFfY29sIDwtIEhlYXRtYXBBbm5vdGF0aW9uKAogIENlbGxfVHlwZSA9IGNlbGx0eXBlX2Fubm90YXRpb24sCiAgUGF0aWVudCAgID0gcGF0aWVudF9hbm5vdGF0aW9uLAogIGNvbCA9IGxpc3QoCiAgICBDZWxsX1R5cGUgPSBjKAogICAgICAiTm9ybWFsIiAgICA9ICIjNERBRjRBIiwKICAgICAgIk1hbGlnbmFudCIgPSAiI0MwMDAwMCIKICAgICksCiAgICBQYXRpZW50ID0gYygKICAgICAgIlBhdGllbnQgMSIgPSAiI0U0MUExQyIsCiAgICAgICJQYXRpZW50IDIiID0gIiMzNzdFQjgiLAogICAgICAiUGF0aWVudCAzIiA9ICIjRkY3RjAwIiwKICAgICAgIk5vcm1hbCIgICAgPSAiIzREQUY0QSIKICAgICkKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImxlZnQiLAogIGFubm90YXRpb25fbmFtZV9ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAogIHNpbXBsZV9hbm5vX3NpemUgICAgID0gdW5pdCg1LCAibW0iKSwKICBib3JkZXIgICAgICAgICAgICAgICA9IFRSVUUKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDYuIFJvdyBhbm5vdGF0aW9uIGNvbG9ycwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CmZ1bmN0aW9uX2NvbG9ycyA8LSBjKAogICJPbmNvZ2VuaWMiICAgICAgICAgICAgID0gIiM4MDgwODAiLAogICJBUC0xIFNpZ25hbGluZyIgICAgICAgID0gIiNGRjhDMDAiLAogICJORkFUIFNpZ25hbGluZyIgICAgICAgID0gIiNGRjQ1MDAiLAogICJORi1cdTAzYmFCIFNpZ25hbGluZyIgPSAiI0UzMUExQyIsCiAgIlN0cmVzcyBSZXNwb25zZSIgICAgICAgPSAiI0ZGRDcwMCIsCiAgIlRoMiAvIEpBSy1TVEFUIENvcmUiICA9ICIjOTg0RUEzIiwKICAiU3RlbS1saWtlIFByb2dlbml0b3IiICA9ICIjRkYxNDkzIiwKICAiUHJvbGlmZXJhdGlvbiIgICAgICAgICA9ICIjMUU5MEZGIiwKICAiVGVybWluYWwgRWZmZWN0b3IiICAgICA9ICIjODAwMDgwIiwKICAiTkstbGlrZSBDeXRvdG94aWNpdHkiICA9ICIjRjc4MUJGIiwKICAiQW50aWdlbiBQcmVzZW50YXRpb24iICA9ICIjNjZDREFBIiwKICAiTWlncmF0aW9uIC8gQWRoZXNpb24iICA9ICIjOEEyQkUyIiwKICAiSUZOIFJlc3BvbnNlIiAgICAgICAgICA9ICIjMDBDRUQxIiwKICAiTWV0YWJvbGlzbSIgICAgICAgICAgICA9ICIjQTY1NjI4IiwKICAiVHVtb3IgU3VwcHJlc3NvciIgICAgICA9ICIjMzc3RUI4IiwKICAiTm9ybWFsIEhvbWVvc3Rhc2lzIiAgICA9ICIjNERBRjRBIgopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNy4gUm93IGFubm90YXRpb24gKGxlZnQpCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KaGFfcm93IDwtIHJvd0Fubm90YXRpb24oCiAgQ29uZGl0aW9uID0gdGZfbWV0YV9maWx0ZXJlZCRDb25kaXRpb24sCiAgRnVuY3Rpb24gID0gdGZfbWV0YV9maWx0ZXJlZCRGdW5jdGlvbiwKICBjb2wgPSBsaXN0KAogICAgQ29uZGl0aW9uID0gYygKICAgICAgIk5vcm1hbCIgICAgPSAiIzREQUY0QSIsCiAgICAgICJNYWxpZ25hbnQiID0gIiNDMDAwMDAiCiAgICApLAogICAgRnVuY3Rpb24gPSBmdW5jdGlvbl9jb2xvcnMKICApLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIsCiAgYW5ub3RhdGlvbl9uYW1lX2dwICAgPSBncGFyKGZvbnRzaXplICA9IDksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgc2ltcGxlX2Fubm9fc2l6ZSAgICAgPSB1bml0KDUsICJtbSIpLAogIGJvcmRlciAgICAgICAgICAgICAgID0gVFJVRSwKICBnYXAgICAgICAgICAgICAgICAgICA9IHVuaXQoMSwgIm1tIikKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDguIEhlYXRtYXAgY29sb3Igc2NhbGUg4oCUIDUgcG9pbnQgZ3JhZGllbnQKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKAogIGMoLTMsIC0xLjUsIDAsIDEuNSwgMyksCiAgYygiIzIxNjZBQyIsICAgIyBEZWVwIGJsdWUKICAgICIjOTJDNURFIiwgICAjIExpZ2h0IGJsdWUKICAgICIjRjdGN0Y3IiwgICAjIE9mZi13aGl0ZQogICAgIiNGNEE1ODIiLCAgICMgTGlnaHQgcmVkCiAgICAiI0IyMTgyQiIpICAgIyBEZWVwIHJlZAopCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgOS4gQnVpbGQgaGVhdG1hcAojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Cmh0IDwtIEhlYXRtYXAoCiAgYXZnX21hdF96LAogIG5hbWUgPSAiVEYgYWN0aXZpdHlcbih6LXNjb3JlKSIsCiAgY29sICA9IGNvbF9mdW4sCgogICMgQW5ub3RhdGlvbnMKICB0b3BfYW5ub3RhdGlvbiAgPSBoYV9jb2wsCiAgbGVmdF9hbm5vdGF0aW9uID0gaGFfcm93LAoKICAjIFNwbGl0dGluZyDigJQgY29sdW1ucyBieSBwYXRpZW50LCByb3dzIGJ5IGZ1bmN0aW9uCiAgY29sdW1uX3NwbGl0ID0gcGF0aWVudF9hbm5vdGF0aW9uLAogIHJvd19zcGxpdCAgICA9IHRmX21ldGFfZmlsdGVyZWQkRnVuY3Rpb24sCgogICMgQ2x1c3RlcmluZwogIGNsdXN0ZXJfcm93X3NsaWNlcyA9IEZBTFNFLAogIGNsdXN0ZXJfcm93cyAgICAgICA9IEZBTFNFLAogIGNsdXN0ZXJfY29sdW1ucyAgICA9IFRSVUUsCiAgc2hvd19yb3dfZGVuZCAgICAgID0gRkFMU0UsCiAgc2hvd19jb2x1bW5fZGVuZCAgID0gVFJVRSwKICBjb2x1bW5fZGVuZF9oZWlnaHQgPSB1bml0KDE1LCAibW0iKSwKCiAgIyBDZWxsIGFwcGVhcmFuY2UKICByZWN0X2dwID0gZ3Bhcihjb2wgPSAid2hpdGUiLCBsd2QgPSAwLjgpLAoKICAjIFJvdyBuYW1lcyDigJQgQk9MRCBmb3Igc2xpZGUgdmlzaWJpbGl0eQogIHJvd19uYW1lc19ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAogIHJvd19uYW1lc19zaWRlID0gInJpZ2h0IiwKCiAgIyBDb2x1bW4gbmFtZXMg4oCUIEJPTEQgZm9yIHNsaWRlIHZpc2liaWxpdHkKICBjb2x1bW5fbmFtZXNfZ3AgID0gZ3Bhcihmb250c2l6ZSAgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sICAgICAgPSAiYmxhY2siKSwKICBjb2x1bW5fbmFtZXNfcm90ID0gNDUsCgogICMgUm93IHRpdGxlCiAgcm93X3RpdGxlX3JvdCAgPSAwLAogIHJvd190aXRsZV9ncCAgID0gZ3Bhcihmb250c2l6ZSAgPSAxMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAogIHJvd190aXRsZV9zaWRlID0gImxlZnQiLAoKICAjIEdhcHMKICByb3dfZ2FwICAgID0gdW5pdCgyLjUsICJtbSIpLAogIGNvbHVtbl9nYXAgPSB1bml0KDYsICAgIm1tIiksCgogICMgTWFpbiB0aXRsZSDigJQgZGVmaW5lZCBvbmx5IG9uY2UKICBjb2x1bW5fdGl0bGUgICAgPSAiRnVuY3Rpb25hbCBURiBNb2R1bGVzIHBlciBDZWxsIExpbmUg4oCUIFPDqXphcnkgU3luZHJvbWUiLAogIGNvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgID0gMTQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAoKICAjIExlZ2VuZCDigJQgYXQvbGFiZWxzIHJlbW92ZWQgdG8gYXZvaWQgdmVyc2lvbiBlcnJvcnMKICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoCiAgICBkaXJlY3Rpb24gICAgID0gInZlcnRpY2FsIiwKICAgIHRpdGxlICAgICAgICAgPSAiVEYgYWN0aXZpdHlcbih6LXNjb3JlKSIsCiAgICB0aXRsZV9ncCAgICAgID0gZ3Bhcihmb250c2l6ZSAgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCAgICAgID0gImJsYWNrIiksCiAgICBsYWJlbHNfZ3AgICAgID0gZ3Bhcihmb250c2l6ZSAgPSA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgICAgICA9ICJibGFjayIpLAogICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoNCwgImNtIiksCiAgICBib3JkZXIgICAgICAgID0gImdyZXk1MCIKICApCikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAxMC4gU2F2ZQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgUERGIOKAlCB2ZWN0b3IgcXVhbGl0eSBmb3IgcHVibGljYXRpb24KcGRmKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfVEZfSGVhdG1hcF9PcmlnSWRlbnRfRmluYWwucGRmIiwKICAgIHdpZHRoICAgICAgID0gMTgsCiAgICBoZWlnaHQgICAgICA9IDE2LAogICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKZHJhdyhodCwKICAgICBtZXJnZV9sZWdlbmQgICAgICAgICAgID0gVFJVRSwKICAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlICAgID0gInJpZ2h0IiwKICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gInJpZ2h0IiwKICAgICBwYWRkaW5nID0gdW5pdChjKDUsIDUsIDUsIDUpLCAibW0iKSkKZGV2Lm9mZigpCgojIFBORyDigJQgaGlnaCByZXNvbHV0aW9uIGZvciBwcmVzZW50YXRpb25zCnBuZygiT3V0cHV0X0ZpZ3VyZXMvRmlndXJlX1RGX0hlYXRtYXBfT3JpZ0lkZW50X0ZpbmFsLnBuZyIsCiAgICB3aWR0aCAgPSAxOCAqIDMwMCwKICAgIGhlaWdodCA9IDE2ICogMzAwLAogICAgcmVzICAgID0gMzAwKQpkcmF3KGh0LAogICAgIG1lcmdlX2xlZ2VuZCAgICAgICAgICAgPSBUUlVFLAogICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgICAgPSAicmlnaHQiLAogICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAicmlnaHQiLAogICAgIHBhZGRpbmcgPSB1bml0KGMoNSwgNSwgNSwgNSksICJtbSIpKQpkZXYub2ZmKCkKCiMgRHJhdyBpbiBub3RlYm9vawpkcmF3KGh0LAogICAgIG1lcmdlX2xlZ2VuZCAgICAgICAgICAgPSBUUlVFLAogICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgICAgPSAicmlnaHQiLAogICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAicmlnaHQiLAogICAgIHBhZGRpbmcgPSB1bml0KGMoNSwgNSwgNSwgNSksICJtbSIpKQoKYGBgCgoKCgoKCgoKIyBEZWZpbmUgVGgxL1RoMi9UaDE3L1RoMjIvVHJlZyBNYXN0ZXIgUmVndWxhdG9yIFBhbmVsCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBMSUJSQVJJRVMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShncmlkKQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAxLiBEZWZpbmUgVGgxL1RoMi9UaDE3L1RoMjIvVHJlZyBNYXN0ZXIgUmVndWxhdG9yIFBhbmVsCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KdGZfbWV0YV90aGVscGVyIDwtIGRhdGEuZnJhbWUoCiAgVEYgPSBjKAogICAgIyBUaDEgTWFzdGVyIFJlZ3VsYXRvcnMKICAgICJUQlgyMSIsICJTVEFUMSIsICJTVEFUNCIsICJJUkYxIiwKICAgIAogICAgIyBUaDIgTWFzdGVyIFJlZ3VsYXRvcnMgIAogICAgIkdBVEEzIiwgIlNUQVQ2IiwgIkJBVEYiLCAiSVJGNCIsCiAgICAKICAgICMgVGgxNyAvIFRoMjIgTWFzdGVyIFJlZ3VsYXRvcnMKICAgICJST1JDIiwgIlNUQVQzIiwgIkFIUiIsICJNQUYiLAogICAgCiAgICAjIFRyZWcgTWFzdGVyIFJlZ3VsYXRvcnMKICAgICJGT1hQMyIsICJGT1hPMSIsICJDVExBNCIgICMgQ1RMQTQgcmVndWxvbiBhcyBUcmVnIHByb3h5CiAgKSwKICBGdW5jdGlvbiA9IGMoCiAgICByZXAoIlRoMSIsIDQpLAogICAgcmVwKCJUaDIiLCA0KSwKICAgIHJlcCgiVGgxNy9UaDIyIiwgNCksCiAgICByZXAoIlRyZWciLCAzKQogICksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgTG9jayBpbiBjYW5vbmljYWwgb3JkZXI6IFRoMSDihpIgVGgyIOKGkiBUaDE3L1RoMjIg4oaSIFRyZWcKdGZfbWV0YV90aGVscGVyJEZ1bmN0aW9uIDwtIGZhY3Rvcih0Zl9tZXRhX3RoZWxwZXIkRnVuY3Rpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlRoMSIsICJUaDIiLCAiVGgxNy9UaDIyIiwgIlRyZWciKSkKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyAyLiBFeHRyYWN0IFRGIGFjdGl2aXR5IG1hdHJpeAojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Cm1hdF9zY2FsZWQgPC0gdHJ5Q2F0Y2goU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJzY2FsZS5kYXRhIiksIGVycm9yID0gZnVuY3Rpb24oZSkgTlVMTCkKbWF0X2RhdGEgPC0gU2V1cmF0T2JqZWN0OjpHZXRBc3NheURhdGEoc2V1cmF0X29iaiwgYXNzYXkgPSAiZG9yb3RoZWEiLCBsYXllciA9ICJkYXRhIikKbWF0X3VzZSA8LSBpZiAoIWlzLm51bGwobWF0X3NjYWxlZCkgJiYgbnJvdyhtYXRfc2NhbGVkKSA+IDApIG1hdF9zY2FsZWQgZWxzZSBtYXRfZGF0YQoKIyBGaWx0ZXIgZm9yIGF2YWlsYWJsZSBURnMKYXZhaWxhYmxlX3RmcyA8LSBpbnRlcnNlY3QodGZfbWV0YV90aGVscGVyJFRGLCByb3duYW1lcyhtYXRfdXNlKSkKbWF0X3VzZSA8LSBtYXRfdXNlW2F2YWlsYWJsZV90ZnMsICwgZHJvcCA9IEZBTFNFXQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDMuIEF2ZXJhZ2UgcGVyIGNsdXN0ZXIgJiB6LXNjb3JlCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3RlcnMgPC0gYXMuZmFjdG9yKHNldXJhdF9vYmokc2V1cmF0X2NsdXN0ZXJzKQphdmdfbWF0IDwtIHNhcHBseShsZXZlbHMoY2x1c3RlcnMpLCBmdW5jdGlvbihjbCkgTWF0cml4Ojpyb3dNZWFucyhtYXRfdXNlWywgY2x1c3RlcnMgPT0gY2wsIGRyb3AgPSBGQUxTRV0pKQpjb2xuYW1lcyhhdmdfbWF0KSA8LSBsZXZlbHMoY2x1c3RlcnMpCgphdmdfbWF0X3ogPC0gdChzY2FsZSh0KGF2Z19tYXQpKSkKYXZnX21hdF96W2lzLm5hKGF2Z19tYXRfeildIDwtIDAKCiMgQWxpZ24gdG8gb3VyIGRlZmluZWQgaGVscGVyIFQgcGFuZWwgb3JkZXIKcm93X29yZGVyX2lkeCA8LSBtYXRjaChyb3duYW1lcyhhdmdfbWF0X3opLCB0Zl9tZXRhX3RoZWxwZXIkVEYpCnRmX21ldGFfdGhlbHBlcl9maWx0ZXJlZCA8LSB0Zl9tZXRhX3RoZWxwZXJbcm93X29yZGVyX2lkeCwgXQphdmdfbWF0X3ogPC0gYXZnX21hdF96W29yZGVyKHRmX21ldGFfdGhlbHBlcl9maWx0ZXJlZCRGdW5jdGlvbiksIF0KdGZfbWV0YV90aGVscGVyX2ZpbHRlcmVkIDwtIHRmX21ldGFfdGhlbHBlcl9maWx0ZXJlZFtvcmRlcih0Zl9tZXRhX3RoZWxwZXJfZmlsdGVyZWQkRnVuY3Rpb24pLCBdCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgNC4gQ29sdW1uICYgcm93IGFubm90YXRpb25zCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KY2x1c3Rlcl9zdGF0dXMgPC0gaWZlbHNlKGNvbG5hbWVzKGF2Z19tYXRfeikgJWluJSBjKCIzIiwiMTAiKSwgIk5vcm1hbCBDRDQgVCBjZWxscyIsICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMiKQpoYV9jb2wgPC0gSGVhdG1hcEFubm90YXRpb24oCiAgQ2VsbF9TdGF0ZSA9IGNsdXN0ZXJfc3RhdHVzLCAKICBjb2wgPSBsaXN0KENlbGxfU3RhdGUgPSBjKCJOb3JtYWwgQ0Q0IFQgY2VsbHMiID0gIiM0REFGNEEiLCAiTWFsaWduYW50IENENCBUIGNlbGxzIiA9ICIjRTQxQTFDIikpLCAKICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJsZWZ0IgopCgojIENsYXNzaWNhbCBUIGhlbHBlciBjb2xvciBzY2hlbWUKaGVscGVyX2NvbG9ycyA8LSBjKAogICJUaDEiID0gIiNFMzFBMUMiLCAgICAgICMgUmVkCiAgIlRoMiIgPSAiIzFGNzhCNCIsICAgICAgIyBCbHVlICAKICAiVGgxNy9UaDIyIiA9ICIjRkY3RjAwIiwgIyBPcmFuZ2UKICAiVHJlZyIgPSAiIzMzQTAyQyIgICAgICAjIEdyZWVuCikKCmhhX3JvdyA8LSByb3dBbm5vdGF0aW9uKAogIEZ1bmN0aW9uID0gdGZfbWV0YV90aGVscGVyX2ZpbHRlcmVkJEZ1bmN0aW9uLCAKICBjb2wgPSBsaXN0KEZ1bmN0aW9uID0gaGVscGVyX2NvbG9ycyksIAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIKKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIDUuIEhlYXRtYXAgY29sb3JzICYgcGxvdHRpbmcKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQpjb2xfZnVuIDwtIGNpcmNsaXplOjpjb2xvclJhbXAyKGMoLTMsMCwzKSwgYygiIzMxMzY5NSIsIndoaXRlIiwiI0E1MDAyNiIpKQoKaHRfdGhlbHBlciA8LSBIZWF0bWFwKAogIGF2Z19tYXRfeiwgCiAgbmFtZSA9ICJURiBhY3Rpdml0eSAoeikiLCAKICBjb2wgPSBjb2xfZnVuLCAKICB0b3BfYW5ub3RhdGlvbiA9IGhhX2NvbCwgCiAgbGVmdF9hbm5vdGF0aW9uID0gaGFfcm93LCAKICBjb2x1bW5fc3BsaXQgPSBjbHVzdGVyX3N0YXR1cywgCiAgcm93X3NwbGl0ID0gdGZfbWV0YV90aGVscGVyX2ZpbHRlcmVkJEZ1bmN0aW9uLCAKICBjbHVzdGVyX3Jvd19zbGljZXMgPSBGQUxTRSwgCiAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIAogIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsIAogIHNob3dfcm93X2RlbmQgPSBGQUxTRSwgCiAgc2hvd19jb2x1bW5fZGVuZCA9IFRSVUUsIAogIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMSwgZm9udGZhY2UgPSAiYm9sZCIpLCAKICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTEpLCAKICBjb2x1bW5fdGl0bGUgPSAiQ0Q0KyBUIEhlbHBlciBMaW5lYWdlIFRyYW5zY3JpcHRpb24gRmFjdG9ycyIsIAogIHJvd190aXRsZV9yb3QgPSAwLCAKICByb3dfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMTAsIGZvbnRmYWNlID0gImJvbGQiKSwgCiAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpCikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyA2LiBTYXZlIHBsb3RzCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KcGRmKCJPdXRwdXRfRmlndXJlcy9GaWd1cmVfVEZfSGVhdG1hcF9USGVscGVyX0xpbmVhZ2VzLnBkZiIsIHdpZHRoPTEyLCBoZWlnaHQ9OCkKZHJhdyhodF90aGVscGVyLCBtZXJnZV9sZWdlbmQ9VFJVRSkKZGV2Lm9mZigpCgpwbmcoIk91dHB1dF9GaWd1cmVzL0ZpZ3VyZV9URl9IZWF0bWFwX1RIZWxwZXJfTGluZWFnZXMucG5nIiwgd2lkdGg9MTIqMzAwLCBoZWlnaHQ9OCozMDAsIHJlcz0zMDApCmRyYXcoaHRfdGhlbHBlciwgbWVyZ2VfbGVnZW5kPVRSVUUpCmRldi5vZmYoKQoKZHJhdyhodF90aGVscGVyLCBtZXJnZV9sZWdlbmQ9VFJVRSkKYGBgCgoKCkZpbmFsIFNhdmUKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KcHJpbnQoIkFuYWx5c2lzIHBpcGVsaW5lIGNvbXBsZXRlLiBBbGwgZmlndXJlcyBhbmQgb2JqZWN0cyBzYXZlZCBpbiBPdXRwdXRfRmlndXJlcyBmb2xkZXIuIikKYGBgCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCg==