4. Enrichment Analysis-All_Pathways
# Define the output folder where the results will be saved
output_folder <- "HSPC_250UP_vs_Control_250DOWN/"
# Create the output folder if it doesn't exist
if (!dir.exists(output_folder)) {
dir.create(output_folder)
}
# Define the number of upregulated and downregulated genes to select
UP_genes <- 250
Down_genes <- 250
# Define threshold for differential expression selection (modified thresholds)
logFC_up_threshold <- 1.5 # Upregulated logFC threshold
logFC_down_threshold <- -1 # Downregulated logFC threshold
# Load your differential expression results (modify based on actual data structure)
# HSPC_vs_Control <- read.csv("Your_DE_Results_File.csv")
# Filter the genes based on avg_log2FC and arrange by p_val_adj
filtered_genes <- HSPC_vs_Control %>%
filter(avg_log2FC > logFC_up_threshold | avg_log2FC < logFC_down_threshold) %>%
arrange(p_val_adj)
# Separate upregulated and downregulated genes
upregulated_genes <- filtered_genes %>%
filter(avg_log2FC > logFC_up_threshold)
downregulated_genes <- filtered_genes %>%
filter(avg_log2FC < logFC_down_threshold)
# Check if there are fewer than the specified number of upregulated genes
if (nrow(upregulated_genes) < UP_genes) {
top_upregulated_genes <- upregulated_genes
cat("Number of upregulated genes selected:", nrow(top_upregulated_genes), "\n")
cat("p_val_adj value for the last selected upregulated gene:", tail(top_upregulated_genes$p_val_adj, 1), "\n")
} else {
# Select the specified number of upregulated genes
top_upregulated_genes <- upregulated_genes %>%
head(UP_genes)
cat("Number of upregulated genes selected:", nrow(top_upregulated_genes), "\n")
cat("p_val_adj value for the last selected upregulated gene:", tail(top_upregulated_genes$p_val_adj, 1), "\n")
}
Number of upregulated genes selected: 250
p_val_adj value for the last selected upregulated gene: 0
# Check if there are fewer than the specified number of downregulated genes
if (nrow(downregulated_genes) < Down_genes) {
top_downregulated_genes <- downregulated_genes
cat("Number of downregulated genes selected:", nrow(top_downregulated_genes), "\n")
cat("p_val_adj value for the last selected downregulated gene:", tail(top_downregulated_genes$p_val_adj, 1), "\n")
} else {
# Select the specified number of downregulated genes
top_downregulated_genes <- downregulated_genes %>%
head(Down_genes)
cat("Number of downregulated genes selected:", nrow(top_downregulated_genes), "\n")
cat("p_val_adj value for the last selected downregulated gene:", tail(top_downregulated_genes$p_val_adj, 1), "\n")
}
Number of downregulated genes selected: 250
p_val_adj value for the last selected downregulated gene: 1.210618e-138
# Combine the top upregulated and downregulated genes
top_genes <- bind_rows(top_upregulated_genes, top_downregulated_genes)
# Check for missing genes (NAs) in the gene column and remove them
top_genes <- na.omit(top_genes)
# Save upregulated and downregulated gene results to CSV
write.csv(top_upregulated_genes, paste0(output_folder, "upregulated_genes.csv"), row.names = FALSE)
write.csv(top_downregulated_genes, paste0(output_folder, "downregulated_genes.csv"), row.names = FALSE)
# Convert gene symbols to Entrez IDs for enrichment analysis, with checks for missing values
upregulated_entrez <- bitr(top_upregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 2.4% of input gene IDs are fail to map...
downregulated_entrez <- bitr(top_downregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 2.4% of input gene IDs are fail to map...
# Check for missing Entrez IDs and retain gene names
missing_upregulated <- top_upregulated_genes$gene[!top_upregulated_genes$gene %in% upregulated_entrez$SYMBOL]
missing_downregulated <- top_downregulated_genes$gene[!top_downregulated_genes$gene %in% downregulated_entrez$SYMBOL]
# Print out the missing gene symbols for debugging
cat("Missing upregulated genes:\n", missing_upregulated, "\n")
Missing upregulated genes:
WDR34 WARS H2AFX IARS GARS TARS
cat("Missing downregulated genes:\n", missing_downregulated, "\n")
Missing downregulated genes:
LINC01578 MT-ND3 AC119396.1 AC243960.1 FAM102A AL138963.4
# Merge the Entrez IDs back with the original data frames to retain gene names
top_upregulated_genes <- merge(top_upregulated_genes, upregulated_entrez, by.x = "gene", by.y = "SYMBOL", all.x = TRUE)
top_downregulated_genes <- merge(top_downregulated_genes, downregulated_entrez, by.x = "gene", by.y = "SYMBOL", all.x = TRUE)
# Remove genes that couldn't be mapped to Entrez IDs
top_upregulated_genes <- top_upregulated_genes[!is.na(top_upregulated_genes$ENTREZID), ]
top_downregulated_genes <- top_downregulated_genes[!is.na(top_downregulated_genes$ENTREZID), ]
# Extract Entrez IDs for enrichment analysis
upregulated_entrez <- top_upregulated_genes$ENTREZID
downregulated_entrez <- top_downregulated_genes$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, readable = TRUE)
if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0(output_folder, gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0(output_folder, 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) {
result <- setReadable(result, OrgDb = org.Hs.eg.db, keyType = "ENTREZID")
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0(output_folder, gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0(output_folder, 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) {
result <- setReadable(result, OrgDb = org.Hs.eg.db, keyType = "ENTREZID")
p <- dotplot(result, showCategory = 10, title = title)
print(p)
ggsave(paste0(output_folder, gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
write.csv(as.data.frame(result), file = paste0(output_folder, 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(top_upregulated_genes$gene, "GO Enrichment for Upregulated Genes", "upregulated_GO_results.csv")

safe_enrichGO(top_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")

Enrichment Analysis_Hallmark
# Load necessary libraries
library(clusterProfiler)
library(org.Hs.eg.db)
library(msigdbr)
For full functionality, please install the 'msigdbdf' package with:
install.packages('msigdbdf', repos = 'https://igordot.r-universe.dev')
library(enrichplot)
library(ggplot2)
library(dplyr)
# Define the output folder where the results will be saved
output_folder <- "HSPC_250UP_vs_Control_250DOWN/"
# Create the output folder if it doesn't exist
if (!dir.exists(output_folder)) {
dir.create(output_folder)
}
# Load Hallmark gene sets from msigdbr
hallmark_sets <- msigdbr(species = "Homo sapiens", collection = "H") # "H" is for Hallmark gene sets
The 'msigdbdf' package must be installed to access the full dataset.
Would you like to install 'msigdbdf'?
1: Yes
2: No
yes
Entrer un des items du menu, ou 0 pour sortir
1
Installing the 'msigdbdf' package.
Installation du package dans ‘/mnt/newhome/nabbasi/R/x86_64-pc-linux-gnu-library/4.2’
(car ‘lib’ n'est pas spécifié)
Avis : ouverture de l’URL 'https://igordot.r-universe.dev/src/contrib/PACKAGES.rds' impossible : le statut HTTP était '404 Not Found'essai de l'URL 'https://igordot.r-universe.dev/src/contrib/msigdbdf_24.1.1.tar.gz'
Content type 'application/gzip' length 12953684 bytes (12.4 MB)
==================================================
downloaded 12.4 MB
* installing *source* package ‘msigdbdf’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
converting help for package ‘msigdbdf’
finding HTML links ... fini
ensembl_genes html
gene_set_details html
gene_set_members html
msigdb_ensembl html
msigdb_sqlite html
msigdbdf-package html
msigdbdf html
** building package indices
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (msigdbdf)
Les packages source téléchargés sont dans
‘/tmp/Rtmpdvyzm6/downloaded_packages’
# Convert gene symbols to uppercase for consistency
top_upregulated_genes$gene <- toupper(top_upregulated_genes$gene)
top_downregulated_genes$gene <- toupper(top_downregulated_genes$gene)
# Check for overlap between your upregulated/downregulated genes and Hallmark gene sets
upregulated_in_hallmark <- intersect(top_upregulated_genes$gene, hallmark_sets$gene_symbol)
downregulated_in_hallmark <- intersect(top_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: 150
cat("Number of downregulated genes in Hallmark gene sets:", length(downregulated_in_hallmark), "\n")
Number of downregulated genes in Hallmark gene sets: 90
# 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
LS0tCnRpdGxlOiAiSFNQQyB2cyBDb250cm9sX2ZpbHRyZWRfb25fbWVhbiIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdAogICMgd29yZF9kb2N1bWVudDogZGVmYXVsdAogICMgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgTG9hZCBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCgoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQpsaWJyYXJ5KGVucmljaHBsb3QpCmxpYnJhcnkoUmVhY3RvbWVQQSkKbGlicmFyeShET1NFKSAjIEZvciBHU0VBIGFuYWx5c2lzCmxpYnJhcnkoZ2dwbG90MikgIyBFbnN1cmUgZ2dwbG90MiBpcyBhdmFpbGFibGUgZm9yIHBsb3R0aW5nCmxpYnJhcnkoZHBseXIpCgpgYGAKCiMgMi4gTG9hZCB0aGUgZmlsdGVyZWQgbGlzdCBvbiBtZWFuIGV4cHJlc3Npb24KYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCiMgTG9hZCB0aGUgREUgcmVzdWx0cyBmcm9tIENTVgpIU1BDX3ZzX0NvbnRyb2wgPC0gcmVhZC5jc3YoIjMtUk5BX0hTUENfdnNfQ29udHJvbF9GaWx0ZXJlZF9ieV9NZWFuRXhwLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCgpgYGAKCgoKCgojIDMuIFZvbGNhbm8gUGxvdHMKYGBge3IgLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiMgQXNzdW1pbmcgeW91IGhhdmUgYSBkYXRhIGZyYW1lIG5hbWVkIEhTUENfdnNfQ29udHJvbCAKIyBGaWx0ZXIgZ2VuZXMgYmFzZWQgb24gbG93ZXN0IHAtdmFsdWVzIGJ1dCBpbmNsdWRlIGFsbCBnZW5lcwpmaWx0ZXJlZF9nZW5lcyA8LSBIU1BDX3ZzX0NvbnRyb2wgICU+JQogIGFycmFuZ2UocF92YWxfYWRqLCBkZXNjKGFicyhhdmdfbG9nMkZDKSkpCgojIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3Qgd2l0aCB0aGUgZmlsdGVyZWQgZGF0YQpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMWUtNiAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nMkZDKSA+PSAxLjUsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2cyRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiSFNQQyB2cyBub3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHBDdXRvZmYgPSAxZS02LAogIEZDY3V0b2ZmID0gMS4wLAogIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywgCiAgbGFiQ29sID0gJ2JsYWNrJywKICBsYWJGYWNlID0gJ2JvbGQnLAogIGJveGVkTGFiZWxzID0gRkFMU0UsICAjIFNldCB0byBGQUxTRSB0byByZW1vdmUgYm94ZWQgbGFiZWxzCiAgcG9pbnRTaXplID0gMy4wLAogIGxhYlNpemUgPSA1LjAsCiAgY29sID0gYygnZ3JleTcwJywgJ2JsYWNrJywgJ2JsdWUnLCAncmVkJyksICAjIEN1c3RvbWl6ZSBwb2ludCBjb2xvcnMKICBzZWxlY3RMYWIgPSBmaWx0ZXJlZF9nZW5lcyRnZW5lW2ZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2cyRkMpID49IDEuMF0gICMgT25seSBsYWJlbCBzaWduaWZpY2FudCBnZW5lcwopCgoKCmBgYAoKIyA0LiBFbnJpY2htZW50IEFuYWx5c2lzLUFsbF9QYXRod2F5cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKCiMgRGVmaW5lIHRoZSBvdXRwdXQgZm9sZGVyIHdoZXJlIHRoZSByZXN1bHRzIHdpbGwgYmUgc2F2ZWQKb3V0cHV0X2ZvbGRlciA8LSAiSFNQQ18yNTBVUF92c19Db250cm9sXzI1MERPV04vIgoKIyBDcmVhdGUgdGhlIG91dHB1dCBmb2xkZXIgaWYgaXQgZG9lc24ndCBleGlzdAppZiAoIWRpci5leGlzdHMob3V0cHV0X2ZvbGRlcikpIHsKICBkaXIuY3JlYXRlKG91dHB1dF9mb2xkZXIpCn0KCiMgRGVmaW5lIHRoZSBudW1iZXIgb2YgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMgdG8gc2VsZWN0ClVQX2dlbmVzIDwtIDI1MApEb3duX2dlbmVzIDwtIDI1MAoKIyBEZWZpbmUgdGhyZXNob2xkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBzZWxlY3Rpb24gKG1vZGlmaWVkIHRocmVzaG9sZHMpCmxvZ0ZDX3VwX3RocmVzaG9sZCA8LSAxLjUgICAgICAgICAgIyBVcHJlZ3VsYXRlZCBsb2dGQyB0aHJlc2hvbGQKbG9nRkNfZG93bl90aHJlc2hvbGQgPC0gLTEgICAgICAgICAjIERvd25yZWd1bGF0ZWQgbG9nRkMgdGhyZXNob2xkCgojIExvYWQgeW91ciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiByZXN1bHRzIChtb2RpZnkgYmFzZWQgb24gYWN0dWFsIGRhdGEgc3RydWN0dXJlKQojIEhTUENfdnNfQ29udHJvbCAgPC0gcmVhZC5jc3YoIllvdXJfREVfUmVzdWx0c19GaWxlLmNzdiIpCgojIEZpbHRlciB0aGUgZ2VuZXMgYmFzZWQgb24gYXZnX2xvZzJGQyBhbmQgYXJyYW5nZSBieSBwX3ZhbF9hZGoKZmlsdGVyZWRfZ2VuZXMgPC0gSFNQQ192c19Db250cm9sICAlPiUKICBmaWx0ZXIoYXZnX2xvZzJGQyA+IGxvZ0ZDX3VwX3RocmVzaG9sZCB8IGF2Z19sb2cyRkMgPCBsb2dGQ19kb3duX3RocmVzaG9sZCkgJT4lCiAgYXJyYW5nZShwX3ZhbF9hZGopCgojIFNlcGFyYXRlIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzCnVwcmVndWxhdGVkX2dlbmVzIDwtIGZpbHRlcmVkX2dlbmVzICU+JQogIGZpbHRlcihhdmdfbG9nMkZDID4gbG9nRkNfdXBfdGhyZXNob2xkKQoKZG93bnJlZ3VsYXRlZF9nZW5lcyA8LSBmaWx0ZXJlZF9nZW5lcyAlPiUKICBmaWx0ZXIoYXZnX2xvZzJGQyA8IGxvZ0ZDX2Rvd25fdGhyZXNob2xkKQoKIyBDaGVjayBpZiB0aGVyZSBhcmUgZmV3ZXIgdGhhbiB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiB1cHJlZ3VsYXRlZCBnZW5lcwppZiAobnJvdyh1cHJlZ3VsYXRlZF9nZW5lcykgPCBVUF9nZW5lcykgewogIHRvcF91cHJlZ3VsYXRlZF9nZW5lcyA8LSB1cHJlZ3VsYXRlZF9nZW5lcwogIGNhdCgiTnVtYmVyIG9mIHVwcmVndWxhdGVkIGdlbmVzIHNlbGVjdGVkOiIsIG5yb3codG9wX3VwcmVndWxhdGVkX2dlbmVzKSwgIlxuIikKICBjYXQoInBfdmFsX2FkaiB2YWx1ZSBmb3IgdGhlIGxhc3Qgc2VsZWN0ZWQgdXByZWd1bGF0ZWQgZ2VuZToiLCB0YWlsKHRvcF91cHJlZ3VsYXRlZF9nZW5lcyRwX3ZhbF9hZGosIDEpLCAiXG4iKQp9IGVsc2UgewogICMgU2VsZWN0IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIHVwcmVndWxhdGVkIGdlbmVzCiAgdG9wX3VwcmVndWxhdGVkX2dlbmVzIDwtIHVwcmVndWxhdGVkX2dlbmVzICU+JQogICAgaGVhZChVUF9nZW5lcykKICBjYXQoIk51bWJlciBvZiB1cHJlZ3VsYXRlZCBnZW5lcyBzZWxlY3RlZDoiLCBucm93KHRvcF91cHJlZ3VsYXRlZF9nZW5lcyksICJcbiIpCiAgY2F0KCJwX3ZhbF9hZGogdmFsdWUgZm9yIHRoZSBsYXN0IHNlbGVjdGVkIHVwcmVndWxhdGVkIGdlbmU6IiwgdGFpbCh0b3BfdXByZWd1bGF0ZWRfZ2VuZXMkcF92YWxfYWRqLCAxKSwgIlxuIikKfQoKIyBDaGVjayBpZiB0aGVyZSBhcmUgZmV3ZXIgdGhhbiB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBkb3ducmVndWxhdGVkIGdlbmVzCmlmIChucm93KGRvd25yZWd1bGF0ZWRfZ2VuZXMpIDwgRG93bl9nZW5lcykgewogIHRvcF9kb3ducmVndWxhdGVkX2dlbmVzIDwtIGRvd25yZWd1bGF0ZWRfZ2VuZXMKICBjYXQoIk51bWJlciBvZiBkb3ducmVndWxhdGVkIGdlbmVzIHNlbGVjdGVkOiIsIG5yb3codG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMpLCAiXG4iKQogIGNhdCgicF92YWxfYWRqIHZhbHVlIGZvciB0aGUgbGFzdCBzZWxlY3RlZCBkb3ducmVndWxhdGVkIGdlbmU6IiwgdGFpbCh0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyRwX3ZhbF9hZGosIDEpLCAiXG4iKQp9IGVsc2UgewogICMgU2VsZWN0IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIGRvd25yZWd1bGF0ZWQgZ2VuZXMKICB0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyA8LSBkb3ducmVndWxhdGVkX2dlbmVzICU+JQogICAgaGVhZChEb3duX2dlbmVzKQogIGNhdCgiTnVtYmVyIG9mIGRvd25yZWd1bGF0ZWQgZ2VuZXMgc2VsZWN0ZWQ6IiwgbnJvdyh0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyksICJcbiIpCiAgY2F0KCJwX3ZhbF9hZGogdmFsdWUgZm9yIHRoZSBsYXN0IHNlbGVjdGVkIGRvd25yZWd1bGF0ZWQgZ2VuZToiLCB0YWlsKHRvcF9kb3ducmVndWxhdGVkX2dlbmVzJHBfdmFsX2FkaiwgMSksICJcbiIpCn0KCiMgQ29tYmluZSB0aGUgdG9wIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzCnRvcF9nZW5lcyA8LSBiaW5kX3Jvd3ModG9wX3VwcmVndWxhdGVkX2dlbmVzLCB0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcykKCiMgQ2hlY2sgZm9yIG1pc3NpbmcgZ2VuZXMgKE5BcykgaW4gdGhlIGdlbmUgY29sdW1uIGFuZCByZW1vdmUgdGhlbQp0b3BfZ2VuZXMgPC0gbmEub21pdCh0b3BfZ2VuZXMpCgojIFNhdmUgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZSByZXN1bHRzIHRvIENTVgp3cml0ZS5jc3YodG9wX3VwcmVndWxhdGVkX2dlbmVzLCBwYXN0ZTAob3V0cHV0X2ZvbGRlciwgInVwcmVndWxhdGVkX2dlbmVzLmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSkKd3JpdGUuY3N2KHRvcF9kb3ducmVndWxhdGVkX2dlbmVzLCBwYXN0ZTAob3V0cHV0X2ZvbGRlciwgImRvd25yZWd1bGF0ZWRfZ2VuZXMuY3N2IiksIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyBDb252ZXJ0IGdlbmUgc3ltYm9scyB0byBFbnRyZXogSURzIGZvciBlbnJpY2htZW50IGFuYWx5c2lzLCB3aXRoIGNoZWNrcyBmb3IgbWlzc2luZyB2YWx1ZXMKdXByZWd1bGF0ZWRfZW50cmV6IDwtIGJpdHIodG9wX3VwcmVndWxhdGVkX2dlbmVzJGdlbmUsIGZyb21UeXBlID0gIlNZTUJPTCIsIHRvVHlwZSA9ICJFTlRSRVpJRCIsIE9yZ0RiID0gb3JnLkhzLmVnLmRiKQpkb3ducmVndWxhdGVkX2VudHJleiA8LSBiaXRyKHRvcF9kb3ducmVndWxhdGVkX2dlbmVzJGdlbmUsIGZyb21UeXBlID0gIlNZTUJPTCIsIHRvVHlwZSA9ICJFTlRSRVpJRCIsIE9yZ0RiID0gb3JnLkhzLmVnLmRiKQoKIyBDaGVjayBmb3IgbWlzc2luZyBFbnRyZXogSURzIGFuZCByZXRhaW4gZ2VuZSBuYW1lcwptaXNzaW5nX3VwcmVndWxhdGVkIDwtIHRvcF91cHJlZ3VsYXRlZF9nZW5lcyRnZW5lWyF0b3BfdXByZWd1bGF0ZWRfZ2VuZXMkZ2VuZSAlaW4lIHVwcmVndWxhdGVkX2VudHJleiRTWU1CT0xdCm1pc3NpbmdfZG93bnJlZ3VsYXRlZCA8LSB0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lWyF0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lICVpbiUgZG93bnJlZ3VsYXRlZF9lbnRyZXokU1lNQk9MXQoKIyBQcmludCBvdXQgdGhlIG1pc3NpbmcgZ2VuZSBzeW1ib2xzIGZvciBkZWJ1Z2dpbmcKY2F0KCJNaXNzaW5nIHVwcmVndWxhdGVkIGdlbmVzOlxuIiwgbWlzc2luZ191cHJlZ3VsYXRlZCwgIlxuIikKY2F0KCJNaXNzaW5nIGRvd25yZWd1bGF0ZWQgZ2VuZXM6XG4iLCBtaXNzaW5nX2Rvd25yZWd1bGF0ZWQsICJcbiIpCgojIE1lcmdlIHRoZSBFbnRyZXogSURzIGJhY2sgd2l0aCB0aGUgb3JpZ2luYWwgZGF0YSBmcmFtZXMgdG8gcmV0YWluIGdlbmUgbmFtZXMKdG9wX3VwcmVndWxhdGVkX2dlbmVzIDwtIG1lcmdlKHRvcF91cHJlZ3VsYXRlZF9nZW5lcywgdXByZWd1bGF0ZWRfZW50cmV6LCBieS54ID0gImdlbmUiLCBieS55ID0gIlNZTUJPTCIsIGFsbC54ID0gVFJVRSkKdG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMgPC0gbWVyZ2UodG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMsIGRvd25yZWd1bGF0ZWRfZW50cmV6LCBieS54ID0gImdlbmUiLCBieS55ID0gIlNZTUJPTCIsIGFsbC54ID0gVFJVRSkKCiMgUmVtb3ZlIGdlbmVzIHRoYXQgY291bGRuJ3QgYmUgbWFwcGVkIHRvIEVudHJleiBJRHMKdG9wX3VwcmVndWxhdGVkX2dlbmVzIDwtIHRvcF91cHJlZ3VsYXRlZF9nZW5lc1shaXMubmEodG9wX3VwcmVndWxhdGVkX2dlbmVzJEVOVFJFWklEKSwgXQp0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyA8LSB0b3BfZG93bnJlZ3VsYXRlZF9nZW5lc1shaXMubmEodG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMkRU5UUkVaSUQpLCBdCgojIEV4dHJhY3QgRW50cmV6IElEcyBmb3IgZW5yaWNobWVudCBhbmFseXNpcwp1cHJlZ3VsYXRlZF9lbnRyZXogPC0gdG9wX3VwcmVndWxhdGVkX2dlbmVzJEVOVFJFWklECmRvd25yZWd1bGF0ZWRfZW50cmV6IDwtIHRvcF9kb3ducmVndWxhdGVkX2dlbmVzJEVOVFJFWklECgojIERlZmluZSBhIGZ1bmN0aW9uIHRvIHNhZmVseSBydW4gZW5yaWNobWVudCwgcGxvdCByZXN1bHRzLCBhbmQgc2F2ZSB0aGVtCnNhZmVfZW5yaWNoR08gPC0gZnVuY3Rpb24oZ2VuZV9saXN0LCB0aXRsZSwgZmlsZW5hbWUpIHsKICBpZiAobGVuZ3RoKGdlbmVfbGlzdCkgPiAwKSB7CiAgICByZXN1bHQgPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVfbGlzdCwgT3JnRGIgPSBvcmcuSHMuZWcuZGIsIGtleVR5cGUgPSAiU1lNQk9MIiwKICAgICAgICAgICAgICAgICAgICAgICBvbnQgPSAiQlAiLCBwQWRqdXN0TWV0aG9kID0gIkJIIiwgcHZhbHVlQ3V0b2ZmID0gMC4wNSwgcmVhZGFibGUgPSBUUlVFKQogICAgaWYgKCFpcy5udWxsKHJlc3VsdCkgJiYgbnJvdyhhcy5kYXRhLmZyYW1lKHJlc3VsdCkpID4gMCkgewogICAgICBwIDwtIGRvdHBsb3QocmVzdWx0LCBzaG93Q2F0ZWdvcnkgPSAxMCwgdGl0bGUgPSB0aXRsZSkKICAgICAgcHJpbnQocCkgIAogICAgICBnZ3NhdmUocGFzdGUwKG91dHB1dF9mb2xkZXIsIGdzdWIoIi5jc3YiLCAiX2RvdHBsb3QucG5nIiwgZmlsZW5hbWUpKSwgcGxvdCA9IHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKICAgICAgd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUocmVzdWx0KSwgZmlsZSA9IHBhc3RlMChvdXRwdXRfZm9sZGVyLCBmaWxlbmFtZSksIHJvdy5uYW1lcyA9IEZBTFNFKQogICAgfSBlbHNlIHsKICAgICAgbWVzc2FnZShwYXN0ZSgiTm8gc2lnbmlmaWNhbnQgZW5yaWNobWVudCBmb3VuZCBmb3I6IiwgdGl0bGUpKQogICAgfQogIH0gZWxzZSB7CiAgICBtZXNzYWdlKHBhc3RlKCJObyBnZW5lcyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogIH0KfQoKc2FmZV9lbnJpY2hLRUdHIDwtIGZ1bmN0aW9uKGVudHJlel9saXN0LCB0aXRsZSwgZmlsZW5hbWUpIHsKICBpZiAobGVuZ3RoKGVudHJlel9saXN0KSA+IDApIHsKICAgIHJlc3VsdCA8LSBlbnJpY2hLRUdHKGdlbmUgPSBlbnRyZXpfbGlzdCwgb3JnYW5pc20gPSAiaHNhIiwgcHZhbHVlQ3V0b2ZmID0gMC4wNSkKICAgIGlmICghaXMubnVsbChyZXN1bHQpICYmIG5yb3coYXMuZGF0YS5mcmFtZShyZXN1bHQpKSA+IDApIHsKICAgICAgcmVzdWx0IDwtIHNldFJlYWRhYmxlKHJlc3VsdCwgT3JnRGIgPSBvcmcuSHMuZWcuZGIsIGtleVR5cGUgPSAiRU5UUkVaSUQiKQogICAgICBwIDwtIGRvdHBsb3QocmVzdWx0LCBzaG93Q2F0ZWdvcnkgPSAxMCwgdGl0bGUgPSB0aXRsZSkKICAgICAgcHJpbnQocCkKICAgICAgZ2dzYXZlKHBhc3RlMChvdXRwdXRfZm9sZGVyLCBnc3ViKCIuY3N2IiwgIl9kb3RwbG90LnBuZyIsIGZpbGVuYW1lKSksIHBsb3QgPSBwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCiAgICAgIHdyaXRlLmNzdihhcy5kYXRhLmZyYW1lKHJlc3VsdCksIGZpbGUgPSBwYXN0ZTAob3V0cHV0X2ZvbGRlciwgZmlsZW5hbWUpLCByb3cubmFtZXMgPSBGQUxTRSkKICAgIH0gZWxzZSB7CiAgICAgIG1lc3NhZ2UocGFzdGUoIk5vIHNpZ25pZmljYW50IEtFR0cgcGF0aHdheXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICAgIH0KICB9IGVsc2UgewogICAgbWVzc2FnZShwYXN0ZSgiTm8gZ2VuZXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICB9Cn0KCnNhZmVfZW5yaWNoUmVhY3RvbWUgPC0gZnVuY3Rpb24oZW50cmV6X2xpc3QsIHRpdGxlLCBmaWxlbmFtZSkgewogIGlmIChsZW5ndGgoZW50cmV6X2xpc3QpID4gMCkgewogICAgcmVzdWx0IDwtIGVucmljaFBhdGh3YXkoZ2VuZSA9IGVudHJlel9saXN0LCBvcmdhbmlzbSA9ICJodW1hbiIsIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgICBpZiAoIWlzLm51bGwocmVzdWx0KSAmJiBucm93KGFzLmRhdGEuZnJhbWUocmVzdWx0KSkgPiAwKSB7CiAgICAgIHJlc3VsdCA8LSBzZXRSZWFkYWJsZShyZXN1bHQsIE9yZ0RiID0gb3JnLkhzLmVnLmRiLCBrZXlUeXBlID0gIkVOVFJFWklEIikKICAgICAgcCA8LSBkb3RwbG90KHJlc3VsdCwgc2hvd0NhdGVnb3J5ID0gMTAsIHRpdGxlID0gdGl0bGUpCiAgICAgIHByaW50KHApCiAgICAgIGdnc2F2ZShwYXN0ZTAob3V0cHV0X2ZvbGRlciwgZ3N1YigiLmNzdiIsICJfZG90cGxvdC5wbmciLCBmaWxlbmFtZSkpLCBwbG90ID0gcCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQogICAgICB3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShyZXN1bHQpLCBmaWxlID0gcGFzdGUwKG91dHB1dF9mb2xkZXIsIGZpbGVuYW1lKSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgICB9IGVsc2UgewogICAgICBtZXNzYWdlKHBhc3RlKCJObyBzaWduaWZpY2FudCBSZWFjdG9tZSBwYXRod2F5cyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogICAgfQogIH0gZWxzZSB7CiAgICBtZXNzYWdlKHBhc3RlKCJObyBnZW5lcyBmb3VuZCBmb3I6IiwgdGl0bGUpKQogIH0KfQoKIyBQZXJmb3JtIGVucmljaG1lbnQgYW5hbHlzZXMsIGdlbmVyYXRlIHBsb3RzLCBhbmQgc2F2ZSByZXN1bHRzCnNhZmVfZW5yaWNoR08odG9wX3VwcmVndWxhdGVkX2dlbmVzJGdlbmUsICJHTyBFbnJpY2htZW50IGZvciBVcHJlZ3VsYXRlZCBHZW5lcyIsICJ1cHJlZ3VsYXRlZF9HT19yZXN1bHRzLmNzdiIpCnNhZmVfZW5yaWNoR08odG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMkZ2VuZSwgIkdPIEVucmljaG1lbnQgZm9yIERvd25yZWd1bGF0ZWQgR2VuZXMiLCAiZG93bnJlZ3VsYXRlZF9HT19yZXN1bHRzLmNzdiIpCgpzYWZlX2VucmljaEtFR0codXByZWd1bGF0ZWRfZW50cmV6LCAiS0VHRyBQYXRod2F5IEVucmljaG1lbnQgZm9yIFVwcmVndWxhdGVkIEdlbmVzIiwgInVwcmVndWxhdGVkX0tFR0dfcmVzdWx0cy5jc3YiKQpzYWZlX2VucmljaEtFR0coZG93bnJlZ3VsYXRlZF9lbnRyZXosICJLRUdHIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgRG93bnJlZ3VsYXRlZCBHZW5lcyIsICJkb3ducmVndWxhdGVkX0tFR0dfcmVzdWx0cy5jc3YiKQoKc2FmZV9lbnJpY2hSZWFjdG9tZSh1cHJlZ3VsYXRlZF9lbnRyZXosICJSZWFjdG9tZSBQYXRod2F5IEVucmljaG1lbnQgZm9yIFVwcmVndWxhdGVkIEdlbmVzIiwgInVwcmVndWxhdGVkX1JlYWN0b21lX3Jlc3VsdHMuY3N2IikKc2FmZV9lbnJpY2hSZWFjdG9tZShkb3ducmVndWxhdGVkX2VudHJleiwgIlJlYWN0b21lIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgRG93bnJlZ3VsYXRlZCBHZW5lcyIsICJkb3ducmVndWxhdGVkX1JlYWN0b21lX3Jlc3VsdHMuY3N2IikKCmBgYAoKIyMgRW5yaWNobWVudCBBbmFseXNpc19IYWxsbWFyawpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQoKIyBEZWZpbmUgdGhlIG91dHB1dCBmb2xkZXIgd2hlcmUgdGhlIHJlc3VsdHMgd2lsbCBiZSBzYXZlZApvdXRwdXRfZm9sZGVyIDwtICJIU1BDXzI1MFVQX3ZzX0NvbnRyb2xfMjUwRE9XTi8iCgojIENyZWF0ZSB0aGUgb3V0cHV0IGZvbGRlciBpZiBpdCBkb2Vzbid0IGV4aXN0CmlmICghZGlyLmV4aXN0cyhvdXRwdXRfZm9sZGVyKSkgewogIGRpci5jcmVhdGUob3V0cHV0X2ZvbGRlcikKfQoKIyBMb2FkIEhhbGxtYXJrIGdlbmUgc2V0cyBmcm9tIG1zaWdkYnIKaGFsbG1hcmtfc2V0cyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY29sbGVjdGlvbiA9ICJIIikgICMgIkgiIGlzIGZvciBIYWxsbWFyayBnZW5lIHNldHMKCiMgQ29udmVydCBnZW5lIHN5bWJvbHMgdG8gdXBwZXJjYXNlIGZvciBjb25zaXN0ZW5jeQp0b3BfdXByZWd1bGF0ZWRfZ2VuZXMkZ2VuZSA8LSB0b3VwcGVyKHRvcF91cHJlZ3VsYXRlZF9nZW5lcyRnZW5lKQp0b3BfZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lIDwtIHRvdXBwZXIodG9wX2Rvd25yZWd1bGF0ZWRfZ2VuZXMkZ2VuZSkKCiMgQ2hlY2sgZm9yIG92ZXJsYXAgYmV0d2VlbiB5b3VyIHVwcmVndWxhdGVkL2Rvd25yZWd1bGF0ZWQgZ2VuZXMgYW5kIEhhbGxtYXJrIGdlbmUgc2V0cwp1cHJlZ3VsYXRlZF9pbl9oYWxsbWFyayA8LSBpbnRlcnNlY3QodG9wX3VwcmVndWxhdGVkX2dlbmVzJGdlbmUsIGhhbGxtYXJrX3NldHMkZ2VuZV9zeW1ib2wpCmRvd25yZWd1bGF0ZWRfaW5faGFsbG1hcmsgPC0gaW50ZXJzZWN0KHRvcF9kb3ducmVndWxhdGVkX2dlbmVzJGdlbmUsIGhhbGxtYXJrX3NldHMkZ2VuZV9zeW1ib2wpCgojIFByaW50IHRoZSBudW1iZXIgb2Ygb3ZlcmxhcHBpbmcgZ2VuZXMgZm9yIGJvdGggdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKY2F0KCJOdW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXMgaW4gSGFsbG1hcmsgZ2VuZSBzZXRzOiIsIGxlbmd0aCh1cHJlZ3VsYXRlZF9pbl9oYWxsbWFyayksICJcbiIpCmNhdCgiTnVtYmVyIG9mIGRvd25yZWd1bGF0ZWQgZ2VuZXMgaW4gSGFsbG1hcmsgZ2VuZSBzZXRzOiIsIGxlbmd0aChkb3ducmVndWxhdGVkX2luX2hhbGxtYXJrKSwgIlxuIikKCiMgSWYgdGhlcmUgYXJlIGdlbmVzIHRvIGFuYWx5emUsIHByb2NlZWQgd2l0aCBlbnJpY2htZW50IGFuYWx5c2lzCmlmIChsZW5ndGgodXByZWd1bGF0ZWRfaW5faGFsbG1hcmspID4gMCkgewogICMgUGVyZm9ybSBlbnJpY2htZW50IGFuYWx5c2lzIGZvciB1cHJlZ3VsYXRlZCBnZW5lcyB1c2luZyBIYWxsbWFyayBnZW5lIHNldHMKICBoYWxsbWFya191cCA8LSBlbnJpY2hlcihnZW5lID0gdXByZWd1bGF0ZWRfaW5faGFsbG1hcmssIAogICAgICAgICAgICAgICAgICAgICAgICAgIFRFUk0yR0VORSA9IGhhbGxtYXJrX3NldHNbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildLCAgIyBFbnN1cmUgVEVSTTJHRU5FIHVzZXMgY29ycmVjdCBjb2x1bW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSkKICAjIENoZWNrIGlmIHJlc3VsdHMgZXhpc3QKICBpZiAoIWlzLm51bGwoaGFsbG1hcmtfdXApICYmIG5yb3coaGFsbG1hcmtfdXApID4gMCkgewogICAgIyBWaXN1YWxpemUgcmVzdWx0cyBpZiBhdmFpbGFibGUKICAgIHVwX2RvdHBsb3QgPC0gZG90cGxvdChoYWxsbWFya191cCwgc2hvd0NhdGVnb3J5ID0gMjAsIHRpdGxlID0gIkhhbGxtYXJrIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgVXByZWd1bGF0ZWQgR2VuZXMiKQogICAgCiAgICAjIERpc3BsYXkgdGhlIHBsb3QgaW4gdGhlIG5vdGVib29rCiAgICBwcmludCh1cF9kb3RwbG90KQogICAgCiAgICAjIFNhdmUgdGhlIGRvdHBsb3QgdG8gYSBQTkcgZmlsZQogICAgZ2dzYXZlKHBhc3RlMChvdXRwdXRfZm9sZGVyLCAiaGFsbG1hcmtfdXByZWd1bGF0ZWRfZG90cGxvdC5wbmciKSwgcGxvdCA9IHVwX2RvdHBsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgpCiAgICAKICAgICMgT3B0aW9uYWxseSwgc2F2ZSB0aGUgcmVzdWx0cyBhcyBDU1YKICAgIHdyaXRlLmNzdihhcy5kYXRhLmZyYW1lKGhhbGxtYXJrX3VwKSwgZmlsZSA9IHBhc3RlMChvdXRwdXRfZm9sZGVyLCAiaGFsbG1hcmtfdXByZWd1bGF0ZWRfZW5yaWNobWVudC5jc3YiKSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgfSBlbHNlIHsKICAgIGNhdCgiTm8gc2lnbmlmaWNhbnQgZW5yaWNobWVudCBmb3VuZCBmb3IgdXByZWd1bGF0ZWQgZ2VuZXMuXG4iKQogIH0KfSBlbHNlIHsKICBjYXQoIk5vIHVwcmVndWxhdGVkIGdlbmVzIG92ZXJsYXAgd2l0aCBIYWxsbWFyayBnZW5lIHNldHMuXG4iKQp9CgppZiAobGVuZ3RoKGRvd25yZWd1bGF0ZWRfaW5faGFsbG1hcmspID4gMCkgewogICMgUGVyZm9ybSBlbnJpY2htZW50IGFuYWx5c2lzIGZvciBkb3ducmVndWxhdGVkIGdlbmVzIHVzaW5nIEhhbGxtYXJrIGdlbmUgc2V0cwogIGhhbGxtYXJrX2Rvd24gPC0gZW5yaWNoZXIoZ2VuZSA9IGRvd25yZWd1bGF0ZWRfaW5faGFsbG1hcmssIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVEVSTTJHRU5FID0gaGFsbG1hcmtfc2V0c1ssIGMoImdzX25hbWUiLCAiZ2VuZV9zeW1ib2wiKV0sICAjIEVuc3VyZSBURVJNMkdFTkUgdXNlcyBjb3JyZWN0IGNvbHVtbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgIyBDaGVjayBpZiByZXN1bHRzIGV4aXN0CiAgaWYgKCFpcy5udWxsKGhhbGxtYXJrX2Rvd24pICYmIG5yb3coaGFsbG1hcmtfZG93bikgPiAwKSB7CiAgICAjIFZpc3VhbGl6ZSByZXN1bHRzIGlmIGF2YWlsYWJsZQogICAgZG93bl9kb3RwbG90IDwtIGRvdHBsb3QoaGFsbG1hcmtfZG93biwgc2hvd0NhdGVnb3J5ID0gMjAsIHRpdGxlID0gIkhhbGxtYXJrIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgRG93bnJlZ3VsYXRlZCBHZW5lcyIpCiAgICAKICAgICMgRGlzcGxheSB0aGUgcGxvdCBpbiB0aGUgbm90ZWJvb2sKICAgIHByaW50KGRvd25fZG90cGxvdCkKICAgIAogICAgIyBTYXZlIHRoZSBkb3RwbG90IHRvIGEgUE5HIGZpbGUKICAgIGdnc2F2ZShwYXN0ZTAob3V0cHV0X2ZvbGRlciwgImhhbGxtYXJrX2Rvd25yZWd1bGF0ZWRfZG90cGxvdC5wbmciKSwgcGxvdCA9IGRvd25fZG90cGxvdCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCkKICAgIAogICAgIyBPcHRpb25hbGx5LCBzYXZlIHRoZSByZXN1bHRzIGFzIENTVgogICAgd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUoaGFsbG1hcmtfZG93biksIGZpbGUgPSBwYXN0ZTAob3V0cHV0X2ZvbGRlciwgImhhbGxtYXJrX2Rvd25yZWd1bGF0ZWRfZW5yaWNobWVudC5jc3YiKSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgfSBlbHNlIHsKICAgIGNhdCgiTm8gc2lnbmlmaWNhbnQgZW5yaWNobWVudCBmb3VuZCBmb3IgZG93bnJlZ3VsYXRlZCBnZW5lcy5cbiIpCiAgfQp9IGVsc2UgewogIGNhdCgiTm8gZG93bnJlZ3VsYXRlZCBnZW5lcyBvdmVybGFwIHdpdGggSGFsbG1hcmsgZ2VuZSBzZXRzLlxuIikKfQoKCmBgYAoKCgo=