1. load libraries

2. Perform DE analysis using Malignant_CD4Tcells_vs_Normal_CD4Tcells genes


Malignant_CD4Tcells_vs_Normal_CD4Tcells <- read.csv("1-Pseudobulk_DEseq2_LRT_DE_with_libra.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_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 = 1e-10,
  FCcutoff = 1.5,
  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 = 1e-10,
  FCcutoff = 1.5,
  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

4. Perform Fast GSEA using Hallmark Gene Sets

# Load necessary libraries
library(fgsea)
library(msigdbr)
For full functionality, please install the 'msigdbdf' package with:
install.packages('msigdbdf', repos = 'https://igordot.r-universe.dev')
library(dplyr)

# Obtain Hallmark gene sets from msigdbr
hallmark_genes <- msigdbr(species = "Homo sapiens", category = "H")
Warning: The `category` argument of `msigdbr()` is deprecated as of msigdbr 10.0.0.
Please use the `collection` argument instead.The 'msigdbdf' package must be installed to access the full dataset.
Would you like to install 'msigdbdf'? 

1: Yes
2: No
yes
Enter an item from the menu, or 0 to exit
Yes
Installing the 'msigdbdf' package.
Installing package into '/home/bioinfo/R/x86_64-pc-linux-gnu-library/4.4'
(as 'lib' is unspecified)
Warning: cannot open URL 'https://igordot.r-universe.dev/src/contrib/PACKAGES.rds': HTTP status was '404 Not Found'trying URL 'https://igordot.r-universe.dev/src/contrib/msigdbdf_24.1.0.tar.gz'
Content type 'application/gzip' length 12837035 bytes (12.2 MB)
==================================================
downloaded 12.2 MB

* installing *source* package ‘msigdbdf’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** 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)

The downloaded source packages are in
    '/tmp/RtmpoFbgHs/downloaded_packages'
# 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_logFC * -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)
data.table 1.17.0 using 8 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: 'data.table'

The following objects are masked from 'package:dplyr':

    between, first, last
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 Legacy gene sets from msigdbr
kegg_genes <- msigdbr(species = "Homo sapiens", category = "C2", subcollection = "CP:KEGG_LEGACY")

# 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_logFC and p_val_adj
Malignant_CD4Tcells_vs_Normal_CD4Tcells <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  mutate(rank_metric = avg_logFC * -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 found 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 found 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")
LS0tCnRpdGxlOiAiRkdTRUEtIG9mIE1hbGlnbmFudCBDRDRUY2VsbHMgdnMgQ29udHJvbChOb3JtYWwgQ0Q0IFRjZWxscykiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KFNldXJhdERhdGEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHJldGljdWxhdGUpCmxpYnJhcnkoQXppbXV0aCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSdHNuZSkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCn0pCiAgCmBgYAoKIyAyLiBQZXJmb3JtIERFIGFuYWx5c2lzIHVzaW5nIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyBnZW5lcwpgYGB7ciBkYXRhMSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgPC0gcmVhZC5jc3YoIjEtUHNldWRvYnVsa19ERXNlcTJfTFJUX0RFX3dpdGhfbGlicmEuY3N2IiwgaGVhZGVyID0gVCkKYGBgCgojIDMuIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3QKYGBge3IgZW5oYW5jZWRWLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiMgQXNzdW1pbmcgeW91IGhhdmUgYSBkYXRhIGZyYW1lIG5hbWVkIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscwojIEZpbHRlciBnZW5lcyBiYXNlZCBvbiBsb3dlc3QgcC12YWx1ZXMgYnV0IGluY2x1ZGUgYWxsIGdlbmVzCmZpbHRlcmVkX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBhcnJhbmdlKHBfdmFsX2FkaiwgZGVzYyhhYnMoYXZnX2xvZ0ZDKSkpCgojIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3Qgd2l0aCB0aGUgZmlsdGVyZWQgZGF0YQpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyhjZWxsIGxpbmVzKSB2cyBub3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHBDdXRvZmYgPSAxZS0xMCwKICBGQ2N1dG9mZiA9IDEuNSwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsIAogIGxhYkNvbCA9ICdibGFjaycsCiAgbGFiRmFjZSA9ICdib2xkJywKICBib3hlZExhYmVscyA9IEZBTFNFLCAgIyBTZXQgdG8gRkFMU0UgdG8gcmVtb3ZlIGJveGVkIGxhYmVscwogIHBvaW50U2l6ZSA9IDMuMCwKICBsYWJTaXplID0gNS4wLAogIGNvbCA9IGMoJ2dyZXk3MCcsICdibGFjaycsICdibHVlJywgJ3JlZCcpLCAgIyBDdXN0b21pemUgcG9pbnQgY29sb3JzCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0gICMgT25seSBsYWJlbCBzaWduaWZpY2FudCBnZW5lcwopCgoKCkVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzIChjZWxsIGxpbmVzKSB2cyBOb3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHN1YnRpdGxlID0gIkhpZ2hsaWdodGluZyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMiLAogIHBDdXRvZmYgPSAxZS0xMCwKICBGQ2N1dG9mZiA9IDEuNSwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgY29sQWxwaGEgPSAwLjgsICAjIFNsaWdodCB0cmFuc3BhcmVuY3kgZm9yIG5vbi1zaWduaWZpY2FudCBwb2ludHMKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9tIGNvbG9yIHNjaGVtZQogIGdyaWRsaW5lcy5tYWpvciA9IFRSVUUsCiAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0KKSAKCgpgYGAKCiMgNC4gIFBlcmZvcm0gRmFzdCBHU0VBIHVzaW5nIEhhbGxtYXJrIEdlbmUgU2V0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZHBseXIpCgojIE9idGFpbiBIYWxsbWFyayBnZW5lIHNldHMgZnJvbSBtc2lnZGJyCmhhbGxtYXJrX2dlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikKCiMgQ29udmVydCB0aGUgZ2VuZSBzZXRzIHRvIGEgbGlzdCBmb3JtYXQgZm9yIGZnc2VhCmhhbGxtYXJrX2xpc3QgPC0gaGFsbG1hcmtfZ2VuZXMgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBDcmVhdGUgYSByYW5rZWQgbGlzdCB3aXRoIFNJR05FRCBtZXRyaWMKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBtdXRhdGUocmFua19tZXRyaWMgPSBhdmdfbG9nRkMgKiAtbG9nMTAocF92YWxfYWRqKSkKCgojIEVuc3VyZSBubyBOQSB2YWx1ZXMgaW4gcmFua19tZXRyaWMKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBmaWx0ZXIoIWlzLm5hKHJhbmtfbWV0cmljKSkKCiMgQ3JlYXRlIGEgbmFtZWQgdmVjdG9yIGZvciByYW5raW5nCmdlbmVfbGlzdCA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcmFua19tZXRyaWMKbmFtZXMoZ2VuZV9saXN0KSA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkZ2VuZQoKIyBSZW1vdmUgaW5maW5pdGUgdmFsdWVzIGFuZCBzb3J0IGluIGRlY3JlYXNpbmcgb3JkZXIKZ2VuZV9saXN0IDwtIGdlbmVfbGlzdFtpcy5maW5pdGUoZ2VuZV9saXN0KV0KZ2VuZV9saXN0IDwtIHNvcnQoZ2VuZV9saXN0LCBkZWNyZWFzaW5nID0gVFJVRSkKCiMgUGVyZm9ybSBmYXN0IEdTRUEgdXNpbmcgZmdzZWFNdWx0aWxldmVsCmZnc2VhX3Jlc3VsdCA8LSBmZ3NlYShwYXRod2F5cyA9IGhhbGxtYXJrX2xpc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRzID0gZ2VuZV9saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVwcyA9IDAuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5TaXplID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4U2l6ZSA9IDUwMCkgICMgTm8gbmVlZCBmb3IgbnBlcm0KCiMgVmlldyB0aGUgZmdzZWEgcmVzdWx0cwpoZWFkKGZnc2VhX3Jlc3VsdFtvcmRlcihwdmFsKSwgXSkKCgpgYGAKCgoKIyA0LiAgUGVyZm9ybSBWaXN1YWxpemF0aW9uIG9mIGZnc2VxIHVzaW5nIEhhbGxtYXJrIEdlbmUgU2V0cwpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkoZ2dwbG90MikKCiMgUGxvdCB0aGUgdG9wIHBhdGh3YXkKdG9wX3BhdGh3YXkgPC0gZmdzZWFfcmVzdWx0W29yZGVyKGZnc2VhX3Jlc3VsdCRwYWRqKSwgXVsxLCBdCnBsb3RFbnJpY2htZW50KGhhbGxtYXJrX2xpc3RbW3RvcF9wYXRod2F5JHBhdGh3YXldXSwgZ2VuZV9saXN0KSArCiAgbGFicyh0aXRsZSA9IHRvcF9wYXRod2F5JHBhdGh3YXkpCgp0b3BQYXRod2F5c1VwIDwtIGZnc2VhX3Jlc3VsdFtFUyA+IDBdW2hlYWQob3JkZXIocGFkaiksIG49MTApLCBwYXRod2F5XQp0b3BQYXRod2F5c0Rvd24gPC0gZmdzZWFfcmVzdWx0W0VTIDwgMF1baGVhZChvcmRlcihwYWRqKSwgbj0xMCksIHBhdGh3YXldCnRvcFBhdGh3YXlzIDwtIGModG9wUGF0aHdheXNVcCwgcmV2KHRvcFBhdGh3YXlzRG93bikpCnBsb3RHc2VhVGFibGUoaGFsbG1hcmtfbGlzdFt0b3BQYXRod2F5c10sIGdlbmVfbGlzdCwgZmdzZWFfcmVzdWx0LCAKICAgICAgICAgICAgICBnc2VhUGFyYW09MC41KQoKCmBgYAoKIyMgLiBWaXN1YWxpemF0aW9uLUhhbGxtYXJrCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmZnc2VhUmVzVGlkeSA8LSBmZ3NlYV9yZXN1bHQgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgYXJyYW5nZShkZXNjKE5FUykpCgojIFNob3cgaW4gYSBuaWNlIHRhYmxlLCBleGNsdWRpbmcgYW55IGNvbHVtbnMgdGhhdCBkbyBub3QgZXhpc3QKZmdzZWFSZXNUaWR5ICU+JSAKICBkcGx5cjo6c2VsZWN0KC1sZWFkaW5nRWRnZSwgLUVTKSAlPiUgCiAgYXJyYW5nZShwYWRqKSAlPiUgCiAgRFQ6OmRhdGF0YWJsZSgpCgpnZ3Bsb3QoZmdzZWFSZXNUaWR5LCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGw9cGFkajwwLjA1KSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh4PSJQYXRod2F5IiwgeT0iTm9ybWFsaXplZCBFbnJpY2htZW50IFNjb3JlIiwKICAgICAgIHRpdGxlPSJIYWxsbWFyayBwYXRod2F5cyBORVMgZnJvbSBmZ3NlYSIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAicmVkIiwgIkZBTFNFIiA9ICJncmV5IikpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICAjIEFkanVzdCBheGlzIHRleHQgc2l6ZSBmb3IgcmVhZGFiaWxpdHkKCgoKYGBgCgojIDUuIE9idGFpbiBLRUdHIEdlbmUgU2V0cyBhbmQgUGVyZm9ybSBmZ3NlYSBVc2luZyBLRUdHIFBhdGh3YXlzCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkobXNpZ2RicikKbGlicmFyeShkcGx5cikKbGlicmFyeShwaGVhdG1hcCkKCiMgT2J0YWluIEtFR0cgTGVnYWN5IGdlbmUgc2V0cyBmcm9tIG1zaWdkYnIKa2VnZ19nZW5lcyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiLCBzdWJjb2xsZWN0aW9uID0gIkNQOktFR0dfTEVHQUNZIikKCiMgQ29udmVydCB0aGUgZ2VuZSBzZXRzIHRvIGEgbGlzdCBmb3JtYXQgZm9yIGZnc2VhCmtlZ2dfbGlzdCA8LSBrZWdnX2dlbmVzICU+JQogIHNwbGl0KHggPSAuJGdlbmVfc3ltYm9sLCBmID0gLiRnc19uYW1lKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgQ3JlYXRlIGEgcmFua2VkIGxpc3QgYmFzZWQgb24gYXZnX2xvZ0ZDIGFuZCBwX3ZhbF9hZGoKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBtdXRhdGUocmFua19tZXRyaWMgPSBhdmdfbG9nRkMgKiAtbG9nMTAocF92YWxfYWRqKSkKCiMgRW5zdXJlIG5vIE5BIHZhbHVlcyBpbiByYW5rX21ldHJpYwpNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzICU+JQogIGZpbHRlcighaXMubmEocmFua19tZXRyaWMpKQoKIyBDcmVhdGUgYSBuYW1lZCB2ZWN0b3IgZm9yIHJhbmtpbmcKZ2VuZV9saXN0IDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRyYW5rX21ldHJpYwpuYW1lcyhnZW5lX2xpc3QpIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRnZW5lCgojIFNvcnQgdGhlIG5hbWVkIHZlY3RvciBpbiBkZWNyZWFzaW5nIG9yZGVyCmdlbmVfbGlzdCA8LSBzb3J0KGdlbmVfbGlzdCwgZGVjcmVhc2luZyA9IFRSVUUpCgpnZW5lX2xpc3QgPC0gZ2VuZV9saXN0W2lzLmZpbml0ZShnZW5lX2xpc3QpXQoKIyBQZXJmb3JtIGZhc3QgR1NFQSB1c2luZyBLRUdHIHBhdGh3YXlzCmZnc2VhX3Jlc3VsdF9rZWdnIDwtIGZnc2VhKHBhdGh3YXlzID0ga2VnZ19saXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMgPSBnZW5lX2xpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVwcz0wLjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4U2l6ZSA9IDUwMCkgIAoKCiMgVmlldyB0aGUgZmdzZWEgcmVzdWx0cwpoZWFkKGZnc2VhX3Jlc3VsdF9rZWdnW29yZGVyKHB2YWwpLCBdKQoKCmBgYAoKIyA2LiAgUGVyZm9ybSBWaXN1YWxpemF0aW9uIG9mIGZnc2VxIHVzaW5nIEtFR0cgR2VuZSBTZXRzCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShmZ3NlYSkKbGlicmFyeShnZ3Bsb3QyKQoKIyBQbG90IHRoZSB0b3AgcGF0aHdheQp0b3BfcGF0aHdheSA8LSBmZ3NlYV9yZXN1bHRfa2VnZ1tvcmRlcihmZ3NlYV9yZXN1bHRfa2VnZyRwYWRqKSwgXVsxLCBdCnBsb3RFbnJpY2htZW50KGtlZ2dfbGlzdFtbdG9wX3BhdGh3YXkkcGF0aHdheV1dLCBnZW5lX2xpc3QpICsKICBsYWJzKHRpdGxlID0gdG9wX3BhdGh3YXkkcGF0aHdheSkKCnRvcFBhdGh3YXlzVXAgPC0gZmdzZWFfcmVzdWx0X2tlZ2dbRVMgPiAwXVtoZWFkKG9yZGVyKHBhZGopLCBuPTEwKSwgcGF0aHdheV0KdG9wUGF0aHdheXNEb3duIDwtIGZnc2VhX3Jlc3VsdF9rZWdnW0VTIDwgMF1baGVhZChvcmRlcihwYWRqKSwgbj0xMCksIHBhdGh3YXldCnRvcFBhdGh3YXlzIDwtIGModG9wUGF0aHdheXNVcCwgcmV2KHRvcFBhdGh3YXlzRG93bikpCnBsb3RHc2VhVGFibGUoa2VnZ19saXN0W3RvcFBhdGh3YXlzXSwgZ2VuZV9saXN0LCBmZ3NlYV9yZXN1bHRfa2VnZywgCiAgICAgICAgICAgICAgZ3NlYVBhcmFtPTAuNSkKCgpgYGAKCiMjIC4gVmlzdWFsaXphdGlvbi1LZWdnMQpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpmZ3NlYVJlc1RpZHkgPC0gZmdzZWFfcmVzdWx0X2tlZ2cgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgYXJyYW5nZShkZXNjKE5FUykpCgojIFNob3cgaW4gYSBuaWNlIHRhYmxlLCBleGNsdWRpbmcgYW55IGNvbHVtbnMgdGhhdCBkbyBub3QgZXhpc3QKZmdzZWFSZXNUaWR5ICU+JSAKICBkcGx5cjo6c2VsZWN0KC1sZWFkaW5nRWRnZSwgLUVTKSAlPiUgCiAgYXJyYW5nZShwYWRqKSAlPiUgCiAgRFQ6OmRhdGF0YWJsZSgpCgpnZ3Bsb3QoZmdzZWFSZXNUaWR5LCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGw9cGFkajwwLjA1KSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh4PSJQYXRod2F5IiwgeT0iTm9ybWFsaXplZCBFbnJpY2htZW50IFNjb3JlIiwKICAgICAgIHRpdGxlPSJIYWxsbWFyayBwYXRod2F5cyBORVMgZnJvbSBmZ3NlYSIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAicmVkIiwgIkZBTFNFIiA9ICJncmV5IikpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICAjIEFkanVzdCBheGlzIHRleHQgc2l6ZSBmb3IgcmVhZGFiaWxpdHkKCgoKYGBgCgojIyAuIFZpc3VhbGl6YXRpb24tS2VnZzIKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KIyBBcnJhbmdlIGJ5IE5FUyBhbmQgc2VsZWN0IHRvcCAyMCB1cCBhbmQgZG93biBwYXRod2F5cwp0b3BVcCA8LSBmZ3NlYVJlc1RpZHkgJT4lCiAgZHBseXI6OmZpbHRlcihORVMgPiAwKSAlPiUKICBkcGx5cjo6YXJyYW5nZShkZXNjKE5FUykpICU+JQogIGRwbHlyOjpzbGljZV9oZWFkKG4gPSAyMCkKCnRvcERvd24gPC0gZmdzZWFSZXNUaWR5ICU+JQogIGRwbHlyOjpmaWx0ZXIoTkVTIDwgMCkgJT4lCiAgZHBseXI6OmFycmFuZ2UoTkVTKSAlPiUKICBkcGx5cjo6c2xpY2VfaGVhZChuID0gMjApCgojIENvbWJpbmUgdGhlIHRvcCB1cCBhbmQgZG93biBwYXRod2F5cwp0b3BQYXRod2F5cyA8LSBkcGx5cjo6YmluZF9yb3dzKHRvcFVwLCB0b3BEb3duKQoKCmdncGxvdCh0b3BQYXRod2F5cywgYWVzKHJlb3JkZXIocGF0aHdheSwgTkVTKSwgTkVTKSkgKwogIGdlb21fY29sKGFlcyhmaWxsID0gcGFkaiA8IDAuMDUpKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHggPSAiUGF0aHdheSIsIHkgPSAiTm9ybWFsaXplZCBFbnJpY2htZW50IFNjb3JlIiwKICAgICAgIHRpdGxlID0gIlRvcCAyMCBVcCBhbmQgRG93biBLRUdHIFBhdGh3YXlzIE5FUyBmcm9tIEdTRUEiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICJyZWQiLCAiRkFMU0UiID0gImdyZXkiKSkKCgoKCmBgYAoKIyA3LiBTYXZlIEhhbGxtYXJrIGFuZCBrZWdnIHRvIENTVgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBBc3N1bWluZyB5b3UgaGF2ZSB0aGUgcmVzdWx0cyBzdG9yZWQgaW4gZmdzZWFfcmVzdWx0X2hhbGxtYXJrIGFuZCBmZ3NlYV9yZXN1bHRfa2VnZwoKIyBGbGF0dGVuIHRoZSBsaXN0IGNvbHVtbnMgaW50byBjaGFyYWN0ZXIgc3RyaW5ncyBmb3IgSGFsbG1hcmsgcmVzdWx0cwpmZ3NlYV9yZXN1bHRfaGFsbG1hcmtfZmxhdHRlbmVkIDwtIGZnc2VhX3Jlc3VsdCAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmxpc3QpLCB+IHNhcHBseSguLCB0b1N0cmluZykpKQoKIyBXcml0ZSB0aGUgZmxhdHRlbmVkIEhhbGxtYXJrIHJlc3VsdHMgdG8gYSBDU1YgZmlsZQp3cml0ZS5jc3YoZmdzZWFfcmVzdWx0X2hhbGxtYXJrX2ZsYXR0ZW5lZCwgImZnc2VhX3Jlc3VsdHNfaGFsbG1hcmsuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIEZsYXR0ZW4gdGhlIGxpc3QgY29sdW1ucyBpbnRvIGNoYXJhY3RlciBzdHJpbmdzIGZvciBLRUdHIHJlc3VsdHMKZmdzZWFfcmVzdWx0X2tlZ2dfZmxhdHRlbmVkIDwtIGZnc2VhX3Jlc3VsdF9rZWdnICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubGlzdCksIH4gc2FwcGx5KC4sIHRvU3RyaW5nKSkpCgojIFdyaXRlIHRoZSBmbGF0dGVuZWQgS0VHRyByZXN1bHRzIHRvIGEgQ1NWIGZpbGUKd3JpdGUuY3N2KGZnc2VhX3Jlc3VsdF9rZWdnX2ZsYXR0ZW5lZCwgImZnc2VhX3Jlc3VsdHNfa2VnZy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCgpnZ3Bsb3QoZGF0YS5mcmFtZShnZW5lX3N5bWJvbCA9IG5hbWVzKGdlbmVfbGlzdClbMTo1MF0sIHJhbmtzID0gZ2VuZV9saXN0WzE6NTBdKSwgYWVzKGdlbmVfc3ltYm9sLCByYW5rcykpICsgCglnZW9tX3BvaW50KCkgKwoJdGhlbWVfY2xhc3NpYygpICsgCgl0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgpgYGAKIyA4LiAgSGFsbG1hcmsgZ2VuZXMgZm91bmQgaW4gbXVsdGlwbGUgcGF0aHdheXMKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKCiMgQXNzdW1pbmcgJ2Znc2VhX3Jlc3VsdHMnIGlzIHRoZSBvdXRwdXQgb2YgeW91ciBmZ3NlYSBhbmFseXNpcwoKIyBTdGVwIDE6IEV4dHJhY3QgdGhlIGxlYWRpbmcgZWRnZSBnZW5lcyBmb3IgZWFjaCBzaWduaWZpY2FudCBwYXRod2F5CiMgJ2xlYWRpbmdFZGdlJyBjb250YWlucyB0aGUgZ2VuZSBuYW1lcyB0aGF0IGNvbnRyaWJ1dGUgdG8gdGhlIGVucmljaG1lbnQgb2YgdGhlIHBhdGh3YXkKc2lnbmlmaWNhbnRfZ2VuZV9zZXRzIDwtIGZnc2VhX3Jlc3VsdCAlPiUKICBmaWx0ZXIocGFkaiA8IDAuMDUpICU+JQogIHNlbGVjdChwYXRod2F5LCBsZWFkaW5nRWRnZSkKCiMgU3RlcCAyOiBVbm5lc3QgdGhlIGxlYWRpbmdFZGdlIGNvbHVtbiAoY29udmVydCBsaXN0IHRvIHJvd3MpCnNpZ25pZmljYW50X2dlbmVfc2V0cyA8LSBzaWduaWZpY2FudF9nZW5lX3NldHMgJT4lCiAgdW5uZXN0KGNvbHMgPSBsZWFkaW5nRWRnZSkKCiMgU3RlcCAzOiBDb3VudCBob3cgbWFueSB0aW1lcyBlYWNoIGdlbmUgYXBwZWFycyBhY3Jvc3MgcGF0aHdheXMKZ2VuZV9jb3VudCA8LSBzaWduaWZpY2FudF9nZW5lX3NldHMgJT4lCiAgZ3JvdXBfYnkobGVhZGluZ0VkZ2UpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50KSkgICMgQXJyYW5nZSBnZW5lcyBieSB0aGUgbnVtYmVyIG9mIHBhdGh3YXlzIHRoZXkgYXBwZWFyIGluCgojIFN0ZXAgNDogVmlzdWFsaXplIHRoZSB0b3AgcmVndWxhdG9yIGdlbmVzIChnZW5lcyB0aGF0IGFwcGVhciBpbiBtdWx0aXBsZSBwYXRod2F5cykKdG9wX3JlZ3VsYXRvcl9nZW5lcyA8LSBnZW5lX2NvdW50ICU+JQogIGZpbHRlcihjb3VudCA+IDEpICAjIEdlbmVzIGludm9sdmVkIGluIG1vcmUgdGhhbiBvbmUgcGF0aHdheQoKIyBQbG90IHRvcCByZWd1bGF0b3IgZ2VuZXMgaW52b2x2ZWQgaW4gbXVsdGlwbGUgcGF0aHdheXMKZ2dwbG90KHRvcF9yZWd1bGF0b3JfZ2VuZXMsIGFlcyh4ID0gcmVvcmRlcihsZWFkaW5nRWRnZSwgLWNvdW50KSwgeSA9IGNvdW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNhbG1vbiIpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIFJlZ3VsYXRvciBHZW5lcyBJbnZvbHZlZCBpbiBNdWx0aXBsZSBQYXRod2F5cyIsCiAgICAgICB4ID0gIkdlbmUiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgUGF0aHdheXMiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIFN0ZXAgNTogT3V0cHV0IHRoZSBnZW5lIGNvdW50cyB0byBhIENTViBmaWxlIGZvciBmdXJ0aGVyIGluc3BlY3Rpb24Kd3JpdGUuY3N2KGdlbmVfY291bnQsICJnZW5lX2NvdW50X2luX211bHRpcGxlX3BhdGh3YXlzLmNzdiIpCgoKYGBgCgoKIyA4LiAgSGFsbG1hcmsgZ2VuZXMgZm91bmQgaW4gbXVsdGlwbGUgcGF0aHdheXMKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKCiMgQXNzdW1pbmcgJ2Znc2VhX3Jlc3VsdHMnIGlzIHRoZSBvdXRwdXQgb2YgeW91ciBmZ3NlYSBhbmFseXNpcwoKIyBTdGVwIDE6IEV4dHJhY3QgdGhlIGxlYWRpbmcgZWRnZSBnZW5lcyBmb3IgZWFjaCBzaWduaWZpY2FudCBwYXRod2F5CiMgJ2xlYWRpbmdFZGdlJyBjb250YWlucyB0aGUgZ2VuZSBuYW1lcyB0aGF0IGNvbnRyaWJ1dGUgdG8gdGhlIGVucmljaG1lbnQgb2YgdGhlIHBhdGh3YXkKc2lnbmlmaWNhbnRfZ2VuZV9zZXRzIDwtIGZnc2VhX3Jlc3VsdF9rZWdnICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSkgJT4lCiAgc2VsZWN0KHBhdGh3YXksIGxlYWRpbmdFZGdlKQoKIyBTdGVwIDI6IFVubmVzdCB0aGUgbGVhZGluZ0VkZ2UgY29sdW1uIChjb252ZXJ0IGxpc3QgdG8gcm93cykKc2lnbmlmaWNhbnRfZ2VuZV9zZXRzIDwtIHNpZ25pZmljYW50X2dlbmVfc2V0cyAlPiUKICB1bm5lc3QoY29scyA9IGxlYWRpbmdFZGdlKQoKIyBTdGVwIDM6IENvdW50IGhvdyBtYW55IHRpbWVzIGVhY2ggZ2VuZSBhcHBlYXJzIGFjcm9zcyBwYXRod2F5cwpnZW5lX2NvdW50IDwtIHNpZ25pZmljYW50X2dlbmVfc2V0cyAlPiUKICBncm91cF9ieShsZWFkaW5nRWRnZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnQpKSAgIyBBcnJhbmdlIGdlbmVzIGJ5IHRoZSBudW1iZXIgb2YgcGF0aHdheXMgdGhleSBhcHBlYXIgaW4KCiMgU3RlcCA0OiBWaXN1YWxpemUgdGhlIHRvcCByZWd1bGF0b3IgZ2VuZXMgKGdlbmVzIHRoYXQgYXBwZWFyIGluIG11bHRpcGxlIHBhdGh3YXlzKQp0b3BfcmVndWxhdG9yX2dlbmVzIDwtIGdlbmVfY291bnQgJT4lCiAgZmlsdGVyKGNvdW50ID4gMSkgICMgR2VuZXMgaW52b2x2ZWQgaW4gbW9yZSB0aGFuIG9uZSBwYXRod2F5CgojIFBsb3QgdG9wIHJlZ3VsYXRvciBnZW5lcyBpbnZvbHZlZCBpbiBtdWx0aXBsZSBwYXRod2F5cwpnZ3Bsb3QodG9wX3JlZ3VsYXRvcl9nZW5lcywgYWVzKHggPSByZW9yZGVyKGxlYWRpbmdFZGdlLCAtY291bnQpLCB5ID0gY291bnQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2FsbW9uIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgUmVndWxhdG9yIEdlbmVzIEludm9sdmVkIGluIE11bHRpcGxlIFBhdGh3YXlzIiwKICAgICAgIHggPSAiR2VuZSIsCiAgICAgICB5ID0gIk51bWJlciBvZiBQYXRod2F5cyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgU3RlcCA1OiBPdXRwdXQgdGhlIGdlbmUgY291bnRzIHRvIGEgQ1NWIGZpbGUgZm9yIGZ1cnRoZXIgaW5zcGVjdGlvbgp3cml0ZS5jc3YoZ2VuZV9jb3VudCwgImdlbmVfY291bnRfaW5fbXVsdGlwbGVfcGF0aHdheXMuY3N2IikKCgpgYGA=