library(DESeq2)
library(ggplot2)
counts_D4 <- read.delim("counts_D4", header = TRUE, sep = "\t", row.names = 1)

total_counts_per_gene_D4 <- rowSums(counts_D4)
hist(total_counts_per_gene_D4, 
     breaks=100, 
     main="Distribution of Total Counts per Gene", 
     xlab="Total counts across all samples",
     ylab="Number of genes")
summary(total_counts_per_gene_D4)
#ignoring low expressed gene to remove noise & get better results

counts_D4 <- counts_D4[which(rowSums(counts_D4) > 50), ]
#calling in the metadata
metadata_D4 <- read.csv("metadata_D4.csv", header = TRUE)
counts_D4 <- round(counts_D4)
dds_D4 <- DESeqDataSetFromMatrix(countData = counts_D4,
                                colData = metadata_D4,        
                                design = ~ PHENOTYPE)
dds_D4

dds_D4 <- DESeq(dds_D4)
dds_D4

res_D4 <- results(dds_D4)
res_D4
#moderate filtering 
keep_D4 <- rowSums(counts(dds_D4) >= 20) >= 3
dds_D4 <- dds_D4[keep_D4,]

cat("Genes retained with moderate filtering:", nrow(dds_D4), "\n")

#Checking data quality after DESeq2
dds_D4 <- DESeq(dds_D4, minReplicatesForReplace = Inf)

resultsNames(dds_D4)
summary_res_D4 <- results(dds_D4, name = "PHENOTYPE_resistant_vs_parental")
summary(summary_res_D4)
plotDispEsts(dds_D4, main = "Dispersion Estimates: EBC-1 vs EBC-CR")

pdf("DispersionPlot_D4.pdf", width = 6, height = 5)
plotDispEsts(dds_D4)
dev.off()

png("DispersionPlot_D4.png", width = 2000, height = 1600, res = 300)
plotDispEsts(dds_D4)
dev.off()



vst_D4 <- vst(dds_D4, blind = FALSE)

vst_matrix_D4 <- assay(vst_D4)

head(vst_matrix_D4[1:5, 1:3])

library(reshape2)

vst_df_D4 <- as.data.frame(vst_matrix_D4)
vst_df_D4$gene_id <- rownames(vst_df_D4)

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

head(vst_final_D4)

We increased the counts threshold because of the imbalance in groups, ie. 1 vs 3. We needed to clear the noise for better results.We got good results.

pca_plot_D4 <- plotPCA(vst_D4, intgroup = "PHENOTYPE") +
  ggtitle("PCA: EBC-1 Parental vs EBC-CR Resistant (1 vs 3 Imbalance)") +
  theme_minimal() +
  theme(legend.position = "bottom") 
pca_plot_D4

ggsave(("D4_PCA.pdf"), pca_plot_D4, width = 6, height = 5)
ggsave(("D4_PCA.png"), pca_plot_D4, width = 6, height = 5, dpi = 300)

The PCA “Spread” is NOT Due to Poor Quality:

resultsNames(dds_D4)
[1] "Intercept"                       "PHENOTYPE_resistant_vs_parental"
results_D4 <- results(dds_D4,
                     alpha = 0.01,           
                     lfcThreshold = 1,      
                     cooksCutoff = FALSE,    
                     contrast = c("PHENOTYPE", "resistant", "parental"))

print("Results summary with strict thresholds:")
[1] "Results summary with strict thresholds:"
summary(results_D4)

out of 12601 with nonzero total read count
adjusted p-value < 0.01
LFC > 1.00 (up)    : 141, 1.1%
LFC < -1.00 (down) : 9, 0.071%
outliers [1]       : 0, 0%
low counts [2]     : 978, 7.8%
(mean count < 38)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
results_D4
log2 fold change (MLE): PHENOTYPE resistant vs parental 
Wald test p-value: PHENOTYPE resistant vs parental 
DataFrame with 12601 rows and 6 columns
                 baseMean log2FoldChange     lfcSE      stat    pvalue      padj
                <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>
ENSG00000142655   42.6408      -0.910796  0.922302 -0.987525  0.557669  0.999995
ENSG00000149527   75.4277      -1.811092  0.742950 -2.437705  0.137556  0.999995
ENSG00000171621   68.4871      -1.451062  0.678824 -2.137612  0.253346  0.999995
ENSG00000173614  210.2283       0.129475  0.668358  0.193720  0.949146  0.999995
ENSG00000171729  325.1116      -0.920575  0.524908 -1.753784  0.560262  0.999995
...                   ...            ...       ...       ...       ...       ...
ENSG00000273730   34.6519       0.769113  0.835253  0.920814  0.625975        NA
ENSG00000301761   85.0955       0.704629  0.655156  1.075513  0.678584  0.999995
ENSG00000304745   19.9733      -0.181435  0.940890 -0.192833  0.912468        NA
ENSG00000276345  180.2394      -0.888292  0.680519 -1.305316  0.567956  0.999995
ENSG00000271254  114.7438      -0.471812  0.608137 -0.775832  0.815205  0.999995
tryCatch({
  results_shrunk_D4 <- lfcShrink(dds_D4, 
                                coef="PHENOTYPE_resistant_vs_parental", 
                                type="apeglm")
  print("LFC shrinkage successful")
}, error = function(e) {
  print("LFC shrinkage failed due to sample imbalance - using unshrunken results")
  results_shrunk_D4 <- results_D4
})
[1] "LFC shrinkage successful"
library(AnnotationDbi)
library(org.Hs.eg.db)

# Converting ENSEMBL IDs to gene symbols
gene_symbols_D4 <- mapIds(org.Hs.eg.db,
                          keys = rownames(dds_D4),
                          column = "SYMBOL",
                          keytype = "ENSEMBL",
                          multiVals = "first")

res_annotated_D4 <- results_D4
res_annotated_D4$gene_symbol <- gene_symbols_D4
as.data.frame(res_annotated_D4)

# Adding annotations to results
res_annotated_D4 <- results_shrunk_D4
res_annotated_D4$gene_symbol <- gene_symbols_D4
# Using strict criteria for significance
sig_genes_D4 <- res_annotated_D4[which(res_annotated_D4$padj < 0.01 & 
                                       abs(res_annotated_D4$log2FoldChange) > 1), ]

nrow(sig_genes_D4)
[1] 377
# Get top genes
top_genes_D4 <- head(sig_genes_D4[order(sig_genes_D4$padj), ], 20)
# Since we have 3 resistant samples, check consistency
normalized_counts_D4 <- counts(dds_D4, normalized = TRUE)

# Calculate fold change for each resistant sample vs parental
parental_counts <- normalized_counts_D4[, metadata_D4$PHENOTYPE == "parental"]
resistant_samples <- colnames(normalized_counts_D4)[metadata_D4$PHENOTYPE == "resistant"]

# Check consistency across resistant samples
fc_matrix <- sapply(resistant_samples, function(sample) {
  log2((normalized_counts_D4[, sample] + 1) / (parental_counts + 1))
})

# Find genes consistently up or down in all resistant samples
consistent_up <- rownames(fc_matrix)[apply(fc_matrix > 0.5, 1, all)]
consistent_down <- rownames(fc_matrix)[apply(fc_matrix < -0.5, 1, all)]

# Robust genes: significant AND consistent
sig_genes_up_D4 <- rownames(sig_genes_D4)[sig_genes_D4$log2FoldChange > 0]
sig_genes_down_D4 <- rownames(sig_genes_D4)[sig_genes_D4$log2FoldChange < 0]

robust_up_D4 <- intersect(sig_genes_up_D4, consistent_up)
robust_down_D4 <- intersect(sig_genes_down_D4, consistent_down)

cat("Significant genes:", nrow(sig_genes_D4), "\n")
Significant genes: 377 
cat("Robust upregulated (significant + consistent):", length(robust_up_D4), "\n")
Robust upregulated (significant + consistent): 326 
cat("Robust downregulated (significant + consistent):", length(robust_down_D4), "\n")
Robust downregulated (significant + consistent): 51 
# MA Plot
plotMA(results_shrunk_D4, ylim = c(-5, 5), main = "Resistant vs Parental")

pdf(("MA_D4.pdf"), width = 6, height = 5)
plotMA(results_shrunk_D4, ylim=c(-5,5), main="Resistant vs Parental")
dev.off()
png 
  2 
png(("MA_D4.png"), width = 2000, height = 1600, res = 300)
plotMA(results_shrunk_D4, ylim=c(-5,5), main="Resistant vs Parental")
dev.off()
png 
  2 
# Volcano plot
library(EnhancedVolcano)
volcano_plot <- EnhancedVolcano(res_annotated_D4, lab = res_annotated_D4$gene_symbol, 
                x = 'log2FoldChange', y = 'padj',
                title = 'EBC-CR Resistant vs EBC-1 Parental',
                pCutoff = 0.01,
                FCcutoff = 1)
ggsave(("D4_Volcano.pdf"), volcano_plot, width = 6, height = 5)
ggsave(("D4_Volcano.png"), volcano_plot, width = 6, height = 5, dpi = 300)

# Heatmap of significant genes
library(pheatmap)
if(nrow(sig_genes_D4) > 0) {
  top_sig_genes <- head(rownames(sig_genes_D4[order(sig_genes_D4$padj), ]), 50)
  pheatmap::pheatmap(assay(vst_D4)[top_sig_genes,], 
           annotation_col = as.data.frame(colData(dds_D4)[, "PHENOTYPE", drop = FALSE]), 
           scale = "row", 
           show_rownames = FALSE,
           main = "Top 50 Differentially Expressed Genes",
           filename = "DEGs_D4.png")
}

library(dplyr)
library(ComplexHeatmap)
library(RColorBrewer)
library(circlize)

# Preparing top genes for enhanced heatmap - focus on robust genes
if(length(c(robust_up_D4, robust_down_D4)) > 10) {
  # Combine robust up and down genes
  robust_genes_D4 <- c(robust_up_D4, robust_down_D4)
  robust_genes_data <- res_annotated_D4[robust_genes_D4,]
  
  # Sort by fold change
  robust_genes_data <- robust_genes_data[order(robust_genes_data$log2FoldChange, decreasing = TRUE),]
  top_robust_D4 <- head(rownames(robust_genes_data), 50)
  
  # Getting normalized count data
  mat_D4 <- assay(vst_D4)[top_robust_D4, ]
  mat_scaled_D4 <- t(apply(mat_D4, 1, scale))
  colnames(mat_scaled_D4) <- colnames(mat_D4)
  
  # Selecting top and bottom genes
  num_keep <- min(25, floor(nrow(mat_scaled_D4)/2))
  rows_keep_D4 <- c(seq(1:num_keep), seq((nrow(mat_scaled_D4) - num_keep + 1), nrow(mat_scaled_D4)))
  
  # Preparing annotation matrices
  l2_val_D4 <- as.matrix(robust_genes_data[rows_keep_D4,]$log2FoldChange)
  colnames(l2_val_D4) <- "logFC"
  
  mean_D4 <- as.matrix(robust_genes_data[rows_keep_D4,]$baseMean)
  colnames(mean_D4) <- "AveExpr"
  
  # Setting up color schemes
  col_logFC_D4 <- colorRamp2(c(min(l2_val_D4), 0, max(l2_val_D4)), c("blue", "white", "red"))
  col_AveExpr_D4 <- colorRamp2(c(quantile(mean_D4)[1], quantile(mean_D4)[4]), c("white", "red"))
  col_zscore_D4 <- colorRamp2(c(-2, 0, 2), c("#4575b4", "white", "#d73027"))
  
  # Creating heatmaps
  h1_D4 <- Heatmap(mat_scaled_D4[rows_keep_D4,], 
                   cluster_rows = TRUE,
                   column_labels = colnames(mat_scaled_D4), 
                   name = "Z-score",
                   col = col_zscore_D4,
                   cluster_columns = TRUE,
                   show_row_names = FALSE,
                   column_names_gp = gpar(fontsize = 9),
                   column_title = "Robust Resistance Genes")
  
  h2_D4 <- Heatmap(l2_val_D4, 
                   row_labels = robust_genes_data$gene_symbol[rows_keep_D4],
                   cluster_rows = FALSE, 
                   name = "logFC", 
                   col = col_logFC_D4,
                   width = unit(15, "mm"),
                   show_column_names = TRUE,
                   row_names_gp = gpar(fontsize = 6),
                   column_names_gp = gpar(fontsize = 9),
                   cell_fun = function(j, i, x, y, w, h, col) { 
                     grid.text(round(l2_val_D4[i, j], 1), x, y, gp = gpar(fontsize = 7))
                   })
  
  h3_D4 <- Heatmap(mean_D4, 
                   row_labels = robust_genes_data$gene_symbol[rows_keep_D4],
                   cluster_rows = FALSE, 
                   name = "AveExpr", 
                   col = col_AveExpr_D4,
                   width = unit(15, "mm"),
                   show_row_names = TRUE,
                   show_column_names = TRUE,
                   column_names_gp = gpar(fontsize = 9),
                   row_names_gp = gpar(fontsize = 6),
                   cell_fun = function(j, i, x, y, w, h, col) { 
                     grid.text(round(mean_D4[i, j], 0), x, y, gp = gpar(fontsize = 7))
                   })
  
  # Combining all heatmaps
  h_D4 <- h1_D4 + h2_D4 + h3_D4
  h_D4
  
pdf("AnnotatedHeatmap_D4.pdf", width = 10, height = 6)
draw(h_D4)
dev.off()

png("AnnotatedHeatmap_D4.png", width = 3000, height = 2000, res = 300)
draw(h_D4)
dev.off()
}
library(DOSE)
library(enrichplot)
library(clusterProfiler)

# Using robust genes for pathway analysis
# Converting ENSEMBL to ENTREZ for KEGG analysis
entrez_genes_up_D4 <- mapIds(org.Hs.eg.db, robust_up_D4, "ENTREZID", "ENSEMBL")
entrez_genes_down_D4 <- mapIds(org.Hs.eg.db, robust_down_D4, "ENTREZID", "ENSEMBL")
entrez_genes_up_D4 <- entrez_genes_up_D4[!is.na(entrez_genes_up_D4)]
entrez_genes_down_D4 <- entrez_genes_down_D4[!is.na(entrez_genes_down_D4)]

# Running GO Analysis
  go_up <- enrichGO(gene = robust_up_D4,
                       OrgDb = org.Hs.eg.db,
                       keyType = "ENSEMBL",
                       ont = "ALL",
                       pAdjustMethod = "BH",
                       pvalueCutoff = 0.05)
  as.data.frame(go_up)
  top_go_up_D4 <- go_up@result[1:10, ]
as.data.frame(top_go_up_D4)
  
  go_up_D4 <- plot(barplot(go_up, showCategory = 15) + labs(title = "Upregulated GO Terms (Resistant vs Parental)"))
  ggsave("GO_up_D4.pdf", go_up_D4, width = 7, height = 6)
  ggsave("GO_up_D4.png", go_up_D4, width = 7, height = 6, dpi = 300)

  go_down <- enrichGO(gene = robust_down_D4,
                         OrgDb = org.Hs.eg.db,
                         keyType = "ENSEMBL",
                         ont = "ALL",
                         pAdjustMethod = "BH",
                         pvalueCutoff = 0.05)
  as.data.frame(go_down)
  go_down_D4 <- plot(barplot(go_down, showCategory = 15) + labs(title = "Downregulated GO Terms (Resistant vs Parental)"))
  ggsave("GO_down_D4.pdf", go_down_D4, width = 7, height = 6)
  ggsave("GO_down_D4.png", go_down_D4, width = 7, height = 6, dpi = 300)

# Running KEGG Pathway Analysis
  kegg_up <- enrichKEGG(gene = entrez_genes_up_D4,
                           organism = 'hsa',
                           pvalueCutoff = 0.05,
                           pAdjustMethod = "BH")
  as.data.frame(kegg_up)
  top_kegg_up_D4 <- kegg_up@result[1:10, ]
as.data.frame(top_kegg_up_D4)
  
  
 kegg_up_D4 <-  plot(barplot(kegg_up, showCategory = 15) + labs(title = "Upregulated KEGG Pathways (Resistant vs Parental)"))
  ggsave("KEGG_up_D4.pdf", kegg_up_D4, width = 7, height = 6)
  ggsave("KEGG_up_D4.png", kegg_up_D4, width = 7, height = 6, dpi = 300)


# Add this after the KEGG analysis attempt
  kegg_down <- enrichKEGG(gene = entrez_genes_down_D4,
                             organism = 'hsa',
                             pvalueCutoff = 0.1,
                             pAdjustMethod = "BH")
  as.data.frame(kegg_down)
  
  if(nrow(as.data.frame(kegg_down)) > 0) {
    print(as.data.frame(kegg_down))
    plot(barplot(kegg_down, showCategory = 15) + 
         labs(title = "Downregulated KEGG Pathways (Resistant vs Parental)"))
  } else {
    cat("No KEGG pathways enriched for downregulated genes (n =", 
        length(entrez_genes_down_D4), "genes)\n")
  }
library(fgsea)
library(msigdbr)

# Preparing ranked gene list for GSEA
gene_ranks_D4 <- results_shrunk_D4$log2FoldChange
names(gene_ranks_D4) <- rownames(results_shrunk_D4)
gene_ranks_D4 <- gene_ranks_D4[!is.na(gene_ranks_D4)]
gene_ranks_D4 <- sort(gene_ranks_D4, decreasing = TRUE)

# Getting Hallmark pathways for GSEA
hallmark_sets_D4 <- msigdbr(species = "Homo sapiens", category = "H")
hallmark_list_D4 <- split(hallmark_sets_D4$ensembl_gene, hallmark_sets_D4$gs_name)

# Running GSEA analysis
fgsea_results_D4 <- fgsea(pathways = hallmark_list_D4,
                          stats = gene_ranks_D4,
                          minSize = 15,
                          maxSize = 500)

# Viewing top results
print("Top GSEA Results (Resistant vs Parental):")
print(head(fgsea_results_D4[order(pval), ], 10))

# Plotting top 3 most significant pathways
print("Top 3 GSEA pathways:")
top_pathways_D4 <- head(fgsea_results_D4[order(pval), ], 3)
print(top_pathways_D4[, c("pathway", "pval", "NES")])

for(i in 1:3) {
  pathway_name <- top_pathways_D4$pathway[i]
  pathways_D4 <- plotEnrichment(hallmark_list_D4[[pathway_name]], gene_ranks_D4) + 
    labs(title = paste("Pathway", i, ":", pathway_name))
  print(pathways_D4)
  ggsave("Top3_GSEA_D4.pdf", pathways_D4, width = 7, height = 6)
  ggsave("Top3_GSEA_D4.png", pathways_D4, width = 7, height = 6, dpi = 300)
}
# Summary statistics table for D4
summary_stats_D4 <- data.frame(
  Metric = c("Total Samples", "Genes Analyzed", "Significant DEGs", "Upregulated genes", "Downregulated genes"),
  Value = c(ncol(counts_D4), 
            nrow(res_D4),
            nrow(sig_genes_D4),
            length(sig_genes_up_D4),
            length(sig_genes_down_D4))
)

summary_stats_D4

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

print("Top 20 Significant Genes")
[1] "Top 20 Significant Genes"
print(top_genes_table_D4)
NA
# Export main results
write.csv(as.data.frame(res_annotated_D4), "D4_annotated_results.csv", row.names = TRUE)
write.csv(sig_genes_D4, "D4_sig_genes.csv", row.names = TRUE)
write.csv(summary_stats_D4, "D4_summary_statistics.csv", row.names = FALSE)
write.csv(top_genes_table_D4, "D4_top20_genes.csv", row.names = FALSE)

# Export normalized data
write.csv(counts(dds_D4, normalized=TRUE), "D4_normalized_counts.csv", row.names = TRUE)
write.csv(assay(vst_D4), "D4_vst_data.csv", row.names = TRUE)

# Export pathway results
  write.csv(go_up@result, "D4_GO_upregulated.csv", row.names = FALSE)

  write.csv(go_down@result, "D4_GO_downregulated.csv", row.names = FALSE)


  write.csv(kegg_up@result, "D4_KEGG_upregulated.csv", row.names = FALSE)

# Remove the leadingEdge column (which contains lists)
fgsea_results_clean_D4 <- fgsea_results_D4 %>%
  select(-leadingEdge)

write.csv(fgsea_results_clean_D4, "D4_GSEA_hallmarks.csv", row.names = FALSE)
LS0tDQp0aXRsZTogIkRhdGFzZXQgNCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyfQ0KbGlicmFyeShERVNlcTIpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KYGBge3J9DQpjb3VudHNfRDQgPC0gcmVhZC5kZWxpbSgiY291bnRzX0Q0IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gMSkNCg0KdG90YWxfY291bnRzX3Blcl9nZW5lX0Q0IDwtIHJvd1N1bXMoY291bnRzX0Q0KQ0KaGlzdCh0b3RhbF9jb3VudHNfcGVyX2dlbmVfRDQsIA0KICAgICBicmVha3M9MTAwLCANCiAgICAgbWFpbj0iRGlzdHJpYnV0aW9uIG9mIFRvdGFsIENvdW50cyBwZXIgR2VuZSIsIA0KICAgICB4bGFiPSJUb3RhbCBjb3VudHMgYWNyb3NzIGFsbCBzYW1wbGVzIiwNCiAgICAgeWxhYj0iTnVtYmVyIG9mIGdlbmVzIikNCnN1bW1hcnkodG90YWxfY291bnRzX3Blcl9nZW5lX0Q0KQ0KYGBgDQoNCmBgYHtyfQ0KI2lnbm9yaW5nIGxvdyBleHByZXNzZWQgZ2VuZSB0byByZW1vdmUgbm9pc2UgJiBnZXQgYmV0dGVyIHJlc3VsdHMNCg0KY291bnRzX0Q0IDwtIGNvdW50c19ENFt3aGljaChyb3dTdW1zKGNvdW50c19ENCkgPiA1MCksIF0NCmBgYA0KDQpgYGB7cn0NCiNjYWxsaW5nIGluIHRoZSBtZXRhZGF0YQ0KbWV0YWRhdGFfRDQgPC0gcmVhZC5jc3YoIm1ldGFkYXRhX0Q0LmNzdiIsIGhlYWRlciA9IFRSVUUpDQpgYGANCg0KYGBge3J9DQpjb3VudHNfRDQgPC0gcm91bmQoY291bnRzX0Q0KQ0KZGRzX0Q0IDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzX0Q0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YWRhdGFfRDQsICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiBQSEVOT1RZUEUpDQpkZHNfRDQNCg0KZGRzX0Q0IDwtIERFU2VxKGRkc19ENCkNCmRkc19ENA0KDQpyZXNfRDQgPC0gcmVzdWx0cyhkZHNfRDQpDQpyZXNfRDQNCmBgYA0KDQpgYGB7cn0NCiNtb2RlcmF0ZSBmaWx0ZXJpbmcgDQprZWVwX0Q0IDwtIHJvd1N1bXMoY291bnRzKGRkc19ENCkgPj0gMjApID49IDMNCmRkc19ENCA8LSBkZHNfRDRba2VlcF9ENCxdDQoNCmNhdCgiR2VuZXMgcmV0YWluZWQgd2l0aCBtb2RlcmF0ZSBmaWx0ZXJpbmc6IiwgbnJvdyhkZHNfRDQpLCAiXG4iKQ0KDQojQ2hlY2tpbmcgZGF0YSBxdWFsaXR5IGFmdGVyIERFU2VxMg0KZGRzX0Q0IDwtIERFU2VxKGRkc19ENCwgbWluUmVwbGljYXRlc0ZvclJlcGxhY2UgPSBJbmYpDQoNCnJlc3VsdHNOYW1lcyhkZHNfRDQpDQpzdW1tYXJ5X3Jlc19ENCA8LSByZXN1bHRzKGRkc19ENCwgbmFtZSA9ICJQSEVOT1RZUEVfcmVzaXN0YW50X3ZzX3BhcmVudGFsIikNCnN1bW1hcnkoc3VtbWFyeV9yZXNfRDQpDQpwbG90RGlzcEVzdHMoZGRzX0Q0LCBtYWluID0gIkRpc3BlcnNpb24gRXN0aW1hdGVzOiBFQkMtMSB2cyBFQkMtQ1IiKQ0KDQpwZGYoIkRpc3BlcnNpb25QbG90X0Q0LnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkNCnBsb3REaXNwRXN0cyhkZHNfRDQpDQpkZXYub2ZmKCkNCg0KcG5nKCJEaXNwZXJzaW9uUGxvdF9ENC5wbmciLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDE2MDAsIHJlcyA9IDMwMCkNCnBsb3REaXNwRXN0cyhkZHNfRDQpDQpkZXYub2ZmKCkNCg0KDQoNCnZzdF9ENCA8LSB2c3QoZGRzX0Q0LCBibGluZCA9IEZBTFNFKQ0KDQp2c3RfbWF0cml4X0Q0IDwtIGFzc2F5KHZzdF9ENCkNCg0KaGVhZCh2c3RfbWF0cml4X0Q0WzE6NSwgMTozXSkNCg0KbGlicmFyeShyZXNoYXBlMikNCg0KdnN0X2RmX0Q0IDwtIGFzLmRhdGEuZnJhbWUodnN0X21hdHJpeF9ENCkNCnZzdF9kZl9ENCRnZW5lX2lkIDwtIHJvd25hbWVzKHZzdF9kZl9ENCkNCg0KdnN0X2ZpbmFsX0Q0IDwtIG1lbHQodnN0X2RmX0Q0LCANCiAgICAgICAgICAgICAgICAgaWQudmFycyA9ICJnZW5lX2lkIiwgDQogICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAic2FtcGxlX2lkIiwgDQogICAgICAgICAgICAgICAgIHZhbHVlLm5hbWUgPSAiZXhwcmVzc2lvbl92YWx1ZSIpDQoNCmhlYWQodnN0X2ZpbmFsX0Q0KQ0KYGBgDQoNCldlIGluY3JlYXNlZCB0aGUgY291bnRzIHRocmVzaG9sZCBiZWNhdXNlIG9mIHRoZSBpbWJhbGFuY2UgaW4gZ3JvdXBzLCBpZS4gMSB2cyAzLiBXZSBuZWVkZWQgdG8gY2xlYXIgdGhlIG5vaXNlIGZvciBiZXR0ZXIgcmVzdWx0cy5XZSBnb3QgZ29vZCByZXN1bHRzLiANCg0KYGBge3J9DQpwY2FfcGxvdF9ENCA8LSBwbG90UENBKHZzdF9ENCwgaW50Z3JvdXAgPSAiUEhFTk9UWVBFIikgKw0KICBnZ3RpdGxlKCJQQ0E6IEVCQy0xIFBhcmVudGFsIHZzIEVCQy1DUiBSZXNpc3RhbnQgKDEgdnMgMyBJbWJhbGFuY2UpIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgDQpwY2FfcGxvdF9ENA0KDQpnZ3NhdmUoKCJENF9QQ0EucGRmIiksIHBjYV9wbG90X0Q0LCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpnZ3NhdmUoKCJENF9QQ0EucG5nIiksIHBjYV9wbG90X0Q0LCB3aWR0aCA9IDYsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkNCmBgYA0KVGhlIFBDQSAiU3ByZWFkIiBpcyBOT1QgRHVlIHRvIFBvb3IgUXVhbGl0eToNCg0KLSBDb3JyZWxhdGlvbnMgbWVhc3VyZSBvdmVyYWxsIGdlbmUgZXhwcmVzc2lvbiBzaW1pbGFyaXR5IChQZWFyc29uIGNvcnJlbGF0aW9uKS4NCi0gUENBIGNhcHR1cmVzIHRoZSBkaW1lbnNpb25zIG9mIGdyZWF0ZXN0IHZhcmlhdGlvbiAoZXZlbiBpZiBzbWFsbCBpbiBhYnNvbHV0ZSB0ZXJtcykuDQotIEhpZ2ggY29ycmVsYXRpb25zICgwLjg3LTAuOTcpIHdpdGggY2xlYXIgUENBIHNlcGFyYXRpb24gPSBoaWdoLXF1YWxpdHkgZGF0YSB3aXRoIHJlYWwgYmlvbG9naWNhbCBkaWZmZXJlbmNlcy4NCg0KYGBge3J9DQpyZXN1bHRzTmFtZXMoZGRzX0Q0KQ0KDQpyZXN1bHRzX0Q0IDwtIHJlc3VsdHMoZGRzX0Q0LA0KICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjAxLCAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICBsZmNUaHJlc2hvbGQgPSAxLCAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgY29va3NDdXRvZmYgPSBGQUxTRSwgICAgDQogICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoIlBIRU5PVFlQRSIsICJyZXNpc3RhbnQiLCAicGFyZW50YWwiKSkNCg0KcHJpbnQoIlJlc3VsdHMgc3VtbWFyeSB3aXRoIHN0cmljdCB0aHJlc2hvbGRzOiIpDQpzdW1tYXJ5KHJlc3VsdHNfRDQpDQpyZXN1bHRzX0Q0DQpgYGANCmBgYHtyfQ0KdHJ5Q2F0Y2goew0KICByZXN1bHRzX3NocnVua19ENCA8LSBsZmNTaHJpbmsoZGRzX0Q0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0iUEhFTk9UWVBFX3Jlc2lzdGFudF92c19wYXJlbnRhbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJhcGVnbG0iKQ0KICBwcmludCgiTEZDIHNocmlua2FnZSBzdWNjZXNzZnVsIikNCn0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICBwcmludCgiTEZDIHNocmlua2FnZSBmYWlsZWQgZHVlIHRvIHNhbXBsZSBpbWJhbGFuY2UgLSB1c2luZyB1bnNocnVua2VuIHJlc3VsdHMiKQ0KICByZXN1bHRzX3NocnVua19ENCA8LSByZXN1bHRzX0Q0DQp9KQ0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KEFubm90YXRpb25EYmkpDQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikNCg0KIyBDb252ZXJ0aW5nIEVOU0VNQkwgSURzIHRvIGdlbmUgc3ltYm9scw0KZ2VuZV9zeW1ib2xzX0Q0IDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGtleXMgPSByb3duYW1lcyhkZHNfRDQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4gPSAiU1lNQk9MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAga2V5dHlwZSA9ICJFTlNFTUJMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGlWYWxzID0gImZpcnN0IikNCg0KcmVzX2Fubm90YXRlZF9ENCA8LSByZXN1bHRzX0Q0DQpyZXNfYW5ub3RhdGVkX0Q0JGdlbmVfc3ltYm9sIDwtIGdlbmVfc3ltYm9sc19ENA0KYXMuZGF0YS5mcmFtZShyZXNfYW5ub3RhdGVkX0Q0KQ0KDQojIEFkZGluZyBhbm5vdGF0aW9ucyB0byByZXN1bHRzDQpyZXNfYW5ub3RhdGVkX0Q0IDwtIHJlc3VsdHNfc2hydW5rX0Q0DQpyZXNfYW5ub3RhdGVkX0Q0JGdlbmVfc3ltYm9sIDwtIGdlbmVfc3ltYm9sc19ENA0KYGBgDQoNCmBgYHtyfQ0KIyBVc2luZyBzdHJpY3QgY3JpdGVyaWEgZm9yIHNpZ25pZmljYW5jZQ0Kc2lnX2dlbmVzX0Q0IDwtIHJlc19hbm5vdGF0ZWRfRDRbd2hpY2gocmVzX2Fubm90YXRlZF9ENCRwYWRqIDwgMC4wMSAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJzKHJlc19hbm5vdGF0ZWRfRDQkbG9nMkZvbGRDaGFuZ2UpID4gMSksIF0NCg0KbnJvdyhzaWdfZ2VuZXNfRDQpDQoNCiMgR2V0IHRvcCBnZW5lcw0KdG9wX2dlbmVzX0Q0IDwtIGhlYWQoc2lnX2dlbmVzX0Q0W29yZGVyKHNpZ19nZW5lc19ENCRwYWRqKSwgXSwgMjApDQoNCmBgYA0KDQpgYGB7cn0NCiMgU2luY2Ugd2UgaGF2ZSAzIHJlc2lzdGFudCBzYW1wbGVzLCBjaGVjayBjb25zaXN0ZW5jeQ0Kbm9ybWFsaXplZF9jb3VudHNfRDQgPC0gY291bnRzKGRkc19ENCwgbm9ybWFsaXplZCA9IFRSVUUpDQoNCiMgQ2FsY3VsYXRlIGZvbGQgY2hhbmdlIGZvciBlYWNoIHJlc2lzdGFudCBzYW1wbGUgdnMgcGFyZW50YWwNCnBhcmVudGFsX2NvdW50cyA8LSBub3JtYWxpemVkX2NvdW50c19ENFssIG1ldGFkYXRhX0Q0JFBIRU5PVFlQRSA9PSAicGFyZW50YWwiXQ0KcmVzaXN0YW50X3NhbXBsZXMgPC0gY29sbmFtZXMobm9ybWFsaXplZF9jb3VudHNfRDQpW21ldGFkYXRhX0Q0JFBIRU5PVFlQRSA9PSAicmVzaXN0YW50Il0NCg0KIyBDaGVjayBjb25zaXN0ZW5jeSBhY3Jvc3MgcmVzaXN0YW50IHNhbXBsZXMNCmZjX21hdHJpeCA8LSBzYXBwbHkocmVzaXN0YW50X3NhbXBsZXMsIGZ1bmN0aW9uKHNhbXBsZSkgew0KICBsb2cyKChub3JtYWxpemVkX2NvdW50c19ENFssIHNhbXBsZV0gKyAxKSAvIChwYXJlbnRhbF9jb3VudHMgKyAxKSkNCn0pDQoNCiMgRmluZCBnZW5lcyBjb25zaXN0ZW50bHkgdXAgb3IgZG93biBpbiBhbGwgcmVzaXN0YW50IHNhbXBsZXMNCmNvbnNpc3RlbnRfdXAgPC0gcm93bmFtZXMoZmNfbWF0cml4KVthcHBseShmY19tYXRyaXggPiAwLjUsIDEsIGFsbCldDQpjb25zaXN0ZW50X2Rvd24gPC0gcm93bmFtZXMoZmNfbWF0cml4KVthcHBseShmY19tYXRyaXggPCAtMC41LCAxLCBhbGwpXQ0KDQojIFJvYnVzdCBnZW5lczogc2lnbmlmaWNhbnQgQU5EIGNvbnNpc3RlbnQNCnNpZ19nZW5lc191cF9ENCA8LSByb3duYW1lcyhzaWdfZ2VuZXNfRDQpW3NpZ19nZW5lc19ENCRsb2cyRm9sZENoYW5nZSA+IDBdDQpzaWdfZ2VuZXNfZG93bl9ENCA8LSByb3duYW1lcyhzaWdfZ2VuZXNfRDQpW3NpZ19nZW5lc19ENCRsb2cyRm9sZENoYW5nZSA8IDBdDQoNCnJvYnVzdF91cF9ENCA8LSBpbnRlcnNlY3Qoc2lnX2dlbmVzX3VwX0Q0LCBjb25zaXN0ZW50X3VwKQ0Kcm9idXN0X2Rvd25fRDQgPC0gaW50ZXJzZWN0KHNpZ19nZW5lc19kb3duX0Q0LCBjb25zaXN0ZW50X2Rvd24pDQoNCmNhdCgiU2lnbmlmaWNhbnQgZ2VuZXM6IiwgbnJvdyhzaWdfZ2VuZXNfRDQpLCAiXG4iKQ0KY2F0KCJSb2J1c3QgdXByZWd1bGF0ZWQgKHNpZ25pZmljYW50ICsgY29uc2lzdGVudCk6IiwgbGVuZ3RoKHJvYnVzdF91cF9ENCksICJcbiIpDQpjYXQoIlJvYnVzdCBkb3ducmVndWxhdGVkIChzaWduaWZpY2FudCArIGNvbnNpc3RlbnQpOiIsIGxlbmd0aChyb2J1c3RfZG93bl9ENCksICJcbiIpDQpgYGANCg0KYGBge3J9DQojIE1BIFBsb3QNCnBsb3RNQShyZXN1bHRzX3NocnVua19ENCwgeWxpbSA9IGMoLTUsIDUpLCBtYWluID0gIlJlc2lzdGFudCB2cyBQYXJlbnRhbCIpDQoNCnBkZigoIk1BX0Q0LnBkZiIpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpDQpwbG90TUEocmVzdWx0c19zaHJ1bmtfRDQsIHlsaW09YygtNSw1KSwgbWFpbj0iUmVzaXN0YW50IHZzIFBhcmVudGFsIikNCmRldi5vZmYoKQ0KDQpwbmcoKCJNQV9ENC5wbmciKSwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNjAwLCByZXMgPSAzMDApDQpwbG90TUEocmVzdWx0c19zaHJ1bmtfRDQsIHlsaW09YygtNSw1KSwgbWFpbj0iUmVzaXN0YW50IHZzIFBhcmVudGFsIikNCmRldi5vZmYoKQ0KDQojIFZvbGNhbm8gcGxvdA0KbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pDQp2b2xjYW5vX3Bsb3QgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc19hbm5vdGF0ZWRfRDQsIGxhYiA9IHJlc19hbm5vdGF0ZWRfRDQkZ2VuZV9zeW1ib2wsIA0KICAgICAgICAgICAgICAgIHggPSAnbG9nMkZvbGRDaGFuZ2UnLCB5ID0gJ3BhZGonLA0KICAgICAgICAgICAgICAgIHRpdGxlID0gJ0VCQy1DUiBSZXNpc3RhbnQgdnMgRUJDLTEgUGFyZW50YWwnLA0KICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjAxLA0KICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSkNCmdnc2F2ZSgoIkQ0X1ZvbGNhbm8ucGRmIiksIHZvbGNhbm9fcGxvdCwgd2lkdGggPSA2LCBoZWlnaHQgPSA1KQ0KZ2dzYXZlKCgiRDRfVm9sY2Fuby5wbmciKSwgdm9sY2Fub19wbG90LCB3aWR0aCA9IDYsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkNCg0KIyBIZWF0bWFwIG9mIHNpZ25pZmljYW50IGdlbmVzDQpsaWJyYXJ5KHBoZWF0bWFwKQ0KaWYobnJvdyhzaWdfZ2VuZXNfRDQpID4gMCkgew0KICB0b3Bfc2lnX2dlbmVzIDwtIGhlYWQocm93bmFtZXMoc2lnX2dlbmVzX0Q0W29yZGVyKHNpZ19nZW5lc19ENCRwYWRqKSwgXSksIDUwKQ0KICBwaGVhdG1hcDo6cGhlYXRtYXAoYXNzYXkodnN0X0Q0KVt0b3Bfc2lnX2dlbmVzLF0sIA0KICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShkZHNfRDQpWywgIlBIRU5PVFlQRSIsIGRyb3AgPSBGQUxTRV0pLCANCiAgICAgICAgICAgc2NhbGUgPSAicm93IiwgDQogICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICAgbWFpbiA9ICJUb3AgNTAgRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIiwNCiAgICAgICAgICAgZmlsZW5hbWUgPSAiREVHc19ENC5wbmciKQ0KfQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShDb21wbGV4SGVhdG1hcCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShjaXJjbGl6ZSkNCg0KIyBQcmVwYXJpbmcgdG9wIGdlbmVzIGZvciBlbmhhbmNlZCBoZWF0bWFwIC0gZm9jdXMgb24gcm9idXN0IGdlbmVzDQppZihsZW5ndGgoYyhyb2J1c3RfdXBfRDQsIHJvYnVzdF9kb3duX0Q0KSkgPiAxMCkgew0KICAjIENvbWJpbmUgcm9idXN0IHVwIGFuZCBkb3duIGdlbmVzDQogIHJvYnVzdF9nZW5lc19ENCA8LSBjKHJvYnVzdF91cF9ENCwgcm9idXN0X2Rvd25fRDQpDQogIHJvYnVzdF9nZW5lc19kYXRhIDwtIHJlc19hbm5vdGF0ZWRfRDRbcm9idXN0X2dlbmVzX0Q0LF0NCiAgDQogICMgU29ydCBieSBmb2xkIGNoYW5nZQ0KICByb2J1c3RfZ2VuZXNfZGF0YSA8LSByb2J1c3RfZ2VuZXNfZGF0YVtvcmRlcihyb2J1c3RfZ2VuZXNfZGF0YSRsb2cyRm9sZENoYW5nZSwgZGVjcmVhc2luZyA9IFRSVUUpLF0NCiAgdG9wX3JvYnVzdF9ENCA8LSBoZWFkKHJvd25hbWVzKHJvYnVzdF9nZW5lc19kYXRhKSwgNTApDQogIA0KICAjIEdldHRpbmcgbm9ybWFsaXplZCBjb3VudCBkYXRhDQogIG1hdF9ENCA8LSBhc3NheSh2c3RfRDQpW3RvcF9yb2J1c3RfRDQsIF0NCiAgbWF0X3NjYWxlZF9ENCA8LSB0KGFwcGx5KG1hdF9ENCwgMSwgc2NhbGUpKQ0KICBjb2xuYW1lcyhtYXRfc2NhbGVkX0Q0KSA8LSBjb2xuYW1lcyhtYXRfRDQpDQogIA0KICAjIFNlbGVjdGluZyB0b3AgYW5kIGJvdHRvbSBnZW5lcw0KICBudW1fa2VlcCA8LSBtaW4oMjUsIGZsb29yKG5yb3cobWF0X3NjYWxlZF9ENCkvMikpDQogIHJvd3Nfa2VlcF9ENCA8LSBjKHNlcSgxOm51bV9rZWVwKSwgc2VxKChucm93KG1hdF9zY2FsZWRfRDQpIC0gbnVtX2tlZXAgKyAxKSwgbnJvdyhtYXRfc2NhbGVkX0Q0KSkpDQogIA0KICAjIFByZXBhcmluZyBhbm5vdGF0aW9uIG1hdHJpY2VzDQogIGwyX3ZhbF9ENCA8LSBhcy5tYXRyaXgocm9idXN0X2dlbmVzX2RhdGFbcm93c19rZWVwX0Q0LF0kbG9nMkZvbGRDaGFuZ2UpDQogIGNvbG5hbWVzKGwyX3ZhbF9ENCkgPC0gImxvZ0ZDIg0KICANCiAgbWVhbl9ENCA8LSBhcy5tYXRyaXgocm9idXN0X2dlbmVzX2RhdGFbcm93c19rZWVwX0Q0LF0kYmFzZU1lYW4pDQogIGNvbG5hbWVzKG1lYW5fRDQpIDwtICJBdmVFeHByIg0KICANCiAgIyBTZXR0aW5nIHVwIGNvbG9yIHNjaGVtZXMNCiAgY29sX2xvZ0ZDX0Q0IDwtIGNvbG9yUmFtcDIoYyhtaW4obDJfdmFsX0Q0KSwgMCwgbWF4KGwyX3ZhbF9ENCkpLCBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQ0KICBjb2xfQXZlRXhwcl9ENCA8LSBjb2xvclJhbXAyKGMocXVhbnRpbGUobWVhbl9ENClbMV0sIHF1YW50aWxlKG1lYW5fRDQpWzRdKSwgYygid2hpdGUiLCAicmVkIikpDQogIGNvbF96c2NvcmVfRDQgPC0gY29sb3JSYW1wMihjKC0yLCAwLCAyKSwgYygiIzQ1NzViNCIsICJ3aGl0ZSIsICIjZDczMDI3IikpDQogIA0KICAjIENyZWF0aW5nIGhlYXRtYXBzDQogIGgxX0Q0IDwtIEhlYXRtYXAobWF0X3NjYWxlZF9ENFtyb3dzX2tlZXBfRDQsXSwgDQogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICBjb2x1bW5fbGFiZWxzID0gY29sbmFtZXMobWF0X3NjYWxlZF9ENCksIA0KICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiWi1zY29yZSIsDQogICAgICAgICAgICAgICAgICAgY29sID0gY29sX3pzY29yZV9ENCwNCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDkpLA0KICAgICAgICAgICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICJSb2J1c3QgUmVzaXN0YW5jZSBHZW5lcyIpDQogIA0KICBoMl9ENCA8LSBIZWF0bWFwKGwyX3ZhbF9ENCwgDQogICAgICAgICAgICAgICAgICAgcm93X2xhYmVscyA9IHJvYnVzdF9nZW5lc19kYXRhJGdlbmVfc3ltYm9sW3Jvd3Nfa2VlcF9ENF0sDQogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgIG5hbWUgPSAibG9nRkMiLCANCiAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xfbG9nRkNfRDQsDQogICAgICAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDE1LCAibW0iKSwNCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLA0KICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA5KSwNCiAgICAgICAgICAgICAgICAgICBjZWxsX2Z1biA9IGZ1bmN0aW9uKGosIGksIHgsIHksIHcsIGgsIGNvbCkgeyANCiAgICAgICAgICAgICAgICAgICAgIGdyaWQudGV4dChyb3VuZChsMl92YWxfRDRbaSwgal0sIDEpLCB4LCB5LCBncCA9IGdwYXIoZm9udHNpemUgPSA3KSkNCiAgICAgICAgICAgICAgICAgICB9KQ0KICANCiAgaDNfRDQgPC0gSGVhdG1hcChtZWFuX0Q0LCANCiAgICAgICAgICAgICAgICAgICByb3dfbGFiZWxzID0gcm9idXN0X2dlbmVzX2RhdGEkZ2VuZV9zeW1ib2xbcm93c19rZWVwX0Q0XSwNCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgbmFtZSA9ICJBdmVFeHByIiwgDQogICAgICAgICAgICAgICAgICAgY29sID0gY29sX0F2ZUV4cHJfRDQsDQogICAgICAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDE1LCAibW0iKSwNCiAgICAgICAgICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA5KSwNCiAgICAgICAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksDQogICAgICAgICAgICAgICAgICAgY2VsbF9mdW4gPSBmdW5jdGlvbihqLCBpLCB4LCB5LCB3LCBoLCBjb2wpIHsgDQogICAgICAgICAgICAgICAgICAgICBncmlkLnRleHQocm91bmQobWVhbl9ENFtpLCBqXSwgMCksIHgsIHksIGdwID0gZ3Bhcihmb250c2l6ZSA9IDcpKQ0KICAgICAgICAgICAgICAgICAgIH0pDQogIA0KICAjIENvbWJpbmluZyBhbGwgaGVhdG1hcHMNCiAgaF9ENCA8LSBoMV9ENCArIGgyX0Q0ICsgaDNfRDQNCiAgaF9ENA0KICANCnBkZigiQW5ub3RhdGVkSGVhdG1hcF9ENC5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2KQ0KZHJhdyhoX0Q0KQ0KZGV2Lm9mZigpDQoNCnBuZygiQW5ub3RhdGVkSGVhdG1hcF9ENC5wbmciLCB3aWR0aCA9IDMwMDAsIGhlaWdodCA9IDIwMDAsIHJlcyA9IDMwMCkNCmRyYXcoaF9ENCkNCmRldi5vZmYoKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShET1NFKQ0KbGlicmFyeShlbnJpY2hwbG90KQ0KbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpDQoNCiMgVXNpbmcgcm9idXN0IGdlbmVzIGZvciBwYXRod2F5IGFuYWx5c2lzDQojIENvbnZlcnRpbmcgRU5TRU1CTCB0byBFTlRSRVogZm9yIEtFR0cgYW5hbHlzaXMNCmVudHJlel9nZW5lc191cF9ENCA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLCByb2J1c3RfdXBfRDQsICJFTlRSRVpJRCIsICJFTlNFTUJMIikNCmVudHJlel9nZW5lc19kb3duX0Q0IDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsIHJvYnVzdF9kb3duX0Q0LCAiRU5UUkVaSUQiLCAiRU5TRU1CTCIpDQplbnRyZXpfZ2VuZXNfdXBfRDQgPC0gZW50cmV6X2dlbmVzX3VwX0Q0WyFpcy5uYShlbnRyZXpfZ2VuZXNfdXBfRDQpXQ0KZW50cmV6X2dlbmVzX2Rvd25fRDQgPC0gZW50cmV6X2dlbmVzX2Rvd25fRDRbIWlzLm5hKGVudHJlel9nZW5lc19kb3duX0Q0KV0NCg0KIyBSdW5uaW5nIEdPIEFuYWx5c2lzDQogIGdvX3VwIDwtIGVucmljaEdPKGdlbmUgPSByb2J1c3RfdXBfRDQsDQogICAgICAgICAgICAgICAgICAgICAgIE9yZ0RiID0gb3JnLkhzLmVnLmRiLA0KICAgICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gIkVOU0VNQkwiLA0KICAgICAgICAgICAgICAgICAgICAgICBvbnQgPSAiQUxMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIsDQogICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpDQogIGFzLmRhdGEuZnJhbWUoZ29fdXApDQogIHRvcF9nb191cF9ENCA8LSBnb191cEByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3BfZ29fdXBfRDQpDQogIA0KICBnb191cF9ENCA8LSBwbG90KGJhcnBsb3QoZ29fdXAsIHNob3dDYXRlZ29yeSA9IDE1KSArIGxhYnModGl0bGUgPSAiVXByZWd1bGF0ZWQgR08gVGVybXMgKFJlc2lzdGFudCB2cyBQYXJlbnRhbCkiKSkNCiAgZ2dzYXZlKCJHT191cF9ENC5wZGYiLCBnb191cF9ENCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIkdPX3VwX0Q0LnBuZyIsIGdvX3VwX0Q0LCB3aWR0aCA9IDcsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KICBnb19kb3duIDwtIGVucmljaEdPKGdlbmUgPSByb2J1c3RfZG93bl9ENCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5Icy5lZy5kYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gIkVOU0VNQkwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG9udCA9ICJBTEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHBBZGp1c3RNZXRob2QgPSAiQkgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMDUpDQogIGFzLmRhdGEuZnJhbWUoZ29fZG93bikNCiAgZ29fZG93bl9ENCA8LSBwbG90KGJhcnBsb3QoZ29fZG93biwgc2hvd0NhdGVnb3J5ID0gMTUpICsgbGFicyh0aXRsZSA9ICJEb3ducmVndWxhdGVkIEdPIFRlcm1zIChSZXNpc3RhbnQgdnMgUGFyZW50YWwpIikpDQogIGdnc2F2ZSgiR09fZG93bl9ENC5wZGYiLCBnb19kb3duX0Q0LCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpDQogIGdnc2F2ZSgiR09fZG93bl9ENC5wbmciLCBnb19kb3duX0Q0LCB3aWR0aCA9IDcsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkNCg0KIyBSdW5uaW5nIEtFR0cgUGF0aHdheSBBbmFseXNpcw0KICBrZWdnX3VwIDwtIGVucmljaEtFR0coZ2VuZSA9IGVudHJlel9nZW5lc191cF9ENCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gJ2hzYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIpDQogIGFzLmRhdGEuZnJhbWUoa2VnZ191cCkNCiAgdG9wX2tlZ2dfdXBfRDQgPC0ga2VnZ191cEByZXN1bHRbMToxMCwgXQ0KYXMuZGF0YS5mcmFtZSh0b3Bfa2VnZ191cF9ENCkNCiAgDQogIA0KIGtlZ2dfdXBfRDQgPC0gIHBsb3QoYmFycGxvdChrZWdnX3VwLCBzaG93Q2F0ZWdvcnkgPSAxNSkgKyBsYWJzKHRpdGxlID0gIlVwcmVndWxhdGVkIEtFR0cgUGF0aHdheXMgKFJlc2lzdGFudCB2cyBQYXJlbnRhbCkiKSkNCiAgZ2dzYXZlKCJLRUdHX3VwX0Q0LnBkZiIsIGtlZ2dfdXBfRDQsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikNCiAgZ2dzYXZlKCJLRUdHX3VwX0Q0LnBuZyIsIGtlZ2dfdXBfRDQsIHdpZHRoID0gNywgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KDQoNCiMgQWRkIHRoaXMgYWZ0ZXIgdGhlIEtFR0cgYW5hbHlzaXMgYXR0ZW1wdA0KICBrZWdnX2Rvd24gPC0gZW5yaWNoS0VHRyhnZW5lID0gZW50cmV6X2dlbmVzX2Rvd25fRDQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gJ2hzYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiA9IDAuMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIpDQogIGFzLmRhdGEuZnJhbWUoa2VnZ19kb3duKQ0KICANCiAgaWYobnJvdyhhcy5kYXRhLmZyYW1lKGtlZ2dfZG93bikpID4gMCkgew0KICAgIHByaW50KGFzLmRhdGEuZnJhbWUoa2VnZ19kb3duKSkNCiAgICBwbG90KGJhcnBsb3Qoa2VnZ19kb3duLCBzaG93Q2F0ZWdvcnkgPSAxNSkgKyANCiAgICAgICAgIGxhYnModGl0bGUgPSAiRG93bnJlZ3VsYXRlZCBLRUdHIFBhdGh3YXlzIChSZXNpc3RhbnQgdnMgUGFyZW50YWwpIikpDQogIH0gZWxzZSB7DQogICAgY2F0KCJObyBLRUdHIHBhdGh3YXlzIGVucmljaGVkIGZvciBkb3ducmVndWxhdGVkIGdlbmVzIChuID0iLCANCiAgICAgICAgbGVuZ3RoKGVudHJlel9nZW5lc19kb3duX0Q0KSwgImdlbmVzKVxuIikNCiAgfQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGZnc2VhKQ0KbGlicmFyeShtc2lnZGJyKQ0KDQojIFByZXBhcmluZyByYW5rZWQgZ2VuZSBsaXN0IGZvciBHU0VBDQpnZW5lX3JhbmtzX0Q0IDwtIHJlc3VsdHNfc2hydW5rX0Q0JGxvZzJGb2xkQ2hhbmdlDQpuYW1lcyhnZW5lX3JhbmtzX0Q0KSA8LSByb3duYW1lcyhyZXN1bHRzX3NocnVua19ENCkNCmdlbmVfcmFua3NfRDQgPC0gZ2VuZV9yYW5rc19ENFshaXMubmEoZ2VuZV9yYW5rc19ENCldDQpnZW5lX3JhbmtzX0Q0IDwtIHNvcnQoZ2VuZV9yYW5rc19ENCwgZGVjcmVhc2luZyA9IFRSVUUpDQoNCiMgR2V0dGluZyBIYWxsbWFyayBwYXRod2F5cyBmb3IgR1NFQQ0KaGFsbG1hcmtfc2V0c19ENCA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiSCIpDQpoYWxsbWFya19saXN0X0Q0IDwtIHNwbGl0KGhhbGxtYXJrX3NldHNfRDQkZW5zZW1ibF9nZW5lLCBoYWxsbWFya19zZXRzX0Q0JGdzX25hbWUpDQoNCiMgUnVubmluZyBHU0VBIGFuYWx5c2lzDQpmZ3NlYV9yZXN1bHRzX0Q0IDwtIGZnc2VhKHBhdGh3YXlzID0gaGFsbG1hcmtfbGlzdF9ENCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMgPSBnZW5lX3JhbmtzX0Q0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5TaXplID0gMTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1heFNpemUgPSA1MDApDQoNCiMgVmlld2luZyB0b3AgcmVzdWx0cw0KcHJpbnQoIlRvcCBHU0VBIFJlc3VsdHMgKFJlc2lzdGFudCB2cyBQYXJlbnRhbCk6IikNCnByaW50KGhlYWQoZmdzZWFfcmVzdWx0c19ENFtvcmRlcihwdmFsKSwgXSwgMTApKQ0KDQojIFBsb3R0aW5nIHRvcCAzIG1vc3Qgc2lnbmlmaWNhbnQgcGF0aHdheXMNCnByaW50KCJUb3AgMyBHU0VBIHBhdGh3YXlzOiIpDQp0b3BfcGF0aHdheXNfRDQgPC0gaGVhZChmZ3NlYV9yZXN1bHRzX0Q0W29yZGVyKHB2YWwpLCBdLCAzKQ0KcHJpbnQodG9wX3BhdGh3YXlzX0Q0WywgYygicGF0aHdheSIsICJwdmFsIiwgIk5FUyIpXSkNCg0KZm9yKGkgaW4gMTozKSB7DQogIHBhdGh3YXlfbmFtZSA8LSB0b3BfcGF0aHdheXNfRDQkcGF0aHdheVtpXQ0KICBwYXRod2F5c19ENCA8LSBwbG90RW5yaWNobWVudChoYWxsbWFya19saXN0X0Q0W1twYXRod2F5X25hbWVdXSwgZ2VuZV9yYW5rc19ENCkgKyANCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlBhdGh3YXkiLCBpLCAiOiIsIHBhdGh3YXlfbmFtZSkpDQogIHByaW50KHBhdGh3YXlzX0Q0KQ0KICBnZ3NhdmUoIlRvcDNfR1NFQV9ENC5wZGYiLCBwYXRod2F5c19ENCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQ0KICBnZ3NhdmUoIlRvcDNfR1NFQV9ENC5wbmciLCBwYXRod2F5c19ENCwgd2lkdGggPSA3LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQp9DQpgYGANCg0KDQpgYGB7cn0NCiMgU3VtbWFyeSBzdGF0aXN0aWNzIHRhYmxlIGZvciBENA0Kc3VtbWFyeV9zdGF0c19ENCA8LSBkYXRhLmZyYW1lKA0KICBNZXRyaWMgPSBjKCJUb3RhbCBTYW1wbGVzIiwgIkdlbmVzIEFuYWx5emVkIiwgIlNpZ25pZmljYW50IERFR3MiLCAiVXByZWd1bGF0ZWQgZ2VuZXMiLCAiRG93bnJlZ3VsYXRlZCBnZW5lcyIpLA0KICBWYWx1ZSA9IGMobmNvbChjb3VudHNfRDQpLCANCiAgICAgICAgICAgIG5yb3cocmVzX0Q0KSwNCiAgICAgICAgICAgIG5yb3coc2lnX2dlbmVzX0Q0KSwNCiAgICAgICAgICAgIGxlbmd0aChzaWdfZ2VuZXNfdXBfRDQpLA0KICAgICAgICAgICAgbGVuZ3RoKHNpZ19nZW5lc19kb3duX0Q0KSkNCikNCg0Kc3VtbWFyeV9zdGF0c19ENA0KDQojIFRvcCBnZW5lcyB0YWJsZQ0KdG9wX2dlbmVzX3RhYmxlX0Q0IDwtIGRhdGEuZnJhbWUoDQogIEdlbmVfU3ltYm9sID0gZ2VuZV9zeW1ib2xzX0Q0W3Jvd25hbWVzKGhlYWQoc2lnX2dlbmVzX0Q0W29yZGVyKHNpZ19nZW5lc19ENCRwYWRqKSxdLCAyMCkpXSwNCiAgRU5TRU1CTF9JRCA9IHJvd25hbWVzKGhlYWQoc2lnX2dlbmVzX0Q0W29yZGVyKHNpZ19nZW5lc19ENCRwYWRqKSxdLCAyMCkpLA0KICBMb2cyRkMgPSByb3VuZChoZWFkKHNpZ19nZW5lc19ENFtvcmRlcihzaWdfZ2VuZXNfRDQkcGFkaiksXSwgMjApJGxvZzJGb2xkQ2hhbmdlLCAzKSwNCiAgUGFkaiA9IGZvcm1hdChoZWFkKHNpZ19nZW5lc19ENFtvcmRlcihzaWdfZ2VuZXNfRDQkcGFkaiksXSwgMjApJHBhZGosIHNjaWVudGlmaWMgPSBUUlVFLCBkaWdpdHMgPSAzKSwNCiAgRGlyZWN0aW9uID0gaWZlbHNlKGhlYWQoc2lnX2dlbmVzX0Q0W29yZGVyKHNpZ19nZW5lc19ENCRwYWRqKSxdLCAyMCkkbG9nMkZvbGRDaGFuZ2UgPiAwLCAiVXAiLCAiRG93biIpDQopDQoNCnByaW50KCJUb3AgMjAgU2lnbmlmaWNhbnQgR2VuZXMiKQ0KcHJpbnQodG9wX2dlbmVzX3RhYmxlX0Q0KQ0KDQpgYGANCg0KYGBge3J9DQojIEV4cG9ydCBtYWluIHJlc3VsdHMNCndyaXRlLmNzdihhcy5kYXRhLmZyYW1lKHJlc19hbm5vdGF0ZWRfRDQpLCAiRDRfYW5ub3RhdGVkX3Jlc3VsdHMuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCndyaXRlLmNzdihzaWdfZ2VuZXNfRDQsICJENF9zaWdfZ2VuZXMuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCndyaXRlLmNzdihzdW1tYXJ5X3N0YXRzX0Q0LCAiRDRfc3VtbWFyeV9zdGF0aXN0aWNzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0Kd3JpdGUuY3N2KHRvcF9nZW5lc190YWJsZV9ENCwgIkQ0X3RvcDIwX2dlbmVzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQojIEV4cG9ydCBub3JtYWxpemVkIGRhdGENCndyaXRlLmNzdihyZXNfYW5ub3RhdGVkX0Q0LCAiRDRfcmVzdWx0cy5jc3YiKQ0Kd3JpdGUuY3N2KGNvdW50cyhkZHNfRDQsIG5vcm1hbGl6ZWQ9VFJVRSksICJENF9ub3JtYWxpemVkX2NvdW50cy5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQ0Kd3JpdGUuY3N2KHZzdF9maW5hbF9ENCwgIkQ0X3ZzdF9kYXRhLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpDQoNCiMgRXhwb3J0IHBhdGh3YXkgcmVzdWx0cw0KICB3cml0ZS5jc3YoZ29fdXBAcmVzdWx0LCAiRDRfR09fdXByZWd1bGF0ZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiAgd3JpdGUuY3N2KGdvX2Rvd25AcmVzdWx0LCAiRDRfR09fZG93bnJlZ3VsYXRlZC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCg0KDQogIHdyaXRlLmNzdihrZWdnX3VwQHJlc3VsdCwgIkQ0X0tFR0dfdXByZWd1bGF0ZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgUmVtb3ZlIHRoZSBsZWFkaW5nRWRnZSBjb2x1bW4gKHdoaWNoIGNvbnRhaW5zIGxpc3RzKQ0KZmdzZWFfcmVzdWx0c19jbGVhbl9ENCA8LSBmZ3NlYV9yZXN1bHRzX0Q0ICU+JQ0KICBzZWxlY3QoLWxlYWRpbmdFZGdlKQ0KDQp3cml0ZS5jc3YoZmdzZWFfcmVzdWx0c19jbGVhbl9ENCwgIkQ0X0dTRUFfaGFsbG1hcmtzLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQpgYGANCg0KDQo=