1. load libraries

#Differential Expression Analysis

2. load seurat object

#Load Seurat Object L7
load("../../../0-IMP-OBJECTS/Harmony_integrated_All_samples_Merged_with_PBMC10x_with_harmony_clustering.Robj")


All_samples_Merged
An object of class Seurat 
64169 features across 59355 samples within 6 assays 
Active assay: SCT (27417 features, 3000 variable features)
 3 layers present: counts, data, scale.data
 5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 6 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony, umap.harmony
DimPlot(All_samples_Merged, reduction = "umap.harmony", group.by = "cell_line",label = T, label.box = T)

DimPlot(All_samples_Merged, reduction = "umap.harmony", group.by = "Harmony_snn_res.0.9",label = T, label.box = T)

#Differential Expression Analysis

3. P1 vs P2


DefaultAssay(All_samples_Merged) <- "SCT"
Idents(All_samples_Merged) <- "Harmony_snn_res.0.9"

# Patient 1 vs Patient 2
p1_vs_p2 <- FindMarkers(All_samples_Merged, 
                        ident.1 = c(3, 8, 10, 18),  # P1 clusters
                        ident.2 = c(1, 2, 13),      # P2 clusters
                        assay = "SCT")
write.csv(p1_vs_p2, "comparison_P1_vs_P2.csv")

# Create volcano plot for P1 vs P2
volcano_p1_vs_p2 <- EnhancedVolcano(p1_vs_p2, 
                                    lab = rownames(p1_vs_p2),
                                    x = 'avg_log2FC',
                                    y = 'p_val_adj',
                                    title = 'P1 vs P2',
                                    xlab = bquote(~Log[2]~ 'fold change'),
                                    pCutoff = 0.05,
                                    FCcutoff = 1.5, 
                                    pointSize = 3.0,
                                    labSize = 5.0,
                                    boxedLabels = TRUE,
                                    colAlpha = 0.5,
                                    legendPosition = 'right',
                                    legendLabSize = 10,
                                    legendIconSize = 4.0,
                                    drawConnectors = TRUE,
                                    widthConnectors = 0.5,
                                    colConnectors = 'grey50',
                                    arrowheads = FALSE,
                                    max.overlaps = 30)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano_p1_vs_p2)
png("volcano_P1_vs_P2.png", width = 12, height = 10, units = "in", res = 300)
print(volcano_p1_vs_p2)
dev.off()
png 
  2 

volcano2_p1_vs_p2 <- EnhancedVolcano(p1_vs_p2, 
                lab = rownames(p1_vs_p2),
                x = "avg_log2FC", 
                y = "p_val_adj",
                selectLab = c('EPCAM', 'KIR3DL2', 'FOXM1', 'TWIST1', 'TNFSF9', 
                              'CD80', 'FOS','PTPN6','NCR1','NCR2',
                              'PCLAF', 'KIR3DL1', 'IL4','ITGA6','CCL5',
                              'IL7R', 'TCF7', 'PTTG1', 'RRM2', 'MKI67', 'CD70', 
                              'IL2RA', 'FCGR3A', 'GNLY', 'FOXP3', 'SELL',  'LEF1',
                              'CCL17', 'THY1', 'CD27', 'CD28', 'CD7',
                              # Key Sézary syndrome genes
                              'PRF1', 'GZMB', 'NCR1', 'NFATC3', 
                              'KLRK1', 'LCK', 'KLRC1', 'KLRC2', 'TNF', 
                              'KIR3DL1','KIR3DL3','KIR3DL4', 'IFNG', 'IFNGR1', 'CD244', 'FASLG'),
                title = "P1 vs P2",
                subtitle = "Sézary Syndrome Cell Lines",
                xlab = bquote(~Log[2]~ 'fold change'),
                pCutoff = 0.05,
                FCcutoff = log2(1.5), 
                pointSize = 3.0,
                labSize = 4.0,
                labFace = 'bold',
                boxedLabels = TRUE,
                colAlpha = 0.5,
                legendPosition = 'right',
                legendLabSize = 10,
                legendIconSize = 4.0,
                drawConnectors = TRUE,
                widthConnectors = 0.5,
                colConnectors = 'grey50',
                arrowheads = FALSE,
                max.overlaps = 30)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano2_p1_vs_p2)
png("volcano2_P1_vs_P2.png", width = 12, height = 10, units = "in", res = 300)
print(volcano2_p1_vs_p2)
dev.off()
png 
  2 

# Display top differentially expressed genes for each comparison
head(p1_vs_p2)
NA
NA

4. P1 vs P3


DefaultAssay(All_samples_Merged) <- "SCT"
Idents(All_samples_Merged) <- "Harmony_snn_res.0.9"

# Patient 1 vs Patient 3
p1_vs_p3 <- FindMarkers(All_samples_Merged, 
                        ident.1 = c(3, 8, 10, 18),  # P1 clusters
                        ident.2 = c(4, 7, 9, 6, 16, 19),  # P3 clusters
                        assay = "SCT")
write.csv(p1_vs_p3, "comparison_P1_vs_P3.csv")

# Create volcano plot for P1 vs P3
volcano_p1_vs_p3 <- EnhancedVolcano(p1_vs_p3, 
                                    lab = rownames(p1_vs_p3),
                                    x = 'avg_log2FC',
                                    y = 'p_val_adj',
                                    title = 'P1 vs P3',
                                    pCutoff = 0.05,
                                    FCcutoff = 1,
                                    pointSize = 1.5,
                                    labSize = 4.0,
                                    col = c('grey', 'darkgreen', 'blue', 'red'),
                                    colAlpha = 0.5,
                                    legendPosition = 'right',
                                    legendLabSize = 10,
                                    legendIconSize = 4.0,
                                    drawConnectors = TRUE,
                                    widthConnectors = 0.5)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano_p1_vs_p3)
png("volcano_P1_vs_P3.png", width = 12, height = 10, units = "in", res = 300)
print(volcano_p1_vs_p3)
dev.off()
png 
  2 

volcano2_p1_vs_p3 <- EnhancedVolcano(p1_vs_p3, 
                lab = rownames(p1_vs_p3),
                x = "avg_log2FC", 
                y = "p_val_adj",
                selectLab = c('KIR3DL2','KIR3DL1','KIR3DL3','KIR3DL4',  'TWIST1', 'TNFSF9', 
                               'FOS', 'TCF7','LEF1',
                               'CD86', 'VCAM1','CCL5',
                              'CD40',  'CD70', 
                              'IL2RA', 'FCGR3A', 'GNLY', 'FOXP3',  'LEF1',
                              'CCL17', 'THY1', 'CD27', 'CD28', 'CD7','EPCAM','TOX','IL16','IL21',
                              # Key Sézary syndrome genes
                              'PRF1', 'GZMB',  
                              'KLRK1', 'LCK', 'KLRC1', 'KLRC2',  
                               'IFNG', 'IFNGR1', 'FASLG'),
                title = "P1 vs P3",
                subtitle = "Sézary Syndrome Cell Lines",
                xlab = bquote(~Log[2]~ 'fold change'),
                pCutoff = 0.05,
                FCcutoff = 1.5, 
                pointSize = 3.0,
                labSize = 4.0,
                labFace = 'bold',
                boxedLabels = TRUE,
                colAlpha = 0.5,
                legendPosition = 'right',
                legendLabSize = 10,
                legendIconSize = 4.0,
                drawConnectors = TRUE,
                widthConnectors = 0.5,
                colConnectors = 'grey50',
                arrowheads = FALSE,
                max.overlaps = 30)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano2_p1_vs_p3)
png("volcano2_P1_vs_P3.png", width = 12, height = 10, units = "in", res = 300)
print(volcano2_p1_vs_p3)
dev.off()
png 
  2 

# Display top differentially expressed genes for each comparison

head(p1_vs_p3)
NA
NA

5. P2 vs P3


DefaultAssay(All_samples_Merged) <- "SCT"
Idents(All_samples_Merged) <- "Harmony_snn_res.0.9"

# Patient 2 vs Patient 3
p2_vs_p3 <- FindMarkers(All_samples_Merged, 
                        ident.1 = c(1, 2, 13),      # P2 clusters
                        ident.2 = c(4, 7, 9, 6, 16, 19),  # P3 clusters
                        assay = "SCT")
write.csv(p2_vs_p3, "comparison_P2_vs_P3.csv")

# Create volcano plot for P2 vs P3
volcano_p2_vs_p3 <- EnhancedVolcano(p2_vs_p3, 
                                    lab = rownames(p2_vs_p3),
                                    x = 'avg_log2FC',
                                    y = 'p_val_adj',
                                    title = 'P2 vs P3',
                                    pCutoff = 0.05,
                                    FCcutoff = 1,
                                    pointSize = 1.5,
                                    labSize = 4.0,
                                    col = c('grey', 'darkgreen', 'blue', 'red'),
                                    colAlpha = 0.5,
                                    legendPosition = 'right',
                                    legendLabSize = 10,
                                    legendIconSize = 4.0,
                                    drawConnectors = TRUE,
                                    widthConnectors = 0.5)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano_p2_vs_p3)
png("volcano_P2_vs_P3.png", width = 12, height = 10, units = "in", res = 300)
print(volcano_p2_vs_p3)
dev.off()
png 
  2 

volcano2_p2_vs_p3 <- EnhancedVolcano(p2_vs_p3, 
                lab = rownames(p2_vs_p3),
                x = "avg_log2FC", 
                y = "p_val_adj",
                selectLab = c('KIR3DL2','KIR3DL1','KIR3DL3','KIR3DL4',  'TWIST1', 'TNFSF9', 
                               
                               'VCAM1','CCL5','CCL23','IL13','IL19', 'TIGIT','JUN','TP53','CD40','CCR10',
                              'CD40',   'KIT','CD52','CD44','RORC','TIFA',
                              'FOXP3',  
                              'CCL17', 'THY1', 'CD28', 'CD7','EPCAM','IL16',
                              # Key Sézary syndrome genes
                                
                              'KLRK1', 'KLRC1', 'KLRC2',  
                               'IFNG', 'IFNGR1', 'FASLG'),
                title = "P2 vs P3",
                subtitle = "Sézary Syndrome Cell Lines",
                xlab = bquote(~Log[2]~ 'fold change'),
                pCutoff = 0.05,
                FCcutoff = 1.5, 
                pointSize = 3.0,
                labSize = 4.0,
                labFace = 'bold',
                boxedLabels = TRUE,
                colAlpha = 0.5,
                legendPosition = 'right',
                legendLabSize = 10,
                legendIconSize = 4.0,
                drawConnectors = TRUE,
                widthConnectors = 0.5,
                colConnectors = 'grey50',
                arrowheads = FALSE,
                max.overlaps = 30)
Avis : One or more p-values is 0. Converting to 10^-1 * current lowest non-zero p-value...
print(volcano2_p2_vs_p3)
png("volcano2_P2_vs_P3.png", width = 12, height = 10, units = "in", res = 300)
print(volcano2_p2_vs_p3)
dev.off()
png 
  2 

print(volcano_p1_vs_p2)

print(volcano_p1_vs_p3)

print(volcano_p2_vs_p3)

print(volcano2_p1_vs_p2)

print(volcano2_p1_vs_p3)

print(volcano2_p2_vs_p3)


# Display top differentially expressed genes for each comparison
head(p1_vs_p2)
head(p1_vs_p3)
head(p2_vs_p3)
NA
NA

6. Enrichment Analysis

library(clusterProfiler)
library(org.Hs.eg.db)
library(enrichplot)

perform_go_enrichment <- function(gene_list, gene_universe, title) {
  ego <- enrichGO(gene = gene_list,
                  universe = gene_universe,
                  OrgDb = org.Hs.eg.db,
                  keyType = "SYMBOL",
                  ont = "BP",
                  pAdjustMethod = "BH",
                  qvalueCutoff = 0.001,
                  readable = TRUE)
  
  if (nrow(ego@result) == 0) {
    warning(paste("No enriched GO terms found for", title))
    return(NULL)
  }
  
  p <- dotplot(ego, showCategory = 20, title = paste("GO -", title)) +
    theme(axis.text.y = element_text(size = 8))
  
  print(p)
  png(paste0("GO_enrichment_", gsub(" ", "_", title), ".png"), width = 12, height = 8, units = "in", res = 300)
  print(p)
  dev.off()
  
  return(ego)
}

perform_kegg_enrichment <- function(gene_list, gene_universe, title) {
  # Convert gene symbols to Entrez IDs
  entrez_ids <- bitr(gene_list, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
  universe_entrez <- bitr(gene_universe, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
  
  print(paste("Number of input genes:", length(gene_list)))
  print(paste("Number of input genes mapped to Entrez IDs:", nrow(entrez_ids)))
  print(paste("Number of universe genes:", length(gene_universe)))
  print(paste("Number of universe genes mapped to Entrez IDs:", nrow(universe_entrez)))
  
  if(nrow(entrez_ids) == 0) {
    warning(paste("No genes could be mapped for", title))
    return(NULL)
  }
  
  tryCatch({
    ekegg <- enrichKEGG(gene = entrez_ids$ENTREZID,
                        universe = universe_entrez$ENTREZID,
                        organism = 'hsa',
                        keyType = "kegg",
                        pvalueCutoff = 0.05,
                        pAdjustMethod = "BH")
    
    if(nrow(ekegg@result) == 0) {
      warning(paste("No enriched KEGG pathways found for", title))
      return(NULL)
    }
    
    p <- dotplot(ekegg, showCategory = 20, title = paste("KEGG -", title)) +
      theme(axis.text.y = element_text(size = 8))
    
    print(p)
    png(paste0("KEGG_enrichment_", gsub(" ", "_", title), ".png"), width = 12, height = 8, units = "in", res = 300)
    print(p)
    dev.off()
    
    return(ekegg)
  }, error = function(e) {
    warning(paste("Error in KEGG enrichment for", title, ":", e$message))
    return(NULL)
  })
}

gene_universe <- rownames(All_samples_Merged)

# P1 vs P2 comparison
upregulated_genes_P1vsP2 <- rownames(p1_vs_p2[p1_vs_p2$avg_log2FC > 1.5 & p1_vs_p2$p_val_adj < 0.001, ])
downregulated_genes_P1vsP2 <- rownames(p1_vs_p2[p1_vs_p2$avg_log2FC < -1.5 & p1_vs_p2$p_val_adj < 0.001, ])

go_up_P1vsP2 <- perform_go_enrichment(upregulated_genes_P1vsP2, gene_universe, "Upregulated Genes in P1 vs P2")

go_down_P1vsP2 <- perform_go_enrichment(downregulated_genes_P1vsP2, gene_universe, "Downregulated Genes in P1 vs P2")

kegg_up_P1vsP2 <- perform_kegg_enrichment(upregulated_genes_P1vsP2, gene_universe, "Upregulated Genes in P1 vs P2")
'select()' returned 1:1 mapping between keys and columns
Avis : 13.59% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 1796"
[1] "Number of input genes mapped to Entrez IDs: 1552"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

kegg_down_P1vsP2 <- perform_kegg_enrichment(downregulated_genes_P1vsP2, gene_universe, "Downregulated Genes in P1 vs P2")
'select()' returned 1:many mapping between keys and columns
Avis : 17.77% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 2223"
[1] "Number of input genes mapped to Entrez IDs: 1829"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

# P1 vs P3 comparison
upregulated_genes_P1vsP3 <- rownames(p1_vs_p3[p1_vs_p3$avg_log2FC > 1.5 & p1_vs_p3$p_val_adj < 0.001, ])
downregulated_genes_P1vsP3 <- rownames(p1_vs_p3[p1_vs_p3$avg_log2FC < -1.5 & p1_vs_p3$p_val_adj < 0.001, ])

go_up_P1vsP3 <- perform_go_enrichment(upregulated_genes_P1vsP3, gene_universe, "Upregulated Genes in P1 vs P3")

go_down_P1vsP3 <- perform_go_enrichment(downregulated_genes_P1vsP3, gene_universe, "Downregulated Genes in P1 vs P3")

kegg_up_P1vsP3 <- perform_kegg_enrichment(upregulated_genes_P1vsP3, gene_universe, "Upregulated Genes in P1 vs P3")
'select()' returned 1:many mapping between keys and columns
Avis : 14.36% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 1839"
[1] "Number of input genes mapped to Entrez IDs: 1576"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

kegg_down_P1vsP3 <- perform_kegg_enrichment(downregulated_genes_P1vsP3, gene_universe, "Downregulated Genes in P1 vs P3")
'select()' returned 1:1 mapping between keys and columns
Avis : 17.32% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 1980"
[1] "Number of input genes mapped to Entrez IDs: 1637"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

# P2 vs P3 comparison
upregulated_genes_P2vsP3 <- rownames(p2_vs_p3[p2_vs_p3$avg_log2FC > 1.5 & p2_vs_p3$p_val_adj < 0.001, ])
downregulated_genes_P2vsP3 <- rownames(p2_vs_p3[p2_vs_p3$avg_log2FC < -1.5 & p2_vs_p3$p_val_adj < 0.001, ])

go_up_P2vsP3 <- perform_go_enrichment(upregulated_genes_P2vsP3, gene_universe, "Upregulated Genes in P2 vs P3")

go_down_P2vsP3 <- perform_go_enrichment(downregulated_genes_P2vsP3, gene_universe, "Downregulated Genes in P2 vs P3")

kegg_up_P2vsP3 <- perform_kegg_enrichment(upregulated_genes_P2vsP3, gene_universe, "Upregulated Genes in P2 vs P3")
'select()' returned 1:many mapping between keys and columns
Avis : 17.06% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 1465"
[1] "Number of input genes mapped to Entrez IDs: 1216"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

kegg_down_P2vsP3 <- perform_kegg_enrichment(downregulated_genes_P2vsP3, gene_universe, "Downregulated Genes in P2 vs P3")
'select()' returned 1:1 mapping between keys and columns
Avis : 18.51% of input gene IDs are fail to map...'select()' returned 1:many mapping between keys and columns
Avis : 28.75% of input gene IDs are fail to map...
[1] "Number of input genes: 1167"
[1] "Number of input genes mapped to Entrez IDs: 951"
[1] "Number of universe genes: 27417"
[1] "Number of universe genes mapped to Entrez IDs: 19538"

LS0tCnRpdGxlOiAiU8OpemFyeSBTeW5kcm9tZSBDZWxsIExpbmUgZGVyaXZlZCBmcm9tIGVhY2ggcGF0aWVudCBERSBjb21wYXJpc29uIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICMgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgIyB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgIyBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuSHMuZWcuZGIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCgoKYGBgCiNEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcwoKIyAyLiBsb2FkIHNldXJhdCBvYmplY3QKYGBge3IgbG9hZF9zZXVyYXR9CiNMb2FkIFNldXJhdCBPYmplY3QgTDcKbG9hZCgiLi4vLi4vLi4vMC1JTVAtT0JKRUNUUy9IYXJtb255X2ludGVncmF0ZWRfQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfUEJNQzEweF93aXRoX2hhcm1vbnlfY2x1c3RlcmluZy5Sb2JqIikKCgpBbGxfc2FtcGxlc19NZXJnZWQKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAidW1hcC5oYXJtb255IiwgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIixsYWJlbCA9IFQsIGxhYmVsLmJveCA9IFQpCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAidW1hcC5oYXJtb255IiwgZ3JvdXAuYnkgPSAiSGFybW9ueV9zbm5fcmVzLjAuOSIsbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKYGBgCgojRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gQW5hbHlzaXMKCiMgMy4gUDEgdnMgUDIKYGBge3IgZmluZG1hcmtlcnMxLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJTQ1QiCklkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJIYXJtb255X3Nubl9yZXMuMC45IgoKIyBQYXRpZW50IDEgdnMgUGF0aWVudCAyCnAxX3ZzX3AyIDwtIEZpbmRNYXJrZXJzKEFsbF9zYW1wbGVzX01lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50LjEgPSBjKDMsIDgsIDEwLCAxOCksICAjIFAxIGNsdXN0ZXJzCiAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50LjIgPSBjKDEsIDIsIDEzKSwgICAgICAjIFAyIGNsdXN0ZXJzCiAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIpCndyaXRlLmNzdihwMV92c19wMiwgImNvbXBhcmlzb25fUDFfdnNfUDIuY3N2IikKCiMgQ3JlYXRlIHZvbGNhbm8gcGxvdCBmb3IgUDEgdnMgUDIKdm9sY2Fub19wMV92c19wMiA8LSBFbmhhbmNlZFZvbGNhbm8ocDFfdnNfcDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIgPSByb3duYW1lcyhwMV92c19wMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAnYXZnX2xvZzJGQycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAncF92YWxfYWRqJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAnUDEgdnMgUDInLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+ICdmb2xkIGNoYW5nZScpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludFNpemUgPSAzLjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYlNpemUgPSA1LjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveGVkTGFiZWxzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kTGFiU2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAnZ3JleTUwJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyb3doZWFkcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAzMCkKcHJpbnQodm9sY2Fub19wMV92c19wMikKcG5nKCJ2b2xjYW5vX1AxX3ZzX1AyLnBuZyIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJpbiIsIHJlcyA9IDMwMCkKcHJpbnQodm9sY2Fub19wMV92c19wMikKZGV2Lm9mZigpCgoKdm9sY2FubzJfcDFfdnNfcDIgPC0gRW5oYW5jZWRWb2xjYW5vKHAxX3ZzX3AyLCAKICAgICAgICAgICAgICAgIGxhYiA9IHJvd25hbWVzKHAxX3ZzX3AyKSwKICAgICAgICAgICAgICAgIHggPSAiYXZnX2xvZzJGQyIsIAogICAgICAgICAgICAgICAgeSA9ICJwX3ZhbF9hZGoiLAogICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gYygnRVBDQU0nLCAnS0lSM0RMMicsICdGT1hNMScsICdUV0lTVDEnLCAnVE5GU0Y5JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDRDgwJywgJ0ZPUycsJ1BUUE42JywnTkNSMScsJ05DUjInLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUENMQUYnLCAnS0lSM0RMMScsICdJTDQnLCdJVEdBNicsJ0NDTDUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUw3UicsICdUQ0Y3JywgJ1BUVEcxJywgJ1JSTTInLCAnTUtJNjcnLCAnQ0Q3MCcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUwyUkEnLCAnRkNHUjNBJywgJ0dOTFknLCAnRk9YUDMnLCAnU0VMTCcsICAnTEVGMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDQ0wxNycsICdUSFkxJywgJ0NEMjcnLCAnQ0QyOCcsICdDRDcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEtleSBTw6l6YXJ5IHN5bmRyb21lIGdlbmVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdQUkYxJywgJ0daTUInLCAnTkNSMScsICdORkFUQzMnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0tMUksxJywgJ0xDSycsICdLTFJDMScsICdLTFJDMicsICdUTkYnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0tJUjNETDEnLCdLSVIzREwzJywnS0lSM0RMNCcsICdJRk5HJywgJ0lGTkdSMScsICdDRDI0NCcsICdGQVNMRycpLAogICAgICAgICAgICAgICAgdGl0bGUgPSAiUDEgdnMgUDIiLAogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiU8OpemFyeSBTeW5kcm9tZSBDZWxsIExpbmVzIiwKICAgICAgICAgICAgICAgIHhsYWIgPSBicXVvdGUofkxvZ1syXX4gJ2ZvbGQgY2hhbmdlJyksCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gbG9nMigxLjUpLCAKICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDMuMCwKICAgICAgICAgICAgICAgIGxhYlNpemUgPSA0LjAsCiAgICAgICAgICAgICAgICBsYWJGYWNlID0gJ2JvbGQnLAogICAgICAgICAgICAgICAgYm94ZWRMYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICBsZWdlbmRMYWJTaXplID0gMTAsCiAgICAgICAgICAgICAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwKICAgICAgICAgICAgICAgIHdpZHRoQ29ubmVjdG9ycyA9IDAuNSwKICAgICAgICAgICAgICAgIGNvbENvbm5lY3RvcnMgPSAnZ3JleTUwJywKICAgICAgICAgICAgICAgIGFycm93aGVhZHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IDMwKQpwcmludCh2b2xjYW5vMl9wMV92c19wMikKcG5nKCJ2b2xjYW5vMl9QMV92c19QMi5wbmciLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDApCnByaW50KHZvbGNhbm8yX3AxX3ZzX3AyKQpkZXYub2ZmKCkKCiMgRGlzcGxheSB0b3AgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGZvciBlYWNoIGNvbXBhcmlzb24KaGVhZChwMV92c19wMikKCgpgYGAKCgojIDQuIFAxIHZzIFAzCmBgYHtyIGZpbmRtYXJrZXJzMiwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpEZWZhdWx0QXNzYXkoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAiU0NUIgpJZGVudHMoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAiSGFybW9ueV9zbm5fcmVzLjAuOSIKCiMgUGF0aWVudCAxIHZzIFBhdGllbnQgMwpwMV92c19wMyA8LSBGaW5kTWFya2VycyhBbGxfc2FtcGxlc19NZXJnZWQsIAogICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4xID0gYygzLCA4LCAxMCwgMTgpLCAgIyBQMSBjbHVzdGVycwogICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4yID0gYyg0LCA3LCA5LCA2LCAxNiwgMTkpLCAgIyBQMyBjbHVzdGVycwogICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiKQp3cml0ZS5jc3YocDFfdnNfcDMsICJjb21wYXJpc29uX1AxX3ZzX1AzLmNzdiIpCgojIENyZWF0ZSB2b2xjYW5vIHBsb3QgZm9yIFAxIHZzIFAzCnZvbGNhbm9fcDFfdnNfcDMgPC0gRW5oYW5jZWRWb2xjYW5vKHAxX3ZzX3AzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiID0gcm93bmFtZXMocDFfdnNfcDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gJ2F2Z19sb2cyRkMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gJ3BfdmFsX2FkaicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ1AxIHZzIFAzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJTaXplID0gNC4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBjKCdncmV5JywgJ2RhcmtncmVlbicsICdibHVlJywgJ3JlZCcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xBbHBoYSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRMYWJTaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZEljb25TaXplID0gNC4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmF3Q29ubmVjdG9ycyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoQ29ubmVjdG9ycyA9IDAuNSkKcHJpbnQodm9sY2Fub19wMV92c19wMykKcG5nKCJ2b2xjYW5vX1AxX3ZzX1AzLnBuZyIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJpbiIsIHJlcyA9IDMwMCkKcHJpbnQodm9sY2Fub19wMV92c19wMykKZGV2Lm9mZigpCgp2b2xjYW5vMl9wMV92c19wMyA8LSBFbmhhbmNlZFZvbGNhbm8ocDFfdnNfcDMsIAogICAgICAgICAgICAgICAgbGFiID0gcm93bmFtZXMocDFfdnNfcDMpLAogICAgICAgICAgICAgICAgeCA9ICJhdmdfbG9nMkZDIiwgCiAgICAgICAgICAgICAgICB5ID0gInBfdmFsX2FkaiIsCiAgICAgICAgICAgICAgICBzZWxlY3RMYWIgPSBjKCdLSVIzREwyJywnS0lSM0RMMScsJ0tJUjNETDMnLCdLSVIzREw0JywgICdUV0lTVDEnLCAnVE5GU0Y5JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRk9TJywgJ1RDRjcnLCdMRUYxJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDRDg2JywgJ1ZDQU0xJywnQ0NMNScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDRDQwJywgICdDRDcwJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJTDJSQScsICdGQ0dSM0EnLCAnR05MWScsICdGT1hQMycsICAnTEVGMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDQ0wxNycsICdUSFkxJywgJ0NEMjcnLCAnQ0QyOCcsICdDRDcnLCdFUENBTScsJ1RPWCcsJ0lMMTYnLCdJTDIxJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBLZXkgU8OpemFyeSBzeW5kcm9tZSBnZW5lcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUFJGMScsICdHWk1CJywgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnS0xSSzEnLCAnTENLJywgJ0tMUkMxJywgJ0tMUkMyJywgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0lGTkcnLCAnSUZOR1IxJywgJ0ZBU0xHJyksCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJQMSB2cyBQMyIsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJTw6l6YXJ5IFN5bmRyb21lIENlbGwgTGluZXMiLAogICAgICAgICAgICAgICAgeGxhYiA9IGJxdW90ZSh+TG9nWzJdfiAnZm9sZCBjaGFuZ2UnKSwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLjUsIAogICAgICAgICAgICAgICAgcG9pbnRTaXplID0gMy4wLAogICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgIGxhYkZhY2UgPSAnYm9sZCcsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IFRSVUUsCiAgICAgICAgICAgICAgICBjb2xBbHBoYSA9IDAuNSwKICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICAgICAgICAgICAgICAgIGxlZ2VuZExhYlNpemUgPSAxMCwKICAgICAgICAgICAgICAgIGxlZ2VuZEljb25TaXplID0gNC4wLAogICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC41LAogICAgICAgICAgICAgICAgY29sQ29ubmVjdG9ycyA9ICdncmV5NTAnLAogICAgICAgICAgICAgICAgYXJyb3doZWFkcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gMzApCnByaW50KHZvbGNhbm8yX3AxX3ZzX3AzKQpwbmcoInZvbGNhbm8yX1AxX3ZzX1AzLnBuZyIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJpbiIsIHJlcyA9IDMwMCkKcHJpbnQodm9sY2FubzJfcDFfdnNfcDMpCmRldi5vZmYoKQoKCiMgRGlzcGxheSB0b3AgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGZvciBlYWNoIGNvbXBhcmlzb24KCmhlYWQocDFfdnNfcDMpCgoKYGBgCgoKIyA1LiBQMiB2cyBQMwpgYGB7ciBmaW5kbWFya2VyczMsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKRGVmYXVsdEFzc2F5KEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIlNDVCIKSWRlbnRzKEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gIkhhcm1vbnlfc25uX3Jlcy4wLjkiCgojIFBhdGllbnQgMiB2cyBQYXRpZW50IDMKcDJfdnNfcDMgPC0gRmluZE1hcmtlcnMoQWxsX3NhbXBsZXNfTWVyZ2VkLCAKICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMSA9IGMoMSwgMiwgMTMpLCAgICAgICMgUDIgY2x1c3RlcnMKICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMiA9IGMoNCwgNywgOSwgNiwgMTYsIDE5KSwgICMgUDMgY2x1c3RlcnMKICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIikKd3JpdGUuY3N2KHAyX3ZzX3AzLCAiY29tcGFyaXNvbl9QMl92c19QMy5jc3YiKQoKIyBDcmVhdGUgdm9sY2FubyBwbG90IGZvciBQMiB2cyBQMwp2b2xjYW5vX3AyX3ZzX3AzIDwtIEVuaGFuY2VkVm9sY2FubyhwMl92c19wMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYiA9IHJvd25hbWVzKHAyX3ZzX3AzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICdhdmdfbG9nMkZDJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICdwX3ZhbF9hZGonLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICdQMiB2cyBQMycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50U2l6ZSA9IDEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gYygnZ3JleScsICdkYXJrZ3JlZW4nLCAnYmx1ZScsICdyZWQnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sQWxwaGEgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kTGFiU2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRJY29uU2l6ZSA9IDQuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjUpCnByaW50KHZvbGNhbm9fcDJfdnNfcDMpCnBuZygidm9sY2Fub19QMl92c19QMy5wbmciLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDApCnByaW50KHZvbGNhbm9fcDJfdnNfcDMpCmRldi5vZmYoKQoKdm9sY2FubzJfcDJfdnNfcDMgPC0gRW5oYW5jZWRWb2xjYW5vKHAyX3ZzX3AzLCAKICAgICAgICAgICAgICAgIGxhYiA9IHJvd25hbWVzKHAyX3ZzX3AzKSwKICAgICAgICAgICAgICAgIHggPSAiYXZnX2xvZzJGQyIsIAogICAgICAgICAgICAgICAgeSA9ICJwX3ZhbF9hZGoiLAogICAgICAgICAgICAgICAgc2VsZWN0TGFiID0gYygnS0lSM0RMMicsJ0tJUjNETDEnLCdLSVIzREwzJywnS0lSM0RMNCcsICAnVFdJU1QxJywgJ1RORlNGOScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVkNBTTEnLCdDQ0w1JywnQ0NMMjMnLCdJTDEzJywnSUwxOScsICdUSUdJVCcsJ0pVTicsJ1RQNTMnLCdDRDQwJywnQ0NSMTAnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ0Q0MCcsICAgJ0tJVCcsJ0NENTInLCdDRDQ0JywnUk9SQycsJ1RJRkEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRk9YUDMnLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDQ0wxNycsICdUSFkxJywgJ0NEMjgnLCAnQ0Q3JywnRVBDQU0nLCdJTDE2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBLZXkgU8OpemFyeSBzeW5kcm9tZSBnZW5lcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnS0xSSzEnLCAnS0xSQzEnLCAnS0xSQzInLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSUZORycsICdJRk5HUjEnLCAnRkFTTEcnKSwKICAgICAgICAgICAgICAgIHRpdGxlID0gIlAyIHZzIFAzIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIlPDqXphcnkgU3luZHJvbWUgQ2VsbCBMaW5lcyIsCiAgICAgICAgICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+ICdmb2xkIGNoYW5nZScpLAogICAgICAgICAgICAgICAgcEN1dG9mZiA9IDAuMDUsCiAgICAgICAgICAgICAgICBGQ2N1dG9mZiA9IDEuNSwgCiAgICAgICAgICAgICAgICBwb2ludFNpemUgPSAzLjAsCiAgICAgICAgICAgICAgICBsYWJTaXplID0gNC4wLAogICAgICAgICAgICAgICAgbGFiRmFjZSA9ICdib2xkJywKICAgICAgICAgICAgICAgIGJveGVkTGFiZWxzID0gVFJVRSwKICAgICAgICAgICAgICAgIGNvbEFscGhhID0gMC41LAogICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogICAgICAgICAgICAgICAgbGVnZW5kTGFiU2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgICAgICAgICAgICAgICBkcmF3Q29ubmVjdG9ycyA9IFRSVUUsCiAgICAgICAgICAgICAgICB3aWR0aENvbm5lY3RvcnMgPSAwLjUsCiAgICAgICAgICAgICAgICBjb2xDb25uZWN0b3JzID0gJ2dyZXk1MCcsCiAgICAgICAgICAgICAgICBhcnJvd2hlYWRzID0gRkFMU0UsCiAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAzMCkKcHJpbnQodm9sY2FubzJfcDJfdnNfcDMpCnBuZygidm9sY2FubzJfUDJfdnNfUDMucG5nIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImluIiwgcmVzID0gMzAwKQpwcmludCh2b2xjYW5vMl9wMl92c19wMykKZGV2Lm9mZigpCgpwcmludCh2b2xjYW5vX3AxX3ZzX3AyKQpwcmludCh2b2xjYW5vX3AxX3ZzX3AzKQpwcmludCh2b2xjYW5vX3AyX3ZzX3AzKQpwcmludCh2b2xjYW5vMl9wMV92c19wMikKcHJpbnQodm9sY2FubzJfcDFfdnNfcDMpCnByaW50KHZvbGNhbm8yX3AyX3ZzX3AzKQoKIyBEaXNwbGF5IHRvcCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgZm9yIGVhY2ggY29tcGFyaXNvbgpoZWFkKHAxX3ZzX3AyKQpoZWFkKHAxX3ZzX3AzKQpoZWFkKHAyX3ZzX3AzKQoKCmBgYAoKCiMgNi4gRW5yaWNobWVudCBBbmFseXNpcwpgYGB7ciBlbnJpY2htZW50MiwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKbGlicmFyeShlbnJpY2hwbG90KQoKcGVyZm9ybV9nb19lbnJpY2htZW50IDwtIGZ1bmN0aW9uKGdlbmVfbGlzdCwgZ2VuZV91bml2ZXJzZSwgdGl0bGUpIHsKICBlZ28gPC0gZW5yaWNoR08oZ2VuZSA9IGdlbmVfbGlzdCwKICAgICAgICAgICAgICAgICAgdW5pdmVyc2UgPSBnZW5lX3VuaXZlcnNlLAogICAgICAgICAgICAgICAgICBPcmdEYiA9IG9yZy5Icy5lZy5kYiwKICAgICAgICAgICAgICAgICAga2V5VHlwZSA9ICJTWU1CT0wiLAogICAgICAgICAgICAgICAgICBvbnQgPSAiQlAiLAogICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgICAgcXZhbHVlQ3V0b2ZmID0gMC4wMDEsCiAgICAgICAgICAgICAgICAgIHJlYWRhYmxlID0gVFJVRSkKICAKICBpZiAobnJvdyhlZ29AcmVzdWx0KSA9PSAwKSB7CiAgICB3YXJuaW5nKHBhc3RlKCJObyBlbnJpY2hlZCBHTyB0ZXJtcyBmb3VuZCBmb3IiLCB0aXRsZSkpCiAgICByZXR1cm4oTlVMTCkKICB9CiAgCiAgcCA8LSBkb3RwbG90KGVnbywgc2hvd0NhdGVnb3J5ID0gMjAsIHRpdGxlID0gcGFzdGUoIkdPIC0iLCB0aXRsZSkpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKICAKICBwcmludChwKQogIHBuZyhwYXN0ZTAoIkdPX2VucmljaG1lbnRfIiwgZ3N1YigiICIsICJfIiwgdGl0bGUpLCAiLnBuZyIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4LCB1bml0cyA9ICJpbiIsIHJlcyA9IDMwMCkKICBwcmludChwKQogIGRldi5vZmYoKQogIAogIHJldHVybihlZ28pCn0KCnBlcmZvcm1fa2VnZ19lbnJpY2htZW50IDwtIGZ1bmN0aW9uKGdlbmVfbGlzdCwgZ2VuZV91bml2ZXJzZSwgdGl0bGUpIHsKICAjIENvbnZlcnQgZ2VuZSBzeW1ib2xzIHRvIEVudHJleiBJRHMKICBlbnRyZXpfaWRzIDwtIGJpdHIoZ2VuZV9saXN0LCBmcm9tVHlwZSA9ICJTWU1CT0wiLCB0b1R5cGUgPSAiRU5UUkVaSUQiLCBPcmdEYiA9IG9yZy5Icy5lZy5kYikKICB1bml2ZXJzZV9lbnRyZXogPC0gYml0cihnZW5lX3VuaXZlcnNlLCBmcm9tVHlwZSA9ICJTWU1CT0wiLCB0b1R5cGUgPSAiRU5UUkVaSUQiLCBPcmdEYiA9IG9yZy5Icy5lZy5kYikKICAKICBwcmludChwYXN0ZSgiTnVtYmVyIG9mIGlucHV0IGdlbmVzOiIsIGxlbmd0aChnZW5lX2xpc3QpKSkKICBwcmludChwYXN0ZSgiTnVtYmVyIG9mIGlucHV0IGdlbmVzIG1hcHBlZCB0byBFbnRyZXogSURzOiIsIG5yb3coZW50cmV6X2lkcykpKQogIHByaW50KHBhc3RlKCJOdW1iZXIgb2YgdW5pdmVyc2UgZ2VuZXM6IiwgbGVuZ3RoKGdlbmVfdW5pdmVyc2UpKSkKICBwcmludChwYXN0ZSgiTnVtYmVyIG9mIHVuaXZlcnNlIGdlbmVzIG1hcHBlZCB0byBFbnRyZXogSURzOiIsIG5yb3codW5pdmVyc2VfZW50cmV6KSkpCiAgCiAgaWYobnJvdyhlbnRyZXpfaWRzKSA9PSAwKSB7CiAgICB3YXJuaW5nKHBhc3RlKCJObyBnZW5lcyBjb3VsZCBiZSBtYXBwZWQgZm9yIiwgdGl0bGUpKQogICAgcmV0dXJuKE5VTEwpCiAgfQogIAogIHRyeUNhdGNoKHsKICAgIGVrZWdnIDwtIGVucmljaEtFR0coZ2VuZSA9IGVudHJlel9pZHMkRU5UUkVaSUQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVuaXZlcnNlID0gdW5pdmVyc2VfZW50cmV6JEVOVFJFWklELAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdoc2EnLAogICAgICAgICAgICAgICAgICAgICAgICBrZXlUeXBlID0gImtlZ2ciLAogICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIikKICAgIAogICAgaWYobnJvdyhla2VnZ0ByZXN1bHQpID09IDApIHsKICAgICAgd2FybmluZyhwYXN0ZSgiTm8gZW5yaWNoZWQgS0VHRyBwYXRod2F5cyBmb3VuZCBmb3IiLCB0aXRsZSkpCiAgICAgIHJldHVybihOVUxMKQogICAgfQogICAgCiAgICBwIDwtIGRvdHBsb3QoZWtlZ2csIHNob3dDYXRlZ29yeSA9IDIwLCB0aXRsZSA9IHBhc3RlKCJLRUdHIC0iLCB0aXRsZSkpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQogICAgCiAgICBwcmludChwKQogICAgcG5nKHBhc3RlMCgiS0VHR19lbnJpY2htZW50XyIsIGdzdWIoIiAiLCAiXyIsIHRpdGxlKSwgIi5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOCwgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDApCiAgICBwcmludChwKQogICAgZGV2Lm9mZigpCiAgICAKICAgIHJldHVybihla2VnZykKICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIGluIEtFR0cgZW5yaWNobWVudCBmb3IiLCB0aXRsZSwgIjoiLCBlJG1lc3NhZ2UpKQogICAgcmV0dXJuKE5VTEwpCiAgfSkKfQoKZ2VuZV91bml2ZXJzZSA8LSByb3duYW1lcyhBbGxfc2FtcGxlc19NZXJnZWQpCgojIFAxIHZzIFAyIGNvbXBhcmlzb24KdXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AyIDwtIHJvd25hbWVzKHAxX3ZzX3AyW3AxX3ZzX3AyJGF2Z19sb2cyRkMgPiAxLjUgJiBwMV92c19wMiRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKZG93bnJlZ3VsYXRlZF9nZW5lc19QMXZzUDIgPC0gcm93bmFtZXMocDFfdnNfcDJbcDFfdnNfcDIkYXZnX2xvZzJGQyA8IC0xLjUgJiBwMV92c19wMiRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKCmdvX3VwX1AxdnNQMiA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AyLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDEgdnMgUDIiKQpnb19kb3duX1AxdnNQMiA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQoZG93bnJlZ3VsYXRlZF9nZW5lc19QMXZzUDIsIGdlbmVfdW5pdmVyc2UsICJEb3ducmVndWxhdGVkIEdlbmVzIGluIFAxIHZzIFAyIikKa2VnZ191cF9QMXZzUDIgPC0gcGVyZm9ybV9rZWdnX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AyLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDEgdnMgUDIiKQprZWdnX2Rvd25fUDF2c1AyIDwtIHBlcmZvcm1fa2VnZ19lbnJpY2htZW50KGRvd25yZWd1bGF0ZWRfZ2VuZXNfUDF2c1AyLCBnZW5lX3VuaXZlcnNlLCAiRG93bnJlZ3VsYXRlZCBHZW5lcyBpbiBQMSB2cyBQMiIpCgojIFAxIHZzIFAzIGNvbXBhcmlzb24KdXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AzIDwtIHJvd25hbWVzKHAxX3ZzX3AzW3AxX3ZzX3AzJGF2Z19sb2cyRkMgPiAxLjUgJiBwMV92c19wMyRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKZG93bnJlZ3VsYXRlZF9nZW5lc19QMXZzUDMgPC0gcm93bmFtZXMocDFfdnNfcDNbcDFfdnNfcDMkYXZnX2xvZzJGQyA8IC0xLjUgJiBwMV92c19wMyRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKCmdvX3VwX1AxdnNQMyA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AzLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDEgdnMgUDMiKQpnb19kb3duX1AxdnNQMyA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQoZG93bnJlZ3VsYXRlZF9nZW5lc19QMXZzUDMsIGdlbmVfdW5pdmVyc2UsICJEb3ducmVndWxhdGVkIEdlbmVzIGluIFAxIHZzIFAzIikKa2VnZ191cF9QMXZzUDMgPC0gcGVyZm9ybV9rZWdnX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDF2c1AzLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDEgdnMgUDMiKQprZWdnX2Rvd25fUDF2c1AzIDwtIHBlcmZvcm1fa2VnZ19lbnJpY2htZW50KGRvd25yZWd1bGF0ZWRfZ2VuZXNfUDF2c1AzLCBnZW5lX3VuaXZlcnNlLCAiRG93bnJlZ3VsYXRlZCBHZW5lcyBpbiBQMSB2cyBQMyIpCgojIFAyIHZzIFAzIGNvbXBhcmlzb24KdXByZWd1bGF0ZWRfZ2VuZXNfUDJ2c1AzIDwtIHJvd25hbWVzKHAyX3ZzX3AzW3AyX3ZzX3AzJGF2Z19sb2cyRkMgPiAxLjUgJiBwMl92c19wMyRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKZG93bnJlZ3VsYXRlZF9nZW5lc19QMnZzUDMgPC0gcm93bmFtZXMocDJfdnNfcDNbcDJfdnNfcDMkYXZnX2xvZzJGQyA8IC0xLjUgJiBwMl92c19wMyRwX3ZhbF9hZGogPCAwLjAwMSwgXSkKCmdvX3VwX1AydnNQMyA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDJ2c1AzLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDIgdnMgUDMiKQpnb19kb3duX1AydnNQMyA8LSBwZXJmb3JtX2dvX2VucmljaG1lbnQoZG93bnJlZ3VsYXRlZF9nZW5lc19QMnZzUDMsIGdlbmVfdW5pdmVyc2UsICJEb3ducmVndWxhdGVkIEdlbmVzIGluIFAyIHZzIFAzIikKa2VnZ191cF9QMnZzUDMgPC0gcGVyZm9ybV9rZWdnX2VucmljaG1lbnQodXByZWd1bGF0ZWRfZ2VuZXNfUDJ2c1AzLCBnZW5lX3VuaXZlcnNlLCAiVXByZWd1bGF0ZWQgR2VuZXMgaW4gUDIgdnMgUDMiKQprZWdnX2Rvd25fUDJ2c1AzIDwtIHBlcmZvcm1fa2VnZ19lbnJpY2htZW50KGRvd25yZWd1bGF0ZWRfZ2VuZXNfUDJ2c1AzLCBnZW5lX3VuaXZlcnNlLCAiRG93bnJlZ3VsYXRlZCBHZW5lcyBpbiBQMiB2cyBQMyIpCgoKYGBgCgoKCgo=