1. load libraries

2. Perform DE analysis using Malignant_CD4Tcells_vs_Normal_CD4Tcells genes


Malignant_CD4Tcells_vs_Normal_CD4Tcells <- read.csv("../1-MAST_with_SCT_batch_patient_cellline_as_Covariate_with_meanExpression.csv", header = T)

3. Create the 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 <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  arrange(p_val_adj, desc(abs(avg_log2FC)))

# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_log2FC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_log2FC", 
  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_log2FC) >= 1.0]  # Only label significant genes
)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_log2FC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_log2FC", 
  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_log2FC) >= 1.0]
) 
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

4. Perform Fast GSEA using Hallmark Gene Sets

# Load necessary libraries
library(fgsea)
library(msigdbr)
library(dplyr)

# Obtain Hallmark gene sets from msigdbr
hallmark_genes <- msigdbr(species = "Homo sapiens", category = "H")

# Convert the gene sets to a list format for fgsea
hallmark_list <- hallmark_genes %>%
  split(x = .$gene_symbol, f = .$gs_name)

# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Create a ranked list with SIGNED metric
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  mutate(rank_metric = avg_log2FC * -log10(p_val_adj))


# Ensure no NA values in rank_metric
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  filter(!is.na(rank_metric))

# Create a named vector for ranking
gene_list <- Malignant_CD4Tcells_vs_Normal_CD4Tcells$rank_metric
names(gene_list) <- Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene

# Remove infinite values and sort in decreasing order
gene_list <- gene_list[is.finite(gene_list)]
gene_list <- sort(gene_list, decreasing = TRUE)

# Perform fast GSEA using fgseaMultilevel
fgsea_result <- fgsea(pathways = hallmark_list, 
                                stats = gene_list,
                                eps = 0.0,
                                minSize = 15,
                                maxSize = 500)  # No need for nperm

# View the fgsea results
head(fgsea_result[order(pval), ])
NA
NA

4. Perform Visualization of fgseq using Hallmark Gene Sets

library(data.table)
library(fgsea)
library(ggplot2)

# Plot the top pathway
top_pathway <- fgsea_result[order(fgsea_result$padj), ][1, ]
plotEnrichment(hallmark_list[[top_pathway$pathway]], gene_list) +
  labs(title = top_pathway$pathway)


topPathwaysUp <- fgsea_result[ES > 0][head(order(padj), n=10), pathway]
topPathwaysDown <- fgsea_result[ES < 0][head(order(padj), n=10), pathway]
topPathways <- c(topPathwaysUp, rev(topPathwaysDown))
plotGseaTable(hallmark_list[topPathways], gene_list, fgsea_result, 
              gseaParam=0.5)

NA
NA

. Visualization-Hallmark

fgseaResTidy <- fgsea_result %>%
  as_tibble() %>%
  arrange(desc(NES))

# Show in a nice table, excluding any columns that do not exist
fgseaResTidy %>% 
  dplyr::select(-leadingEdge, -ES) %>% 
  arrange(padj) %>% 
  DT::datatable()

ggplot(fgseaResTidy, aes(reorder(pathway, NES), NES)) +
  geom_col(aes(fill=padj<0.05)) +
  coord_flip() +
  labs(x="Pathway", y="Normalized Enrichment Score",
       title="Hallmark pathways NES from fgsea") + 
  theme_minimal() + 
  scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "grey")) +
  theme(axis.text.y = element_text(size = 8))  # Adjust axis text size for readability

NA
NA
NA

5. Obtain KEGG Gene Sets and Perform fgsea Using KEGG Pathways

library(fgsea)
library(msigdbr)
library(dplyr)
library(pheatmap)

# Obtain KEGG gene sets from msigdbr
kegg_genes <- msigdbr(species = "Homo sapiens", category = "C2", subcategory = "CP:KEGG")

# Convert the gene sets to a list format for fgsea
kegg_list <- kegg_genes %>%
  split(x = .$gene_symbol, f = .$gs_name)

# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Create a ranked list based on avg_log2FC and p_val_adj
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  mutate(rank_metric = avg_log2FC * -log10(p_val_adj))

# Ensure no NA values in rank_metric
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  filter(!is.na(rank_metric))

# Create a named vector for ranking
gene_list <- Malignant_CD4Tcells_vs_Normal_CD4Tcells$rank_metric
names(gene_list) <- Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene

# Sort the named vector in decreasing order
gene_list <- sort(gene_list, decreasing = TRUE)

gene_list <- gene_list[is.finite(gene_list)]

# Perform fast GSEA using KEGG pathways
fgsea_result_kegg <- fgsea(pathways = kegg_list, 
                           stats = gene_list,
                           eps=0.0,
                           minSize = 10,
                           maxSize = 500)  


# View the fgsea results
head(fgsea_result_kegg[order(pval), ])
NA
NA

6. Perform Visualization of fgseq using KEGG Gene Sets

library(data.table)
library(fgsea)
library(ggplot2)

# Plot the top pathway
top_pathway <- fgsea_result_kegg[order(fgsea_result_kegg$padj), ][1, ]
plotEnrichment(kegg_list[[top_pathway$pathway]], gene_list) +
  labs(title = top_pathway$pathway)


topPathwaysUp <- fgsea_result_kegg[ES > 0][head(order(padj), n=10), pathway]
topPathwaysDown <- fgsea_result_kegg[ES < 0][head(order(padj), n=10), pathway]
topPathways <- c(topPathwaysUp, rev(topPathwaysDown))
plotGseaTable(kegg_list[topPathways], gene_list, fgsea_result_kegg, 
              gseaParam=0.5)

NA
NA

. Visualization-Kegg1

fgseaResTidy <- fgsea_result_kegg %>%
  as_tibble() %>%
  arrange(desc(NES))

# Show in a nice table, excluding any columns that do not exist
fgseaResTidy %>% 
  dplyr::select(-leadingEdge, -ES) %>% 
  arrange(padj) %>% 
  DT::datatable()

ggplot(fgseaResTidy, aes(reorder(pathway, NES), NES)) +
  geom_col(aes(fill=padj<0.05)) +
  coord_flip() +
  labs(x="Pathway", y="Normalized Enrichment Score",
       title="Hallmark pathways NES from fgsea") + 
  theme_minimal() + 
  scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "grey")) +
  theme(axis.text.y = element_text(size = 8))  # Adjust axis text size for readability

NA
NA
NA

. Visualization-Kegg2

# Arrange by NES and select top 20 up and down pathways
topUp <- fgseaResTidy %>%
  dplyr::filter(NES > 0) %>%
  dplyr::arrange(desc(NES)) %>%
  dplyr::slice_head(n = 20)

topDown <- fgseaResTidy %>%
  dplyr::filter(NES < 0) %>%
  dplyr::arrange(NES) %>%
  dplyr::slice_head(n = 20)

# Combine the top up and down pathways
topPathways <- dplyr::bind_rows(topUp, topDown)


ggplot(topPathways, aes(reorder(pathway, NES), NES)) +
  geom_col(aes(fill = padj < 0.05)) +
  coord_flip() +
  labs(x = "Pathway", y = "Normalized Enrichment Score",
       title = "Top 20 Up and Down KEGG Pathways NES from GSEA") +
  theme_minimal() +
  scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "grey"))

NA
NA
NA
NA

7. Save Hallmark and kegg to CSV


# # Assuming you have the results stored in fgsea_result_hallmark and fgsea_result_kegg
# 
# # Flatten the list columns into character strings for Hallmark results
# fgsea_result_hallmark_flattened <- fgsea_result %>%
#   mutate(across(where(is.list), ~ sapply(., toString)))
# 
# # Write the flattened Hallmark results to a CSV file
# write.csv(fgsea_result_hallmark_flattened, "fgsea_results_hallmark.csv", row.names = FALSE)
# 
# # Flatten the list columns into character strings for KEGG results
# fgsea_result_kegg_flattened <- fgsea_result_kegg %>%
#   mutate(across(where(is.list), ~ sapply(., toString)))
# 
# # Write the flattened KEGG results to a CSV file
# write.csv(fgsea_result_kegg_flattened, "fgsea_results_kegg.csv", row.names = FALSE)


ggplot(data.frame(gene_symbol = names(gene_list)[1:50], ranks = gene_list[1:50]), aes(gene_symbol, ranks)) + 
    geom_point() +
    theme_classic() + 
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

8. Hallmark genes founf in multiple pathways


# Load necessary libraries
library(dplyr)
library(tidyr)
library(ggplot2)

# Assuming 'fgsea_results' is the output of your fgsea analysis

# Step 1: Extract the leading edge genes for each significant pathway
# 'leadingEdge' contains the gene names that contribute to the enrichment of the pathway
significant_gene_sets <- fgsea_result %>%
  filter(padj < 0.05) %>%
  select(pathway, leadingEdge)

# Step 2: Unnest the leadingEdge column (convert list to rows)
significant_gene_sets <- significant_gene_sets %>%
  unnest(cols = leadingEdge)

# Step 3: Count how many times each gene appears across pathways
gene_count <- significant_gene_sets %>%
  group_by(leadingEdge) %>%
  summarise(count = n()) %>%
  arrange(desc(count))  # Arrange genes by the number of pathways they appear in

# Step 4: Visualize the top regulator genes (genes that appear in multiple pathways)
top_regulator_genes <- gene_count %>%
  filter(count > 1)  # Genes involved in more than one pathway

# Plot top regulator genes involved in multiple pathways
ggplot(top_regulator_genes, aes(x = reorder(leadingEdge, -count), y = count)) +
  geom_bar(stat = "identity", fill = "salmon") +
  coord_flip() +
  labs(title = "Top Regulator Genes Involved in Multiple Pathways",
       x = "Gene",
       y = "Number of Pathways") +
  theme_minimal()


# Step 5: Output the gene counts to a CSV file for further inspection
write.csv(gene_count, "gene_count_in_multiple_pathways.csv")

8. Hallmark genes founf in multiple pathways


# Load necessary libraries
library(dplyr)
library(tidyr)
library(ggplot2)

# Assuming 'fgsea_results' is the output of your fgsea analysis

# Step 1: Extract the leading edge genes for each significant pathway
# 'leadingEdge' contains the gene names that contribute to the enrichment of the pathway
significant_gene_sets <- fgsea_result_kegg %>%
  filter(padj < 0.05) %>%
  select(pathway, leadingEdge)

# Step 2: Unnest the leadingEdge column (convert list to rows)
significant_gene_sets <- significant_gene_sets %>%
  unnest(cols = leadingEdge)

# Step 3: Count how many times each gene appears across pathways
gene_count <- significant_gene_sets %>%
  group_by(leadingEdge) %>%
  summarise(count = n()) %>%
  arrange(desc(count))  # Arrange genes by the number of pathways they appear in

# Step 4: Visualize the top regulator genes (genes that appear in multiple pathways)
top_regulator_genes <- gene_count %>%
  filter(count > 1)  # Genes involved in more than one pathway

# Plot top regulator genes involved in multiple pathways
ggplot(top_regulator_genes, aes(x = reorder(leadingEdge, -count), y = count)) +
  geom_bar(stat = "identity", fill = "salmon") +
  coord_flip() +
  labs(title = "Top Regulator Genes Involved in Multiple Pathways",
       x = "Gene",
       y = "Number of Pathways") +
  theme_minimal()


# Step 5: Output the gene counts to a CSV file for further inspection
write.csv(gene_count, "gene_count_in_multiple_pathways.csv")
LS0tCnRpdGxlOiAiRkdTRUEtIG9mIE1hbGlnbmFudCBDRDRUY2VsbHMgdnMgQ29udHJvbChOb3JtYWwgQ0Q0IFRjZWxscykiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KFNldXJhdERhdGEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHJldGljdWxhdGUpCmxpYnJhcnkoQXppbXV0aCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSdHNuZSkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCn0pCiAgCmBgYAoKIyAyLiBQZXJmb3JtIERFIGFuYWx5c2lzIHVzaW5nIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyBnZW5lcwpgYGB7ciBkYXRhMSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgPC0gcmVhZC5jc3YoIi4uLzEtTUFTVF93aXRoX1NDVF9iYXRjaF9wYXRpZW50X2NlbGxsaW5lX2FzX0NvdmFyaWF0ZV93aXRoX21lYW5FeHByZXNzaW9uLmNzdiIsIGhlYWRlciA9IFQpCmBgYAoKIyAzLiBDcmVhdGUgdGhlIEVuaGFuY2VkVm9sY2FubyBwbG90CmBgYHtyIGVuaGFuY2VkViwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQoKbGlicmFyeShkcGx5cikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBGaWx0ZXIgZ2VuZXMgYmFzZWQgb24gbG93ZXN0IHAtdmFsdWVzIGJ1dCBpbmNsdWRlIGFsbCBnZW5lcwpmaWx0ZXJlZF9nZW5lcyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgJT4lCiAgYXJyYW5nZShwX3ZhbF9hZGosIGRlc2MoYWJzKGF2Z19sb2cyRkMpKSkKCiMgQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gcGxvdCB3aXRoIHRoZSBmaWx0ZXJlZCBkYXRhCkVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2cyRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZzJGQyIsIAogIHkgPSAicF92YWxfYWRqIiwKICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMoY2VsbCBsaW5lcykgdnMgbm9ybWFsIENENCBUIGNlbGxzIiwKICBwQ3V0b2ZmID0gMC4wNSwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIAogIGxhYkNvbCA9ICdibGFjaycsCiAgbGFiRmFjZSA9ICdib2xkJywKICBib3hlZExhYmVscyA9IEZBTFNFLCAgIyBTZXQgdG8gRkFMU0UgdG8gcmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b21pemUgcG9pbnQgY29sb3JzCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nMkZDKSA+PSAxLjBdICAjIE9ubHkgbGFiZWwgc2lnbmlmaWNhbnQgZ2VuZXMKKQoKCgpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nMkZDKSA+PSAxLjAsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2cyRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzIChjZWxsIGxpbmVzKSB2cyBOb3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHN1YnRpdGxlID0gIkhpZ2hsaWdodGluZyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMiLAogIHBDdXRvZmYgPSAwLjA1LAogIEZDY3V0b2ZmID0gMS4wLAogIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICBjb2xBbHBoYSA9IDAuOCwgICMgU2xpZ2h0IHRyYW5zcGFyZW5jeSBmb3Igbm9uLXNpZ25pZmljYW50IHBvaW50cwogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b20gY29sb3Igc2NoZW1lCiAgZ3JpZGxpbmVzLm1ham9yID0gVFJVRSwKICBncmlkbGluZXMubWlub3IgPSBGQUxTRSwKICBzZWxlY3RMYWIgPSBmaWx0ZXJlZF9nZW5lcyRnZW5lW2ZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2cyRkMpID49IDEuMF0KKSAKCgpgYGAKCiMgNC4gIFBlcmZvcm0gRmFzdCBHU0VBIHVzaW5nIEhhbGxtYXJrIEdlbmUgU2V0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZHBseXIpCgojIE9idGFpbiBIYWxsbWFyayBnZW5lIHNldHMgZnJvbSBtc2lnZGJyCmhhbGxtYXJrX2dlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikKCiMgQ29udmVydCB0aGUgZ2VuZSBzZXRzIHRvIGEgbGlzdCBmb3JtYXQgZm9yIGZnc2VhCmhhbGxtYXJrX2xpc3QgPC0gaGFsbG1hcmtfZ2VuZXMgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBDcmVhdGUgYSByYW5rZWQgbGlzdCB3aXRoIFNJR05FRCBtZXRyaWMKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBtdXRhdGUocmFua19tZXRyaWMgPSBhdmdfbG9nMkZDICogLWxvZzEwKHBfdmFsX2FkaikpCgoKIyBFbnN1cmUgbm8gTkEgdmFsdWVzIGluIHJhbmtfbWV0cmljCk1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgJT4lCiAgZmlsdGVyKCFpcy5uYShyYW5rX21ldHJpYykpCgojIENyZWF0ZSBhIG5hbWVkIHZlY3RvciBmb3IgcmFua2luZwpnZW5lX2xpc3QgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJHJhbmtfbWV0cmljCm5hbWVzKGdlbmVfbGlzdCkgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUKCiMgUmVtb3ZlIGluZmluaXRlIHZhbHVlcyBhbmQgc29ydCBpbiBkZWNyZWFzaW5nIG9yZGVyCmdlbmVfbGlzdCA8LSBnZW5lX2xpc3RbaXMuZmluaXRlKGdlbmVfbGlzdCldCmdlbmVfbGlzdCA8LSBzb3J0KGdlbmVfbGlzdCwgZGVjcmVhc2luZyA9IFRSVUUpCgojIFBlcmZvcm0gZmFzdCBHU0VBIHVzaW5nIGZnc2VhTXVsdGlsZXZlbApmZ3NlYV9yZXN1bHQgPC0gZmdzZWEocGF0aHdheXMgPSBoYWxsbWFya19saXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0cyA9IGdlbmVfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcHMgPSAwLjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluU2l6ZSA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heFNpemUgPSA1MDApICAjIE5vIG5lZWQgZm9yIG5wZXJtCgojIFZpZXcgdGhlIGZnc2VhIHJlc3VsdHMKaGVhZChmZ3NlYV9yZXN1bHRbb3JkZXIocHZhbCksIF0pCgoKYGBgCgoKCiMgNC4gIFBlcmZvcm0gVmlzdWFsaXphdGlvbiBvZiBmZ3NlcSB1c2luZyBIYWxsbWFyayBHZW5lIFNldHMKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KGdncGxvdDIpCgojIFBsb3QgdGhlIHRvcCBwYXRod2F5CnRvcF9wYXRod2F5IDwtIGZnc2VhX3Jlc3VsdFtvcmRlcihmZ3NlYV9yZXN1bHQkcGFkaiksIF1bMSwgXQpwbG90RW5yaWNobWVudChoYWxsbWFya19saXN0W1t0b3BfcGF0aHdheSRwYXRod2F5XV0sIGdlbmVfbGlzdCkgKwogIGxhYnModGl0bGUgPSB0b3BfcGF0aHdheSRwYXRod2F5KQoKdG9wUGF0aHdheXNVcCA8LSBmZ3NlYV9yZXN1bHRbRVMgPiAwXVtoZWFkKG9yZGVyKHBhZGopLCBuPTEwKSwgcGF0aHdheV0KdG9wUGF0aHdheXNEb3duIDwtIGZnc2VhX3Jlc3VsdFtFUyA8IDBdW2hlYWQob3JkZXIocGFkaiksIG49MTApLCBwYXRod2F5XQp0b3BQYXRod2F5cyA8LSBjKHRvcFBhdGh3YXlzVXAsIHJldih0b3BQYXRod2F5c0Rvd24pKQpwbG90R3NlYVRhYmxlKGhhbGxtYXJrX2xpc3RbdG9wUGF0aHdheXNdLCBnZW5lX2xpc3QsIGZnc2VhX3Jlc3VsdCwgCiAgICAgICAgICAgICAgZ3NlYVBhcmFtPTAuNSkKCgpgYGAKCiMjIC4gVmlzdWFsaXphdGlvbi1IYWxsbWFyawpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpmZ3NlYVJlc1RpZHkgPC0gZmdzZWFfcmVzdWx0ICU+JQogIGFzX3RpYmJsZSgpICU+JQogIGFycmFuZ2UoZGVzYyhORVMpKQoKIyBTaG93IGluIGEgbmljZSB0YWJsZSwgZXhjbHVkaW5nIGFueSBjb2x1bW5zIHRoYXQgZG8gbm90IGV4aXN0CmZnc2VhUmVzVGlkeSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtbGVhZGluZ0VkZ2UsIC1FUykgJT4lIAogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKQoKZ2dwbG90KGZnc2VhUmVzVGlkeSwgYWVzKHJlb3JkZXIocGF0aHdheSwgTkVTKSwgTkVTKSkgKwogIGdlb21fY29sKGFlcyhmaWxsPXBhZGo8MC4wNSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoeD0iUGF0aHdheSIsIHk9Ik5vcm1hbGl6ZWQgRW5yaWNobWVudCBTY29yZSIsCiAgICAgICB0aXRsZT0iSGFsbG1hcmsgcGF0aHdheXMgTkVTIGZyb20gZmdzZWEiKSArIAogIHRoZW1lX21pbmltYWwoKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gInJlZCIsICJGQUxTRSIgPSAiZ3JleSIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSAgIyBBZGp1c3QgYXhpcyB0ZXh0IHNpemUgZm9yIHJlYWRhYmlsaXR5CgoKCmBgYAoKIyA1LiBPYnRhaW4gS0VHRyBHZW5lIFNldHMgYW5kIFBlcmZvcm0gZmdzZWEgVXNpbmcgS0VHRyBQYXRod2F5cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGhlYXRtYXApCgojIE9idGFpbiBLRUdHIGdlbmUgc2V0cyBmcm9tIG1zaWdkYnIKa2VnZ19nZW5lcyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiLCBzdWJjYXRlZ29yeSA9ICJDUDpLRUdHIikKCiMgQ29udmVydCB0aGUgZ2VuZSBzZXRzIHRvIGEgbGlzdCBmb3JtYXQgZm9yIGZnc2VhCmtlZ2dfbGlzdCA8LSBrZWdnX2dlbmVzICU+JQogIHNwbGl0KHggPSAuJGdlbmVfc3ltYm9sLCBmID0gLiRnc19uYW1lKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgQ3JlYXRlIGEgcmFua2VkIGxpc3QgYmFzZWQgb24gYXZnX2xvZzJGQyBhbmQgcF92YWxfYWRqCk1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgJT4lCiAgbXV0YXRlKHJhbmtfbWV0cmljID0gYXZnX2xvZzJGQyAqIC1sb2cxMChwX3ZhbF9hZGopKQoKIyBFbnN1cmUgbm8gTkEgdmFsdWVzIGluIHJhbmtfbWV0cmljCk1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgJT4lCiAgZmlsdGVyKCFpcy5uYShyYW5rX21ldHJpYykpCgojIENyZWF0ZSBhIG5hbWVkIHZlY3RvciBmb3IgcmFua2luZwpnZW5lX2xpc3QgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJHJhbmtfbWV0cmljCm5hbWVzKGdlbmVfbGlzdCkgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUKCiMgU29ydCB0aGUgbmFtZWQgdmVjdG9yIGluIGRlY3JlYXNpbmcgb3JkZXIKZ2VuZV9saXN0IDwtIHNvcnQoZ2VuZV9saXN0LCBkZWNyZWFzaW5nID0gVFJVRSkKCmdlbmVfbGlzdCA8LSBnZW5lX2xpc3RbaXMuZmluaXRlKGdlbmVfbGlzdCldCgojIFBlcmZvcm0gZmFzdCBHU0VBIHVzaW5nIEtFR0cgcGF0aHdheXMKZmdzZWFfcmVzdWx0X2tlZ2cgPC0gZmdzZWEocGF0aHdheXMgPSBrZWdnX2xpc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0cyA9IGdlbmVfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZXBzPTAuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluU2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhTaXplID0gNTAwKSAgCgoKIyBWaWV3IHRoZSBmZ3NlYSByZXN1bHRzCmhlYWQoZmdzZWFfcmVzdWx0X2tlZ2dbb3JkZXIocHZhbCksIF0pCgoKYGBgCgojIDYuICBQZXJmb3JtIFZpc3VhbGl6YXRpb24gb2YgZmdzZXEgdXNpbmcgS0VHRyBHZW5lIFNldHMKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KGdncGxvdDIpCgojIFBsb3QgdGhlIHRvcCBwYXRod2F5CnRvcF9wYXRod2F5IDwtIGZnc2VhX3Jlc3VsdF9rZWdnW29yZGVyKGZnc2VhX3Jlc3VsdF9rZWdnJHBhZGopLCBdWzEsIF0KcGxvdEVucmljaG1lbnQoa2VnZ19saXN0W1t0b3BfcGF0aHdheSRwYXRod2F5XV0sIGdlbmVfbGlzdCkgKwogIGxhYnModGl0bGUgPSB0b3BfcGF0aHdheSRwYXRod2F5KQoKdG9wUGF0aHdheXNVcCA8LSBmZ3NlYV9yZXN1bHRfa2VnZ1tFUyA+IDBdW2hlYWQob3JkZXIocGFkaiksIG49MTApLCBwYXRod2F5XQp0b3BQYXRod2F5c0Rvd24gPC0gZmdzZWFfcmVzdWx0X2tlZ2dbRVMgPCAwXVtoZWFkKG9yZGVyKHBhZGopLCBuPTEwKSwgcGF0aHdheV0KdG9wUGF0aHdheXMgPC0gYyh0b3BQYXRod2F5c1VwLCByZXYodG9wUGF0aHdheXNEb3duKSkKcGxvdEdzZWFUYWJsZShrZWdnX2xpc3RbdG9wUGF0aHdheXNdLCBnZW5lX2xpc3QsIGZnc2VhX3Jlc3VsdF9rZWdnLCAKICAgICAgICAgICAgICBnc2VhUGFyYW09MC41KQoKCmBgYAoKIyMgLiBWaXN1YWxpemF0aW9uLUtlZ2cxCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmZnc2VhUmVzVGlkeSA8LSBmZ3NlYV9yZXN1bHRfa2VnZyAlPiUKICBhc190aWJibGUoKSAlPiUKICBhcnJhbmdlKGRlc2MoTkVTKSkKCiMgU2hvdyBpbiBhIG5pY2UgdGFibGUsIGV4Y2x1ZGluZyBhbnkgY29sdW1ucyB0aGF0IGRvIG5vdCBleGlzdApmZ3NlYVJlc1RpZHkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWxlYWRpbmdFZGdlLCAtRVMpICU+JSAKICBhcnJhbmdlKHBhZGopICU+JSAKICBEVDo6ZGF0YXRhYmxlKCkKCmdncGxvdChmZ3NlYVJlc1RpZHksIGFlcyhyZW9yZGVyKHBhdGh3YXksIE5FUyksIE5FUykpICsKICBnZW9tX2NvbChhZXMoZmlsbD1wYWRqPDAuMDUpKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHg9IlBhdGh3YXkiLCB5PSJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUiLAogICAgICAgdGl0bGU9IkhhbGxtYXJrIHBhdGh3YXlzIE5FUyBmcm9tIGZnc2VhIikgKyAKICB0aGVtZV9taW5pbWFsKCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICJyZWQiLCAiRkFMU0UiID0gImdyZXkiKSkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgICMgQWRqdXN0IGF4aXMgdGV4dCBzaXplIGZvciByZWFkYWJpbGl0eQoKCgpgYGAKCiMjIC4gVmlzdWFsaXphdGlvbi1LZWdnMgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIEFycmFuZ2UgYnkgTkVTIGFuZCBzZWxlY3QgdG9wIDIwIHVwIGFuZCBkb3duIHBhdGh3YXlzCnRvcFVwIDwtIGZnc2VhUmVzVGlkeSAlPiUKICBkcGx5cjo6ZmlsdGVyKE5FUyA+IDApICU+JQogIGRwbHlyOjphcnJhbmdlKGRlc2MoTkVTKSkgJT4lCiAgZHBseXI6OnNsaWNlX2hlYWQobiA9IDIwKQoKdG9wRG93biA8LSBmZ3NlYVJlc1RpZHkgJT4lCiAgZHBseXI6OmZpbHRlcihORVMgPCAwKSAlPiUKICBkcGx5cjo6YXJyYW5nZShORVMpICU+JQogIGRwbHlyOjpzbGljZV9oZWFkKG4gPSAyMCkKCiMgQ29tYmluZSB0aGUgdG9wIHVwIGFuZCBkb3duIHBhdGh3YXlzCnRvcFBhdGh3YXlzIDwtIGRwbHlyOjpiaW5kX3Jvd3ModG9wVXAsIHRvcERvd24pCgoKZ2dwbG90KHRvcFBhdGh3YXlzLCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBwYWRqIDwgMC4wNSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoeCA9ICJQYXRod2F5IiwgeSA9ICJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUiLAogICAgICAgdGl0bGUgPSAiVG9wIDIwIFVwIGFuZCBEb3duIEtFR0cgUGF0aHdheXMgTkVTIGZyb20gR1NFQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gInJlZCIsICJGQUxTRSIgPSAiZ3JleSIpKQoKCgoKYGBgCgojIDcuIFNhdmUgSGFsbG1hcmsgYW5kIGtlZ2cgdG8gQ1NWCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgojICMgQXNzdW1pbmcgeW91IGhhdmUgdGhlIHJlc3VsdHMgc3RvcmVkIGluIGZnc2VhX3Jlc3VsdF9oYWxsbWFyayBhbmQgZmdzZWFfcmVzdWx0X2tlZ2cKIyAKIyAjIEZsYXR0ZW4gdGhlIGxpc3QgY29sdW1ucyBpbnRvIGNoYXJhY3RlciBzdHJpbmdzIGZvciBIYWxsbWFyayByZXN1bHRzCiMgZmdzZWFfcmVzdWx0X2hhbGxtYXJrX2ZsYXR0ZW5lZCA8LSBmZ3NlYV9yZXN1bHQgJT4lCiMgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmxpc3QpLCB+IHNhcHBseSguLCB0b1N0cmluZykpKQojIAojICMgV3JpdGUgdGhlIGZsYXR0ZW5lZCBIYWxsbWFyayByZXN1bHRzIHRvIGEgQ1NWIGZpbGUKIyB3cml0ZS5jc3YoZmdzZWFfcmVzdWx0X2hhbGxtYXJrX2ZsYXR0ZW5lZCwgImZnc2VhX3Jlc3VsdHNfaGFsbG1hcmsuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCiMgCiMgIyBGbGF0dGVuIHRoZSBsaXN0IGNvbHVtbnMgaW50byBjaGFyYWN0ZXIgc3RyaW5ncyBmb3IgS0VHRyByZXN1bHRzCiMgZmdzZWFfcmVzdWx0X2tlZ2dfZmxhdHRlbmVkIDwtIGZnc2VhX3Jlc3VsdF9rZWdnICU+JQojICAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5saXN0KSwgfiBzYXBwbHkoLiwgdG9TdHJpbmcpKSkKIyAKIyAjIFdyaXRlIHRoZSBmbGF0dGVuZWQgS0VHRyByZXN1bHRzIHRvIGEgQ1NWIGZpbGUKIyB3cml0ZS5jc3YoZmdzZWFfcmVzdWx0X2tlZ2dfZmxhdHRlbmVkLCAiZmdzZWFfcmVzdWx0c19rZWdnLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCmdncGxvdChkYXRhLmZyYW1lKGdlbmVfc3ltYm9sID0gbmFtZXMoZ2VuZV9saXN0KVsxOjUwXSwgcmFua3MgPSBnZW5lX2xpc3RbMTo1MF0pLCBhZXMoZ2VuZV9zeW1ib2wsIHJhbmtzKSkgKyAKCWdlb21fcG9pbnQoKSArCgl0aGVtZV9jbGFzc2ljKCkgKyAKCXRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKCmBgYAojIDguICBIYWxsbWFyayBnZW5lcyBmb3VuZiBpbiBtdWx0aXBsZSBwYXRod2F5cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQoKIyBBc3N1bWluZyAnZmdzZWFfcmVzdWx0cycgaXMgdGhlIG91dHB1dCBvZiB5b3VyIGZnc2VhIGFuYWx5c2lzCgojIFN0ZXAgMTogRXh0cmFjdCB0aGUgbGVhZGluZyBlZGdlIGdlbmVzIGZvciBlYWNoIHNpZ25pZmljYW50IHBhdGh3YXkKIyAnbGVhZGluZ0VkZ2UnIGNvbnRhaW5zIHRoZSBnZW5lIG5hbWVzIHRoYXQgY29udHJpYnV0ZSB0byB0aGUgZW5yaWNobWVudCBvZiB0aGUgcGF0aHdheQpzaWduaWZpY2FudF9nZW5lX3NldHMgPC0gZmdzZWFfcmVzdWx0ICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSkgJT4lCiAgc2VsZWN0KHBhdGh3YXksIGxlYWRpbmdFZGdlKQoKIyBTdGVwIDI6IFVubmVzdCB0aGUgbGVhZGluZ0VkZ2UgY29sdW1uIChjb252ZXJ0IGxpc3QgdG8gcm93cykKc2lnbmlmaWNhbnRfZ2VuZV9zZXRzIDwtIHNpZ25pZmljYW50X2dlbmVfc2V0cyAlPiUKICB1bm5lc3QoY29scyA9IGxlYWRpbmdFZGdlKQoKIyBTdGVwIDM6IENvdW50IGhvdyBtYW55IHRpbWVzIGVhY2ggZ2VuZSBhcHBlYXJzIGFjcm9zcyBwYXRod2F5cwpnZW5lX2NvdW50IDwtIHNpZ25pZmljYW50X2dlbmVfc2V0cyAlPiUKICBncm91cF9ieShsZWFkaW5nRWRnZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnQpKSAgIyBBcnJhbmdlIGdlbmVzIGJ5IHRoZSBudW1iZXIgb2YgcGF0aHdheXMgdGhleSBhcHBlYXIgaW4KCiMgU3RlcCA0OiBWaXN1YWxpemUgdGhlIHRvcCByZWd1bGF0b3IgZ2VuZXMgKGdlbmVzIHRoYXQgYXBwZWFyIGluIG11bHRpcGxlIHBhdGh3YXlzKQp0b3BfcmVndWxhdG9yX2dlbmVzIDwtIGdlbmVfY291bnQgJT4lCiAgZmlsdGVyKGNvdW50ID4gMSkgICMgR2VuZXMgaW52b2x2ZWQgaW4gbW9yZSB0aGFuIG9uZSBwYXRod2F5CgojIFBsb3QgdG9wIHJlZ3VsYXRvciBnZW5lcyBpbnZvbHZlZCBpbiBtdWx0aXBsZSBwYXRod2F5cwpnZ3Bsb3QodG9wX3JlZ3VsYXRvcl9nZW5lcywgYWVzKHggPSByZW9yZGVyKGxlYWRpbmdFZGdlLCAtY291bnQpLCB5ID0gY291bnQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2FsbW9uIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgUmVndWxhdG9yIEdlbmVzIEludm9sdmVkIGluIE11bHRpcGxlIFBhdGh3YXlzIiwKICAgICAgIHggPSAiR2VuZSIsCiAgICAgICB5ID0gIk51bWJlciBvZiBQYXRod2F5cyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgU3RlcCA1OiBPdXRwdXQgdGhlIGdlbmUgY291bnRzIHRvIGEgQ1NWIGZpbGUgZm9yIGZ1cnRoZXIgaW5zcGVjdGlvbgp3cml0ZS5jc3YoZ2VuZV9jb3VudCwgImdlbmVfY291bnRfaW5fbXVsdGlwbGVfcGF0aHdheXMuY3N2IikKCgpgYGAKCgojIDguICBIYWxsbWFyayBnZW5lcyBmb3VuZiBpbiBtdWx0aXBsZSBwYXRod2F5cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQoKIyBBc3N1bWluZyAnZmdzZWFfcmVzdWx0cycgaXMgdGhlIG91dHB1dCBvZiB5b3VyIGZnc2VhIGFuYWx5c2lzCgojIFN0ZXAgMTogRXh0cmFjdCB0aGUgbGVhZGluZyBlZGdlIGdlbmVzIGZvciBlYWNoIHNpZ25pZmljYW50IHBhdGh3YXkKIyAnbGVhZGluZ0VkZ2UnIGNvbnRhaW5zIHRoZSBnZW5lIG5hbWVzIHRoYXQgY29udHJpYnV0ZSB0byB0aGUgZW5yaWNobWVudCBvZiB0aGUgcGF0aHdheQpzaWduaWZpY2FudF9nZW5lX3NldHMgPC0gZmdzZWFfcmVzdWx0X2tlZ2cgJT4lCiAgZmlsdGVyKHBhZGogPCAwLjA1KSAlPiUKICBzZWxlY3QocGF0aHdheSwgbGVhZGluZ0VkZ2UpCgojIFN0ZXAgMjogVW5uZXN0IHRoZSBsZWFkaW5nRWRnZSBjb2x1bW4gKGNvbnZlcnQgbGlzdCB0byByb3dzKQpzaWduaWZpY2FudF9nZW5lX3NldHMgPC0gc2lnbmlmaWNhbnRfZ2VuZV9zZXRzICU+JQogIHVubmVzdChjb2xzID0gbGVhZGluZ0VkZ2UpCgojIFN0ZXAgMzogQ291bnQgaG93IG1hbnkgdGltZXMgZWFjaCBnZW5lIGFwcGVhcnMgYWNyb3NzIHBhdGh3YXlzCmdlbmVfY291bnQgPC0gc2lnbmlmaWNhbnRfZ2VuZV9zZXRzICU+JQogIGdyb3VwX2J5KGxlYWRpbmdFZGdlKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIGFycmFuZ2UoZGVzYyhjb3VudCkpICAjIEFycmFuZ2UgZ2VuZXMgYnkgdGhlIG51bWJlciBvZiBwYXRod2F5cyB0aGV5IGFwcGVhciBpbgoKIyBTdGVwIDQ6IFZpc3VhbGl6ZSB0aGUgdG9wIHJlZ3VsYXRvciBnZW5lcyAoZ2VuZXMgdGhhdCBhcHBlYXIgaW4gbXVsdGlwbGUgcGF0aHdheXMpCnRvcF9yZWd1bGF0b3JfZ2VuZXMgPC0gZ2VuZV9jb3VudCAlPiUKICBmaWx0ZXIoY291bnQgPiAxKSAgIyBHZW5lcyBpbnZvbHZlZCBpbiBtb3JlIHRoYW4gb25lIHBhdGh3YXkKCiMgUGxvdCB0b3AgcmVndWxhdG9yIGdlbmVzIGludm9sdmVkIGluIG11bHRpcGxlIHBhdGh3YXlzCmdncGxvdCh0b3BfcmVndWxhdG9yX2dlbmVzLCBhZXMoeCA9IHJlb3JkZXIobGVhZGluZ0VkZ2UsIC1jb3VudCksIHkgPSBjb3VudCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJzYWxtb24iKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCBSZWd1bGF0b3IgR2VuZXMgSW52b2x2ZWQgaW4gTXVsdGlwbGUgUGF0aHdheXMiLAogICAgICAgeCA9ICJHZW5lIiwKICAgICAgIHkgPSAiTnVtYmVyIG9mIFBhdGh3YXlzIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBTdGVwIDU6IE91dHB1dCB0aGUgZ2VuZSBjb3VudHMgdG8gYSBDU1YgZmlsZSBmb3IgZnVydGhlciBpbnNwZWN0aW9uCndyaXRlLmNzdihnZW5lX2NvdW50LCAiZ2VuZV9jb3VudF9pbl9tdWx0aXBsZV9wYXRod2F5cy5jc3YiKQoKCmBgYA==