Heatmap of significant genes per cluster

Load data and libraries

##################
# LOAD LIBRARIES #
##################
library(tidyverse)
library(Seurat)
library(SeuratObject)
library(tidyseurat)
library(cowplot)
library(ggrepel)
library(gridtext)
library(png)
library(grid)
#library(scatterpie)
library(patchwork)
library(openxlsx)
library(readxl)

# BiocManager::install("ComplexHeatmap")
library(ComplexHeatmap)

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

#########
# PATHS #
#########
input_dir <- "../../03_clustering_st_data/"
epi_clus <- "^5$|^6$|^7|^8" # res 0.7

#############
# LOAD DATA #
#############
DEGs_table <- read_csv(paste0("../../results/05_DGE_clusters_st_data/","DGEs_clusters_wilcox.0.7.csv"))
DATA <- readRDS(paste0("../../results/03_clustering_st_data/","seuratObj_clustered.RDS"))


sample_id <- c("P020", "P045", "P050", "P057",
               "P008", "P031", "P080", "P044", "P026", "P105", 
               "P001", "P004", "P014", "P018", "P087", "P118",
               "P021", "P024", "P067", "P081", "P117" ) %>% set_names()

Identify marker genes to seperate epithelial clusters

#######################################
# FILTER BY P-VAL logFC AND pct.diff #
######################################
filter_top.fun <- function(nested_df, n, var, min_pct = 0){
  if(is.na(n[4])){n[4] = min_pct}
  res <- nested_df %>% # res <- top20_epi$data[[3]] %>%
    #mutate(p_val_adj = 1.000-.$p_val_adj) %>%
    filter(p_val_adj < 0.05) %>%
    arrange(desc(avg_log2FC)) %>%
    filter(pct.1 > n[4]) %>%
    top_n(., n=n[1], abs(!!sym(var[1]))) %>%
    arrange(desc(avg_log2FC)) %>%
    #top_n(., n=n[2], Avg_exp) %>%
    top_n(., n=n[2], abs(!!sym(var[2]))) %>%
    top_n(., n=n[3], abs(!!sym(var[3]))) 
  print(res)
  return(res[1:n[3],])
}

sel_epi <- list(
  #Sup_1 = list(n=c(-40, 30, 5),var=c("p_val_adj", "pct.diff", "Avg_exp", "log.pct.diff")),
  "Superficial" = list(n=c(-40, 50, 5),var=c("p_val_adj", "pct.diff", "log.pct.diff")),
  #Sup_1 = list(n=c(-100, 70, 5, 0.5),var=c("pct.diff", "p_val_adj", "log.pct.diff")),
  "Upper IM" = list(n=c(-40, 50, 5),var=c("p_val_adj", "pct.diff", "log.pct.diff")),
  #Sup_2 = list(n=c(20, 5, 5),var=c("avg_log2FC", "log.pct.diff", "log.pct.diff")),
  "Lower IM" = list(n=c(25, 7, 5, .5),var=c("avg_log2FC", "log.pct.diff", "log.pct.diff")),
  "Basal" = list(n=c(10, 5, 5, .8),var=c("avg_log2FC", "log.pct.diff", "log.pct.diff")) )

# Identify the top genes that have a high difference in expression between the clusters
top20_epi <- DEGs_table %>%
  filter(grepl(epi_clus, .$clus)) %>%
  arrange(match(Clusters, names(sel_epi))) %>%
  mutate(Direction = ifelse(avg_log2FC > 0, "UP", "DOWN")) %>%
  filter(Direction == "UP") %>%
  #filter(!(pct.2 > 0.2)) %>%
  nest(., .by = "Clusters") %>%
  mutate(data = pmap(., ~filter_top.fun(..2, n=sel_epi[[..1]]$n, var=sel_epi[[..1]]$var)) ) %>%
  unnest(., cols=c("data"))
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 7.79e-167       3.11 0.733 0.245 2.00e-162 5_all   FLG     -0.978         1.58
## 2 1.89e-179       2.44 0.721 0.213 4.85e-175 5_all   RNAS…   -0.934         1.76
## 3 1.16e-172       1.82 0.649 0.146 2.98e-168 5_all   DUOX…   -0.795         2.15
## 4 5.19e-164       1.82 0.733 0.246 1.33e-159 5_all   HMOX1   -0.979         1.58
## 5 6.36e-168       1.47 0.617 0.129 1.63e-163 5_all   DHRS9   -0.746         2.26
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 4.36e-142      1.01  0.863 0.353 1.12e-137 6_all   ENDOU   -1.22          1.29
## 2 3.17e-123      0.939 0.83  0.339 8.14e-119 6_all   FAM3D   -1.17          1.29
## 3 1.88e-125      0.906 0.841 0.353 4.84e-121 6_all   CYP4…   -1.19          1.25
## 4 8.67e-113      0.826 0.813 0.34  2.23e-108 6_all   CDA     -1.15          1.26
## 5 9.46e- 94      0.756 0.705 0.294 2.43e- 89 6_all   ACPP    -0.999         1.26
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##      p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene   pct.diff log.pct.diff
##      <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>     <dbl>        <dbl>
## 1 2.06e-83      0.714 0.895 0.537  5.29e-79 7_all   NDRG4     -1.43        0.737
## 2 1.00e-69      0.684 0.898 0.568  2.57e-65 7_all   C10or…    -1.47        0.661
## 3 2.04e-78      0.649 0.935 0.617  5.25e-74 7_all   NOTCH3    -1.55        0.600
## 4 5.16e-67      0.625 0.911 0.615  1.33e-62 7_all   DDR1      -1.53        0.567
## 5 1.80e-59      0.611 0.897 0.59   4.63e-55 7_all   RHOV      -1.49        0.604
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 4.10e-225       2.53 0.92  0.667 1.05e-220 8_all   IGFB…    -1.59        0.464
## 2 4.79e-172       2.31 0.814 0.44  1.23e-167 8_all   APOD     -1.25        0.888
## 3 3.16e-234       2.13 0.946 0.703 8.12e-230 8_all   DCN      -1.65        0.428
## 4 4.97e-218       2.12 0.924 0.668 1.28e-213 8_all   VIM      -1.59        0.468
## 5 6.84e-132       2.10 0.864 0.65  1.76e-127 8_all   SPARC    -1.51        0.411
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>

Identify marker genes to seperate Submucosal clusters

#######################################
# FILTER BY P-VAL logFC AND pct.diff #
######################################
filter_top.fun <- function(nested_df, n, var, filt_pct2=0.9){
  filt <- TRUE
  #if(is.na(n[4])){n[4] = pct}
  res <- nested_df %>% # res <- top20_sub$data[[7]] %>%
    #mutate(p_val_adj = 1.000-.$p_val_adj) %>%
    #filter(Avg_diff > 0) %>%
    #filter(pct.2 < n[4]) %>%
    top_n(., n=n[1], abs(!!sym(var[1]))) %>%
    {if(filt) filter(., between(pct.2, 0.01,filt_pct2 )) else .} %>%
    top_n(., n=n[2], abs(!!sym(var[2]))) %>%
    
    
    #{if(filt) filter(., between(pct.1, 0.8,0.3) | between(pct.2, 0.1,0.4)) else .} %>%
    #arrange(desc(Avg_exp_3)) %>%
    
    top_n(., n=n[3], abs(!!sym(var[3]))) #%>%
    #arrange(desc(!!sym(var[3])))
  print(res)
  return(res)
}

sel_s <- list(
  #"3" = list(n=c(-60, 30, 5),var=c("p_val_adj", "pct.1", "pct.1"), filt_pct2=.25),
  "1" = list(n=c(-60, 30, 5),var=c("p_val_adj", "pct.1", "pct.2"), filt_pct2=.25),
  #"3" = list(filt=F, n=c(-150, 100, 5),var=c("p_val_adj", "pct.diff", "log.pct.diff")),
  "4" = list( n=c(-100, 50, 5),var=c("p_val_adj", "pct.diff", "log.pct.diff"), filt_pct2=.9),
  "0" = list( n=c(-100, 50, 5),var=c("p_val_adj", "avg_log2FC", "log.pct.diff"), filt_pct2=.4),
  #"0" = list( n=c(-60, 30, 5),var=c( "pct.2", "avg_log2FC", "log.pct.diff"), filt_pct2=.4),
  #"0" = list( n=c( -50, 30, 5, 0.2),var=c( "p_val_adj", "avg_log2FC", "log.pct.diff"), filt=T),
  "3" = list(n=c(40, -50, 5),var=c("avg_log2FC", "pct.diff", "log.pct.diff"), filt_pct2=.9),
  "2" = list( n=c(-90, -20, -5),var=c("p_val_adj", "pct.2", "pct.2"), filt_pct2=.5),
  "9" = list( n=c(-90, 50, 5),var=c("p_val_adj", "pct.diff", "log.pct.diff"), filt_pct2=.9),
  "10" = list( n=c(-90, 5, 5),var=c("p_val_adj", "pct.1", "pct.1"), filt_pct2=.15)
  )

# Identify the top genes that have a high difference in expression between the clusters
top20_sub <- DEGs_table %>%
  filter(Regulation == "UP") %>%
  filter(!(grepl(epi_clus, .$clus))) %>%
  filter(!(grepl("^11$|^12$", .$clus))) %>%
  mutate(Direction = ifelse(avg_log2FC > 0, "UP", "DOWN")) %>%
  
  nest(., .by = "Clusters") %>%
  arrange(match(Clusters, names(sel_s))) %>%
  mutate(data = pmap(., ~filter_top.fun(..2, n=sel_s[[..1]]$n, var=sel_s[[..1]]$var, filt=sel_s[[..1]]$filt ))) %>%
  unnest(., cols=c("data"))
## # A tibble: 5 × 12
##      p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene   pct.diff log.pct.diff
##      <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>     <dbl>        <dbl>
## 1 1.98e-83      0.633 0.557 0.241  5.09e-79 1_all   FXYD3    -0.798         1.21
## 2 3.85e-80      0.614 0.56  0.246  9.89e-76 1_all   TRIM29   -0.806         1.19
## 3 6.06e-53      0.401 0.44  0.202  1.56e-48 1_all   C19or…   -0.642         1.12
## 4 9.46e-52      0.449 0.394 0.174  2.43e-47 1_all   SPINT2   -0.568         1.18
## 5 3.05e-51      0.443 0.398 0.179  7.83e-47 1_all   DSG1     -0.577         1.15
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 7.93e-237      1.62  0.704 0.222 2.04e-232 4_all   ACKR1   -0.926         1.67
## 2 5.10e-160      1.10  0.398 0.084 1.31e-155 4_all   TSPA…   -0.482         2.24
## 3 1.46e-137      1.10  0.471 0.135 3.76e-133 4_all   RAMP3   -0.606         1.80
## 4 9.27e-105      0.844 0.368 0.103 2.38e-100 4_all   IL33    -0.471         1.84
## 5 4.94e- 79      0.745 0.349 0.114 1.27e- 74 4_all   ITM2A   -0.463         1.61
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##      p_val avg_log2FC pct.1 pct.2  p_val_adj cluster gene  pct.diff log.pct.diff
##      <dbl>      <dbl> <dbl> <dbl>      <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 1.39e-10     0.0260 0.065 0.143 0.00000357 0_all   NDUF…   -0.208        -1.14
## 2 7.72e-10     0.0369 0.081 0.163 0.0000198  0_all   RGL2    -0.244        -1.01
## 3 2.28e- 9     0.0101 0.063 0.135 0.0000587  0_all   RBM42   -0.198        -1.10
## 4 3.38e- 9     0.0681 0.073 0.148 0.0000869  0_all   SNRPC   -0.221        -1.02
## 5 5.03e- 9     0.0149 0.063 0.133 0.000129   0_all   WARS    -0.196        -1.08
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##      p_val avg_log2FC pct.1 pct.2  p_val_adj cluster gene  pct.diff log.pct.diff
##      <dbl>      <dbl> <dbl> <dbl>      <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 1.07e-11      0.396 0.149 0.288    2.76e-7 3_all   TAX1…   -0.437       -0.951
## 2 9.47e-11      0.364 0.123 0.24     2.43e-6 3_all   PCM1    -0.363       -0.964
## 3 5.58e- 9      0.343 0.069 0.146    1.43e-4 3_all   UPF3A   -0.215       -1.08 
## 4 2.55e- 8      0.414 0.089 0.173    6.55e-4 3_all   USP8    -0.262       -0.959
## 5 8.00e- 7      0.341 0.056 0.114    2.05e-2 3_all   ZFC3…   -0.17        -1.03 
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##      p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##      <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 5.94e-27      0.590 0.235 0.113  1.53e-22 2_all   OGN     -0.348        1.06 
## 2 4.14e-11      0.345 0.154 0.088  1.06e- 6 2_all   PGBD5   -0.242        0.807
## 3 5.72e-11      0.364 0.13  0.071  1.47e- 6 2_all   PLK5    -0.201        0.873
## 4 9.83e-11      0.344 0.19  0.119  2.52e- 6 2_all   WNT16   -0.309        0.675
## 5 1.05e-10      0.248 0.182 0.11   2.70e- 6 2_all   CADM3   -0.292        0.726
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 3.67e-262      2.76  0.72  0.129 9.43e-258 9_all   DES     -0.849         2.48
## 2 8.82e-248      2.76  0.65  0.108 2.27e-243 9_all   ACTG2   -0.758         2.59
## 3 4.12e-137      1.49  0.297 0.033 1.06e-132 9_all   KCNM…   -0.33          3.17
## 4 2.00e-104      1.56  0.329 0.057 5.14e-100 9_all   PCP4    -0.386         2.53
## 5 1.63e- 65      0.946 0.237 0.045 4.18e- 61 9_all   SMOC2   -0.282         2.40
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
## # A tibble: 5 × 12
##       p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene  pct.diff log.pct.diff
##       <dbl>      <dbl> <dbl> <dbl>     <dbl> <chr>   <chr>    <dbl>        <dbl>
## 1 1.18e-291       2.17 0.728 0.138 3.04e-292 10_all  MUST…   -0.866         2.40
## 2 1.39e-222       1.51 0.573 0.104 3.57e-218 10_all  MCAM    -0.677         2.46
## 3 3.44e-158       1.16 0.472 0.094 8.83e-154 10_all  FRZB    -0.566         2.33
## 4 1.49e-141       1.15 0.458 0.099 3.82e-137 10_all  ITGA7   -0.557         2.21
## 5 1.43e-131       1.20 0.486 0.121 3.67e-127 10_all  CCDC3   -0.607         2.01
## # ℹ 3 more variables: clus <dbl>, Regulation <chr>, Direction <chr>
clus_2 <- DEGs_table %>%
  filter(Regulation == "DOWN") %>%
  filter(!(grepl(epi_clus, .$clus))) %>%
  
    filter(Regulation == "DOWN") %>%
    filter((grepl("^2$", .$clus))) %>%
    #top_n(., n=-10, abs(pct.2)) %>%
    filter(., between(pct.2, 0.3,0.8 )) %>%
    filter(., between(pct.1, 0.1,0.3 ))
    # #slice_min(order_by = p_val_adj, n = 20) %>%


c( top20_sub$gene[1:15], clus_2$gene, top20_sub$gene[21:35]) 
##  [1] "FXYD3"    "TRIM29"   "C19orf33" "SPINT2"   "DSG1"     "ACKR1"   
##  [7] "TSPAN7"   "RAMP3"    "IL33"     "ITM2A"    "NDUFB6"   "RGL2"    
## [13] "RBM42"    "SNRPC"    "WARS"     "DSG3"     "HOPX"     "CALML3"  
## [19] "KRT16"    "A2ML1"    "OGN"      "PGBD5"    "PLK5"     "WNT16"   
## [25] "CADM3"    "DES"      "ACTG2"    "KCNMA1"   "PCP4"     "SMOC2"   
## [31] "MUSTN1"   "MCAM"     "FRZB"     "ITGA7"    "CCDC3"
clus_2_genes <- c("CD151", "C12orf57", "NPDC1", "TGFBR2", "PECAM1")

# Housekeeping genes
# clus_2_genes <- c("RPL17", "TUBA","EF1A", "B2M", "RPSD", "GAPDH")
# probably not going to use
Idents(DATA) <- "layers"
Idents(DATA) <- "layers"
DATA %>%
filter(., grepl(epi_clus, DATA$Clusters)) %>%
  RidgePlot(., features = top20_epi$gene[1:2], ncol = 2)

# epithelium
genes <- top20_epi$gene
col <- c("#E41A1C","#FF7F00","#C77CFF","#984EA3")
# Submucosa
genes <- c( top20_sub$gene[1:10],clus_2_genes , top20_sub$gene[21:35]) 
col <- c("#00A9FF","#377EB8","#CD9600","#7CAE00","#e0e067","#FF61CC","#FF9DA7")

df <- DATA %>%
  filter(., grepl(epi_clus, DATA$Clusters)) %>% 
  #filter(., !(grepl("^5$|^6$|^7|^8|^11$|^12$", DATA$Clusters))) %>% 
  mutate(., FetchData(., vars = genes)) %>%
  as_tibble() %>%
  select(.cell, sp_annot, orig.ident, groups, layers, any_of(genes)) %>%
  pivot_longer(cols = any_of(genes), names_to = "Genes", values_to = "Expression") %>%
  mutate(Genes = factor(.$Genes, levels=rev(genes))) %>%
  arrange(layers) %>%
  nest(data= -layers) %>%
  mutate(col = col)


p <- df %>%
  mutate(plot = pmap(., 
        ~ggplot(..2, aes(x = Expression, y = Genes, fill = ..3)) +
                geom_density_ridges() +
                scale_fill_identity() +
                xlim(c(0,4)) +
                theme_ridges() + labs(title = ..1 )  +
                theme(legend.position = "none",
                      plot.margin = unit(c(0,-0,0,0),units = "pt"),
                      axis.title.y = element_blank())
  ))

(p_ <- plot_grid(plotlist = p$plot, ncol=length(col)) )
ggsave("./Figures/Marker_genes_ridges_epi.pdf", p_, width = 12, height = 5)
ggsave("./Figures/Marker_genes_ridges_sub.pdf", p_, width = 21, height = 7)
library(ComplexHeatmap)
library(circlize)

#### GENES THAT ARE UNIQELY OVERLAPING ####
getVennOverlap <- function(lsvenn) {
  
  ItemsList <- gplots::venn(lsvenn, show.plot = FALSE)
  print(lengths(attributes(ItemsList)$intersections))
  return(attributes(ItemsList)$intersections)
}

################
# PLOT HEATMAP #
################
heatmap.fun <- function(genes, cluster){
###############
# GET MATRIX #
###############
DAT <- filter(DATA, grepl(paste0("^",cluster,"$",collapse="|"), DATA$layers))
VariableFeatures(DAT) <- genes
DAT <- Seurat::ScaleData(DAT)
matx <- DAT@assays$RNA$scale.data %>% 
  as.matrix()
  
  
##############
# ANNOTATION #
##############
annot_col <<- DAT@meta.data %>%
  #mutate(layers = factor(.$layers, levels = cluster)) %>%
  dplyr::select(1:7) 

# set row order
matx <- matx[genes,]
#print( dput(rownames(matx)))
#col_order <<- rownames(arrange(annot_col, layers) )

clus_cols <- c("#E41A1C","#FF7F00","#C77CFF","#984EA3",
               "#00A9FF","#377EB8","#CD9600","#7CAE00","#e0e067","#FF61CC","#FF9DA7","#BAB0AC","#A65628")
clus <- c("Superficial","Upper IM","Lower IM","Basal","1","4","0","3","2","9","10","11","12") #
clus_cols <- set_names(clus_cols, clus)
clus_cols <- clus_cols[unique(annot_col$layers)]

ID_cols <- c("#4E79A7","#F28E2B","#E15759","#76B7B2","#59A14F","#EDC948","#9C755F","#B07AA1","#FF9DA7",
             "#E78AC3","#7FC97F","#BEAED4","#BAB0AC","#FDC086","#FFFF99","#386CB0","#F0027F","#BF5B17",
             "#66C2A5","#FC8D62","#8DA0CB")
ID_cols <- set_names(ID_cols, sample_id)
ID_cols <- ID_cols[unique(annot_col$orig.ident)]

group_cols <- c("#56B4E9","#009E73","#CC79A7","#FC8D62")
gr <- c('L1', 'L2', 'L3', 'L4') %>% set_names()
group_cols <- set_names(group_cols, gr)
group_cols <- group_cols[unique(annot_col$groups)]

################
# DRAW HEATMAP #
################

# qwartile 
q <- quantile(matx, c(0.05, 0.95))
c(min(matx), max(matx))

# average expression:
set.seed(123)
H <- Heatmap(matx, name = " ",
             col = circlize::colorRamp2(c(q[1]*2, q[1], 0, q[2], q[2]*2), 
                                        c("#440154FF","#6A51A3","#21908CFF","#FDE725FF","#FF7F00")
                                        #rev(c("#D7191C","#FDAE61", "white","#ABD9E9","#4575B4"))
                                        ),
             #row_km = 6, #column_km = 2, # kmeans change every time you run it
             column_split =  factor(as.character(annot_col$layers), levels = cluster),
             #row_split = 10,  # hierarchical static
             row_order = rownames(matx),
             column_order = rownames(arrange(annot_col, layers) ),
             show_column_names = FALSE,
             show_row_dend = FALSE,
             show_column_dend = FALSE,
             #cluster_columns = T,
             use_raster = F, # removes white vertical lines in the heatmap
             
             # text
             row_title = gt_render("", padding = unit(c(0, 0, 0, 0), "pt")),
             
             #column_labels = gt_render(column_labels, padding = unit(c(0, 0, 0, 0), "pt")),
             column_title_gp = grid::gpar(fontsize = 8),
             #column_labels_gp =  grid::gpar(fontsize = 8),
             
             column_names_gp = grid::gpar(fontsize = 8),
             row_names_gp = grid::gpar(fontsize = 8),
            
             
             # annotation
             # right_annotation = right_anno_row, left_annotation = left_anno_row,
             top_annotation =
               columnAnnotation(Cluster=annot_col$layers,
                                #show_legend = FALSE,
                                show_annotation_name = F,
                                annotation_legend_param =
                                  list(grid_height = unit(.2, "mm"),
                                       grid_width = unit(2, "mm"), title = "",
                                       labels_gp = gpar(fontsize = 7),
                                       title_gp = gpar(fontsize = 8)),
                                simple_anno_size = unit(.1, "cm"),
                                #gap = unit(1, "cm"),
                                col=list( Cluster = clus_cols )
                                ),

             # legend
             heatmap_legend_param = list(legend_height = unit(20, "mm"), grid_width = unit(2, "mm"), 
                                         labels_gp = gpar(fontsize = 7))
             #annotation_legend_param = list(size = unit(2, "mm"))

             ) #colorRampPalette(c(col))(10) 

H <- draw(H, merge_legend = TRUE)
return(H)
}
# Heatmap global options:
ht_opt$COLUMN_ANNO_PADDING = unit(.05, "cm")
ht_opt$HEATMAP_LEGEND_PADDING = unit(0, "cm")
ht_opt$TITLE_PADDING = unit(.05, "cm")
ht_opt$DIMNAME_PADDING = unit(.05, "cm")

lvl_layers <- c("Superficial", "Upper IM", "Lower IM", "Basal","1","4","0","3","2","9","10","11","12")

# all clusters together: 
# genes <- c(top20_epi$gene, top20_sub$gene)
# H <- heatmap.fun(genes = genes, lvl_layers)

##############
# EPITHELIUM #
##############
genes <- top20_epi$gene
H_epi <- heatmap.fun(genes = genes, lvl_layers[1:4])

# save file
H_grob <- grid.grabExpr(draw(H_epi, merge_legend = TRUE))  # show_heatmap_legend = FALSE,
ggsave("./Figures/01/heatmap_clusters_epi.png", H_grob, width = 6, height = 3, limitsize = F)
#############
# SUBMUCOSA #
#############
genes <- c( top20_sub$gene[1:10], clus_2_genes, top20_sub$gene[21:35]) 
H_sub <- heatmap.fun(genes = genes, lvl_layers[5:11])

# save file
H_grob <- grid.grabExpr(draw(H_sub, merge_legend = TRUE))  # show_heatmap_legend = FALSE,
ggsave("./Figures/01/heatmap_clusters_sub.png", H_grob, width = 6, height = 4, limitsize = F)
# NB! when working with the heatmap, make sure output is printed to the console
#######################
# DEFINE MARKER GENES #
#######################
Cell_marker <- c("MS4A1","CD79A", "POU2AF1", "MZB1", "FCRL5", "CD38",
                 "CD247","CD8A","CD3D","CD3G","CD4","CXCR4",  
                 "NCAM1", "GZMA", "GNLY",  "FCER1A", "CD1A", "LTB",  
                 "COL3A1","COL1A1", "APOD","LAMA2", "MYH11","ICAM2","PECAM1","MCAM",   # FLT1 #"COL3A1","COL1A1", "MYH11","LAMA2"
                 "ATG9B", "KPRP","ALOX12", "PRSS3", "BICDL2", "MT1X")
names <- c("B cell", "B cell","B cell", "Plasma cell","Plasma cell", "Plasma cell", 
           "T cell", "T cell","T cell", "T cell", "T cell", "T cell", 
           "NK cells", "NK cells", "NK cells","Myeloid", "Myeloid", "Myeloid", 
           "Fibroblast", "Fibroblast", "Fibroblast","Fibroblast", 
           "Endothelial","Endothelial", "Endothelial", "Endothelial", "Keratinocyte supra", "Keratinocyte supra", 
           "Keratinocyte supra","Keratinocyte supra", "Keratinocyte basal", "Keratinocyte basal")
cell_type <- set_names(names, Cell_marker)
clus_lvl <- rev(c("5", "6", "7", "8", "1","4","0","3","2","9","10","11","12")) 

clus_lvl <- set_names(seq_along(clus_lvl), clus_lvl)
gene_lvl <- set_names(seq_along(Cell_marker), Cell_marker)
################
# FETCH GENES #
################
cell_type <- set_names(names, Cell_marker)
df <- DATA %>%
  mutate(., FetchData(., vars = c(Cell_marker)) ) %>%
  as_tibble() %>%
  select(., .cell, Clusters, any_of(Cell_marker)) %>%
  pivot_longer(., cols = -c(".cell", "Clusters"), 
               names_to = "marker", values_to = "values") %>%
  mutate(., cell = cell_type[as.character(.$marker)]) %>%
  mutate( marker_id = paste0(.$cell," (",.$marker,")")) %>%
  #filter(., Clusters != "11"| Clusters != "12") %>%
  mutate(Clusters = factor(.$Clusters, levels=names(clus_lvl))) %>%
  mutate(marker = factor(.$marker, levels=Cell_marker)) %>%
  group_by(Clusters, marker, cell) %>%
  summarise(Avg = mean(values),
            Pct = sum(values > 0) / length(values) * 100, .groups="drop") %>%
  mutate(., ymin = clus_lvl[as.character(.$Clusters)]-0.5,
            ymax = clus_lvl[as.character(.$Clusters)]+0.5) %>%
  mutate(., xmin = gene_lvl[as.character(.$marker)]-0.5,
            xmax = gene_lvl[as.character(.$marker)]+0.5)

########################
# MARKER GENES DOTPLOT #
########################
library(ggnewscale)
cell_col <- c("#FFD92F","#FFFFCC","#8DA0CB","#eb6062","#A6D854","#E78AC3","#66C2A5","#FC8D62","#FED9A6",
         "#377EB8","#4DAF4A","#B3B3B3","#984EA3","#FF7F00","#FFFF33","#A65628","#F781BF")

clus_col <- rev(c("#FBAAB1","#FFDAB8","#F1D2FF","#E6B3E9","#92DBFF","#ABC9E1", "#E5C264","#BBD99B", "#E1E2A4", "#FF61CC","#FA9DA7", "#B3B3B3", "#A65628"))
lab <- c("B cell", "Plasma cell", "T cell", "NK cells", "Myeloid", "Fibroblast", 
"Endothelial", "Keratinocytes")

ym <- max(df$ymax)
xm <- length(cell_type)+3.5

clus_lvl <- rev(c("5","6","7","8","1","4","0","3","2","9","10","11","12"))
# DATA %>%
#   mutate(Clusters = factor(.$Clusters, levels = clus_lvl)) %>%
# ggplot(., aes(x=Clusters, y=nCount_RNA, fill=Clusters)) + geom_violin() + scale_fill_manual(values = clus_col)

(A <- ggplot(df, aes(x=marker, y=Clusters)) +
  geom_point(aes(size = Pct, fill = Avg), color="white", shape=21) +
  scale_fill_gradientn(colours = viridisLite::magma(100),
                       guide = guide_colorbar(ticks.colour = "white",
                                              frame.colour = "white",
                                              barwidth = .5, barheight = 4),
                       name = "Average\nexpression") +
  #facet_grid(~ cell, scales = "free_x") +
  # Cell type colour bar
  new_scale_fill() +
  geom_rect(aes(ymin=max(ymax), ymax=max(ymax)+.4,
                xmin=xmin, xmax=xmax,
                fill = cell),data=df,alpha = 0.1,show.legend=F) +
  annotate("text", x = c(1.8, 5, 10, 14, 17, 20.5, 24.6, 29.5 ), y = 13.7, label = lab) +
  geom_rect(aes(ymin=min(ymin), ymax=min(ymin)+.3,
                xmin=xmin, xmax=xmax,
                fill = cell),data=df,alpha = 0.1,show.legend=F) +
  scale_fill_manual(values = set_names(cell_col[1:length(unique(cell_type))], unique(cell_type))) +
    
  # add extra borders for the colour bars
  # annotate(x = c(.5,xm,-.5,-.5,.5,-.5), xend=c(.5,xm,xm,xm,xm,-.5),
  #            y=c(1,1,.5,ym,ym+.5,.5), yend=c(ym+.5,ym+.5,.5,ym,ym+.5,ym),
  #            geom="segment",colour = "black", linewidth = .6, alpha = 1) +
  # Cluster bar annnotation
  new_scale_fill() +
  geom_rect(aes(ymin=ymin, ymax=ymax,
                xmin=0.4, xmax=-.5,
                fill = Clusters),data=df,alpha = 1,show.legend=F) +  
  scale_fill_manual(values = clus_col) +
  coord_cartesian(clip="off", xlim=c(.5,xm),ylim=c(.5,ym),expand = F) +
  scale_size("% detected", range = c(0,6)) +

  ylab("Cluster") + xlab("") +
  theme_bw() +
  guides(size = guide_legend(override.aes = list(color = "black"), keywidth = .6, keyheight = .6)) +
  theme(axis.text.x = element_text(size=8, angle=45, hjust=1, color="black"),
        axis.text.y = element_text(size=9, color="black",hjust=.9 ),
        axis.title = element_text(size=9),
        axis.ticks.y = element_blank(),
        panel.border = element_blank(),
        legend.title = element_text(size = 9),
        legend.margin=margin(0,0,-0,0),
        plot.margin = unit(c(1,0,-.4,.1),units = "cm") #trbl
        ) 
)

# dev.new(width=8, height=3.5, noRStudioGD = TRUE)
# ggsave("./Figures/01/marker-gene-dotplot_new.pdf", A, width = 8, height = 3.5) # cell_marker

Not used!

library(edgeR)
pseudo.bulk <- function(DATA, group_var, degs=FALSE){
  # create ID per cluster group
  DATA <- mutate(DATA, ID_clus = paste0(DATA$orig.ident, "_", DATA[[group_var]]))
  
  # get the count matrix for all cells
  sparse_mtrx <- DATA@assays$RNA@counts
  
  # Compute pseudobulk
  mm <- Matrix::sparse.model.matrix(~0 + DATA$ID_clus)
  pseudobulk <- sparse_mtrx %*% mm
  colnames(pseudobulk) <- str_replace(colnames(pseudobulk), "DATA\\$ID_clus", "")
  
  # group
  gr <- str_replace(colnames(pseudobulk), "P\\d\\d\\d_", "")
  gr <- set_names(gr, colnames(pseudobulk))
  
  if(length(degs) > 1){
    # filter genes based on DEG analysis
    matx <- as.matrix(pseudobulk)
    matx <- matx[degs,]
  }else{
    # filter genes based on groups
  dge.list <- DGEList(counts = pseudobulk, group = factor(gr))
  keep <- filterByExpr(dge.list)
  matx <- dge.list[keep, , keep.lib.sizes = FALSE]}
  
  return(matx)
}

# remove specified genes:
remove_genes <- function(x, gene_name) x[!(grepl(gene_name, rownames(x[["RNA"]]))), ]
sample_id <- c("P020","P045","P050","P057",
               "P008","P026","P031","P044","P080","P105", 
               "P001","P004","P014","P018","P087","P108","P118",
               "P021","P024","P067","P081","P117")
groups <- c( "L1","L1","L1","L1",
             "L2","L2","L2","L2","L2","L2",
             "L3","L3","L3","L3","L3","L3","L3",
             "L4","L4","L4","L4","L4")
id_gr <- set_names(groups, sample_id)
######################
# GET DEGS  # 
######################
pseudo_DEGs <- readRDS(paste0("../results/06_DGE_condition_st_data/","Pseudobulk_across_DEGs.RDS"))
pseudo_DEGs <- pseudo_DEGs %>%
  #filter(layers != "11" | layers != "12" ) %>% unnest() %>%
  mutate(test = map(test, ~filter(.x, PValue <= 0.001) )) %>%
  unnest(test) %>% .$symbol %>% unique()
######################
# NORMALIZE TRX DATA # 
######################
matx <- pseudo.bulk(DATA, "layers", degs = pseudo_DEGs)
matx <- pseudo.bulk(DATA, "orig.ident")
#### CPM-log2 ####
# counts per million (CPM) log2 transfomed counts:
matrix_trans <- cpm( matx, log=T)

########
# UMAP # 
########
lvl_layers <- c("Superficial","Upper IM","Lower IM","Basal","3","4","0","2","1","9","10","11","12")
col <- c("#E41A1C","#FF7F00","#C77CFF","#984EA3","#00A9FF","#377EB8","#CD9600","#7CAE00","#e0e067","#FF61CC","#FF9DA7","#999999","#A65628")

lvl_layers <- sample_id
col <-  c("#4E79A7", "#F28E2B", "#E15759", "#76B7B2", "#59A14F", "#EDC948", "#9C755F", "#B07AA1", "#FF9DA7", "#E78AC3", "#7FC97F", "#BEAED4", "#BAB0AC", "#FDC086", "#FFFF99", "#386CB0", "#F0027F", "#BF5B17", "#666666", "#66C2A5", "#FC8D62", "#8DA0CB")

#### UMAP analysis ####
set.seed(1);umap<-uwot::umap(t(matrix_trans), 
                 n_neighbors=15, init="spectral", scale=T)
umap_df <- tibble("UMAP 1"=umap[,1],"UMAP 2"=umap[,2], 
                  "u_ID"=rownames(umap), "group"=gr[rownames(umap)], "ID"=str_extract(rownames(umap), "P\\d\\d\\d") ) %>%
            mutate(group = factor(.$group, levels = lvl_layers)) %>%
            mutate(g = id_gr[.$ID]) 


txt_df <- umap_df %>% 
  filter(., grepl("^P", .$txt)) #%>%
  #mutate("UMAP 2" = .$`UMAP 2`+ c(0, .1, rep(0,ncol(.))))

#### UMAP plotting by groups ####
UMAP.fun <- function(umap_df, group){
  # dev.new(width=8.5, height=8)
  p <- ggplot(umap_df, aes(x=`UMAP 1`, y=`UMAP 2`, fill={{group}}))+ 
    #geom_jitter( shape=21, size=3, color="white", width=.5, height=.5) +  # Tassos used jitter
    geom_point( shape=21, size=3, alpha = .7, stroke =1) +  
    scale_fill_manual(values=col) + 
    # geom_text(data=txt_df, aes(x=`UMAP 1`, y=`UMAP 2`, label=txt), size=3, vjust = -.5, nudge_x = 0.03, color="gray51") +
    theme_void() +
    xlab("UMAP 1") + ylab("UMAP 2") +
    theme(panel.border = element_rect(colour = "black", fill=NA),
          legend.title = element_text(size = 8),
          legend.text = element_text(size = 8),
          legend.position = "bottom",
          plot.margin = unit(c(1,.5,1,.5), "lines"),
          axis.title.x.bottom = element_text(margin = margin(b = 1)),
          axis.title.y.left = element_text(margin = margin(l = 0), angle = 90),
          axis.ticks=element_line(color="black"), 
          axis.title=element_blank()) 
  return(p)
}

(p <- UMAP.fun(umap_df, g))
(p_T <- UMAP.fun(umap_df, Tissue_gr_v3))

# dev.new(width=8, height=3.5, noRStudioGD = TRUE)
(p_ <- plot_grid(p_L, p_T, ncol = 2 ) )
LS0tCnRpdGxlOiAiRmlndXJlIDEiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSVtLSVZJylgIgpmb3JtYXQ6CiAgaHRtbDoKICAgIGVtYmVkLXJlc291cmNlczogdHJ1ZQogICAgY29kZS1mb2xkOiBzaG93CnBhcmFtczoKICBmaWcucGF0aDogImByIHBhc3RlMChwYXJhbXMkZmlnLnBhdGgpYCIgIy4vRmlndXJlcy8KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQojIyBIZWF0bWFwIG9mIHNpZ25pZmljYW50IGdlbmVzIHBlciBjbHVzdGVyCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGZpZy53aWR0aCAgICAgPSA2LjY5MjkxMzM4NTgsCiAgIyBmaWcucGF0aCAgICAgID0gcGFyYW1zJGZpZy5wYXRoLCMiLi4vRmlndXJlcy8iLAogIGZpZy5hbGlnbiAgICAgPSAiY2VudGVyIiwKICBtZXNzYWdlICAgICAgID0gRkFMU0UsCiAgd2FybmluZyAgICAgICA9IEZBTFNFLAogIGRldiAgICAgICAgICAgPSBjKCJwbmciKSwKICBkcGkgICAgICAgICAgID0gMzAwLAogIGZpZy5wcm9jZXNzID0gZnVuY3Rpb24oZmlsZW5hbWUpewogICAgbmV3X2ZpbGVuYW1lIDwtIHN0cmluZ3I6OnN0cl9yZW1vdmUoc3RyaW5nID0gZmlsZW5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi0xIikKICAgIGZzOjpmaWxlX21vdmUocGF0aCA9IGZpbGVuYW1lLCBuZXdfcGF0aCA9IG5ld19maWxlbmFtZSkKICAgIGlmZWxzZShmczo6ZmlsZV9leGlzdHMobmV3X2ZpbGVuYW1lKSwgbmV3X2ZpbGVuYW1lLCBmaWxlbmFtZSkKICB9CiAgKQojICBzZXR3ZCgifi93b3JrL0Jyb2xpZGVuc193b3JrL1Byb2plY3RzL1NwYXRpYWxfTWljcm9iaW90YS9zcmMvTWFudXNjcmlwdCIpCmBgYAoKYGBge3IgYmFja2dyb3VuZF9qb2IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgiLi4vLi4vYmluL3JlbmRlcl93aXRoX2pvYnMuUiIpCgojIHF1YXJ0bwojIHJlbmRlcl9odG1sX3dpdGhfam9iKG91dF9kaXIgPSBsYWJfZGlyKQojIGZzOjpmaWxlX21vdmUocGF0aCA9IGZpbGUsIG5ld19wYXRoID0gcGFzdGUwKGxhYl9kaXIsIGZpbGUpKQoKIyBjdXJyZW50bHkgdXNpbmcgcXVhcnRvIGZvciBnaXRodWIgYW5kIGtuaXRlciBmb3IgaHRtbCBkdWUgdG8gc291cmNlIGNvZGUgb3B0aW9uIApyZW5kZXJfZ2l0X3dpdGhfam9iKGZpZ19wYXRoID0gIi4vRmlndXJlcy8wMS8iKQpzeXN0ZW0yKGNvbW1hbmQgPSAic2VkIiwgc3Rkb3V0ID0gVFJVRSwKICAgICAgICBhcmdzID0gYygiLWkiLCAiJyciLCItZSIsICdzL3NyYz1cXCJcXC4vc3JjPVxcIlxcLlxcLi9nJywKICAgICAgICAgICAgICAgICBwYXN0ZTAoIi4vbWRfZmlsZXMvIiwgYmFzZW5hbWUoIi4vMDFfZmlndXJlcy5tZCIpKSkpCgojIGtuaXRlcgprbml0X2h0bWxfd2l0aF9qb2Iob3V0X2RpciA9ICIuLi9sYWJfYm9vay9maWd1cmVfMDEiLCBmaWdfcGF0aCA9ICIuL0ZpZ3VyZXMvMDEvIikKYGBgCgojIyMgTG9hZCBkYXRhIGFuZCBsaWJyYXJpZXMKYGBge3IgTG9hZF9kYXRhfQojIyMjIyMjIyMjIyMjIyMjIyMKIyBMT0FEIExJQlJBUklFUyAjCiMjIyMjIyMjIyMjIyMjIyMjIwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KHRpZHlzZXVyYXQpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdyaWR0ZXh0KQpsaWJyYXJ5KHBuZykKbGlicmFyeShncmlkKQojbGlicmFyeShzY2F0dGVycGllKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShvcGVueGxzeCkKbGlicmFyeShyZWFkeGwpCgojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJDb21wbGV4SGVhdG1hcCIpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCgpzb3VyY2UoIi4uLy4uL2Jpbi9zcGF0aWFsX3Zpc3VhbGl6YXRpb24uUiIpCnNvdXJjZSgiLi4vLi4vYmluL3Bsb3R0aW5nX2Z1bmN0aW9ucy5SIikKCiMjIyMjIyMjIwojIFBBVEhTICMKIyMjIyMjIyMjCmlucHV0X2RpciA8LSAiLi4vLi4vMDNfY2x1c3RlcmluZ19zdF9kYXRhLyIKZXBpX2NsdXMgPC0gIl41JHxeNiR8Xjd8XjgiICMgcmVzIDAuNwoKIyMjIyMjIyMjIyMjIwojIExPQUQgREFUQSAjCiMjIyMjIyMjIyMjIyMKREVHc190YWJsZSA8LSByZWFkX2NzdihwYXN0ZTAoIi4uLy4uL3Jlc3VsdHMvMDVfREdFX2NsdXN0ZXJzX3N0X2RhdGEvIiwiREdFc19jbHVzdGVyc193aWxjb3guMC43LmNzdiIpKQpEQVRBIDwtIHJlYWRSRFMocGFzdGUwKCIuLi8uLi9yZXN1bHRzLzAzX2NsdXN0ZXJpbmdfc3RfZGF0YS8iLCJzZXVyYXRPYmpfY2x1c3RlcmVkLlJEUyIpKQoKCnNhbXBsZV9pZCA8LSBjKCJQMDIwIiwgIlAwNDUiLCAiUDA1MCIsICJQMDU3IiwKICAgICAgICAgICAgICAgIlAwMDgiLCAiUDAzMSIsICJQMDgwIiwgIlAwNDQiLCAiUDAyNiIsICJQMTA1IiwgCiAgICAgICAgICAgICAgICJQMDAxIiwgIlAwMDQiLCAiUDAxNCIsICJQMDE4IiwgIlAwODciLCAiUDExOCIsCiAgICAgICAgICAgICAgICJQMDIxIiwgIlAwMjQiLCAiUDA2NyIsICJQMDgxIiwgIlAxMTciICkgJT4lIHNldF9uYW1lcygpCmBgYAoKCiMjIyBJZGVudGlmeSBtYXJrZXIgZ2VuZXMgdG8gc2VwZXJhdGUgZXBpdGhlbGlhbCBjbHVzdGVycwpgYGB7ciBHZXQtYmVzdC1tYXJrcnNfZXBpfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBGSUxURVIgQlkgUC1WQUwgbG9nRkMgQU5EIHBjdC5kaWZmICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZmlsdGVyX3RvcC5mdW4gPC0gZnVuY3Rpb24obmVzdGVkX2RmLCBuLCB2YXIsIG1pbl9wY3QgPSAwKXsKICBpZihpcy5uYShuWzRdKSl7bls0XSA9IG1pbl9wY3R9CiAgcmVzIDwtIG5lc3RlZF9kZiAlPiUgIyByZXMgPC0gdG9wMjBfZXBpJGRhdGFbWzNdXSAlPiUKICAgICNtdXRhdGUocF92YWxfYWRqID0gMS4wMDAtLiRwX3ZhbF9hZGopICU+JQogICAgZmlsdGVyKHBfdmFsX2FkaiA8IDAuMDUpICU+JQogICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUKICAgIGZpbHRlcihwY3QuMSA+IG5bNF0pICU+JQogICAgdG9wX24oLiwgbj1uWzFdLCBhYnMoISFzeW0odmFyWzFdKSkpICU+JQogICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUKICAgICN0b3BfbiguLCBuPW5bMl0sIEF2Z19leHApICU+JQogICAgdG9wX24oLiwgbj1uWzJdLCBhYnMoISFzeW0odmFyWzJdKSkpICU+JQogICAgdG9wX24oLiwgbj1uWzNdLCBhYnMoISFzeW0odmFyWzNdKSkpIAogIHByaW50KHJlcykKICByZXR1cm4ocmVzWzE6blszXSxdKQp9CgpzZWxfZXBpIDwtIGxpc3QoCiAgI1N1cF8xID0gbGlzdChuPWMoLTQwLCAzMCwgNSksdmFyPWMoInBfdmFsX2FkaiIsICJwY3QuZGlmZiIsICJBdmdfZXhwIiwgImxvZy5wY3QuZGlmZiIpKSwKICAiU3VwZXJmaWNpYWwiID0gbGlzdChuPWMoLTQwLCA1MCwgNSksdmFyPWMoInBfdmFsX2FkaiIsICJwY3QuZGlmZiIsICJsb2cucGN0LmRpZmYiKSksCiAgI1N1cF8xID0gbGlzdChuPWMoLTEwMCwgNzAsIDUsIDAuNSksdmFyPWMoInBjdC5kaWZmIiwgInBfdmFsX2FkaiIsICJsb2cucGN0LmRpZmYiKSksCiAgIlVwcGVyIElNIiA9IGxpc3Qobj1jKC00MCwgNTAsIDUpLHZhcj1jKCJwX3ZhbF9hZGoiLCAicGN0LmRpZmYiLCAibG9nLnBjdC5kaWZmIikpLAogICNTdXBfMiA9IGxpc3Qobj1jKDIwLCA1LCA1KSx2YXI9YygiYXZnX2xvZzJGQyIsICJsb2cucGN0LmRpZmYiLCAibG9nLnBjdC5kaWZmIikpLAogICJMb3dlciBJTSIgPSBsaXN0KG49YygyNSwgNywgNSwgLjUpLHZhcj1jKCJhdmdfbG9nMkZDIiwgImxvZy5wY3QuZGlmZiIsICJsb2cucGN0LmRpZmYiKSksCiAgIkJhc2FsIiA9IGxpc3Qobj1jKDEwLCA1LCA1LCAuOCksdmFyPWMoImF2Z19sb2cyRkMiLCAibG9nLnBjdC5kaWZmIiwgImxvZy5wY3QuZGlmZiIpKSApCgojIElkZW50aWZ5IHRoZSB0b3AgZ2VuZXMgdGhhdCBoYXZlIGEgaGlnaCBkaWZmZXJlbmNlIGluIGV4cHJlc3Npb24gYmV0d2VlbiB0aGUgY2x1c3RlcnMKdG9wMjBfZXBpIDwtIERFR3NfdGFibGUgJT4lCiAgZmlsdGVyKGdyZXBsKGVwaV9jbHVzLCAuJGNsdXMpKSAlPiUKICBhcnJhbmdlKG1hdGNoKENsdXN0ZXJzLCBuYW1lcyhzZWxfZXBpKSkpICU+JQogIG11dGF0ZShEaXJlY3Rpb24gPSBpZmVsc2UoYXZnX2xvZzJGQyA+IDAsICJVUCIsICJET1dOIikpICU+JQogIGZpbHRlcihEaXJlY3Rpb24gPT0gIlVQIikgJT4lCiAgI2ZpbHRlcighKHBjdC4yID4gMC4yKSkgJT4lCiAgbmVzdCguLCAuYnkgPSAiQ2x1c3RlcnMiKSAlPiUKICBtdXRhdGUoZGF0YSA9IHBtYXAoLiwgfmZpbHRlcl90b3AuZnVuKC4uMiwgbj1zZWxfZXBpW1suLjFdXSRuLCB2YXI9c2VsX2VwaVtbLi4xXV0kdmFyKSkgKSAlPiUKICB1bm5lc3QoLiwgY29scz1jKCJkYXRhIikpCiAgCmBgYAoKIyMjIElkZW50aWZ5IG1hcmtlciBnZW5lcyB0byBzZXBlcmF0ZSBTdWJtdWNvc2FsIGNsdXN0ZXJzCmBgYHtyIEdldC1iZXN0LW1hcmtyc19TdWJNdWN9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEZJTFRFUiBCWSBQLVZBTCBsb2dGQyBBTkQgcGN0LmRpZmYgIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpmaWx0ZXJfdG9wLmZ1biA8LSBmdW5jdGlvbihuZXN0ZWRfZGYsIG4sIHZhciwgZmlsdF9wY3QyPTAuOSl7CiAgZmlsdCA8LSBUUlVFCiAgI2lmKGlzLm5hKG5bNF0pKXtuWzRdID0gcGN0fQogIHJlcyA8LSBuZXN0ZWRfZGYgJT4lICMgcmVzIDwtIHRvcDIwX3N1YiRkYXRhW1s3XV0gJT4lCiAgICAjbXV0YXRlKHBfdmFsX2FkaiA9IDEuMDAwLS4kcF92YWxfYWRqKSAlPiUKICAgICNmaWx0ZXIoQXZnX2RpZmYgPiAwKSAlPiUKICAgICNmaWx0ZXIocGN0LjIgPCBuWzRdKSAlPiUKICAgIHRvcF9uKC4sIG49blsxXSwgYWJzKCEhc3ltKHZhclsxXSkpKSAlPiUKICAgIHtpZihmaWx0KSBmaWx0ZXIoLiwgYmV0d2VlbihwY3QuMiwgMC4wMSxmaWx0X3BjdDIgKSkgZWxzZSAufSAlPiUKICAgIHRvcF9uKC4sIG49blsyXSwgYWJzKCEhc3ltKHZhclsyXSkpKSAlPiUKICAgIAogICAgCiAgICAje2lmKGZpbHQpIGZpbHRlciguLCBiZXR3ZWVuKHBjdC4xLCAwLjgsMC4zKSB8IGJldHdlZW4ocGN0LjIsIDAuMSwwLjQpKSBlbHNlIC59ICU+JQogICAgI2FycmFuZ2UoZGVzYyhBdmdfZXhwXzMpKSAlPiUKICAgIAogICAgdG9wX24oLiwgbj1uWzNdLCBhYnMoISFzeW0odmFyWzNdKSkpICMlPiUKICAgICNhcnJhbmdlKGRlc2MoISFzeW0odmFyWzNdKSkpCiAgcHJpbnQocmVzKQogIHJldHVybihyZXMpCn0KCnNlbF9zIDwtIGxpc3QoCiAgIyIzIiA9IGxpc3Qobj1jKC02MCwgMzAsIDUpLHZhcj1jKCJwX3ZhbF9hZGoiLCAicGN0LjEiLCAicGN0LjEiKSwgZmlsdF9wY3QyPS4yNSksCiAgIjEiID0gbGlzdChuPWMoLTYwLCAzMCwgNSksdmFyPWMoInBfdmFsX2FkaiIsICJwY3QuMSIsICJwY3QuMiIpLCBmaWx0X3BjdDI9LjI1KSwKICAjIjMiID0gbGlzdChmaWx0PUYsIG49YygtMTUwLCAxMDAsIDUpLHZhcj1jKCJwX3ZhbF9hZGoiLCAicGN0LmRpZmYiLCAibG9nLnBjdC5kaWZmIikpLAogICI0IiA9IGxpc3QoIG49YygtMTAwLCA1MCwgNSksdmFyPWMoInBfdmFsX2FkaiIsICJwY3QuZGlmZiIsICJsb2cucGN0LmRpZmYiKSwgZmlsdF9wY3QyPS45KSwKICAiMCIgPSBsaXN0KCBuPWMoLTEwMCwgNTAsIDUpLHZhcj1jKCJwX3ZhbF9hZGoiLCAiYXZnX2xvZzJGQyIsICJsb2cucGN0LmRpZmYiKSwgZmlsdF9wY3QyPS40KSwKICAjIjAiID0gbGlzdCggbj1jKC02MCwgMzAsIDUpLHZhcj1jKCAicGN0LjIiLCAiYXZnX2xvZzJGQyIsICJsb2cucGN0LmRpZmYiKSwgZmlsdF9wY3QyPS40KSwKICAjIjAiID0gbGlzdCggbj1jKCAtNTAsIDMwLCA1LCAwLjIpLHZhcj1jKCAicF92YWxfYWRqIiwgImF2Z19sb2cyRkMiLCAibG9nLnBjdC5kaWZmIiksIGZpbHQ9VCksCiAgIjMiID0gbGlzdChuPWMoNDAsIC01MCwgNSksdmFyPWMoImF2Z19sb2cyRkMiLCAicGN0LmRpZmYiLCAibG9nLnBjdC5kaWZmIiksIGZpbHRfcGN0Mj0uOSksCiAgIjIiID0gbGlzdCggbj1jKC05MCwgLTIwLCAtNSksdmFyPWMoInBfdmFsX2FkaiIsICJwY3QuMiIsICJwY3QuMiIpLCBmaWx0X3BjdDI9LjUpLAogICI5IiA9IGxpc3QoIG49YygtOTAsIDUwLCA1KSx2YXI9YygicF92YWxfYWRqIiwgInBjdC5kaWZmIiwgImxvZy5wY3QuZGlmZiIpLCBmaWx0X3BjdDI9LjkpLAogICIxMCIgPSBsaXN0KCBuPWMoLTkwLCA1LCA1KSx2YXI9YygicF92YWxfYWRqIiwgInBjdC4xIiwgInBjdC4xIiksIGZpbHRfcGN0Mj0uMTUpCiAgKQoKIyBJZGVudGlmeSB0aGUgdG9wIGdlbmVzIHRoYXQgaGF2ZSBhIGhpZ2ggZGlmZmVyZW5jZSBpbiBleHByZXNzaW9uIGJldHdlZW4gdGhlIGNsdXN0ZXJzCnRvcDIwX3N1YiA8LSBERUdzX3RhYmxlICU+JQogIGZpbHRlcihSZWd1bGF0aW9uID09ICJVUCIpICU+JQogIGZpbHRlcighKGdyZXBsKGVwaV9jbHVzLCAuJGNsdXMpKSkgJT4lCiAgZmlsdGVyKCEoZ3JlcGwoIl4xMSR8XjEyJCIsIC4kY2x1cykpKSAlPiUKICBtdXRhdGUoRGlyZWN0aW9uID0gaWZlbHNlKGF2Z19sb2cyRkMgPiAwLCAiVVAiLCAiRE9XTiIpKSAlPiUKICAKICBuZXN0KC4sIC5ieSA9ICJDbHVzdGVycyIpICU+JQogIGFycmFuZ2UobWF0Y2goQ2x1c3RlcnMsIG5hbWVzKHNlbF9zKSkpICU+JQogIG11dGF0ZShkYXRhID0gcG1hcCguLCB+ZmlsdGVyX3RvcC5mdW4oLi4yLCBuPXNlbF9zW1suLjFdXSRuLCB2YXI9c2VsX3NbWy4uMV1dJHZhciwgZmlsdD1zZWxfc1tbLi4xXV0kZmlsdCApKSkgJT4lCiAgdW5uZXN0KC4sIGNvbHM9YygiZGF0YSIpKQogIAoKY2x1c18yIDwtIERFR3NfdGFibGUgJT4lCiAgZmlsdGVyKFJlZ3VsYXRpb24gPT0gIkRPV04iKSAlPiUKICBmaWx0ZXIoIShncmVwbChlcGlfY2x1cywgLiRjbHVzKSkpICU+JQogIAogICAgZmlsdGVyKFJlZ3VsYXRpb24gPT0gIkRPV04iKSAlPiUKICAgIGZpbHRlcigoZ3JlcGwoIl4yJCIsIC4kY2x1cykpKSAlPiUKICAgICN0b3BfbiguLCBuPS0xMCwgYWJzKHBjdC4yKSkgJT4lCiAgICBmaWx0ZXIoLiwgYmV0d2VlbihwY3QuMiwgMC4zLDAuOCApKSAlPiUKICAgIGZpbHRlciguLCBiZXR3ZWVuKHBjdC4xLCAwLjEsMC4zICkpCiAgICAjICNzbGljZV9taW4ob3JkZXJfYnkgPSBwX3ZhbF9hZGosIG4gPSAyMCkgJT4lCgoKYyggdG9wMjBfc3ViJGdlbmVbMToxNV0sIGNsdXNfMiRnZW5lLCB0b3AyMF9zdWIkZ2VuZVsyMTozNV0pIApjbHVzXzJfZ2VuZXMgPC0gYygiQ0QxNTEiLCAiQzEyb3JmNTciLCAiTlBEQzEiLCAiVEdGQlIyIiwgIlBFQ0FNMSIpCgojIEhvdXNla2VlcGluZyBnZW5lcwojIGNsdXNfMl9nZW5lcyA8LSBjKCJSUEwxNyIsICJUVUJBIiwiRUYxQSIsICJCMk0iLCAiUlBTRCIsICJHQVBESCIpCmBgYAoKYGBge3IgcmlnZGdlLXBsb3QtbWFya2VyLWdlbmVzLCBldmFsPUZBTFNFfQojIHByb2JhYmx5IG5vdCBnb2luZyB0byB1c2UKSWRlbnRzKERBVEEpIDwtICJsYXllcnMiCklkZW50cyhEQVRBKSA8LSAibGF5ZXJzIgpEQVRBICU+JQpmaWx0ZXIoLiwgZ3JlcGwoZXBpX2NsdXMsIERBVEEkQ2x1c3RlcnMpKSAlPiUKICBSaWRnZVBsb3QoLiwgZmVhdHVyZXMgPSB0b3AyMF9lcGkkZ2VuZVsxOjJdLCBuY29sID0gMikKCiMgZXBpdGhlbGl1bQpnZW5lcyA8LSB0b3AyMF9lcGkkZ2VuZQpjb2wgPC0gYygiI0U0MUExQyIsIiNGRjdGMDAiLCIjQzc3Q0ZGIiwiIzk4NEVBMyIpCiMgU3VibXVjb3NhCmdlbmVzIDwtIGMoIHRvcDIwX3N1YiRnZW5lWzE6MTBdLGNsdXNfMl9nZW5lcyAsIHRvcDIwX3N1YiRnZW5lWzIxOjM1XSkgCmNvbCA8LSBjKCIjMDBBOUZGIiwiIzM3N0VCOCIsIiNDRDk2MDAiLCIjN0NBRTAwIiwiI2UwZTA2NyIsIiNGRjYxQ0MiLCIjRkY5REE3IikKCmRmIDwtIERBVEEgJT4lCiAgZmlsdGVyKC4sIGdyZXBsKGVwaV9jbHVzLCBEQVRBJENsdXN0ZXJzKSkgJT4lIAogICNmaWx0ZXIoLiwgIShncmVwbCgiXjUkfF42JHxeN3xeOHxeMTEkfF4xMiQiLCBEQVRBJENsdXN0ZXJzKSkpICU+JSAKICBtdXRhdGUoLiwgRmV0Y2hEYXRhKC4sIHZhcnMgPSBnZW5lcykpICU+JQogIGFzX3RpYmJsZSgpICU+JQogIHNlbGVjdCguY2VsbCwgc3BfYW5ub3QsIG9yaWcuaWRlbnQsIGdyb3VwcywgbGF5ZXJzLCBhbnlfb2YoZ2VuZXMpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGFueV9vZihnZW5lcyksIG5hbWVzX3RvID0gIkdlbmVzIiwgdmFsdWVzX3RvID0gIkV4cHJlc3Npb24iKSAlPiUKICBtdXRhdGUoR2VuZXMgPSBmYWN0b3IoLiRHZW5lcywgbGV2ZWxzPXJldihnZW5lcykpKSAlPiUKICBhcnJhbmdlKGxheWVycykgJT4lCiAgbmVzdChkYXRhPSAtbGF5ZXJzKSAlPiUKICBtdXRhdGUoY29sID0gY29sKQoKCnAgPC0gZGYgJT4lCiAgbXV0YXRlKHBsb3QgPSBwbWFwKC4sIAogICAgICAgIH5nZ3Bsb3QoLi4yLCBhZXMoeCA9IEV4cHJlc3Npb24sIHkgPSBHZW5lcywgZmlsbCA9IC4uMykpICsKICAgICAgICAgICAgICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoKSArCiAgICAgICAgICAgICAgICBzY2FsZV9maWxsX2lkZW50aXR5KCkgKwogICAgICAgICAgICAgICAgeGxpbShjKDAsNCkpICsKICAgICAgICAgICAgICAgIHRoZW1lX3JpZGdlcygpICsgbGFicyh0aXRsZSA9IC4uMSApICArCiAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLC0wLDAsMCksdW5pdHMgPSAicHQiKSwKICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKICApKQoKKHBfIDwtIHBsb3RfZ3JpZChwbG90bGlzdCA9IHAkcGxvdCwgbmNvbD1sZW5ndGgoY29sKSkgKQpnZ3NhdmUoIi4vRmlndXJlcy9NYXJrZXJfZ2VuZXNfcmlkZ2VzX2VwaS5wZGYiLCBwXywgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNSkKZ2dzYXZlKCIuL0ZpZ3VyZXMvTWFya2VyX2dlbmVzX3JpZGdlc19zdWIucGRmIiwgcF8sIHdpZHRoID0gMjEsIGhlaWdodCA9IDcpCmBgYAoKCmBgYHtyIG1hcmtlci1nZW5lLWhlYXRtYXAtZnVuY3Rpb259CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCgojIyMjIEdFTkVTIFRIQVQgQVJFIFVOSVFFTFkgT1ZFUkxBUElORyAjIyMjCmdldFZlbm5PdmVybGFwIDwtIGZ1bmN0aW9uKGxzdmVubikgewogIAogIEl0ZW1zTGlzdCA8LSBncGxvdHM6OnZlbm4obHN2ZW5uLCBzaG93LnBsb3QgPSBGQUxTRSkKICBwcmludChsZW5ndGhzKGF0dHJpYnV0ZXMoSXRlbXNMaXN0KSRpbnRlcnNlY3Rpb25zKSkKICByZXR1cm4oYXR0cmlidXRlcyhJdGVtc0xpc3QpJGludGVyc2VjdGlvbnMpCn0KCiMjIyMjIyMjIyMjIyMjIyMKIyBQTE9UIEhFQVRNQVAgIwojIyMjIyMjIyMjIyMjIyMjCmhlYXRtYXAuZnVuIDwtIGZ1bmN0aW9uKGdlbmVzLCBjbHVzdGVyKXsKIyMjIyMjIyMjIyMjIyMjCiMgR0VUIE1BVFJJWCAjCiMjIyMjIyMjIyMjIyMjIwpEQVQgPC0gZmlsdGVyKERBVEEsIGdyZXBsKHBhc3RlMCgiXiIsY2x1c3RlciwiJCIsY29sbGFwc2U9InwiKSwgREFUQSRsYXllcnMpKQpWYXJpYWJsZUZlYXR1cmVzKERBVCkgPC0gZ2VuZXMKREFUIDwtIFNldXJhdDo6U2NhbGVEYXRhKERBVCkKbWF0eCA8LSBEQVRAYXNzYXlzJFJOQSRzY2FsZS5kYXRhICU+JSAKICBhcy5tYXRyaXgoKQogIAogIAojIyMjIyMjIyMjIyMjIwojIEFOTk9UQVRJT04gIwojIyMjIyMjIyMjIyMjIwphbm5vdF9jb2wgPDwtIERBVEBtZXRhLmRhdGEgJT4lCiAgI211dGF0ZShsYXllcnMgPSBmYWN0b3IoLiRsYXllcnMsIGxldmVscyA9IGNsdXN0ZXIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KDE6NykgCgojIHNldCByb3cgb3JkZXIKbWF0eCA8LSBtYXR4W2dlbmVzLF0KI3ByaW50KCBkcHV0KHJvd25hbWVzKG1hdHgpKSkKI2NvbF9vcmRlciA8PC0gcm93bmFtZXMoYXJyYW5nZShhbm5vdF9jb2wsIGxheWVycykgKQoKY2x1c19jb2xzIDwtIGMoIiNFNDFBMUMiLCIjRkY3RjAwIiwiI0M3N0NGRiIsIiM5ODRFQTMiLAogICAgICAgICAgICAgICAiIzAwQTlGRiIsIiMzNzdFQjgiLCIjQ0Q5NjAwIiwiIzdDQUUwMCIsIiNlMGUwNjciLCIjRkY2MUNDIiwiI0ZGOURBNyIsIiNCQUIwQUMiLCIjQTY1NjI4IikKY2x1cyA8LSBjKCJTdXBlcmZpY2lhbCIsIlVwcGVyIElNIiwiTG93ZXIgSU0iLCJCYXNhbCIsIjEiLCI0IiwiMCIsIjMiLCIyIiwiOSIsIjEwIiwiMTEiLCIxMiIpICMKY2x1c19jb2xzIDwtIHNldF9uYW1lcyhjbHVzX2NvbHMsIGNsdXMpCmNsdXNfY29scyA8LSBjbHVzX2NvbHNbdW5pcXVlKGFubm90X2NvbCRsYXllcnMpXQoKSURfY29scyA8LSBjKCIjNEU3OUE3IiwiI0YyOEUyQiIsIiNFMTU3NTkiLCIjNzZCN0IyIiwiIzU5QTE0RiIsIiNFREM5NDgiLCIjOUM3NTVGIiwiI0IwN0FBMSIsIiNGRjlEQTciLAogICAgICAgICAgICAgIiNFNzhBQzMiLCIjN0ZDOTdGIiwiI0JFQUVENCIsIiNCQUIwQUMiLCIjRkRDMDg2IiwiI0ZGRkY5OSIsIiMzODZDQjAiLCIjRjAwMjdGIiwiI0JGNUIxNyIsCiAgICAgICAgICAgICAiIzY2QzJBNSIsIiNGQzhENjIiLCIjOERBMENCIikKSURfY29scyA8LSBzZXRfbmFtZXMoSURfY29scywgc2FtcGxlX2lkKQpJRF9jb2xzIDwtIElEX2NvbHNbdW5pcXVlKGFubm90X2NvbCRvcmlnLmlkZW50KV0KCmdyb3VwX2NvbHMgPC0gYygiIzU2QjRFOSIsIiMwMDlFNzMiLCIjQ0M3OUE3IiwiI0ZDOEQ2MiIpCmdyIDwtIGMoJ0wxJywgJ0wyJywgJ0wzJywgJ0w0JykgJT4lIHNldF9uYW1lcygpCmdyb3VwX2NvbHMgPC0gc2V0X25hbWVzKGdyb3VwX2NvbHMsIGdyKQpncm91cF9jb2xzIDwtIGdyb3VwX2NvbHNbdW5pcXVlKGFubm90X2NvbCRncm91cHMpXQoKIyMjIyMjIyMjIyMjIyMjIwojIERSQVcgSEVBVE1BUCAjCiMjIyMjIyMjIyMjIyMjIyMKCiMgcXdhcnRpbGUgCnEgPC0gcXVhbnRpbGUobWF0eCwgYygwLjA1LCAwLjk1KSkKYyhtaW4obWF0eCksIG1heChtYXR4KSkKCiMgYXZlcmFnZSBleHByZXNzaW9uOgpzZXQuc2VlZCgxMjMpCkggPC0gSGVhdG1hcChtYXR4LCBuYW1lID0gIiAiLAogICAgICAgICAgICAgY29sID0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYyhxWzFdKjIsIHFbMV0sIDAsIHFbMl0sIHFbMl0qMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiIzQ0MDE1NEZGIiwiIzZBNTFBMyIsIiMyMTkwOENGRiIsIiNGREU3MjVGRiIsIiNGRjdGMDAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3JldihjKCIjRDcxOTFDIiwiI0ZEQUU2MSIsICJ3aGl0ZSIsIiNBQkQ5RTkiLCIjNDU3NUI0IikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgI3Jvd19rbSA9IDYsICNjb2x1bW5fa20gPSAyLCAjIGttZWFucyBjaGFuZ2UgZXZlcnkgdGltZSB5b3UgcnVuIGl0CiAgICAgICAgICAgICBjb2x1bW5fc3BsaXQgPSAgZmFjdG9yKGFzLmNoYXJhY3Rlcihhbm5vdF9jb2wkbGF5ZXJzKSwgbGV2ZWxzID0gY2x1c3RlciksCiAgICAgICAgICAgICAjcm93X3NwbGl0ID0gMTAsICAjIGhpZXJhcmNoaWNhbCBzdGF0aWMKICAgICAgICAgICAgIHJvd19vcmRlciA9IHJvd25hbWVzKG1hdHgpLAogICAgICAgICAgICAgY29sdW1uX29yZGVyID0gcm93bmFtZXMoYXJyYW5nZShhbm5vdF9jb2wsIGxheWVycykgKSwKICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAjY2x1c3Rlcl9jb2x1bW5zID0gVCwKICAgICAgICAgICAgIHVzZV9yYXN0ZXIgPSBGLCAjIHJlbW92ZXMgd2hpdGUgdmVydGljYWwgbGluZXMgaW4gdGhlIGhlYXRtYXAKICAgICAgICAgICAgIAogICAgICAgICAgICAgIyB0ZXh0CiAgICAgICAgICAgICByb3dfdGl0bGUgPSBndF9yZW5kZXIoIiIsIHBhZGRpbmcgPSB1bml0KGMoMCwgMCwgMCwgMCksICJwdCIpKSwKICAgICAgICAgICAgIAogICAgICAgICAgICAgI2NvbHVtbl9sYWJlbHMgPSBndF9yZW5kZXIoY29sdW1uX2xhYmVscywgcGFkZGluZyA9IHVuaXQoYygwLCAwLCAwLCAwKSwgInB0IikpLAogICAgICAgICAgICAgY29sdW1uX3RpdGxlX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDgpLAogICAgICAgICAgICAgI2NvbHVtbl9sYWJlbHNfZ3AgPSAgZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDgpLAogICAgICAgICAgICAgCiAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gOCksCiAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gOCksCiAgICAgICAgICAgIAogICAgICAgICAgICAgCiAgICAgICAgICAgICAjIGFubm90YXRpb24KICAgICAgICAgICAgICMgcmlnaHRfYW5ub3RhdGlvbiA9IHJpZ2h0X2Fubm9fcm93LCBsZWZ0X2Fubm90YXRpb24gPSBsZWZ0X2Fubm9fcm93LAogICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPQogICAgICAgICAgICAgICBjb2x1bW5Bbm5vdGF0aW9uKENsdXN0ZXI9YW5ub3RfY29sJGxheWVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjc2hvd19sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2Fubm90YXRpb25fbmFtZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfcGFyYW0gPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChncmlkX2hlaWdodCA9IHVuaXQoLjIsICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgyLCAibW0iKSwgdGl0bGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA4KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcGxlX2Fubm9fc2l6ZSA9IHVuaXQoLjEsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNnYXAgPSB1bml0KDEsICJjbSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1saXN0KCBDbHVzdGVyID0gY2x1c19jb2xzICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAoKICAgICAgICAgICAgICMgbGVnZW5kCiAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QobGVnZW5kX2hlaWdodCA9IHVuaXQoMjAsICJtbSIpLCBncmlkX3dpZHRoID0gdW5pdCgyLCAibW0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDcpKQogICAgICAgICAgICAgI2Fubm90YXRpb25fbGVnZW5kX3BhcmFtID0gbGlzdChzaXplID0gdW5pdCgyLCAibW0iKSkKCiAgICAgICAgICAgICApICNjb2xvclJhbXBQYWxldHRlKGMoY29sKSkoMTApIAoKSCA8LSBkcmF3KEgsIG1lcmdlX2xlZ2VuZCA9IFRSVUUpCnJldHVybihIKQp9CmBgYAoKYGBge3IgZXBpX21hcmtlci1nZW5lLWhlYXRtYXAsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9CiMgSGVhdG1hcCBnbG9iYWwgb3B0aW9uczoKaHRfb3B0JENPTFVNTl9BTk5PX1BBRERJTkcgPSB1bml0KC4wNSwgImNtIikKaHRfb3B0JEhFQVRNQVBfTEVHRU5EX1BBRERJTkcgPSB1bml0KDAsICJjbSIpCmh0X29wdCRUSVRMRV9QQURESU5HID0gdW5pdCguMDUsICJjbSIpCmh0X29wdCRESU1OQU1FX1BBRERJTkcgPSB1bml0KC4wNSwgImNtIikKCmx2bF9sYXllcnMgPC0gYygiU3VwZXJmaWNpYWwiLCAiVXBwZXIgSU0iLCAiTG93ZXIgSU0iLCAiQmFzYWwiLCIxIiwiNCIsIjAiLCIzIiwiMiIsIjkiLCIxMCIsIjExIiwiMTIiKQoKIyBhbGwgY2x1c3RlcnMgdG9nZXRoZXI6IAojIGdlbmVzIDwtIGModG9wMjBfZXBpJGdlbmUsIHRvcDIwX3N1YiRnZW5lKQojIEggPC0gaGVhdG1hcC5mdW4oZ2VuZXMgPSBnZW5lcywgbHZsX2xheWVycykKCiMjIyMjIyMjIyMjIyMjCiMgRVBJVEhFTElVTSAjCiMjIyMjIyMjIyMjIyMjCmdlbmVzIDwtIHRvcDIwX2VwaSRnZW5lCkhfZXBpIDwtIGhlYXRtYXAuZnVuKGdlbmVzID0gZ2VuZXMsIGx2bF9sYXllcnNbMTo0XSkKCiMgc2F2ZSBmaWxlCkhfZ3JvYiA8LSBncmlkLmdyYWJFeHByKGRyYXcoSF9lcGksIG1lcmdlX2xlZ2VuZCA9IFRSVUUpKSAgIyBzaG93X2hlYXRtYXBfbGVnZW5kID0gRkFMU0UsCmdnc2F2ZSgiLi9GaWd1cmVzLzAxL2hlYXRtYXBfY2x1c3RlcnNfZXBpLnBuZyIsIEhfZ3JvYiwgd2lkdGggPSA2LCBoZWlnaHQgPSAzLCBsaW1pdHNpemUgPSBGKQoKYGBgCgpgYGB7ciBTdWJNdWNfbWFya2VyLWdlbmUtaGVhdG1hcCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KIyMjIyMjIyMjIyMjIwojIFNVQk1VQ09TQSAjCiMjIyMjIyMjIyMjIyMKZ2VuZXMgPC0gYyggdG9wMjBfc3ViJGdlbmVbMToxMF0sIGNsdXNfMl9nZW5lcywgdG9wMjBfc3ViJGdlbmVbMjE6MzVdKSAKSF9zdWIgPC0gaGVhdG1hcC5mdW4oZ2VuZXMgPSBnZW5lcywgbHZsX2xheWVyc1s1OjExXSkKCiMgc2F2ZSBmaWxlCkhfZ3JvYiA8LSBncmlkLmdyYWJFeHByKGRyYXcoSF9zdWIsIG1lcmdlX2xlZ2VuZCA9IFRSVUUpKSAgIyBzaG93X2hlYXRtYXBfbGVnZW5kID0gRkFMU0UsCmdnc2F2ZSgiLi9GaWd1cmVzLzAxL2hlYXRtYXBfY2x1c3RlcnNfc3ViLnBuZyIsIEhfZ3JvYiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBsaW1pdHNpemUgPSBGKQojIE5CISB3aGVuIHdvcmtpbmcgd2l0aCB0aGUgaGVhdG1hcCwgbWFrZSBzdXJlIG91dHB1dCBpcyBwcmludGVkIHRvIHRoZSBjb25zb2xlCmBgYAoKYGBge3IgY29tYmluZS1wbG90cywgZmlnLndpZHRoPTMuNSwgZmlnLmhlaWdodD03LjQ4LCBldmFsPUZBTFNFfQoKYGBgCgpgYGB7ciBNYXJrZXItZ2VuZXN9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgREVGSU5FIE1BUktFUiBHRU5FUyAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCkNlbGxfbWFya2VyIDwtIGMoIk1TNEExIiwiQ0Q3OUEiLCAiUE9VMkFGMSIsICJNWkIxIiwgIkZDUkw1IiwgIkNEMzgiLAogICAgICAgICAgICAgICAgICJDRDI0NyIsIkNEOEEiLCJDRDNEIiwiQ0QzRyIsIkNENCIsIkNYQ1I0IiwgIAogICAgICAgICAgICAgICAgICJOQ0FNMSIsICJHWk1BIiwgIkdOTFkiLCAgIkZDRVIxQSIsICJDRDFBIiwgIkxUQiIsICAKICAgICAgICAgICAgICAgICAiQ09MM0ExIiwiQ09MMUExIiwgIkFQT0QiLCJMQU1BMiIsICJNWUgxMSIsIklDQU0yIiwiUEVDQU0xIiwiTUNBTSIsICAgIyBGTFQxICMiQ09MM0ExIiwiQ09MMUExIiwgIk1ZSDExIiwiTEFNQTIiCiAgICAgICAgICAgICAgICAgIkFURzlCIiwgIktQUlAiLCJBTE9YMTIiLCAiUFJTUzMiLCAiQklDREwyIiwgIk1UMVgiKQpuYW1lcyA8LSBjKCJCIGNlbGwiLCAiQiBjZWxsIiwiQiBjZWxsIiwgIlBsYXNtYSBjZWxsIiwiUGxhc21hIGNlbGwiLCAiUGxhc21hIGNlbGwiLCAKICAgICAgICAgICAiVCBjZWxsIiwgIlQgY2VsbCIsIlQgY2VsbCIsICJUIGNlbGwiLCAiVCBjZWxsIiwgIlQgY2VsbCIsIAogICAgICAgICAgICJOSyBjZWxscyIsICJOSyBjZWxscyIsICJOSyBjZWxscyIsIk15ZWxvaWQiLCAiTXllbG9pZCIsICJNeWVsb2lkIiwgCiAgICAgICAgICAgIkZpYnJvYmxhc3QiLCAiRmlicm9ibGFzdCIsICJGaWJyb2JsYXN0IiwiRmlicm9ibGFzdCIsIAogICAgICAgICAgICJFbmRvdGhlbGlhbCIsIkVuZG90aGVsaWFsIiwgIkVuZG90aGVsaWFsIiwgIkVuZG90aGVsaWFsIiwgIktlcmF0aW5vY3l0ZSBzdXByYSIsICJLZXJhdGlub2N5dGUgc3VwcmEiLCAKICAgICAgICAgICAiS2VyYXRpbm9jeXRlIHN1cHJhIiwiS2VyYXRpbm9jeXRlIHN1cHJhIiwgIktlcmF0aW5vY3l0ZSBiYXNhbCIsICJLZXJhdGlub2N5dGUgYmFzYWwiKQpjZWxsX3R5cGUgPC0gc2V0X25hbWVzKG5hbWVzLCBDZWxsX21hcmtlcikKY2x1c19sdmwgPC0gcmV2KGMoIjUiLCAiNiIsICI3IiwgIjgiLCAiMSIsIjQiLCIwIiwiMyIsIjIiLCI5IiwiMTAiLCIxMSIsIjEyIikpIAoKY2x1c19sdmwgPC0gc2V0X25hbWVzKHNlcV9hbG9uZyhjbHVzX2x2bCksIGNsdXNfbHZsKQpnZW5lX2x2bCA8LSBzZXRfbmFtZXMoc2VxX2Fsb25nKENlbGxfbWFya2VyKSwgQ2VsbF9tYXJrZXIpCmBgYAoKYGBge3IgMDJhX21hcmtlci1nZW5lLWRvdHBsb3QsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9CiMjIyMjIyMjIyMjIyMjIyMKIyBGRVRDSCBHRU5FUyAjCiMjIyMjIyMjIyMjIyMjIyMKY2VsbF90eXBlIDwtIHNldF9uYW1lcyhuYW1lcywgQ2VsbF9tYXJrZXIpCmRmIDwtIERBVEEgJT4lCiAgbXV0YXRlKC4sIEZldGNoRGF0YSguLCB2YXJzID0gYyhDZWxsX21hcmtlcikpICkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgc2VsZWN0KC4sIC5jZWxsLCBDbHVzdGVycywgYW55X29mKENlbGxfbWFya2VyKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKC4sIGNvbHMgPSAtYygiLmNlbGwiLCAiQ2x1c3RlcnMiKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIm1hcmtlciIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAlPiUKICBtdXRhdGUoLiwgY2VsbCA9IGNlbGxfdHlwZVthcy5jaGFyYWN0ZXIoLiRtYXJrZXIpXSkgJT4lCiAgbXV0YXRlKCBtYXJrZXJfaWQgPSBwYXN0ZTAoLiRjZWxsLCIgKCIsLiRtYXJrZXIsIikiKSkgJT4lCiAgI2ZpbHRlciguLCBDbHVzdGVycyAhPSAiMTEifCBDbHVzdGVycyAhPSAiMTIiKSAlPiUKICBtdXRhdGUoQ2x1c3RlcnMgPSBmYWN0b3IoLiRDbHVzdGVycywgbGV2ZWxzPW5hbWVzKGNsdXNfbHZsKSkpICU+JQogIG11dGF0ZShtYXJrZXIgPSBmYWN0b3IoLiRtYXJrZXIsIGxldmVscz1DZWxsX21hcmtlcikpICU+JQogIGdyb3VwX2J5KENsdXN0ZXJzLCBtYXJrZXIsIGNlbGwpICU+JQogIHN1bW1hcmlzZShBdmcgPSBtZWFuKHZhbHVlcyksCiAgICAgICAgICAgIFBjdCA9IHN1bSh2YWx1ZXMgPiAwKSAvIGxlbmd0aCh2YWx1ZXMpICogMTAwLCAuZ3JvdXBzPSJkcm9wIikgJT4lCiAgbXV0YXRlKC4sIHltaW4gPSBjbHVzX2x2bFthcy5jaGFyYWN0ZXIoLiRDbHVzdGVycyldLTAuNSwKICAgICAgICAgICAgeW1heCA9IGNsdXNfbHZsW2FzLmNoYXJhY3RlciguJENsdXN0ZXJzKV0rMC41KSAlPiUKICBtdXRhdGUoLiwgeG1pbiA9IGdlbmVfbHZsW2FzLmNoYXJhY3RlciguJG1hcmtlcildLTAuNSwKICAgICAgICAgICAgeG1heCA9IGdlbmVfbHZsW2FzLmNoYXJhY3RlciguJG1hcmtlcildKzAuNSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIE1BUktFUiBHRU5FUyBET1RQTE9UICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmxpYnJhcnkoZ2duZXdzY2FsZSkKY2VsbF9jb2wgPC0gYygiI0ZGRDkyRiIsIiNGRkZGQ0MiLCIjOERBMENCIiwiI2ViNjA2MiIsIiNBNkQ4NTQiLCIjRTc4QUMzIiwiIzY2QzJBNSIsIiNGQzhENjIiLCIjRkVEOUE2IiwKICAgICAgICAgIiMzNzdFQjgiLCIjNERBRjRBIiwiI0IzQjNCMyIsIiM5ODRFQTMiLCIjRkY3RjAwIiwiI0ZGRkYzMyIsIiNBNjU2MjgiLCIjRjc4MUJGIikKCmNsdXNfY29sIDwtIHJldihjKCIjRkJBQUIxIiwiI0ZGREFCOCIsIiNGMUQyRkYiLCIjRTZCM0U5IiwiIzkyREJGRiIsIiNBQkM5RTEiLCAiI0U1QzI2NCIsIiNCQkQ5OUIiLCAiI0UxRTJBNCIsICIjRkY2MUNDIiwiI0ZBOURBNyIsICIjQjNCM0IzIiwgIiNBNjU2MjgiKSkKbGFiIDwtIGMoIkIgY2VsbCIsICJQbGFzbWEgY2VsbCIsICJUIGNlbGwiLCAiTksgY2VsbHMiLCAiTXllbG9pZCIsICJGaWJyb2JsYXN0IiwgCiJFbmRvdGhlbGlhbCIsICJLZXJhdGlub2N5dGVzIikKCnltIDwtIG1heChkZiR5bWF4KQp4bSA8LSBsZW5ndGgoY2VsbF90eXBlKSszLjUKCmNsdXNfbHZsIDwtIHJldihjKCI1IiwiNiIsIjciLCI4IiwiMSIsIjQiLCIwIiwiMyIsIjIiLCI5IiwiMTAiLCIxMSIsIjEyIikpCiMgREFUQSAlPiUKIyAgIG11dGF0ZShDbHVzdGVycyA9IGZhY3RvciguJENsdXN0ZXJzLCBsZXZlbHMgPSBjbHVzX2x2bCkpICU+JQojIGdncGxvdCguLCBhZXMoeD1DbHVzdGVycywgeT1uQ291bnRfUk5BLCBmaWxsPUNsdXN0ZXJzKSkgKyBnZW9tX3Zpb2xpbigpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2x1c19jb2wpCgooQSA8LSBnZ3Bsb3QoZGYsIGFlcyh4PW1hcmtlciwgeT1DbHVzdGVycykpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gUGN0LCBmaWxsID0gQXZnKSwgY29sb3I9IndoaXRlIiwgc2hhcGU9MjEpICsKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gdmlyaWRpc0xpdGU6Om1hZ21hKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcih0aWNrcy5jb2xvdXIgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJhbWUuY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gLjUsIGJhcmhlaWdodCA9IDQpLAogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQXZlcmFnZVxuZXhwcmVzc2lvbiIpICsKICAjZmFjZXRfZ3JpZCh+IGNlbGwsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgIyBDZWxsIHR5cGUgY29sb3VyIGJhcgogIG5ld19zY2FsZV9maWxsKCkgKwogIGdlb21fcmVjdChhZXMoeW1pbj1tYXgoeW1heCksIHltYXg9bWF4KHltYXgpKy40LAogICAgICAgICAgICAgICAgeG1pbj14bWluLCB4bWF4PXhtYXgsCiAgICAgICAgICAgICAgICBmaWxsID0gY2VsbCksZGF0YT1kZixhbHBoYSA9IDAuMSxzaG93LmxlZ2VuZD1GKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gYygxLjgsIDUsIDEwLCAxNCwgMTcsIDIwLjUsIDI0LjYsIDI5LjUgKSwgeSA9IDEzLjcsIGxhYmVsID0gbGFiKSArCiAgZ2VvbV9yZWN0KGFlcyh5bWluPW1pbih5bWluKSwgeW1heD1taW4oeW1pbikrLjMsCiAgICAgICAgICAgICAgICB4bWluPXhtaW4sIHhtYXg9eG1heCwKICAgICAgICAgICAgICAgIGZpbGwgPSBjZWxsKSxkYXRhPWRmLGFscGhhID0gMC4xLHNob3cubGVnZW5kPUYpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBzZXRfbmFtZXMoY2VsbF9jb2xbMTpsZW5ndGgodW5pcXVlKGNlbGxfdHlwZSkpXSwgdW5pcXVlKGNlbGxfdHlwZSkpKSArCiAgICAKICAjIGFkZCBleHRyYSBib3JkZXJzIGZvciB0aGUgY29sb3VyIGJhcnMKICAjIGFubm90YXRlKHggPSBjKC41LHhtLC0uNSwtLjUsLjUsLS41KSwgeGVuZD1jKC41LHhtLHhtLHhtLHhtLC0uNSksCiAgIyAgICAgICAgICAgIHk9YygxLDEsLjUseW0seW0rLjUsLjUpLCB5ZW5kPWMoeW0rLjUseW0rLjUsLjUseW0seW0rLjUseW0pLAogICMgICAgICAgICAgICBnZW9tPSJzZWdtZW50Iixjb2xvdXIgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAuNiwgYWxwaGEgPSAxKSArCiAgIyBDbHVzdGVyIGJhciBhbm5ub3RhdGlvbgogIG5ld19zY2FsZV9maWxsKCkgKwogIGdlb21fcmVjdChhZXMoeW1pbj15bWluLCB5bWF4PXltYXgsCiAgICAgICAgICAgICAgICB4bWluPTAuNCwgeG1heD0tLjUsCiAgICAgICAgICAgICAgICBmaWxsID0gQ2x1c3RlcnMpLGRhdGE9ZGYsYWxwaGEgPSAxLHNob3cubGVnZW5kPUYpICsgIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNsdXNfY29sKSArCiAgY29vcmRfY2FydGVzaWFuKGNsaXA9Im9mZiIsIHhsaW09YyguNSx4bSkseWxpbT1jKC41LHltKSxleHBhbmQgPSBGKSArCiAgc2NhbGVfc2l6ZSgiJSBkZXRlY3RlZCIsIHJhbmdlID0gYygwLDYpKSArCgogIHlsYWIoIkNsdXN0ZXIiKSArIHhsYWIoIiIpICsKICB0aGVtZV9idygpICsKICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGNvbG9yID0gImJsYWNrIiksIGtleXdpZHRoID0gLjYsIGtleWhlaWdodCA9IC42KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9OCwgYW5nbGU9NDUsIGhqdXN0PTEsIGNvbG9yPSJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9OSwgY29sb3I9ImJsYWNrIixoanVzdD0uOSApLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05KSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLm1hcmdpbj1tYXJnaW4oMCwwLC0wLDApLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMCwtLjQsLjEpLHVuaXRzID0gImNtIikgI3RyYmwKICAgICAgICApIAopCiMgZGV2Lm5ldyh3aWR0aD04LCBoZWlnaHQ9My41LCBub1JTdHVkaW9HRCA9IFRSVUUpCiMgZ2dzYXZlKCIuL0ZpZ3VyZXMvMDEvbWFya2VyLWdlbmUtZG90cGxvdF9uZXcucGRmIiwgQSwgd2lkdGggPSA4LCBoZWlnaHQgPSAzLjUpICMgY2VsbF9tYXJrZXIKYGBgCgoKIyMgTm90IHVzZWQhCgpgYGB7ciBwc2V1ZG8tYnVsaywgZXZhbD1GQUxTRX0KbGlicmFyeShlZGdlUikKcHNldWRvLmJ1bGsgPC0gZnVuY3Rpb24oREFUQSwgZ3JvdXBfdmFyLCBkZWdzPUZBTFNFKXsKICAjIGNyZWF0ZSBJRCBwZXIgY2x1c3RlciBncm91cAogIERBVEEgPC0gbXV0YXRlKERBVEEsIElEX2NsdXMgPSBwYXN0ZTAoREFUQSRvcmlnLmlkZW50LCAiXyIsIERBVEFbW2dyb3VwX3Zhcl1dKSkKICAKICAjIGdldCB0aGUgY291bnQgbWF0cml4IGZvciBhbGwgY2VsbHMKICBzcGFyc2VfbXRyeCA8LSBEQVRBQGFzc2F5cyRSTkFAY291bnRzCiAgCiAgIyBDb21wdXRlIHBzZXVkb2J1bGsKICBtbSA8LSBNYXRyaXg6OnNwYXJzZS5tb2RlbC5tYXRyaXgofjAgKyBEQVRBJElEX2NsdXMpCiAgcHNldWRvYnVsayA8LSBzcGFyc2VfbXRyeCAlKiUgbW0KICBjb2xuYW1lcyhwc2V1ZG9idWxrKSA8LSBzdHJfcmVwbGFjZShjb2xuYW1lcyhwc2V1ZG9idWxrKSwgIkRBVEFcXCRJRF9jbHVzIiwgIiIpCiAgCiAgIyBncm91cAogIGdyIDwtIHN0cl9yZXBsYWNlKGNvbG5hbWVzKHBzZXVkb2J1bGspLCAiUFxcZFxcZFxcZF8iLCAiIikKICBnciA8LSBzZXRfbmFtZXMoZ3IsIGNvbG5hbWVzKHBzZXVkb2J1bGspKQogIAogIGlmKGxlbmd0aChkZWdzKSA+IDEpewogICAgIyBmaWx0ZXIgZ2VuZXMgYmFzZWQgb24gREVHIGFuYWx5c2lzCiAgICBtYXR4IDwtIGFzLm1hdHJpeChwc2V1ZG9idWxrKQogICAgbWF0eCA8LSBtYXR4W2RlZ3MsXQogIH1lbHNlewogICAgIyBmaWx0ZXIgZ2VuZXMgYmFzZWQgb24gZ3JvdXBzCiAgZGdlLmxpc3QgPC0gREdFTGlzdChjb3VudHMgPSBwc2V1ZG9idWxrLCBncm91cCA9IGZhY3RvcihncikpCiAga2VlcCA8LSBmaWx0ZXJCeUV4cHIoZGdlLmxpc3QpCiAgbWF0eCA8LSBkZ2UubGlzdFtrZWVwLCAsIGtlZXAubGliLnNpemVzID0gRkFMU0VdfQogIAogIHJldHVybihtYXR4KQp9CgojIHJlbW92ZSBzcGVjaWZpZWQgZ2VuZXM6CnJlbW92ZV9nZW5lcyA8LSBmdW5jdGlvbih4LCBnZW5lX25hbWUpIHhbIShncmVwbChnZW5lX25hbWUsIHJvd25hbWVzKHhbWyJSTkEiXV0pKSksIF0KCgpgYGAKCmBgYHtyIFVNQVAsIGV2YWw9RkFMU0V9CnNhbXBsZV9pZCA8LSBjKCJQMDIwIiwiUDA0NSIsIlAwNTAiLCJQMDU3IiwKICAgICAgICAgICAgICAgIlAwMDgiLCJQMDI2IiwiUDAzMSIsIlAwNDQiLCJQMDgwIiwiUDEwNSIsIAogICAgICAgICAgICAgICAiUDAwMSIsIlAwMDQiLCJQMDE0IiwiUDAxOCIsIlAwODciLCJQMTA4IiwiUDExOCIsCiAgICAgICAgICAgICAgICJQMDIxIiwiUDAyNCIsIlAwNjciLCJQMDgxIiwiUDExNyIpCmdyb3VwcyA8LSBjKCAiTDEiLCJMMSIsIkwxIiwiTDEiLAogICAgICAgICAgICAgIkwyIiwiTDIiLCJMMiIsIkwyIiwiTDIiLCJMMiIsCiAgICAgICAgICAgICAiTDMiLCJMMyIsIkwzIiwiTDMiLCJMMyIsIkwzIiwiTDMiLAogICAgICAgICAgICAgIkw0IiwiTDQiLCJMNCIsIkw0IiwiTDQiKQppZF9nciA8LSBzZXRfbmFtZXMoZ3JvdXBzLCBzYW1wbGVfaWQpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBHRVQgREVHUyAgIyAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpwc2V1ZG9fREVHcyA8LSByZWFkUkRTKHBhc3RlMCgiLi4vcmVzdWx0cy8wNl9ER0VfY29uZGl0aW9uX3N0X2RhdGEvIiwiUHNldWRvYnVsa19hY3Jvc3NfREVHcy5SRFMiKSkKcHNldWRvX0RFR3MgPC0gcHNldWRvX0RFR3MgJT4lCiAgI2ZpbHRlcihsYXllcnMgIT0gIjExIiB8IGxheWVycyAhPSAiMTIiICkgJT4lIHVubmVzdCgpICU+JQogIG11dGF0ZSh0ZXN0ID0gbWFwKHRlc3QsIH5maWx0ZXIoLngsIFBWYWx1ZSA8PSAwLjAwMSkgKSkgJT4lCiAgdW5uZXN0KHRlc3QpICU+JSAuJHN5bWJvbCAlPiUgdW5pcXVlKCkKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIE5PUk1BTElaRSBUUlggREFUQSAjIAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm1hdHggPC0gcHNldWRvLmJ1bGsoREFUQSwgImxheWVycyIsIGRlZ3MgPSBwc2V1ZG9fREVHcykKbWF0eCA8LSBwc2V1ZG8uYnVsayhEQVRBLCAib3JpZy5pZGVudCIpCiMjIyMgQ1BNLWxvZzIgIyMjIwojIGNvdW50cyBwZXIgbWlsbGlvbiAoQ1BNKSBsb2cyIHRyYW5zZm9tZWQgY291bnRzOgptYXRyaXhfdHJhbnMgPC0gY3BtKCBtYXR4LCBsb2c9VCkKCiMjIyMjIyMjCiMgVU1BUCAjIAojIyMjIyMjIwpsdmxfbGF5ZXJzIDwtIGMoIlN1cGVyZmljaWFsIiwiVXBwZXIgSU0iLCJMb3dlciBJTSIsIkJhc2FsIiwiMyIsIjQiLCIwIiwiMiIsIjEiLCI5IiwiMTAiLCIxMSIsIjEyIikKY29sIDwtIGMoIiNFNDFBMUMiLCIjRkY3RjAwIiwiI0M3N0NGRiIsIiM5ODRFQTMiLCIjMDBBOUZGIiwiIzM3N0VCOCIsIiNDRDk2MDAiLCIjN0NBRTAwIiwiI2UwZTA2NyIsIiNGRjYxQ0MiLCIjRkY5REE3IiwiIzk5OTk5OSIsIiNBNjU2MjgiKQoKbHZsX2xheWVycyA8LSBzYW1wbGVfaWQKY29sIDwtICBjKCIjNEU3OUE3IiwgIiNGMjhFMkIiLCAiI0UxNTc1OSIsICIjNzZCN0IyIiwgIiM1OUExNEYiLCAiI0VEQzk0OCIsICIjOUM3NTVGIiwgIiNCMDdBQTEiLCAiI0ZGOURBNyIsICIjRTc4QUMzIiwgIiM3RkM5N0YiLCAiI0JFQUVENCIsICIjQkFCMEFDIiwgIiNGREMwODYiLCAiI0ZGRkY5OSIsICIjMzg2Q0IwIiwgIiNGMDAyN0YiLCAiI0JGNUIxNyIsICIjNjY2NjY2IiwgIiM2NkMyQTUiLCAiI0ZDOEQ2MiIsICIjOERBMENCIikKCiMjIyMgVU1BUCBhbmFseXNpcyAjIyMjCnNldC5zZWVkKDEpO3VtYXA8LXV3b3Q6OnVtYXAodChtYXRyaXhfdHJhbnMpLCAKICAgICAgICAgICAgICAgICBuX25laWdoYm9ycz0xNSwgaW5pdD0ic3BlY3RyYWwiLCBzY2FsZT1UKQp1bWFwX2RmIDwtIHRpYmJsZSgiVU1BUCAxIj11bWFwWywxXSwiVU1BUCAyIj11bWFwWywyXSwgCiAgICAgICAgICAgICAgICAgICJ1X0lEIj1yb3duYW1lcyh1bWFwKSwgImdyb3VwIj1ncltyb3duYW1lcyh1bWFwKV0sICJJRCI9c3RyX2V4dHJhY3Qocm93bmFtZXModW1hcCksICJQXFxkXFxkXFxkIikgKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3VwID0gZmFjdG9yKC4kZ3JvdXAsIGxldmVscyA9IGx2bF9sYXllcnMpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGcgPSBpZF9nclsuJElEXSkgCgoKdHh0X2RmIDwtIHVtYXBfZGYgJT4lIAogIGZpbHRlciguLCBncmVwbCgiXlAiLCAuJHR4dCkpICMlPiUKICAjbXV0YXRlKCJVTUFQIDIiID0gLiRgVU1BUCAyYCsgYygwLCAuMSwgcmVwKDAsbmNvbCguKSkpKQoKIyMjIyBVTUFQIHBsb3R0aW5nIGJ5IGdyb3VwcyAjIyMjClVNQVAuZnVuIDwtIGZ1bmN0aW9uKHVtYXBfZGYsIGdyb3VwKXsKICAjIGRldi5uZXcod2lkdGg9OC41LCBoZWlnaHQ9OCkKICBwIDwtIGdncGxvdCh1bWFwX2RmLCBhZXMoeD1gVU1BUCAxYCwgeT1gVU1BUCAyYCwgZmlsbD17e2dyb3VwfX0pKSsgCiAgICAjZ2VvbV9qaXR0ZXIoIHNoYXBlPTIxLCBzaXplPTMsIGNvbG9yPSJ3aGl0ZSIsIHdpZHRoPS41LCBoZWlnaHQ9LjUpICsgICMgVGFzc29zIHVzZWQgaml0dGVyCiAgICBnZW9tX3BvaW50KCBzaGFwZT0yMSwgc2l6ZT0zLCBhbHBoYSA9IC43LCBzdHJva2UgPTEpICsgIAogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbCkgKyAKICAgICMgZ2VvbV90ZXh0KGRhdGE9dHh0X2RmLCBhZXMoeD1gVU1BUCAxYCwgeT1gVU1BUCAyYCwgbGFiZWw9dHh0KSwgc2l6ZT0zLCB2anVzdCA9IC0uNSwgbnVkZ2VfeCA9IDAuMDMsIGNvbG9yPSJncmF5NTEiKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgeGxhYigiVU1BUCAxIikgKyB5bGFiKCJVTUFQIDIiKSArCiAgICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLC41LDEsLjUpLCAibGluZXMiKSwKICAgICAgICAgIGF4aXMudGl0bGUueC5ib3R0b20gPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKGIgPSAxKSksCiAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4obCA9IDApLCBhbmdsZSA9IDkwKSwKICAgICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9saW5lKGNvbG9yPSJibGFjayIpLCAKICAgICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpKSAKICByZXR1cm4ocCkKfQoKKHAgPC0gVU1BUC5mdW4odW1hcF9kZiwgZykpCihwX1QgPC0gVU1BUC5mdW4odW1hcF9kZiwgVGlzc3VlX2dyX3YzKSkKCiMgZGV2Lm5ldyh3aWR0aD04LCBoZWlnaHQ9My41LCBub1JTdHVkaW9HRCA9IFRSVUUpCihwXyA8LSBwbG90X2dyaWQocF9MLCBwX1QsIG5jb2wgPSAyICkgKQpgYGA=