# Load count matrix and metadata
counts_D1 <- read.delim("counts_D1", header = TRUE, row.names = 1)
metadata_D1 <- read.csv("metadata_D1.csv", header = TRUE)
# Check distribution of counts
total_counts_per_gene_D1 <- rowSums(counts_D1)
hist(total_counts_per_gene_D1, 
     breaks=100, 
     main="Distribution of Total Counts per Gene", 
     xlab="Total counts across all samples",
     ylab="Number of genes")
summary(total_counts_per_gene_D1)

# Filter low expressed genes
counts_D1 <- counts_D1[which(rowSums(counts_D1) > 50), ]

# Round counts for DESeq2
counts_D1 <- round(counts_D1)
# Create DESeq2 object
library(DESeq2)
dds_D1 <- DESeqDataSetFromMatrix(countData = counts_D1,
                                colData = metadata_D1,        
                                design = ~Treatment)

dds_D1

# Run DESeq2 analysis
dds_D1 <- DESeq(dds_D1)

# Variance stabilizing transformation
vsdata_D1 <- vst(dds_D1, blind = TRUE)

summary(dds_D1)
#Get VST matrix (genes as rows, samples as columns)
vst_matrix_D1 <- assay(vst(dds_D1, blind = TRUE))
head(vst_matrix_D1)

library(reshape2)
vst_df_D1 <- as.data.frame(vst_matrix_D1)
vst_df_D1$gene_id <- rownames(vst_df_D1)

vst_final_D1 <- melt(vst_df_D1, 
                 id.vars = "gene_id", 
                 variable.name = "sample_id", 
                 value.name = "expression_value")

head(vst_final_D1)
nrow(vst_final_D1)
# Enhanced PCA plot
library(ggplot2)
library(pheatmap)
pca_plot_D1 <- plotPCA(vsdata_D1, intgroup = "Treatment") +
  theme_minimal() +
  labs(title = "PCA - Osimertinib 6w vs Untreated",
       subtitle = paste("n =", ncol(counts_D1), "samples")) +
  theme(plot.title = element_text(hjust = 0.5, size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 12))
pca_plot_D1

#saving PCA plot in pdf & png 
ggsave(("D1_PCA.pdf"), pca_plot_D1, width = 6, height = 5)
ggsave(("D1_PCA.png"), pca_plot_D1, width = 6, height = 5, dpi = 300)

# Sample distance heatmap
sample_distances_D1 <- dist(t(assay(vsdata_D1)))
sampleDistMatrix_D1 <- as.matrix(sample_distances_D1)
pheatmap::pheatmap(sampleDistMatrix_D1,
         clustering_distance_rows = sample_distances_D1,
         clustering_distance_cols = sample_distances_D1,
         main = "Sample-to-Sample Distances",
         filename = "SampleDistances_D1.png")
# Dispersion plot
plotDispEsts(dds_D1)

# Save as PDF
pdf("DispersionPlot_D1.pdf", width = 6, height = 5)
plotDispEsts(dds_D1)
dev.off()

# Or save as high-resolution PNG
png("DispersionPlot_D1.png", width = 2000, height = 1600, res = 300)
plotDispEsts(dds_D1)
dev.off()
# Get results with contrast
resultsNames(dds_D1)
res_D1 <- results(dds_D1, contrast = c("Treatment", "Osimertinib 6w", "Untreated"))
summary(res_D1)

# Apply LFC shrinkage
library(apeglm)
res_shrunk_D1 <- lfcShrink(dds_D1, coef=2, type="apeglm")

# Add gene annotations (ENSEMBL to SYMBOL)
library(dplyr)
library(AnnotationDbi)
library(org.Hs.eg.db)
gene_symbols_D1 <- mapIds(org.Hs.eg.db,
                      keys = rownames(res_shrunk_D1),
                      column = "SYMBOL",
                      keytype = "ENSEMBL",
                      multiVals = "first")

res_D1_annotated <- res_D1
res_D1_annotated$gene_symbol <- gene_symbols_D1  


as.data.frame(res_D1_annotated)

res_shrunk_annotated_D1 <- res_shrunk_D1
res_shrunk_annotated_D1$gene_symbol_D1 <- gene_symbols_D1

# Define significant genes
sig_overall_D1 <- res_shrunk_D1[which(res_shrunk_D1$padj < 0.05 & 
                                     abs(res_shrunk_D1$log2FoldChange) > 1), ]
head(sig_overall_D1)
# Separate up and down regulated genes
sig_genes_up_D1 <- rownames(res_shrunk_D1)[res_shrunk_D1$log2FoldChange > 1 & 
                                        res_shrunk_D1$padj < 0.05 & 
                                        !is.na(res_shrunk_D1$padj)]
# Extract gene symbols for your significant upregulated genes
gene_symbols_sig_up_D1 <- res_D1_annotated[sig_genes_up_D1, "gene_symbol"]

# Create a data frame with both gene IDs and symbols
sig_genes_up_D1_annotated <- data.frame(
  gene_id = sig_genes_up_D1,
  gene_symbol = gene_symbols_sig_up_D1
)
head(sig_genes_up_D1)
sig_genes_down_D1 <- rownames(res_shrunk_D1)[res_shrunk_D1$log2FoldChange < -1 & 
                                         res_shrunk_D1$padj < 0.05 & 
                                         !is.na(res_shrunk_D1$padj)]

print(paste("Significant DEGs:", nrow(sig_overall_D1)))
print(paste("Upregulated:", length(sig_genes_up_D1)))
print(paste("Downregulated:", length(sig_genes_down_D1)))
# MA Plot
plotMA(res_shrunk_D1, ylim=c(-5,5), main="Osimertinib vs Untreated")

pdf(("D1_MAplot.pdf"), width = 6, height = 5)
plotMA(res_shrunk_D1, ylim=c(-5,5), main="Osimertinib vs Untreated")
dev.off()

png(("D1_MAplot.png"), width = 2000, height = 1600, res = 300)
plotMA(res_shrunk_D1, ylim=c(-5,5), main="Osimertinib vs Untreated")
dev.off()

library(tibble)  # for rownames_to_column

# Select top 20 most significant genes for labeling
top_genes_data <- res_shrunk_annotated_D1 %>%
  as.data.frame() %>%
  rownames_to_column("gene_id") %>%
  filter(!is.na(padj) & !is.na(gene_symbol_D1)) %>%
  arrange(padj) %>%
  head(20)

top_gene_symbols_D1 <- top_genes_data$gene_symbol_D1

# Clean volcano plot
library(EnhancedVolcano)

volcano_plot_D1 <- EnhancedVolcano(res_shrunk_annotated_D1,
                lab = res_shrunk_annotated_D1$gene_symbol_D1,
                selectLab = top_gene_symbols_D1,
                x = 'log2FoldChange',
                y = 'padj',
                title = 'Osimertinib 6w vs Untreated',
                subtitle = paste('DEGs:', length(sig_genes_up_D1), 'up,', length(sig_genes_down_D1), 'down'),
                pCutoff = 0.05,
                FCcutoff = 1,
                pointSize = 1.5,
                labSize = 3.5,
                drawConnectors = TRUE,
                xlim = c(-6, 6))

volcano_plot_D1

ggsave(("D1_Volcano.pdf"), volcano_plot_D1, width = 6, height = 5)
ggsave(("D1_Volcano.png"), volcano_plot_D1, width = 6, height = 5, dpi = 300)

# Heatmap of top 50 significant genes
library(pheatmap)
top50_genes_D1 <- head(order(res_shrunk_annotated_D1$padj), 50)
png("Top50_Heatmap_D1.png", width = 2000, height = 1600, res = 300)
pheatmap::pheatmap(assay(vsdata_D1)[top50_genes_D1,], 
         annotation_col = as.data.frame(colData(dds_D1)[,"Treatment", drop=FALSE]), 
         scale = "row", 
         show_rownames = FALSE,
         main = "Top 50 Significant Genes",
         cluster_cols = TRUE)
dev.off()
library(ComplexHeatmap)
library(RColorBrewer)
library(circlize)
library(dplyr)

# First, prepare top genes for heatmap
top_genes_heatmap_D1 <- res_shrunk_annotated_D1[!is.na(res_shrunk_annotated_D1$padj) & 
                                          res_shrunk_annotated_D1$padj < 0.05 & 
                                          res_shrunk_annotated_D1$baseMean > 50 & 
                                          abs(res_shrunk_annotated_D1$log2FoldChange) > 2,]

top_genes_heatmap_D1 <- head(as.data.frame(top_genes_heatmap_D1), 100)  # More genes for 115 samples
top_genes_heatmap_D1 <- top_genes_heatmap_D1[order(top_genes_heatmap_D1$log2FoldChange, decreasing = TRUE),]

# Get normalized count data from vst
mat_D1 <- assay(vsdata_D1)[rownames(top_genes_heatmap_D1), ]
mat_scaled_D1 <- t(apply(mat_D1, 1, scale))
colnames(mat_scaled_D1) <- colnames(mat_D1)

# Select top and bottom genes (increase for 115 samples)
num_keep <- 40  # Show more genes with 115 samples
rows_keep_D1 <- c(seq(1:num_keep), seq((nrow(mat_scaled_D1) - num_keep + 1), nrow(mat_scaled_D1)))

# Prepare annotation matrices
l2_val_D1 <- as.matrix(top_genes_heatmap_D1[rows_keep_D1,]$log2FoldChange)
colnames(l2_val_D1) <- "logFC"

mean_D1 <- as.matrix(top_genes_heatmap_D1[rows_keep_D1,]$baseMean)
colnames(mean_D1) <- "AveExpr"

# Set up color schemes
col_logFC_D1 <- colorRamp2(c(min(l2_val_D1), 0, max(l2_val_D1)), c("blue", "white", "red"))
col_AveExpr_D1 <- colorRamp2(c(quantile(mean_D1)[1], quantile(mean_D1)[4]), c("white", "red"))
col_zscore_D1 <- colorRamp2(c(-2, 0, 2), c("#4575b4", "white", "#d73027"))

# Add sample annotation for 115 samples
sample_annotation <- HeatmapAnnotation(
  Treatment = metadata_D1$Treatment,  # Assuming your metadata has treatment column
  col = list(Treatment = c("Untreated" = "gray", "Osimertinib 6w" = "darkgreen"))
)

# Main expression heatmap - adjusted for 115 samples
h1_D1 <- Heatmap(
  mat_scaled_D1[rows_keep_D1,], 
  cluster_rows = TRUE,
  cluster_columns = TRUE,               # keep clustering to see subgroups
  column_split = metadata_D1$Treatment, # enforce 2 main blocks (Untreated / Osimertinib 6w)
  top_annotation = sample_annotation,
  show_row_names = FALSE,
  show_column_names = FALSE,
  column_names_gp = gpar(fontsize = 6),
  column_title = "115 Samples",
  heatmap_legend_param = list(title_gp = gpar(fontsize = 10)),
  col = col_zscore_D1,
  name = "Z-score"
)

# LogFC heatmap
h2_D1 <- Heatmap(l2_val_D1, 
                 row_labels = top_genes_heatmap_D1$gene_symbol[rows_keep_D1],
                 cluster_rows = FALSE, 
                 name = "logFC", 
                 col = col_logFC_D1,
                 width = unit(15, "mm"),
                 row_names_gp = gpar(fontsize = 6),  # Smaller font for many genes
                 cell_fun = function(j, i, x, y, w, h, col) { 
                   grid.text(round(l2_val_D1[i, j], 1), x, y, gp = gpar(fontsize = 5))
                 })

# Average expression heatmap
h3_D1 <- Heatmap(mean_D1, 
                 row_labels = top_genes_heatmap_D1$gene_symbol[rows_keep_D1],
                 cluster_rows = FALSE, 
                 name = "AveExpr", 
                 col = col_AveExpr_D1,
                 width = unit(15, "mm"),
                 row_names_gp = gpar(fontsize = 6),
                 cell_fun = function(j, i, x, y, w, h, col) { 
                   grid.text(round(mean_D1[i, j], 0), x, y, gp = gpar(fontsize = 5))
                 })

# Combine heatmaps
h_D1 <- h1_D1 + h2_D1 + h3_D1
h_D1

pdf("AnnotatedHeatmap_D1.pdf", width = 10, height = 6)
draw(h_D1)
dev.off()

png("AnnotatedHeatmap_D1.png", width = 3000, height = 2000, res = 300)
draw(h_D1)
dev.off()
# Convert ENSEMBL to ENTREZ for KEGG analysis
library(DOSE)
library(enrichplot)

library(clusterProfiler)
entrez_genes_up_D1 <- mapIds(org.Hs.eg.db, sig_genes_up_D1, "ENTREZID", "ENSEMBL")
entrez_genes_down_D1 <- mapIds(org.Hs.eg.db, sig_genes_down_D1, "ENTREZID", "ENSEMBL")
entrez_genes_up_D1 <- entrez_genes_up_D1[!is.na(entrez_genes_up_D1)]
entrez_genes_down_D1 <- entrez_genes_down_D1[!is.na(entrez_genes_down_D1)]

# GO Analysis

go_up_D1 <- enrichGO(gene = sig_genes_up_D1,
                    OrgDb = org.Hs.eg.db,
                    keyType = "ENSEMBL",
                    ont = "ALL",  # BP, CC, MF
                    pAdjustMethod = "BH",
                    pvalueCutoff = 0.05)
top_go_up_D1 <- go_up_D1@result[1:10, ]
as.data.frame(top_go_up_D1)

go_down_D1 <- enrichGO(gene = sig_genes_down_D1,
                      OrgDb = org.Hs.eg.db,
                      keyType = "ENSEMBL",
                      ont = "ALL",
                      pAdjustMethod = "BH",
                      pvalueCutoff = 0.05)
top_go_down_D1 <- go_down_D1@result[1:10, ]
as.data.frame(top_go_down_D1)

# KEGG Pathway Analysis
kegg_up_D1 <- enrichKEGG(gene = entrez_genes_up_D1,
                         organism = 'hsa',
                         pvalueCutoff = 0.05,
                         pAdjustMethod = "BH")
as.data.frame(kegg_up_D1)
top_kegg_up_D1 <- kegg_up_D1@result[1:10, ]
as.data.frame(top_kegg_up_D1)

kegg_down_D1 <- enrichKEGG(gene = entrez_genes_down_D1,
                           organism = 'hsa',
                           pvalueCutoff = 0.05,
                           pAdjustMethod = "BH")
as.data.frame(kegg_down_D1)
top_kegg_down_D1 <- kegg_down_D1@result[1:10,]
as.data.frame(top_kegg_down_D1)

# Visualize pathway results
if(nrow(go_up_D1@result) > 0) {
  p1 <- barplot(go_up_D1, split="ONTOLOGY", showCategory = 8) + 
    facet_grid(ONTOLOGY~., scale="free") +
    labs(title = "Upregulated GO Terms")
  print(p1)
  ggsave("GO_Upregulated_D1.pdf", p1, width = 7, height = 6)
  ggsave("GO_Upregulated_D1.png", p1, width = 7, height = 6, dpi = 300)
}

if(nrow(go_down_D1@result) > 0) {
  p2 <- barplot(go_down_D1, split="ONTOLOGY", showCategory = 8) + 
    facet_grid(ONTOLOGY~., scale="free") +
    labs(title = "Downregulated GO Terms")
  print(p1)
  ggsave("GO_Downregulated_D1.pdf", p2, width = 7, height = 6)
  ggsave("GO_Downregulated_D1.png", p2, width = 7, height = 6, dpi = 300)
}


if(nrow(kegg_up_D1@result) > 0) {
  p3 <- dotplot(kegg_up_D1, showCategory = 15, title = "Upregulated KEGG Pathways")
  print(p2)
  ggsave("KEGG_Upregulated_D1.pdf", p3, width = 7, height = 6)
  ggsave("KEGG_Upregulated_D1.png", p3, width = 7, height = 6, dpi = 300)
}

if(nrow(kegg_down_D1@result) > 0) {
  p4 <- dotplot(kegg_down_D1, showCategory = 15, title = "Downregulated KEGG Pathways")
  print(p3)
  ggsave("KEGG_Downregulated_D1.pdf", p4, width = 7, height = 6)
  ggsave("KEGG_Downregulated_D1.png", p4, width = 7, height = 6, dpi = 300)
}
# Prepare ranked gene list
library(fgsea)
library(msigdbr)
gene_ranks_D1 <- res_shrunk_D1$log2FoldChange
names(gene_ranks_D1) <- rownames(res_shrunk_D1)
gene_ranks_D1 <- gene_ranks_D1[!is.na(gene_ranks_D1)]
gene_ranks_D1 <- sort(gene_ranks_D1, decreasing = TRUE)

# Get Hallmark pathways
hallmark_sets_D1 <- msigdbr(species = "Homo sapiens", category = "H")
hallmark_list_D1 <- split(hallmark_sets_D1$ensembl_gene, hallmark_sets_D1$gs_name)

# Run GSEA
fgsea_results_D1 <- fgsea(pathways = hallmark_list_D1,
                         stats = gene_ranks_D1,
                         minSize = 15,
                         maxSize = 500,
                         nperm = 1000)

#plotting top 3 pathways
print("Top 3 GSEA pathways:")
top_pathways_D1 <- head(fgsea_results_D1[order(pval), ], 3)
print(top_pathways_D1[, c("pathway", "pval", "NES")])

for(i in 1:3) {
  pathway_names_D1 <- top_pathways_D1$pathway[i]
  p <- plotEnrichment(hallmark_list_D1[[pathway_names_D1]], gene_ranks_D1) + 
    labs(title = paste("Pathway", i, ":", pathway_names_D1))
  print(p)
  ggsave("Top3_GSEA_D1.pdf", p, width = 7, height = 6)
  ggsave("Top3_GSEA_D1.png", p, width = 7, height = 6, dpi = 300)
}

head(fgsea_results_D1[order(pval), ], 10)
# Summary statistics table
summary_stats_D1 <- data.frame(
  Metric = c("Total Samples", "Osimertinib Treated", "Untreated", 
            "Genes Analyzed", "Significant DEGs", "Upregulated", "Downregulated"),
  Value = c(ncol(counts_D1), 
           sum(metadata_D1$Treatment == "Osimertinib 6w"),
           sum(metadata_D1$Treatment == "Untreated"),
           nrow(res_shrunk_D1),
           nrow(sig_overall_D1),
           length(sig_genes_up_D1),
           length(sig_genes_down_D1))
)

print("Analysis Summary:")
print(summary_stats_D1)

# Top genes table
top_genes_table_D1 <- data.frame(
  Gene_Symbol = gene_symbols_D1[rownames(head(sig_overall_D1[order(sig_overall_D1$padj),], 20))],
  ENSEMBL_ID = rownames(head(sig_overall_D1[order(sig_overall_D1$padj),], 20)),
  Log2FC = round(head(sig_overall_D1[order(sig_overall_D1$padj),], 20)$log2FoldChange, 3),
  Padj = format(head(sig_overall_D1[order(sig_overall_D1$padj),], 20)$padj, scientific = TRUE, digits = 3),
  Direction = ifelse(head(sig_overall_D1[order(sig_overall_D1$padj),], 20)$log2FoldChange > 0, "Up", "Down")
)

print("Top 20 Significant Genes:")
print(top_genes_table_D1)
# Export main results
write.csv(as.data.frame(res_shrunk_annotated_D1), "D1_annotated_results.csv", row.names = TRUE)
write.csv(sig_overall_D1, "D1_significant_genes.csv", row.names = TRUE)
write.csv(summary_stats_D1, "D1_summary_statistics.csv", row.names = FALSE)
write.csv(top_genes_table_D1, "D1_top_genes.csv", row.names = FALSE)

# Export normalized data
write.csv(res_D1_annotated, "D1_results.csv")
write.csv(counts(dds_D1, normalized=TRUE), "D1_normalized_counts.csv", row.names = TRUE)
write.csv(vst_final_D1, "D1_vst_data.csv", row.names = TRUE)

# Export pathway results
if(nrow(go_up_D1@result) > 0) {
  write.csv(go_up_D1@result, "D1_GO_upregulated.csv", row.names = FALSE)
}
if(nrow(go_down_D1@result) > 0) {
  write.csv(go_down_D1@result, "D1_GO_downregulated.csv", row.names = FALSE)
}
if(nrow(kegg_up_D1@result) > 0) {
  write.csv(kegg_up_D1@result, "D1_KEGG_upregulated.csv", row.names = FALSE)
}
if(nrow(kegg_down_D1@result) > 0) {
  write.csv(kegg_down_D1@result, "D1_KEGG_downregulated.csv", row.names = FALSE)
}

# Remove the leadingEdge column (which contains lists)
fgsea_results_clean <- fgsea_results_D1 %>%
  select(-leadingEdge)

write.csv(fgsea_results_clean, "D1_GSEA_hallmarks.csv", row.names = FALSE)
LS0tDQp0aXRsZTogIkRhdGFzZXQgMSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyfQ0KIyBMb2FkIGNvdW50IG1hdHJpeCBhbmQgbWV0YWRhdGENCmNvdW50c19EMSA8LSByZWFkLmRlbGltKCJjb3VudHNfRDEiLCBoZWFkZXIgPSBUUlVFLCByb3cubmFtZXMgPSAxKQ0KbWV0YWRhdGFfRDEgPC0gcmVhZC5jc3YoIm1ldGFkYXRhX0QxLmNzdiIsIGhlYWRlciA9IFRSVUUpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBDaGVjayBkaXN0cmlidXRpb24gb2YgY291bnRzDQp0b3RhbF9jb3VudHNfcGVyX2dlbmVfRDEgPC0gcm93U3Vtcyhjb3VudHNfRDEpDQpoaXN0KHRvdGFsX2NvdW50c19wZXJfZ2VuZV9EMSwgDQogICAgIGJyZWFrcz0xMDAsIA0KICAgICBtYWluPSJEaXN0cmlidXRpb24gb2YgVG90YWwgQ291bnRzIHBlciBHZW5lIiwgDQogICAgIHhsYWI9IlRvdGFsIGNvdW50cyBhY3Jvc3MgYWxsIHNhbXBsZXMiLA0KICAgICB5bGFiPSJOdW1iZXIgb2YgZ2VuZXMiKQ0Kc3VtbWFyeSh0b3RhbF9jb3VudHNfcGVyX2dlbmVfRDEpDQoNCiMgRmlsdGVyIGxvdyBleHByZXNzZWQgZ2VuZXMNCmNvdW50c19EMSA8LSBjb3VudHNfRDFbd2hpY2gocm93U3Vtcyhjb3VudHNfRDEpID4gNTApLCBdDQoNCiMgUm91bmQgY291bnRzIGZvciBERVNlcTINCmNvdW50c19EMSA8LSByb3VuZChjb3VudHNfRDEpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBDcmVhdGUgREVTZXEyIG9iamVjdA0KbGlicmFyeShERVNlcTIpDQpkZHNfRDEgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHNfRDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBtZXRhZGF0YV9EMSwgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+VHJlYXRtZW50KQ0KDQpkZHNfRDENCg0KIyBSdW4gREVTZXEyIGFuYWx5c2lzDQpkZHNfRDEgPC0gREVTZXEoZGRzX0QxKQ0KDQojIFZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uDQp2c2RhdGFfRDEgPC0gdnN0KGRkc19EMSwgYmxpbmQgPSBUUlVFKQ0KDQpzdW1tYXJ5KGRkc19EMSkNCiNHZXQgVlNUIG1hdHJpeCAoZ2VuZXMgYXMgcm93cywgc2FtcGxlcyBhcyBjb2x1bW5zKQ0KdnN0X21hdHJpeF9EMSA8LSBhc3NheSh2c3QoZGRzX0QxLCBibGluZCA9IFRSVUUpKQ0KaGVhZCh2c3RfbWF0cml4X0QxKQ0KDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KdnN0X2RmX0QxIDwtIGFzLmRhdGEuZnJhbWUodnN0X21hdHJpeF9EMSkNCnZzdF9kZl9EMSRnZW5lX2lkIDwtIHJvd25hbWVzKHZzdF9kZl9EMSkNCg0KdnN0X2ZpbmFsX0QxIDwtIG1lbHQodnN0X2RmX0QxLCANCiAgICAgICAgICAgICAgICAgaWQudmFycyA9ICJnZW5lX2lkIiwgDQogICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlX2lkIiwgDQogICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiZXhwcmVzc2lvbl92YWx1ZSIpDQoNCmhlYWQodnN0X2ZpbmFsX0QxKQ0KbnJvdyh2c3RfZmluYWxfRDEpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBFbmhhbmNlZCBQQ0EgcGxvdA0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwaGVhdG1hcCkNCnBjYV9wbG90X0QxIDwtIHBsb3RQQ0EodnNkYXRhX0QxLCBpbnRncm91cCA9ICJUcmVhdG1lbnQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiUENBIC0gT3NpbWVydGluaWIgNncgdnMgVW50cmVhdGVkIiwNCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlKCJuID0iLCBuY29sKGNvdW50c19EMSksICJzYW1wbGVzIikpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKSkNCnBjYV9wbG90X0QxDQoNCiNzYXZpbmcgUENBIHBsb3QgaW4gcGRmICYgcG5nIA0KZ2dzYXZlKCgiRDFfUENBLnBkZiIpLCBwY2FfcGxvdF9EMSwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQ0KZ2dzYXZlKCgiRDFfUENBLnBuZyIpLCBwY2FfcGxvdF9EMSwgd2lkdGggPSA2LCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApDQoNCiMgU2FtcGxlIGRpc3RhbmNlIGhlYXRtYXANCnNhbXBsZV9kaXN0YW5jZXNfRDEgPC0gZGlzdCh0KGFzc2F5KHZzZGF0YV9EMSkpKQ0Kc2FtcGxlRGlzdE1hdHJpeF9EMSA8LSBhcy5tYXRyaXgoc2FtcGxlX2Rpc3RhbmNlc19EMSkNCnBoZWF0bWFwOjpwaGVhdG1hcChzYW1wbGVEaXN0TWF0cml4X0QxLA0KICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gc2FtcGxlX2Rpc3RhbmNlc19EMSwNCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9IHNhbXBsZV9kaXN0YW5jZXNfRDEsDQogICAgICAgICBtYWluID0gIlNhbXBsZS10by1TYW1wbGUgRGlzdGFuY2VzIiwNCiAgICAgICAgIGZpbGVuYW1lID0gIlNhbXBsZURpc3RhbmNlc19EMS5wbmciKQ0KIyBEaXNwZXJzaW9uIHBsb3QNCnBsb3REaXNwRXN0cyhkZHNfRDEpDQoNCiMgU2F2ZSBhcyBQREYNCnBkZigiRGlzcGVyc2lvblBsb3RfRDEucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQ0KcGxvdERpc3BFc3RzKGRkc19EMSkNCmRldi5vZmYoKQ0KDQojIE9yIHNhdmUgYXMgaGlnaC1yZXNvbHV0aW9uIFBORw0KcG5nKCJEaXNwZXJzaW9uUGxvdF9EMS5wbmciLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE2MDAsIHJlcyA9IDMwMCkNCnBsb3REaXNwRXN0cyhkZHNfRDEpDQpkZXYub2ZmKCkNCg0KYGBgDQoNCg0KYGBge3J9DQojIEdldCByZXN1bHRzIHdpdGggY29udHJhc3QNCnJlc3VsdHNOYW1lcyhkZHNfRDEpDQpyZXNfRDEgPC0gcmVzdWx0cyhkZHNfRDEsIGNvbnRyYXN0ID0gYygiVHJlYXRtZW50IiwgIk9zaW1lcnRpbmliIDZ3IiwgIlVudHJlYXRlZCIpKQ0Kc3VtbWFyeShyZXNfRDEpDQoNCiMgQXBwbHkgTEZDIHNocmlua2FnZQ0KbGlicmFyeShhcGVnbG0pDQpyZXNfc2hydW5rX0QxIDwtIGxmY1NocmluayhkZHNfRDEsIGNvZWY9MiwgdHlwZT0iYXBlZ2xtIikNCg0KIyBBZGQgZ2VuZSBhbm5vdGF0aW9ucyAoRU5TRU1CTCB0byBTWU1CT0wpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShBbm5vdGF0aW9uRGJpKQ0KbGlicmFyeShvcmcuSHMuZWcuZGIpDQpnZW5lX3N5bWJvbHNfRDEgPC0gbWFwSWRzKG9yZy5Icy5lZy5kYiwNCiAgICAgICAgICAgICAgICAgICAgICBrZXlzID0gcm93bmFtZXMocmVzX3NocnVua19EMSksDQogICAgICAgICAgICAgICAgICAgICAgY29sdW1uID0gIlNZTUJPTCIsDQogICAgICAgICAgICAgICAgICAgICAga2V5dHlwZSA9ICJFTlNFTUJMIiwNCiAgICAgICAgICAgICAgICAgICAgICBtdWx0aVZhbHMgPSAiZmlyc3QiKQ0KDQpyZXNfRDFfYW5ub3RhdGVkIDwtIHJlc19EMQ0KcmVzX0QxX2Fubm90YXRlZCRnZW5lX3N5bWJvbCA8LSBnZW5lX3N5bWJvbHNfRDEgIA0KDQoNCmFzLmRhdGEuZnJhbWUocmVzX0QxX2Fubm90YXRlZCkNCg0KcmVzX3NocnVua19hbm5vdGF0ZWRfRDEgPC0gcmVzX3NocnVua19EMQ0KcmVzX3NocnVua19hbm5vdGF0ZWRfRDEkZ2VuZV9zeW1ib2xfRDEgPC0gZ2VuZV9zeW1ib2xzX0QxDQoNCiMgRGVmaW5lIHNpZ25pZmljYW50IGdlbmVzDQpzaWdfb3ZlcmFsbF9EMSA8LSByZXNfc2hydW5rX0QxW3doaWNoKHJlc19zaHJ1bmtfRDEkcGFkaiA8IDAuMDUgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMocmVzX3NocnVua19EMSRsb2cyRm9sZENoYW5nZSkgPiAxKSwgXQ0KaGVhZChzaWdfb3ZlcmFsbF9EMSkNCiMgU2VwYXJhdGUgdXAgYW5kIGRvd24gcmVndWxhdGVkIGdlbmVzDQpzaWdfZ2VuZXNfdXBfRDEgPC0gcm93bmFtZXMocmVzX3NocnVua19EMSlbcmVzX3NocnVua19EMSRsb2cyRm9sZENoYW5nZSA+IDEgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNfc2hydW5rX0QxJHBhZGogPCAwLjA1ICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKHJlc19zaHJ1bmtfRDEkcGFkaildDQojIEV4dHJhY3QgZ2VuZSBzeW1ib2xzIGZvciB5b3VyIHNpZ25pZmljYW50IHVwcmVndWxhdGVkIGdlbmVzDQpnZW5lX3N5bWJvbHNfc2lnX3VwX0QxIDwtIHJlc19EMV9hbm5vdGF0ZWRbc2lnX2dlbmVzX3VwX0QxLCAiZ2VuZV9zeW1ib2wiXQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCBib3RoIGdlbmUgSURzIGFuZCBzeW1ib2xzDQpzaWdfZ2VuZXNfdXBfRDFfYW5ub3RhdGVkIDwtIGRhdGEuZnJhbWUoDQogIGdlbmVfaWQgPSBzaWdfZ2VuZXNfdXBfRDEsDQogIGdlbmVfc3ltYm9sID0gZ2VuZV9zeW1ib2xzX3NpZ191cF9EMQ0KKQ0KaGVhZChzaWdfZ2VuZXNfdXBfRDEpDQpzaWdfZ2VuZXNfZG93bl9EMSA8LSByb3duYW1lcyhyZXNfc2hydW5rX0QxKVtyZXNfc2hydW5rX0QxJGxvZzJGb2xkQ2hhbmdlIDwgLTEgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzX3NocnVua19EMSRwYWRqIDwgMC4wNSAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEocmVzX3NocnVua19EMSRwYWRqKV0NCg0KcHJpbnQocGFzdGUoIlNpZ25pZmljYW50IERFR3M6IiwgbnJvdyhzaWdfb3ZlcmFsbF9EMSkpKQ0KcHJpbnQocGFzdGUoIlVwcmVndWxhdGVkOiIsIGxlbmd0aChzaWdfZ2VuZXNfdXBfRDEpKSkNCnByaW50KHBhc3RlKCJEb3ducmVndWxhdGVkOiIsIGxlbmd0aChzaWdfZ2VuZXNfZG93bl9EMSkpKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiMgTUEgUGxvdA0KcGxvdE1BKHJlc19zaHJ1bmtfRDEsIHlsaW09YygtNSw1KSwgbWFpbj0iT3NpbWVydGluaWIgdnMgVW50cmVhdGVkIikNCg0KcGRmKCgiRDFfTUFwbG90LnBkZiIpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpwbG90TUEocmVzX3NocnVua19EMSwgeWxpbT1jKC01LDUpLCBtYWluPSJPc2ltZXJ0aW5pYiB2cyBVbnRyZWF0ZWQiKQ0KZGV2Lm9mZigpDQoNCnBuZygoIkQxX01BcGxvdC5wbmciKSwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNjAwLCByZXMgPSAzMDApDQpwbG90TUEocmVzX3NocnVua19EMSwgeWxpbT1jKC01LDUpLCBtYWluPSJPc2ltZXJ0aW5pYiB2cyBVbnRyZWF0ZWQiKQ0KZGV2Lm9mZigpDQoNCmxpYnJhcnkodGliYmxlKSAgIyBmb3Igcm93bmFtZXNfdG9fY29sdW1uDQoNCiMgU2VsZWN0IHRvcCAyMCBtb3N0IHNpZ25pZmljYW50IGdlbmVzIGZvciBsYWJlbGluZw0KdG9wX2dlbmVzX2RhdGEgPC0gcmVzX3NocnVua19hbm5vdGF0ZWRfRDEgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgcm93bmFtZXNfdG9fY29sdW1uKCJnZW5lX2lkIikgJT4lDQogIGZpbHRlcighaXMubmEocGFkaikgJiAhaXMubmEoZ2VuZV9zeW1ib2xfRDEpKSAlPiUNCiAgYXJyYW5nZShwYWRqKSAlPiUNCiAgaGVhZCgyMCkNCg0KdG9wX2dlbmVfc3ltYm9sc19EMSA8LSB0b3BfZ2VuZXNfZGF0YSRnZW5lX3N5bWJvbF9EMQ0KDQojIENsZWFuIHZvbGNhbm8gcGxvdA0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pDQoNCnZvbGNhbm9fcGxvdF9EMSA8LSBFbmhhbmNlZFZvbGNhbm8ocmVzX3NocnVua19hbm5vdGF0ZWRfRDEsDQogICAgICAgICAgICAgICAgbGFiID0gcmVzX3NocnVua19hbm5vdGF0ZWRfRDEkZ2VuZV9zeW1ib2xfRDEsDQogICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gdG9wX2dlbmVfc3ltYm9sc19EMSwNCiAgICAgICAgICAgICAgICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywNCiAgICAgICAgICAgICAgICB5ID0gJ3BhZGonLA0KICAgICAgICAgICAgICAgIHRpdGxlID0gJ09zaW1lcnRpbmliIDZ3IHZzIFVudHJlYXRlZCcsDQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSBwYXN0ZSgnREVHczonLCBsZW5ndGgoc2lnX2dlbmVzX3VwX0QxKSwgJ3VwLCcsIGxlbmd0aChzaWdfZ2VuZXNfZG93bl9EMSksICdkb3duJyksDQogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsDQogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLA0KICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDEuNSwNCiAgICAgICAgICAgICAgICBsYWJTaXplID0gMy41LA0KICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwNCiAgICAgICAgICAgICAgICB4bGltID0gYygtNiwgNikpDQoNCnZvbGNhbm9fcGxvdF9EMQ0KDQpnZ3NhdmUoKCJEMV9Wb2xjYW5vLnBkZiIpLCB2b2xjYW5vX3Bsb3RfRDEsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkNCmdnc2F2ZSgoIkQxX1ZvbGNhbm8ucG5nIiksIHZvbGNhbm9fcGxvdF9EMSwgd2lkdGggPSA2LCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApDQoNCiMgSGVhdG1hcCBvZiB0b3AgNTAgc2lnbmlmaWNhbnQgZ2VuZXMNCmxpYnJhcnkocGhlYXRtYXApDQp0b3A1MF9nZW5lc19EMSA8LSBoZWFkKG9yZGVyKHJlc19zaHJ1bmtfYW5ub3RhdGVkX0QxJHBhZGopLCA1MCkNCnBuZygiVG9wNTBfSGVhdG1hcF9EMS5wbmciLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE2MDAsIHJlcyA9IDMwMCkNCnBoZWF0bWFwOjpwaGVhdG1hcChhc3NheSh2c2RhdGFfRDEpW3RvcDUwX2dlbmVzX0QxLF0sIA0KICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoZGRzX0QxKVssIlRyZWF0bWVudCIsIGRyb3A9RkFMU0VdKSwgDQogICAgICAgICBzY2FsZSA9ICJyb3ciLCANCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgIG1haW4gPSAiVG9wIDUwIFNpZ25pZmljYW50IEdlbmVzIiwNCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUpDQpkZXYub2ZmKCkNCg0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpsaWJyYXJ5KGNpcmNsaXplKQ0KbGlicmFyeShkcGx5cikNCg0KIyBGaXJzdCwgcHJlcGFyZSB0b3AgZ2VuZXMgZm9yIGhlYXRtYXANCnRvcF9nZW5lc19oZWF0bWFwX0QxIDwtIHJlc19zaHJ1bmtfYW5ub3RhdGVkX0QxWyFpcy5uYShyZXNfc2hydW5rX2Fubm90YXRlZF9EMSRwYWRqKSAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzX3NocnVua19hbm5vdGF0ZWRfRDEkcGFkaiA8IDAuMDUgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc19zaHJ1bmtfYW5ub3RhdGVkX0QxJGJhc2VNZWFuID4gNTAgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFicyhyZXNfc2hydW5rX2Fubm90YXRlZF9EMSRsb2cyRm9sZENoYW5nZSkgPiAyLF0NCg0KdG9wX2dlbmVzX2hlYXRtYXBfRDEgPC0gaGVhZChhcy5kYXRhLmZyYW1lKHRvcF9nZW5lc19oZWF0bWFwX0QxKSwgMTAwKSAgIyBNb3JlIGdlbmVzIGZvciAxMTUgc2FtcGxlcw0KdG9wX2dlbmVzX2hlYXRtYXBfRDEgPC0gdG9wX2dlbmVzX2hlYXRtYXBfRDFbb3JkZXIodG9wX2dlbmVzX2hlYXRtYXBfRDEkbG9nMkZvbGRDaGFuZ2UsIGRlY3JlYXNpbmcgPSBUUlVFKSxdDQoNCiMgR2V0IG5vcm1hbGl6ZWQgY291bnQgZGF0YSBmcm9tIHZzdA0KbWF0X0QxIDwtIGFzc2F5KHZzZGF0YV9EMSlbcm93bmFtZXModG9wX2dlbmVzX2hlYXRtYXBfRDEpLCBdDQptYXRfc2NhbGVkX0QxIDwtIHQoYXBwbHkobWF0X0QxLCAxLCBzY2FsZSkpDQpjb2xuYW1lcyhtYXRfc2NhbGVkX0QxKSA8LSBjb2xuYW1lcyhtYXRfRDEpDQoNCiMgU2VsZWN0IHRvcCBhbmQgYm90dG9tIGdlbmVzIChpbmNyZWFzZSBmb3IgMTE1IHNhbXBsZXMpDQpudW1fa2VlcCA8LSA0MCAgIyBTaG93IG1vcmUgZ2VuZXMgd2l0aCAxMTUgc2FtcGxlcw0Kcm93c19rZWVwX0QxIDwtIGMoc2VxKDE6bnVtX2tlZXApLCBzZXEoKG5yb3cobWF0X3NjYWxlZF9EMSkgLSBudW1fa2VlcCArIDEpLCBucm93KG1hdF9zY2FsZWRfRDEpKSkNCg0KIyBQcmVwYXJlIGFubm90YXRpb24gbWF0cmljZXMNCmwyX3ZhbF9EMSA8LSBhcy5tYXRyaXgodG9wX2dlbmVzX2hlYXRtYXBfRDFbcm93c19rZWVwX0QxLF0kbG9nMkZvbGRDaGFuZ2UpDQpjb2xuYW1lcyhsMl92YWxfRDEpIDwtICJsb2dGQyINCg0KbWVhbl9EMSA8LSBhcy5tYXRyaXgodG9wX2dlbmVzX2hlYXRtYXBfRDFbcm93c19rZWVwX0QxLF0kYmFzZU1lYW4pDQpjb2xuYW1lcyhtZWFuX0QxKSA8LSAiQXZlRXhwciINCg0KIyBTZXQgdXAgY29sb3Igc2NoZW1lcw0KY29sX2xvZ0ZDX0QxIDwtIGNvbG9yUmFtcDIoYyhtaW4obDJfdmFsX0QxKSwgMCwgbWF4KGwyX3ZhbF9EMSkpLCBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQ0KY29sX0F2ZUV4cHJfRDEgPC0gY29sb3JSYW1wMihjKHF1YW50aWxlKG1lYW5fRDEpWzFdLCBxdWFudGlsZShtZWFuX0QxKVs0XSksIGMoIndoaXRlIiwgInJlZCIpKQ0KY29sX3pzY29yZV9EMSA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCBjKCIjNDU3NWI0IiwgIndoaXRlIiwgIiNkNzMwMjciKSkNCg0KIyBBZGQgc2FtcGxlIGFubm90YXRpb24gZm9yIDExNSBzYW1wbGVzDQpzYW1wbGVfYW5ub3RhdGlvbiA8LSBIZWF0bWFwQW5ub3RhdGlvbigNCiAgVHJlYXRtZW50ID0gbWV0YWRhdGFfRDEkVHJlYXRtZW50LCAgIyBBc3N1bWluZyB5b3VyIG1ldGFkYXRhIGhhcyB0cmVhdG1lbnQgY29sdW1uDQogIGNvbCA9IGxpc3QoVHJlYXRtZW50ID0gYygiVW50cmVhdGVkIiA9ICJncmF5IiwgIk9zaW1lcnRpbmliIDZ3IiA9ICJkYXJrZ3JlZW4iKSkNCikNCg0KIyBNYWluIGV4cHJlc3Npb24gaGVhdG1hcCAtIGFkanVzdGVkIGZvciAxMTUgc2FtcGxlcw0KaDFfRDEgPC0gSGVhdG1hcCgNCiAgbWF0X3NjYWxlZF9EMVtyb3dzX2tlZXBfRDEsXSwgDQogIGNsdXN0ZXJfcm93cyA9IFRSVUUsDQogIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsICAgICAgICAgICAgICAgIyBrZWVwIGNsdXN0ZXJpbmcgdG8gc2VlIHN1Ymdyb3Vwcw0KICBjb2x1bW5fc3BsaXQgPSBtZXRhZGF0YV9EMSRUcmVhdG1lbnQsICMgZW5mb3JjZSAyIG1haW4gYmxvY2tzIChVbnRyZWF0ZWQgLyBPc2ltZXJ0aW5pYiA2dykNCiAgdG9wX2Fubm90YXRpb24gPSBzYW1wbGVfYW5ub3RhdGlvbiwNCiAgc2hvd19yb3dfbmFtZXMgPSBGQUxTRSwNCiAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwNCiAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLA0KICBjb2x1bW5fdGl0bGUgPSAiMTE1IFNhbXBsZXMiLA0KICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKSwNCiAgY29sID0gY29sX3pzY29yZV9EMSwNCiAgbmFtZSA9ICJaLXNjb3JlIg0KKQ0KDQojIExvZ0ZDIGhlYXRtYXANCmgyX0QxIDwtIEhlYXRtYXAobDJfdmFsX0QxLCANCiAgICAgICAgICAgICAgICAgcm93X2xhYmVscyA9IHRvcF9nZW5lc19oZWF0bWFwX0QxJGdlbmVfc3ltYm9sW3Jvd3Nfa2VlcF9EMV0sDQogICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgbmFtZSA9ICJsb2dGQyIsIA0KICAgICAgICAgICAgICAgICBjb2wgPSBjb2xfbG9nRkNfRDEsDQogICAgICAgICAgICAgICAgIHdpZHRoID0gdW5pdCgxNSwgIm1tIiksDQogICAgICAgICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA2KSwgICMgU21hbGxlciBmb250IGZvciBtYW55IGdlbmVzDQogICAgICAgICAgICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgdywgaCwgY29sKSB7IA0KICAgICAgICAgICAgICAgICAgIGdyaWQudGV4dChyb3VuZChsMl92YWxfRDFbaSwgal0sIDEpLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSA1KSkNCiAgICAgICAgICAgICAgICAgfSkNCg0KIyBBdmVyYWdlIGV4cHJlc3Npb24gaGVhdG1hcA0KaDNfRDEgPC0gSGVhdG1hcChtZWFuX0QxLCANCiAgICAgICAgICAgICAgICAgcm93X2xhYmVscyA9IHRvcF9nZW5lc19oZWF0bWFwX0QxJGdlbmVfc3ltYm9sW3Jvd3Nfa2VlcF9EMV0sDQogICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgbmFtZSA9ICJBdmVFeHByIiwgDQogICAgICAgICAgICAgICAgIGNvbCA9IGNvbF9BdmVFeHByX0QxLA0KICAgICAgICAgICAgICAgICB3aWR0aCA9IHVuaXQoMTUsICJtbSIpLA0KICAgICAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksDQogICAgICAgICAgICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgdywgaCwgY29sKSB7IA0KICAgICAgICAgICAgICAgICAgIGdyaWQudGV4dChyb3VuZChtZWFuX0QxW2ksIGpdLCAwKSwgeCwgeSwgZ3AgPSBncGFyKGZvbnRzaXplID0gNSkpDQogICAgICAgICAgICAgICAgIH0pDQoNCiMgQ29tYmluZSBoZWF0bWFwcw0KaF9EMSA8LSBoMV9EMSArIGgyX0QxICsgaDNfRDENCmhfRDENCg0KcGRmKCJBbm5vdGF0ZWRIZWF0bWFwX0QxLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYpDQpkcmF3KGhfRDEpDQpkZXYub2ZmKCkNCg0KcG5nKCJBbm5vdGF0ZWRIZWF0bWFwX0QxLnBuZyIsIHdpZHRoID0gMzAwMCwgaGVpZ2h0ID0gMjAwMCwgcmVzID0gMzAwKQ0KZHJhdyhoX0QxKQ0KZGV2Lm9mZigpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBDb252ZXJ0IEVOU0VNQkwgdG8gRU5UUkVaIGZvciBLRUdHIGFuYWx5c2lzDQpsaWJyYXJ5KERPU0UpDQpsaWJyYXJ5KGVucmljaHBsb3QpDQoNCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQ0KZW50cmV6X2dlbmVzX3VwX0QxIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsIHNpZ19nZW5lc191cF9EMSwgIkVOVFJFWklEIiwgIkVOU0VNQkwiKQ0KZW50cmV6X2dlbmVzX2Rvd25fRDEgPC0gbWFwSWRzKG9yZy5Icy5lZy5kYiwgc2lnX2dlbmVzX2Rvd25fRDEsICJFTlRSRVpJRCIsICJFTlNFTUJMIikNCmVudHJlel9nZW5lc191cF9EMSA8LSBlbnRyZXpfZ2VuZXNfdXBfRDFbIWlzLm5hKGVudHJlel9nZW5lc191cF9EMSldDQplbnRyZXpfZ2VuZXNfZG93bl9EMSA8LSBlbnRyZXpfZ2VuZXNfZG93bl9EMVshaXMubmEoZW50cmV6X2dlbmVzX2Rvd25fRDEpXQ0KDQojIEdPIEFuYWx5c2lzDQoNCmdvX3VwX0QxIDwtIGVucmljaEdPKGdlbmUgPSBzaWdfZ2VuZXNfdXBfRDEsDQogICAgICAgICAgICAgICAgICAgIE9yZ0RiID0gb3JnLkhzLmVnLmRiLA0KICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gIkVOU0VNQkwiLA0KICAgICAgICAgICAgICAgICAgICBvbnQgPSAiQUxMIiwgICMgQlAsIENDLCBNRg0KICAgICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIiwNCiAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSkNCnRvcF9nb191cF9EMSA8LSBnb191cF9EMUByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3BfZ29fdXBfRDEpDQoNCmdvX2Rvd25fRDEgPC0gZW5yaWNoR08oZ2VuZSA9IHNpZ19nZW5lc19kb3duX0QxLA0KICAgICAgICAgICAgICAgICAgICAgIE9yZ0RiID0gb3JnLkhzLmVnLmRiLA0KICAgICAgICAgICAgICAgICAgICAgIGtleVR5cGUgPSAiRU5TRU1CTCIsDQogICAgICAgICAgICAgICAgICAgICAgb250ID0gIkFMTCIsDQogICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIsDQogICAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSkNCnRvcF9nb19kb3duX0QxIDwtIGdvX2Rvd25fRDFAcmVzdWx0WzE6MTAsIF0NCmFzLmRhdGEuZnJhbWUodG9wX2dvX2Rvd25fRDEpDQoNCiMgS0VHRyBQYXRod2F5IEFuYWx5c2lzDQprZWdnX3VwX0QxIDwtIGVucmljaEtFR0coZ2VuZSA9IGVudHJlel9nZW5lc191cF9EMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdoc2EnLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIpDQphcy5kYXRhLmZyYW1lKGtlZ2dfdXBfRDEpDQp0b3Bfa2VnZ191cF9EMSA8LSBrZWdnX3VwX0QxQHJlc3VsdFsxOjEwLCBdDQphcy5kYXRhLmZyYW1lKHRvcF9rZWdnX3VwX0QxKQ0KDQprZWdnX2Rvd25fRDEgPC0gZW5yaWNoS0VHRyhnZW5lID0gZW50cmV6X2dlbmVzX2Rvd25fRDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdoc2EnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBBZGp1c3RNZXRob2QgPSAiQkgiKQ0KYXMuZGF0YS5mcmFtZShrZWdnX2Rvd25fRDEpDQp0b3Bfa2VnZ19kb3duX0QxIDwtIGtlZ2dfZG93bl9EMUByZXN1bHRbMToxMCxdDQphcy5kYXRhLmZyYW1lKHRvcF9rZWdnX2Rvd25fRDEpDQoNCiMgVmlzdWFsaXplIHBhdGh3YXkgcmVzdWx0cw0KaWYobnJvdyhnb191cF9EMUByZXN1bHQpID4gMCkgew0KICBwMSA8LSBiYXJwbG90KGdvX3VwX0QxLCBzcGxpdD0iT05UT0xPR1kiLCBzaG93Q2F0ZWdvcnkgPSA4KSArIA0KICAgIGZhY2V0X2dyaWQoT05UT0xPR1l+Liwgc2NhbGU9ImZyZWUiKSArDQogICAgbGFicyh0aXRsZSA9ICJVcHJlZ3VsYXRlZCBHTyBUZXJtcyIpDQogIHByaW50KHAxKQ0KICBnZ3NhdmUoIkdPX1VwcmVndWxhdGVkX0QxLnBkZiIsIHAxLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpDQogIGdnc2F2ZSgiR09fVXByZWd1bGF0ZWRfRDEucG5nIiwgcDEsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KfQ0KDQppZihucm93KGdvX2Rvd25fRDFAcmVzdWx0KSA+IDApIHsNCiAgcDIgPC0gYmFycGxvdChnb19kb3duX0QxLCBzcGxpdD0iT05UT0xPR1kiLCBzaG93Q2F0ZWdvcnkgPSA4KSArIA0KICAgIGZhY2V0X2dyaWQoT05UT0xPR1l+Liwgc2NhbGU9ImZyZWUiKSArDQogICAgbGFicyh0aXRsZSA9ICJEb3ducmVndWxhdGVkIEdPIFRlcm1zIikNCiAgcHJpbnQocDEpDQogIGdnc2F2ZSgiR09fRG93bnJlZ3VsYXRlZF9EMS5wZGYiLCBwMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIkdPX0Rvd25yZWd1bGF0ZWRfRDEucG5nIiwgcDIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KfQ0KDQoNCmlmKG5yb3coa2VnZ191cF9EMUByZXN1bHQpID4gMCkgew0KICBwMyA8LSBkb3RwbG90KGtlZ2dfdXBfRDEsIHNob3dDYXRlZ29yeSA9IDE1LCB0aXRsZSA9ICJVcHJlZ3VsYXRlZCBLRUdHIFBhdGh3YXlzIikNCiAgcHJpbnQocDIpDQogIGdnc2F2ZSgiS0VHR19VcHJlZ3VsYXRlZF9EMS5wZGYiLCBwMywgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIktFR0dfVXByZWd1bGF0ZWRfRDEucG5nIiwgcDMsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KfQ0KDQppZihucm93KGtlZ2dfZG93bl9EMUByZXN1bHQpID4gMCkgew0KICBwNCA8LSBkb3RwbG90KGtlZ2dfZG93bl9EMSwgc2hvd0NhdGVnb3J5ID0gMTUsIHRpdGxlID0gIkRvd25yZWd1bGF0ZWQgS0VHRyBQYXRod2F5cyIpDQogIHByaW50KHAzKQ0KICBnZ3NhdmUoIktFR0dfRG93bnJlZ3VsYXRlZF9EMS5wZGYiLCBwNCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIktFR0dfRG93bnJlZ3VsYXRlZF9EMS5wbmciLCBwNCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQp9DQoNCg0KYGBgDQoNCg0KYGBge3J9DQojIFByZXBhcmUgcmFua2VkIGdlbmUgbGlzdA0KbGlicmFyeShmZ3NlYSkNCmxpYnJhcnkobXNpZ2RicikNCmdlbmVfcmFua3NfRDEgPC0gcmVzX3NocnVua19EMSRsb2cyRm9sZENoYW5nZQ0KbmFtZXMoZ2VuZV9yYW5rc19EMSkgPC0gcm93bmFtZXMocmVzX3NocnVua19EMSkNCmdlbmVfcmFua3NfRDEgPC0gZ2VuZV9yYW5rc19EMVshaXMubmEoZ2VuZV9yYW5rc19EMSldDQpnZW5lX3JhbmtzX0QxIDwtIHNvcnQoZ2VuZV9yYW5rc19EMSwgZGVjcmVhc2luZyA9IFRSVUUpDQoNCiMgR2V0IEhhbGxtYXJrIHBhdGh3YXlzDQpoYWxsbWFya19zZXRzX0QxIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJIIikNCmhhbGxtYXJrX2xpc3RfRDEgPC0gc3BsaXQoaGFsbG1hcmtfc2V0c19EMSRlbnNlbWJsX2dlbmUsIGhhbGxtYXJrX3NldHNfRDEkZ3NfbmFtZSkNCg0KIyBSdW4gR1NFQQ0KZmdzZWFfcmVzdWx0c19EMSA8LSBmZ3NlYShwYXRod2F5cyA9IGhhbGxtYXJrX2xpc3RfRDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMgPSBnZW5lX3JhbmtzX0QxLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1pblNpemUgPSAxNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtYXhTaXplID0gNTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5wZXJtID0gMTAwMCkNCg0KI3Bsb3R0aW5nIHRvcCAzIHBhdGh3YXlzDQpwcmludCgiVG9wIDMgR1NFQSBwYXRod2F5czoiKQ0KdG9wX3BhdGh3YXlzX0QxIDwtIGhlYWQoZmdzZWFfcmVzdWx0c19EMVtvcmRlcihwdmFsKSwgXSwgMykNCnByaW50KHRvcF9wYXRod2F5c19EMVssIGMoInBhdGh3YXkiLCAicHZhbCIsICJORVMiKV0pDQoNCmZvcihpIGluIDE6Mykgew0KICBwYXRod2F5X25hbWVzX0QxIDwtIHRvcF9wYXRod2F5c19EMSRwYXRod2F5W2ldDQogIHAgPC0gcGxvdEVucmljaG1lbnQoaGFsbG1hcmtfbGlzdF9EMVtbcGF0aHdheV9uYW1lc19EMV1dLCBnZW5lX3JhbmtzX0QxKSArIA0KICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiUGF0aHdheSIsIGksICI6IiwgcGF0aHdheV9uYW1lc19EMSkpDQogIHByaW50KHApDQogIGdnc2F2ZSgiVG9wM19HU0VBX0QxLnBkZiIsIHAsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikNCiAgZ2dzYXZlKCJUb3AzX0dTRUFfRDEucG5nIiwgcCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQp9DQoNCmhlYWQoZmdzZWFfcmVzdWx0c19EMVtvcmRlcihwdmFsKSwgXSwgMTApDQoNCmBgYA0KDQoNCg0KYGBge3J9DQojIFN1bW1hcnkgc3RhdGlzdGljcyB0YWJsZQ0Kc3VtbWFyeV9zdGF0c19EMSA8LSBkYXRhLmZyYW1lKA0KICBNZXRyaWMgPSBjKCJUb3RhbCBTYW1wbGVzIiwgIk9zaW1lcnRpbmliIFRyZWF0ZWQiLCAiVW50cmVhdGVkIiwgDQogICAgICAgICAgICAiR2VuZXMgQW5hbHl6ZWQiLCAiU2lnbmlmaWNhbnQgREVHcyIsICJVcHJlZ3VsYXRlZCIsICJEb3ducmVndWxhdGVkIiksDQogIFZhbHVlID0gYyhuY29sKGNvdW50c19EMSksIA0KICAgICAgICAgICBzdW0obWV0YWRhdGFfRDEkVHJlYXRtZW50ID09ICJPc2ltZXJ0aW5pYiA2dyIpLA0KICAgICAgICAgICBzdW0obWV0YWRhdGFfRDEkVHJlYXRtZW50ID09ICJVbnRyZWF0ZWQiKSwNCiAgICAgICAgICAgbnJvdyhyZXNfc2hydW5rX0QxKSwNCiAgICAgICAgICAgbnJvdyhzaWdfb3ZlcmFsbF9EMSksDQogICAgICAgICAgIGxlbmd0aChzaWdfZ2VuZXNfdXBfRDEpLA0KICAgICAgICAgICBsZW5ndGgoc2lnX2dlbmVzX2Rvd25fRDEpKQ0KKQ0KDQpwcmludCgiQW5hbHlzaXMgU3VtbWFyeToiKQ0KcHJpbnQoc3VtbWFyeV9zdGF0c19EMSkNCg0KIyBUb3AgZ2VuZXMgdGFibGUNCnRvcF9nZW5lc190YWJsZV9EMSA8LSBkYXRhLmZyYW1lKA0KICBHZW5lX1N5bWJvbCA9IGdlbmVfc3ltYm9sc19EMVtyb3duYW1lcyhoZWFkKHNpZ19vdmVyYWxsX0QxW29yZGVyKHNpZ19vdmVyYWxsX0QxJHBhZGopLF0sIDIwKSldLA0KICBFTlNFTUJMX0lEID0gcm93bmFtZXMoaGVhZChzaWdfb3ZlcmFsbF9EMVtvcmRlcihzaWdfb3ZlcmFsbF9EMSRwYWRqKSxdLCAyMCkpLA0KICBMb2cyRkMgPSByb3VuZChoZWFkKHNpZ19vdmVyYWxsX0QxW29yZGVyKHNpZ19vdmVyYWxsX0QxJHBhZGopLF0sIDIwKSRsb2cyRm9sZENoYW5nZSwgMyksDQogIFBhZGogPSBmb3JtYXQoaGVhZChzaWdfb3ZlcmFsbF9EMVtvcmRlcihzaWdfb3ZlcmFsbF9EMSRwYWRqKSxdLCAyMCkkcGFkaiwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpLA0KICBEaXJlY3Rpb24gPSBpZmVsc2UoaGVhZChzaWdfb3ZlcmFsbF9EMVtvcmRlcihzaWdfb3ZlcmFsbF9EMSRwYWRqKSxdLCAyMCkkbG9nMkZvbGRDaGFuZ2UgPiAwLCAiVXAiLCAiRG93biIpDQopDQoNCnByaW50KCJUb3AgMjAgU2lnbmlmaWNhbnQgR2VuZXM6IikNCnByaW50KHRvcF9nZW5lc190YWJsZV9EMSkNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgRXhwb3J0IG1haW4gcmVzdWx0cw0Kd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUocmVzX3NocnVua19hbm5vdGF0ZWRfRDEpLCAiRDFfYW5ub3RhdGVkX3Jlc3VsdHMuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCndyaXRlLmNzdihzaWdfb3ZlcmFsbF9EMSwgIkQxX3NpZ25pZmljYW50X2dlbmVzLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpDQp3cml0ZS5jc3Yoc3VtbWFyeV9zdGF0c19EMSwgIkQxX3N1bW1hcnlfc3RhdGlzdGljcy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCndyaXRlLmNzdih0b3BfZ2VuZXNfdGFibGVfRDEsICJEMV90b3BfZ2VuZXMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgRXhwb3J0IG5vcm1hbGl6ZWQgZGF0YQ0Kd3JpdGUuY3N2KHJlc19EMV9hbm5vdGF0ZWQsICJEMV9yZXN1bHRzLmNzdiIpDQp3cml0ZS5jc3YoY291bnRzKGRkc19EMSwgbm9ybWFsaXplZD1UUlVFKSwgIkQxX25vcm1hbGl6ZWRfY291bnRzLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpDQp3cml0ZS5jc3YodnN0X2ZpbmFsX0QxLCAiRDFfdnN0X2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCg0KIyBFeHBvcnQgcGF0aHdheSByZXN1bHRzDQppZihucm93KGdvX3VwX0QxQHJlc3VsdCkgPiAwKSB7DQogIHdyaXRlLmNzdihnb191cF9EMUByZXN1bHQsICJEMV9HT191cHJlZ3VsYXRlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCn0NCmlmKG5yb3coZ29fZG93bl9EMUByZXN1bHQpID4gMCkgew0KICB3cml0ZS5jc3YoZ29fZG93bl9EMUByZXN1bHQsICJEMV9HT19kb3ducmVndWxhdGVkLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KfQ0KaWYobnJvdyhrZWdnX3VwX0QxQHJlc3VsdCkgPiAwKSB7DQogIHdyaXRlLmNzdihrZWdnX3VwX0QxQHJlc3VsdCwgIkQxX0tFR0dfdXByZWd1bGF0ZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQp9DQppZihucm93KGtlZ2dfZG93bl9EMUByZXN1bHQpID4gMCkgew0KICB3cml0ZS5jc3Yoa2VnZ19kb3duX0QxQHJlc3VsdCwgIkQxX0tFR0dfZG93bnJlZ3VsYXRlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCn0NCg0KIyBSZW1vdmUgdGhlIGxlYWRpbmdFZGdlIGNvbHVtbiAod2hpY2ggY29udGFpbnMgbGlzdHMpDQpmZ3NlYV9yZXN1bHRzX2NsZWFuIDwtIGZnc2VhX3Jlc3VsdHNfRDEgJT4lDQogIHNlbGVjdCgtbGVhZGluZ0VkZ2UpDQoNCndyaXRlLmNzdihmZ3NlYV9yZXN1bHRzX2NsZWFuLCAiRDFfR1NFQV9oYWxsbWFya3MuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCmBgYA0KDQoNCg==