hdWGCNA analysis

Load data and libraries

##################
# LOAD LIBRARIES #
##################
library(tidyverse)
library(Seurat)
library(SeuratObject)
library(tidyseurat)
library(hdWGCNA)
library(enrichR)
library(png)
library(cowplot)
library(patchwork)
library(openxlsx)

source("../../bin/spatial_visualization.R")
source("../../bin/plotting_functions.R")

#########
# PATHS #
#########
input_dir <- "../../results/06_DGE_condition_st_data/"
result_dir <- "./Figures/05/"
if( isFALSE(dir.exists(result_dir)) ) { dir.create(result_dir,recursive = TRUE) }
epi_clus <- "^5$|^6$|^7|^8" # res 0.7

ord <- c("Superficial", "Upper IM", "Lower IM", "Basal","1","4","0","3","2","9","10","11","12")
ord1 <- c("5", "6", "7", "8","1","4","0","3","2","9","10","11","12")
sample_id <- c("P020", "P045", "P050", "P057",
               "P008", "P031", "P044","P080", "P026", "P105", 
               "P001", "P004", "P014", "P018", "P087", "P118",
               "P021", "P024", "P067", "P081", "P117" ) %>% set_names()

#############
# LOAD DATA #
#############
# hdWGCNA
DATA <- readRDS(paste0("../../results/09_hdWGCNA/","hdWGCNA_3771DEGs_Seurat.RDS"))
modules <- read_csv(paste0("../../results/09_hdWGCNA/", "wgcna_3771DEGs_modules.csv"))

# DATA <- readRDS(paste0("../../results/09_hdWGCNA/",,"all_Clus_4000DEGs/","hdWGCNA_Seurat.RDS"))
# modules <- read_csv(paste0("../../results/09_hdWGCNA/all_Clus_4000DEGs/", "wgcna_all_Clus_modules.csv"))
# plot the dendrogram
png(paste0("./Figures/05/", "Spatial_hdWGCNA_dendrogram.png"), 
    width = 10, height = 3, units = "in", res = 300)
PlotDendrogram(DATA, main=NA, marAll = c(1, 4, 1, 0))
dev.off()
## quartz_off_screen 
##                 2
dend <- readPNG("./Figures/05/Spatial_hdWGCNA_dendrogram.png")
g <- grid::rasterGrob(dend, interpolate=TRUE) 

A <- ggplot() +
  annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
  theme_nothing() +
  theme(rect = element_blank(), # removes the box around the plot)
        plot.margin = unit(c(-0,0,0,0), "lines")) #t,r,b,l  

# dev.new(width=3.5, height=3, noRStudioGD = TRUE)
A

# get module eigengenes and gene-module assignment tables
MEs <-  DATA@misc[["vis"]][["MEs"]]
# add the MEs to the seurat metadata so we can plot it with Seurat functions
DATA@meta.data <- cbind(DATA@meta.data, MEs)

# plot with Seurat's DotPlot function
mods <- unique(modules$module)[unique(modules$module) != 'grey']
p <- c('groups', 'layers') %>%
  map(., ~DotPlot(DATA, features=rev(mods), group.by = .x, dot.min=0.1) )

# flip the x/y axes, rotate the axis labels, and change color scheme:
p <- map(p,~.x +
  coord_flip() +
  RotatedAxis() +
  scale_color_gradientn(colours = c('blue','grey95', 'red'), name = "Avg. Expression",
                       limits = c(-1.5, 2.5), oob = scales::squish,
                       values = scales::rescale(c(-1.5, 0, 2.5))) + 
    theme(axis.text = element_text(size = 10),
          legend.text = element_text(size = 9), legend.title =element_text(size = 10),
          axis.line = element_line(size = .4), # , colour = "#bebebe"
          axis.ticks = element_line(size = .4), # , colour = "#bebebe"
          legend.direction = "vertical", legend.box = "horizontal",
          legend.margin=margin(1,-1,1,6),
          plot.margin = unit(c(.7, -0, -1.2, -1), "lines")) + # t,r,b,l
    xlab('') + ylab('') + guides(col = guide_colourbar(barwidth = .3, barheight = 4 )) 
)

# combine plots
# dev.new(width=3.9, height=3.3, noRStudioGD = TRUE)
leg <- get_legend(p[[1]])
p1 <- plot_grid(p[[1]]+theme(legend.position = "none"),NULL, rel_widths = c(1, 1.3))
(B <- plot_grid(p1, p[[2]]+theme(legend.position = "none"),rel_heights = c(.75,1,1), ncol = 1) )

ggsave(filename=paste0("./Figures/05/", "dot-plot.png"),B,  width = 3.9, height = 3.3, bg = "white")
# relative expression level of each module
plot_list <- ModuleRadarPlot(
  arrange(DATA, layers),
  group.by = 'groups', combine = F, # ncol = 4, 
  #barcodes = seurat_obj@meta.data %>% subset(cell_type == 'INH') %>% rownames(),
  axis.label.size=3, group.line.width =  0.3, grid.line.width = 0.3, gridline.max.linetype = "dashed",
  grid.label.size=3
) 

# dev.new(width=5.5, height=2, noRStudioGD = TRUE)
(C <- wrap_plots(plot_list, ncol=4) & theme(title = element_text(size=8), plot.margin = unit(c(.1, -0, -1, -0), "lines")) )

# ggsave(filename=paste0("./Figures/05/", "Group_contribution.png"),C,  width = 10, height = 3, bg = "white")
plot_filt.fun <- function(DATA, gr = "L1"){
  DAT <- filter(DATA, groups == gr)
  DAT@misc[["vis"]][["MEs"]] <- DATA@misc[["vis"]][["MEs"]][colnames(DAT),]
  plot_list <- ModuleFeaturePlot(DAT, reduction = "umapharmony", features = "MEs", title =F) 
  return(plot_list)
}

mod <-  c("SM1", "SM2", "SM3", "SM4") # , "SM5", "SM6"
mod <- map(mod, ~plot_genes.fun(DATA, 
               gene = .x, 
               scale = F,
               mins = -20, maxs = 20,
               diverging = T,
               col = rev(c("#c41625","#dc4e43","#fa9975","#FDDBC7","#F7F7F7","#D1E5F0","#92C5DE","#4393C3","#2166AC")),
               point_size = .5,
               red="umapharmony", 
               lable = TRUE) + ggtitle(" ") + theme(plot.title = element_text(hjust = 0))) # size = 3

# dev.new(width=4, height=4, noRStudioGD = TRUE)
(D_1 <- map(seq_along(mod), ~mod[[.x]] + facet_wrap(~groups, ncol = 4)) %>% wrap_plots(., ncol=1) )

# ggsave(filename=paste0("./Figures/05/", "Modules_across_groups_UMAP.png"),D_1,  width = 10, height = 10, bg = "white")
# enrichr databases to test
dbs <- c('GO_Biological_Process_2021','KEGG_2021_Human','Transcription_Factor_PPIs')

# perform enrichment tests
DATA <- RunEnrichr( #map(dbs, ~
  DATA,
  dbs=dbs, # character vector of enrichr databases to test
  max_genes = Inf # number of genes per module to test. use max_genes = Inf to choose all genes!
)
## Uploading data to Enrichr... Done.
##   Querying GO_Biological_Process_2021... Done.
##   Querying KEGG_2021_Human... Done.
##   Querying Transcription_Factor_PPIs... Done.
## Parsing results... Done.
## Uploading data to Enrichr... Done.
##   Querying GO_Biological_Process_2021... Done.
##   Querying KEGG_2021_Human... Done.
##   Querying Transcription_Factor_PPIs... Done.
## Parsing results... Done.
## Uploading data to Enrichr... Done.
##   Querying GO_Biological_Process_2021... Done.
##   Querying KEGG_2021_Human... Done.
##   Querying Transcription_Factor_PPIs... Done.
## Parsing results... Done.
## Uploading data to Enrichr... Done.
##   Querying GO_Biological_Process_2021... Done.
##   Querying KEGG_2021_Human... Done.
##   Querying Transcription_Factor_PPIs... Done.
## Parsing results... Done.
# retrieve the output table
enrich_df <- GetEnrichrTable(DATA) %>%
  filter(Adjusted.P.value < 0.05) %>% 
  split(~db)

enrich_df %>%
  map(., ~split(.x, ~module)) %>%
  imap(., ~write.xlsx(.x, paste0(result_dir,"New_3771DEGs/", "Enrichment_",.y,".xlsx")) )
## $GO_Biological_Process_2021
## A Workbook object.
##  
## Worksheets:
##  Sheet 1: "SM1"
##  
## 
##  Sheet 2: "SM2"
##  
## 
##  Sheet 3: "SM3"
##  
## 
##  Sheet 4: "SM4"
##  
## 
##  
##  Worksheet write order: 1, 2, 3, 4
##  Active Sheet 1: "SM1" 
##  Position: 1
## 
## 
## $KEGG_2021_Human
## A Workbook object.
##  
## Worksheets:
##  Sheet 1: "SM1"
##  
## 
##  Sheet 2: "SM2"
##  
## 
##  Sheet 3: "SM3"
##  
## 
##  
##  Worksheet write order: 1, 2, 3
##  Active Sheet 1: "SM1" 
##  Position: 1
## 
## 
## $Transcription_Factor_PPIs
## A Workbook object.
##  
## Worksheets:
##  Sheet 1: "SM1"
##  
## 
##  Sheet 2: "SM2"
##  
## 
##  Sheet 3: "SM3"
##  
## 
##  Sheet 4: "SM4"
##  
## 
##  
##  Worksheet write order: 1, 2, 3, 4
##  Active Sheet 1: "SM1" 
##  Position: 1
# saveRDS(enrich_df, paste0("../../results/09_hdWGCNA/New_3771DEGs/", "Enrichment.RDS"))
# enrich_df <- readRDS(paste0("../../results/09_hdWGCNA/New_3771DEGs/", "Enrichment.RDS"))
#######################
# ENRICHMENT BARPLOT #
#######################
overlap.fun <- function(string){
  l <- str_split(string, pattern ="/")
  l <- map_dbl(l, ~as.numeric(.x[1])/as.numeric(.x[2]) )
  return(l)}

# str_match("cytoplasmic translation (GO:0002181)", "^(.+?)\\s\\((.+)\\)$")[2]
GeneRatio_plot.fun <- function(enrich_df, txt_size = 15, nr_path=3,
                               col=c("#ed968c","#f9d14a","#88a0dc","#e78429")){
  dot_df <- enrich_df %>%  # dot_df <- enrich_df$GO_Biological_Process_2021 %>%
    {if(grepl("GO",.$Term[[1]])){mutate(., "Term" = str_match(.$Term, "^(.+?)\\s\\((.+)\\)$")[,2], 
           "GOid" = str_match(.$Term, "^(.+?)\\s\\((.+)\\)$")[,3] )}else .} %>%
    filter(Adjusted.P.value < 0.05) %>%
    mutate("-log10(P-value)" = -log10(P.value)) %>%
    mutate(GeneRatio = overlap.fun(.$Overlap)*100) 
  
  dot_df <- dot_df %>%
    group_by(module) %>% 
    top_n(., -nr_path, Adjusted.P.value) 
  
  p <- ggplot(dot_df, aes(x = `-log10(P-value)`, y = fct_reorder(Term, `-log10(P-value)`), fill = module, col = module)) +
    geom_col(width = .05, show.legend = F) +
    geom_point(aes(size = GeneRatio)) + theme_classic() + 
    scale_fill_manual(values = col, aesthetics = c("fill", "colour")) +
    
    facet_wrap(~module, scales = 'free', ncol = 1) +
    #scale_x_continuous(expand = c(0, 1.5)) +
    coord_cartesian(clip = F) +
    scale_x_continuous(limits = function(x){c(0, +max(0.1, x))}) +
    scale_size_continuous(breaks = c(10, 50, 80)) +
    theme(axis.title.y = element_blank(),
          strip.text.x = element_text(hjust = 0.1, margin=margin(l=0)),
          strip.background = element_blank(),
          panel.spacing = unit(1, "lines"),
          axis.text.y = element_text(size = 10),
          panel.border = element_blank())
  return(p)
}

df <- bind_rows(enrich_df[[2]], enrich_df[[3]]) %>%
  filter(db == "Transcription_Factor_PPIs" & module == "SM4" | db == "KEGG_2021_Human")

# dev.new(width=3.5, height=5, noRStudioGD = TRUE)
(D_2 <- GeneRatio_plot.fun(df) + theme(legend.position = "none") )

# ggsave(paste0("./Figures/05/", "Enrichment.png"),D_2,  width = 3.8, height = 5, bg = "white")
######################
# COMBINE ALL PANELS #
######################
# dev.new(width=7, height=8, noRStudioGD = TRUE) 
A_C <- plot_grid(A, C, ncol = 1, rel_widths = c(1, .4))
A_B_C <- plot_grid(A_C, B, ncol = 2)
D <- plot_grid(D_1, D_2)
(Figure5 <- plot_grid(A_B_C, D, ncol = 1, rel_heights = c(0.33, .66)) )

LS0tCnRpdGxlOiAiRmlndXJlIDUiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSVtLSVZJylgIgpmb3JtYXQ6CiAgaHRtbDoKICAgIGVtYmVkLXJlc291cmNlczogdHJ1ZQogICAgY29kZS1mb2xkOiBzaG93CnBhcmFtczoKICBmaWcucGF0aDogImByIHBhc3RlMChwYXJhbXMkZmlnLnBhdGgpYCIgIy4vRmlndXJlcy8KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBmaWcud2lkdGggICAgID0gNi42OTI5MTMzODU4LAogIGZpZy5wYXRoICAgICAgPSBwYXJhbXMkZmlnLnBhdGgsIyIuLi9GaWd1cmVzLyIsCiAgZmlnLmFsaWduICAgICA9ICJjZW50ZXIiLAogIG1lc3NhZ2UgICAgICAgPSBGQUxTRSwKICB3YXJuaW5nICAgICAgID0gRkFMU0UsCiAgZGV2ICAgICAgICAgICA9IGMoInBuZyIpLAogIGRwaSAgICAgICAgICAgPSAzMDAsCiAgZmlnLnByb2Nlc3MgPSBmdW5jdGlvbihmaWxlbmFtZSl7CiAgICBuZXdfZmlsZW5hbWUgPC0gc3RyaW5ncjo6c3RyX3JlbW92ZShzdHJpbmcgPSBmaWxlbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLTEiKQogICAgZnM6OmZpbGVfbW92ZShwYXRoID0gZmlsZW5hbWUsIG5ld19wYXRoID0gbmV3X2ZpbGVuYW1lKQogICAgaWZlbHNlKGZzOjpmaWxlX2V4aXN0cyhuZXdfZmlsZW5hbWUpLCBuZXdfZmlsZW5hbWUsIGZpbGVuYW1lKQogIH0KICApCiMgIHNldHdkKCJ+L3dvcmsvQnJvbGlkZW5zX3dvcmsvUHJvamVjdHMvU3BhdGlhbF9NaWNyb2Jpb3RhL3NyYy9NYW51c2NyaXB0IikKYGBgCgojIyBoZFdHQ05BIGFuYWx5c2lzCmBgYHtyIGJhY2tncm91bmRfam9iLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzb3VyY2UoIi4uLy4uL2Jpbi9yZW5kZXJfd2l0aF9qb2JzLlIiKQoKIyBxdWFydG8KIyByZW5kZXJfaHRtbF93aXRoX2pvYihvdXRfZGlyID0gbGFiX2RpcikKIyBmczo6ZmlsZV9tb3ZlKHBhdGggPSBmaWxlLCBuZXdfcGF0aCA9IHBhc3RlMChsYWJfZGlyLCBmaWxlKSkKCiMgY3VycmVudGx5IHVzaW5nIHF1YXJ0byBmb3IgZ2l0aHViIGFuZCBrbml0ZXIgZm9yIGh0bWwgZHVlIHRvIHNvdXJjZSBjb2RlIG9wdGlvbiAKcmVuZGVyX2dpdF93aXRoX2pvYihmaWdfcGF0aCA9ICIuL0ZpZ3VyZXMvMDImMDMvIikKc3lzdGVtMihjb21tYW5kID0gInNlZCIsIHN0ZG91dCA9IFRSVUUsCiAgICAgICAgYXJncyA9IGMoIi1pIiwgIicnIiwiLWUiLCAncy9zcmM9XFwiXFwuL3NyYz1cXCJcXC5cXC4vZycsCiAgICAgICAgICAgICAgICAgcGFzdGUwKCIuL21kX2ZpbGVzLyIsIGJhc2VuYW1lKCIuLzA1X2ZpZ3VyZXMubWQiKSkpKQoKIyBrbml0ZXIKa25pdF9odG1sX3dpdGhfam9iKG91dF9kaXIgPSAiLi4vLi4vbGFiX2Jvb2svZmlndXJlXzA1IiwgZmlnX3BhdGggPSAiLi9GaWd1cmVzLzA1LyIpCmBgYAoKIyMjIExvYWQgZGF0YSBhbmQgbGlicmFyaWVzCmBgYHtyIExvYWRfZGF0YX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgTE9BRCBMSUJSQVJJRVMgIwojIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeSh0aWR5c2V1cmF0KQpsaWJyYXJ5KGhkV0dDTkEpCmxpYnJhcnkoZW5yaWNoUikKbGlicmFyeShwbmcpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkob3Blbnhsc3gpCgpzb3VyY2UoIi4uLy4uL2Jpbi9zcGF0aWFsX3Zpc3VhbGl6YXRpb24uUiIpCnNvdXJjZSgiLi4vLi4vYmluL3Bsb3R0aW5nX2Z1bmN0aW9ucy5SIikKCiMjIyMjIyMjIwojIFBBVEhTICMKIyMjIyMjIyMjCmlucHV0X2RpciA8LSAiLi4vLi4vcmVzdWx0cy8wNl9ER0VfY29uZGl0aW9uX3N0X2RhdGEvIgpyZXN1bHRfZGlyIDwtICIuL0ZpZ3VyZXMvMDUvIgppZiggaXNGQUxTRShkaXIuZXhpc3RzKHJlc3VsdF9kaXIpKSApIHsgZGlyLmNyZWF0ZShyZXN1bHRfZGlyLHJlY3Vyc2l2ZSA9IFRSVUUpIH0KZXBpX2NsdXMgPC0gIl41JHxeNiR8Xjd8XjgiICMgcmVzIDAuNwoKb3JkIDwtIGMoIlN1cGVyZmljaWFsIiwgIlVwcGVyIElNIiwgIkxvd2VyIElNIiwgIkJhc2FsIiwiMSIsIjQiLCIwIiwiMyIsIjIiLCI5IiwiMTAiLCIxMSIsIjEyIikKb3JkMSA8LSBjKCI1IiwgIjYiLCAiNyIsICI4IiwiMSIsIjQiLCIwIiwiMyIsIjIiLCI5IiwiMTAiLCIxMSIsIjEyIikKc2FtcGxlX2lkIDwtIGMoIlAwMjAiLCAiUDA0NSIsICJQMDUwIiwgIlAwNTciLAogICAgICAgICAgICAgICAiUDAwOCIsICJQMDMxIiwgIlAwNDQiLCJQMDgwIiwgIlAwMjYiLCAiUDEwNSIsIAogICAgICAgICAgICAgICAiUDAwMSIsICJQMDA0IiwgIlAwMTQiLCAiUDAxOCIsICJQMDg3IiwgIlAxMTgiLAogICAgICAgICAgICAgICAiUDAyMSIsICJQMDI0IiwgIlAwNjciLCAiUDA4MSIsICJQMTE3IiApICU+JSBzZXRfbmFtZXMoKQoKIyMjIyMjIyMjIyMjIwojIExPQUQgREFUQSAjCiMjIyMjIyMjIyMjIyMKIyBoZFdHQ05BCkRBVEEgPC0gcmVhZFJEUyhwYXN0ZTAoIi4uLy4uL3Jlc3VsdHMvMDlfaGRXR0NOQS8iLCJoZFdHQ05BXzM3NzFERUdzX1NldXJhdC5SRFMiKSkKbW9kdWxlcyA8LSByZWFkX2NzdihwYXN0ZTAoIi4uLy4uL3Jlc3VsdHMvMDlfaGRXR0NOQS8iLCAid2djbmFfMzc3MURFR3NfbW9kdWxlcy5jc3YiKSkKCiMgREFUQSA8LSByZWFkUkRTKHBhc3RlMCgiLi4vLi4vcmVzdWx0cy8wOV9oZFdHQ05BLyIsLCJhbGxfQ2x1c180MDAwREVHcy8iLCJoZFdHQ05BX1NldXJhdC5SRFMiKSkKIyBtb2R1bGVzIDwtIHJlYWRfY3N2KHBhc3RlMCgiLi4vLi4vcmVzdWx0cy8wOV9oZFdHQ05BL2FsbF9DbHVzXzQwMDBERUdzLyIsICJ3Z2NuYV9hbGxfQ2x1c19tb2R1bGVzLmNzdiIpKQoKYGBgCgpgYGB7ciBTcGF0aWFsX2hkV0dDTkFfZGVuZHJvZ3JhbSwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTN9CiMgcGxvdCB0aGUgZGVuZHJvZ3JhbQpwbmcocGFzdGUwKCIuL0ZpZ3VyZXMvMDUvIiwgIlNwYXRpYWxfaGRXR0NOQV9kZW5kcm9ncmFtLnBuZyIpLCAKICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDMsIHVuaXRzID0gImluIiwgcmVzID0gMzAwKQpQbG90RGVuZHJvZ3JhbShEQVRBLCBtYWluPU5BLCBtYXJBbGwgPSBjKDEsIDQsIDEsIDApKQpkZXYub2ZmKCkKCmRlbmQgPC0gcmVhZFBORygiLi9GaWd1cmVzLzA1L1NwYXRpYWxfaGRXR0NOQV9kZW5kcm9ncmFtLnBuZyIpCmcgPC0gZ3JpZDo6cmFzdGVyR3JvYihkZW5kLCBpbnRlcnBvbGF0ZT1UUlVFKSAKCkEgPC0gZ2dwbG90KCkgKwogIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKICB0aGVtZV9ub3RoaW5nKCkgKwogIHRoZW1lKHJlY3QgPSBlbGVtZW50X2JsYW5rKCksICMgcmVtb3ZlcyB0aGUgYm94IGFyb3VuZCB0aGUgcGxvdCkKICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygtMCwwLDAsMCksICJsaW5lcyIpKSAjdCxyLGIsbCAgCgojIGRldi5uZXcod2lkdGg9My41LCBoZWlnaHQ9Mywgbm9SU3R1ZGlvR0QgPSBUUlVFKQpBCmBgYAoKYGBge3IgZG90LXBsb3RzfQojIGdldCBtb2R1bGUgZWlnZW5nZW5lcyBhbmQgZ2VuZS1tb2R1bGUgYXNzaWdubWVudCB0YWJsZXMKTUVzIDwtICBEQVRBQG1pc2NbWyJ2aXMiXV1bWyJNRXMiXV0KIyBhZGQgdGhlIE1FcyB0byB0aGUgc2V1cmF0IG1ldGFkYXRhIHNvIHdlIGNhbiBwbG90IGl0IHdpdGggU2V1cmF0IGZ1bmN0aW9ucwpEQVRBQG1ldGEuZGF0YSA8LSBjYmluZChEQVRBQG1ldGEuZGF0YSwgTUVzKQoKIyBwbG90IHdpdGggU2V1cmF0J3MgRG90UGxvdCBmdW5jdGlvbgptb2RzIDwtIHVuaXF1ZShtb2R1bGVzJG1vZHVsZSlbdW5pcXVlKG1vZHVsZXMkbW9kdWxlKSAhPSAnZ3JleSddCnAgPC0gYygnZ3JvdXBzJywgJ2xheWVycycpICU+JQogIG1hcCguLCB+RG90UGxvdChEQVRBLCBmZWF0dXJlcz1yZXYobW9kcyksIGdyb3VwLmJ5ID0gLngsIGRvdC5taW49MC4xKSApCgojIGZsaXAgdGhlIHgveSBheGVzLCByb3RhdGUgdGhlIGF4aXMgbGFiZWxzLCBhbmQgY2hhbmdlIGNvbG9yIHNjaGVtZToKcCA8LSBtYXAocCx+LnggKwogIGNvb3JkX2ZsaXAoKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBjKCdibHVlJywnZ3JleTk1JywgJ3JlZCcpLCBuYW1lID0gIkF2Zy4gRXhwcmVzc2lvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMS41LCAyLjUpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoYygtMS41LCAwLCAyLjUpKSkgKyAKICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLCBsZWdlbmQudGl0bGUgPWVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAuNCksICMgLCBjb2xvdXIgPSAiI2JlYmViZSIKICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IC40KSwgIyAsIGNvbG91ciA9ICIjYmViZWJlIgogICAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgICBsZWdlbmQubWFyZ2luPW1hcmdpbigxLC0xLDEsNiksCiAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYyguNywgLTAsIC0xLjIsIC0xKSwgImxpbmVzIikpICsgIyB0LHIsYixsCiAgICB4bGFiKCcnKSArIHlsYWIoJycpICsgZ3VpZGVzKGNvbCA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IC4zLCBiYXJoZWlnaHQgPSA0ICkpIAopCgojIGNvbWJpbmUgcGxvdHMKIyBkZXYubmV3KHdpZHRoPTMuOSwgaGVpZ2h0PTMuMywgbm9SU3R1ZGlvR0QgPSBUUlVFKQpsZWcgPC0gZ2V0X2xlZ2VuZChwW1sxXV0pCnAxIDwtIHBsb3RfZ3JpZChwW1sxXV0rdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSxOVUxMLCByZWxfd2lkdGhzID0gYygxLCAxLjMpKQooQiA8LSBwbG90X2dyaWQocDEsIHBbWzJdXSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLHJlbF9oZWlnaHRzID0gYyguNzUsMSwxKSwgbmNvbCA9IDEpICkKCmdnc2F2ZShmaWxlbmFtZT1wYXN0ZTAoIi4vRmlndXJlcy8wNS8iLCAiZG90LXBsb3QucG5nIiksQiwgIHdpZHRoID0gMy45LCBoZWlnaHQgPSAzLjMsIGJnID0gIndoaXRlIikKYGBgCgpgYGB7ciByYWRhcl9wbG90fQojIHJlbGF0aXZlIGV4cHJlc3Npb24gbGV2ZWwgb2YgZWFjaCBtb2R1bGUKcGxvdF9saXN0IDwtIE1vZHVsZVJhZGFyUGxvdCgKICBhcnJhbmdlKERBVEEsIGxheWVycyksCiAgZ3JvdXAuYnkgPSAnZ3JvdXBzJywgY29tYmluZSA9IEYsICMgbmNvbCA9IDQsIAogICNiYXJjb2RlcyA9IHNldXJhdF9vYmpAbWV0YS5kYXRhICU+JSBzdWJzZXQoY2VsbF90eXBlID09ICdJTkgnKSAlPiUgcm93bmFtZXMoKSwKICBheGlzLmxhYmVsLnNpemU9MywgZ3JvdXAubGluZS53aWR0aCA9ICAwLjMsIGdyaWQubGluZS53aWR0aCA9IDAuMywgZ3JpZGxpbmUubWF4LmxpbmV0eXBlID0gImRhc2hlZCIsCiAgZ3JpZC5sYWJlbC5zaXplPTMKKSAKCiMgZGV2Lm5ldyh3aWR0aD01LjUsIGhlaWdodD0yLCBub1JTdHVkaW9HRCA9IFRSVUUpCihDIDwtIHdyYXBfcGxvdHMocGxvdF9saXN0LCBuY29sPTQpICYgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoLjEsIC0wLCAtMSwgLTApLCAibGluZXMiKSkgKQojIGdnc2F2ZShmaWxlbmFtZT1wYXN0ZTAoIi4vRmlndXJlcy8wNS8iLCAiR3JvdXBfY29udHJpYnV0aW9uLnBuZyIpLEMsICB3aWR0aCA9IDEwLCBoZWlnaHQgPSAzLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKCmBgYHtyIHBsb3QtbW9kdWxlcywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpwbG90X2ZpbHQuZnVuIDwtIGZ1bmN0aW9uKERBVEEsIGdyID0gIkwxIil7CiAgREFUIDwtIGZpbHRlcihEQVRBLCBncm91cHMgPT0gZ3IpCiAgREFUQG1pc2NbWyJ2aXMiXV1bWyJNRXMiXV0gPC0gREFUQUBtaXNjW1sidmlzIl1dW1siTUVzIl1dW2NvbG5hbWVzKERBVCksXQogIHBsb3RfbGlzdCA8LSBNb2R1bGVGZWF0dXJlUGxvdChEQVQsIHJlZHVjdGlvbiA9ICJ1bWFwaGFybW9ueSIsIGZlYXR1cmVzID0gIk1FcyIsIHRpdGxlID1GKSAKICByZXR1cm4ocGxvdF9saXN0KQp9Cgptb2QgPC0gIGMoIlNNMSIsICJTTTIiLCAiU00zIiwgIlNNNCIpICMgLCAiU001IiwgIlNNNiIKbW9kIDwtIG1hcChtb2QsIH5wbG90X2dlbmVzLmZ1bihEQVRBLCAKICAgICAgICAgICAgICAgZ2VuZSA9IC54LCAKICAgICAgICAgICAgICAgc2NhbGUgPSBGLAogICAgICAgICAgICAgICBtaW5zID0gLTIwLCBtYXhzID0gMjAsCiAgICAgICAgICAgICAgIGRpdmVyZ2luZyA9IFQsCiAgICAgICAgICAgICAgIGNvbCA9IHJldihjKCIjYzQxNjI1IiwiI2RjNGU0MyIsIiNmYTk5NzUiLCIjRkREQkM3IiwiI0Y3RjdGNyIsIiNEMUU1RjAiLCIjOTJDNURFIiwiIzQzOTNDMyIsIiMyMTY2QUMiKSksCiAgICAgICAgICAgICAgIHBvaW50X3NpemUgPSAuNSwKICAgICAgICAgICAgICAgcmVkPSJ1bWFwaGFybW9ueSIsIAogICAgICAgICAgICAgICBsYWJsZSA9IFRSVUUpICsgZ2d0aXRsZSgiICIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApKSkgIyBzaXplID0gMwoKIyBkZXYubmV3KHdpZHRoPTQsIGhlaWdodD00LCBub1JTdHVkaW9HRCA9IFRSVUUpCihEXzEgPC0gbWFwKHNlcV9hbG9uZyhtb2QpLCB+bW9kW1sueF1dICsgZmFjZXRfd3JhcCh+Z3JvdXBzLCBuY29sID0gNCkpICU+JSB3cmFwX3Bsb3RzKC4sIG5jb2w9MSkgKQojIGdnc2F2ZShmaWxlbmFtZT1wYXN0ZTAoIi4vRmlndXJlcy8wNS8iLCAiTW9kdWxlc19hY3Jvc3NfZ3JvdXBzX1VNQVAucG5nIiksRF8xLCAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTAsIGJnID0gIndoaXRlIikKYGBgCgpgYGB7ciBlbnJpY2hSfQojIGVucmljaHIgZGF0YWJhc2VzIHRvIHRlc3QKZGJzIDwtIGMoJ0dPX0Jpb2xvZ2ljYWxfUHJvY2Vzc18yMDIxJywnS0VHR18yMDIxX0h1bWFuJywnVHJhbnNjcmlwdGlvbl9GYWN0b3JfUFBJcycpCgojIHBlcmZvcm0gZW5yaWNobWVudCB0ZXN0cwpEQVRBIDwtIFJ1bkVucmljaHIoICNtYXAoZGJzLCB+CiAgREFUQSwKICBkYnM9ZGJzLCAjIGNoYXJhY3RlciB2ZWN0b3Igb2YgZW5yaWNociBkYXRhYmFzZXMgdG8gdGVzdAogIG1heF9nZW5lcyA9IEluZiAjIG51bWJlciBvZiBnZW5lcyBwZXIgbW9kdWxlIHRvIHRlc3QuIHVzZSBtYXhfZ2VuZXMgPSBJbmYgdG8gY2hvb3NlIGFsbCBnZW5lcyEKKQoKIyByZXRyaWV2ZSB0aGUgb3V0cHV0IHRhYmxlCmVucmljaF9kZiA8LSBHZXRFbnJpY2hyVGFibGUoREFUQSkgJT4lCiAgZmlsdGVyKEFkanVzdGVkLlAudmFsdWUgPCAwLjA1KSAlPiUgCiAgc3BsaXQofmRiKQoKZW5yaWNoX2RmICU+JQogIG1hcCguLCB+c3BsaXQoLngsIH5tb2R1bGUpKSAlPiUKICBpbWFwKC4sIH53cml0ZS54bHN4KC54LCBwYXN0ZTAocmVzdWx0X2RpciwiTmV3XzM3NzFERUdzLyIsICJFbnJpY2htZW50XyIsLnksIi54bHN4IikpICkKCiMgc2F2ZVJEUyhlbnJpY2hfZGYsIHBhc3RlMCgiLi4vLi4vcmVzdWx0cy8wOV9oZFdHQ05BL05ld18zNzcxREVHcy8iLCAiRW5yaWNobWVudC5SRFMiKSkKIyBlbnJpY2hfZGYgPC0gcmVhZFJEUyhwYXN0ZTAoIi4uLy4uL3Jlc3VsdHMvMDlfaGRXR0NOQS9OZXdfMzc3MURFR3MvIiwgIkVucmljaG1lbnQuUkRTIikpCgpgYGAKCmBgYHtyIEVucmljaG1lbnQtcGxvdCwgZmlnLndpZHRoPTMuNSwgZmlnLmhlaWdodD01fQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEVOUklDSE1FTlQgQkFSUExPVCAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm92ZXJsYXAuZnVuIDwtIGZ1bmN0aW9uKHN0cmluZyl7CiAgbCA8LSBzdHJfc3BsaXQoc3RyaW5nLCBwYXR0ZXJuID0iLyIpCiAgbCA8LSBtYXBfZGJsKGwsIH5hcy5udW1lcmljKC54WzFdKS9hcy5udW1lcmljKC54WzJdKSApCiAgcmV0dXJuKGwpfQoKIyBzdHJfbWF0Y2goImN5dG9wbGFzbWljIHRyYW5zbGF0aW9uIChHTzowMDAyMTgxKSIsICJeKC4rPylcXHNcXCgoLispXFwpJCIpWzJdCkdlbmVSYXRpb19wbG90LmZ1biA8LSBmdW5jdGlvbihlbnJpY2hfZGYsIHR4dF9zaXplID0gMTUsIG5yX3BhdGg9MywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1jKCIjZWQ5NjhjIiwiI2Y5ZDE0YSIsIiM4OGEwZGMiLCIjZTc4NDI5IikpewogIGRvdF9kZiA8LSBlbnJpY2hfZGYgJT4lICAjIGRvdF9kZiA8LSBlbnJpY2hfZGYkR09fQmlvbG9naWNhbF9Qcm9jZXNzXzIwMjEgJT4lCiAgICB7aWYoZ3JlcGwoIkdPIiwuJFRlcm1bWzFdXSkpe211dGF0ZSguLCAiVGVybSIgPSBzdHJfbWF0Y2goLiRUZXJtLCAiXiguKz8pXFxzXFwoKC4rKVxcKSQiKVssMl0sIAogICAgICAgICAgICJHT2lkIiA9IHN0cl9tYXRjaCguJFRlcm0sICJeKC4rPylcXHNcXCgoLispXFwpJCIpWywzXSApfWVsc2UgLn0gJT4lCiAgICBmaWx0ZXIoQWRqdXN0ZWQuUC52YWx1ZSA8IDAuMDUpICU+JQogICAgbXV0YXRlKCItbG9nMTAoUC12YWx1ZSkiID0gLWxvZzEwKFAudmFsdWUpKSAlPiUKICAgIG11dGF0ZShHZW5lUmF0aW8gPSBvdmVybGFwLmZ1biguJE92ZXJsYXApKjEwMCkgCiAgCiAgZG90X2RmIDwtIGRvdF9kZiAlPiUKICAgIGdyb3VwX2J5KG1vZHVsZSkgJT4lIAogICAgdG9wX24oLiwgLW5yX3BhdGgsIEFkanVzdGVkLlAudmFsdWUpIAogIAogIHAgPC0gZ2dwbG90KGRvdF9kZiwgYWVzKHggPSBgLWxvZzEwKFAtdmFsdWUpYCwgeSA9IGZjdF9yZW9yZGVyKFRlcm0sIGAtbG9nMTAoUC12YWx1ZSlgKSwgZmlsbCA9IG1vZHVsZSwgY29sID0gbW9kdWxlKSkgKwogICAgZ2VvbV9jb2wod2lkdGggPSAuMDUsIHNob3cubGVnZW5kID0gRikgKwogICAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IEdlbmVSYXRpbykpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wsIGFlc3RoZXRpY3MgPSBjKCJmaWxsIiwgImNvbG91ciIpKSArCiAgICAKICAgIGZhY2V0X3dyYXAofm1vZHVsZSwgc2NhbGVzID0gJ2ZyZWUnLCBuY29sID0gMSkgKwogICAgI3NjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDEuNSkpICsKICAgIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gRikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGZ1bmN0aW9uKHgpe2MoMCwgK21heCgwLjEsIHgpKX0pICsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhicmVha3MgPSBjKDEwLCA1MCwgODApKSArCiAgICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjEsIG1hcmdpbj1tYXJnaW4obD0wKSksCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMSwgImxpbmVzIiksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQogIHJldHVybihwKQp9CgpkZiA8LSBiaW5kX3Jvd3MoZW5yaWNoX2RmW1syXV0sIGVucmljaF9kZltbM11dKSAlPiUKICBmaWx0ZXIoZGIgPT0gIlRyYW5zY3JpcHRpb25fRmFjdG9yX1BQSXMiICYgbW9kdWxlID09ICJTTTQiIHwgZGIgPT0gIktFR0dfMjAyMV9IdW1hbiIpCgojIGRldi5uZXcod2lkdGg9My41LCBoZWlnaHQ9NSwgbm9SU3R1ZGlvR0QgPSBUUlVFKQooRF8yIDwtIEdlbmVSYXRpb19wbG90LmZ1bihkZikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICkKCiMgZ2dzYXZlKHBhc3RlMCgiLi9GaWd1cmVzLzA1LyIsICJFbnJpY2htZW50LnBuZyIpLERfMiwgIHdpZHRoID0gMy44LCBoZWlnaHQgPSA1LCBiZyA9ICJ3aGl0ZSIpCmBgYAoKYGBge3IgY29tYmluZS1wYW5lbHN9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDT01CSU5FIEFMTCBQQU5FTFMgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgZGV2Lm5ldyh3aWR0aD03LCBoZWlnaHQ9OCwgbm9SU3R1ZGlvR0QgPSBUUlVFKSAKQV9DIDwtIHBsb3RfZ3JpZChBLCBDLCBuY29sID0gMSwgcmVsX3dpZHRocyA9IGMoMSwgLjQpKQpBX0JfQyA8LSBwbG90X2dyaWQoQV9DLCBCLCBuY29sID0gMikKRCA8LSBwbG90X2dyaWQoRF8xLCBEXzIpCihGaWd1cmU1IDwtIHBsb3RfZ3JpZChBX0JfQywgRCwgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYygwLjMzLCAuNjYpKSApCmBgYAoK