1. load libraries

2. load seurat object

#Load Seurat Object L7
load("/home/nabbasi/isilon/To_Transfer_between_computers/23-Harmony_Integration/0-robj/5-Harmony_Integrated_All_samples_Merged_CD4Tcells_final_Resolution_Selected_0.8_ADT_Normalized_cleaned_mt.robj")

pseudobulk_seurat <- All_samples_Merged

pseudobulk_seurat$label <- factor(
  ifelse(pseudobulk_seurat$orig.ident %in% c("L1", "L2", "L3", "L4", "L5", "L6", "L7"), "Malignant", "Control"),
  levels = c("Malignant", "Control")  # Ensuring "Malignant" is the reference
)

# Ensure 'condition' is a factor with the correct levels
pseudobulk_seurat$label <- factor(pseudobulk_seurat$label, levels = c("Control", "Malignant"))

# Ensure 'replicate' is a factor
pseudobulk_seurat$replicate <- as.factor(pseudobulk_seurat$cell_line)

# Rename the cell type column
pseudobulk_seurat$cell_type <- "CD4T"

3. DE using LIBRA

libra_test <-pseudobulk_seurat



DE_results <- run_de(
  libra_test,
  cell_type_col = "cell_type", 
  replicate_col = "replicate",
  label_col = "label",
  de_family = "pseudobulk",   # or "singlecell"
  de_method = "DESeq2",        # or "wilcox"
)
[1] "CD4T"
converting counts to integer mode
  it appears that the last variable in the design formula, 'group',
  has a factor level, 'Control', which is not the reference level. we recommend
  to use factor(...,levels=...) or relevel() to set this as the reference level
  before proceeding. for more information, please see the 'Note on factor levels'
  in vignette('DESeq2').
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1197 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing

4. Volcano Plot

library(ggplot2)
library(dplyr)

# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)

# Save results to CSV
write.csv(DE_results_df, file = "1-Pseudobulk_DEseq2_LRT_DE_results_with_RNA_batch_with_meanExpression.csv", row.names = FALSE)

# Ensure logFC and p-value columns are named correctly
colnames(DE_results_df)
 [1] "cell_type"     "gene"          "avg_logFC"     "Malignant.pct" "Control.pct"   "Malignant.exp" "Control.exp"  
 [8] "p_val"         "p_val_adj"     "de_family"     "de_method"     "de_type"      
# Filtering for significant genes:
volcano_data <- DE_results_df %>%
  mutate(
    significance = case_when(
      p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
      p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
      TRUE ~ "Not Significant"
    )
  )
ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
  geom_point(alpha = 0.6, size = 2) +
  scale_color_manual(values = c("Upregulated" = "red", "Downregulated" = "blue", "Not Significant" = "grey")) +
  theme_minimal() +
  labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
       x = "Log2 Fold Change",
       y = "-Log10 Adjusted P-Value",
       color = "Significance") +
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") +
  geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black")

NA
NA

Volcano Plot

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

Volcano Plot

library(ggplot2)
library(dplyr)
library(ggrepel)

# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)

# Ensure correct column names
colnames(DE_results_df)
 [1] "cell_type"     "gene"          "avg_logFC"     "Malignant.pct" "Control.pct"   "Malignant.exp" "Control.exp"  
 [8] "p_val"         "p_val_adj"     "de_family"     "de_method"     "de_type"      
# Define significance categories
volcano_data <- DE_results_df %>%
  mutate(
    significance = case_when(
      p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
      p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
      TRUE ~ "Not Significant"
    )
  )

# Select genes to label: p_val_adj < 1e-50 OR logFC > 2 OR logFC < -2
top_genes <- volcano_data %>%
  filter(p_val_adj < 0.05 | avg_logFC > 2 | avg_logFC < -2)

ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
  geom_point(alpha = 0.6, size = 2) +  # Main points
  scale_color_manual(values = c("Upregulated" = "red", "Downregulated" = "blue", "Not Significant" = "grey")) +
  theme_minimal() +
  labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
       x = "Log2 Fold Change",
       y = "-Log10 Adjusted P-Value",
       color = "Significance") +

  # Add gene labels WITHOUT any lines connecting them
  geom_text_repel(data = top_genes, 
                  aes(label = gene),  
                  size = 3, box.padding = 0.3, max.overlaps = 15, segment.color = NA) +  

  # Add threshold lines
  geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black") +  # logFC thresholds
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") +  # p-value threshold

  ylim(0, 70)  # Set max y-axis limit to avoid extreme values

NA
NA

Volcano Plot

library(ggplot2)
library(dplyr)
library(ggrepel)

# Extract results from Libra
DE_results_df <- as.data.frame(DE_results)

# Ensure correct column names
colnames(DE_results_df)
 [1] "cell_type"     "gene"          "avg_logFC"     "Malignant.pct" "Control.pct"   "Malignant.exp" "Control.exp"  
 [8] "p_val"         "p_val_adj"     "de_family"     "de_method"     "de_type"      
# Define significance categories
volcano_data <- DE_results_df %>%
  mutate(
    significance = case_when(
      p_val_adj < 1e-20 & avg_logFC > 2 ~ "Highly Upregulated",
      p_val_adj < 1e-20 & avg_logFC < -2 ~ "Highly Downregulated",
      p_val_adj < 0.05 & avg_logFC > 2 ~ "Upregulated",
      p_val_adj < 0.05 & avg_logFC < -2 ~ "Downregulated",
      TRUE ~ "Not Significant"
    )
  )

# Select only very significant genes for labeling
top_genes <- volcano_data %>%
  filter(p_val_adj < 0.05 & (avg_logFC > 2 | avg_logFC < -2))

ggplot(volcano_data, aes(x = avg_logFC, y = -log10(p_val_adj), color = significance)) +
  
  # Main points
  geom_point(alpha = 0.7, size = 2.5) +
  
  # Highlight highly significant genes with larger points
  geom_point(data = top_genes, aes(x = avg_logFC, y = -log10(p_val_adj)), 
             color = "black", size = 3, shape = 21, fill = "black") +

  # Custom color scheme
  scale_color_manual(values = c(
    "Highly Upregulated" = "darkred",
    "Highly Downregulated" = "darkblue",
    "Upregulated" = "red",
    "Downregulated" = "blue",
    "Not Significant" = "grey"
  )) +

  # Add gene labels (only for highly significant genes)
  geom_text_repel(data = top_genes, aes(label = gene),  
                  size = 4, box.padding = 0.5, max.overlaps = 10, segment.color = NA) +
  
  # Add threshold lines
  geom_vline(xintercept = c(-2, 2), linetype = "dashed", color = "black") +  
  geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "black") +  

  # Improve theme
  theme_minimal(base_size = 14) +
  labs(title = "Volcano Plot: Pseudobulk DESeq2 Analysis",
       x = "Log2 Fold Change",
       y = "-Log10 Adjusted P-Value",
       color = "Significance") +

  ylim(0, 50)  # Avoid extreme scaling issues

NA
NA

5. Summarize Markers

markers <- DE_results_df

summarize_markers <- function(markers) {
  num_pval0 <- sum(markers$p_val_adj == 0)
  num_pval1 <- sum(markers$p_val_adj == 1)
  num_significant <- sum(markers$p_val_adj < 0.05)
  num_upregulated <- sum(markers$avg_logFC > 1)
  num_downregulated <- sum(markers$avg_logFC < -1)
  
  cat("Number of genes with p_val_adj = 0:", num_pval0, "\n")
  cat("Number of genes with p_val_adj = 1:", num_pval1, "\n")
  cat("Number of significant genes (p_val_adj < 0.05):", num_significant, "\n")
  cat("Number of upregulated genes (avg_logFC > 1):", num_upregulated, "\n")
  cat("Number of downregulated genes (avg_logFC < 1):", num_downregulated, "\n")
}

cat("Markers1 Summary (MAST with Batch Correction):\n")
Markers1 Summary (MAST with Batch Correction):
summarize_markers(markers)
Number of genes with p_val_adj = 0: 0 
Number of genes with p_val_adj = 1: 164 
Number of significant genes (p_val_adj < 0.05): 5582 
Number of upregulated genes (avg_logFC > 1): 5591 
Number of downregulated genes (avg_logFC < 1): 4822 

9. EnhancedVolcano plot


library(dplyr)
library(EnhancedVolcano)

# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- markers %>%
  arrange(p_val_adj, desc(abs(avg_logFC)))

# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 0.0000905 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_logFC", 
  y = "p_val_adj",
  title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
  pCutoff = 0.0000905,
  FCcutoff = 1.0,
  legendPosition = 'right', 
  labCol = 'black',
  labFace = 'bold',
  boxedLabels = FALSE,  # Set to FALSE to remove boxed labels
  pointSize = 3.0,
  labSize = 5.0,
  col = c('grey70', 'lightblue', 'blue', 'red'),  # Customize point colors
  selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]  # Only label significant genes
)

EnhancedVolcano plot


library(dplyr)
library(EnhancedVolcano)

# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- markers %>%
  arrange(p_val_adj, desc(abs(avg_logFC)))

# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 0.0000905 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_logFC", 
  y = "p_val_adj",
  title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
  pCutoff = 1e-4,
  FCcutoff = 1.0,
  legendPosition = 'right', 
  labCol = 'black',
  labFace = 'bold',
  boxedLabels = FALSE,  # Set to FALSE to remove boxed labels
  pointSize = 3.0,
  labSize = 5.0,
  col = c('grey70', 'black', 'blue', 'red'),  # Customize point colors
  selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]  # Only label significant genes
)

NA
NA
NA

Create the EnhancedVolcano plot

 Malignant_CD4Tcells_vs_Normal_CD4Tcells <- markers

EnhancedVolcano(Malignant_CD4Tcells_vs_Normal_CD4Tcells,
                lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
                x = "avg_logFC",
                y = "p_val_adj",
                title = "MAST with Batch Correction (All Genes)",
                pCutoff = 0.05,
                FCcutoff = 1.0)



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



library(dplyr)
library(EnhancedVolcano)

# Assuming you have a data frame named Malignant_CD4Tcells_vs_Normal_CD4Tcells
# Filter genes based on lowest p-values but include all genes
filtered_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  arrange(p_val_adj, desc(abs(avg_logFC)))

# Create the EnhancedVolcano plot with the filtered data
EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_logFC", 
  y = "p_val_adj",
  title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
  pCutoff = 0.05,
  FCcutoff = 1.0,
  legendPosition = 'right', 
  labCol = 'black',
  labFace = 'bold',
  boxedLabels = FALSE,  # Set to FALSE to remove boxed labels
  pointSize = 3.0,
  labSize = 5.0,
  col = c('grey70', 'black', 'blue', 'red'),  # Customize point colors
  selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]  # Only label significant genes
)




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

NA
NA

ggplot2 for Volcano

library(ggplot2)
library(ggrepel)

# Identify top and bottom genes
top_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < 0.05 & Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > 0.5, ]
bottom_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < 0.05 & Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < -0.5, ]

# Create a new column for color based on significance
Malignant_CD4Tcells_vs_Normal_CD4Tcells$color <- ifelse(Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > 0.5, "Upregulated genes",
                                                   ifelse(Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < -0.5, "Downregulated genes", "Nonsignificant"))

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

NA
NA
NA
NA
NA

Create the EnhancedVolcano plot


library(ggplot2)
library(EnhancedVolcano)
library(dplyr)

# Define the output directory
output_dir <- "Malignant_vs_Control"
dir.create(output_dir, showWarnings = FALSE)

# First Volcano Plot
p1 <- EnhancedVolcano(
  Malignant_CD4Tcells_vs_Normal_CD4Tcells,
  lab = Malignant_CD4Tcells_vs_Normal_CD4Tcells$gene,
  x = "avg_logFC",
  y = "p_val_adj",
  title = "Malignant_CD4Tcells_vs_Normal_CD4Tcells",
  pCutoff = 1e-4,
  FCcutoff = 1.0
)
print(p1)  # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot1.png"), plot = p1, width = 14, height = 10, dpi = 300)

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

ggsave(filename = file.path(output_dir, "VolcanoPlot2.png"), plot = p2, width = 14, height = 10, dpi = 300)

# Filtering genes
filtered_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells %>%
  arrange(p_val_adj, desc(abs(avg_logFC)))

# Third Volcano Plot - Filtering by p-value and logFC
p3 <- EnhancedVolcano(
  filtered_genes, 
  lab = ifelse(filtered_genes$p_val_adj <= 1e-4 & abs(filtered_genes$avg_logFC) >= 1.0, filtered_genes$gene, NA),
  x = "avg_logFC", 
  y = "p_val_adj",
  title = "Malignant CD4 T cells(cell lines) vs normal CD4 T cells",
  pCutoff = 1e-4,
  FCcutoff = 1.0,
  legendPosition = 'right', 
  labCol = 'black',
  labFace = 'bold',
  boxedLabels = FALSE,  # Remove boxed labels
  pointSize = 3.0,
  labSize = 5.0,
  col = c('grey70', 'black', 'blue', 'red'),  # Customize point colors
  selectLab = filtered_genes$gene[filtered_genes$p_val_adj <= 0.05 & abs(filtered_genes$avg_logFC) >= 1.0]
)
print(p3)  # Display in notebook

ggsave(filename = file.path(output_dir, "VolcanoPlot3.png"), plot = p3, width = 14, height = 10, dpi = 300)

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

ggsave(filename = file.path(output_dir, "VolcanoPlot4.png"), plot = p4, width = 14, height = 10, dpi = 300)

message("All volcano plots have been displayed and saved successfully in the 'L1_vs_Control' folder.")
All volcano plots have been displayed and saved successfully in the 'L1_vs_Control' folder.

10. Enrichment Analysis-1

# Load necessary libraries
library(clusterProfiler)
library(org.Hs.eg.db)
library(enrichplot)
library(ReactomePA)
library(DOSE) # For GSEA analysis
library(ggplot2) # Ensure ggplot2 is available for plotting

# Define threshold for differential expression selection (modified thresholds)
logFC_up_threshold <- 1          # Upregulated logFC threshold
logFC_down_threshold <- -1       # Downregulated logFC threshold
pval_threshold <- 0.05  # p-value threshold as specified

# Load your differential expression results (modify based on actual data structure)
# Malignant_CD4Tcells_vs_Normal_CD4Tcells <- read.csv("Your_DE_Results_File.csv")

# Select upregulated and downregulated genes
upregulated_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[
  Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC > logFC_up_threshold & 
  Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < pval_threshold, ]

downregulated_genes <- Malignant_CD4Tcells_vs_Normal_CD4Tcells[
  Malignant_CD4Tcells_vs_Normal_CD4Tcells$avg_logFC < logFC_down_threshold & 
  Malignant_CD4Tcells_vs_Normal_CD4Tcells$p_val_adj < pval_threshold, ]

# Check for missing genes (NAs) in the gene column and remove them
upregulated_genes <- na.omit(upregulated_genes)
downregulated_genes <- na.omit(downregulated_genes)

# Save upregulated and downregulated gene results to CSV
write.csv(upregulated_genes, "Malignant_vs_Control/upregulated_genes.csv", row.names = FALSE)
write.csv(downregulated_genes, "Malignant_vs_Control/downregulated_genes.csv", row.names = FALSE)

# Convert gene symbols to Entrez IDs for enrichment analysis, with checks for missing values
upregulated_entrez <- bitr(upregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 14.39% of input gene IDs are fail to map...
downregulated_entrez <- bitr(downregulated_genes$gene, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
'select()' returned 1:1 mapping between keys and columns
Avis : 26.94% of input gene IDs are fail to map...
# Check for missing Entrez IDs
missing_upregulated <- upregulated_genes$gene[is.na(upregulated_entrez$ENTREZID)]
missing_downregulated <- downregulated_genes$gene[is.na(downregulated_entrez$ENTREZID)]

# Print out the missing gene symbols for debugging
cat("Missing upregulated genes:\n", missing_upregulated, "\n")
Missing upregulated genes:
  
cat("Missing downregulated genes:\n", missing_downregulated, "\n")
Missing downregulated genes:
  
# Remove genes that couldn't be mapped to Entrez IDs
upregulated_entrez <- upregulated_entrez$ENTREZID[!is.na(upregulated_entrez$ENTREZID)]
downregulated_entrez <- downregulated_entrez$ENTREZID[!is.na(downregulated_entrez$ENTREZID)]

# Define a function to safely run enrichment, plot results, and save them
safe_enrichGO <- function(gene_list, title, filename) {
  if (length(gene_list) > 0) {
    result <- enrichGO(gene = gene_list, OrgDb = org.Hs.eg.db, keyType = "SYMBOL",
                       ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05)
    if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
      p <- dotplot(result, showCategory = 10, title = title)
      print(p)  
      ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
      write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
    } else {
      message(paste("No significant enrichment found for:", title))
    }
  } else {
    message(paste("No genes found for:", title))
  }
}

safe_enrichKEGG <- function(entrez_list, title, filename) {
  if (length(entrez_list) > 0) {
    result <- enrichKEGG(gene = entrez_list, organism = "hsa", pvalueCutoff = 0.05)
    if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
      p <- dotplot(result, showCategory = 10, title = title)
      print(p)
      ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
      write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
    } else {
      message(paste("No significant KEGG pathways found for:", title))
    }
  } else {
    message(paste("No genes found for:", title))
  }
}

safe_enrichReactome <- function(entrez_list, title, filename) {
  if (length(entrez_list) > 0) {
    result <- enrichPathway(gene = entrez_list, organism = "human", pvalueCutoff = 0.05)
    if (!is.null(result) && nrow(as.data.frame(result)) > 0) {
      p <- dotplot(result, showCategory = 10, title = title)
      print(p)
      ggsave(paste0("Malignant_vs_Control/", gsub(".csv", "_dotplot.png", filename)), plot = p, width = 8, height = 6)
      write.csv(as.data.frame(result), file = paste0("Malignant_vs_Control/", filename), row.names = FALSE)
    } else {
      message(paste("No significant Reactome pathways found for:", title))
    }
  } else {
    message(paste("No genes found for:", title))
  }
}

# Perform enrichment analyses, generate plots, and save results
safe_enrichGO(upregulated_genes$gene, "GO Enrichment for Upregulated Genes", "upregulated_GO_results.csv")

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


safe_enrichKEGG(upregulated_entrez, "KEGG Pathway Enrichment for Upregulated Genes", "upregulated_KEGG_results.csv")
View(downregulated_genes)

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


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

safe_enrichReactome(downregulated_entrez, "Reactome Pathway Enrichment for Downregulated Genes", "downregulated_Reactome_results.csv")
No significant Reactome pathways found for: Reactome Pathway Enrichment for Downregulated Genes

Enrichment Analysis-2-Hallmark


# Load necessary libraries
library(clusterProfiler)
library(org.Hs.eg.db)
library(msigdbr)
library(enrichplot)

# Load Hallmark gene sets from msigdbr
hallmark_sets <- msigdbr(species = "Homo sapiens", category = "H")  # "H" is for Hallmark gene sets

# Convert gene symbols to uppercase for consistency
upregulated_genes$gene <- toupper(upregulated_genes$gene)
downregulated_genes$gene <- toupper(downregulated_genes$gene)

# Check for overlap between your upregulated/downregulated genes and Hallmark gene sets
upregulated_in_hallmark <- intersect(upregulated_genes$gene, hallmark_sets$gene_symbol)
downregulated_in_hallmark <- intersect(downregulated_genes$gene, hallmark_sets$gene_symbol)

# Print the number of overlapping genes for both upregulated and downregulated genes
cat("Number of upregulated genes in Hallmark gene sets:", length(upregulated_in_hallmark), "\n")
Number of upregulated genes in Hallmark gene sets: 588 
cat("Number of downregulated genes in Hallmark gene sets:", length(downregulated_in_hallmark), "\n")
Number of downregulated genes in Hallmark gene sets: 264 
# Define the output folder where the results will be saved
output_folder <- "Malignant_vs_Control/"

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


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

NA
NA
LS0tCnRpdGxlOiAiUHNldWRvQnVsayBBbmFseXNpcyB1c2luZyBMaWJyYSBSTkEgYXNzYXktRGVzZXEyLUxSVCIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdAogICMgd29yZF9kb2N1bWVudDogZGVmYXVsdAogICMgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgojIExvYWQgbGlicmFyaWVzCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKbGlicmFyeShERVNlcTIpCmxpYnJhcnkoTGlicmEpCgpgYGAKCgojIDIuIGxvYWQgc2V1cmF0IG9iamVjdApgYGB7ciBsb2FkX3NldXJhdH0KI0xvYWQgU2V1cmF0IE9iamVjdCBMNwpsb2FkKCIvaG9tZS9uYWJiYXNpL2lzaWxvbi9Ub19UcmFuc2Zlcl9iZXR3ZWVuX2NvbXB1dGVycy8yMy1IYXJtb255X0ludGVncmF0aW9uLzAtcm9iai81LUhhcm1vbnlfSW50ZWdyYXRlZF9BbGxfc2FtcGxlc19NZXJnZWRfQ0Q0VGNlbGxzX2ZpbmFsX1Jlc29sdXRpb25fU2VsZWN0ZWRfMC44X0FEVF9Ob3JtYWxpemVkX2NsZWFuZWRfbXQucm9iaiIpCgpwc2V1ZG9idWxrX3NldXJhdCA8LSBBbGxfc2FtcGxlc19NZXJnZWQKCnBzZXVkb2J1bGtfc2V1cmF0JGxhYmVsIDwtIGZhY3RvcigKICBpZmVsc2UocHNldWRvYnVsa19zZXVyYXQkb3JpZy5pZGVudCAlaW4lIGMoIkwxIiwgIkwyIiwgIkwzIiwgIkw0IiwgIkw1IiwgIkw2IiwgIkw3IiksICJNYWxpZ25hbnQiLCAiQ29udHJvbCIpLAogIGxldmVscyA9IGMoIk1hbGlnbmFudCIsICJDb250cm9sIikgICMgRW5zdXJpbmcgIk1hbGlnbmFudCIgaXMgdGhlIHJlZmVyZW5jZQopCgojIEVuc3VyZSAnY29uZGl0aW9uJyBpcyBhIGZhY3RvciB3aXRoIHRoZSBjb3JyZWN0IGxldmVscwpwc2V1ZG9idWxrX3NldXJhdCRsYWJlbCA8LSBmYWN0b3IocHNldWRvYnVsa19zZXVyYXQkbGFiZWwsIGxldmVscyA9IGMoIk1hbGlnbmFudCIsICJDb250cm9sIikpCgojIEVuc3VyZSAncmVwbGljYXRlJyBpcyBhIGZhY3Rvcgpwc2V1ZG9idWxrX3NldXJhdCRyZXBsaWNhdGUgPC0gYXMuZmFjdG9yKHBzZXVkb2J1bGtfc2V1cmF0JGNlbGxfbGluZSkKCiMgUmVuYW1lIHRoZSBjZWxsIHR5cGUgY29sdW1uCnBzZXVkb2J1bGtfc2V1cmF0JGNlbGxfdHlwZSA8LSAiQ0Q0VCIKYGBgCgojIDMuIERFIHVzaW5nIExJQlJBCmBgYHtyICwgZmlnLmhlaWdodD0xNCwgZmlnLndpZHRoPTE4fQpsaWJyYV90ZXN0IDwtcHNldWRvYnVsa19zZXVyYXQKCgoKREVfcmVzdWx0cyA8LSBydW5fZGUoCiAgbGlicmFfdGVzdCwKICBjZWxsX3R5cGVfY29sID0gImNlbGxfdHlwZSIsIAogIHJlcGxpY2F0ZV9jb2wgPSAicmVwbGljYXRlIiwKICBsYWJlbF9jb2wgPSAibGFiZWwiLAogIGRlX2ZhbWlseSA9ICJwc2V1ZG9idWxrIiwgICAjIG9yICJzaW5nbGVjZWxsIgogIGRlX21ldGhvZCA9ICJERVNlcTIiLCAgICAgICAgIyBvciAid2lsY294IgopCgpgYGAKCgojIDQuIFZvbGNhbm8gUGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQoKIyBFeHRyYWN0IHJlc3VsdHMgZnJvbSBMaWJyYQpERV9yZXN1bHRzX2RmIDwtIGFzLmRhdGEuZnJhbWUoREVfcmVzdWx0cykKCiMgU2F2ZSByZXN1bHRzIHRvIENTVgp3cml0ZS5jc3YoREVfcmVzdWx0c19kZiwgZmlsZSA9ICIxLVBzZXVkb2J1bGtfREVzZXEyX0xSVF9ERV93aXRoX2xpYnJhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyBFbnN1cmUgbG9nRkMgYW5kIHAtdmFsdWUgY29sdW1ucyBhcmUgbmFtZWQgY29ycmVjdGx5CmNvbG5hbWVzKERFX3Jlc3VsdHNfZGYpCgojIEZpbHRlcmluZyBmb3Igc2lnbmlmaWNhbnQgZ2VuZXM6CnZvbGNhbm9fZGF0YSA8LSBERV9yZXN1bHRzX2RmICU+JQogIG11dGF0ZSgKICAgIHNpZ25pZmljYW5jZSA9IGNhc2Vfd2hlbigKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2dGQyA+IDIgfiAiVXByZWd1bGF0ZWQiLAogICAgICBwX3ZhbF9hZGogPCAwLjA1ICYgYXZnX2xvZ0ZDIDwgLTIgfiAiRG93bnJlZ3VsYXRlZCIsCiAgICAgIFRSVUUgfiAiTm90IFNpZ25pZmljYW50IgogICAgKQogICkKZ2dwbG90KHZvbGNhbm9fZGF0YSwgYWVzKHggPSBhdmdfbG9nRkMsIHkgPSAtbG9nMTAocF92YWxfYWRqKSwgY29sb3IgPSBzaWduaWZpY2FuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVXByZWd1bGF0ZWQiID0gInJlZCIsICJEb3ducmVndWxhdGVkIiA9ICJibHVlIiwgIk5vdCBTaWduaWZpY2FudCIgPSAiZ3JleSIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdDogUHNldWRvYnVsayBERVNlcTIgQW5hbHlzaXMiLAogICAgICAgeCA9ICJMb2cyIEZvbGQgQ2hhbmdlIiwKICAgICAgIHkgPSAiLUxvZzEwIEFkanVzdGVkIFAtVmFsdWUiLAogICAgICAgY29sb3IgPSAiU2lnbmlmaWNhbmNlIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMiwgMiksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikKCgpgYGAKCgoKCiMjIFZvbGNhbm8gUGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCgpFbmhhbmNlZFZvbGNhbm8oCiAgREVfcmVzdWx0cywgCiAgbGFiID0gREVfcmVzdWx0cyRnZW5lLCAgIyBMYWJlbHMgZm9yIGdlbmVzCiAgeCA9ICdhdmdfbG9nRkMnLCAgICAgICAgICAgICAjIExvZzIgRm9sZCBDaGFuZ2UgKGNvcnJlY3RlZCBuYW1lKQogIHkgPSAncF92YWxfYWRqJywgICAgICAgICAgICAgIyBBZGp1c3RlZCBQLXZhbHVlCiAgdGl0bGUgPSAnVm9sY2FubyBQbG90OiBQc2V1ZG9idWxrIERFU2VxMiBBbmFseXNpcycsCiAgc3VidGl0bGUgPSAnTWFsaWduYW50IHZzIE5vcm1hbCBDRDRUIENlbGxzJywKICBwQ3V0b2ZmID0gMC4wNSwgICAgICAgICAgICAgICMgQWRqdXN0ZWQgcC12YWx1ZSB0aHJlc2hvbGQKICBGQ2N1dG9mZiA9IDIsICAgICAgICAgICAgICAgICMgRm9sZCBDaGFuZ2UgdGhyZXNob2xkCiAgcG9pbnRTaXplID0gMi4wLCAgICAgICAgICAgICAjIEFkanVzdCBwb2ludCBzaXplCiAgbGFiU2l6ZSA9IDQuMCwgICAgICAgICAgICAgICAjIEFkanVzdCBsYWJlbCBzaXplCiAgY29sID0gYygiYmxhY2siLCAiZ3JleSIsICJibHVlIiwgInJlZCIpLCAjIENvbG9yIGNvZGluZwogIGNvbEFscGhhID0gMC42LCAgICAgICAgICAgICAgIyBUcmFuc3BhcmVuY3kgZm9yIHBvaW50cwogIGxlZ2VuZExhYmVscyA9IGMoIk5TIiwgIkxvZzJGQyIsICJQLXZhbHVlIiwgIkJvdGgiKSwKICBsZWdlbmRQb3NpdGlvbiA9ICJyaWdodCIsCiAgbGVnZW5kTGFiU2l6ZSA9IDEwLAogIGxlZ2VuZEljb25TaXplID0gNC4wLAogIGRyYXdDb25uZWN0b3JzID0gVFJVRSwgICAgICAgIyBDb25uZWN0IGdlbmUgbGFiZWxzCiAgd2lkdGhDb25uZWN0b3JzID0gMC41LAogIHZsaW5lID0gYygtMiwgMiksICAgICAgICAgICAgIyBWZXJ0aWNhbCBsaW5lcyBhdCBsb2dGQyDCsTIKICBobGluZSA9IC1sb2cxMCgwLjA1KSwgICAgICAgICMgSG9yaXpvbnRhbCBsaW5lIGF0IGFkanVzdGVkIHAtdmFsdWUgMC4wNQogIGJvcmRlciA9ICJmdWxsIgopCgpgYGAKCgoKCiMjIFZvbGNhbm8gUGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncmVwZWwpCgojIEV4dHJhY3QgcmVzdWx0cyBmcm9tIExpYnJhCkRFX3Jlc3VsdHNfZGYgPC0gYXMuZGF0YS5mcmFtZShERV9yZXN1bHRzKQoKIyBFbnN1cmUgY29ycmVjdCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoREVfcmVzdWx0c19kZikKCiMgRGVmaW5lIHNpZ25pZmljYW5jZSBjYXRlZ29yaWVzCnZvbGNhbm9fZGF0YSA8LSBERV9yZXN1bHRzX2RmICU+JQogIG11dGF0ZSgKICAgIHNpZ25pZmljYW5jZSA9IGNhc2Vfd2hlbigKICAgICAgcF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2dGQyA+IDIgfiAiVXByZWd1bGF0ZWQiLAogICAgICBwX3ZhbF9hZGogPCAwLjA1ICYgYXZnX2xvZ0ZDIDwgLTIgfiAiRG93bnJlZ3VsYXRlZCIsCiAgICAgIFRSVUUgfiAiTm90IFNpZ25pZmljYW50IgogICAgKQogICkKCiMgU2VsZWN0IGdlbmVzIHRvIGxhYmVsOiBwX3ZhbF9hZGogPCAxZS01MCBPUiBsb2dGQyA+IDIgT1IgbG9nRkMgPCAtMgp0b3BfZ2VuZXMgPC0gdm9sY2Fub19kYXRhICU+JQogIGZpbHRlcihwX3ZhbF9hZGogPCAwLjA1IHwgYXZnX2xvZ0ZDID4gMiB8IGF2Z19sb2dGQyA8IC0yKQoKZ2dwbG90KHZvbGNhbm9fZGF0YSwgYWVzKHggPSBhdmdfbG9nRkMsIHkgPSAtbG9nMTAocF92YWxfYWRqKSwgY29sb3IgPSBzaWduaWZpY2FuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgc2l6ZSA9IDIpICsgICMgTWFpbiBwb2ludHMKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVXByZWd1bGF0ZWQiID0gInJlZCIsICJEb3ducmVndWxhdGVkIiA9ICJibHVlIiwgIk5vdCBTaWduaWZpY2FudCIgPSAiZ3JleSIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdDogUHNldWRvYnVsayBERVNlcTIgQW5hbHlzaXMiLAogICAgICAgeCA9ICJMb2cyIEZvbGQgQ2hhbmdlIiwKICAgICAgIHkgPSAiLUxvZzEwIEFkanVzdGVkIFAtVmFsdWUiLAogICAgICAgY29sb3IgPSAiU2lnbmlmaWNhbmNlIikgKwoKICAjIEFkZCBnZW5lIGxhYmVscyBXSVRIT1VUIGFueSBsaW5lcyBjb25uZWN0aW5nIHRoZW0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IHRvcF9nZW5lcywgCiAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IGdlbmUpLCAgCiAgICAgICAgICAgICAgICAgIHNpemUgPSAzLCBib3gucGFkZGluZyA9IDAuMywgbWF4Lm92ZXJsYXBzID0gMTUsIHNlZ21lbnQuY29sb3IgPSBOQSkgKyAgCgogICMgQWRkIHRocmVzaG9sZCBsaW5lcwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTIsIDIpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICsgICMgbG9nRkMgdGhyZXNob2xkcwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArICAjIHAtdmFsdWUgdGhyZXNob2xkCgogIHlsaW0oMCwgNzApICAjIFNldCBtYXggeS1heGlzIGxpbWl0IHRvIGF2b2lkIGV4dHJlbWUgdmFsdWVzCgoKYGBgCiMjIFZvbGNhbm8gUGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xOH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncmVwZWwpCgojIEV4dHJhY3QgcmVzdWx0cyBmcm9tIExpYnJhCkRFX3Jlc3VsdHNfZGYgPC0gYXMuZGF0YS5mcmFtZShERV9yZXN1bHRzKQoKIyBFbnN1cmUgY29ycmVjdCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoREVfcmVzdWx0c19kZikKCiMgRGVmaW5lIHNpZ25pZmljYW5jZSBjYXRlZ29yaWVzCnZvbGNhbm9fZGF0YSA8LSBERV9yZXN1bHRzX2RmICU+JQogIG11dGF0ZSgKICAgIHNpZ25pZmljYW5jZSA9IGNhc2Vfd2hlbigKICAgICAgcF92YWxfYWRqIDwgMWUtMjAgJiBhdmdfbG9nRkMgPiAyIH4gIkhpZ2hseSBVcHJlZ3VsYXRlZCIsCiAgICAgIHBfdmFsX2FkaiA8IDFlLTIwICYgYXZnX2xvZ0ZDIDwgLTIgfiAiSGlnaGx5IERvd25yZWd1bGF0ZWQiLAogICAgICBwX3ZhbF9hZGogPCAwLjA1ICYgYXZnX2xvZ0ZDID4gMiB+ICJVcHJlZ3VsYXRlZCIsCiAgICAgIHBfdmFsX2FkaiA8IDAuMDUgJiBhdmdfbG9nRkMgPCAtMiB+ICJEb3ducmVndWxhdGVkIiwKICAgICAgVFJVRSB+ICJOb3QgU2lnbmlmaWNhbnQiCiAgICApCiAgKQoKIyBTZWxlY3Qgb25seSB2ZXJ5IHNpZ25pZmljYW50IGdlbmVzIGZvciBsYWJlbGluZwp0b3BfZ2VuZXMgPC0gdm9sY2Fub19kYXRhICU+JQogIGZpbHRlcihwX3ZhbF9hZGogPCAwLjA1ICYgKGF2Z19sb2dGQyA+IDIgfCBhdmdfbG9nRkMgPCAtMikpCgpnZ3Bsb3Qodm9sY2Fub19kYXRhLCBhZXMoeCA9IGF2Z19sb2dGQywgeSA9IC1sb2cxMChwX3ZhbF9hZGopLCBjb2xvciA9IHNpZ25pZmljYW5jZSkpICsKICAKICAjIE1haW4gcG9pbnRzCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNywgc2l6ZSA9IDIuNSkgKwogIAogICMgSGlnaGxpZ2h0IGhpZ2hseSBzaWduaWZpY2FudCBnZW5lcyB3aXRoIGxhcmdlciBwb2ludHMKICBnZW9tX3BvaW50KGRhdGEgPSB0b3BfZ2VuZXMsIGFlcyh4ID0gYXZnX2xvZ0ZDLCB5ID0gLWxvZzEwKHBfdmFsX2FkaikpLCAKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIHNoYXBlID0gMjEsIGZpbGwgPSAiYmxhY2siKSArCgogICMgQ3VzdG9tIGNvbG9yIHNjaGVtZQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKAogICAgIkhpZ2hseSBVcHJlZ3VsYXRlZCIgPSAiZGFya3JlZCIsCiAgICAiSGlnaGx5IERvd25yZWd1bGF0ZWQiID0gImRhcmtibHVlIiwKICAgICJVcHJlZ3VsYXRlZCIgPSAicmVkIiwKICAgICJEb3ducmVndWxhdGVkIiA9ICJibHVlIiwKICAgICJOb3QgU2lnbmlmaWNhbnQiID0gImdyZXkiCiAgKSkgKwoKICAjIEFkZCBnZW5lIGxhYmVscyAob25seSBmb3IgaGlnaGx5IHNpZ25pZmljYW50IGdlbmVzKQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gdG9wX2dlbmVzLCBhZXMobGFiZWwgPSBnZW5lKSwgIAogICAgICAgICAgICAgICAgICBzaXplID0gNCwgYm94LnBhZGRpbmcgPSAwLjUsIG1heC5vdmVybGFwcyA9IDEwLCBzZWdtZW50LmNvbG9yID0gTkEpICsKICAKICAjIEFkZCB0aHJlc2hvbGQgbGluZXMKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0yLCAyKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgKyAgCgogICMgSW1wcm92ZSB0aGVtZQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdDogUHNldWRvYnVsayBERVNlcTIgQW5hbHlzaXMiLAogICAgICAgeCA9ICJMb2cyIEZvbGQgQ2hhbmdlIiwKICAgICAgIHkgPSAiLUxvZzEwIEFkanVzdGVkIFAtVmFsdWUiLAogICAgICAgY29sb3IgPSAiU2lnbmlmaWNhbmNlIikgKwoKICB5bGltKDAsIDUwKSAgIyBBdm9pZCBleHRyZW1lIHNjYWxpbmcgaXNzdWVzCgoKYGBgCgojIDUuIFN1bW1hcml6ZSBNYXJrZXJzCmBgYHtyICwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQptYXJrZXJzIDwtIERFX3Jlc3VsdHNfZGYKCnN1bW1hcml6ZV9tYXJrZXJzIDwtIGZ1bmN0aW9uKG1hcmtlcnMpIHsKICBudW1fcHZhbDAgPC0gc3VtKG1hcmtlcnMkcF92YWxfYWRqID09IDApCiAgbnVtX3B2YWwxIDwtIHN1bShtYXJrZXJzJHBfdmFsX2FkaiA9PSAxKQogIG51bV9zaWduaWZpY2FudCA8LSBzdW0obWFya2VycyRwX3ZhbF9hZGogPCAwLjA1KQogIG51bV91cHJlZ3VsYXRlZCA8LSBzdW0obWFya2VycyRhdmdfbG9nRkMgPiAxKQogIG51bV9kb3ducmVndWxhdGVkIDwtIHN1bShtYXJrZXJzJGF2Z19sb2dGQyA8IC0xKQogIAogIGNhdCgiTnVtYmVyIG9mIGdlbmVzIHdpdGggcF92YWxfYWRqID0gMDoiLCBudW1fcHZhbDAsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2YgZ2VuZXMgd2l0aCBwX3ZhbF9hZGogPSAxOiIsIG51bV9wdmFsMSwgIlxuIikKICBjYXQoIk51bWJlciBvZiBzaWduaWZpY2FudCBnZW5lcyAocF92YWxfYWRqIDwgMC4wNSk6IiwgbnVtX3NpZ25pZmljYW50LCAiXG4iKQogIGNhdCgiTnVtYmVyIG9mIHVwcmVndWxhdGVkIGdlbmVzIChhdmdfbG9nRkMgPiAxKToiLCBudW1fdXByZWd1bGF0ZWQsICJcbiIpCiAgY2F0KCJOdW1iZXIgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcyAoYXZnX2xvZ0ZDIDwgMSk6IiwgbnVtX2Rvd25yZWd1bGF0ZWQsICJcbiIpCn0KCmNhdCgiTWFya2VyczEgU3VtbWFyeSAoTUFTVCB3aXRoIEJhdGNoIENvcnJlY3Rpb24pOlxuIikKCnN1bW1hcml6ZV9tYXJrZXJzKG1hcmtlcnMpCmBgYAoKCiMgOS4gRW5oYW5jZWRWb2xjYW5vIHBsb3QKYGBge3IgLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiMgQXNzdW1pbmcgeW91IGhhdmUgYSBkYXRhIGZyYW1lIG5hbWVkIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscwojIEZpbHRlciBnZW5lcyBiYXNlZCBvbiBsb3dlc3QgcC12YWx1ZXMgYnV0IGluY2x1ZGUgYWxsIGdlbmVzCmZpbHRlcmVkX2dlbmVzIDwtIG1hcmtlcnMgJT4lCiAgYXJyYW5nZShwX3ZhbF9hZGosIGRlc2MoYWJzKGF2Z19sb2dGQykpKQoKIyBDcmVhdGUgdGhlIEVuaGFuY2VkVm9sY2FubyBwbG90IHdpdGggdGhlIGZpbHRlcmVkIGRhdGEKRW5oYW5jZWRWb2xjYW5vKAogIGZpbHRlcmVkX2dlbmVzLCAKICBsYWIgPSBpZmVsc2UoZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDAwMDkwNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyhjZWxsIGxpbmVzKSB2cyBub3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHBDdXRvZmYgPSAwLjAwMDA5MDUsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCAKICBsYWJDb2wgPSAnYmxhY2snLAogIGxhYkZhY2UgPSAnYm9sZCcsCiAgYm94ZWRMYWJlbHMgPSBGQUxTRSwgICMgU2V0IHRvIEZBTFNFIHRvIHJlbW92ZSBib3hlZCBsYWJlbHMKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBjb2wgPSBjKCdncmV5NzAnLCAnbGlnaHRibHVlJywgJ2JsdWUnLCAncmVkJyksICAjIEN1c3RvbWl6ZSBwb2ludCBjb2xvcnMKICBzZWxlY3RMYWIgPSBmaWx0ZXJlZF9nZW5lcyRnZW5lW2ZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wXSAgIyBPbmx5IGxhYmVsIHNpZ25pZmljYW50IGdlbmVzCikKCmBgYAoKCgojIyBFbmhhbmNlZFZvbGNhbm8gcGxvdApgYGB7ciAsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNn0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgRmlsdGVyIGdlbmVzIGJhc2VkIG9uIGxvd2VzdCBwLXZhbHVlcyBidXQgaW5jbHVkZSBhbGwgZ2VuZXMKZmlsdGVyZWRfZ2VuZXMgPC0gbWFya2VycyAlPiUKICBhcnJhbmdlKHBfdmFsX2FkaiwgZGVzYyhhYnMoYXZnX2xvZ0ZDKSkpCgojIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3Qgd2l0aCB0aGUgZmlsdGVyZWQgZGF0YQpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wMDAwOTA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgcEN1dG9mZiA9IDFlLTQsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCAKICBsYWJDb2wgPSAnYmxhY2snLAogIGxhYkZhY2UgPSAnYm9sZCcsCiAgYm94ZWRMYWJlbHMgPSBGQUxTRSwgICMgU2V0IHRvIEZBTFNFIHRvIHJlbW92ZSBib3hlZCBsYWJlbHMKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9taXplIHBvaW50IGNvbG9ycwogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjBdICAjIE9ubHkgbGFiZWwgc2lnbmlmaWNhbnQgZ2VuZXMKKQoKCgpgYGAKCiMjIENyZWF0ZSB0aGUgRW5oYW5jZWRWb2xjYW5vIHBsb3QKYGBge3IgZW5oYW5jZWRWLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CiBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMgPC0gbWFya2VycwoKRW5oYW5jZWRWb2xjYW5vKE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscywKICAgICAgICAgICAgICAgIGxhYiA9IE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRnZW5lLAogICAgICAgICAgICAgICAgeCA9ICJhdmdfbG9nRkMiLAogICAgICAgICAgICAgICAgeSA9ICJwX3ZhbF9hZGoiLAogICAgICAgICAgICAgICAgdGl0bGUgPSAiTUFTVCB3aXRoIEJhdGNoIENvcnJlY3Rpb24gKEFsbCBHZW5lcykiLAogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEuMCkKCgpFbmhhbmNlZFZvbGNhbm8oTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzLCAKICAgICAgICAgICAgICAgIGxhYiA9IE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRnZW5lLAogICAgICAgICAgICAgICAgeCA9ICJhdmdfbG9nRkMiLCAKICAgICAgICAgICAgICAgIHkgPSAicF92YWxfYWRqIiwKICAgICAgICAgICAgICAgIHNlbGVjdExhYiA9IGMoJ0VQQ0FNJywgJ0JDQVQxJywgJ0tJUjNETDInLCAnRk9YTTEnLCAnVFdJU1QxJywgJ1RORlNGOScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ0Q4MCcsICAnSUwxQicsICdSUFM0WTEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0lMN1InLCAnVENGNycsICAnTUtJNjcnLCAnQ0Q3MCcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUwyUkEnLCdUUkJWNi0yJywgJ1RSQlYxMC0zJywgJ1RSQlY0LTInLCAnVFJCVjknLCAnVFJCVjctOScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVFJBVjEyLTEnLCAnQ0Q4QicsICdGQ0dSM0EnLCAnR05MWScsICdGT1hQMycsICdTRUxMJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHSU1BUDEnLCAnUklQT1IyJywgJ0xFRjEnLCAnSE9YQzknLCAnU1A1JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0NDTDE3JywgJ0VUVjQnLCAnVEhZMScsICdGT1hBMicsICdJVEdBRCcsICdTMTAwUCcsICdUQlg0JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJRDEnLCAnWENMMScsICdTT1gyJywgJ0NEMjcnLCAnQ0QyOCcsJ1BMUzMnLCdDRDcwJywnUkFCMjUnICwgJ1RSQlYyNycsICdUUkJWMicpLAogICAgICAgICAgICAgICAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgICAgICAgICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+ICdmb2xkIGNoYW5nZScpLAogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEuNSwgCiAgICAgICAgICAgICAgICBwb2ludFNpemUgPSAzLjAsCiAgICAgICAgICAgICAgICBsYWJTaXplID0gNS4wLAogICAgICAgICAgICAgICAgYm94ZWRMYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICBsZWdlbmRMYWJTaXplID0gMTAsCiAgICAgICAgICAgICAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwKICAgICAgICAgICAgICAgIHdpZHRoQ29ubmVjdG9ycyA9IDAuNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAnZ3JleTUwJywKICAgICAgICAgICAgICAgIGFycm93aGVhZHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDMwKQoKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQoKIyBBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGEgZnJhbWUgbmFtZWQgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzCiMgRmlsdGVyIGdlbmVzIGJhc2VkIG9uIGxvd2VzdCBwLXZhbHVlcyBidXQgaW5jbHVkZSBhbGwgZ2VuZXMKZmlsdGVyZWRfZ2VuZXMgPC0gTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzICU+JQogIGFycmFuZ2UocF92YWxfYWRqLCBkZXNjKGFicyhhdmdfbG9nRkMpKSkKCiMgQ3JlYXRlIHRoZSBFbmhhbmNlZFZvbGNhbm8gcGxvdCB3aXRoIHRoZSBmaWx0ZXJlZCBkYXRhCkVuaGFuY2VkVm9sY2FubygKICBmaWx0ZXJlZF9nZW5lcywgCiAgbGFiID0gaWZlbHNlKGZpbHRlcmVkX2dlbmVzJHBfdmFsX2FkaiA8PSAwLjA1ICYgYWJzKGZpbHRlcmVkX2dlbmVzJGF2Z19sb2dGQykgPj0gMS4wLCBmaWx0ZXJlZF9nZW5lcyRnZW5lLCBOQSksCiAgeCA9ICJhdmdfbG9nRkMiLCAKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgcEN1dG9mZiA9IDAuMDUsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLCAKICBsYWJDb2wgPSAnYmxhY2snLAogIGxhYkZhY2UgPSAnYm9sZCcsCiAgYm94ZWRMYWJlbHMgPSBGQUxTRSwgICMgU2V0IHRvIEZBTFNFIHRvIHJlbW92ZSBib3hlZCBsYWJlbHMKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9taXplIHBvaW50IGNvbG9ycwogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjBdICAjIE9ubHkgbGFiZWwgc2lnbmlmaWNhbnQgZ2VuZXMKKQoKCgpFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyAoY2VsbCBsaW5lcykgdnMgTm9ybWFsIENENCBUIGNlbGxzIiwKICBzdWJ0aXRsZSA9ICJIaWdobGlnaHRpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIiwKICBwQ3V0b2ZmID0gMC4wNSwKICBGQ2N1dG9mZiA9IDEuMCwKICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgY29sQWxwaGEgPSAwLjgsICAjIFNsaWdodCB0cmFuc3BhcmVuY3kgZm9yIG5vbi1zaWduaWZpY2FudCBwb2ludHMKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9tIGNvbG9yIHNjaGVtZQogIGdyaWRsaW5lcy5tYWpvciA9IFRSVUUsCiAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgc2VsZWN0TGFiID0gZmlsdGVyZWRfZ2VuZXMkZ2VuZVtmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMC4wNSAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMF0KKSAKCgpgYGAKCiMjIGdncGxvdDIgZm9yIFZvbGNhbm8KYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCgojIElkZW50aWZ5IHRvcCBhbmQgYm90dG9tIGdlbmVzCnRvcF9nZW5lcyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHNbTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJHBfdmFsX2FkaiA8IDAuMDUgJiBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDID4gMC41LCBdCmJvdHRvbV9nZW5lcyA8LSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHNbTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJHBfdmFsX2FkaiA8IDAuMDUgJiBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDIDwgLTAuNSwgXQoKIyBDcmVhdGUgYSBuZXcgY29sdW1uIGZvciBjb2xvciBiYXNlZCBvbiBzaWduaWZpY2FuY2UKTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGNvbG9yIDwtIGlmZWxzZShNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDID4gMC41LCAiVXByZWd1bGF0ZWQgZ2VuZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJGF2Z19sb2dGQyA8IC0wLjUsICJEb3ducmVndWxhdGVkIGdlbmVzIiwgIk5vbnNpZ25pZmljYW50IikpCgojIENyZWF0ZSBhIHZvbGNhbm8gcGxvdApnZ3Bsb3QoTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzLCBhZXMoeCA9IGF2Z19sb2dGQywgeSA9IC1sb2cxMChwX3ZhbF9hZGopKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29sb3IpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDIpICsKICAKICAjIEFkZCBsYWJlbHMgZm9yIHRvcCBhbmQgYm90dG9tIGdlbmVzCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB0b3BfZ2VuZXMsIGFlcyhsYWJlbCA9IGdlbmUpLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGJvdHRvbV9nZW5lcywgYWVzKGxhYmVsID0gZ2VuZSksIGNvbG9yID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgZm9udGZhY2UgPSAiYm9sZCIpICsKICAKICAjIEN1c3RvbWl6ZSBsYWJlbHMgYW5kIHRpdGxlCiAgbGFicyh0aXRsZSA9ICJWb2xjYW5vIFBsb3QiLAogICAgICAgeCA9ICJsb2cyIEZvbGQgQ2hhbmdlIiwKICAgICAgIHkgPSAiLWxvZzEwKHAtdmFsdWUpIikgKwogIAogICMgIyBBZGQgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCBsaW5lcwogICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4wMDAwMSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgKwogICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0wLjUsIDAuNSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgKwogIAogICMgU2V0IGNvbG9ycyBmb3IgdG9wIGFuZCBib3R0b20gZ2VuZXMKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVXByZWd1bGF0ZWQgZ2VuZXMiID0gInJlZCIsICJEb3ducmVndWxhdGVkIGdlbmVzIiA9ICJibHVlIiwgIk5vbnNpZ25pZmljYW50IiA9ICJkYXJrZ3JleSIpKSArCiAgCiAgIyBDdXN0b21pemUgdGhlbWUgaWYgbmVlZGVkCiAgdGhlbWVfbWluaW1hbCgpCgoKCgoKYGBgCgojIyBDcmVhdGUgdGhlIEVuaGFuY2VkVm9sY2FubyBwbG90CmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQpsaWJyYXJ5KGRwbHlyKQoKIyBEZWZpbmUgdGhlIG91dHB1dCBkaXJlY3RvcnkKb3V0cHV0X2RpciA8LSAiTWFsaWduYW50X3ZzX0NvbnRyb2wiCmRpci5jcmVhdGUob3V0cHV0X2Rpciwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgojIEZpcnN0IFZvbGNhbm8gUGxvdApwMSA8LSBFbmhhbmNlZFZvbGNhbm8oCiAgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzLAogIGxhYiA9IE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyRnZW5lLAogIHggPSAiYXZnX2xvZ0ZDIiwKICB5ID0gInBfdmFsX2FkaiIsCiAgdGl0bGUgPSAiTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzIiwKICBwQ3V0b2ZmID0gMWUtNCwKICBGQ2N1dG9mZiA9IDEuMAopCnByaW50KHAxKSAgIyBEaXNwbGF5IGluIG5vdGVib29rCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChvdXRwdXRfZGlyLCAiVm9sY2Fub1Bsb3QxLnBuZyIpLCBwbG90ID0gcDEsIHdpZHRoID0gMTQsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCgojIFNlY29uZCBWb2xjYW5vIFBsb3Qgd2l0aCBzZWxlY3RlZCBnZW5lcwpwMiA8LSBFbmhhbmNlZFZvbGNhbm8oCiAgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzLCAKICBsYWIgPSBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkZ2VuZSwKICB4ID0gImF2Z19sb2dGQyIsIAogIHkgPSAicF92YWxfYWRqIiwKICBzZWxlY3RMYWIgPSBjKCdFUENBTScsICdCQ0FUMScsICdLSVIzREwyJywgJ0ZPWE0xJywgJ1RXSVNUMScsICdUTkZTRjknLCAKICAgICAgICAgICAgICAgICdDRDgwJywgICdJTDFCJywgJ1JQUzRZMScsIAogICAgICAgICAgICAgICAgJ0lMN1InLCAnVENGNycsICAnTUtJNjcnLCAnQ0Q3MCcsIAogICAgICAgICAgICAgICAgJ0lMMlJBJywnVFJCVjYtMicsICdUUkJWMTAtMycsICdUUkJWNC0yJywgJ1RSQlY5JywgJ1RSQlY3LTknLCAKICAgICAgICAgICAgICAgICdUUkFWMTItMScsICdDRDhCJywgJ0ZDR1IzQScsICdHTkxZJywgJ0ZPWFAzJywgJ1NFTEwnLCAKICAgICAgICAgICAgICAgICdHSU1BUDEnLCAnUklQT1IyJywgJ0xFRjEnLCAnSE9YQzknLCAnU1A1JywKICAgICAgICAgICAgICAgICdDQ0wxNycsICdFVFY0JywgJ1RIWTEnLCAnRk9YQTInLCAnSVRHQUQnLCAnUzEwMFAnLCAnVEJYNCcsIAogICAgICAgICAgICAgICAgJ0lEMScsICdYQ0wxJywgJ1NPWDInLCAnQ0QyNycsICdDRDI4JywnUExTMycsJ0NENzAnLCdSQUIyNScgLCAnVFJCVjI3JywgJ1RSQlYyJyksCiAgdGl0bGUgPSAiTWFsaWduYW50IENENCBUIGNlbGxzKGNlbGwgbGluZXMpIHZzIG5vcm1hbCBDRDQgVCBjZWxscyIsCiAgeGxhYiA9IGJxdW90ZSh+TG9nWzJdfiAnZm9sZCBjaGFuZ2UnKSwKICBwQ3V0b2ZmID0gMWUtNCwKICBGQ2N1dG9mZiA9IDEuNSwgCiAgcG9pbnRTaXplID0gMy4wLAogIGxhYlNpemUgPSA1LjAsCiAgYm94ZWRMYWJlbHMgPSBUUlVFLAogIGNvbEFscGhhID0gMC41LAogIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICBsZWdlbmRMYWJTaXplID0gMTAsCiAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogIHdpZHRoQ29ubmVjdG9ycyA9IDAuNSwKICBjb2xDb25uZWN0b3JzID0gJ2dyZXk1MCcsCiAgYXJyb3doZWFkcyA9IEZBTFNFLAogIG1heC5vdmVybGFwcyA9IDMwCikKcHJpbnQocDIpICAjIERpc3BsYXkgaW4gbm90ZWJvb2sKZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJWb2xjYW5vUGxvdDIucG5nIiksIHBsb3QgPSBwMiwgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCiMgRmlsdGVyaW5nIGdlbmVzCmZpbHRlcmVkX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyAlPiUKICBhcnJhbmdlKHBfdmFsX2FkaiwgZGVzYyhhYnMoYXZnX2xvZ0ZDKSkpCgojIFRoaXJkIFZvbGNhbm8gUGxvdCAtIEZpbHRlcmluZyBieSBwLXZhbHVlIGFuZCBsb2dGQwpwMyA8LSBFbmhhbmNlZFZvbGNhbm8oCiAgZmlsdGVyZWRfZ2VuZXMsIAogIGxhYiA9IGlmZWxzZShmaWx0ZXJlZF9nZW5lcyRwX3ZhbF9hZGogPD0gMWUtNCAmIGFicyhmaWx0ZXJlZF9nZW5lcyRhdmdfbG9nRkMpID49IDEuMCwgZmlsdGVyZWRfZ2VuZXMkZ2VuZSwgTkEpLAogIHggPSAiYXZnX2xvZ0ZDIiwgCiAgeSA9ICJwX3ZhbF9hZGoiLAogIHRpdGxlID0gIk1hbGlnbmFudCBDRDQgVCBjZWxscyhjZWxsIGxpbmVzKSB2cyBub3JtYWwgQ0Q0IFQgY2VsbHMiLAogIHBDdXRvZmYgPSAxZS00LAogIEZDY3V0b2ZmID0gMS4wLAogIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywgCiAgbGFiQ29sID0gJ2JsYWNrJywKICBsYWJGYWNlID0gJ2JvbGQnLAogIGJveGVkTGFiZWxzID0gRkFMU0UsICAjIFJlbW92ZSBib3hlZCBsYWJlbHMKICBwb2ludFNpemUgPSAzLjAsCiAgbGFiU2l6ZSA9IDUuMCwKICBjb2wgPSBjKCdncmV5NzAnLCAnYmxhY2snLCAnYmx1ZScsICdyZWQnKSwgICMgQ3VzdG9taXplIHBvaW50IGNvbG9ycwogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjBdCikKcHJpbnQocDMpICAjIERpc3BsYXkgaW4gbm90ZWJvb2sKZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJWb2xjYW5vUGxvdDMucG5nIiksIHBsb3QgPSBwMywgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCiMgRm91cnRoIFZvbGNhbm8gUGxvdCAtIE1vcmUgcmVmaW5lZCBmaWx0ZXJpbmcKcDQgPC0gRW5oYW5jZWRWb2xjYW5vKAogIGZpbHRlcmVkX2dlbmVzLCAKICBsYWIgPSBpZmVsc2UoZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDFlLTQgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjAsIGZpbHRlcmVkX2dlbmVzJGdlbmUsIE5BKSwKICB4ID0gImF2Z19sb2dGQyIsIAogIHkgPSAicF92YWxfYWRqIiwKICB0aXRsZSA9ICJNYWxpZ25hbnQgQ0Q0IFQgY2VsbHMgKGNlbGwgbGluZXMpIHZzIE5vcm1hbCBDRDQgVCBjZWxscyIsCiAgc3VidGl0bGUgPSAiSGlnaGxpZ2h0aW5nIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyIsCiAgcEN1dG9mZiA9IDFlLTQsCiAgRkNjdXRvZmYgPSAxLjAsCiAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogIGNvbEFscGhhID0gMC44LCAgIyBTbGlnaHQgdHJhbnNwYXJlbmN5IGZvciBub24tc2lnbmlmaWNhbnQgcG9pbnRzCiAgY29sID0gYygnZ3JleTcwJywgJ2JsYWNrJywgJ2JsdWUnLCAncmVkJyksICAjIEN1c3RvbSBjb2xvciBzY2hlbWUKICBncmlkbGluZXMubWFqb3IgPSBUUlVFLAogIGdyaWRsaW5lcy5taW5vciA9IEZBTFNFLAogIHNlbGVjdExhYiA9IGZpbHRlcmVkX2dlbmVzJGdlbmVbZmlsdGVyZWRfZ2VuZXMkcF92YWxfYWRqIDw9IDAuMDUgJiBhYnMoZmlsdGVyZWRfZ2VuZXMkYXZnX2xvZ0ZDKSA+PSAxLjBdCikKcHJpbnQocDQpICAjIERpc3BsYXkgaW4gbm90ZWJvb2sKZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKG91dHB1dF9kaXIsICJWb2xjYW5vUGxvdDQucG5nIiksIHBsb3QgPSBwNCwgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKCm1lc3NhZ2UoIkFsbCB2b2xjYW5vIHBsb3RzIGhhdmUgYmVlbiBkaXNwbGF5ZWQgYW5kIHNhdmVkIHN1Y2Nlc3NmdWxseSBpbiB0aGUgJ0wxX3ZzX0NvbnRyb2wnIGZvbGRlci4iKQoKCgpgYGAKCgojIDEwLiBFbnJpY2htZW50IEFuYWx5c2lzLTEKYGBge3IgLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuSHMuZWcuZGIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeShSZWFjdG9tZVBBKQpsaWJyYXJ5KERPU0UpICMgRm9yIEdTRUEgYW5hbHlzaXMKbGlicmFyeShnZ3Bsb3QyKSAjIEVuc3VyZSBnZ3Bsb3QyIGlzIGF2YWlsYWJsZSBmb3IgcGxvdHRpbmcKCiMgRGVmaW5lIHRocmVzaG9sZCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gc2VsZWN0aW9uIChtb2RpZmllZCB0aHJlc2hvbGRzKQpsb2dGQ191cF90aHJlc2hvbGQgPC0gMSAgICAgICAgICAjIFVwcmVndWxhdGVkIGxvZ0ZDIHRocmVzaG9sZApsb2dGQ19kb3duX3RocmVzaG9sZCA8LSAtMSAgICAgICAjIERvd25yZWd1bGF0ZWQgbG9nRkMgdGhyZXNob2xkCnB2YWxfdGhyZXNob2xkIDwtIDAuMDUgICMgcC12YWx1ZSB0aHJlc2hvbGQgYXMgc3BlY2lmaWVkCgojIExvYWQgeW91ciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiByZXN1bHRzIChtb2RpZnkgYmFzZWQgb24gYWN0dWFsIGRhdGEgc3RydWN0dXJlKQojIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxscyA8LSByZWFkLmNzdigiWW91cl9ERV9SZXN1bHRzX0ZpbGUuY3N2IikKCiMgU2VsZWN0IHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzCnVwcmVndWxhdGVkX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxsc1sKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDID4gbG9nRkNfdXBfdGhyZXNob2xkICYgCiAgTWFsaWduYW50X0NENFRjZWxsc192c19Ob3JtYWxfQ0Q0VGNlbGxzJHBfdmFsX2FkaiA8IHB2YWxfdGhyZXNob2xkLCBdCgpkb3ducmVndWxhdGVkX2dlbmVzIDwtIE1hbGlnbmFudF9DRDRUY2VsbHNfdnNfTm9ybWFsX0NENFRjZWxsc1sKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkYXZnX2xvZ0ZDIDwgbG9nRkNfZG93bl90aHJlc2hvbGQgJiAKICBNYWxpZ25hbnRfQ0Q0VGNlbGxzX3ZzX05vcm1hbF9DRDRUY2VsbHMkcF92YWxfYWRqIDwgcHZhbF90aHJlc2hvbGQsIF0KCiMgQ2hlY2sgZm9yIG1pc3NpbmcgZ2VuZXMgKE5BcykgaW4gdGhlIGdlbmUgY29sdW1uIGFuZCByZW1vdmUgdGhlbQp1cHJlZ3VsYXRlZF9nZW5lcyA8LSBuYS5vbWl0KHVwcmVndWxhdGVkX2dlbmVzKQpkb3ducmVndWxhdGVkX2dlbmVzIDwtIG5hLm9taXQoZG93bnJlZ3VsYXRlZF9nZW5lcykKCiMgU2F2ZSB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lIHJlc3VsdHMgdG8gQ1NWCndyaXRlLmNzdih1cHJlZ3VsYXRlZF9nZW5lcywgIk1hbGlnbmFudF92c19Db250cm9sL3VwcmVndWxhdGVkX2dlbmVzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQp3cml0ZS5jc3YoZG93bnJlZ3VsYXRlZF9nZW5lcywgIk1hbGlnbmFudF92c19Db250cm9sL2Rvd25yZWd1bGF0ZWRfZ2VuZXMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIENvbnZlcnQgZ2VuZSBzeW1ib2xzIHRvIEVudHJleiBJRHMgZm9yIGVucmljaG1lbnQgYW5hbHlzaXMsIHdpdGggY2hlY2tzIGZvciBtaXNzaW5nIHZhbHVlcwp1cHJlZ3VsYXRlZF9lbnRyZXogPC0gYml0cih1cHJlZ3VsYXRlZF9nZW5lcyRnZW5lLCBmcm9tVHlwZSA9ICJTWU1CT0wiLCB0b1R5cGUgPSAiRU5UUkVaSUQiLCBPcmdEYiA9IG9yZy5Icy5lZy5kYikKZG93bnJlZ3VsYXRlZF9lbnRyZXogPC0gYml0cihkb3ducmVndWxhdGVkX2dlbmVzJGdlbmUsIGZyb21UeXBlID0gIlNZTUJPTCIsIHRvVHlwZSA9ICJFTlRSRVpJRCIsIE9yZ0RiID0gb3JnLkhzLmVnLmRiKQoKIyBDaGVjayBmb3IgbWlzc2luZyBFbnRyZXogSURzCm1pc3NpbmdfdXByZWd1bGF0ZWQgPC0gdXByZWd1bGF0ZWRfZ2VuZXMkZ2VuZVtpcy5uYSh1cHJlZ3VsYXRlZF9lbnRyZXokRU5UUkVaSUQpXQptaXNzaW5nX2Rvd25yZWd1bGF0ZWQgPC0gZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lW2lzLm5hKGRvd25yZWd1bGF0ZWRfZW50cmV6JEVOVFJFWklEKV0KCiMgUHJpbnQgb3V0IHRoZSBtaXNzaW5nIGdlbmUgc3ltYm9scyBmb3IgZGVidWdnaW5nCmNhdCgiTWlzc2luZyB1cHJlZ3VsYXRlZCBnZW5lczpcbiIsIG1pc3NpbmdfdXByZWd1bGF0ZWQsICJcbiIpCmNhdCgiTWlzc2luZyBkb3ducmVndWxhdGVkIGdlbmVzOlxuIiwgbWlzc2luZ19kb3ducmVndWxhdGVkLCAiXG4iKQoKIyBSZW1vdmUgZ2VuZXMgdGhhdCBjb3VsZG4ndCBiZSBtYXBwZWQgdG8gRW50cmV6IElEcwp1cHJlZ3VsYXRlZF9lbnRyZXogPC0gdXByZWd1bGF0ZWRfZW50cmV6JEVOVFJFWklEWyFpcy5uYSh1cHJlZ3VsYXRlZF9lbnRyZXokRU5UUkVaSUQpXQpkb3ducmVndWxhdGVkX2VudHJleiA8LSBkb3ducmVndWxhdGVkX2VudHJleiRFTlRSRVpJRFshaXMubmEoZG93bnJlZ3VsYXRlZF9lbnRyZXokRU5UUkVaSUQpXQoKIyBEZWZpbmUgYSBmdW5jdGlvbiB0byBzYWZlbHkgcnVuIGVucmljaG1lbnQsIHBsb3QgcmVzdWx0cywgYW5kIHNhdmUgdGhlbQpzYWZlX2VucmljaEdPIDwtIGZ1bmN0aW9uKGdlbmVfbGlzdCwgdGl0bGUsIGZpbGVuYW1lKSB7CiAgaWYgKGxlbmd0aChnZW5lX2xpc3QpID4gMCkgewogICAgcmVzdWx0IDwtIGVucmljaEdPKGdlbmUgPSBnZW5lX2xpc3QsIE9yZ0RiID0gb3JnLkhzLmVnLmRiLCBrZXlUeXBlID0gIlNZTUJPTCIsCiAgICAgICAgICAgICAgICAgICAgICAgb250ID0gIkJQIiwgcEFkanVzdE1ldGhvZCA9ICJCSCIsIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgICBpZiAoIWlzLm51bGwocmVzdWx0KSAmJiBucm93KGFzLmRhdGEuZnJhbWUocmVzdWx0KSkgPiAwKSB7CiAgICAgIHAgPC0gZG90cGxvdChyZXN1bHQsIHNob3dDYXRlZ29yeSA9IDEwLCB0aXRsZSA9IHRpdGxlKQogICAgICBwcmludChwKSAgCiAgICAgIGdnc2F2ZShwYXN0ZTAoIk1hbGlnbmFudF92c19Db250cm9sLyIsIGdzdWIoIi5jc3YiLCAiX2RvdHBsb3QucG5nIiwgZmlsZW5hbWUpKSwgcGxvdCA9IHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKICAgICAgd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUocmVzdWx0KSwgZmlsZSA9IHBhc3RlMCgiTWFsaWduYW50X3ZzX0NvbnRyb2wvIiwgZmlsZW5hbWUpLCByb3cubmFtZXMgPSBGQUxTRSkKICAgIH0gZWxzZSB7CiAgICAgIG1lc3NhZ2UocGFzdGUoIk5vIHNpZ25pZmljYW50IGVucmljaG1lbnQgZm91bmQgZm9yOiIsIHRpdGxlKSkKICAgIH0KICB9IGVsc2UgewogICAgbWVzc2FnZShwYXN0ZSgiTm8gZ2VuZXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICB9Cn0KCnNhZmVfZW5yaWNoS0VHRyA8LSBmdW5jdGlvbihlbnRyZXpfbGlzdCwgdGl0bGUsIGZpbGVuYW1lKSB7CiAgaWYgKGxlbmd0aChlbnRyZXpfbGlzdCkgPiAwKSB7CiAgICByZXN1bHQgPC0gZW5yaWNoS0VHRyhnZW5lID0gZW50cmV6X2xpc3QsIG9yZ2FuaXNtID0gImhzYSIsIHB2YWx1ZUN1dG9mZiA9IDAuMDUpCiAgICBpZiAoIWlzLm51bGwocmVzdWx0KSAmJiBucm93KGFzLmRhdGEuZnJhbWUocmVzdWx0KSkgPiAwKSB7CiAgICAgIHAgPC0gZG90cGxvdChyZXN1bHQsIHNob3dDYXRlZ29yeSA9IDEwLCB0aXRsZSA9IHRpdGxlKQogICAgICBwcmludChwKQogICAgICBnZ3NhdmUocGFzdGUwKCJNYWxpZ25hbnRfdnNfQ29udHJvbC8iLCBnc3ViKCIuY3N2IiwgIl9kb3RwbG90LnBuZyIsIGZpbGVuYW1lKSksIHBsb3QgPSBwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCiAgICAgIHdyaXRlLmNzdihhcy5kYXRhLmZyYW1lKHJlc3VsdCksIGZpbGUgPSBwYXN0ZTAoIk1hbGlnbmFudF92c19Db250cm9sLyIsIGZpbGVuYW1lKSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgICB9IGVsc2UgewogICAgICBtZXNzYWdlKHBhc3RlKCJObyBzaWduaWZpY2FudCBLRUdHIHBhdGh3YXlzIGZvdW5kIGZvcjoiLCB0aXRsZSkpCiAgICB9CiAgfSBlbHNlIHsKICAgIG1lc3NhZ2UocGFzdGUoIk5vIGdlbmVzIGZvdW5kIGZvcjoiLCB0aXRsZSkpCiAgfQp9CgpzYWZlX2VucmljaFJlYWN0b21lIDwtIGZ1bmN0aW9uKGVudHJlel9saXN0LCB0aXRsZSwgZmlsZW5hbWUpIHsKICBpZiAobGVuZ3RoKGVudHJlel9saXN0KSA+IDApIHsKICAgIHJlc3VsdCA8LSBlbnJpY2hQYXRod2F5KGdlbmUgPSBlbnRyZXpfbGlzdCwgb3JnYW5pc20gPSAiaHVtYW4iLCBwdmFsdWVDdXRvZmYgPSAwLjA1KQogICAgaWYgKCFpcy5udWxsKHJlc3VsdCkgJiYgbnJvdyhhcy5kYXRhLmZyYW1lKHJlc3VsdCkpID4gMCkgewogICAgICBwIDwtIGRvdHBsb3QocmVzdWx0LCBzaG93Q2F0ZWdvcnkgPSAxMCwgdGl0bGUgPSB0aXRsZSkKICAgICAgcHJpbnQocCkKICAgICAgZ2dzYXZlKHBhc3RlMCgiTWFsaWduYW50X3ZzX0NvbnRyb2wvIiwgZ3N1YigiLmNzdiIsICJfZG90cGxvdC5wbmciLCBmaWxlbmFtZSkpLCBwbG90ID0gcCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQogICAgICB3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShyZXN1bHQpLCBmaWxlID0gcGFzdGUwKCJNYWxpZ25hbnRfdnNfQ29udHJvbC8iLCBmaWxlbmFtZSksIHJvdy5uYW1lcyA9IEZBTFNFKQogICAgfSBlbHNlIHsKICAgICAgbWVzc2FnZShwYXN0ZSgiTm8gc2lnbmlmaWNhbnQgUmVhY3RvbWUgcGF0aHdheXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICAgIH0KICB9IGVsc2UgewogICAgbWVzc2FnZShwYXN0ZSgiTm8gZ2VuZXMgZm91bmQgZm9yOiIsIHRpdGxlKSkKICB9Cn0KCiMgUGVyZm9ybSBlbnJpY2htZW50IGFuYWx5c2VzLCBnZW5lcmF0ZSBwbG90cywgYW5kIHNhdmUgcmVzdWx0cwpzYWZlX2VucmljaEdPKHVwcmVndWxhdGVkX2dlbmVzJGdlbmUsICJHTyBFbnJpY2htZW50IGZvciBVcHJlZ3VsYXRlZCBHZW5lcyIsICJ1cHJlZ3VsYXRlZF9HT19yZXN1bHRzLmNzdiIpCnNhZmVfZW5yaWNoR08oZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lLCAiR08gRW5yaWNobWVudCBmb3IgRG93bnJlZ3VsYXRlZCBHZW5lcyIsICJkb3ducmVndWxhdGVkX0dPX3Jlc3VsdHMuY3N2IikKCnNhZmVfZW5yaWNoS0VHRyh1cHJlZ3VsYXRlZF9lbnRyZXosICJLRUdHIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgVXByZWd1bGF0ZWQgR2VuZXMiLCAidXByZWd1bGF0ZWRfS0VHR19yZXN1bHRzLmNzdiIpCnNhZmVfZW5yaWNoS0VHRyhkb3ducmVndWxhdGVkX2VudHJleiwgIktFR0cgUGF0aHdheSBFbnJpY2htZW50IGZvciBEb3ducmVndWxhdGVkIEdlbmVzIiwgImRvd25yZWd1bGF0ZWRfS0VHR19yZXN1bHRzLmNzdiIpCgpzYWZlX2VucmljaFJlYWN0b21lKHVwcmVndWxhdGVkX2VudHJleiwgIlJlYWN0b21lIFBhdGh3YXkgRW5yaWNobWVudCBmb3IgVXByZWd1bGF0ZWQgR2VuZXMiLCAidXByZWd1bGF0ZWRfUmVhY3RvbWVfcmVzdWx0cy5jc3YiKQpzYWZlX2VucmljaFJlYWN0b21lKGRvd25yZWd1bGF0ZWRfZW50cmV6LCAiUmVhY3RvbWUgUGF0aHdheSBFbnJpY2htZW50IGZvciBEb3ducmVndWxhdGVkIEdlbmVzIiwgImRvd25yZWd1bGF0ZWRfUmVhY3RvbWVfcmVzdWx0cy5jc3YiKQoKCmBgYAoKCgoKIyMgRW5yaWNobWVudCBBbmFseXNpcy0yLUhhbGxtYXJrCmBgYHtyICwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKbGlicmFyeShtc2lnZGJyKQpsaWJyYXJ5KGVucmljaHBsb3QpCgojIExvYWQgSGFsbG1hcmsgZ2VuZSBzZXRzIGZyb20gbXNpZ2RicgpoYWxsbWFya19zZXRzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikgICMgIkgiIGlzIGZvciBIYWxsbWFyayBnZW5lIHNldHMKCiMgQ29udmVydCBnZW5lIHN5bWJvbHMgdG8gdXBwZXJjYXNlIGZvciBjb25zaXN0ZW5jeQp1cHJlZ3VsYXRlZF9nZW5lcyRnZW5lIDwtIHRvdXBwZXIodXByZWd1bGF0ZWRfZ2VuZXMkZ2VuZSkKZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lIDwtIHRvdXBwZXIoZG93bnJlZ3VsYXRlZF9nZW5lcyRnZW5lKQoKIyBDaGVjayBmb3Igb3ZlcmxhcCBiZXR3ZWVuIHlvdXIgdXByZWd1bGF0ZWQvZG93bnJlZ3VsYXRlZCBnZW5lcyBhbmQgSGFsbG1hcmsgZ2VuZSBzZXRzCnVwcmVndWxhdGVkX2luX2hhbGxtYXJrIDwtIGludGVyc2VjdCh1cHJlZ3VsYXRlZF9nZW5lcyRnZW5lLCBoYWxsbWFya19zZXRzJGdlbmVfc3ltYm9sKQpkb3ducmVndWxhdGVkX2luX2hhbGxtYXJrIDwtIGludGVyc2VjdChkb3ducmVndWxhdGVkX2dlbmVzJGdlbmUsIGhhbGxtYXJrX3NldHMkZ2VuZV9zeW1ib2wpCgojIFByaW50IHRoZSBudW1iZXIgb2Ygb3ZlcmxhcHBpbmcgZ2VuZXMgZm9yIGJvdGggdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKY2F0KCJOdW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXMgaW4gSGFsbG1hcmsgZ2VuZSBzZXRzOiIsIGxlbmd0aCh1cHJlZ3VsYXRlZF9pbl9oYWxsbWFyayksICJcbiIpCmNhdCgiTnVtYmVyIG9mIGRvd25yZWd1bGF0ZWQgZ2VuZXMgaW4gSGFsbG1hcmsgZ2VuZSBzZXRzOiIsIGxlbmd0aChkb3ducmVndWxhdGVkX2luX2hhbGxtYXJrKSwgIlxuIikKCiMgRGVmaW5lIHRoZSBvdXRwdXQgZm9sZGVyIHdoZXJlIHRoZSByZXN1bHRzIHdpbGwgYmUgc2F2ZWQKb3V0cHV0X2ZvbGRlciA8LSAiTWFsaWduYW50X3ZzX0NvbnRyb2wvIgoKIyBJZiB0aGVyZSBhcmUgZ2VuZXMgdG8gYW5hbHl6ZSwgcHJvY2VlZCB3aXRoIGVucmljaG1lbnQgYW5hbHlzaXMKaWYgKGxlbmd0aCh1cHJlZ3VsYXRlZF9pbl9oYWxsbWFyaykgPiAwKSB7CiAgIyBQZXJmb3JtIGVucmljaG1lbnQgYW5hbHlzaXMgZm9yIHVwcmVndWxhdGVkIGdlbmVzIHVzaW5nIEhhbGxtYXJrIGdlbmUgc2V0cwogIGhhbGxtYXJrX3VwIDwtIGVucmljaGVyKGdlbmUgPSB1cHJlZ3VsYXRlZF9pbl9oYWxsbWFyaywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgVEVSTTJHRU5FID0gaGFsbG1hcmtfc2V0c1ssIGMoImdzX25hbWUiLCAiZ2VuZV9zeW1ib2wiKV0sICAjIEVuc3VyZSBURVJNMkdFTkUgdXNlcyBjb3JyZWN0IGNvbHVtbnMKICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgPSAwLjA1KQogICMgQ2hlY2sgaWYgcmVzdWx0cyBleGlzdAogIGlmICghaXMubnVsbChoYWxsbWFya191cCkgJiYgbnJvdyhoYWxsbWFya191cCkgPiAwKSB7CiAgICAjIFZpc3VhbGl6ZSByZXN1bHRzIGlmIGF2YWlsYWJsZQogICAgdXBfZG90cGxvdCA8LSBkb3RwbG90KGhhbGxtYXJrX3VwLCBzaG93Q2F0ZWdvcnkgPSAyMCwgdGl0bGUgPSAiSGFsbG1hcmsgUGF0aHdheSBFbnJpY2htZW50IGZvciBVcHJlZ3VsYXRlZCBHZW5lcyIpCiAgICAKICAgICMgRGlzcGxheSB0aGUgcGxvdCBpbiB0aGUgbm90ZWJvb2sKICAgIHByaW50KHVwX2RvdHBsb3QpCiAgICAKICAgICMgU2F2ZSB0aGUgZG90cGxvdCB0byBhIFBORyBmaWxlCiAgICBnZ3NhdmUocGFzdGUwKG91dHB1dF9mb2xkZXIsICJoYWxsbWFya191cHJlZ3VsYXRlZF9kb3RwbG90LnBuZyIpLCBwbG90ID0gdXBfZG90cGxvdCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCkKICAgIAogICAgIyBPcHRpb25hbGx5LCBzYXZlIHRoZSByZXN1bHRzIGFzIENTVgogICAgd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUoaGFsbG1hcmtfdXApLCBmaWxlID0gcGFzdGUwKG91dHB1dF9mb2xkZXIsICJoYWxsbWFya191cHJlZ3VsYXRlZF9lbnJpY2htZW50LmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSkKICB9IGVsc2UgewogICAgY2F0KCJObyBzaWduaWZpY2FudCBlbnJpY2htZW50IGZvdW5kIGZvciB1cHJlZ3VsYXRlZCBnZW5lcy5cbiIpCiAgfQp9IGVsc2UgewogIGNhdCgiTm8gdXByZWd1bGF0ZWQgZ2VuZXMgb3ZlcmxhcCB3aXRoIEhhbGxtYXJrIGdlbmUgc2V0cy5cbiIpCn0KCmlmIChsZW5ndGgoZG93bnJlZ3VsYXRlZF9pbl9oYWxsbWFyaykgPiAwKSB7CiAgIyBQZXJmb3JtIGVucmljaG1lbnQgYW5hbHlzaXMgZm9yIGRvd25yZWd1bGF0ZWQgZ2VuZXMgdXNpbmcgSGFsbG1hcmsgZ2VuZSBzZXRzCiAgaGFsbG1hcmtfZG93biA8LSBlbnJpY2hlcihnZW5lID0gZG93bnJlZ3VsYXRlZF9pbl9oYWxsbWFyaywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURVJNMkdFTkUgPSBoYWxsbWFya19zZXRzWywgYygiZ3NfbmFtZSIsICJnZW5lX3N5bWJvbCIpXSwgICMgRW5zdXJlIFRFUk0yR0VORSB1c2VzIGNvcnJlY3QgY29sdW1ucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSkKICAjIENoZWNrIGlmIHJlc3VsdHMgZXhpc3QKICBpZiAoIWlzLm51bGwoaGFsbG1hcmtfZG93bikgJiYgbnJvdyhoYWxsbWFya19kb3duKSA+IDApIHsKICAgICMgVmlzdWFsaXplIHJlc3VsdHMgaWYgYXZhaWxhYmxlCiAgICBkb3duX2RvdHBsb3QgPC0gZG90cGxvdChoYWxsbWFya19kb3duLCBzaG93Q2F0ZWdvcnkgPSAyMCwgdGl0bGUgPSAiSGFsbG1hcmsgUGF0aHdheSBFbnJpY2htZW50IGZvciBEb3ducmVndWxhdGVkIEdlbmVzIikKICAgIAogICAgIyBEaXNwbGF5IHRoZSBwbG90IGluIHRoZSBub3RlYm9vawogICAgcHJpbnQoZG93bl9kb3RwbG90KQogICAgCiAgICAjIFNhdmUgdGhlIGRvdHBsb3QgdG8gYSBQTkcgZmlsZQogICAgZ2dzYXZlKHBhc3RlMChvdXRwdXRfZm9sZGVyLCAiaGFsbG1hcmtfZG93bnJlZ3VsYXRlZF9kb3RwbG90LnBuZyIpLCBwbG90ID0gZG93bl9kb3RwbG90LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQogICAgCiAgICAjIE9wdGlvbmFsbHksIHNhdmUgdGhlIHJlc3VsdHMgYXMgQ1NWCiAgICB3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShoYWxsbWFya19kb3duKSwgZmlsZSA9IHBhc3RlMChvdXRwdXRfZm9sZGVyLCAiaGFsbG1hcmtfZG93bnJlZ3VsYXRlZF9lbnJpY2htZW50LmNzdiIpLCByb3cubmFtZXMgPSBGQUxTRSkKICB9IGVsc2UgewogICAgY2F0KCJObyBzaWduaWZpY2FudCBlbnJpY2htZW50IGZvdW5kIGZvciBkb3ducmVndWxhdGVkIGdlbmVzLlxuIikKICB9Cn0gZWxzZSB7CiAgY2F0KCJObyBkb3ducmVndWxhdGVkIGdlbmVzIG92ZXJsYXAgd2l0aCBIYWxsbWFyayBnZW5lIHNldHMuXG4iKQp9CgoKYGBgCgoKCgoKCgo=