4. Volcano Plot
library(ggplot2)
library(dplyr)
Attachement du package : ‘dplyr’
L'objet suivant est masqué depuis ‘package:Biobase’:
combine
Les objets suivants sont masqués depuis ‘package:GenomicRanges’:
intersect, setdiff, union
L'objet suivant est masqué depuis ‘package:GenomeInfoDb’:
intersect
Les objets suivants sont masqués depuis ‘package:IRanges’:
collapse, desc, intersect, setdiff, slice, union
Les objets suivants sont masqués depuis ‘package:S4Vectors’:
first, intersect, rename, setdiff, setequal, union
Les objets suivants sont masqués depuis ‘package:BiocGenerics’:
combine, intersect, setdiff, union
L'objet suivant est masqué depuis ‘package:matrixStats’:
count
Les objets suivants sont masqués depuis ‘package:stats’:
filter, lag
Les objets suivants sont masqués depuis ‘package:base’:
intersect, setdiff, setequal, union
# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)
# Save results to CSV
write.csv(DE_results_df, file = "1-Pseudobulk_edgeR_LRT_DE_with_libra.csv", row.names = FALSE)
# Ensure logFC and p-value columns are named correctly
colnames(DE_results_df)
[1] "cell_type" "gene" "avg_logFC" "Malignant.pct" "Control.pct" "Malignant.exp"
[7] "Control.exp" "p_val" "p_val_adj" "de_family" "de_method" "de_type"
# Filtering for significant genes:
volcano_data <- DE_results_df %>%
mutate(
significance = case_when(
p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
TRUE ~ "Not Significant"
)
)
ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
geom_point(alpha = 0.6, size = 2) +
scale_color_manual(values = c("Upregulated" = "red", "Downregulated" = "blue", "Not Significant" = "grey")) +
theme_minimal() +
labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
x = "Log2 Fold Change",
y = "-Log10 Adjusted P-Value",
color = "Significance") +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") +
geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black")

NA
NA
Volcano Plot
library(EnhancedVolcano)
Le chargement a nécessité le package : ggrepel
EnhancedVolcano(
DE_results,
lab = DE_results$gene, # Labels for genes
x = 'avg_logFC', # Log2 Fold Change (corrected name)
y = 'p_val_adj', # Adjusted P-value
title = 'Volcano Plot: Pseudobulk DESeq2 Analysis',
subtitle = 'Malignant vs Normal CD4T Cells',
pCutoff = 0.05, # Adjusted p-value threshold
FCcutoff = 2, # Fold Change threshold
pointSize = 2.0, # Adjust point size
labSize = 4.0, # Adjust label size
col = c("black", "grey", "blue", "red"), # Color coding
colAlpha = 0.6, # Transparency for points
legendLabels = c("NS", "Log2FC", "P-value", "Both"),
legendPosition = "right",
legendLabSize = 10,
legendIconSize = 4.0,
drawConnectors = TRUE, # Connect gene labels
widthConnectors = 0.5,
vline = c(-2, 2), # Vertical lines at logFC ±2
hline = -log10(0.05), # Horizontal line at adjusted p-value 0.05
border = "full"
)

Volcano Plot
library(ggplot2)
library(dplyr)
library(ggrepel)
# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)
# Ensure correct column names
colnames(DE_results_df)
[1] "cell_type" "gene" "avg_logFC" "Malignant.pct" "Control.pct" "Malignant.exp"
[7] "Control.exp" "p_val" "p_val_adj" "de_family" "de_method" "de_type"
# Define significance categories
volcano_data <- DE_results_df %>%
mutate(
significance = case_when(
p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
TRUE ~ "Not Significant"
)
)
# Select genes to label: p_val_adj < 1e-50 OR logFC > 2 OR logFC < -2
top_genes <- volcano_data %>%
filter(p_val_adj < 0.05 | avg_logFC > 2 | avg_logFC < -2)
ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
geom_point(alpha = 0.6, size = 2) + # Main points
scale_color_manual(values = c("Upregulated" = "red", "Downregulated" = "blue", "Not Significant" = "grey")) +
theme_minimal() +
labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
x = "Log2 Fold Change",
y = "-Log10 Adjusted P-Value",
color = "Significance") +
# Add gene labels WITHOUT any lines connecting them
geom_text_repel(data = top_genes,
aes(label = gene),
size = 3, box.padding = 0.3, max.overlaps = 15, segment.color = NA) +
# Add threshold lines
geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black") + # logFC thresholds
geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") + # p-value threshold
ylim(0, 70) # Set max y-axis limit to avoid extreme values

NA
NA
Volcano Plot
library(ggplot2)
library(dplyr)
library(ggrepel)
# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)
# Ensure correct column names
colnames(DE_results_df)
[1] "cell_type" "gene" "avg_logFC" "Malignant.pct" "Control.pct" "Malignant.exp"
[7] "Control.exp" "p_val" "p_val_adj" "de_family" "de_method" "de_type"
# Define significance categories
volcano_data <- DE_results_df %>%
mutate(
significance = case_when(
p_val_adj < 1e-20 & avg_logFC > 2 ~ "Highly Upregulated",
p_val_adj < 1e-20 & avg_logFC < -2 ~ "Highly Downregulated",
p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
TRUE ~ "Not Significant"
)
)
# Select only very significant genes for labeling
top_genes <- volcano_data %>%
filter(p_val_adj < 0.05 & (avg_logFC > 2 | avg_logFC < -2))
ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
# Main points
geom_point(alpha = 0.7, size = 2.5) +
# Highlight highly significant genes with larger points
geom_point(data = top_genes, aes(x = avg_logFC, y = -log10(p_val_adj)),
color = "black", size = 3, shape = 21, fill = "black") +
# Custom color scheme
scale_color_manual(values = c(
"Highly Upregulated" = "darkred",
"Highly Downregulated" = "darkblue",
"Upregulated" = "red",
"Downregulated" = "blue",
"Not Significant" = "grey"
)) +
# Add gene labels (only for highly significant genes)
geom_text_repel(data = top_genes, aes(label = gene),
size = 4, box.padding = 0.5, max.overlaps = 10, segment.color = NA) +
# Add threshold lines
geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black") +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") +
# Improve theme
theme_minimal(base_size = 14) +
labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
x = "Log2 Fold Change",
y = "-Log10 Adjusted P-Value",
color = "Significance") +
ylim(0, 50) # Avoid extreme scaling issues

NA
NA
9. EnhancedVolcano plot
library(dplyr)
library(EnhancedVolcano)
# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- markers %>%
arrange(p_val_adj, desc(abs(avg_logFC)))
# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 0.0000905 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
pCutoff = 0.0000905,
FCcutoff = 1.0,
legendPosition = 'right',
labCol = 'black',
labFace = 'bold',
boxedLabels = FALSE, # Set to FALSE to remove boxed labels
pointSize = 3.0,
labSize = 5.0,
col = c('grey70', 'lightblue', 'blue', 'red'), # Customize point colors
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0] # Only label significant genes
)

EnhancedVolcano plot
library(dplyr)
library(EnhancedVolcano)
# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- markers %>%
arrange(p_val_adj, desc(abs(avg_logFC)))
# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 0.0000905 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
pCutoff = 1e-4,
FCcutoff = 1.0,
legendPosition = 'right',
labCol = 'black',
labFace = 'bold',
boxedLabels = FALSE, # Set to FALSE to remove boxed labels
pointSize = 3.0,
labSize = 5.0,
col = c('grey70', 'black', 'blue', 'red'), # Customize point colors
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0] # Only label significant genes
)

NA
NA
NA
Create the EnhancedVolcano plot
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- markers
EnhancedVolcano(Malignant_CD4Tcells_vs_Normal_CD4Tcells,
lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
x = "avg_logFC",
y = "p_val_adj",
title = "MAST with Batch Correction (All Genes)",
pCutoff = 0.05,
FCcutoff = 1.0)

EnhancedVolcano(Malignant_CD4Tcells_vs_Normal_CD4Tcells,
lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
x = "avg_logFC",
y = "p_val_adj",
selectLab = c('EPCAM', 'BCAT1', 'KIR3DL2', 'FOXM1', 'TWIST1', 'TNFSF9',
'CD80', 'IL1B', 'RPS4Y1',
'IL7R', 'TCF7', 'MKI67', 'CD70',
'IL2RA','TRBV6-2', 'TRBV10-3', 'TRBV4-2', 'TRBV9', 'TRBV7-9',
'TRAV12-1', 'CD8B', 'FCGR3A', 'GNLY', 'FOXP3', 'SELL',
'GIMAP1', 'RIPOR2', 'LEF1', 'HOXC9', 'SP5',
'CCL17', 'ETV4', 'THY1', 'FOXA2', 'ITGAD', 'S100P', 'TBX4',
'ID1', 'XCL1', 'SOX2', 'CD27', 'CD28','PLS3','CD70','RAB25' , 'TRBV27', 'TRBV2'),
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
xlab = bquote(~Log[2]~ 'fold change'),
pCutoff = 0.05,
FCcutoff = 1.5,
pointSize = 3.0,
labSize = 5.0,
boxedLabels = TRUE,
colAlpha = 0.5,
legendPosition = 'right',
legendLabSize = 10,
legendIconSize = 4.0,
drawConnectors = TRUE,
widthConnectors = 0.5,
colConnectors = 'grey50',
arrowheads = FALSE,
max.overlaps = 30)

library(dplyr)
library(EnhancedVolcano)
# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
arrange(p_val_adj, desc(abs(avg_logFC)))
# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
pCutoff = 0.05,
FCcutoff = 1.0,
legendPosition = 'right',
labCol = 'black',
labFace = 'bold',
boxedLabels = FALSE, # Set to FALSE to remove boxed labels
pointSize = 3.0,
labSize = 5.0,
col = c('grey70', 'black', 'blue', 'red'), # Customize point colors
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0] # Only label significant genes
)

EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells (cell lines) vs Normal CD4 T cells",
subtitle = "Highlighting differentially expressed genes",
pCutoff = 0.05,
FCcutoff = 1.0,
legendPosition = 'right',
colAlpha = 0.8, # Slight transparency for non-significant points
col = c('grey70', 'black', 'blue', 'red'), # Custom color scheme
gridlines.major = TRUE,
gridlines.minor = FALSE,
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]
)

NA
NA
ggplot2 for Volcano
library(ggplot2)
library(ggrepel)
# Identify top and bottom genes
top_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < 0.05 & Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > 0.5, ]
bottom_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < 0.05 & Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < -0.5, ]
# Create a new column for color based on significance
Malignant_CD4Tcells_vs_Normal_CD4Tcells$color <- ifelse(Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > 0.5, "Upregulated genes",
ifelse(Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < -0.5, "Downregulated genes", "Nonsignificant"))
# Create a volcano plot
ggplot(Malignant_CD4Tcells_vs_Normal_CD4Tcells, aes(x = avg_logFC, y = -log10(p_val_adj))) +
geom_point(aes(color = color), alpha = 0.7, size = 2) +
# Add labels for top and bottom genes
geom_text_repel(data = top_genes, aes(label = gene), color = "black", vjust = 1, fontface = "bold") +
geom_text_repel(data = bottom_genes, aes(label = gene), color = "black", vjust = -1, fontface = "bold") +
# Customize labels and title
labs(title = "Volcano Plot",
x = "log2 Fold Change",
y = "-log10(p-value)") +
# # Add significance threshold lines
geom_hline(yintercept = -log10(0.00001), linetype = "dashed", color = "black") +
geom_vline(xintercept = c(-0.5, 0.5), linetype = "dashed", color = "black") +
# Set colors for top and bottom genes
scale_color_manual(values = c("Upregulated genes" = "red", "Downregulated genes" = "blue", "Nonsignificant" = "darkgrey")) +
# Customize theme if needed
theme_minimal()

NA
NA
NA
NA
NA
Create the EnhancedVolcano plot
library(ggplot2)
library(EnhancedVolcano)
library(dplyr)
# Define the output directory
output_dir <- "Malignant_vs_Control"
dir.create(output_dir, showWarnings = FALSE)
# First Volcano Plot
p1 <- EnhancedVolcano(
Malignant_CD4Tcells_vs_Normal_CD4Tcells,
lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant_CD4Tcells_vs_Normal_CD4Tcells",
pCutoff = 1e-4,
FCcutoff = 1.0
)
print(p1) # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot1.png"), plot = p1, width = 14, height = 10, dpi = 300)
# Second Volcano Plot with selected genes
p2 <- EnhancedVolcano(
Malignant_CD4Tcells_vs_Normal_CD4Tcells,
lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
x = "avg_logFC",
y = "p_val_adj",
selectLab = c('EPCAM', 'BCAT1', 'KIR3DL2', 'FOXM1', 'TWIST1', 'TNFSF9',
'CD80', 'IL1B', 'RPS4Y1',
'IL7R', 'TCF7', 'MKI67', 'CD70',
'IL2RA','TRBV6-2', 'TRBV10-3', 'TRBV4-2', 'TRBV9', 'TRBV7-9',
'TRAV12-1', 'CD8B', 'FCGR3A', 'GNLY', 'FOXP3', 'SELL',
'GIMAP1', 'RIPOR2', 'LEF1', 'HOXC9', 'SP5',
'CCL17', 'ETV4', 'THY1', 'FOXA2', 'ITGAD', 'S100P', 'TBX4',
'ID1', 'XCL1', 'SOX2', 'CD27', 'CD28','PLS3','CD70','RAB25' , 'TRBV27', 'TRBV2'),
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
xlab = bquote(~Log[2]~ 'fold change'),
pCutoff = 1e-4,
FCcutoff = 1.5,
pointSize = 3.0,
labSize = 5.0,
boxedLabels = TRUE,
colAlpha = 0.5,
legendPosition = 'right',
legendLabSize = 10,
legendIconSize = 4.0,
drawConnectors = TRUE,
widthConnectors = 0.5,
colConnectors = 'grey50',
arrowheads = FALSE,
max.overlaps = 30
)
print(p2) # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot2.png"), plot = p2, width = 14, height = 10, dpi = 300)
# Filtering genes
filtered_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
arrange(p_val_adj, desc(abs(avg_logFC)))
# Third Volcano Plot - Filtering by p-value and logFC
p3 <- EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 1e-4 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
pCutoff = 1e-4,
FCcutoff = 1.0,
legendPosition = 'right',
labCol = 'black',
labFace = 'bold',
boxedLabels = FALSE, # Remove boxed labels
pointSize = 3.0,
labSize = 5.0,
col = c('grey70', 'black', 'blue', 'red'), # Customize point colors
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]
)
print(p3) # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot3.png"), plot = p3, width = 14, height = 10, dpi = 300)
# Fourth Volcano Plot - More refined filtering
p4 <- EnhancedVolcano(
filtered_genes,
lab = ifelse(filtered_genes$p_val_adj <= 1e-4 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
x = "avg_logFC",
y = "p_val_adj",
title = "Malignant CD4 T cells (cell lines) vs Normal CD4 T cells",
subtitle = "Highlighting differentially expressed genes",
pCutoff = 1e-4,
FCcutoff = 1.0,
legendPosition = 'right',
colAlpha = 0.8, # Slight transparency for non-significant points
col = c('grey70', 'black', 'blue', 'red'), # Custom color scheme
gridlines.major = TRUE,
gridlines.minor = FALSE,
selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]
)
print(p4) # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot4.png"), plot = p4, width = 14, height = 10, dpi = 300)
message("All volcano plots have been displayed and saved successfully in the 'L1_vs_Control' folder.")
All volcano plots have been displayed and saved successfully in the 'L1_vs_Control' folder.
10. Enrichment Analysis-1
# Load necessary libraries
library(clusterProfiler)
library(org.Hs.eg.db)
library(enrichplot)
library(ReactomePA)
library(DOSE) # For GSEA analysis
library(ggplot2) # Ensure ggplot2 is available for plotting
# Define threshold for differential expression selection (modified thresholds)
logFC_up_threshold <- 2 # Upregulated logFC threshold
logFC_down_threshold <- -2 # Downregulated logFC threshold
pval_threshold <- 0.05 # p-value threshold as specified
# Load your differential expression results (modify based on actual data structure)
# Malignant_CD4Tcells_vs_Normal_CD4Tcells <- read.csv("Your_DE_Results_File.csv")
# Select upregulated and downregulated genes
upregulated_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[
Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > logFC_up_threshold &
Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < pval_threshold, ]
downregulated_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[
Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < logFC_down_threshold &
Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < pval_threshold, ]
# Check for missing genes (NAs) in the gene column and remove them
upregulated_genes <- na.omit(upregulated_genes)
downregulated_genes <- na.omit(downregulated_genes)
# Save upregulated and downregulated gene results to CSV
write.csv(upregulated_genes, "Malignant_vs_Control/upregulated_genes.csv", row.names = FALSE)
write.csv(downregulated_genes, "Malignant_vs_Control/downregulated_genes.csv", row.names = FALSE)
# Convert gene symbols to Entrez IDs for enrichment analysis, with checks for missing values
upregulated_entrez <- bitr(upregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 15.77% of input gene IDs are fail to map...
downregulated_entrez <- bitr(downregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 28.72% of input gene IDs are fail to map...
# Check for missing Entrez IDs
missing_upregulated <- upregulated_genes$gene[is.na(upregulated_entrez$ENTREZID)]
missing_downregulated <- downregulated_genes$gene[is.na(downregulated_entrez$ENTREZID)]
# Print out the missing gene symbols for debugging
cat("Missing upregulated genes:\n", missing_upregulated, "\n")
Missing upregulated genes:
cat("Missing downregulated genes:\n", missing_downregulated, "\n")
Missing downregulated genes:
# Remove genes that couldn't be mapped to Entrez IDs
upregulated_entrez <- upregulated_entrez$ENTREZID[!is.na(upregulated_entrez$ENTREZID)]
downregulated_entrez <- downregulated_entrez$ENTREZID[!is.na(downregulated_entrez$ENTREZID)]
# Define a function to safely run enrichment, plot results, and save them
safe_enrichGO <- function(gene_list, title, filename) {
if (length(gene_list) > 0) {
result <- enrichGO(gene = gene_list, OrgDb = org.Hs.eg.db, keyType = "SYMBOL",
ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05)
if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
} else {
message(paste("No significant enrichment found for:", title))
}
} else {
message(paste("No genes found for:", title))
}
}
safe_enrichKEGG <- function(entrez_list, title, filename) {
if (length(entrez_list) > 0) {
result <- enrichKEGG(gene = entrez_list, organism = "hsa", pvalueCutoff = 0.05)
if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
} else {
message(paste("No significant KEGG pathways found for:", title))
}
} else {
message(paste("No genes found for:", title))
}
}
safe_enrichReactome <- function(entrez_list, title, filename) {
if (length(entrez_list) > 0) {
result <- enrichPathway(gene = entrez_list, organism = "human", pvalueCutoff = 0.05)
if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
} else {
message(paste("No significant Reactome pathways found for:", title))
}
} else {
message(paste("No genes found for:", title))
}
}
# Perform enrichment analyses, generate plots, and save results
safe_enrichGO(upregulated_genes$gene, "GO Enrichment for Upregulated Genes", "upregulated_GO_results.csv")

safe_enrichGO(downregulated_genes$gene, "GO Enrichment for Downregulated Genes", "downregulated_GO_results.csv")

safe_enrichKEGG(upregulated_entrez, "KEGG Pathway Enrichment for Upregulated Genes", "upregulated_KEGG_results.csv")
Reading KEGG annotation online: "https://rest.kegg.jp/link/hsa/pathway"...
Reading KEGG annotation online: "https://rest.kegg.jp/list/pathway/hsa"...

safe_enrichKEGG(downregulated_entrez, "KEGG Pathway Enrichment for Downregulated Genes", "downregulated_KEGG_results.csv")

safe_enrichReactome(upregulated_entrez, "Reactome Pathway Enrichment for Upregulated Genes", "upregulated_Reactome_results.csv")

safe_enrichReactome(downregulated_entrez, "Reactome Pathway Enrichment for Downregulated Genes", "downregulated_Reactome_results.csv")
No significant Reactome pathways found for: Reactome Pathway Enrichment for Downregulated Genes
Enrichment Analysis-2-Hallmark
# Load necessary libraries
library(clusterProfiler)
library(org.Hs.eg.db)
library(msigdbr)
library(enrichplot)
# Load Hallmark gene sets from msigdbr
hallmark_sets <- msigdbr(species = "Homo sapiens", category = "H") # "H" is for Hallmark gene sets
# Convert gene symbols to uppercase for consistency
upregulated_genes$gene <- toupper(upregulated_genes$gene)
downregulated_genes$gene <- toupper(downregulated_genes$gene)
# Check for overlap between your upregulated/downregulated genes and Hallmark gene sets
upregulated_in_hallmark <- intersect(upregulated_genes$gene, hallmark_sets$gene_symbol)
downregulated_in_hallmark <- intersect(downregulated_genes$gene, hallmark_sets$gene_symbol)
# Print the number of overlapping genes for both upregulated and downregulated genes
cat("Number of upregulated genes in Hallmark gene sets:", length(upregulated_in_hallmark), "\n")
Number of upregulated genes in Hallmark gene sets: 274
cat("Number of downregulated genes in Hallmark gene sets:", length(downregulated_in_hallmark), "\n")
Number of downregulated genes in Hallmark gene sets: 133
# Define the output folder where the results will be saved
output_folder <- "Malignant_vs_Control/"
# If there are genes to analyze, proceed with enrichment analysis
if (length(upregulated_in_hallmark) > 0) {
# Perform enrichment analysis for upregulated genes using Hallmark gene sets
hallmark_up <- enricher(gene = upregulated_in_hallmark,
TERM2GENE = hallmark_sets[, c("gs_name", "gene_symbol")], # Ensure TERM2GENE uses correct columns
pvalueCutoff = 0.05)
# Check if results exist
if (!is.null(hallmark_up) && nrow(hallmark_up) > 0) {
# Visualize results if available
up_dotplot <- dotplot(hallmark_up, showCategory = 20, title = "Hallmark Pathway Enrichment for Upregulated Genes")
# Display the plot in the notebook
print(up_dotplot)
# Save the dotplot to a PNG file
ggsave(paste0(output_folder, "hallmark_upregulated_dotplot.png"), plot = up_dotplot, width = 10, height = 8)
# Optionally, save the results as CSV
write.csv(as.data.frame(hallmark_up), file = paste0(output_folder, "hallmark_upregulated_enrichment.csv"), row.names = FALSE)
} else {
cat("No significant enrichment found for upregulated genes.\n")
}
} else {
cat("No upregulated genes overlap with Hallmark gene sets.\n")
}

if (length(downregulated_in_hallmark) > 0) {
# Perform enrichment analysis for downregulated genes using Hallmark gene sets
hallmark_down <- enricher(gene = downregulated_in_hallmark,
TERM2GENE = hallmark_sets[, c("gs_name", "gene_symbol")], # Ensure TERM2GENE uses correct columns
pvalueCutoff = 0.05)
# Check if results exist
if (!is.null(hallmark_down) && nrow(hallmark_down) > 0) {
# Visualize results if available
down_dotplot <- dotplot(hallmark_down, showCategory = 20, title = "Hallmark Pathway Enrichment for Downregulated Genes")
# Display the plot in the notebook
print(down_dotplot)
# Save the dotplot to a PNG file
ggsave(paste0(output_folder, "hallmark_downregulated_dotplot.png"), plot = down_dotplot, width = 10, height = 8)
# Optionally, save the results as CSV
write.csv(as.data.frame(hallmark_down), file = paste0(output_folder, "hallmark_downregulated_enrichment.csv"), row.names = FALSE)
} else {
cat("No significant enrichment found for downregulated genes.\n")
}
} else {
cat("No downregulated genes overlap with Hallmark gene sets.\n")
}

NA
NA
LS0tCnRpdGxlOiAiUHNldWRvQnVsayBBbmFseXNpcyB1c2luZyBMaWJyYSBSTkEgYXNzYXktZWRnZVItTFJUIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICMgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgIyB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgIyBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCiMgTG9hZCBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShMaWJyYSkKbGlicmFyeShlZGdlUikKCmBgYAoKCiMgMi4gbG9hZCBzZXVyYXQgb2JqZWN0CmBgYHtyIGxvYWRfc2V1cmF0fQojTG9hZCBTZXVyYXQgT2JqZWN0IEw3CmxvYWQoIi9ob21lL25hYmJhc2kvaXNpbG9uL1RvX1RyYW5zZmVyX2JldHdlZW5fY29tcHV0ZXJzLzIzLUhhcm1vbnlfSW50ZWdyYXRpb24vMC1yb2JqLzUtSGFybW9ueV9JbnRlZ3JhdGVkX0FsbF9zYW1wbGVzX01lcmdlZF9DRDRUY2VsbHNfZmluYWxfUmVzb2x1dGlvbl9TZWxlY3RlZF8wLjhfQURUX05vcm1hbGl6ZWRfY2xlYW5lZF9tdC5yb2JqIikKCnBzZXVkb2J1bGtfc2V1cmF0IDwtIEFsbF9zYW1wbGVzX01lcmdlZAoKcHNldWRvYnVsa19zZXVyYXQkbGFiZWwgPC0gZmFjdG9yKAogIGlmZWxzZShwc2V1ZG9idWxrX3NldXJhdCRvcmlnLmlkZW50ICVpbiUgYygiTDEiLCAiTDIiLCAiTDMiLCAiTDQiLCAiTDUiLCAiTDYiLCAiTDciKSwgIk1hbGlnbmFudCIsICJDb250cm9sIiksCiAgbGV2ZWxzID0gYygiTWFsaWduYW50IiwgIkNvbnRyb2wiKSAgIyBFbnN1cmluZyAiTWFsaWduYW50IiBpcyB0aGUgcmVmZXJlbmNlCikKCiMgRW5zdXJlICdjb25kaXRpb24nIGlzIGEgZmFjdG9yIHdpdGggdGhlIGNvcnJlY3QgbGV2ZWxzCnBzZXVkb2J1bGtfc2V1cmF0JGxhYmVsIDwtIGZhY3Rvcihwc2V1ZG9idWxrX3NldXJhdCRsYWJlbCwgbGV2ZWxzID0gYygiTWFsaWduYW50IiwgIkNvbnRyb2wiKSkKCiMgRW5zdXJlICdyZXBsaWNhdGUnIGlzIGEgZmFjdG9yCnBzZXVkb2J1bGtfc2V1cmF0JHJlcGxpY2F0ZSA8LSBhcy5mYWN0b3IocHNldWRvYnVsa19zZXVyYXQkY2VsbF9saW5lKQoKIyBSZW5hbWUgdGhlIGNlbGwgdHlwZSBjb2x1bW4KcHNldWRvYnVsa19zZXVyYXQkY2VsbF90eXBlIDwtICJDRDRUIgpgYGAKCiMgMy4gREUgdXNpbmcgTElCUkEKYGBge3IgLCBmaWcuaGVpZ2h0PTE0LCBmaWcud2lkdGg9MTh9CmxpYnJhX3Rlc3QgPC1wc2V1ZG9idWxrX3NldXJhdAoKIyBMb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZWRnZVIpCmxpYnJhcnkoTGlicmEpCgojIEFzc3VtaW5nICdiYXRjaCcgaXMgdGhlIGNvbHVtbiBpbiB5b3VyIGRhdGEgdGhhdCBjb250YWlucyBiYXRjaCBpbmZvcm1hdGlvbgojIFJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyB1c2luZyBMaWJyYSB3aXRoIGJhdGNoIGVmZmVjdCBjb3JyZWN0aW9uCkRFX3Jlc3VsdHMgPC0gcnVuX2RlKAogIGxpYnJhX3Rlc3QsCiAgY2VsbF90eXBlX2NvbCA9ICJjZWxsX3R5cGUiLAogIHJlcGxpY2F0ZV9jb2wgPSAicmVwbGljYXRlIiwgIAogIGxhYmVsX2NvbCA9ICJsYWJlbCIsCiAgZGVfZmFtaWx5ID0gInBzZXVkb2J1bGsiLAogIGRlX21ldGhvZCA9ICJlZGdlUiIsCiAgZGVfdHlwZSA9ICJMUlQiLAogIGNvdmFyaWF0ZXMgPSBjKCJjZWxsLWxpbmUiKSAgIyBJbmNsdWRlIGJhdGNoIGFzIGEgY292YXJpYXRlCikKCgpgYGAKCgojIDQuIFZvbGNhbm8gUGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQoKIyBFeHRyYWN0IHJlc3VsdHMgZnJvbSBMaWJyYQpERV9yZXN1bHRzX2RmIDwtIGFzLmRhdGEuZnJhbWUoREVfcmVzdWx0cykKCiMgU2F2ZSByZXN1bHRzIHRvIENTVgp3cml0ZS5jc3YoREVfcmVzdWx0c19kZiwgZmlsZSA9ICIxLVBzZXVkb2J1bGtfZWRnZVJfTFJUX0RFX3dpdGhfbGlicmEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIEVuc3VyZSBsb2dGQyBhbmQgcC12YWx1ZSBjb2x1bW5zIGFyZSBuYW1lZCBjb3JyZWN0bHkKY29sbmFtZXMoREVfcmVzdWx0c19kZikKCiMgRmlsdGVyaW5nIGZvciBzaWduaWZpY2FudCBnZW5lczoKdm9sY2Fub19kYXRhIDwtIERFX3Jlc3VsdHNfZGYgJT4lCiAgbXV0YXRlKAogICAgc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKAogICAgICBwX3ZhbF9hZGogPCAwLjA1ICYgYXZnX2xvZ0ZDID4gMiB+ICJVcHJlZ3VsYXRlZCIsCiAgICAgIHBfdmFsX2FkaiA8IDAuMDUgJiBhdmdfbG9nRkMgPCAtMiB+ICJEb3ducmVndWxhdGVkIiwKICAgICAgVFJVRSB+ICJOb3QgU2lnbmlmaWNhbnQiCiAgICApCiAgKQpnZ3Bsb3Qodm9sY2Fub19kYXRhLCBhZXMoeCA9IGF2Z19sb2dGQywgeSA9IC1sb2cxMChwX3ZhbF9hZGopLCBjb2xvciA9IHNpZ25pZmljYW5jZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJVcHJlZ3VsYXRlZCIgPSAicmVkIiwgIkRvd25yZWd1bGF0ZWQiID0gImJsdWUiLCAiTm90IFNpZ25pZmljYW50IiA9ICJncmV5IikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiVm9sY2FubyBQbG90OiBQc2V1ZG9idWxrIERFU2VxMiBBbmFseXNpcyIsCiAgICAgICB4ID0gIkxvZzIgRm9sZCBDaGFuZ2UiLAogICAgICAgeSA9ICItTG9nMTAgQWRqdXN0ZWQgUC1WYWx1ZSIsCiAgICAgICBjb2xvciA9ICJTaWduaWZpY2FuY2UiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0yLCAyKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKQoKCmBgYAoKCgoKIyMgVm9sY2FubyBQbG90CmBgYHtyICwgZmlnLmhlaWdodD0xNCwgZmlnLndpZHRoPTE4fQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCkVuaGFuY2VkVm9sY2FubygKICBERV9yZXN1bHRzLCAKICBsYWIgPSBERV9yZXN1bHRzJGdlbmUsICAjIExhYmVscyBmb3IgZ2VuZXMKICB4ID0gJ2F2Z19sb2dGQycsICAgICAgICAgICAgICMgTG9nMiBGb2xkIENoYW5nZSAoY29ycmVjdGVkIG5hbWUpCiAgeSA9ICdwX3ZhbF9hZGonLCAgICAgICAgICAgICAjIEFkanVzdGVkIFAtdmFsdWUKICB0aXRsZSA9ICdWb2xjYW5vIFBsb3Q6IFBzZXVkb2J1bGsgREVTZXEyIEFuYWx5c2lzJywKICBzdWJ0aXRsZSA9ICdNYWxpZ25hbnQgdnMgTm9ybWFsIENENFQgQ2VsbHMnLAogIHBDdXRvZmYgPSAwLjA1LCAgICAgICAgICAgICAgIyBBZGp1c3RlZCBwLXZhbHVlIHRocmVzaG9sZAogIEZDY3V0b2ZmID0gMiwgICAgICAgICAgICAgICAgIyBGb2xkIENoYW5nZSB0aHJlc2hvbGQKICBwb2ludFNpemUgPSAyLjAsICAgICAgICAgICAgICMgQWRqdXN0IHBvaW50IHNpemUKICBsYWJTaXplID0gNC4wLCAgICAgICAgICAgICAgICMgQWRqdXN0IGxhYmVsIHNpemUKICBjb2wgPSBjKCJibGFjayIsICJncmV5IiwgImJsdWUiLCAicmVkIiksICMgQ29sb3IgY29kaW5nCiAgY29sQWxwaGEgPSAwLjYsICAgICAgICAgICAgICAjIFRyYW5zcGFyZW5jeSBmb3IgcG9pbnRzCiAgbGVnZW5kTGFiZWxzID0gYygiTlMiLCAiTG9nMkZDIiwgIlAtdmFsdWUiLCAiQm90aCIpLAogIGxlZ2VuZFBvc2l0aW9uID0gInJpZ2h0IiwKICBsZWdlbmRMYWJTaXplID0gMTAsCiAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLCAgICAgICAjIENvbm5lY3QgZ2VuZSBsYWJlbHMKICB3aWR0aENvbm5lY3RvcnMgPSAwLjUsCiAgdmxpbmUgPSBjKC0yLCAyKSwgICAgICAgICAgICAjIFZlcnRpY2FsIGxpbmVzIGF0IGxvZ0ZDIMKxMgogIGhsaW5lID0gLWxvZzEwKDAuMDUpLCAgICAgICAgIyBIb3Jpem9udGFsIGxpbmUgYXQgYWRqdXN0ZWQgcC12YWx1ZSAwLjA1CiAgYm9yZGVyID0gImZ1bGwiCikKCmBgYAoKCgoKIyMgVm9sY2FubyBQbG90CmBgYHtyICwgZmlnLmhlaWdodD0xNCwgZmlnLndpZHRoPTE4fQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKCiMgRXh0cmFjdCByZXN1bHRzIGZyb20gTGlicmEKREVfcmVzdWx0c19kZiA8LSBhcy5kYXRhLmZyYW1lKERFX3Jlc3VsdHMpCgojIEVuc3VyZSBjb3JyZWN0IGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhERV9yZXN1bHRzX2RmKQoKIyBEZWZpbmUgc2lnbmlmaWNhbmNlIGNhdGVnb3JpZXMKdm9sY2Fub19kYXRhIDwtIERFX3Jlc3VsdHNfZGYgJT4lCiAgbXV0YXRlKAogICAgc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKAogICAgICBwX3ZhbF9hZGogPCAwLjA1ICYgYXZnX2xvZ0ZDID4gMiB+ICJVcHJlZ3VsYXRlZCIsCiAgICAgIHBfdmFsX2FkaiA8IDAuMDUgJiBhdmdfbG9nRkMgPCAtMiB+ICJEb3ducmVndWxhdGVkIiwKICAgICAgVFJVRSB+ICJOb3QgU2lnbmlmaWNhbnQiCiAgICApCiAgKQoKIyBTZWxlY3QgZ2VuZXMgdG8gbGFiZWw6IHBfdmFsX2FkaiA8IDFlLTUwIE9SIGxvZ0ZDID4gMiBPUiBsb2dGQyA8IC0yCnRvcF9nZW5lcyA8LSB2b2xjYW5vX2RhdGEgJT4lCiAgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUgfCBhdmdfbG9nRkMgPiAyIHwgYXZnX2xvZ0ZDIDwgLTIpCgpnZ3Bsb3Qodm9sY2Fub19kYXRhLCBhZXMoeCA9IGF2Z19sb2dGQywgeSA9IC1sb2cxMChwX3ZhbF9hZGopLCBjb2xvciA9IHNpZ25pZmljYW5jZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaXplID0gMikgKyAgIyBNYWluIHBvaW50cwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJVcHJlZ3VsYXRlZCIgPSAicmVkIiwgIkRvd25yZWd1bGF0ZWQiID0gImJsdWUiLCAiTm90IFNpZ25pZmljYW50IiA9ICJncmV5IikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiVm9sY2FubyBQbG90OiBQc2V1ZG9idWxrIERFU2VxMiBBbmFseXNpcyIsCiAgICAgICB4ID0gIkxvZzIgRm9sZCBDaGFuZ2UiLAogICAgICAgeSA9ICItTG9nMTAgQWRqdXN0ZWQgUC1WYWx1ZSIsCiAgICAgICBjb2xvciA9ICJTaWduaWZpY2FuY2UiKSArCgogICMgQWRkIGdlbmUgbGFiZWxzIFdJVEhPVVQgYW55IGxpbmVzIGNvbm5lY3RpbmcgdGhlbQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gdG9wX2dlbmVzLCAKICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gZ2VuZSksICAKICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsIGJveC5wYWRkaW5nID0gMC4zLCBtYXgub3ZlcmxhcHMgPSAxNSwgc2VnbWVudC5jb2xvciA9IE5BKSArICAKCiAgIyBBZGQgdGhyZXNob2xkIGxpbmVzCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMiwgMiksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgKyAgIyBsb2dGQyB0aHJlc2hvbGRzCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICsgICMgcC12YWx1ZSB0aHJlc2hvbGQKCiAgeWxpbSgwLCA3MCkgICMgU2V0IG1heCB5LWF4aXMgbGltaXQgdG8gYXZvaWQgZXh0cmVtZSB2YWx1ZXMKCgpgYGAKIyMgVm9sY2FubyBQbG90CmBgYHtyICwgZmlnLmhlaWdodD0xNCwgZmlnLndpZHRoPTE4fQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKCiMgRXh0cmFjdCByZXN1bHRzIGZyb20gTGlicmEKREVfcmVzdWx0c19kZiA8LSBhcy5kYXRhLmZyYW1lKERFX3Jlc3VsdHMpCgojIEVuc3VyZSBjb3JyZWN0IGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhERV9yZXN1bHRzX2RmKQoKIyBEZWZpbmUgc2lnbmlmaWNhbmNlIGNhdGVnb3JpZXMKdm9sY2Fub19kYXRhIDwtIERFX3Jlc3VsdHNfZGYgJT4lCiAgbXV0YXRlKAogICAgc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKAogICAgICBwX3ZhbF9hZGogPCAxZS0yMCAmIGF2Z19sb2dGQyA+IDIgfiAiSGlnaGx5IFVwcmVndWxhdGVkIiwKICAgICAgcF92YWxfYWRqIDwgMWUtMjAgJiBhdmdfbG9nRkMgPCAtMiB+ICJIaWdobHkgRG93bnJlZ3VsYXRlZCIsCiAgICAgIHBfdmFsX2FkaiA8IDAuMDUgJiBhdmdfbG9nRkMgPiAyIH4gIlVwcmVndWxhdGVkIiwKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2dGQyA8IC0yIH4gIkRvd25yZWd1bGF0ZWQiLAogICAgICBUUlVFIH4gIk5vdCBTaWduaWZpY2FudCIKICAgICkKICApCgojIFNlbGVjdCBvbmx5IHZlcnkgc2lnbmlmaWNhbnQgZ2VuZXMgZm9yIGxhYmVsaW5nCnRvcF9nZW5lcyA8LSB2b2xjYW5vX2RhdGEgJT4lCiAgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUgJiAoYXZnX2xvZ0ZDID4gMiB8IGF2Z19sb2dGQyA8IC0yKSkKCmdncGxvdCh2b2xjYW5vX2RhdGEsIGFlcyh4ID0gYXZnX2xvZ0ZDLCB5ID0gLWxvZzEwKHBfdmFsX2FkaiksIGNvbG9yID0gc2lnbmlmaWNhbmNlKSkgKwogIAogICMgTWFpbiBwb2ludHMKICBnZW9tX3BvaW50KGFscGhhID0gMC43LCBzaXplID0gMi41KSArCiAgCiAgIyBIaWdobGlnaHQgaGlnaGx5IHNpZ25pZmljYW50IGdlbmVzIHdpdGggbGFyZ2VyIHBvaW50cwogIGdlb21fcG9pbnQoZGF0YSA9IHRvcF9nZW5lcywgYWVzKHggPSBhdmdfbG9nRkMsIHkgPSAtbG9nMTAocF92YWxfYWRqKSksIAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgc2hhcGUgPSAyMSwgZmlsbCA9ICJibGFjayIpICsKCiAgIyBDdXN0b20gY29sb3Igc2NoZW1lCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoCiAgICAiSGlnaGx5IFVwcmVndWxhdGVkIiA9ICJkYXJrcmVkIiwKICAgICJIaWdobHkgRG93bnJlZ3VsYXRlZCIgPSAiZGFya2JsdWUiLAogICAgIlVwcmVndWxhdGVkIiA9ICJyZWQiLAogICAgIkRvd25yZWd1bGF0ZWQiID0gImJsdWUiLAogICAgIk5vdCBTaWduaWZpY2FudCIgPSAiZ3JleSIKICApKSArCgogICMgQWRkIGdlbmUgbGFiZWxzIChvbmx5IGZvciBoaWdobHkgc2lnbmlmaWNhbnQgZ2VuZXMpCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB0b3BfZ2VuZXMsIGFlcyhsYWJlbCA9IGdlbmUpLCAgCiAgICAgICAgICAgICAgICAgIHNpemUgPSA0LCBib3gucGFkZGluZyA9IDAuNSwgbWF4Lm92ZXJsYXBzID0gMTAsIHNlZ21lbnQuY29sb3IgPSBOQSkgKwogIAogICMgQWRkIHRocmVzaG9sZCBsaW5lcwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTIsIDIpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICsgIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArICAKCiAgIyBJbXByb3ZlIHRoZW1lCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGxhYnModGl0bGUgPSAiVm9sY2FubyBQbG90OiBQc2V1ZG9idWxrIERFU2VxMiBBbmFseXNpcyIsCiAgICAgICB4ID0gIkxvZzIgRm9sZCBDaGFuZ2UiLAogICAgICAgeSA9ICItTG9nMTAgQWRqdXN0ZWQgUC1WYWx1ZSIsCiAgICAgICBjb2xvciA9ICJTaWduaWZpY2FuY2UiKSArCgogIHlsaW0oMCwgNTApICAjIEF2b2lkIGV4dHJlbWUgc2NhbGluZyBpc3N1ZXMKCgpgYGAKCiMgNS4gU3VtbWFyaXplIE1hcmtlcnMKYGBge3IgLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9Cm1hcmtlcnMgPC0gREVfcmVzdWx0c19kZgoKc3VtbWFyaXplX21hcmtlcnMgPC0gZnVuY3Rpb24obWFya2VycykgewogIG51bV9wdmFsMCA8LSBzdW0obWFya2VycyRwX3ZhbF9hZGogPT0gMCkKICBudW1fcHZhbDEgPC0gc3VtKG1hcmtlcnMkcF92YWxfYWRqID09IDEpCiAgbnVtX3NpZ25pZmljYW50IDwtIHN1bShtYXJrZXJzJHBfdmFsX2FkaiA8IDAuMDUpCiAgbnVtX3VwcmVndWxhdGVkIDwtIHN1bShtYXJrZXJzJGF2Z19sb2dGQyA+IDEpCiAgbnVtX2Rvd25yZWd1bGF0ZWQgPC0gc3VtKG1hcmtlcnMkYXZnX2xvZ0ZDIDwgLTEpCiAgCiAgY2F0KCJOdW1iZXIgb2YgZ2VuZXMgd2l0aCBwX3ZhbF9hZGogPSAwOiIsIG51bV9wdmFsMCwgIlxuIikKICBjYXQoIk51bWJlciBvZiBnZW5lcyB3aXRoIHBfdmFsX2FkaiA9IDE6IiwgbnVtX3B2YWwxLCAiXG4iKQogIGNhdCgiTnVtYmVyIG9mIHNpZ25pZmljYW50IGdlbmVzIChwX3ZhbF9hZGogPCAwLjA1KToiLCBudW1fc2lnbmlmaWNhbnQsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXMgKGF2Z19sb2dGQyA+IDEpOiIsIG51bV91cHJlZ3VsYXRlZCwgIlxuIikKICBjYXQoIk51bWJlciBvZiBkb3ducmVndWxhdGVkIGdlbmVzIChhdmdfbG9nRkMgPCAxKToiLCBudW1fZG93bnJlZ3VsYXRlZCwgIlxuIikKfQoKY2F0KCJNYXJrZXJzMSBTdW1tYXJ5IChNQVNUIHdpdGggQmF0Y2ggQ29ycmVjdGlvbik6XG4iKQoKc3VtbWFyaXplX21hcmtlcnMobWFya2VycykKYGBgCgoKIyA5LiBFbmhhbmNlZFZvbGNhbm8gcGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgRmlsdGVyIGdlbmVzIGJhc2VkIG9uIGxvd2VzdCBwLXZhbHVlcyBidXQgaW5jbHVkZSBhbGwgZ2VuZXMKZmlsdGVyZWRfZ2VuZXMgPC0gbWFya2VycyAlPiUKICBhcnJhbmdlKHBfdmFsX2FkaiwgZGVzYyhhYnMoYXZnX2xvZ0ZDKSkpCgojIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3Qgd2l0aCB0aGUgZmlsdGVyZWQgZGF0YQpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wMDAwOTA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgcEN1dG9mZiA9IDAuMDAwMDkwNSwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIAogIGxhYkNvbCA9ICdibGFjaycsCiAgbGFiRmFjZSA9ICdib2xkJywKICBib3hlZExhYmVscyA9IEZBTFNFLCAgIyBTZXQgdG8gRkFMU0UgdG8gcmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdsaWdodGJsdWUnLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9taXplIHBvaW50IGNvbG9ycwogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjBdICAjIE9ubHkgbGFiZWwgc2lnbmlmaWNhbnQgZ2VuZXMKKQoKYGBgCgoKCiMjIEVuaGFuY2VkVm9sY2FubyBwbG90CmBgYHtyICwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQoKbGlicmFyeShkcGx5cikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBGaWx0ZXIgZ2VuZXMgYmFzZWQgb24gbG93ZXN0IHAtdmFsdWVzIGJ1dCBpbmNsdWRlIGFsbCBnZW5lcwpmaWx0ZXJlZF9nZW5lcyA8LSBtYXJrZXJzICU+JQogIGFycmFuZ2UocF92YWxfYWRqLCBkZXNjKGFicyhhdmdfbG9nRkMpKSkKCiMgQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gcGxvdCB3aXRoIHRoZSBmaWx0ZXJlZCBkYXRhCkVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjAwMDA5MDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjAsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2dGQyIsIAogIHkgPSAicF92YWxfYWRqIiwKICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMoY2VsbCBsaW5lcykgdnMgbm9ybWFsIENENCBUIGNlbGxzIiwKICBwQ3V0b2ZmID0gMWUtNCwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIAogIGxhYkNvbCA9ICdibGFjaycsCiAgbGFiRmFjZSA9ICdib2xkJywKICBib3hlZExhYmVscyA9IEZBTFNFLCAgIyBTZXQgdG8gRkFMU0UgdG8gcmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b21pemUgcG9pbnQgY29sb3JzCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0gICMgT25seSBsYWJlbCBzaWduaWZpY2FudCBnZW5lcwopCgoKCmBgYAoKIyMgQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gcGxvdApgYGB7ciBlbmhhbmNlZFYsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyA8LSBtYXJrZXJzCgpFbmhhbmNlZFZvbGNhbm8oTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzLAogICAgICAgICAgICAgICAgbGFiID0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUsCiAgICAgICAgICAgICAgICB4ID0gImF2Z19sb2dGQyIsCiAgICAgICAgICAgICAgICB5ID0gInBfdmFsX2FkaiIsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJNQVNUIHdpdGggQmF0Y2ggQ29ycmVjdGlvbiAoQWxsIEdlbmVzKSIsCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMS4wKQoKCkVuaGFuY2VkVm9sY2FubyhNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsIAogICAgICAgICAgICAgICAgbGFiID0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUsCiAgICAgICAgICAgICAgICB4ID0gImF2Z19sb2dGQyIsIAogICAgICAgICAgICAgICAgeSA9ICJwX3ZhbF9hZGoiLAogICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gYygnRVBDQU0nLCAnQkNBVDEnLCAnS0lSM0RMMicsICdGT1hNMScsICdUV0lTVDEnLCAnVE5GU0Y5JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDRDgwJywgICdJTDFCJywgJ1JQUzRZMScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUw3UicsICdUQ0Y3JywgICdNS0k2NycsICdDRDcwJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJTDJSQScsJ1RSQlY2LTInLCAnVFJCVjEwLTMnLCAnVFJCVjQtMicsICdUUkJWOScsICdUUkJWNy05JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUUkFWMTItMScsICdDRDhCJywgJ0ZDR1IzQScsICdHTkxZJywgJ0ZPWFAzJywgJ1NFTEwnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dJTUFQMScsICdSSVBPUjInLCAnTEVGMScsICdIT1hDOScsICdTUDUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ0NMMTcnLCAnRVRWNCcsICdUSFkxJywgJ0ZPWEEyJywgJ0lUR0FEJywgJ1MxMDBQJywgJ1RCWDQnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0lEMScsICdYQ0wxJywgJ1NPWDInLCAnQ0QyNycsICdDRDI4JywnUExTMycsJ0NENzAnLCdSQUIyNScgLCAnVFJCVjI3JywgJ1RSQlYyJyksCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMoY2VsbCBsaW5lcykgdnMgbm9ybWFsIENENCBUIGNlbGxzIiwKICAgICAgICAgICAgICAgIHhsYWIgPSBicXVvdGUofkxvZ1syXX4gJ2ZvbGQgY2hhbmdlJyksCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMS41LCAKICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDMuMCwKICAgICAgICAgICAgICAgIGxhYlNpemUgPSA1LjAsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IFRSVUUsCiAgICAgICAgICAgICAgICBjb2xBbHBoYSA9IDAuNSwKICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICAgICAgICAgICAgICAgIGxlZ2VuZExhYlNpemUgPSAxMCwKICAgICAgICAgICAgICAgIGxlZ2VuZEljb25TaXplID0gNC4wLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC41LAogICAgICAgICAgICAgICAgY29sQ29ubmVjdG9ycyA9ICdncmV5NTAnLAogICAgICAgICAgICAgICAgYXJyb3doZWFkcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMzApCgoKbGlicmFyeShkcGx5cikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBGaWx0ZXIgZ2VuZXMgYmFzZWQgb24gbG93ZXN0IHAtdmFsdWVzIGJ1dCBpbmNsdWRlIGFsbCBnZW5lcwpmaWx0ZXJlZF9nZW5lcyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgJT4lCiAgYXJyYW5nZShwX3ZhbF9hZGosIGRlc2MoYWJzKGF2Z19sb2dGQykpKQoKIyBDcmVhdGUgdGhlIEVuaGFuY2VkVm9sY2FubyBwbG90IHdpdGggdGhlIGZpbHRlcmVkIGRhdGEKRW5oYW5jZWRWb2xjYW5vKAogIGZpbHRlcmVkX2dlbmVzLCAKICBsYWIgPSBpZmVsc2UoZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjAsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2dGQyIsIAogIHkgPSAicF92YWxfYWRqIiwKICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMoY2VsbCBsaW5lcykgdnMgbm9ybWFsIENENCBUIGNlbGxzIiwKICBwQ3V0b2ZmID0gMC4wNSwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIAogIGxhYkNvbCA9ICdibGFjaycsCiAgbGFiRmFjZSA9ICdib2xkJywKICBib3hlZExhYmVscyA9IEZBTFNFLCAgIyBTZXQgdG8gRkFMU0UgdG8gcmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b21pemUgcG9pbnQgY29sb3JzCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0gICMgT25seSBsYWJlbCBzaWduaWZpY2FudCBnZW5lcwopCgoKCkVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzIChjZWxsIGxpbmVzKSB2cyBOb3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHN1YnRpdGxlID0gIkhpZ2hsaWdodGluZyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMiLAogIHBDdXRvZmYgPSAwLjA1LAogIEZDY3V0b2ZmID0gMS4wLAogIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICBjb2xBbHBoYSA9IDAuOCwgICMgU2xpZ2h0IHRyYW5zcGFyZW5jeSBmb3Igbm9uLXNpZ25pZmljYW50IHBvaW50cwogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b20gY29sb3Igc2NoZW1lCiAgZ3JpZGxpbmVzLm1ham9yID0gVFJVRSwKICBncmlkbGluZXMubWlub3IgPSBGQUxTRSwKICBzZWxlY3RMYWIgPSBmaWx0ZXJlZF9nZW5lcyRnZW5lW2ZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wXQopIAoKCmBgYAoKIyMgZ2dwbG90MiBmb3IgVm9sY2FubwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKCiMgSWRlbnRpZnkgdG9wIGFuZCBib3R0b20gZ2VuZXMKdG9wX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxsc1tNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcF92YWxfYWRqIDwgMC4wNSAmIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRhdmdfbG9nRkMgPiAwLjUsIF0KYm90dG9tX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxsc1tNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcF92YWxfYWRqIDwgMC4wNSAmIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRhdmdfbG9nRkMgPCAtMC41LCBdCgojIENyZWF0ZSBhIG5ldyBjb2x1bW4gZm9yIGNvbG9yIGJhc2VkIG9uIHNpZ25pZmljYW5jZQpNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkY29sb3IgPC0gaWZlbHNlKE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRhdmdfbG9nRkMgPiAwLjUsICJVcHJlZ3VsYXRlZCBnZW5lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDIDwgLTAuNSwgIkRvd25yZWd1bGF0ZWQgZ2VuZXMiLCAiTm9uc2lnbmlmaWNhbnQiKSkKCiMgQ3JlYXRlIGEgdm9sY2FubyBwbG90CmdncGxvdChNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsIGFlcyh4ID0gYXZnX2xvZ0ZDLCB5ID0gLWxvZzEwKHBfdmFsX2FkaikpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb2xvciksIGFscGhhID0gMC43LCBzaXplID0gMikgKwogIAogICMgQWRkIGxhYmVscyBmb3IgdG9wIGFuZCBib3R0b20gZ2VuZXMKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IHRvcF9nZW5lcywgYWVzKGxhYmVsID0gZ2VuZSksIGNvbG9yID0gImJsYWNrIiwgdmp1c3QgPSAxLCBmb250ZmFjZSA9ICJib2xkIikgKwogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gYm90dG9tX2dlbmVzLCBhZXMobGFiZWwgPSBnZW5lKSwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBmb250ZmFjZSA9ICJib2xkIikgKwogIAogICMgQ3VzdG9taXplIGxhYmVscyBhbmQgdGl0bGUKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdCIsCiAgICAgICB4ID0gImxvZzIgRm9sZCBDaGFuZ2UiLAogICAgICAgeSA9ICItbG9nMTAocC12YWx1ZSkiKSArCiAgCiAgIyAjIEFkZCBzaWduaWZpY2FuY2UgdGhyZXNob2xkIGxpbmVzCiAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjAwMDAxKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTAuNSwgMC41KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgCiAgIyBTZXQgY29sb3JzIGZvciB0b3AgYW5kIGJvdHRvbSBnZW5lcwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJVcHJlZ3VsYXRlZCBnZW5lcyIgPSAicmVkIiwgIkRvd25yZWd1bGF0ZWQgZ2VuZXMiID0gImJsdWUiLCAiTm9uc2lnbmlmaWNhbnQiID0gImRhcmtncmV5IikpICsKICAKICAjIEN1c3RvbWl6ZSB0aGVtZSBpZiBuZWVkZWQKICB0aGVtZV9taW5pbWFsKCkKCgoKCgpgYGAKCiMjIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3QKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCmxpYnJhcnkoZHBseXIpCgojIERlZmluZSB0aGUgb3V0cHV0IGRpcmVjdG9yeQpvdXRwdXRfZGlyIDwtICJNYWxpZ25hbnRfdnNfQ29udHJvbCIKZGlyLmNyZWF0ZShvdXRwdXRfZGlyLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKCiMgRmlyc3QgVm9sY2FubyBQbG90CnAxIDwtIEVuaGFuY2VkVm9sY2FubygKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsCiAgbGFiID0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUsCiAgeCA9ICJhdmdfbG9nRkMiLAogIHkgPSAicF92YWxfYWRqIiwKICB0aXRsZSA9ICJNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMiLAogIHBDdXRvZmYgPSAxZS00LAogIEZDY3V0b2ZmID0gMS4wCikKcHJpbnQocDEpICAjIERpc3BsYXkgaW4gbm90ZWJvb2sKZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJWb2xjYW5vUGxvdDEucG5nIiksIHBsb3QgPSBwMSwgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCiMgU2Vjb25kIFZvbGNhbm8gUGxvdCB3aXRoIHNlbGVjdGVkIGdlbmVzCnAyIDwtIEVuaGFuY2VkVm9sY2FubygKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsIAogIGxhYiA9IE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRnZW5lLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHNlbGVjdExhYiA9IGMoJ0VQQ0FNJywgJ0JDQVQxJywgJ0tJUjNETDInLCAnRk9YTTEnLCAnVFdJU1QxJywgJ1RORlNGOScsIAogICAgICAgICAgICAgICAgJ0NEODAnLCAgJ0lMMUInLCAnUlBTNFkxJywgCiAgICAgICAgICAgICAgICAnSUw3UicsICdUQ0Y3JywgICdNS0k2NycsICdDRDcwJywgCiAgICAgICAgICAgICAgICAnSUwyUkEnLCdUUkJWNi0yJywgJ1RSQlYxMC0zJywgJ1RSQlY0LTInLCAnVFJCVjknLCAnVFJCVjctOScsIAogICAgICAgICAgICAgICAgJ1RSQVYxMi0xJywgJ0NEOEInLCAnRkNHUjNBJywgJ0dOTFknLCAnRk9YUDMnLCAnU0VMTCcsIAogICAgICAgICAgICAgICAgJ0dJTUFQMScsICdSSVBPUjInLCAnTEVGMScsICdIT1hDOScsICdTUDUnLAogICAgICAgICAgICAgICAgJ0NDTDE3JywgJ0VUVjQnLCAnVEhZMScsICdGT1hBMicsICdJVEdBRCcsICdTMTAwUCcsICdUQlg0JywgCiAgICAgICAgICAgICAgICAnSUQxJywgJ1hDTDEnLCAnU09YMicsICdDRDI3JywgJ0NEMjgnLCdQTFMzJywnQ0Q3MCcsJ1JBQjI1JyAsICdUUkJWMjcnLCAnVFJCVjInKSwKICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMoY2VsbCBsaW5lcykgdnMgbm9ybWFsIENENCBUIGNlbGxzIiwKICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+ICdmb2xkIGNoYW5nZScpLAogIHBDdXRvZmYgPSAxZS00LAogIEZDY3V0b2ZmID0gMS41LCAKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBib3hlZExhYmVscyA9IFRSVUUsCiAgY29sQWxwaGEgPSAwLjUsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogIGxlZ2VuZExhYlNpemUgPSAxMCwKICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICBkcmF3Q29ubmVjdG9ycyA9IFRSVUUsCiAgd2lkdGhDb25uZWN0b3JzID0gMC41LAogIGNvbENvbm5lY3RvcnMgPSAnZ3JleTUwJywKICBhcnJvd2hlYWRzID0gRkFMU0UsCiAgbWF4Lm92ZXJsYXBzID0gMzAKKQpwcmludChwMikgICMgRGlzcGxheSBpbiBub3RlYm9vawpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgIlZvbGNhbm9QbG90Mi5wbmciKSwgcGxvdCA9IHAyLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQoKIyBGaWx0ZXJpbmcgZ2VuZXMKZmlsdGVyZWRfZ2VuZXMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzICU+JQogIGFycmFuZ2UocF92YWxfYWRqLCBkZXNjKGFicyhhdmdfbG9nRkMpKSkKCiMgVGhpcmQgVm9sY2FubyBQbG90IC0gRmlsdGVyaW5nIGJ5IHAtdmFsdWUgYW5kIGxvZ0ZDCnAzIDwtIEVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAxZS00ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgcEN1dG9mZiA9IDFlLTQsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCAKICBsYWJDb2wgPSAnYmxhY2snLAogIGxhYkZhY2UgPSAnYm9sZCcsCiAgYm94ZWRMYWJlbHMgPSBGQUxTRSwgICMgUmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b21pemUgcG9pbnQgY29sb3JzCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0KKQpwcmludChwMykgICMgRGlzcGxheSBpbiBub3RlYm9vawpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgIlZvbGNhbm9QbG90My5wbmciKSwgcGxvdCA9IHAzLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQoKIyBGb3VydGggVm9sY2FubyBQbG90IC0gTW9yZSByZWZpbmVkIGZpbHRlcmluZwpwNCA8LSBFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMWUtNCAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyAoY2VsbCBsaW5lcykgdnMgTm9ybWFsIENENCBUIGNlbGxzIiwKICBzdWJ0aXRsZSA9ICJIaWdobGlnaHRpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIiwKICBwQ3V0b2ZmID0gMWUtNCwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgY29sQWxwaGEgPSAwLjgsICAjIFNsaWdodCB0cmFuc3BhcmVuY3kgZm9yIG5vbi1zaWduaWZpY2FudCBwb2ludHMKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9tIGNvbG9yIHNjaGVtZQogIGdyaWRsaW5lcy5tYWpvciA9IFRSVUUsCiAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0KKQpwcmludChwNCkgICMgRGlzcGxheSBpbiBub3RlYm9vawpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlLnBhdGgob3V0cHV0X2RpciwgIlZvbGNhbm9QbG90NC5wbmciKSwgcGxvdCA9IHA0LCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQoKbWVzc2FnZSgiQWxsIHZvbGNhbm8gcGxvdHMgaGF2ZSBiZWVuIGRpc3BsYXllZCBhbmQgc2F2ZWQgc3VjY2Vzc2Z1bGx5IGluIHRoZSAnTDFfdnNfQ29udHJvbCcgZm9sZGVyLiIpCgoKCmBgYAoKCiMgMTAuIEVucmljaG1lbnQgQW5hbHlzaXMtMQpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KFJlYWN0b21lUEEpCmxpYnJhcnkoRE9TRSkgIyBGb3IgR1NFQSBhbmFseXNpcwpsaWJyYXJ5KGdncGxvdDIpICMgRW5zdXJlIGdncGxvdDIgaXMgYXZhaWxhYmxlIGZvciBwbG90dGluZwoKIyBEZWZpbmUgdGhyZXNob2xkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBzZWxlY3Rpb24gKG1vZGlmaWVkIHRocmVzaG9sZHMpCmxvZ0ZDX3VwX3RocmVzaG9sZCA8LSAyICAgICAgICAgICMgVXByZWd1bGF0ZWQgbG9nRkMgdGhyZXNob2xkCmxvZ0ZDX2Rvd25fdGhyZXNob2xkIDwtIC0yICAgICAgICMgRG93bnJlZ3VsYXRlZCBsb2dGQyB0aHJlc2hvbGQKcHZhbF90aHJlc2hvbGQgPC0gMC4wNSAgIyBwLXZhbHVlIHRocmVzaG9sZCBhcyBzcGVjaWZpZWQKCiMgTG9hZCB5b3VyIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIHJlc3VsdHMgKG1vZGlmeSBiYXNlZCBvbiBhY3R1YWwgZGF0YSBzdHJ1Y3R1cmUpCiMgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIHJlYWQuY3N2KCJZb3VyX0RFX1Jlc3VsdHNfRmlsZS5jc3YiKQoKIyBTZWxlY3QgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKdXByZWd1bGF0ZWRfZ2VuZXMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzWwogIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRhdmdfbG9nRkMgPiBsb2dGQ191cF90aHJlc2hvbGQgJiAKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcF92YWxfYWRqIDwgcHZhbF90aHJlc2hvbGQsIF0KCmRvd25yZWd1bGF0ZWRfZ2VuZXMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzWwogIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRhdmdfbG9nRkMgPCBsb2dGQ19kb3duX3RocmVzaG9sZCAmIAogIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRwX3ZhbF9hZGogPCBwdmFsX3RocmVzaG9sZCwgXQoKIyBDaGVjayBmb3IgbWlzc2luZyBnZW5lcyAoTkFzKSBpbiB0aGUgZ2VuZSBjb2x1bW4gYW5kIHJlbW92ZSB0aGVtCnVwcmVndWxhdGVkX2dlbmVzIDwtIG5hLm9taXQodXByZWd1bGF0ZWRfZ2VuZXMpCmRvd25yZWd1bGF0ZWRfZ2VuZXMgPC0gbmEub21pdChkb3ducmVndWxhdGVkX2dlbmVzKQoKIyBTYXZlIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmUgcmVzdWx0cyB0byBDU1YKd3JpdGUuY3N2KHVwcmVndWxhdGVkX2dlbmVzLCAiTWFsaWduYW50X3ZzX0NvbnRyb2wvdXByZWd1bGF0ZWRfZ2VuZXMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCndyaXRlLmNzdihkb3ducmVndWxhdGVkX2dlbmVzLCAiTWFsaWduYW50X3ZzX0NvbnRyb2wvZG93bnJlZ3VsYXRlZF9nZW5lcy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMgQ29udmVydCBnZW5lIHN5bWJvbHMgdG8gRW50cmV6IElEcyBmb3IgZW5yaWNobWVudCBhbmFseXNpcywgd2l0aCBjaGVja3MgZm9yIG1pc3NpbmcgdmFsdWVzCnVwcmVndWxhdGVkX2VudHJleiA8LSBiaXRyKHVwcmVndWxhdGVkX2dlbmVzJGdlbmUsIGZyb21UeXBlID0gIlNZTUJPTCIsIHRvVHlwZSA9ICJFTlRSRVpJRCIsIE9yZ0RiID0gb3JnLkhzLmVnLmRiKQpkb3ducmVndWxhdGVkX2VudHJleiA8LSBiaXRyKGRvd25yZWd1bGF0ZWRfZ2VuZXMkZ2VuZSwgZnJvbVR5cGUgPSAiU1lNQk9MIiwgdG9UeXBlID0gIkVOVFJFWklEIiwgT3JnRGIgPSBvcmcuSHMuZWcuZGIpCgojIENoZWNrIGZvciBtaXNzaW5nIEVudHJleiBJRHMKbWlzc2luZ191cHJlZ3VsYXRlZCA8LSB1cHJlZ3VsYXRlZF9nZW5lcyRnZW5lW2lzLm5hKHVwcmVndWxhdGVkX2VudHJleiRFTlRSRVpJRCldCm1pc3NpbmdfZG93bnJlZ3VsYXRlZCA8LSBkb3ducmVndWxhdGVkX2dlbmVzJGdlbmVbaXMubmEoZG93bnJlZ3VsYXRlZF9lbnRyZXokRU5UUkVaSUQpXQoKIyBQcmludCBvdXQgdGhlIG1pc3NpbmcgZ2VuZSBzeW1ib2xzIGZvciBkZWJ1Z2dpbmcKY2F0KCJNaXNzaW5nIHVwcmVndWxhdGVkIGdlbmVzOlxuIiwgbWlzc2luZ191cHJlZ3VsYXRlZCwgIlxuIikKY2F0KCJNaXNzaW5nIGRvd25yZWd1bGF0ZWQgZ2VuZXM6XG4iLCBtaXNzaW5nX2Rvd25yZWd1bGF0ZWQsICJcbiIpCgojIFJlbW92ZSBnZW5lcyB0aGF0IGNvdWxkbid0IGJlIG1hcHBlZCB0byBFbnRyZXogSURzCnVwcmVndWxhdGVkX2VudHJleiA8LSB1cHJlZ3VsYXRlZF9lbnRyZXokRU5UUkVaSURbIWlzLm5hKHVwcmVndWxhdGVkX2VudHJleiRFTlRSRVpJRCldCmRvd25yZWd1bGF0ZWRfZW50cmV6IDwtIGRvd25yZWd1bGF0ZWRfZW50cmV6JEVOVFJFWklEWyFpcy5uYShkb3ducmVndWxhdGVkX2VudHJleiRFTlRSRVpJRCldCgojIERlZmluZSBhIGZ1bmN0aW9uIHRvIHNhZmVseSBydW4gZW5yaWNobWVudCwgcGxvdCByZXN1bHRzLCBhbmQgc2F2ZSB0aGVtCnNhZmVfZW5yaWNoR08gPC0gZnVuY3Rpb24oZ2VuZV9saXN0LCB0aXRsZSwgZmlsZW5hbWUpIHsKICBpZiAobGVuZ3RoKGdlbmVfbGlzdCkgPiAwKSB7CiAgICByZXN1bHQgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVfbGlzdCwgT3JnRGIgPSBvcmcuSHMuZWcuZGIsIGtleVR5cGUgPSAiU1lNQk9MIiwKICAgICAgICAgICAgICAgICAgICAgICBvbnQgPSAiQlAiLCBwQWRqdXN0TWV0aG9kID0gIkJIIiwgcHZhbHVlQ3V0b2ZmID0gMC4wNSkKICAgIGlmICghaXMubnVsbChyZXN1bHQpICYmIG5yb3coYXMuZGF0YS5mcmFtZShyZXN1bHQpKSA+IDApIHsKICAgICAgcCA8LSBkb3RwbG90KHJlc3VsdCwgc2hvd0NhdGVnb3J5ID0gMTAsIHRpdGxlID0gdGl0bGUpCiAgICAgIHByaW50KHApICAKICAgICAgZ2dzYXZlKHBhc3RlMCgiTWFsaWduYW50X3ZzX0NvbnRyb2wvIiwgZ3N1YigiLmNzdiIsICJfZG90cGxvdC5wbmciLCBmaWxlbmFtZSkpLCBwbG90ID0gcCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQogICAgICB3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShyZXN1bHQpLCBmaWxlID0gcGFzdGUwKCJNYWxpZ25hbnRfdnNfQ29udHJvbC8iLCBmaWxlbmFtZSksIHJvdy5uYW1lcyA9IEZBTFNFKQogICAgfSBlbHNlIHsKICAgICAgbWVzc2FnZShwYXN0ZSgiTm8gc2lnbmlmaWNhbnQgZW5yaWNobWVudCBmb3VuZCBmb3I6IiwgdGl0bGUpKQogICAgfQogIH0gZWxzZSB7CiAgICBtZXNzYWdlKHBhc3RlKCJObyBnZW5lcyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogIH0KfQoKc2FmZV9lbnJpY2hLRUdHIDwtIGZ1bmN0aW9uKGVudHJlel9saXN0LCB0aXRsZSwgZmlsZW5hbWUpIHsKICBpZiAobGVuZ3RoKGVudHJlel9saXN0KSA+IDApIHsKICAgIHJlc3VsdCA8LSBlbnJpY2hLRUdHKGdlbmUgPSBlbnRyZXpfbGlzdCwgb3JnYW5pc20gPSAiaHNhIiwgcHZhbHVlQ3V0b2ZmID0gMC4wNSkKICAgIGlmICghaXMubnVsbChyZXN1bHQpICYmIG5yb3coYXMuZGF0YS5mcmFtZShyZXN1bHQpKSA+IDApIHsKICAgICAgcCA8LSBkb3RwbG90KHJlc3VsdCwgc2hvd0NhdGVnb3J5ID0gMTAsIHRpdGxlID0gdGl0bGUpCiAgICAgIHByaW50KHApCiAgICAgIGdnc2F2ZShwYXN0ZTAoIk1hbGlnbmFudF92c19Db250cm9sLyIsIGdzdWIoIi5jc3YiLCAiX2RvdHBsb3QucG5nIiwgZmlsZW5hbWUpKSwgcGxvdCA9IHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKICAgICAgd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUocmVzdWx0KSwgZmlsZSA9IHBhc3RlMCgiTWFsaWduYW50X3ZzX0NvbnRyb2wvIiwgZmlsZW5hbWUpLCByb3cubmFtZXMgPSBGQUxTRSkKICAgIH0gZWxzZSB7CiAgICAgIG1lc3NhZ2UocGFzdGUoIk5vIHNpZ25pZmljYW50IEtFR0cgcGF0aHdheXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICAgIH0KICB9IGVsc2UgewogICAgbWVzc2FnZShwYXN0ZSgiTm8gZ2VuZXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICB9Cn0KCnNhZmVfZW5yaWNoUmVhY3RvbWUgPC0gZnVuY3Rpb24oZW50cmV6X2xpc3QsIHRpdGxlLCBmaWxlbmFtZSkgewogIGlmIChsZW5ndGgoZW50cmV6X2xpc3QpID4gMCkgewogICAgcmVzdWx0IDwtIGVucmljaFBhdGh3YXkoZ2VuZSA9IGVudHJlel9saXN0LCBvcmdhbmlzbSA9ICJodW1hbiIsIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgICBpZiAoIWlzLm51bGwocmVzdWx0KSAmJiBucm93KGFzLmRhdGEuZnJhbWUocmVzdWx0KSkgPiAwKSB7CiAgICAgIHAgPC0gZG90cGxvdChyZXN1bHQsIHNob3dDYXRlZ29yeSA9IDEwLCB0aXRsZSA9IHRpdGxlKQogICAgICBwcmludChwKQogICAgICBnZ3NhdmUocGFzdGUwKCJNYWxpZ25hbnRfdnNfQ29udHJvbC8iLCBnc3ViKCIuY3N2IiwgIl9kb3RwbG90LnBuZyIsIGZpbGVuYW1lKSksIHBsb3QgPSBwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCiAgICAgIHdyaXRlLmNzdihhcy5kYXRhLmZyYW1lKHJlc3VsdCksIGZpbGUgPSBwYXN0ZTAoIk1hbGlnbmFudF92c19Db250cm9sLyIsIGZpbGVuYW1lKSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgICB9IGVsc2UgewogICAgICBtZXNzYWdlKHBhc3RlKCJObyBzaWduaWZpY2FudCBSZWFjdG9tZSBwYXRod2F5cyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogICAgfQogIH0gZWxzZSB7CiAgICBtZXNzYWdlKHBhc3RlKCJObyBnZW5lcyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogIH0KfQoKIyBQZXJmb3JtIGVucmljaG1lbnQgYW5hbHlzZXMsIGdlbmVyYXRlIHBsb3RzLCBhbmQgc2F2ZSByZXN1bHRzCnNhZmVfZW5yaWNoR08odXByZWd1bGF0ZWRfZ2VuZXMkZ2VuZSwgIkdPIEVucmljaG1lbnQgZm9yIFVwcmVndWxhdGVkIEdlbmVzIiwgInVwcmVndWxhdGVkX0dPX3Jlc3VsdHMuY3N2IikKc2FmZV9lbnJpY2hHTyhkb3ducmVndWxhdGVkX2dlbmVzJGdlbmUsICJHTyBFbnJpY2htZW50IGZvciBEb3ducmVndWxhdGVkIEdlbmVzIiwgImRvd25yZWd1bGF0ZWRfR09fcmVzdWx0cy5jc3YiKQoKc2FmZV9lbnJpY2hLRUdHKHVwcmVndWxhdGVkX2VudHJleiwgIktFR0cgUGF0aHdheSBFbnJpY2htZW50IGZvciBVcHJlZ3VsYXRlZCBHZW5lcyIsICJ1cHJlZ3VsYXRlZF9LRUdHX3Jlc3VsdHMuY3N2IikKc2FmZV9lbnJpY2hLRUdHKGRvd25yZWd1bGF0ZWRfZW50cmV6LCAiS0VHRyBQYXRod2F5IEVucmljaG1lbnQgZm9yIERvd25yZWd1bGF0ZWQgR2VuZXMiLCAiZG93bnJlZ3VsYXRlZF9LRUdHX3Jlc3VsdHMuY3N2IikKCnNhZmVfZW5yaWNoUmVhY3RvbWUodXByZWd1bGF0ZWRfZW50cmV6LCAiUmVhY3RvbWUgUGF0aHdheSBFbnJpY2htZW50IGZvciBVcHJlZ3VsYXRlZCBHZW5lcyIsICJ1cHJlZ3VsYXRlZF9SZWFjdG9tZV9yZXN1bHRzLmNzdiIpCnNhZmVfZW5yaWNoUmVhY3RvbWUoZG93bnJlZ3VsYXRlZF9lbnRyZXosICJSZWFjdG9tZSBQYXRod2F5IEVucmljaG1lbnQgZm9yIERvd25yZWd1bGF0ZWQgR2VuZXMiLCAiZG93bnJlZ3VsYXRlZF9SZWFjdG9tZV9yZXN1bHRzLmNzdiIpCgoKYGBgCgoKCgojIyBFbnJpY2htZW50IEFuYWx5c2lzLTItSGFsbG1hcmsKYGBge3IgLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZW5yaWNocGxvdCkKCiMgTG9hZCBIYWxsbWFyayBnZW5lIHNldHMgZnJvbSBtc2lnZGJyCmhhbGxtYXJrX3NldHMgPC0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIsIGNhdGVnb3J5ID0gIkgiKSAgIyAiSCIgaXMgZm9yIEhhbGxtYXJrIGdlbmUgc2V0cwoKIyBDb252ZXJ0IGdlbmUgc3ltYm9scyB0byB1cHBlcmNhc2UgZm9yIGNvbnNpc3RlbmN5CnVwcmVndWxhdGVkX2dlbmVzJGdlbmUgPC0gdG91cHBlcih1cHJlZ3VsYXRlZF9nZW5lcyRnZW5lKQpkb3ducmVndWxhdGVkX2dlbmVzJGdlbmUgPC0gdG91cHBlcihkb3ducmVndWxhdGVkX2dlbmVzJGdlbmUpCgojIENoZWNrIGZvciBvdmVybGFwIGJldHdlZW4geW91ciB1cHJlZ3VsYXRlZC9kb3ducmVndWxhdGVkIGdlbmVzIGFuZCBIYWxsbWFyayBnZW5lIHNldHMKdXByZWd1bGF0ZWRfaW5faGFsbG1hcmsgPC0gaW50ZXJzZWN0KHVwcmVndWxhdGVkX2dlbmVzJGdlbmUsIGhhbGxtYXJrX3NldHMkZ2VuZV9zeW1ib2wpCmRvd25yZWd1bGF0ZWRfaW5faGFsbG1hcmsgPC0gaW50ZXJzZWN0KGRvd25yZWd1bGF0ZWRfZ2VuZXMkZ2VuZSwgaGFsbG1hcmtfc2V0cyRnZW5lX3N5bWJvbCkKCiMgUHJpbnQgdGhlIG51bWJlciBvZiBvdmVybGFwcGluZyBnZW5lcyBmb3IgYm90aCB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lcwpjYXQoIk51bWJlciBvZiB1cHJlZ3VsYXRlZCBnZW5lcyBpbiBIYWxsbWFyayBnZW5lIHNldHM6IiwgbGVuZ3RoKHVwcmVndWxhdGVkX2luX2hhbGxtYXJrKSwgIlxuIikKY2F0KCJOdW1iZXIgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcyBpbiBIYWxsbWFyayBnZW5lIHNldHM6IiwgbGVuZ3RoKGRvd25yZWd1bGF0ZWRfaW5faGFsbG1hcmspLCAiXG4iKQoKIyBEZWZpbmUgdGhlIG91dHB1dCBmb2xkZXIgd2hlcmUgdGhlIHJlc3VsdHMgd2lsbCBiZSBzYXZlZApvdXRwdXRfZm9sZGVyIDwtICJNYWxpZ25hbnRfdnNfQ29udHJvbC8iCgojIElmIHRoZXJlIGFyZSBnZW5lcyB0byBhbmFseXplLCBwcm9jZWVkIHdpdGggZW5yaWNobWVudCBhbmFseXNpcwppZiAobGVuZ3RoKHVwcmVndWxhdGVkX2luX2hhbGxtYXJrKSA+IDApIHsKICAjIFBlcmZvcm0gZW5yaWNobWVudCBhbmFseXNpcyBmb3IgdXByZWd1bGF0ZWQgZ2VuZXMgdXNpbmcgSGFsbG1hcmsgZ2VuZSBzZXRzCiAgaGFsbG1hcmtfdXAgPC0gZW5yaWNoZXIoZ2VuZSA9IHVwcmVndWxhdGVkX2luX2hhbGxtYXJrLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBURVJNMkdFTkUgPSBoYWxsbWFya19zZXRzWywgYygiZ3NfbmFtZSIsICJnZW5lX3N5bWJvbCIpXSwgICMgRW5zdXJlIFRFUk0yR0VORSB1c2VzIGNvcnJlY3QgY29sdW1ucwogICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgIyBDaGVjayBpZiByZXN1bHRzIGV4aXN0CiAgaWYgKCFpcy5udWxsKGhhbGxtYXJrX3VwKSAmJiBucm93KGhhbGxtYXJrX3VwKSA+IDApIHsKICAgICMgVmlzdWFsaXplIHJlc3VsdHMgaWYgYXZhaWxhYmxlCiAgICB1cF9kb3RwbG90IDwtIGRvdHBsb3QoaGFsbG1hcmtfdXAsIHNob3dDYXRlZ29yeSA9IDIwLCB0aXRsZSA9ICJIYWxsbWFyayBQYXRod2F5IEVucmljaG1lbnQgZm9yIFVwcmVndWxhdGVkIEdlbmVzIikKICAgIAogICAgIyBEaXNwbGF5IHRoZSBwbG90IGluIHRoZSBub3RlYm9vawogICAgcHJpbnQodXBfZG90cGxvdCkKICAgIAogICAgIyBTYXZlIHRoZSBkb3RwbG90IHRvIGEgUE5HIGZpbGUKICAgIGdnc2F2ZShwYXN0ZTAob3V0cHV0X2ZvbGRlciwgImhhbGxtYXJrX3VwcmVndWxhdGVkX2RvdHBsb3QucG5nIiksIHBsb3QgPSB1cF9kb3RwbG90LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQogICAgCiAgICAjIE9wdGlvbmFsbHksIHNhdmUgdGhlIHJlc3VsdHMgYXMgQ1NWCiAgICB3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShoYWxsbWFya191cCksIGZpbGUgPSBwYXN0ZTAob3V0cHV0X2ZvbGRlciwgImhhbGxtYXJrX3VwcmVndWxhdGVkX2VucmljaG1lbnQuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQogIH0gZWxzZSB7CiAgICBjYXQoIk5vIHNpZ25pZmljYW50IGVucmljaG1lbnQgZm91bmQgZm9yIHVwcmVndWxhdGVkIGdlbmVzLlxuIikKICB9Cn0gZWxzZSB7CiAgY2F0KCJObyB1cHJlZ3VsYXRlZCBnZW5lcyBvdmVybGFwIHdpdGggSGFsbG1hcmsgZ2VuZSBzZXRzLlxuIikKfQoKaWYgKGxlbmd0aChkb3ducmVndWxhdGVkX2luX2hhbGxtYXJrKSA+IDApIHsKICAjIFBlcmZvcm0gZW5yaWNobWVudCBhbmFseXNpcyBmb3IgZG93bnJlZ3VsYXRlZCBnZW5lcyB1c2luZyBIYWxsbWFyayBnZW5lIHNldHMKICBoYWxsbWFya19kb3duIDwtIGVucmljaGVyKGdlbmUgPSBkb3ducmVndWxhdGVkX2luX2hhbGxtYXJrLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRFUk0yR0VORSA9IGhhbGxtYXJrX3NldHNbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildLCAgIyBFbnN1cmUgVEVSTTJHRU5FIHVzZXMgY29ycmVjdCBjb2x1bW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgPSAwLjA1KQogICMgQ2hlY2sgaWYgcmVzdWx0cyBleGlzdAogIGlmICghaXMubnVsbChoYWxsbWFya19kb3duKSAmJiBucm93KGhhbGxtYXJrX2Rvd24pID4gMCkgewogICAgIyBWaXN1YWxpemUgcmVzdWx0cyBpZiBhdmFpbGFibGUKICAgIGRvd25fZG90cGxvdCA8LSBkb3RwbG90KGhhbGxtYXJrX2Rvd24sIHNob3dDYXRlZ29yeSA9IDIwLCB0aXRsZSA9ICJIYWxsbWFyayBQYXRod2F5IEVucmljaG1lbnQgZm9yIERvd25yZWd1bGF0ZWQgR2VuZXMiKQogICAgCiAgICAjIERpc3BsYXkgdGhlIHBsb3QgaW4gdGhlIG5vdGVib29rCiAgICBwcmludChkb3duX2RvdHBsb3QpCiAgICAKICAgICMgU2F2ZSB0aGUgZG90cGxvdCB0byBhIFBORyBmaWxlCiAgICBnZ3NhdmUocGFzdGUwKG91dHB1dF9mb2xkZXIsICJoYWxsbWFya19kb3ducmVndWxhdGVkX2RvdHBsb3QucG5nIiksIHBsb3QgPSBkb3duX2RvdHBsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgpCiAgICAKICAgICMgT3B0aW9uYWxseSwgc2F2ZSB0aGUgcmVzdWx0cyBhcyBDU1YKICAgIHdyaXRlLmNzdihhcy5kYXRhLmZyYW1lKGhhbGxtYXJrX2Rvd24pLCBmaWxlID0gcGFzdGUwKG91dHB1dF9mb2xkZXIsICJoYWxsbWFya19kb3ducmVndWxhdGVkX2VucmljaG1lbnQuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQogIH0gZWxzZSB7CiAgICBjYXQoIk5vIHNpZ25pZmljYW50IGVucmljaG1lbnQgZm91bmQgZm9yIGRvd25yZWd1bGF0ZWQgZ2VuZXMuXG4iKQogIH0KfSBlbHNlIHsKICBjYXQoIk5vIGRvd25yZWd1bGF0ZWQgZ2VuZXMgb3ZlcmxhcCB3aXRoIEhhbGxtYXJrIGdlbmUgc2V0cy5cbiIpCn0KCgpgYGAKCgoKCgoKCg==