library(DESeq2)
library(ggplot2)
# Loading my dataset & metadata
counts_D2 <- read.delim("counts_D2", header = TRUE, sep = "\t", row.names = 1)
metadata_D2 <- read.csv("metadata_D2.csv", header = TRUE)
#checking the distribution of counts in my dataset
total_counts_per_gene_D2 <- rowSums(counts_D2)
hist(total_counts_per_gene_D2,
breaks=100,
main="Distribution of Total Counts per Gene - Dataset 2",
xlab="Total counts across all samples",
ylab="Number of genes")
summary(total_counts_per_gene_D2)
#ignoring low expressed gene to remove noise & get better results
print(paste("Genes before filtering:", nrow(counts_D2)))
counts_D2 <- counts_D2[which(rowSums(counts_D2) > 50), ]
print(paste("Genes after filtering:", nrow(counts_D2)))
#need to round counts for DESeq2 compatibility
counts_D2 <- round(counts_D2)
library(DESeq2)
#creating DESeq2 object with interaction design
dds_D2 <- DESeqDataSetFromMatrix(countData = counts_D2,
colData = metadata_D2,
design = ~ tissue + egfr_mutation + tissue:egfr_mutation)
dds_D2
#running the main DESeq2 analysis
dds_D2 <- DESeq(dds_D2)
#creating variance stabilized data for visualization
vsdata_D2 <- vst(dds_D2, blind = TRUE)
resultsNames(dds_D2)
vst_matrix_D2 <- assay(vsdata_D2)
head(vst_matrix_D2[1:5, 1:3])
library(reshape2)
vst_df_D2 <- as.data.frame(vst_matrix_D2)
vst_df_D2$gene_id <- rownames(vst_df_D2)
vst_final_D2 <- melt(vst_df_D2,
id.vars = "gene_id",
variable.name = "sample_id",
value.name = "expression_value")
# Check the result - should have exactly 3 columns
head(vst_final_D2)
results_WT_D2 <- results(dds_D2, name = "egfr_mutation_Wild.type_vs_Exon.19.deletion")
#SANITY CHECKS - because there's only 1 replicate for each mutation type
#mm <- model.matrix(design(dds_D2), colData(dds_D2))
#qr(mm)$rank
#ncol(mm)
# After running DESeq(dds_D2)
#res <- results(dds_D2, name = "egfr_mutation_Wild.type_vs_Exon.19.deletion")
#summary(res)
#(hist(res$pvalue, breaks=50))
#resLFC <- lfcShrink(dds_D2, coef="egfr_mutation_Wild.type_vs_Exon.19.deletion", type="apeglm")
#plotMA(resLFC)
library(ggplot2)
plotDispEsts(dds_D2)
# Save as PDF
pdf("DispersionPlot_D2.pdf", width = 6, height = 5)
plotDispEsts(dds_D2)
dev.off()
# Or save as high-resolution PNG
png("DispersionPlot_D2.png", width = 2000, height = 1600, res = 300)
plotDispEsts(dds_D2)
dev.off()
#creating an enhanced PCA plot to see sample clustering
pca_data_D2 <- plotPCA(vsdata_D2, intgroup = c("tissue", "egfr_mutation"), returnData = TRUE)
pca_plot_D2 <- ggplot(pca_data_D2, aes(PC1, PC2, color = interaction(egfr_mutation, tissue))) +
geom_point(size = 3, alpha = 0.8) +
xlab(paste0("PC1: ", round(100 * attr(pca_data_D2, "percentVar")[1]), "% variance")) +
ylab(paste0("PC2: ", round(100 * attr(pca_data_D2, "percentVar")[2]), "% variance")) +
labs(title = "PCA - Dataset 2: EGFR Mutations and Tissue Types",
color = "Group") +
theme_minimal() +
theme(legend.position = "right")
pca_plot_D2
#saving PCA plot in pdf & png
ggsave(("D2_PCA.pdf"), pca_plot_D2, width = 6, height = 5)
ggsave(("D2_PCA.png"), pca_plot_D2, width = 6, height = 5, dpi = 300)

#loading pheatmap for sample distance visualization
library(pheatmap)
#creating sample distance heatmap
sample_distances_D2 <- dist(t(assay(vsdata_D2)))
sampleDistMatrix_D2 <- as.matrix(sample_distances_D2)
pheatmap::pheatmap(sampleDistMatrix_D2,
clustering_distance_rows = sample_distances_D2,
clustering_distance_cols = sample_distances_D2,
annotation_col = as.data.frame(colData(dds_D2)[,c("tissue", "egfr_mutation")]),
main = "Sample-to-Sample Distances - Dataset 2",
filename = "SampleDistances_D2.png")
resultsNames(dds_D2)
[1] "Intercept"
[2] "tissue_Surgically.resected.tumor_vs_Patient.derived.xenograft.tumor"
[3] "egfr_mutation_Exon.21.L858R_vs_Exon.19.deletion"
[4] "egfr_mutation_Wild.type_vs_Exon.19.deletion"
[5] "tissueSurgically.resected.tumor.egfr_mutationExon.21.L858R"
[6] "tissueSurgically.resected.tumor.egfr_mutationWild.type"
summary_res_D2 <- results(dds_D2, name = "egfr_mutation_Wild.type_vs_Exon.19.deletion" )
summary(summary_res_D2)
out of 27943 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up) : 2227, 8%
LFC < 0 (down) : 1198, 4.3%
outliers [1] : 531, 1.9%
low counts [2] : 3791, 14%
(mean count < 8)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
#NON-NEGOTIABLE for reliable results
library(apeglm)
# Shrink coefficients for all main comparisons
res_WT_vs_del19_D2 <- lfcShrink(dds_D2, coef="egfr_mutation_Wild.type_vs_Exon.19.deletion", type="apeglm") #primary comparison
res_tissue_D2 <- lfcShrink(dds_D2, coef="tissue_Surgically.resected.tumor_vs_Patient.derived.xenograft.tumor", type="apeglm")
res_21_vs_del19_D2 <- lfcShrink(dds_D2, coef="egfr_mutation_Exon.21.L858R_vs_Exon.19.deletion", type="apeglm")
# Interaction effects (tissue-specific mutation effects)
res_interaction_21_D2 <- lfcShrink(dds_D2, coef="tissueSurgically.resected.tumor.egfr_mutationExon.21.L858R", type="apeglm")
res_interaction_WT_D2 <- lfcShrink(dds_D2, coef="tissueSurgically.resected.tumor.egfr_mutationWild.type", type="apeglm")
library(AnnotationDbi)
library(org.Hs.eg.db)
#converting ENSEMBL IDs to gene symbols
gene_symbols_D2 <- mapIds(org.Hs.eg.db,
keys = rownames(dds_D2),
column = "SYMBOL",
keytype = "ENSEMBL",
multiVals = "first")
res_annotated_D2 <- results_WT_D2
res_annotated_D2$gene_symbol <- gene_symbols_D2
as.data.frame(res_annotated_D2)
#adding annotations to all my important results
resAnnotate_WT_D2 <- res_WT_vs_del19_D2
resAnnotate_WT_D2$gene_symbol <- gene_symbols_D2
resAnnotate_tissue_D2 <- res_tissue_D2
resAnnotate_tissue_D2$gene_symbol <- gene_symbols_D2
resAnnotate_21_D2 <- res_21_vs_del19_D2
resAnnotate_21_D2$gene_symbol <- gene_symbols_D2
# Summary statistics for each comparison
summary(res_tissue_D2, alpha=0.05)
summary(res_21_vs_del19_D2, alpha=0.05)
summary(res_WT_vs_del19_D2, alpha=0.05)
summary(res_interaction_21_D2, alpha=0.05)
summary(res_interaction_WT_D2, alpha=0.05)
# Extract significant genes (padj < 0.05, |LFC| > 1)
sig_tissue_D2 <- res_tissue_D2[which(res_tissue_D2$padj < 0.05 & abs(res_tissue_D2$log2FoldChange) > 1), ]
sig_21_D2 <- res_21_vs_del19_D2[which(res_21_vs_del19_D2$padj < 0.05 & abs(res_21_vs_del19_D2$log2FoldChange) > 1), ]
sig_WT_D2 <- res_WT_vs_del19_D2[which(res_WT_vs_del19_D2$padj < 0.05 & abs(res_WT_vs_del19_D2$log2FoldChange) > 1), ]
# See how many significant genes in each comparison
nrow(sig_tissue_D2) # Tissue effect genes
nrow(sig_21_D2) # L858R vs Del19 genes
nrow(sig_WT_D2) # WT vs Del19 genes (your drug targets!)
# Also complete the interaction extractions
sig_interaction_21_D2 <- res_interaction_21_D2[which(res_interaction_21_D2$padj < 0.05 & abs(res_interaction_21_D2$log2FoldChange) > 0.5), ]
sig_interaction_WT_D2 <- res_interaction_WT_D2[which(res_interaction_WT_D2$padj < 0.05 & abs(res_interaction_WT_D2$log2FoldChange) > 0.5), ]
nrow(sig_interaction_21_D2) # How many interaction genes
[1] 11
nrow(sig_interaction_WT_D2)
[1] 24
Visualization Plots
# MA plots for each comparison
plotMA(res_tissue_D2, ylim=c(-5,5), main="Tissue Effect")
plotMA(res_21_vs_del19_D2, ylim=c(-5,5), main="L858R vs Del19")
plotMA(res_WT_vs_del19_D2, ylim=c(-5,5), main="Wild Type vs Del19")
pdf(("MA_res_tissue_D2.pdf"), width = 6, height = 5)
plotMA(res_tissue_D2, ylim=c(-5,5), main="Tissue Effect")
dev.off()
png(("MA_res_tissue_D2.png"), width = 2000, height = 1600, res = 300)
plotMA(res_tissue_D2, ylim=c(-5,5), main="Tissue Effect")
dev.off()
pdf(("MA_res_21_vs_del19_D2.pdf"), width = 6, height = 5)
plotMA(res_21_vs_del19_D2, ylim=c(-5,5), main="L858R vs Del19")
dev.off()
png(("MA_res_21_vs_del19_D2.png"), width = 2000, height = 1600, res = 300)
plotMA(res_21_vs_del19_D2, ylim=c(-5,5), main="L858R vs Del19")
dev.off()
pdf(("MA_res_WT_vs_del19_D2.pdf"), width = 6, height = 5)
plotMA(res_WT_vs_del19_D2, ylim=c(-5,5), main="Wild Type vs Del19")
dev.off()
png(("MA_res_WT_vs_del19_D2.png"), width = 2000, height = 1600, res = 300)
plotMA(res_WT_vs_del19_D2, ylim=c(-5,5), main="Wild Type vs Del19")
dev.off()
# Volcano plots
library(EnhancedVolcano)
top_genes_WT_D2 <- rownames(resAnnotate_WT_D2[order(resAnnotate_WT_D2$padj), ][1:50, ])
volcano_WT_D2 <- EnhancedVolcano(resAnnotate_WT_D2,
lab = resAnnotate_WT_D2$gene_symbol,
x = 'log2FoldChange',
y = 'padj',
selectLab = resAnnotate_WT_D2$gene_symbol[rownames(resAnnotate_WT_D2) %in% top_genes_WT_D2],
title = 'Wild Type vs Exon 19 Deletion (Drug Resistance)')
print(volcano_WT_D2)
ggsave(("D2_Volcano.pdf"), volcano_WT_D2, width = 6, height = 5)
ggsave(("D2_Volcano.png"), volcano_WT_D2, width = 6, height = 5, dpi = 300)
# Heatmap of top differentially expressed genes - with values & genes
library(pheatmap)
keys <- rownames(resAnnotate_WT_D2)
values <- resAnnotate_WT_D2$gene_symbol
l <- list()
for (i in 1:length(keys)){
l[keys[i]] <- values[i]
}
l
library(dplyr)
top_WT_heatmap <- resAnnotate_WT_D2[!is.na(resAnnotate_WT_D2$padj) &
!is.na(resAnnotate_WT_D2$baseMean) &
!is.na(resAnnotate_WT_D2$log2FoldChange) &
(resAnnotate_WT_D2$padj < 0.05) &
(resAnnotate_WT_D2$baseMean > 50) &
(abs(resAnnotate_WT_D2$log2FoldChange) > 2),]
top_WT_heatmap <- top_WT_heatmap %>%
as.data.frame() %>%
head(50)
top_WT_heatmap
top_WT_heatmap <- top_WT_heatmap[order(top_WT_heatmap$log2FoldChange, decreasing = TRUE),]
#get normalized count data from vst object
mat <- assay(vsdata_D2)[rownames(top_WT_heatmap), metadata_D2$Run]
colnames(mat) <- metadata_D2$Run
base_mean <- rowMeans(mat)
mat.scaled <- t(apply(mat, 1, scale)) #center and scale each column (Z-score) then transpose
colnames(mat.scaled)<-colnames(mat)
num_keep <- 25
#1 to num_keep len-num_keep to len
rows_keep <- c(seq(1:num_keep), seq((nrow(mat.scaled)-num_keep), nrow(mat.scaled)) )
l2_val <- as.matrix(top_WT_heatmap[rows_keep,]$log2FoldChange) #getting log2 value for each gene we are keeping
colnames(l2_val)<-"logFC"
mean <- as.matrix(top_WT_heatmap[rows_keep,]$baseMean) #getting mean value for each gene we are keeping
colnames(mean)<-"AveExpr"
library(ComplexHeatmap)
library(RColorBrewer)
library(circlize)
#maps values between b/w/r for min and max l2 values
col_logFC <- colorRamp2(c(min(l2_val),0, max(l2_val)), c("blue", "white", "red"))
#maps between 0% quantile, and 75% quantile of mean values --- 0, 25, 50, 75, 100
col_AveExpr <- colorRamp2(c(quantile(mean)[1], quantile(mean)[4]), c("white", "red"))
col_zscore <- colorRamp2(c(-2, 0, 2), c("#4575b4", "white", "#d73027"))
ha <- HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2),
height = unit(2, "cm")))
h1 <- Heatmap(mat.scaled[rows_keep,],
cluster_rows = TRUE, # Enable clustering for better grouping
column_labels = colnames(mat.scaled),
name="Z-score",
col = col_zscore, # Add color scheme
cluster_columns = TRUE,
show_row_names = FALSE, # Clean up row names
column_names_gp = gpar(fontsize = 9),
heatmap_legend_param = list(title_gp = gpar(fontsize = 10)))
h2 <- Heatmap(l2_val,
row_labels = top_WT_heatmap$gene_symbol_D2[rows_keep], # Use gene symbols
cluster_rows = FALSE,
name="logFC",
col = col_logFC,
width = unit(15, "mm"), # Fixed width
show_column_names = TRUE,
row_names_gp = gpar(fontsize = 8), # Smaller font for gene names
column_names_gp = gpar(fontsize = 9),
cell_fun = function(j, i, x, y, w, h, col) {
grid.text(round(l2_val[i, j], 1), x, y, gp = gpar(fontsize = 7)) # Smaller text
})
h3 <- Heatmap(mean,
row_labels = top_WT_heatmap$gene_symbol[rows_keep],
cluster_rows = FALSE,
name = "AveExpr",
col = col_AveExpr,
width = unit(15, "mm"), # Fixed width
show_row_names = TRUE, # Don't repeat gene names
show_column_names = TRUE,
column_names_gp = gpar(fontsize = 9),
row_names_gp = gpar(fontsize = 7),
cell_fun = function(j, i, x, y, w, h, col) {
grid.text(round(mean[i, j], 0), x, y, gp = gpar(fontsize = 7)) # Round to whole numbers
})
h_D2<-h1+h2+h3
h_D2
pdf("AnnotatedHeatmap_D2.pdf", width = 10, height = 6)
draw(h_D2)
dev.off()
png("AnnotatedHeatmap_D2.png", width = 3000, height = 2000, res = 300)
draw(h_D2)
dev.off()
#heatmap - for understanding experimental design
top_genes_heatmap_WT_D2 <- head(order(res_WT_vs_del19_D2$log2FoldChange, decreasing = TRUE), 50)
png("Top50_Heatmap_D2.png", width = 2000, height = 1600, res = 300)
pheatmap::pheatmap(assay(vsdata_D2)[top_genes_heatmap_WT_D2,],
annotation_col = as.data.frame(colData(dds_D2)[,c("tissue", "egfr_mutation")]),
scale = "row",
show_rownames = FALSE,
main = "Top 50 DEGs: WT vs Exon 19 Deletion",
cluster_cols = TRUE)
dev.off()
Pathway Analysis
#loading pathway analysis packages
library(DOSE)
library(enrichplot)
library(clusterProfiler)
# I'm separating upregulated and downregulated genes
sig_genes_up_WT_D2 <- rownames(sig_WT_D2)[sig_WT_D2$log2FoldChange > 1]
sig_genes_down_WT_D2 <- rownames(sig_WT_D2)[sig_WT_D2$log2FoldChange < -1]
print(paste("Upregulated:", length(sig_genes_up_WT_D2)))
print(paste("Downregulated:", length(sig_genes_down_WT_D2)))
# I'm converting ENSEMBL to ENTREZ for KEGG analysis
entrez_genes_up_WT_D2 <- mapIds(org.Hs.eg.db, sig_genes_up_WT_D2, "ENTREZID", "ENSEMBL")
entrez_genes_down_WT_D2 <- mapIds(org.Hs.eg.db, sig_genes_down_WT_D2, "ENTREZID", "ENSEMBL")
entrez_genes_up_WT_D2 <- entrez_genes_up_WT_D2[!is.na(entrez_genes_up_WT_D2)]
entrez_genes_down_WT_D2 <- entrez_genes_down_WT_D2[!is.na(entrez_genes_down_WT_D2)]
# I'm running GO Analysis
go_up_WT_D2 <- enrichGO(gene = sig_genes_up_WT_D2,
OrgDb = org.Hs.eg.db,
keyType = "ENSEMBL",
ont = "ALL", # BP, CC, MF
pAdjustMethod = "BH",
pvalueCutoff = 0.05)
as.data.frame(go_up_WT_D2)
top_go_up_D2 <- go_up_WT_D2@result[1:10, ]
as.data.frame(top_go_up_D2)
p1_D2 <- plot(barplot(go_up_WT_D2, showCategory = 15)+labs(title = "Upregulated GO Terms (WT vs Del19)"))
ggsave("GO_WT_Upregulated_D2.pdf", p1_D2, width = 7, height = 6)
ggsave("GO_WT_Upregulated_D2.png", p1_D2, width = 7, height = 6, dpi = 300)
go_down_WT_D2 <- enrichGO(gene = sig_genes_down_WT_D2,
OrgDb = org.Hs.eg.db,
keyType = "ENSEMBL",
ont = "ALL",
pAdjustMethod = "BH",
pvalueCutoff = 0.05)
as.data.frame(go_down_WT_D2)
top_go_down_D2 <- go_down_WT_D2@result[1:10, ]
as.data.frame(top_go_down_D2)
p2_D2 <- plot(barplot(go_down_WT_D2, showCategory = 15)+labs(title = "Downregulated GO Terms (WT vs Del19)"))
ggsave("GO_WT_Downregulated_D2.pdf", p2_D2, width = 7, height = 6)
ggsave("GO_WT_Downregulated_D2.png", p2_D2, width = 7, height = 6, dpi = 300)
#running KEGG Pathway Analysis
kegg_up_WT_D2 <- enrichKEGG(gene = entrez_genes_up_WT_D2,
organism = 'hsa',
pvalueCutoff = 0.05,
pAdjustMethod = "BH")
as.data.frame(kegg_up_WT_D2)
top_kegg_up_D2 <- kegg_up_WT_D2@result[1:10, ]
as.data.frame(top_kegg_up_D2)
p3_D2 <- plot(barplot(kegg_up_WT_D2, showCategory = 15)+labs(title = "Upregulated KEGG Pathways (WT vs Del19)"))
ggsave("KEGG_WT_Upregulated_D2.pdf", p3_D2, width = 7, height = 6)
ggsave("KEGG_WT_Upregulated_D2.png", p3_D2, width = 7, height = 6, dpi = 300)
kegg_down_WT_D2 <- enrichKEGG(gene = entrez_genes_down_WT_D2,
organism = 'hsa',
pvalueCutoff = 0.05,
pAdjustMethod = "BH")
as.data.frame(kegg_down_WT_D2)
top_kegg_up_D2 <- kegg_up_WT_D2@result[1:10, ]
as.data.frame(top_kegg_up_D2)
p4_D2 <- plot(barplot(kegg_down_WT_D2, showCategory = 15)+labs(title = "Downregulated KEGG Pathways (WT vs Del19)"))
ggsave("KEGG_WT_Downregulated_D2.pdf", p4_D2, width = 7, height = 6)
ggsave("KEGG_WT_Downregulated_D2.png", p4_D2, width = 7, height = 6, dpi = 300)
#loading GSEA packages
library(fgsea)
library(msigdbr)
#preparing ranked gene list for GSEA
gene_ranks_WT_D2 <- res_WT_vs_del19_D2$log2FoldChange
names(gene_ranks_WT_D2) <- rownames(res_WT_vs_del19_D2)
gene_ranks_WT_D2 <- gene_ranks_WT_D2[!is.na(gene_ranks_WT_D2)]
gene_ranks_WT_D2 <- sort(gene_ranks_WT_D2, decreasing = TRUE)
#getting Hallmark pathways for GSEA
gse_D2 <- gseGO(gene_ranks_WT_D2,
ont = "BP",
keyType = "ENSEMBL",
OrgDb = "org.Hs.eg.db",
eps = 1e-300)
as.data.frame(gse_D2)
gse_plot_D2 <- gseaplot(gse_D2, geneSetID = 1)
gse_plot_D2
ggsave("GSEA_pathway_D2.pdf", gse_plot_D2, width = 7, height = 6)
ggsave("GSEA_pathway_D2.png", gse_plot_D2, width = 7, height = 6, dpi = 300)

hallmark_sets_D2 <- msigdbr(species = "Homo sapiens", category = "H")
hallmark_list_D2 <- split(hallmark_sets_D2$ensembl_gene, hallmark_sets_D2$gs_name)
#running GSEA analysis
fgsea_results_WT_D2 <- fgsea(pathways = hallmark_list_D2,
stats = gene_ranks_WT_D2,
minSize = 15,
maxSize = 500)
print(head(fgsea_results_WT_D2[order(pval), ], 10))
#plotting top 3 pathways
print("Top 3 GSEA pathways:")
[1] "Top 3 GSEA pathways:"
top_pathways_D2 <- head(fgsea_results_WT_D2[order(pval), ], 3)
print(top_pathways_D2[, c("pathway", "pval", "NES")])
for(i in 1:3) {
pathway_name <- top_pathways_D2$pathway[i]
pathways_D2 <- plotEnrichment(hallmark_list_D2[[pathway_name]], gene_ranks_WT_D2) +
labs(title = paste("Pathway", i, ":", pathway_name))
print(pathways_D2)
ggsave("Top3_GSEA_D2.pdf", pathways_D2, width = 7, height = 6)
ggsave("Top3_GSEA_D2.png", pathways_D2, width = 7, height = 6, dpi = 300)
}



# Summary statistics table for D2
summary_stats_D2 <- data.frame(
Metric = c("Total Samples", "Genes Analyzed", "Significant DEGs - WT vs Deletion 19", "Upregulated - WT vs Deletion 19", "Downregulated - WT vs Deletion 19"),
Value = c(ncol(counts_D2),
nrow(dds_D2),
nrow(sig_WT_D2),
length(sig_genes_up_WT_D2),
length(sig_genes_down_WT_D2))
)
summary_stats_D2
# Top genes table
top_genes_table_D2 <- data.frame(
Gene_Symbol = gene_symbols_D2[rownames(head(sig_WT_D2[order(sig_WT_D2$padj),], 20))],
ENSEMBL_ID = rownames(head(sig_WT_D2[order(sig_WT_D2$padj),], 20)),
Log2FC = round(head(sig_WT_D2[order(sig_WT_D2$padj),], 20)$log2FoldChange, 3),
Padj = format(head(sig_WT_D2[order(sig_WT_D2$padj),], 20)$padj, scientific = TRUE, digits = 3),
Direction = ifelse(head(sig_WT_D2[order(sig_WT_D2$padj),], 20)$log2FoldChange > 0, "Up", "Down")
)
print("Top 20 Significant Genes: WT vs Deletion 19")
print(top_genes_table_D2)
# Export main results
write.csv(as.data.frame(res_WT_vs_del19_D2), "D2_WT_annotated_results.csv", row.names = TRUE)
write.csv(sig_WT_D2, "D2_WT_significant_genes.csv", row.names = TRUE)
write.csv(summary_stats_D2, "D2_summary_statistics.csv", row.names = FALSE)
write.csv(top_genes_table_D2, "D2_top20_genes.csv", row.names = FALSE)
# Export normalized data
write.csv(res_annotated_D2, "D2_results.csv")
write.csv(counts(dds_D2, normalized=TRUE), "D2_normalized_counts.csv", row.names = TRUE)
write.csv(vst_final_D2, "D2_vst_data.csv", row.names = TRUE)
# Export pathway results
if(nrow(go_up_WT_D2@result) > 0) {
write.csv(go_up_WT_D2@result, "D2_GO_upregulated.csv", row.names = FALSE)
}
if(nrow(go_down_WT_D2@result) > 0) {
write.csv(go_down_WT_D2@result, "D2_GO_downregulated.csv", row.names = FALSE)
}
if(nrow(kegg_up_WT_D2@result) > 0) {
write.csv(kegg_up_WT_D2@result, "D2_KEGG_upregulated.csv", row.names = FALSE)
}
if(nrow(kegg_down_WT_D2@result) > 0) {
write.csv(kegg_down_WT_D2@result, "D2_KEGG_downregulated.csv", row.names = FALSE)
}
# Remove the leadingEdge column (which contains lists)
fgsea_results_clean_D2 <- fgsea_results_WT_D2 %>%
select(-leadingEdge)
write.csv(fgsea_results_clean_D2, "D2_GSEA_hallmarks.csv", row.names = FALSE)
LS0tDQp0aXRsZTogIkRhdGFzZXQgMiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyfQ0KbGlicmFyeShERVNlcTIpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KYGBge3J9DQojIExvYWRpbmcgbXkgZGF0YXNldCAmIG1ldGFkYXRhDQpjb3VudHNfRDIgPC0gcmVhZC5kZWxpbSgiY291bnRzX0QyIiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gMSkNCm1ldGFkYXRhX0QyIDwtIHJlYWQuY3N2KCJtZXRhZGF0YV9EMi5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KDQpgYGANCg0KYGBge3J9DQoNCiNjaGVja2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGNvdW50cyBpbiBteSBkYXRhc2V0DQp0b3RhbF9jb3VudHNfcGVyX2dlbmVfRDIgPC0gcm93U3Vtcyhjb3VudHNfRDIpDQpoaXN0KHRvdGFsX2NvdW50c19wZXJfZ2VuZV9EMiwgDQogICAgIGJyZWFrcz0xMDAsIA0KICAgICBtYWluPSJEaXN0cmlidXRpb24gb2YgVG90YWwgQ291bnRzIHBlciBHZW5lIC0gRGF0YXNldCAyIiwgDQogICAgIHhsYWI9IlRvdGFsIGNvdW50cyBhY3Jvc3MgYWxsIHNhbXBsZXMiLA0KICAgICB5bGFiPSJOdW1iZXIgb2YgZ2VuZXMiKQ0Kc3VtbWFyeSh0b3RhbF9jb3VudHNfcGVyX2dlbmVfRDIpDQpgYGANCg0KYGBge3J9DQojaWdub3JpbmcgbG93IGV4cHJlc3NlZCBnZW5lIHRvIHJlbW92ZSBub2lzZSAmIGdldCBiZXR0ZXIgcmVzdWx0cw0KDQpwcmludChwYXN0ZSgiR2VuZXMgYmVmb3JlIGZpbHRlcmluZzoiLCBucm93KGNvdW50c19EMikpKQ0KY291bnRzX0QyIDwtIGNvdW50c19EMlt3aGljaChyb3dTdW1zKGNvdW50c19EMikgPiA1MCksIF0NCnByaW50KHBhc3RlKCJHZW5lcyBhZnRlciBmaWx0ZXJpbmc6IiwgbnJvdyhjb3VudHNfRDIpKSkNCmBgYA0KDQpgYGB7cn0NCiNuZWVkIHRvIHJvdW5kIGNvdW50cyBmb3IgREVTZXEyIGNvbXBhdGliaWxpdHkNCmNvdW50c19EMiA8LSByb3VuZChjb3VudHNfRDIpDQoNCmxpYnJhcnkoREVTZXEyKQ0KDQojY3JlYXRpbmcgREVTZXEyIG9iamVjdCB3aXRoIGludGVyYWN0aW9uIGRlc2lnbg0KZGRzX0QyIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzX0QyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YWRhdGFfRDIsICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiB0aXNzdWUgKyBlZ2ZyX211dGF0aW9uICsgdGlzc3VlOmVnZnJfbXV0YXRpb24pDQpkZHNfRDINCg0KI3J1bm5pbmcgdGhlIG1haW4gREVTZXEyIGFuYWx5c2lzDQpkZHNfRDIgPC0gREVTZXEoZGRzX0QyKQ0KDQojY3JlYXRpbmcgdmFyaWFuY2Ugc3RhYmlsaXplZCBkYXRhIGZvciB2aXN1YWxpemF0aW9uDQp2c2RhdGFfRDIgPC0gdnN0KGRkc19EMiwgYmxpbmQgPSBUUlVFKQ0KcmVzdWx0c05hbWVzKGRkc19EMikNCg0KdnN0X21hdHJpeF9EMiA8LSBhc3NheSh2c2RhdGFfRDIpDQoNCmhlYWQodnN0X21hdHJpeF9EMlsxOjUsIDE6M10pIA0KDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KDQp2c3RfZGZfRDIgPC0gYXMuZGF0YS5mcmFtZSh2c3RfbWF0cml4X0QyKQ0KdnN0X2RmX0QyJGdlbmVfaWQgPC0gcm93bmFtZXModnN0X2RmX0QyKQ0KDQp2c3RfZmluYWxfRDIgPC0gbWVsdCh2c3RfZGZfRDIsIA0KICAgICAgICAgICAgICAgICBpZC52YXJzID0gImdlbmVfaWQiLCANCiAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJzYW1wbGVfaWQiLCANCiAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJleHByZXNzaW9uX3ZhbHVlIikNCg0KIyBDaGVjayB0aGUgcmVzdWx0IC0gc2hvdWxkIGhhdmUgZXhhY3RseSAzIGNvbHVtbnMNCmhlYWQodnN0X2ZpbmFsX0QyKQ0KDQpyZXN1bHRzX1dUX0QyIDwtIHJlc3VsdHMoZGRzX0QyLCBuYW1lID0gImVnZnJfbXV0YXRpb25fV2lsZC50eXBlX3ZzX0V4b24uMTkuZGVsZXRpb24iKQ0KDQojU0FOSVRZIENIRUNLUyAtIGJlY2F1c2UgdGhlcmUncyBvbmx5IDEgcmVwbGljYXRlIGZvciBlYWNoIG11dGF0aW9uIHR5cGUNCiNtbSA8LSBtb2RlbC5tYXRyaXgoZGVzaWduKGRkc19EMiksIGNvbERhdGEoZGRzX0QyKSkNCiNxcihtbSkkcmFuaw0KI25jb2wobW0pDQoNCiMgQWZ0ZXIgcnVubmluZyBERVNlcShkZHNfRDIpDQojcmVzIDwtIHJlc3VsdHMoZGRzX0QyLCBuYW1lID0gImVnZnJfbXV0YXRpb25fV2lsZC50eXBlX3ZzX0V4b24uMTkuZGVsZXRpb24iKQ0KI3N1bW1hcnkocmVzKQ0KDQojKGhpc3QocmVzJHB2YWx1ZSwgYnJlYWtzPTUwKSkNCg0KI3Jlc0xGQyA8LSBsZmNTaHJpbmsoZGRzX0QyLCBjb2VmPSJlZ2ZyX211dGF0aW9uX1dpbGQudHlwZV92c19FeG9uLjE5LmRlbGV0aW9uIiwgdHlwZT0iYXBlZ2xtIikNCiNwbG90TUEocmVzTEZDKQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpwbG90RGlzcEVzdHMoZGRzX0QyKQ0KDQojIFNhdmUgYXMgUERGDQpwZGYoIkRpc3BlcnNpb25QbG90X0QyLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkNCnBsb3REaXNwRXN0cyhkZHNfRDIpDQpkZXYub2ZmKCkNCg0KIyBPciBzYXZlIGFzIGhpZ2gtcmVzb2x1dGlvbiBQTkcNCnBuZygiRGlzcGVyc2lvblBsb3RfRDIucG5nIiwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNjAwLCByZXMgPSAzMDApDQpwbG90RGlzcEVzdHMoZGRzX0QyKQ0KZGV2Lm9mZigpDQpgYGANCg0KYGBge3J9DQojY3JlYXRpbmcgYW4gZW5oYW5jZWQgUENBIHBsb3QgdG8gc2VlIHNhbXBsZSBjbHVzdGVyaW5nDQpwY2FfZGF0YV9EMiA8LSBwbG90UENBKHZzZGF0YV9EMiwgaW50Z3JvdXAgPSBjKCJ0aXNzdWUiLCAiZWdmcl9tdXRhdGlvbiIpLCByZXR1cm5EYXRhID0gVFJVRSkNCg0KcGNhX3Bsb3RfRDIgPC0gZ2dwbG90KHBjYV9kYXRhX0QyLCBhZXMoUEMxLCBQQzIsIGNvbG9yID0gaW50ZXJhY3Rpb24oZWdmcl9tdXRhdGlvbiwgdGlzc3VlKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjgpICsNCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcm91bmQoMTAwICogYXR0cihwY2FfZGF0YV9EMiwgInBlcmNlbnRWYXIiKVsxXSksICIlIHZhcmlhbmNlIikpICsNCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcm91bmQoMTAwICogYXR0cihwY2FfZGF0YV9EMiwgInBlcmNlbnRWYXIiKVsyXSksICIlIHZhcmlhbmNlIikpICsNCiAgbGFicyh0aXRsZSA9ICJQQ0EgLSBEYXRhc2V0IDI6IEVHRlIgTXV0YXRpb25zIGFuZCBUaXNzdWUgVHlwZXMiLA0KICAgICAgIGNvbG9yID0gIkdyb3VwIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KcGNhX3Bsb3RfRDINCg0KI3NhdmluZyBQQ0EgcGxvdCBpbiBwZGYgJiBwbmcgDQpnZ3NhdmUoKCJEMl9QQ0EucGRmIiksIHBjYV9wbG90X0QyLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpnZ3NhdmUoKCJEMl9QQ0EucG5nIiksIHBjYV9wbG90X0QyLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkNCmBgYA0KDQpgYGB7cn0NCiNsb2FkaW5nIHBoZWF0bWFwIGZvciBzYW1wbGUgZGlzdGFuY2UgdmlzdWFsaXphdGlvbg0KbGlicmFyeShwaGVhdG1hcCkNCg0KI2NyZWF0aW5nIHNhbXBsZSBkaXN0YW5jZSBoZWF0bWFwDQpzYW1wbGVfZGlzdGFuY2VzX0QyIDwtIGRpc3QodChhc3NheSh2c2RhdGFfRDIpKSkNCnNhbXBsZURpc3RNYXRyaXhfRDIgPC0gYXMubWF0cml4KHNhbXBsZV9kaXN0YW5jZXNfRDIpDQpwaGVhdG1hcDo6cGhlYXRtYXAoc2FtcGxlRGlzdE1hdHJpeF9EMiwNCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9IHNhbXBsZV9kaXN0YW5jZXNfRDIsDQogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSBzYW1wbGVfZGlzdGFuY2VzX0QyLA0KICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoZGRzX0QyKVssYygidGlzc3VlIiwgImVnZnJfbXV0YXRpb24iKV0pLA0KICAgICAgICAgbWFpbiA9ICJTYW1wbGUtdG8tU2FtcGxlIERpc3RhbmNlcyAtIERhdGFzZXQgMiIsDQogICAgICAgICBmaWxlbmFtZSA9ICJTYW1wbGVEaXN0YW5jZXNfRDIucG5nIikNCmBgYA0KDQoNCmBgYHtyfQ0KcmVzdWx0c05hbWVzKGRkc19EMikNCnN1bW1hcnlfcmVzX0QyIDwtIHJlc3VsdHMoZGRzX0QyLCBuYW1lID0gImVnZnJfbXV0YXRpb25fV2lsZC50eXBlX3ZzX0V4b24uMTkuZGVsZXRpb24iICkNCnN1bW1hcnkoc3VtbWFyeV9yZXNfRDIpDQpgYGANCg0KYGBge3J9DQojTk9OLU5FR09USUFCTEUgZm9yIHJlbGlhYmxlIHJlc3VsdHMNCmxpYnJhcnkoYXBlZ2xtKQ0KDQojIFNocmluayBjb2VmZmljaWVudHMgZm9yIGFsbCBtYWluIGNvbXBhcmlzb25zDQoNCnJlc19XVF92c19kZWwxOV9EMiA8LSBsZmNTaHJpbmsoZGRzX0QyLCBjb2VmPSJlZ2ZyX211dGF0aW9uX1dpbGQudHlwZV92c19FeG9uLjE5LmRlbGV0aW9uIiwgdHlwZT0iYXBlZ2xtIikgI3ByaW1hcnkgY29tcGFyaXNvbg0KcmVzX3Rpc3N1ZV9EMiA8LSBsZmNTaHJpbmsoZGRzX0QyLCBjb2VmPSJ0aXNzdWVfU3VyZ2ljYWxseS5yZXNlY3RlZC50dW1vcl92c19QYXRpZW50LmRlcml2ZWQueGVub2dyYWZ0LnR1bW9yIiwgdHlwZT0iYXBlZ2xtIikNCnJlc18yMV92c19kZWwxOV9EMiA8LSBsZmNTaHJpbmsoZGRzX0QyLCBjb2VmPSJlZ2ZyX211dGF0aW9uX0V4b24uMjEuTDg1OFJfdnNfRXhvbi4xOS5kZWxldGlvbiIsIHR5cGU9ImFwZWdsbSIpDQoNCiMgSW50ZXJhY3Rpb24gZWZmZWN0cyAodGlzc3VlLXNwZWNpZmljIG11dGF0aW9uIGVmZmVjdHMpDQpyZXNfaW50ZXJhY3Rpb25fMjFfRDIgPC0gbGZjU2hyaW5rKGRkc19EMiwgY29lZj0idGlzc3VlU3VyZ2ljYWxseS5yZXNlY3RlZC50dW1vci5lZ2ZyX211dGF0aW9uRXhvbi4yMS5MODU4UiIsIHR5cGU9ImFwZWdsbSIpDQpyZXNfaW50ZXJhY3Rpb25fV1RfRDIgPC0gbGZjU2hyaW5rKGRkc19EMiwgY29lZj0idGlzc3VlU3VyZ2ljYWxseS5yZXNlY3RlZC50dW1vci5lZ2ZyX211dGF0aW9uV2lsZC50eXBlIiwgdHlwZT0iYXBlZ2xtIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShBbm5vdGF0aW9uRGJpKQ0KbGlicmFyeShvcmcuSHMuZWcuZGIpDQoNCiNjb252ZXJ0aW5nIEVOU0VNQkwgSURzIHRvIGdlbmUgc3ltYm9scw0KZ2VuZV9zeW1ib2xzX0QyIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsDQogICAgICAgICAgICAgICAgICAgICAgICAga2V5cyA9IHJvd25hbWVzKGRkc19EMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uID0gIlNZTUJPTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAga2V5dHlwZSA9ICJFTlNFTUJMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aVZhbHMgPSAiZmlyc3QiKQ0KcmVzX2Fubm90YXRlZF9EMiA8LSByZXN1bHRzX1dUX0QyDQpyZXNfYW5ub3RhdGVkX0QyJGdlbmVfc3ltYm9sIDwtIGdlbmVfc3ltYm9sc19EMg0KYXMuZGF0YS5mcmFtZShyZXNfYW5ub3RhdGVkX0QyKQ0KDQojYWRkaW5nIGFubm90YXRpb25zIHRvIGFsbCBteSBpbXBvcnRhbnQgcmVzdWx0cw0KcmVzQW5ub3RhdGVfV1RfRDIgPC0gcmVzX1dUX3ZzX2RlbDE5X0QyDQpyZXNBbm5vdGF0ZV9XVF9EMiRnZW5lX3N5bWJvbCA8LSBnZW5lX3N5bWJvbHNfRDINCg0KcmVzQW5ub3RhdGVfdGlzc3VlX0QyIDwtIHJlc190aXNzdWVfRDINCnJlc0Fubm90YXRlX3Rpc3N1ZV9EMiRnZW5lX3N5bWJvbCA8LSBnZW5lX3N5bWJvbHNfRDINCg0KcmVzQW5ub3RhdGVfMjFfRDIgPC0gcmVzXzIxX3ZzX2RlbDE5X0QyDQpyZXNBbm5vdGF0ZV8yMV9EMiRnZW5lX3N5bWJvbCA8LSBnZW5lX3N5bWJvbHNfRDINCg0KYGBgDQoNCg0KYGBge3J9DQojIFN1bW1hcnkgc3RhdGlzdGljcyBmb3IgZWFjaCBjb21wYXJpc29uDQpzdW1tYXJ5KHJlc190aXNzdWVfRDIsIGFscGhhPTAuMDUpDQpzdW1tYXJ5KHJlc18yMV92c19kZWwxOV9EMiwgYWxwaGE9MC4wNSkNCnN1bW1hcnkocmVzX1dUX3ZzX2RlbDE5X0QyLCBhbHBoYT0wLjA1KQ0Kc3VtbWFyeShyZXNfaW50ZXJhY3Rpb25fMjFfRDIsIGFscGhhPTAuMDUpDQpzdW1tYXJ5KHJlc19pbnRlcmFjdGlvbl9XVF9EMiwgYWxwaGE9MC4wNSkNCg0KIyBFeHRyYWN0IHNpZ25pZmljYW50IGdlbmVzIChwYWRqIDwgMC4wNSwgfExGQ3wgPiAxKQ0Kc2lnX3Rpc3N1ZV9EMiA8LSByZXNfdGlzc3VlX0QyW3doaWNoKHJlc190aXNzdWVfRDIkcGFkaiA8IDAuMDUgJiBhYnMocmVzX3Rpc3N1ZV9EMiRsb2cyRm9sZENoYW5nZSkgPiAxKSwgXQ0Kc2lnXzIxX0QyIDwtIHJlc18yMV92c19kZWwxOV9EMlt3aGljaChyZXNfMjFfdnNfZGVsMTlfRDIkcGFkaiA8IDAuMDUgJiBhYnMocmVzXzIxX3ZzX2RlbDE5X0QyJGxvZzJGb2xkQ2hhbmdlKSA+IDEpLCBdDQpzaWdfV1RfRDIgPC0gcmVzX1dUX3ZzX2RlbDE5X0QyW3doaWNoKHJlc19XVF92c19kZWwxOV9EMiRwYWRqIDwgMC4wNSAmIGFicyhyZXNfV1RfdnNfZGVsMTlfRDIkbG9nMkZvbGRDaGFuZ2UpID4gMSksIF0NCg0KIyBTZWUgaG93IG1hbnkgc2lnbmlmaWNhbnQgZ2VuZXMgaW4gZWFjaCBjb21wYXJpc29uDQpucm93KHNpZ190aXNzdWVfRDIpICAgICMgVGlzc3VlIGVmZmVjdCBnZW5lcw0KbnJvdyhzaWdfMjFfRDIpICAgICAjIEw4NThSIHZzIERlbDE5IGdlbmVzICANCm5yb3coc2lnX1dUX0QyKSAgICAgICAgIyBXVCB2cyBEZWwxOSBnZW5lcyAoeW91ciBkcnVnIHRhcmdldHMhKQ0KDQoNCg0KYGBgDQoNCmBgYHtyfQ0KIyBBbHNvIGNvbXBsZXRlIHRoZSBpbnRlcmFjdGlvbiBleHRyYWN0aW9ucw0Kc2lnX2ludGVyYWN0aW9uXzIxX0QyIDwtIHJlc19pbnRlcmFjdGlvbl8yMV9EMlt3aGljaChyZXNfaW50ZXJhY3Rpb25fMjFfRDIkcGFkaiA8IDAuMDUgJiBhYnMocmVzX2ludGVyYWN0aW9uXzIxX0QyJGxvZzJGb2xkQ2hhbmdlKSA+IDAuNSksIF0NCnNpZ19pbnRlcmFjdGlvbl9XVF9EMiA8LSByZXNfaW50ZXJhY3Rpb25fV1RfRDJbd2hpY2gocmVzX2ludGVyYWN0aW9uX1dUX0QyJHBhZGogPCAwLjA1ICYgYWJzKHJlc19pbnRlcmFjdGlvbl9XVF9EMiRsb2cyRm9sZENoYW5nZSkgPiAwLjUpLCBdDQoNCm5yb3coc2lnX2ludGVyYWN0aW9uXzIxX0QyKSAgIyBIb3cgbWFueSBpbnRlcmFjdGlvbiBnZW5lcw0KbnJvdyhzaWdfaW50ZXJhY3Rpb25fV1RfRDIpDQpgYGANClZpc3VhbGl6YXRpb24gUGxvdHMNCmBgYHtyfQ0KIyBNQSBwbG90cyBmb3IgZWFjaCBjb21wYXJpc29uDQpwbG90TUEocmVzX3Rpc3N1ZV9EMiwgeWxpbT1jKC01LDUpLCBtYWluPSJUaXNzdWUgRWZmZWN0IikNCnBsb3RNQShyZXNfMjFfdnNfZGVsMTlfRDIsIHlsaW09YygtNSw1KSwgbWFpbj0iTDg1OFIgdnMgRGVsMTkiKQ0KcGxvdE1BKHJlc19XVF92c19kZWwxOV9EMiwgeWxpbT1jKC01LDUpLCBtYWluPSJXaWxkIFR5cGUgdnMgRGVsMTkiKQ0KDQpwZGYoKCJNQV9yZXNfdGlzc3VlX0QyLnBkZiIpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpwbG90TUEocmVzX3Rpc3N1ZV9EMiwgeWxpbT1jKC01LDUpLCBtYWluPSJUaXNzdWUgRWZmZWN0IikNCmRldi5vZmYoKQ0KDQpwbmcoKCJNQV9yZXNfdGlzc3VlX0QyLnBuZyIpLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE2MDAsIHJlcyA9IDMwMCkNCnBsb3RNQShyZXNfdGlzc3VlX0QyLCB5bGltPWMoLTUsNSksIG1haW49IlRpc3N1ZSBFZmZlY3QiKQ0KZGV2Lm9mZigpDQoNCnBkZigoIk1BX3Jlc18yMV92c19kZWwxOV9EMi5wZGYiKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQ0KcGxvdE1BKHJlc18yMV92c19kZWwxOV9EMiwgeWxpbT1jKC01LDUpLCBtYWluPSJMODU4UiB2cyBEZWwxOSIpDQpkZXYub2ZmKCkNCg0KcG5nKCgiTUFfcmVzXzIxX3ZzX2RlbDE5X0QyLnBuZyIpLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE2MDAsIHJlcyA9IDMwMCkNCnBsb3RNQShyZXNfMjFfdnNfZGVsMTlfRDIsIHlsaW09YygtNSw1KSwgbWFpbj0iTDg1OFIgdnMgRGVsMTkiKQ0KZGV2Lm9mZigpDQoNCnBkZigoIk1BX3Jlc19XVF92c19kZWwxOV9EMi5wZGYiKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQ0KcGxvdE1BKHJlc19XVF92c19kZWwxOV9EMiwgeWxpbT1jKC01LDUpLCBtYWluPSJXaWxkIFR5cGUgdnMgRGVsMTkiKQ0KZGV2Lm9mZigpDQoNCnBuZygoIk1BX3Jlc19XVF92c19kZWwxOV9EMi5wbmciKSwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNjAwLCByZXMgPSAzMDApDQpwbG90TUEocmVzX1dUX3ZzX2RlbDE5X0QyLCB5bGltPWMoLTUsNSksIG1haW49IldpbGQgVHlwZSB2cyBEZWwxOSIpDQpkZXYub2ZmKCkNCg0KIyBWb2xjYW5vIHBsb3RzDQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykNCg0KdG9wX2dlbmVzX1dUX0QyIDwtIHJvd25hbWVzKHJlc0Fubm90YXRlX1dUX0QyW29yZGVyKHJlc0Fubm90YXRlX1dUX0QyJHBhZGopLCBdWzE6NTAsIF0pDQoNCnZvbGNhbm9fV1RfRDIgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc0Fubm90YXRlX1dUX0QyLA0KICAgICAgICAgICAgICAgIGxhYiA9IHJlc0Fubm90YXRlX1dUX0QyJGdlbmVfc3ltYm9sLA0KICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLA0KICAgICAgICAgICAgICAgIHkgPSAncGFkaicsDQogICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gcmVzQW5ub3RhdGVfV1RfRDIkZ2VuZV9zeW1ib2xbcm93bmFtZXMocmVzQW5ub3RhdGVfV1RfRDIpICVpbiUgdG9wX2dlbmVzX1dUX0QyXSwNCiAgICAgICAgICAgICAgICB0aXRsZSA9ICdXaWxkIFR5cGUgdnMgRXhvbiAxOSBEZWxldGlvbiAoRHJ1ZyBSZXNpc3RhbmNlKScpDQpwcmludCh2b2xjYW5vX1dUX0QyKQ0KDQpnZ3NhdmUoKCJEMl9Wb2xjYW5vLnBkZiIpLCB2b2xjYW5vX1dUX0QyLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpnZ3NhdmUoKCJEMl9Wb2xjYW5vLnBuZyIpLCB2b2xjYW5vX1dUX0QyLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkNCg0KIyBIZWF0bWFwIG9mIHRvcCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgLSB3aXRoIHZhbHVlcyAmIGdlbmVzDQpsaWJyYXJ5KHBoZWF0bWFwKQ0KDQprZXlzIDwtIHJvd25hbWVzKHJlc0Fubm90YXRlX1dUX0QyKQ0KdmFsdWVzIDwtIHJlc0Fubm90YXRlX1dUX0QyJGdlbmVfc3ltYm9sDQoNCmwgPC0gbGlzdCgpDQpmb3IgKGkgaW4gMTpsZW5ndGgoa2V5cykpew0KICBsW2tleXNbaV1dIDwtIHZhbHVlc1tpXQ0KfQ0KbA0KbGlicmFyeShkcGx5cikNCg0KdG9wX1dUX2hlYXRtYXAgPC0gcmVzQW5ub3RhdGVfV1RfRDJbIWlzLm5hKHJlc0Fubm90YXRlX1dUX0QyJHBhZGopICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEocmVzQW5ub3RhdGVfV1RfRDIkYmFzZU1lYW4pICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEocmVzQW5ub3RhdGVfV1RfRDIkbG9nMkZvbGRDaGFuZ2UpICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZXNBbm5vdGF0ZV9XVF9EMiRwYWRqIDwgMC4wNSkgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZXNBbm5vdGF0ZV9XVF9EMiRiYXNlTWVhbiA+IDUwKSAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGFicyhyZXNBbm5vdGF0ZV9XVF9EMiRsb2cyRm9sZENoYW5nZSkgPiAyKSxdDQp0b3BfV1RfaGVhdG1hcCA8LSB0b3BfV1RfaGVhdG1hcCAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBoZWFkKDUwKSAgDQp0b3BfV1RfaGVhdG1hcA0KdG9wX1dUX2hlYXRtYXAgPC0gdG9wX1dUX2hlYXRtYXBbb3JkZXIodG9wX1dUX2hlYXRtYXAkbG9nMkZvbGRDaGFuZ2UsIGRlY3JlYXNpbmcgPSBUUlVFKSxdDQoNCiNnZXQgbm9ybWFsaXplZCBjb3VudCBkYXRhIGZyb20gdnN0IG9iamVjdA0KbWF0IDwtIGFzc2F5KHZzZGF0YV9EMilbcm93bmFtZXModG9wX1dUX2hlYXRtYXApLCBtZXRhZGF0YV9EMiRSdW5dDQpjb2xuYW1lcyhtYXQpIDwtIG1ldGFkYXRhX0QyJFJ1bg0KYmFzZV9tZWFuIDwtIHJvd01lYW5zKG1hdCkNCm1hdC5zY2FsZWQgPC0gdChhcHBseShtYXQsIDEsIHNjYWxlKSkgI2NlbnRlciBhbmQgc2NhbGUgZWFjaCBjb2x1bW4gKFotc2NvcmUpIHRoZW4gdHJhbnNwb3NlDQpjb2xuYW1lcyhtYXQuc2NhbGVkKTwtY29sbmFtZXMobWF0KQ0KDQpudW1fa2VlcCA8LSAyNQ0KIzEgdG8gbnVtX2tlZXAgbGVuLW51bV9rZWVwIHRvIGxlbg0Kcm93c19rZWVwIDwtIGMoc2VxKDE6bnVtX2tlZXApLCBzZXEoKG5yb3cobWF0LnNjYWxlZCktbnVtX2tlZXApLCBucm93KG1hdC5zY2FsZWQpKSApDQoNCmwyX3ZhbCA8LSBhcy5tYXRyaXgodG9wX1dUX2hlYXRtYXBbcm93c19rZWVwLF0kbG9nMkZvbGRDaGFuZ2UpICNnZXR0aW5nIGxvZzIgdmFsdWUgZm9yIGVhY2ggZ2VuZSB3ZSBhcmUga2VlcGluZw0KY29sbmFtZXMobDJfdmFsKTwtImxvZ0ZDIg0KDQptZWFuIDwtIGFzLm1hdHJpeCh0b3BfV1RfaGVhdG1hcFtyb3dzX2tlZXAsXSRiYXNlTWVhbikgI2dldHRpbmcgbWVhbiB2YWx1ZSBmb3IgZWFjaCBnZW5lIHdlIGFyZSBrZWVwaW5nDQpjb2xuYW1lcyhtZWFuKTwtIkF2ZUV4cHIiDQoNCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkoY2lyY2xpemUpDQoNCiNtYXBzIHZhbHVlcyBiZXR3ZWVuIGIvdy9yIGZvciBtaW4gYW5kIG1heCBsMiB2YWx1ZXMNCmNvbF9sb2dGQyA8LSBjb2xvclJhbXAyKGMobWluKGwyX3ZhbCksMCwgbWF4KGwyX3ZhbCkpLCBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSANCg0KI21hcHMgYmV0d2VlbiAwJSBxdWFudGlsZSwgYW5kIDc1JSBxdWFudGlsZSBvZiBtZWFuIHZhbHVlcyAtLS0gMCwgMjUsIDUwLCA3NSwgMTAwDQpjb2xfQXZlRXhwciA8LSBjb2xvclJhbXAyKGMocXVhbnRpbGUobWVhbilbMV0sIHF1YW50aWxlKG1lYW4pWzRdKSwgYygid2hpdGUiLCAicmVkIikpDQpjb2xfenNjb3JlIDwtIGNvbG9yUmFtcDIoYygtMiwgMCwgMiksIGMoIiM0NTc1YjQiLCAid2hpdGUiLCAiI2Q3MzAyNyIpKQ0KDQpoYSA8LSBIZWF0bWFwQW5ub3RhdGlvbihzdW1tYXJ5ID0gYW5ub19zdW1tYXJ5KGdwID0gZ3BhcihmaWxsID0gMiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSB1bml0KDIsICJjbSIpKSkNCg0KaDEgPC0gSGVhdG1hcChtYXQuc2NhbGVkW3Jvd3Nfa2VlcCxdLCANCiAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgICMgRW5hYmxlIGNsdXN0ZXJpbmcgZm9yIGJldHRlciBncm91cGluZw0KICAgICAgICAgICAgICBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMobWF0LnNjYWxlZCksIA0KICAgICAgICAgICAgICBuYW1lPSJaLXNjb3JlIiwNCiAgICAgICAgICAgICAgY29sID0gY29sX3pzY29yZSwgICMgQWRkIGNvbG9yIHNjaGVtZQ0KICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLA0KICAgICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLCAgIyBDbGVhbiB1cCByb3cgbmFtZXMNCiAgICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDkpLA0KICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMTApKSkNCg0KaDIgPC0gSGVhdG1hcChsMl92YWwsIA0KICAgICAgICAgICAgICByb3dfbGFiZWxzID0gdG9wX1dUX2hlYXRtYXAkZ2VuZV9zeW1ib2xfRDJbcm93c19rZWVwXSwgICMgVXNlIGdlbmUgc3ltYm9scw0KICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwgDQogICAgICAgICAgICAgIG5hbWU9ImxvZ0ZDIiwgDQogICAgICAgICAgICAgIGNvbCA9IGNvbF9sb2dGQywNCiAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDE1LCAibW0iKSwgICMgRml4ZWQgd2lkdGgNCiAgICAgICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBUUlVFLA0KICAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksICAjIFNtYWxsZXIgZm9udCBmb3IgZ2VuZSBuYW1lcw0KICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOSksDQogICAgICAgICAgICAgIGNlbGxfZnVuID0gZnVuY3Rpb24oaiwgaSwgeCwgeSwgdywgaCwgY29sKSB7IA0KICAgICAgICAgICAgICAgIGdyaWQudGV4dChyb3VuZChsMl92YWxbaSwgal0sIDEpLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSA3KSkgICMgU21hbGxlciB0ZXh0DQogICAgICAgICAgICAgIH0pDQpoMyA8LSBIZWF0bWFwKG1lYW4sIA0KICAgICAgICAgICAgICByb3dfbGFiZWxzID0gdG9wX1dUX2hlYXRtYXAkZ2VuZV9zeW1ib2xbcm93c19rZWVwXSwNCiAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIA0KICAgICAgICAgICAgICBuYW1lID0gIkF2ZUV4cHIiLCANCiAgICAgICAgICAgICAgY29sID0gY29sX0F2ZUV4cHIsDQogICAgICAgICAgICAgIHdpZHRoID0gdW5pdCgxNSwgIm1tIiksICAjIEZpeGVkIHdpZHRoDQogICAgICAgICAgICAgIHNob3dfcm93X25hbWVzID0gVFJVRSwgICMgRG9uJ3QgcmVwZWF0IGdlbmUgbmFtZXMNCiAgICAgICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBUUlVFLA0KICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOSksDQogICAgICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA3KSwNCiAgICAgICAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3LCBoLCBjb2wpIHsgDQogICAgICAgICAgICAgICAgZ3JpZC50ZXh0KHJvdW5kKG1lYW5baSwgal0sIDApLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSA3KSkgICMgUm91bmQgdG8gd2hvbGUgbnVtYmVycw0KICAgICAgICAgICAgICB9KQ0KDQpoX0QyPC1oMStoMitoMw0KaF9EMg0KDQpwZGYoIkFubm90YXRlZEhlYXRtYXBfRDIucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikNCmRyYXcoaF9EMikNCmRldi5vZmYoKQ0KDQpwbmcoIkFubm90YXRlZEhlYXRtYXBfRDIucG5nIiwgd2lkdGggPSAzMDAwLCBoZWlnaHQgPSAyMDAwLCByZXMgPSAzMDApDQpkcmF3KGhfRDIpDQpkZXYub2ZmKCkNCg0KYGBgDQpgYGB7cn0NCiNoZWF0bWFwIC0gZm9yIHVuZGVyc3RhbmRpbmcgZXhwZXJpbWVudGFsIGRlc2lnbg0KdG9wX2dlbmVzX2hlYXRtYXBfV1RfRDIgPC0gaGVhZChvcmRlcihyZXNfV1RfdnNfZGVsMTlfRDIkbG9nMkZvbGRDaGFuZ2UsIGRlY3JlYXNpbmcgPSBUUlVFKSwgNTApDQpwbmcoIlRvcDUwX0hlYXRtYXBfRDIucG5nIiwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNjAwLCByZXMgPSAzMDApDQpwaGVhdG1hcDo6cGhlYXRtYXAoYXNzYXkodnNkYXRhX0QyKVt0b3BfZ2VuZXNfaGVhdG1hcF9XVF9EMixdLCANCiAgICAgICAgIGFubm90YXRpb25fY29sID0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGRkc19EMilbLGMoInRpc3N1ZSIsICJlZ2ZyX211dGF0aW9uIildKSwgDQogICAgICAgICBzY2FsZSA9ICJyb3ciLCANCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgIG1haW4gPSAiVG9wIDUwIERFR3M6IFdUIHZzIEV4b24gMTkgRGVsZXRpb24iLA0KICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSkNCmRldi5vZmYoKQ0KYGBgDQoNCg0KUGF0aHdheSBBbmFseXNpcw0KYGBge3J9DQogIA0KICAjbG9hZGluZyBwYXRod2F5IGFuYWx5c2lzIHBhY2thZ2VzDQogIGxpYnJhcnkoRE9TRSkNCiAgbGlicmFyeShlbnJpY2hwbG90KQ0KICBsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikNCiAgDQogICMgSSdtIHNlcGFyYXRpbmcgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMNCiAgc2lnX2dlbmVzX3VwX1dUX0QyIDwtIHJvd25hbWVzKHNpZ19XVF9EMilbc2lnX1dUX0QyJGxvZzJGb2xkQ2hhbmdlID4gMV0NCiAgc2lnX2dlbmVzX2Rvd25fV1RfRDIgPC0gcm93bmFtZXMoc2lnX1dUX0QyKVtzaWdfV1RfRDIkbG9nMkZvbGRDaGFuZ2UgPCAtMV0NCiAgDQogIHByaW50KHBhc3RlKCJVcHJlZ3VsYXRlZDoiLCBsZW5ndGgoc2lnX2dlbmVzX3VwX1dUX0QyKSkpDQpwcmludChwYXN0ZSgiRG93bnJlZ3VsYXRlZDoiLCBsZW5ndGgoc2lnX2dlbmVzX2Rvd25fV1RfRDIpKSkNCiAgDQogICMgSSdtIGNvbnZlcnRpbmcgRU5TRU1CTCB0byBFTlRSRVogZm9yIEtFR0cgYW5hbHlzaXMNCiAgZW50cmV6X2dlbmVzX3VwX1dUX0QyIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsIHNpZ19nZW5lc191cF9XVF9EMiwgIkVOVFJFWklEIiwgIkVOU0VNQkwiKQ0KICBlbnRyZXpfZ2VuZXNfZG93bl9XVF9EMiA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLCBzaWdfZ2VuZXNfZG93bl9XVF9EMiwgIkVOVFJFWklEIiwgIkVOU0VNQkwiKQ0KICBlbnRyZXpfZ2VuZXNfdXBfV1RfRDIgPC0gZW50cmV6X2dlbmVzX3VwX1dUX0QyWyFpcy5uYShlbnRyZXpfZ2VuZXNfdXBfV1RfRDIpXQ0KICBlbnRyZXpfZ2VuZXNfZG93bl9XVF9EMiA8LSBlbnRyZXpfZ2VuZXNfZG93bl9XVF9EMlshaXMubmEoZW50cmV6X2dlbmVzX2Rvd25fV1RfRDIpXQ0KICANCiAgIyBJJ20gcnVubmluZyBHTyBBbmFseXNpcw0KICBnb191cF9XVF9EMiA8LSBlbnJpY2hHTyhnZW5lID0gc2lnX2dlbmVzX3VwX1dUX0QyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5Icy5lZy5kYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAga2V5VHlwZSA9ICJFTlNFTUJMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgb250ID0gIkFMTCIsICAjIEJQLCBDQywgTUYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpDQogIGFzLmRhdGEuZnJhbWUoZ29fdXBfV1RfRDIpDQogIHRvcF9nb191cF9EMiA8LSBnb191cF9XVF9EMkByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3BfZ29fdXBfRDIpDQoNCiAgcDFfRDIgPC0gcGxvdChiYXJwbG90KGdvX3VwX1dUX0QyLCBzaG93Q2F0ZWdvcnkgPSAxNSkrbGFicyh0aXRsZSA9ICJVcHJlZ3VsYXRlZCBHTyBUZXJtcyAoV1QgdnMgRGVsMTkpIikpDQogIGdnc2F2ZSgiR09fV1RfVXByZWd1bGF0ZWRfRDIucGRmIiwgcDFfRDIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikNCiAgZ2dzYXZlKCJHT19XVF9VcHJlZ3VsYXRlZF9EMi5wbmciLCBwMV9EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQogIA0KICBnb19kb3duX1dUX0QyIDwtIGVucmljaEdPKGdlbmUgPSBzaWdfZ2VuZXNfZG93bl9XVF9EMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5Icy5lZy5kYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gIkVOU0VNQkwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9udCA9ICJBTEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBBZGp1c3RNZXRob2QgPSAiQkgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpDQogIGFzLmRhdGEuZnJhbWUoZ29fZG93bl9XVF9EMikNCiAgdG9wX2dvX2Rvd25fRDIgPC0gZ29fZG93bl9XVF9EMkByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3BfZ29fZG93bl9EMikNCg0KICBwMl9EMiA8LSBwbG90KGJhcnBsb3QoZ29fZG93bl9XVF9EMiwgc2hvd0NhdGVnb3J5ID0gMTUpK2xhYnModGl0bGUgPSAiRG93bnJlZ3VsYXRlZCBHTyBUZXJtcyAoV1QgdnMgRGVsMTkpIikpDQogIGdnc2F2ZSgiR09fV1RfRG93bnJlZ3VsYXRlZF9EMi5wZGYiLCBwMl9EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIkdPX1dUX0Rvd25yZWd1bGF0ZWRfRDIucG5nIiwgcDJfRDIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KICANCiAgI3J1bm5pbmcgS0VHRyBQYXRod2F5IEFuYWx5c2lzDQogIGtlZ2dfdXBfV1RfRDIgPC0gZW5yaWNoS0VHRyhnZW5lID0gZW50cmV6X2dlbmVzX3VwX1dUX0QyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHNhJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIikNCiAgYXMuZGF0YS5mcmFtZShrZWdnX3VwX1dUX0QyKQ0KdG9wX2tlZ2dfdXBfRDIgPC0ga2VnZ191cF9XVF9EMkByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3Bfa2VnZ191cF9EMikNCg0KICBwM19EMiA8LSBwbG90KGJhcnBsb3Qoa2VnZ191cF9XVF9EMiwgc2hvd0NhdGVnb3J5ID0gMTUpK2xhYnModGl0bGUgPSAiVXByZWd1bGF0ZWQgS0VHRyBQYXRod2F5cyAoV1QgdnMgRGVsMTkpIikpDQogIGdnc2F2ZSgiS0VHR19XVF9VcHJlZ3VsYXRlZF9EMi5wZGYiLCBwM19EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIktFR0dfV1RfVXByZWd1bGF0ZWRfRDIucG5nIiwgcDNfRDIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KICANCiAga2VnZ19kb3duX1dUX0QyIDwtIGVucmljaEtFR0coZ2VuZSA9IGVudHJlel9nZW5lc19kb3duX1dUX0QyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdoc2EnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIikNCiAgDQogIGFzLmRhdGEuZnJhbWUoa2VnZ19kb3duX1dUX0QyKQ0KdG9wX2tlZ2dfdXBfRDIgPC0ga2VnZ191cF9XVF9EMkByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3Bfa2VnZ191cF9EMikNCg0KIHA0X0QyIDwtIHBsb3QoYmFycGxvdChrZWdnX2Rvd25fV1RfRDIsIHNob3dDYXRlZ29yeSA9IDE1KStsYWJzKHRpdGxlID0gIkRvd25yZWd1bGF0ZWQgS0VHRyBQYXRod2F5cyAoV1QgdnMgRGVsMTkpIikpDQogIGdnc2F2ZSgiS0VHR19XVF9Eb3ducmVndWxhdGVkX0QyLnBkZiIsIHA0X0QyLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpDQogIGdnc2F2ZSgiS0VHR19XVF9Eb3ducmVndWxhdGVkX0QyLnBuZyIsIHA0X0QyLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCmBgYA0KDQoNCg0KYGBge3J9DQojbG9hZGluZyBHU0VBIHBhY2thZ2VzIA0KbGlicmFyeShmZ3NlYSkNCmxpYnJhcnkobXNpZ2RicikNCg0KDQojcHJlcGFyaW5nIHJhbmtlZCBnZW5lIGxpc3QgZm9yIEdTRUEgDQpnZW5lX3JhbmtzX1dUX0QyIDwtIHJlc19XVF92c19kZWwxOV9EMiRsb2cyRm9sZENoYW5nZQ0KbmFtZXMoZ2VuZV9yYW5rc19XVF9EMikgPC0gcm93bmFtZXMocmVzX1dUX3ZzX2RlbDE5X0QyKQ0KZ2VuZV9yYW5rc19XVF9EMiA8LSBnZW5lX3JhbmtzX1dUX0QyWyFpcy5uYShnZW5lX3JhbmtzX1dUX0QyKV0NCmdlbmVfcmFua3NfV1RfRDIgPC0gc29ydChnZW5lX3JhbmtzX1dUX0QyLCBkZWNyZWFzaW5nID0gVFJVRSkNCg0KI2dldHRpbmcgSGFsbG1hcmsgcGF0aHdheXMgZm9yIEdTRUEgDQoNCmdzZV9EMiA8LSBnc2VHTyhnZW5lX3JhbmtzX1dUX0QyLA0KICAgICAgb250ID0gIkJQIiwNCiAgICAgIGtleVR5cGUgPSAiRU5TRU1CTCIsDQogICAgICBPcmdEYiA9ICJvcmcuSHMuZWcuZGIiLA0KICAgICAgZXBzID0gMWUtMzAwKQ0KYXMuZGF0YS5mcmFtZShnc2VfRDIpDQoNCmdzZV9wbG90X0QyIDwtIGdzZWFwbG90KGdzZV9EMiwgZ2VuZVNldElEID0gMSkNCmdzZV9wbG90X0QyDQoNCmdnc2F2ZSgiR1NFQV9wYXRod2F5X0QyLnBkZiIsIGdzZV9wbG90X0QyLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpDQpnZ3NhdmUoIkdTRUFfcGF0aHdheV9EMi5wbmciLCBnc2VfcGxvdF9EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQoNCg0KaGFsbG1hcmtfc2V0c19EMiA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiSCIpDQpoYWxsbWFya19saXN0X0QyIDwtIHNwbGl0KGhhbGxtYXJrX3NldHNfRDIkZW5zZW1ibF9nZW5lLCBoYWxsbWFya19zZXRzX0QyJGdzX25hbWUpDQoNCiNydW5uaW5nIEdTRUEgYW5hbHlzaXMgDQpmZ3NlYV9yZXN1bHRzX1dUX0QyIDwtIGZnc2VhKHBhdGh3YXlzID0gaGFsbG1hcmtfbGlzdF9EMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0cyA9IGdlbmVfcmFua3NfV1RfRDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluU2l6ZSA9IDE1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heFNpemUgPSA1MDApDQoNCnByaW50KGhlYWQoZmdzZWFfcmVzdWx0c19XVF9EMltvcmRlcihwdmFsKSwgXSwgMTApKQ0KDQojcGxvdHRpbmcgdG9wIDMgcGF0aHdheXMNCnByaW50KCJUb3AgMyBHU0VBIHBhdGh3YXlzOiIpDQp0b3BfcGF0aHdheXNfRDIgPC0gaGVhZChmZ3NlYV9yZXN1bHRzX1dUX0QyW29yZGVyKHB2YWwpLCBdLCAzKQ0KcHJpbnQodG9wX3BhdGh3YXlzX0QyWywgYygicGF0aHdheSIsICJwdmFsIiwgIk5FUyIpXSkNCg0KZm9yKGkgaW4gMTozKSB7DQogIHBhdGh3YXlfbmFtZSA8LSB0b3BfcGF0aHdheXNfRDIkcGF0aHdheVtpXQ0KICBwYXRod2F5c19EMiA8LSBwbG90RW5yaWNobWVudChoYWxsbWFya19saXN0X0QyW1twYXRod2F5X25hbWVdXSwgZ2VuZV9yYW5rc19XVF9EMikgKyANCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlBhdGh3YXkiLCBpLCAiOiIsIHBhdGh3YXlfbmFtZSkpDQogIHByaW50KHBhdGh3YXlzX0QyKQ0KICBnZ3NhdmUoIlRvcDNfR1NFQV9EMi5wZGYiLCBwYXRod2F5c19EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIlRvcDNfR1NFQV9EMi5wbmciLCBwYXRod2F5c19EMiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQp9DQoNCmBgYA0KIA0KYGBge3J9DQojIFN1bW1hcnkgc3RhdGlzdGljcyB0YWJsZSBmb3IgRDINCnN1bW1hcnlfc3RhdHNfRDIgPC0gZGF0YS5mcmFtZSgNCiAgTWV0cmljID0gYygiVG90YWwgU2FtcGxlcyIsICJHZW5lcyBBbmFseXplZCIsICJTaWduaWZpY2FudCBERUdzIC0gV1QgdnMgRGVsZXRpb24gMTkiLCAiVXByZWd1bGF0ZWQgLSBXVCB2cyBEZWxldGlvbiAxOSIsICJEb3ducmVndWxhdGVkIC0gV1QgdnMgRGVsZXRpb24gMTkiKSwNCiAgVmFsdWUgPSBjKG5jb2woY291bnRzX0QyKSwgDQogICAgICAgICAgICBucm93KGRkc19EMiksDQogICAgICAgICAgICBucm93KHNpZ19XVF9EMiksDQogICAgICAgICAgICBsZW5ndGgoc2lnX2dlbmVzX3VwX1dUX0QyKSwNCiAgICAgICAgICAgIGxlbmd0aChzaWdfZ2VuZXNfZG93bl9XVF9EMikpDQopDQoNCnN1bW1hcnlfc3RhdHNfRDINCg0KIyBUb3AgZ2VuZXMgdGFibGUNCnRvcF9nZW5lc190YWJsZV9EMiA8LSBkYXRhLmZyYW1lKA0KICBHZW5lX1N5bWJvbCA9IGdlbmVfc3ltYm9sc19EMltyb3duYW1lcyhoZWFkKHNpZ19XVF9EMltvcmRlcihzaWdfV1RfRDIkcGFkaiksXSwgMjApKV0sDQogIEVOU0VNQkxfSUQgPSByb3duYW1lcyhoZWFkKHNpZ19XVF9EMltvcmRlcihzaWdfV1RfRDIkcGFkaiksXSwgMjApKSwNCiAgTG9nMkZDID0gcm91bmQoaGVhZChzaWdfV1RfRDJbb3JkZXIoc2lnX1dUX0QyJHBhZGopLF0sIDIwKSRsb2cyRm9sZENoYW5nZSwgMyksDQogIFBhZGogPSBmb3JtYXQoaGVhZChzaWdfV1RfRDJbb3JkZXIoc2lnX1dUX0QyJHBhZGopLF0sIDIwKSRwYWRqLCBzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMyksDQogIERpcmVjdGlvbiA9IGlmZWxzZShoZWFkKHNpZ19XVF9EMltvcmRlcihzaWdfV1RfRDIkcGFkaiksXSwgMjApJGxvZzJGb2xkQ2hhbmdlID4gMCwgIlVwIiwgIkRvd24iKQ0KKQ0KDQpwcmludCgiVG9wIDIwIFNpZ25pZmljYW50IEdlbmVzOiBXVCB2cyBEZWxldGlvbiAxOSIpDQpwcmludCh0b3BfZ2VuZXNfdGFibGVfRDIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KIyBFeHBvcnQgbWFpbiByZXN1bHRzDQp3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShyZXNfV1RfdnNfZGVsMTlfRDIpLCAiRDJfV1RfYW5ub3RhdGVkX3Jlc3VsdHMuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCndyaXRlLmNzdihzaWdfV1RfRDIsICJEMl9XVF9zaWduaWZpY2FudF9nZW5lcy5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQ0Kd3JpdGUuY3N2KHN1bW1hcnlfc3RhdHNfRDIsICJEMl9zdW1tYXJ5X3N0YXRpc3RpY3MuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQp3cml0ZS5jc3YodG9wX2dlbmVzX3RhYmxlX0QyLCAiRDJfdG9wMjBfZ2VuZXMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgRXhwb3J0IG5vcm1hbGl6ZWQgZGF0YQ0Kd3JpdGUuY3N2KHJlc19hbm5vdGF0ZWRfRDIsICJEMl9yZXN1bHRzLmNzdiIpDQp3cml0ZS5jc3YoY291bnRzKGRkc19EMiwgbm9ybWFsaXplZD1UUlVFKSwgIkQyX25vcm1hbGl6ZWRfY291bnRzLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpDQp3cml0ZS5jc3YodnN0X2ZpbmFsX0QyLCAiRDJfdnN0X2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCg0KIyBFeHBvcnQgcGF0aHdheSByZXN1bHRzDQppZihucm93KGdvX3VwX1dUX0QyQHJlc3VsdCkgPiAwKSB7DQogIHdyaXRlLmNzdihnb191cF9XVF9EMkByZXN1bHQsICJEMl9HT191cHJlZ3VsYXRlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCn0NCmlmKG5yb3coZ29fZG93bl9XVF9EMkByZXN1bHQpID4gMCkgew0KICB3cml0ZS5jc3YoZ29fZG93bl9XVF9EMkByZXN1bHQsICJEMl9HT19kb3ducmVndWxhdGVkLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KfQ0KaWYobnJvdyhrZWdnX3VwX1dUX0QyQHJlc3VsdCkgPiAwKSB7DQogIHdyaXRlLmNzdihrZWdnX3VwX1dUX0QyQHJlc3VsdCwgIkQyX0tFR0dfdXByZWd1bGF0ZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQp9DQppZihucm93KGtlZ2dfZG93bl9XVF9EMkByZXN1bHQpID4gMCkgew0KICB3cml0ZS5jc3Yoa2VnZ19kb3duX1dUX0QyQHJlc3VsdCwgIkQyX0tFR0dfZG93bnJlZ3VsYXRlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCn0NCg0KIyBSZW1vdmUgdGhlIGxlYWRpbmdFZGdlIGNvbHVtbiAod2hpY2ggY29udGFpbnMgbGlzdHMpDQpmZ3NlYV9yZXN1bHRzX2NsZWFuX0QyIDwtIGZnc2VhX3Jlc3VsdHNfV1RfRDIgJT4lDQogIHNlbGVjdCgtbGVhZGluZ0VkZ2UpDQoNCndyaXRlLmNzdihmZ3NlYV9yZXN1bHRzX2NsZWFuX0QyLCAiRDJfR1NFQV9oYWxsbWFya3MuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCmBgYA0KDQoNCg0K