1. load libraries

2. Perform DE analysis using Malignant_CD4Tcells_vs_Normal_CD4Tcells genes


Malignant_CD4Tcells_vs_Normal_CD4Tcells <- read.csv("All_genes_celllines_vs_normal_updated_with_mean_expression/Updated_DE_Results_L1_with_MeanExpr.csv", header = T)

3. Create the EnhancedVolcano plot


EnhancedVolcano(Malignant_CD4Tcells_vs_Normal_CD4Tcells,
                lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
                x = "avg_log2FC",
                y = "p_val_adj",
                title = "MAST with Batch Correction (All Genes)",
                pCutoff = 0.05,
                FCcutoff = 1.0)
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

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

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
)
Warning: 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]
) 
Warning: One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...

4. Perform fgsea using Hallmark Gene Sets


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 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
fgsea_result <- fgsea(pathways = hallmark_list, 
                      stats = gene_list, 
                      minSize = 10,
                      maxSize = 500,
                      nperm = 10000)  # Number of permutations
Warning: You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.
# View the fgsea results
head(fgsea_result)

# 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)


#Filter the results table to show only the top 10 UP or DOWN regulated processes (Optional)
top10_UP <- fgsea_result$pathways[1:10]

#summary Table
plotGseaTable(hallmark_list[top10_UP], gene_list, fgsea_result, gseaParam = 0.5)

NA
NA

5. Create the Heatmap of fgsea results

library(pheatmap)

# Select the top 50 pathways
top_pathways <- fgsea_result %>%
  arrange(padj) %>%
  head(50)

# Create a matrix for the heatmap with pathways as rows and NES as the values
heatmap_data <- matrix(top_pathways$NES, nrow = length(top_pathways$pathway), ncol = 1)
rownames(heatmap_data) <- top_pathways$pathway
colnames(heatmap_data) <- c("NES")

# Plot the combined heatmap for the top 50 pathways
pheatmap(heatmap_data, 
         cluster_rows = TRUE, 
         cluster_cols = FALSE, 
         show_rownames = TRUE, 
         show_colnames = TRUE,
         main = "Hallmark Pathways: Malignant CD4 T Cells compared to normal CD4 T cells",
         color = colorRampPalette(c("blue", "white", "red"))(50))

6. 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,
                           minSize = 10,
                           maxSize = 500,
                           nperm = 10000)  # Number of permutations
Warning: You are trying to run fgseaSimple. It is recommended to use fgseaMultilevel. To run fgseaMultilevel, you need to remove the nperm argument in the fgsea function call.
# View the fgsea results
head(fgsea_result_kegg)


#Filter the results table to show only the top 10 UP or DOWN regulated processes (Optional)
top10_UP_kegg <- fgsea_result_kegg$pathways[1:10]

#summary Table
plotGseaTable(kegg_list[top10_UP_kegg], gene_list, fgsea_result_kegg, gseaParam = 0.5)



# Separate upregulated (positive NES) and downregulated (negative NES) pathways
upregulated_pathways <- fgsea_result_kegg %>% filter(NES > 0) %>% arrange(padj) %>% head(20)
downregulated_pathways <- fgsea_result_kegg %>% filter(NES < 0) %>% arrange(padj) %>% head(20)

# Combine the top 20 upregulated and top 20 downregulated pathways
combined_pathways <- bind_rows(upregulated_pathways, downregulated_pathways)

# Create a matrix for the heatmap with pathways as rows and NES as the values
heatmap_data_combined <- matrix(combined_pathways$NES, nrow = length(combined_pathways$pathway), ncol = 1)
rownames(heatmap_data_combined) <- combined_pathways$pathway
colnames(heatmap_data_combined) <- c("NES")

# Plot the combined heatmap for the top 20 upregulated and top 20 downregulated pathways
pheatmap(heatmap_data_combined, 
         cluster_rows = TRUE, 
         cluster_cols = FALSE, 
         show_rownames = TRUE, 
         show_colnames = TRUE,
         main = "KEGG Pathways: Malignant CD4 T Cells compared to normal CD4 T Cells",
         color = colorRampPalette(c("blue", "white", "red"))(50))

. Visualization-Hallmark

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

# Show in a nice table:
fgseaResTidy %>% 
  dplyr::select(-leadingEdge, -ES, -nMoreExtreme) %>% 
  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 GSEA") + 
  theme_minimal()+ scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "grey"))

NA
NA
NA

. Visualization-Kegg1

. 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, "GSEA_Results_All_genes_celllines_vs_normal_updated_with_mean_expression/fgsea_results_hallmark_L1.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, "GSEA_Results_All_genes_celllines_vs_normal_updated_with_mean_expression/fgsea_results_kegg_L1.csv", row.names = FALSE)
LS0tCnRpdGxlOiAiZmdzZWEtTDEgdnMgQ29udHJvbChOb3JtYWwgQ0Q0IFRjZWxscykiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KFNldXJhdERhdGEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHJldGljdWxhdGUpCmxpYnJhcnkoQXppbXV0aCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSdHNuZSkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCn0pCiAgCmBgYAoKIyAyLiBQZXJmb3JtIERFIGFuYWx5c2lzIHVzaW5nIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyBnZW5lcwpgYGB7ciBkYXRhMSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgPC0gcmVhZC5jc3YoIjItQWxsX2dlbmVzX2NlbGxsaW5lc192c19ub3JtYWxfdXBkYXRlZF93aXRoX21lYW5fZXhwcmVzc2lvbi9VcGRhdGVkX0RFX1Jlc3VsdHNfTDFfd2l0aF9NZWFuRXhwci5jc3YiLCBoZWFkZXIgPSBUKQpgYGAKCiMgMy4gQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gcGxvdApgYGB7ciBlbmhhbmNlZFYsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KCkVuaGFuY2VkVm9sY2FubyhNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsCiAgICAgICAgICAgICAgICBsYWIgPSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkZ2VuZSwKICAgICAgICAgICAgICAgIHggPSAiYXZnX2xvZzJGQyIsCiAgICAgICAgICAgICAgICB5ID0gInBfdmFsX2FkaiIsCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJNQVNUIHdpdGggQmF0Y2ggQ29ycmVjdGlvbiAoQWxsIEdlbmVzKSIsCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMS4wKQoKCkVuaGFuY2VkVm9sY2FubyhNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMsIAogICAgICAgICAgICAgICAgbGFiID0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGdlbmUsCiAgICAgICAgICAgICAgICB4ID0gImF2Z19sb2cyRkMiLCAKICAgICAgICAgICAgICAgIHkgPSAicF92YWxfYWRqIiwKICAgICAgICAgICAgICAgIHNlbGVjdExhYiA9IGMoJ0VQQ0FNJywgJ0JDQVQxJywgJ0tJUjNETDInLCAnRk9YTTEnLCAnVFdJU1QxJywgJ1RORlNGOScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ0Q4MCcsICAnSUwxQicsICdSUFM0WTEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0lMN1InLCAnVENGNycsICAnTUtJNjcnLCAnQ0Q3MCcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUwyUkEnLCdUUkJWNi0yJywgJ1RSQlYxMC0zJywgJ1RSQlY0LTInLCAnVFJCVjknLCAnVFJCVjctOScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVFJBVjEyLTEnLCAnQ0Q4QicsICdGQ0dSM0EnLCAnR05MWScsICdGT1hQMycsICdTRUxMJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHSU1BUDEnLCAnUklQT1IyJywgJ0xFRjEnLCAnSE9YQzknLCAnU1A1JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0NDTDE3JywgJ0VUVjQnLCAnVEhZMScsICdGT1hBMicsICdJVEdBRCcsICdTMTAwUCcsICdUQlg0JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJRDEnLCAnWENMMScsICdTT1gyJywgJ0NEMjcnLCAnQ0QyOCcsJ1BMUzMnLCdDRDcwJywnUkFCMjUnICwgJ1RSQlYyNycsICdUUkJWMicpLAogICAgICAgICAgICAgICAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgICAgICAgICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+ICdmb2xkIGNoYW5nZScpLAogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEuNSwgCiAgICAgICAgICAgICAgICBwb2ludFNpemUgPSAzLjAsCiAgICAgICAgICAgICAgICBsYWJTaXplID0gNS4wLAogICAgICAgICAgICAgICAgYm94ZWRMYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICBsZWdlbmRMYWJTaXplID0gMTAsCiAgICAgICAgICAgICAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwKICAgICAgICAgICAgICAgIHdpZHRoQ29ubmVjdG9ycyA9IDAuNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAnZ3JleTUwJywKICAgICAgICAgICAgICAgIGFycm93aGVhZHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDMwKQoKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgRmlsdGVyIGdlbmVzIGJhc2VkIG9uIGxvd2VzdCBwLXZhbHVlcyBidXQgaW5jbHVkZSBhbGwgZ2VuZXMKZmlsdGVyZWRfZ2VuZXMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzICU+JQogIGFycmFuZ2UocF92YWxfYWRqLCBkZXNjKGFicyhhdmdfbG9nMkZDKSkpCgojIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3Qgd2l0aCB0aGUgZmlsdGVyZWQgZGF0YQpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nMkZDKSA+PSAxLjAsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2cyRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgcEN1dG9mZiA9IDAuMDUsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCAKICBsYWJDb2wgPSAnYmxhY2snLAogIGxhYkZhY2UgPSAnYm9sZCcsCiAgYm94ZWRMYWJlbHMgPSBGQUxTRSwgICMgU2V0IHRvIEZBTFNFIHRvIHJlbW92ZSBib3hlZCBsYWJlbHMKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9taXplIHBvaW50IGNvbG9ycwogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZzJGQykgPj0gMS4wXSAgIyBPbmx5IGxhYmVsIHNpZ25pZmljYW50IGdlbmVzCikKCgoKRW5oYW5jZWRWb2xjYW5vKAogIGZpbHRlcmVkX2dlbmVzLCAKICBsYWIgPSBpZmVsc2UoZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZzJGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nMkZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyAoY2VsbCBsaW5lcykgdnMgTm9ybWFsIENENCBUIGNlbGxzIiwKICBzdWJ0aXRsZSA9ICJIaWdobGlnaHRpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIiwKICBwQ3V0b2ZmID0gMC4wNSwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgY29sQWxwaGEgPSAwLjgsICAjIFNsaWdodCB0cmFuc3BhcmVuY3kgZm9yIG5vbi1zaWduaWZpY2FudCBwb2ludHMKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9tIGNvbG9yIHNjaGVtZQogIGdyaWRsaW5lcy5tYWpvciA9IFRSVUUsCiAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nMkZDKSA+PSAxLjBdCikgCgoKYGBgCgojIDQuICBQZXJmb3JtIGZnc2VhIHVzaW5nIEhhbGxtYXJrIEdlbmUgU2V0cwpgYGB7ciBkYXRhMiwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoZHBseXIpCgojIE9idGFpbiBIYWxsbWFyayBnZW5lIHNldHMgZnJvbSBtc2lnZGJyCmhhbGxtYXJrX2dlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikKCiMgQ29udmVydCB0aGUgZ2VuZSBzZXRzIHRvIGEgbGlzdCBmb3JtYXQgZm9yIGZnc2VhCmhhbGxtYXJrX2xpc3QgPC0gaGFsbG1hcmtfZ2VuZXMgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBDcmVhdGUgYSByYW5rZWQgbGlzdCBiYXNlZCBvbiBhdmdfbG9nMkZDIGFuZCBwX3ZhbF9hZGoKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBtdXRhdGUocmFua19tZXRyaWMgPSBhdmdfbG9nMkZDICogLWxvZzEwKHBfdmFsX2FkaikpCgojIEVuc3VyZSBubyBOQSB2YWx1ZXMgaW4gcmFua19tZXRyaWMKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBmaWx0ZXIoIWlzLm5hKHJhbmtfbWV0cmljKSkKCiMgQ3JlYXRlIGEgbmFtZWQgdmVjdG9yIGZvciByYW5raW5nCmdlbmVfbGlzdCA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcmFua19tZXRyaWMKbmFtZXMoZ2VuZV9saXN0KSA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkZ2VuZQoKIyBTb3J0IHRoZSBuYW1lZCB2ZWN0b3IgaW4gZGVjcmVhc2luZyBvcmRlcgpnZW5lX2xpc3QgPC0gc29ydChnZW5lX2xpc3QsIGRlY3JlYXNpbmcgPSBUUlVFKQoKZ2VuZV9saXN0IDwtIGdlbmVfbGlzdFtpcy5maW5pdGUoZ2VuZV9saXN0KV0KCgojIFBlcmZvcm0gZmFzdCBHU0VBCmZnc2VhX3Jlc3VsdCA8LSBmZ3NlYShwYXRod2F5cyA9IGhhbGxtYXJrX2xpc3QsIAogICAgICAgICAgICAgICAgICAgICAgc3RhdHMgPSBnZW5lX2xpc3QsIAogICAgICAgICAgICAgICAgICAgICAgbWluU2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgbWF4U2l6ZSA9IDUwMCwKICAgICAgICAgICAgICAgICAgICAgIG5wZXJtID0gMTAwMDApICAjIE51bWJlciBvZiBwZXJtdXRhdGlvbnMKCiMgVmlldyB0aGUgZmdzZWEgcmVzdWx0cwpoZWFkKGZnc2VhX3Jlc3VsdCkKCiMgUGxvdCB0aGUgdG9wIHBhdGh3YXkKdG9wX3BhdGh3YXkgPC0gZmdzZWFfcmVzdWx0W29yZGVyKGZnc2VhX3Jlc3VsdCRwYWRqKSwgXVsxLCBdCnBsb3RFbnJpY2htZW50KGhhbGxtYXJrX2xpc3RbW3RvcF9wYXRod2F5JHBhdGh3YXldXSwgZ2VuZV9saXN0KSArCiAgbGFicyh0aXRsZSA9IHRvcF9wYXRod2F5JHBhdGh3YXkpCgojRmlsdGVyIHRoZSByZXN1bHRzIHRhYmxlIHRvIHNob3cgb25seSB0aGUgdG9wIDEwIFVQIG9yIERPV04gcmVndWxhdGVkIHByb2Nlc3NlcyAoT3B0aW9uYWwpCnRvcDEwX1VQIDwtIGZnc2VhX3Jlc3VsdCRwYXRod2F5c1sxOjEwXQoKI3N1bW1hcnkgVGFibGUKcGxvdEdzZWFUYWJsZShoYWxsbWFya19saXN0W3RvcDEwX1VQXSwgZ2VuZV9saXN0LCBmZ3NlYV9yZXN1bHQsIGdzZWFQYXJhbSA9IDAuNSkKCgpgYGAKCiMgNS4gQ3JlYXRlIHRoZSBIZWF0bWFwIG9mIGZnc2VhIHJlc3VsdHMKYGBge3IgZGF0YTMsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQpsaWJyYXJ5KHBoZWF0bWFwKQoKIyBTZWxlY3QgdGhlIHRvcCA1MCBwYXRod2F5cwp0b3BfcGF0aHdheXMgPC0gZmdzZWFfcmVzdWx0ICU+JQogIGFycmFuZ2UocGFkaikgJT4lCiAgaGVhZCg1MCkKCiMgQ3JlYXRlIGEgbWF0cml4IGZvciB0aGUgaGVhdG1hcCB3aXRoIHBhdGh3YXlzIGFzIHJvd3MgYW5kIE5FUyBhcyB0aGUgdmFsdWVzCmhlYXRtYXBfZGF0YSA8LSBtYXRyaXgodG9wX3BhdGh3YXlzJE5FUywgbnJvdyA9IGxlbmd0aCh0b3BfcGF0aHdheXMkcGF0aHdheSksIG5jb2wgPSAxKQpyb3duYW1lcyhoZWF0bWFwX2RhdGEpIDwtIHRvcF9wYXRod2F5cyRwYXRod2F5CmNvbG5hbWVzKGhlYXRtYXBfZGF0YSkgPC0gYygiTkVTIikKCiMgUGxvdCB0aGUgY29tYmluZWQgaGVhdG1hcCBmb3IgdGhlIHRvcCA1MCBwYXRod2F5cwpwaGVhdG1hcChoZWF0bWFwX2RhdGEsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLCAKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwgCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICBtYWluID0gIkhhbGxtYXJrIFBhdGh3YXlzOiBNYWxpZ25hbnQgQ0Q0IFQgQ2VsbHMgY29tcGFyZWQgdG8gbm9ybWFsIENENCBUIGNlbGxzIiwKICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDUwKSkKCmBgYAoKIyA2LiBPYnRhaW4gS0VHRyBHZW5lIFNldHMgYW5kIFBlcmZvcm0gZmdzZWEgVXNpbmcgS0VHRyBQYXRod2F5cwpgYGB7ciBkYXRhNCwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoZmdzZWEpCmxpYnJhcnkobXNpZ2RicikKbGlicmFyeShkcGx5cikKbGlicmFyeShwaGVhdG1hcCkKCiMgT2J0YWluIEtFR0cgZ2VuZSBzZXRzIGZyb20gbXNpZ2RicgprZWdnX2dlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJDMiIsIHN1YmNhdGVnb3J5ID0gIkNQOktFR0ciKQoKIyBDb252ZXJ0IHRoZSBnZW5lIHNldHMgdG8gYSBsaXN0IGZvcm1hdCBmb3IgZmdzZWEKa2VnZ19saXN0IDwtIGtlZ2dfZ2VuZXMgJT4lCiAgc3BsaXQoeCA9IC4kZ2VuZV9zeW1ib2wsIGYgPSAuJGdzX25hbWUpCgojIEFzc3VtaW5nIHlvdSBoYXZlIGEgZGF0YSBmcmFtZSBuYW1lZCBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMKIyBDcmVhdGUgYSByYW5rZWQgbGlzdCBiYXNlZCBvbiBhdmdfbG9nMkZDIGFuZCBwX3ZhbF9hZGoKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBtdXRhdGUocmFua19tZXRyaWMgPSBhdmdfbG9nMkZDICogLWxvZzEwKHBfdmFsX2FkaikpCgojIEVuc3VyZSBubyBOQSB2YWx1ZXMgaW4gcmFua19tZXRyaWMKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBmaWx0ZXIoIWlzLm5hKHJhbmtfbWV0cmljKSkKCiMgQ3JlYXRlIGEgbmFtZWQgdmVjdG9yIGZvciByYW5raW5nCmdlbmVfbGlzdCA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcmFua19tZXRyaWMKbmFtZXMoZ2VuZV9saXN0KSA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkZ2VuZQoKIyBTb3J0IHRoZSBuYW1lZCB2ZWN0b3IgaW4gZGVjcmVhc2luZyBvcmRlcgpnZW5lX2xpc3QgPC0gc29ydChnZW5lX2xpc3QsIGRlY3JlYXNpbmcgPSBUUlVFKQoKZ2VuZV9saXN0IDwtIGdlbmVfbGlzdFtpcy5maW5pdGUoZ2VuZV9saXN0KV0KCiMgUGVyZm9ybSBmYXN0IEdTRUEgdXNpbmcgS0VHRyBwYXRod2F5cwpmZ3NlYV9yZXN1bHRfa2VnZyA8LSBmZ3NlYShwYXRod2F5cyA9IGtlZ2dfbGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRzID0gZ2VuZV9saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5TaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heFNpemUgPSA1MDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5wZXJtID0gMTAwMDApICAjIE51bWJlciBvZiBwZXJtdXRhdGlvbnMKCiMgVmlldyB0aGUgZmdzZWEgcmVzdWx0cwpoZWFkKGZnc2VhX3Jlc3VsdF9rZWdnKQoKCiNGaWx0ZXIgdGhlIHJlc3VsdHMgdGFibGUgdG8gc2hvdyBvbmx5IHRoZSB0b3AgMTAgVVAgb3IgRE9XTiByZWd1bGF0ZWQgcHJvY2Vzc2VzIChPcHRpb25hbCkKdG9wMTBfVVBfa2VnZyA8LSBmZ3NlYV9yZXN1bHRfa2VnZyRwYXRod2F5c1sxOjEwXQoKI3N1bW1hcnkgVGFibGUKcGxvdEdzZWFUYWJsZShrZWdnX2xpc3RbdG9wMTBfVVBfa2VnZ10sIGdlbmVfbGlzdCwgZmdzZWFfcmVzdWx0X2tlZ2csIGdzZWFQYXJhbSA9IDAuNSkKCgojIFNlcGFyYXRlIHVwcmVndWxhdGVkIChwb3NpdGl2ZSBORVMpIGFuZCBkb3ducmVndWxhdGVkIChuZWdhdGl2ZSBORVMpIHBhdGh3YXlzCnVwcmVndWxhdGVkX3BhdGh3YXlzIDwtIGZnc2VhX3Jlc3VsdF9rZWdnICU+JSBmaWx0ZXIoTkVTID4gMCkgJT4lIGFycmFuZ2UocGFkaikgJT4lIGhlYWQoMjApCmRvd25yZWd1bGF0ZWRfcGF0aHdheXMgPC0gZmdzZWFfcmVzdWx0X2tlZ2cgJT4lIGZpbHRlcihORVMgPCAwKSAlPiUgYXJyYW5nZShwYWRqKSAlPiUgaGVhZCgyMCkKCiMgQ29tYmluZSB0aGUgdG9wIDIwIHVwcmVndWxhdGVkIGFuZCB0b3AgMjAgZG93bnJlZ3VsYXRlZCBwYXRod2F5cwpjb21iaW5lZF9wYXRod2F5cyA8LSBiaW5kX3Jvd3ModXByZWd1bGF0ZWRfcGF0aHdheXMsIGRvd25yZWd1bGF0ZWRfcGF0aHdheXMpCgojIENyZWF0ZSBhIG1hdHJpeCBmb3IgdGhlIGhlYXRtYXAgd2l0aCBwYXRod2F5cyBhcyByb3dzIGFuZCBORVMgYXMgdGhlIHZhbHVlcwpoZWF0bWFwX2RhdGFfY29tYmluZWQgPC0gbWF0cml4KGNvbWJpbmVkX3BhdGh3YXlzJE5FUywgbnJvdyA9IGxlbmd0aChjb21iaW5lZF9wYXRod2F5cyRwYXRod2F5KSwgbmNvbCA9IDEpCnJvd25hbWVzKGhlYXRtYXBfZGF0YV9jb21iaW5lZCkgPC0gY29tYmluZWRfcGF0aHdheXMkcGF0aHdheQpjb2xuYW1lcyhoZWF0bWFwX2RhdGFfY29tYmluZWQpIDwtIGMoIk5FUyIpCgojIFBsb3QgdGhlIGNvbWJpbmVkIGhlYXRtYXAgZm9yIHRoZSB0b3AgMjAgdXByZWd1bGF0ZWQgYW5kIHRvcCAyMCBkb3ducmVndWxhdGVkIHBhdGh3YXlzCnBoZWF0bWFwKGhlYXRtYXBfZGF0YV9jb21iaW5lZCwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsIAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwgCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLCAKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUsCiAgICAgICAgIG1haW4gPSAiS0VHRyBQYXRod2F5czogTWFsaWduYW50IENENCBUIENlbGxzIGNvbXBhcmVkIHRvIG5vcm1hbCBDRDQgVCBDZWxscyIsCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg1MCkpCmBgYAojIyAuIFZpc3VhbGl6YXRpb24tSGFsbG1hcmsKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KZmdzZWFSZXNUaWR5IDwtIGZnc2VhX3Jlc3VsdCAlPiUKICBhc190aWJibGUoKSAlPiUKICBhcnJhbmdlKGRlc2MoTkVTKSkKCiMgU2hvdyBpbiBhIG5pY2UgdGFibGU6CmZnc2VhUmVzVGlkeSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtbGVhZGluZ0VkZ2UsIC1FUywgLW5Nb3JlRXh0cmVtZSkgJT4lIAogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKQoKCmdncGxvdChmZ3NlYVJlc1RpZHksIGFlcyhyZW9yZGVyKHBhdGh3YXksIE5FUyksIE5FUykpICsKICBnZW9tX2NvbChhZXMoZmlsbD1wYWRqPDAuMDUpKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHg9IlBhdGh3YXkiLCB5PSJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUiLAogICAgICAgdGl0bGU9IkhhbGxtYXJrIHBhdGh3YXlzIE5FUyBmcm9tIEdTRUEiKSArIAogIHRoZW1lX21pbmltYWwoKSsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAicmVkIiwgIkZBTFNFIiA9ICJncmV5IikpCgoKCmBgYAoKIyMgLiBWaXN1YWxpemF0aW9uLUtlZ2cxCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmZnc2VhUmVzVGlkeSA8LSBmZ3NlYV9yZXN1bHRfa2VnZyAlPiUKICBhc190aWJibGUoKSAlPiUKICBhcnJhbmdlKGRlc2MoTkVTKSkKCiMgU2hvdyBpbiBhIG5pY2UgdGFibGU6CmZnc2VhUmVzVGlkeSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtbGVhZGluZ0VkZ2UsIC1FUywgLW5Nb3JlRXh0cmVtZSkgJT4lIAogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKQoKCgpnZ3Bsb3QoZmdzZWFSZXNUaWR5LCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGw9cGFkajwwLjA1KSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh4PSJQYXRod2F5IiwgeT0iTm9ybWFsaXplZCBFbnJpY2htZW50IFNjb3JlIiwKICAgICAgIHRpdGxlPSJLRUdHIHBhdGh3YXlzIE5FUyBmcm9tIEdTRUEiKSArIAogIHRoZW1lX21pbmltYWwoKSsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAicmVkIiwgIkZBTFNFIiA9ICJncmV5IikpCgpgYGAKCiMjIC4gVmlzdWFsaXphdGlvbi1LZWdnMgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIEFycmFuZ2UgYnkgTkVTIGFuZCBzZWxlY3QgdG9wIDIwIHVwIGFuZCBkb3duIHBhdGh3YXlzCnRvcFVwIDwtIGZnc2VhUmVzVGlkeSAlPiUKICBkcGx5cjo6ZmlsdGVyKE5FUyA+IDApICU+JQogIGRwbHlyOjphcnJhbmdlKGRlc2MoTkVTKSkgJT4lCiAgZHBseXI6OnNsaWNlX2hlYWQobiA9IDIwKQoKdG9wRG93biA8LSBmZ3NlYVJlc1RpZHkgJT4lCiAgZHBseXI6OmZpbHRlcihORVMgPCAwKSAlPiUKICBkcGx5cjo6YXJyYW5nZShORVMpICU+JQogIGRwbHlyOjpzbGljZV9oZWFkKG4gPSAyMCkKCiMgQ29tYmluZSB0aGUgdG9wIHVwIGFuZCBkb3duIHBhdGh3YXlzCnRvcFBhdGh3YXlzIDwtIGRwbHlyOjpiaW5kX3Jvd3ModG9wVXAsIHRvcERvd24pCgoKZ2dwbG90KHRvcFBhdGh3YXlzLCBhZXMocmVvcmRlcihwYXRod2F5LCBORVMpLCBORVMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBwYWRqIDwgMC4wNSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoeCA9ICJQYXRod2F5IiwgeSA9ICJOb3JtYWxpemVkIEVucmljaG1lbnQgU2NvcmUiLAogICAgICAgdGl0bGUgPSAiVG9wIDIwIFVwIGFuZCBEb3duIEtFR0cgUGF0aHdheXMgTkVTIGZyb20gR1NFQSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gInJlZCIsICJGQUxTRSIgPSAiZ3JleSIpKQoKCgoKYGBgCgojIDcuIFNhdmUgSGFsbG1hcmsgYW5kIGtlZ2cgdG8gQ1NWCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgojIEFzc3VtaW5nIHlvdSBoYXZlIHRoZSByZXN1bHRzIHN0b3JlZCBpbiBmZ3NlYV9yZXN1bHRfaGFsbG1hcmsgYW5kIGZnc2VhX3Jlc3VsdF9rZWdnCgojIEZsYXR0ZW4gdGhlIGxpc3QgY29sdW1ucyBpbnRvIGNoYXJhY3RlciBzdHJpbmdzIGZvciBIYWxsbWFyayByZXN1bHRzCmZnc2VhX3Jlc3VsdF9oYWxsbWFya19mbGF0dGVuZWQgPC0gZmdzZWFfcmVzdWx0ICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubGlzdCksIH4gc2FwcGx5KC4sIHRvU3RyaW5nKSkpCgojIFdyaXRlIHRoZSBmbGF0dGVuZWQgSGFsbG1hcmsgcmVzdWx0cyB0byBhIENTViBmaWxlCndyaXRlLmNzdihmZ3NlYV9yZXN1bHRfaGFsbG1hcmtfZmxhdHRlbmVkLCAiR1NFQV9SZXN1bHRzX0FsbF9nZW5lc19jZWxsbGluZXNfdnNfbm9ybWFsX3VwZGF0ZWRfd2l0aF9tZWFuX2V4cHJlc3Npb24vZmdzZWFfcmVzdWx0c19oYWxsbWFya19MMS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiMgRmxhdHRlbiB0aGUgbGlzdCBjb2x1bW5zIGludG8gY2hhcmFjdGVyIHN0cmluZ3MgZm9yIEtFR0cgcmVzdWx0cwpmZ3NlYV9yZXN1bHRfa2VnZ19mbGF0dGVuZWQgPC0gZmdzZWFfcmVzdWx0X2tlZ2cgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5saXN0KSwgfiBzYXBwbHkoLiwgdG9TdHJpbmcpKSkKCiMgV3JpdGUgdGhlIGZsYXR0ZW5lZCBLRUdHIHJlc3VsdHMgdG8gYSBDU1YgZmlsZQp3cml0ZS5jc3YoZmdzZWFfcmVzdWx0X2tlZ2dfZmxhdHRlbmVkLCAiR1NFQV9SZXN1bHRzX0FsbF9nZW5lc19jZWxsbGluZXNfdnNfbm9ybWFsX3VwZGF0ZWRfd2l0aF9tZWFuX2V4cHJlc3Npb24vZmdzZWFfcmVzdWx0c19rZWdnX0wxLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCmBgYAo=