##################
# LOAD LIBRARIES #
##################
suppressWarnings({suppressMessages({suppressPackageStartupMessages({
  library(tidyverse)
  library(openxlsx)
  library(fgsea)
  library(rafalib)
  library(Rcpp)
  library(igraph)
  #remotes::install_github("czarnewski/niceRplots",force=T)
  library(niceRplots)
  library(parallel)
})  })  })

#########
# PATHS #
#########
PATH <- "../../.."
reprod_files <- "../../data/reprod.Suppl.Fig.4_5/"

#############
# LODA DATA #
#############
datasets_all_samples <- readRDS("../../results/03_normalize_data_output/datasets_all_samples.RDS")
SNN_bacteria <- read.csv("../../results/04_clustering_output/bacteria_SNN_graph.csv",row.names = 1)
bac_communities <- read.xlsx("./Suppl.Tbl/Suppl.Tbl.01.xlsx", sheet = "Bacterial Communities")

Correlation heatmap

myletter <- letters
#reprod. <- FALSE
reprod. <- TRUE

ASV <- list(c("Luminal","ASV_Luminal_normalized"),
            c("Tissue","ASV_Tissue_normalized")
            )
# i <- ASV[[1]]
for(i in ASV){
  cat(paste0("Correlation between RNAseq and ",i[1], " 16S","\n"))
  
  # because hclust is non reproducible 
  if(reprod. == TRUE){
    NESes <- read.csv2(paste0(reprod_files,i[1],"_TRX_Bact_norm_enrichment_scores",".csv"), row.names = 1)
  }else{
    
    TRX <- datasets_all_samples[["Tissue_RNAseq_V3_normalized"]]
    bac_dataset <- datasets_all_samples[[i[2]]]
    samples_TRX_and_CVL3 <- colnames(counts) [ colSums(counts[c("Tissue_RNAseq_V3_normalized",i[2]),] > 0)==2 ]
    
    #filter TRX dataset
    TRX <- TRX [ , samples_TRX_and_CVL3 ]
    TRX <- TRX [ rowSums(TRX>0)>= 2 , ]
    # only top 5000 most variabe genes are included in the correlation
    top_vars_TRX <- names(sort(apply(TRX,1,var),decreasing = T)[1:5000] )
    TRX <- TRX[ top_vars_TRX , ]
    dim(TRX)
  
    #filter bac_dataset dataset
    bac_dataset <- bac_dataset [ , samples_TRX_and_CVL3 ]
    # keeping taxa that is present in at least two samples :
    bac_dataset <- bac_dataset [ rowSums(bac_dataset>0)>= 2 , ]
    top_vars_bacs <- names(sort(apply(bac_dataset,1,var),decreasing = T)[1:100] )
    dim(bac_dataset)
    
    cors <- cor( t(rbind(TRX) ) ,  t(rbind(bac_dataset) ) )
    
    bacteria_use <- colnames(cors)
    gmt <- gmtPathways(paste0(PATH, "/supplementary_files/c2.cp.kegg.v6.2.symbols.gmt.txt"))
    
    enrichments <- lapply(bacteria_use,gmt=gmt,cors=cors,function(x,gmt,cors){
      res <- fgsea(pathways = gmt,stats = sort(cors[,x],decreasing = T),nper=10000)
      return(res)
    })
    names(enrichments) <- bacteria_use
    
    pvalues <- lapply(enrichments,function(x) setNames(x$pval,x$pathway) )
    pvalues <- t(as.data.frame(pvalues))
    pvalues <- -log10( pvalues )
    top_pathways <- names(sort(apply(pvalues,1,median),T))[1:50]  

    NESes <- lapply(enrichments,function(x) setNames(x$NES,x$pathway) )
    NESes <- t(as.data.frame(NESes))
    NESes[is.na(NESes)] <- 0
    # replace all NESes values with 0 if they don't have a significant p-value < 0.05:
    NESes[ pvalues < -log10(0.05) ] <- 0 
    # filter out bacterium and pathways with <10 significant NES scores 
    NESes <- NESes[rowSums(NESes!=0) >= 10 , colSums(NESes!=0) >= 10]
    
    set.seed(1)
    o_kegg <- hclust( as.dist( (1-cor(NESes))/2 ),"ward.D2")$order
    o_bacs <- hclust( as.dist( (1-cor(t(NESes) ))/2 ),"ward.D2")$order
    NESes <- NESes[o_bacs, o_kegg]
    
    bact <- gsub("\\.{1}", "/", rownames(NESes))
    bact <- gsub("\\/{2}", ". ", bact)
    rownames(NESes) <- bact
  
    #write.csv2(NESes, paste0("../../../results/",i[1],"_TRX_Bact_norm_enrichment_scores",".csv"))
  
  }
  
  terms <- gsub("_", " ", colnames(NESes))
  terms <- gsub("(GO |KEGG )", "", terms, perl = TRUE)
  colnames(NESes) <- terms
  
  ### Suppl. Figure 4-5
  #######################################
  # FUNCTIONAL ASSOCIATION BACT AND TRX #
  #######################################
  par(mfrow=c(1,1),mar=c(12,0,2,4)) #b,l,t,r
  image( t(NESes[nrow(NESes):1,]),col=colorRampPalette(c("navy","grey95","firebrick"))(91),breaks=seq(-3,3,length.out = 92),
         axes=F,border=NA,main="tissue RNAseq KEGG pathways",xlab="",ylab=i,line=.4,cex.main=1,font.main=1)
  text(  par("usr")[c(4)] , seq(1,0,length.out = nrow(NESes)),
        labels = rownames(NESes), srt = 0, adj = c(0,.5), xpd = TRUE, cex=.4)
  text( seq(0,1,length.out = ncol(NESes)) , par("usr")[c(1)],
        labels = colnames(NESes), srt = 90, adj = c(1,.5), xpd = TRUE, cex=.4)
  
}
## Correlation between RNAseq and Luminal 16S

## Correlation between RNAseq and Tissue 16S

Suppl. Figure 4-5. Functional associations of the luminal microbiome with host tissue gene expression profiles. Bacterial abundances in the luminal samples were correlated with gene expression of the top 5,000 highly variable genes from the RNAseq dataset. This generated a correlation matrix between bacteria and genes. For each bacteria, genes were ranked based on their correlation to that bacteria, followed by gene set enrichment anlaysis (GSEA) using the KEGG gene annotation database. The resulting matrix display associations between individual bacterial taxa and corresponding KEGG term as defined in the host tissue sample. The heatmap shows the normalized enrichment score (NES). Only enrichments with p-value < 0.05 are shown. Bacterium and pathways with less than 10 significant NES scores were omitted from the heatmap. Bacteria are grouped according to anatomical/functional activity and marked with different colours per category.

LS0tCnRpdGxlOiAiU3VwcGwuIEZpZ3VyZSA0LiAmIDUuIE1pcm9iaW9tZS1LRUdHIGNvcnJlbGF0aW9ucy4iCmdlb21ldHJ5OiAibGVmdD0yY20scmlnaHQ9MmNtLHRvcD0yY20sYm90dG9tPTJjbSIKaGVhZGVyLWluY2x1ZGVzOiAKLSBcdXNlcGFja2FnZXtmbG9hdH0KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIG91dF9kaXIsIC4uLikgewogICAgc291cmNlKCIuLi8uLi9jb2RlL2tuaXRfZnVuY3Rpb24uUiIpOwogICAgY3VzdG9tX2tuaXQoaW5wdXRGaWxlLCAiLi4vLi4vbGFiX2Jvb2svU3VwcGxGaWd1cmU0XzUvIiwgLi4uKQogICAgfSkKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGZpZy5wYXRoPSIuL1N1cHBsLkZpZ3VyZXMvIiwKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBmaWcucHJvY2VzcyA9IGZ1bmN0aW9uKGZpbGVuYW1lKXsKICAgIG5ld19maWxlbmFtZSA8LSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gZmlsZW5hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiNC01LTEiPSI0IiwgIjQtNS0yIj0iNSIpKQogICAgZnM6OmZpbGVfbW92ZShwYXRoID0gZmlsZW5hbWUsIG5ld19wYXRoID0gbmV3X2ZpbGVuYW1lKQogICAgaWZlbHNlKGZzOjpmaWxlX2V4aXN0cyhuZXdfZmlsZW5hbWUpLCBuZXdfZmlsZW5hbWUsIGZpbGVuYW1lKQp9KQojIHNldHdkKCIvVXNlcnMvdmlsa2FsL3dvcmsvQnJvbGlkZW5zX3dvcmsvUHJvamVjdHMvYnJvbGlkZW5fNTMyNS9yZXBvcnRzL21hbnVzY3JpcHQiKQpgYGAKCmBgYHtyIExvYWQtZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgTE9BRCBMSUJSQVJJRVMgIwojIyMjIyMjIyMjIyMjIyMjIyMKc3VwcHJlc3NXYXJuaW5ncyh7c3VwcHJlc3NNZXNzYWdlcyh7c3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICBsaWJyYXJ5KG9wZW54bHN4KQogIGxpYnJhcnkoZmdzZWEpCiAgbGlicmFyeShyYWZhbGliKQogIGxpYnJhcnkoUmNwcCkKICBsaWJyYXJ5KGlncmFwaCkKICAjcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImN6YXJuZXdza2kvbmljZVJwbG90cyIsZm9yY2U9VCkKICBsaWJyYXJ5KG5pY2VScGxvdHMpCiAgbGlicmFyeShwYXJhbGxlbCkKfSkgIH0pICB9KQoKIyMjIyMjIyMjCiMgUEFUSFMgIwojIyMjIyMjIyMKUEFUSCA8LSAiLi4vLi4vLi4iCnJlcHJvZF9maWxlcyA8LSAiLi4vLi4vZGF0YS9yZXByb2QuU3VwcGwuRmlnLjRfNS8iCgojIyMjIyMjIyMjIyMjCiMgTE9EQSBEQVRBICMKIyMjIyMjIyMjIyMjIwpkYXRhc2V0c19hbGxfc2FtcGxlcyA8LSByZWFkUkRTKCIuLi8uLi9yZXN1bHRzLzAzX25vcm1hbGl6ZV9kYXRhX291dHB1dC9kYXRhc2V0c19hbGxfc2FtcGxlcy5SRFMiKQpTTk5fYmFjdGVyaWEgPC0gcmVhZC5jc3YoIi4uLy4uL3Jlc3VsdHMvMDRfY2x1c3RlcmluZ19vdXRwdXQvYmFjdGVyaWFfU05OX2dyYXBoLmNzdiIscm93Lm5hbWVzID0gMSkKYmFjX2NvbW11bml0aWVzIDwtIHJlYWQueGxzeCgiLi9TdXBwbC5UYmwvU3VwcGwuVGJsLjAxLnhsc3giLCBzaGVldCA9ICJCYWN0ZXJpYWwgQ29tbXVuaXRpZXMiKQoKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpjb3VudHMgPC0gdChhcy5kYXRhLmZyYW1lKCBsYXBwbHkoZGF0YXNldHNfYWxsX3NhbXBsZXMsY29sU3VtcykgKSkKY291bnRzW2lzLm5hKGNvdW50cyldIDwtIDAKYGBgCgojIyMgQ29ycmVsYXRpb24gaGVhdG1hcApgYGB7ciBTdXBwbC5GaWcuNC01LCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTN9Cm15bGV0dGVyIDwtIGxldHRlcnMKI3JlcHJvZC4gPC0gRkFMU0UKcmVwcm9kLiA8LSBUUlVFCgpBU1YgPC0gbGlzdChjKCJMdW1pbmFsIiwiQVNWX0x1bWluYWxfbm9ybWFsaXplZCIpLAogICAgICAgICAgICBjKCJUaXNzdWUiLCJBU1ZfVGlzc3VlX25vcm1hbGl6ZWQiKQogICAgICAgICAgICApCiMgaSA8LSBBU1ZbWzFdXQpmb3IoaSBpbiBBU1YpewogIGNhdChwYXN0ZTAoIkNvcnJlbGF0aW9uIGJldHdlZW4gUk5Bc2VxIGFuZCAiLGlbMV0sICIgMTZTIiwiXG4iKSkKICAKICAjIGJlY2F1c2UgaGNsdXN0IGlzIG5vbiByZXByb2R1Y2libGUgCiAgaWYocmVwcm9kLiA9PSBUUlVFKXsKICAgIE5FU2VzIDwtIHJlYWQuY3N2MihwYXN0ZTAocmVwcm9kX2ZpbGVzLGlbMV0sIl9UUlhfQmFjdF9ub3JtX2VucmljaG1lbnRfc2NvcmVzIiwiLmNzdiIpLCByb3cubmFtZXMgPSAxKQogIH1lbHNlewogICAgCiAgICBUUlggPC0gZGF0YXNldHNfYWxsX3NhbXBsZXNbWyJUaXNzdWVfUk5Bc2VxX1YzX25vcm1hbGl6ZWQiXV0KICAgIGJhY19kYXRhc2V0IDwtIGRhdGFzZXRzX2FsbF9zYW1wbGVzW1tpWzJdXV0KICAgIHNhbXBsZXNfVFJYX2FuZF9DVkwzIDwtIGNvbG5hbWVzKGNvdW50cykgWyBjb2xTdW1zKGNvdW50c1tjKCJUaXNzdWVfUk5Bc2VxX1YzX25vcm1hbGl6ZWQiLGlbMl0pLF0gPiAwKT09MiBdCiAgICAKICAgICNmaWx0ZXIgVFJYIGRhdGFzZXQKICAgIFRSWCA8LSBUUlggWyAsIHNhbXBsZXNfVFJYX2FuZF9DVkwzIF0KICAgIFRSWCA8LSBUUlggWyByb3dTdW1zKFRSWD4wKT49IDIgLCBdCiAgICAjIG9ubHkgdG9wIDUwMDAgbW9zdCB2YXJpYWJlIGdlbmVzIGFyZSBpbmNsdWRlZCBpbiB0aGUgY29ycmVsYXRpb24KICAgIHRvcF92YXJzX1RSWCA8LSBuYW1lcyhzb3J0KGFwcGx5KFRSWCwxLHZhciksZGVjcmVhc2luZyA9IFQpWzE6NTAwMF0gKQogICAgVFJYIDwtIFRSWFsgdG9wX3ZhcnNfVFJYICwgXQogICAgZGltKFRSWCkKICAKICAgICNmaWx0ZXIgYmFjX2RhdGFzZXQgZGF0YXNldAogICAgYmFjX2RhdGFzZXQgPC0gYmFjX2RhdGFzZXQgWyAsIHNhbXBsZXNfVFJYX2FuZF9DVkwzIF0KICAgICMga2VlcGluZyB0YXhhIHRoYXQgaXMgcHJlc2VudCBpbiBhdCBsZWFzdCB0d28gc2FtcGxlcyA6CiAgICBiYWNfZGF0YXNldCA8LSBiYWNfZGF0YXNldCBbIHJvd1N1bXMoYmFjX2RhdGFzZXQ+MCk+PSAyICwgXQogICAgdG9wX3ZhcnNfYmFjcyA8LSBuYW1lcyhzb3J0KGFwcGx5KGJhY19kYXRhc2V0LDEsdmFyKSxkZWNyZWFzaW5nID0gVClbMToxMDBdICkKICAgIGRpbShiYWNfZGF0YXNldCkKICAgIAogICAgY29ycyA8LSBjb3IoIHQocmJpbmQoVFJYKSApICwgIHQocmJpbmQoYmFjX2RhdGFzZXQpICkgKQogICAgCiAgICBiYWN0ZXJpYV91c2UgPC0gY29sbmFtZXMoY29ycykKICAgIGdtdCA8LSBnbXRQYXRod2F5cyhwYXN0ZTAoUEFUSCwgIi9zdXBwbGVtZW50YXJ5X2ZpbGVzL2MyLmNwLmtlZ2cudjYuMi5zeW1ib2xzLmdtdC50eHQiKSkKICAgIAogICAgZW5yaWNobWVudHMgPC0gbGFwcGx5KGJhY3RlcmlhX3VzZSxnbXQ9Z210LGNvcnM9Y29ycyxmdW5jdGlvbih4LGdtdCxjb3JzKXsKICAgICAgcmVzIDwtIGZnc2VhKHBhdGh3YXlzID0gZ210LHN0YXRzID0gc29ydChjb3JzWyx4XSxkZWNyZWFzaW5nID0gVCksbnBlcj0xMDAwMCkKICAgICAgcmV0dXJuKHJlcykKICAgIH0pCiAgICBuYW1lcyhlbnJpY2htZW50cykgPC0gYmFjdGVyaWFfdXNlCiAgICAKICAgIHB2YWx1ZXMgPC0gbGFwcGx5KGVucmljaG1lbnRzLGZ1bmN0aW9uKHgpIHNldE5hbWVzKHgkcHZhbCx4JHBhdGh3YXkpICkKICAgIHB2YWx1ZXMgPC0gdChhcy5kYXRhLmZyYW1lKHB2YWx1ZXMpKQogICAgcHZhbHVlcyA8LSAtbG9nMTAoIHB2YWx1ZXMgKQogICAgdG9wX3BhdGh3YXlzIDwtIG5hbWVzKHNvcnQoYXBwbHkocHZhbHVlcywxLG1lZGlhbiksVCkpWzE6NTBdICAKCiAgICBORVNlcyA8LSBsYXBwbHkoZW5yaWNobWVudHMsZnVuY3Rpb24oeCkgc2V0TmFtZXMoeCRORVMseCRwYXRod2F5KSApCiAgICBORVNlcyA8LSB0KGFzLmRhdGEuZnJhbWUoTkVTZXMpKQogICAgTkVTZXNbaXMubmEoTkVTZXMpXSA8LSAwCiAgICAjIHJlcGxhY2UgYWxsIE5FU2VzIHZhbHVlcyB3aXRoIDAgaWYgdGhleSBkb24ndCBoYXZlIGEgc2lnbmlmaWNhbnQgcC12YWx1ZSA8IDAuMDU6CiAgICBORVNlc1sgcHZhbHVlcyA8IC1sb2cxMCgwLjA1KSBdIDwtIDAgCiAgICAjIGZpbHRlciBvdXQgYmFjdGVyaXVtIGFuZCBwYXRod2F5cyB3aXRoIDwxMCBzaWduaWZpY2FudCBORVMgc2NvcmVzIAogICAgTkVTZXMgPC0gTkVTZXNbcm93U3VtcyhORVNlcyE9MCkgPj0gMTAgLCBjb2xTdW1zKE5FU2VzIT0wKSA+PSAxMF0KICAgIAogICAgc2V0LnNlZWQoMSkKICAgIG9fa2VnZyA8LSBoY2x1c3QoIGFzLmRpc3QoICgxLWNvcihORVNlcykpLzIgKSwid2FyZC5EMiIpJG9yZGVyCiAgICBvX2JhY3MgPC0gaGNsdXN0KCBhcy5kaXN0KCAoMS1jb3IodChORVNlcykgKSkvMiApLCJ3YXJkLkQyIikkb3JkZXIKICAgIE5FU2VzIDwtIE5FU2VzW29fYmFjcywgb19rZWdnXQogICAgCiAgICBiYWN0IDwtIGdzdWIoIlxcLnsxfSIsICIvIiwgcm93bmFtZXMoTkVTZXMpKQogICAgYmFjdCA8LSBnc3ViKCJcXC97Mn0iLCAiLiAiLCBiYWN0KQogICAgcm93bmFtZXMoTkVTZXMpIDwtIGJhY3QKICAKICAgICN3cml0ZS5jc3YyKE5FU2VzLCBwYXN0ZTAoIi4uLy4uLy4uL3Jlc3VsdHMvIixpWzFdLCJfVFJYX0JhY3Rfbm9ybV9lbnJpY2htZW50X3Njb3JlcyIsIi5jc3YiKSkKICAKICB9CiAgCiAgdGVybXMgPC0gZ3N1YigiXyIsICIgIiwgY29sbmFtZXMoTkVTZXMpKQogIHRlcm1zIDwtIGdzdWIoIihHTyB8S0VHRyApIiwgIiIsIHRlcm1zLCBwZXJsID0gVFJVRSkKICBjb2xuYW1lcyhORVNlcykgPC0gdGVybXMKICAKICAjIyMgU3VwcGwuIEZpZ3VyZSA0LTUKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIEZVTkNUSU9OQUwgQVNTT0NJQVRJT04gQkFDVCBBTkQgVFJYICMKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBwYXIobWZyb3c9YygxLDEpLG1hcj1jKDEyLDAsMiw0KSkgI2IsbCx0LHIKICBpbWFnZSggdChORVNlc1tucm93KE5FU2VzKToxLF0pLGNvbD1jb2xvclJhbXBQYWxldHRlKGMoIm5hdnkiLCJncmV5OTUiLCJmaXJlYnJpY2siKSkoOTEpLGJyZWFrcz1zZXEoLTMsMyxsZW5ndGgub3V0ID0gOTIpLAogICAgICAgICBheGVzPUYsYm9yZGVyPU5BLG1haW49InRpc3N1ZSBSTkFzZXEgS0VHRyBwYXRod2F5cyIseGxhYj0iIix5bGFiPWksbGluZT0uNCxjZXgubWFpbj0xLGZvbnQubWFpbj0xKQogIHRleHQoICBwYXIoInVzciIpW2MoNCldICwgc2VxKDEsMCxsZW5ndGgub3V0ID0gbnJvdyhORVNlcykpLAogICAgICAgIGxhYmVscyA9IHJvd25hbWVzKE5FU2VzKSwgc3J0ID0gMCwgYWRqID0gYygwLC41KSwgeHBkID0gVFJVRSwgY2V4PS40KQogIHRleHQoIHNlcSgwLDEsbGVuZ3RoLm91dCA9IG5jb2woTkVTZXMpKSAsIHBhcigidXNyIilbYygxKV0sCiAgICAgICAgbGFiZWxzID0gY29sbmFtZXMoTkVTZXMpLCBzcnQgPSA5MCwgYWRqID0gYygxLC41KSwgeHBkID0gVFJVRSwgY2V4PS40KQogIAp9CgpgYGAKCgoqKlN1cHBsLiBGaWd1cmUgNC01LiBGdW5jdGlvbmFsIGFzc29jaWF0aW9ucyBvZiB0aGUgbHVtaW5hbCBtaWNyb2Jpb21lIHdpdGggaG9zdCB0aXNzdWUgZ2VuZSBleHByZXNzaW9uIHByb2ZpbGVzLioqIEJhY3RlcmlhbCBhYnVuZGFuY2VzIGluIHRoZSBsdW1pbmFsIHNhbXBsZXMgd2VyZSBjb3JyZWxhdGVkIHdpdGggZ2VuZSBleHByZXNzaW9uIG9mIHRoZSB0b3AgNSwwMDAgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIGZyb20gdGhlIFJOQXNlcSBkYXRhc2V0LiBUaGlzIGdlbmVyYXRlZCBhIGNvcnJlbGF0aW9uIG1hdHJpeCBiZXR3ZWVuIGJhY3RlcmlhIGFuZCBnZW5lcy4gRm9yIGVhY2ggYmFjdGVyaWEsIGdlbmVzIHdlcmUgcmFua2VkIGJhc2VkIG9uIHRoZWlyIGNvcnJlbGF0aW9uIHRvIHRoYXQgYmFjdGVyaWEsIGZvbGxvd2VkIGJ5IGdlbmUgc2V0IGVucmljaG1lbnQgYW5sYXlzaXMgKEdTRUEpIHVzaW5nIHRoZSBLRUdHIGdlbmUgYW5ub3RhdGlvbiBkYXRhYmFzZS4gVGhlIHJlc3VsdGluZyBtYXRyaXggZGlzcGxheSBhc3NvY2lhdGlvbnMgYmV0d2VlbiBpbmRpdmlkdWFsIGJhY3RlcmlhbCB0YXhhIGFuZCBjb3JyZXNwb25kaW5nIEtFR0cgdGVybSBhcyBkZWZpbmVkIGluIHRoZSBob3N0IHRpc3N1ZSBzYW1wbGUuIFRoZSBoZWF0bWFwIHNob3dzIHRoZSBub3JtYWxpemVkIGVucmljaG1lbnQgc2NvcmUgKE5FUykuIE9ubHkgZW5yaWNobWVudHMgd2l0aCBwLXZhbHVlIDwgMC4wNSBhcmUgc2hvd24uIEJhY3Rlcml1bSBhbmQgcGF0aHdheXMgd2l0aCBsZXNzIHRoYW4gMTAgc2lnbmlmaWNhbnQgTkVTIHNjb3JlcyB3ZXJlIG9taXR0ZWQgZnJvbSB0aGUgaGVhdG1hcC4gQmFjdGVyaWEgYXJlIGdyb3VwZWQgYWNjb3JkaW5nIHRvIGFuYXRvbWljYWwvZnVuY3Rpb25hbCBhY3Rpdml0eSBhbmQgbWFya2VkIHdpdGggZGlmZmVyZW50IGNvbG91cnMgcGVyIGNhdGVnb3J5LgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZyA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgoYXMubWF0cml4KFNOTl9iYWN0ZXJpYSksIG1vZGUgPSAidW5kaXJlY3RlZCIsZGlhZyA9IEYsd2VpZ2h0ZWQgPSBUKQpjbCA8LSBpZ3JhcGg6OmNsdXN0ZXJfbG91dmFpbihnKQpjb3JzIDwtIGNvcih0KGRhdGFzZXRzX2FsbF9zYW1wbGVzW1tpXV1bcm93U3VtcyhkYXRhc2V0c19hbGxfc2FtcGxlc1tbaV1dID4gMCk+PTEwLF0pKQoKCm1vZHVsZV9tZWFucyA8LSBiYWNfY29tbXVuaXRpZXMgJT4lCiAgbGVmdF9qb2luKGFzX3RpYmJsZShkYXRhc2V0c19hbGxfc2FtcGxlc1tbaV1dLCByb3duYW1lcyA9ICJUYXhhIiksIGJ5PSJUYXhhIikgICU+JQogIGdyb3VwX2J5KGJhY3RlcmlhbC5jb21tdW5pdGllcykgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnN1bSgueCkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+LngvYyh0YWJsZShiYWNfY29tbXVuaXRpZXMkYmFjdGVyaWFsLmNvbW11bml0aWVzKSkpICkgJT4lCiAgc2VsZWN0KC1iYWN0ZXJpYWwuY29tbXVuaXRpZXMpICU+JQogICNjb2x1bW5fdG9fcm93bmFtZXModmFyPSJiYWN0ZXJpYWwuY29tbXVuaXRpZXMiKSAlPiUKICBhcy5tYXRyaXgoKSAlPiUKICBgcm93bmFtZXM8LWAodW5pcXVlKCBiYWNfY29tbXVuaXRpZXMkYmFjdGVyaWFsLmNvbW11bml0aWVzKSkgCmJhY3RfZGYgPC0gbW9kdWxlX21lYW5zCgoKYWxsX21pY3JvYmlvbWUgPC0gY2JpbmQoZGF0YXNldHNfYWxsX3NhbXBsZXNbWyJBU1ZfdGlzc3VlX1YzX25vcm1hbGl6ZWRfYmF0Y2hfY29ycmVjdGVkIl1dLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhc2V0c19hbGxfc2FtcGxlc1tbIkFTVl9DVkxfVjNfbm9ybWFsaXplZF9iYXRjaF9jb3JyZWN0ZWQiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFzZXRzX2FsbF9zYW1wbGVzW1siQVNWX0NWTF9WMl9ub3JtYWxpemVkX05PVF9iYXRjaF9jb3JyZWN0ZWQiXV0pCiNjb3JzIDwtIGNvciggdChyYmluZChUUlgpICkgLCAgdChyYmluZChiYWNfZGF0YXNldCkgKSApCgoKbW9kdWxlX21lYW5zX3Blcl9kYXRhc2V0IDwtIGxhcHBseShkYXRhc2V0c19hbGxfc2FtcGxlc1tbaV1dLGZ1bmN0aW9uKHgpewogIHJldHVybiggcm93c3VtKCB4W2JhY19jb21tdW5pdGllcyRUYXhhLF0gLCBncm91cCA9IGJhY19jb21tdW5pdGllcyRiYWN0ZXJpYWwuY29tbXVuaXRpZXMgKSAvIGModGFibGUoYmFjX2NvbW11bml0aWVzJGJhY3RlcmlhbC5jb21tdW5pdGllcykpICkKfSkKCm1vZHVsZV9tZWFucyA8LSBiYWNfY29tbXVuaXRpZXMgJT4lCiAgbGVmdF9qb2luKGFzX3RpYmJsZShkYXRhc2V0c19hbGxfc2FtcGxlc1tbaV1dLCByb3duYW1lcyA9ICJUYXhhIiksIGJ5PSJUYXhhIikgICU+JQogIGdyb3VwX2J5KGJhY3RlcmlhbC5jb21tdW5pdGllcykgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnN1bSgueCkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+LngvYyh0YWJsZShiYWNfY29tbXVuaXRpZXMkYmFjdGVyaWFsLmNvbW11bml0aWVzKSkpICkKICAKICAKICAKCmIgIDwtICBkYXRhc2V0c19hbGxfc2FtcGxlc1tbaV1dW2JhY19jb21tdW5pdGllcyRUYXhhLF0Kcm93c3VtKGRhdGFzZXRzX2FsbF9zYW1wbGVzW1tpXV1bYmFjX2NvbW11bml0aWVzJFRheGEsXSAsIGdyb3VwID0gYmFjX2NvbW11bml0aWVzJGJhY3RlcmlhbC5jb21tdW5pdGllcyApCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIGluY2x1ZGU9RkFMU0V9Cm15bGV0dGVyIDwtIGxldHRlcnMKCk5FU3NlX2xpc3QgPC0gbGlzdCgpCnB2YWx1ZXNfbGlzdCA8LSBsaXN0KCkKCmZvcihpIGluIGMoIkFTVl90aXNzdWVfVjNfbm9ybWFsaXplZF9iYXRjaF9jb3JyZWN0ZWQiLAogICAgICAgICAgICJBU1ZfQ1ZMX1YzX25vcm1hbGl6ZWRfYmF0Y2hfY29ycmVjdGVkIikpewogIAogIGNhdChwYXN0ZTAoIlxuQ29ycmVsYXRpb24gYmV0d2VlbiBSTkFzZXEgYW5kICIsc3ViKCJfbm9ybS4qIiwiIixpKSkpCiAgCiAgVFJYIDwtIGFzLm1hdHJpeChkYXRhc2V0c19hbGxfc2FtcGxlc1tbIlRpc3N1ZV9STkFzZXFfVjNfbm9ybWFsaXplZCJdXSkKICBiYWNfZGF0YXNldCA8LSBtb2R1bGVfbWVhbnNfcGVyX2RhdGFzZXRbW2ldXQogIHNhbXBsZXNfVFJYX2FuZF9DVkwzIDwtIGNvbG5hbWVzKGJhY19kYXRhc2V0KQogIAogICMgbXlwYXIoNCwzLG1hcj1jKDQsMiwyLDIpKQogICNmaWx0ZXIgVFJYIGRhdGFzZXQKICBUUlggPC0gVFJYIFsgLCBzYW1wbGVzX1RSWF9hbmRfQ1ZMMyBdCiAgVFJYIDwtIFRSWCBbIHJvd1N1bXMoVFJYPjApPj0gNSAsIF0KICAKICAjZmlsdGVyIGJhY19kYXRhc2V0IGRhdGFzZXQKICBiYWNfZGF0YXNldCA8LSBiYWNfZGF0YXNldCBbICwgc2FtcGxlc19UUlhfYW5kX0NWTDMgXQogIGRpbShiYWNfZGF0YXNldCkKICAKICBjb3JzIDwtIGNvciggdChyYmluZChUUlgpICkgLCAgdChyYmluZChiYWNfZGF0YXNldCkgKSApCiAgZGltKGNvcnMpCiAgCiAgYmFjdGVyaWFfdXNlIDwtIGNvbG5hbWVzKGNvcnMpCiAgI2dtdCA8LSBnbXRQYXRod2F5cygiLi4vLi4vc3VwcGxlbWVudGFyeV9maWxlcy9oLmFsbC52Ni4yLnN5bWJvbHMuZ210LnR4dCIpCiAgZ210IDwtIGdtdFBhdGh3YXlzKCIuLi8uLi9zdXBwbGVtZW50YXJ5X2ZpbGVzL2MyLmNwLmtlZ2cudjYuMi5zeW1ib2xzLmdtdC50eHQiKQogIGNsIDwtIHBhcmFsbGVsOjptYWtlUFNPQ0tjbHVzdGVyKHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpLTEpCiAgaW52aXNpYmxlKHBhcmFsbGVsOjpjbHVzdGVyRXZhbFEoY2wsIHtjKCJnbXQiLCJjb3JzIik7bGlicmFyeShmZ3NlYSk7bGlicmFyeShzdGF0cyk7bGlicmFyeShiYXNlKX0pKQogIGVucmljaG1lbnRzIDwtIHBhcmFsbGVsOjpwYXJMYXBwbHkoY2wsYmFjdGVyaWFfdXNlLGdtdD1nbXQsY29ycz1jb3JzLGZ1bmN0aW9uKHgsZ210LGNvcnMpewogICAgcmVzIDwtIGZnc2VhTXVsdGlsZXZlbChwYXRod2F5cyA9IGdtdCxzdGF0cyA9IGNvcnNbLHhdKQogICAgcmV0dXJuKHJlcykKICB9KQogIHBhcmFsbGVsOjpzdG9wQ2x1c3RlcihjbCkKICBuYW1lcyhlbnJpY2htZW50cykgPC0gcGFzdGUwKCAiYmFjLmNvbS4iLCBiYWN0ZXJpYV91c2UgKQogIAogIGFsbHBhdGh3YXlzIDwtIHVuaXF1ZSh1bmxpc3QobGFwcGx5KGVucmljaG1lbnRzLGZ1bmN0aW9uKHgpe3hbLDFdfSkpKQogIGFsbHB2YWxzIDwtIHNldE5hbWVzKHJlcChOQSxsZW5ndGgoYWxscGF0aHdheXMpKSxhbGxwYXRod2F5cykKICAKICBwdmFsdWVzIDwtIGxhcHBseShlbnJpY2htZW50cyxmdW5jdGlvbih4KXsKICAgIHRlbXAgPC0gYWxscHZhbHMKICAgIHRlbXBbeCRwYXRod2F5XSA8LSB4JHB2YWwKICAgIHJldHVybih0ZW1wKQogIH0pCiAgcHZhbHVlcyA8LSB0KGFzLmRhdGEuZnJhbWUocHZhbHVlcykpCiAgcHZhbHVlcyA8LSAtbG9nMTAoIHB2YWx1ZXMgKQogIHB2YWx1ZXNbaXMubmEocHZhbHVlcyldIDwtIDAKICAKICBhbGxORVMgPC0gc2V0TmFtZXMocmVwKE5BLGxlbmd0aChhbGxwYXRod2F5cykpLGFsbHBhdGh3YXlzKQogIE5FU2VzIDwtIGxhcHBseShlbnJpY2htZW50cyxmdW5jdGlvbih4KSB7CiAgICB0ZW1wIDwtIGFsbE5FUwogICAgdGVtcFt4JHBhdGh3YXldIDwtIHgkTkVTCiAgICByZXR1cm4odGVtcCkKICB9KQogIE5FU2VzIDwtIHQoYXMuZGF0YS5mcmFtZShORVNlcykpCiAgTkVTZXNbaXMubmEoTkVTZXMpXSA8LSAwCiAgIyBORVNlc1sgcHZhbHVlcyA8IC1sb2cxMCgwLjEpIF0gPC0gMAoKICBORVNzZV9saXN0W1tpXV0gPC0gTkVTZXMKICBwdmFsdWVzX2xpc3RbW2ldXSA8LSBwdmFsdWVzCiAgCn0KCndyaXRlLmNzdjIoTkVTc2VfbGlzdCwiLi4vLi4vcmVzdWx0cy9IYWxsbWFya19ORVNzZV9saXN0LmNzdiIpCndyaXRlLmNzdjIocHZhbHVlc19saXN0LCIuLi8uLi9yZXN1bHRzL0hhbGxtYXJrX3B2YWx1ZXNfbGlzdC5jc3YiKQoKY29tbW9uX3BhdGh3YXlzIDwtIHVuaXF1ZSggdW5saXN0KCBsYXBwbHkoIE5FU3NlX2xpc3QgLCBmdW5jdGlvbih4KSBjb2xuYW1lcyh4KVtjb2xTdW1zKHghPTApPj0xXSApICkgKQoKbGF5b3V0KG1hdHJpeChjKDEsMiwzLDQsNCksbnJvdyA9IDEpKQpwYXIobWFyPWMoNiwxLDIsMCkpCmZvciggaSBpbiBuYW1lcyhORVNzZV9saXN0KSl7CiAgeCA8LSBORVNzZV9saXN0W1tpXV1bLGNvbW1vbl9wYXRod2F5c10KICBpbWFnZSggeFssbmNvbCh4KToxXSxjb2w9Y29sb3JSYW1wUGFsZXR0ZShjKCJuYXZ5IiwiZ3JleTk1IiwiZmlyZWJyaWNrIikpKDkxKSxicmVha3M9c2VxKC01LDUsbGVuZ3RoLm91dCA9IDkyKSwKICAgICAgICAgYXhlcz1GLGJvcmRlcj1OQSxtYWluPXN1YigiX25vcm0uKiIsIiIsaSkseGxhYj0iIix5bGFiPSIiLGxpbmU9LjQsY2V4Lm1haW49MSxmb250Lm1haW49MSkKICAjIGFkZF9sZXR0ZXIobXlsZXR0ZXIpOyBteWxldHRlciA8LSBteWxldHRlclstMV0KICB0ZXh0KCAgIHNlcSgwLDEsbGVuZ3RoLm91dCA9IG5yb3coeCkpICwgcGFyKCJ1c3IiKVtjKDMpXSAsCiAgICAgIGxhYmVscyA9IHJvd25hbWVzKHgpLCBzcnQgPSA5MCwgYWRqID0gYygxLC41KSwgeHBkID0gVFJVRSwgY2V4PTEpCn0KZW1wdHlfcGxvdCh4YXhzPSJpIix5YXhzPSJpIiwKICAgICAgICAgICB4bGltPXBhcigidXNyIilbYygxLDIpXSx5bGltPXBhcigidXNyIilbYygzLDQpXSkKdGV4dCggIHBhcigidXNyIilbYygxKV0sc2VxKDEsMCxsZW5ndGgub3V0ID0gbmNvbCh4KSkgLAogICAgICBsYWJlbHMgPSBzdWIoIkhBTExNQVJLXyIsIiIsY29sbmFtZXMoeCkpLCBzcnQgPSAwLCBhZGogPSBjKDAsLjUpLCB4cGQgPSBUUlVFLCBjZXg9MSkKICAKY2F0KCJcXGNsZWFycGFnZSIpCgojIENvbWJpbmVkIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0d28gZGF0YXNldHMKbGF5b3V0KG1hdHJpeChjKDEsMiwyLDIsMiksbnJvdyA9IDEpKQpwYXIobWFyPWMoNiwxLDMsMCkpCnggPC0gKE5FU3NlX2xpc3RbWzFdXVssY29tbW9uX3BhdGh3YXlzXSArIE5FU3NlX2xpc3RbWzJdXVssY29tbW9uX3BhdGh3YXlzXSkgLyAyCnhbTkVTc2VfbGlzdFtbMV1dWyxjb21tb25fcGF0aHdheXNdID09IDBdIDwtIDAKeFtORVNzZV9saXN0W1syXV1bLGNvbW1vbl9wYXRod2F5c10gPT0gMF0gPC0gMAp4IDwtIHhbLCBjb2xTdW1zKHghPTApPjBdCmltYWdlKCB4WyxuY29sKHgpOjFdLGNvbD1jb2xvclJhbXBQYWxldHRlKGMoIm5hdnkiLCJncmV5OTUiLCJmaXJlYnJpY2siKSkoOTEpLGJyZWFrcz1zZXEoLTUsNSxsZW5ndGgub3V0ID0gOTIpLAogICAgICAgYXhlcz1GLGJvcmRlcj1OQSxtYWluPSJDVkxfdjMgKyB0aXNzdWVfdjNcbmNvbWJpbmVkIix4bGFiPSIiLHlsYWI9IiIsbGluZT0uNCxjZXgubWFpbj0xLGZvbnQubWFpbj0xKQojIGFkZF9sZXR0ZXIobXlsZXR0ZXIpOyBteWxldHRlciA8LSBteWxldHRlclstMV0KdGV4dCggICBzZXEoMCwxLGxlbmd0aC5vdXQgPSBucm93KHgpKSAsIHBhcigidXNyIilbYygzKV0gLAogICAgbGFiZWxzID0gcmV2KHJvd25hbWVzKHgpKSwgc3J0ID0gOTAsIGFkaiA9IGMoMSwuNSksIHhwZCA9IFRSVUUsIGNleD0xKQplbXB0eV9wbG90KHhheHM9ImkiLHlheHM9ImkiLAogICAgICAgICAgIHhsaW09cGFyKCJ1c3IiKVtjKDEsMildLHlsaW09cGFyKCJ1c3IiKVtjKDMsNCldLG1haW49IkhBTExNQVJLIikKdGV4dCggIHBhcigidXNyIilbYygxKV0sc2VxKDAsMSxsZW5ndGgub3V0ID0gbmNvbCh4KSkgLAogICAgICBsYWJlbHMgPSByZXYoc3ViKCJIQUxMTUFSS18iLCIiLGNvbG5hbWVzKHgpKSksIHNydCA9IDAsIGFkaiA9IGMoMCwuNSksIHhwZCA9IFRSVUUsIGNleD0xKQoKCgoKIyBDb21iaW5lZCByZXByZXNlbnRhdGlvbiBvZiB0aGUgdHdvIGRhdGFzZXRzCmxheW91dChtYXRyaXgoYygxLDEsMSwxLDEsMiwyKSxucm93ID0gMSkpCnBhcihtYXI9Yyg2LDMwLDMsMCkpCnggPC0gKE5FU3NlX2xpc3RbWzFdXVssY29tbW9uX3BhdGh3YXlzXSArIE5FU3NlX2xpc3RbWzJdXVssY29tbW9uX3BhdGh3YXlzXSkgLyAyCnhbTkVTc2VfbGlzdFtbMV1dWyxjb21tb25fcGF0aHdheXNdID09IDBdIDwtIDAKeFtORVNzZV9saXN0W1syXV1bLGNvbW1vbl9wYXRod2F5c10gPT0gMF0gPC0gMAp4IDwtIHhbLCBjb2xTdW1zKHghPTApPjBdCgpUUlggPC0gZGF0YXNldHNfYWxsX3NhbXBsZXNbWyJUaXNzdWVfUk5Bc2VxX1YzX25vcm1hbGl6ZWQiXV0Kbm9uX3plcm9zIDwtIGNvbFN1bXMoVFJYKSE9MApUUlggPC0gVFJYIFsgICwgbm9uX3plcm9zIF0KcGF0aHdheV9tZWFucyA8LSB0KHNhcHBseSggY29sbmFtZXMoeCkgLCBmdW5jdGlvbihpKXsKICBpIDwtIGdtdFtbaV1dCiAgaSA8LSBhcy5tYXRyaXgoIFRSWFsgcm93bmFtZXMoVFJYKSAlaW4lIGkgLCBdICkKICBpZihuY29sKGkpPjEpewogICAgaSA8LSAoIGkgLSBhcHBseShpLDEsbWluKSApIC8gKCBhcHBseShpLDEsbWF4KS0gYXBwbHkoaSwxLG1pbikgKQogICAgaSA8LSBjb2xNZWFucyhpKQogIH0gZWxzZSB7CiAgICBpIDwtIChpIC0gbWluKGkpKSAvIChtYXgoaSkgLSBtaW4oaSkpCiAgfQogIHJldHVybiggaSAtIG1pbihpKSApCn0gKSkKcGxvdF9kb3RzKGRhdGE9cGF0aHdheV9tZWFucyxtYWluPSJwYXRpZW50IGdyb3VwcyIsY2V4Lm1haW49MSxmb250Lm1haW49MSwKICAgICAgICBnZW5lcz1yb3duYW1lcyhwYXRod2F5X21lYW5zKSwKICAgICAgICBjbHVzdGVyaW5nPWZhY3RvcihtZXRhZGF0YSRqb2ludF9jbHVzdGVyaW5nW25vbl96ZXJvc10pLAogICAgICAgIHNydD0wLHBhbD1jKCJibHVlIiwiYmx1ZSIsIm5hdnkiLCJuYXZ5IiwiZ3JleTk1IiwiZ3JleTk1IiwiZmlyZWJyaWNrMyIsImJsYWNrIikpCgoKcGFyKG1hcj1jKDYsMiwzLDIpKQppbWFnZSggeFssbmNvbCh4KToxXSxjb2w9Y29sb3JSYW1wUGFsZXR0ZShjKCJuYXZ5IiwiZ3JleTk1IiwiZmlyZWJyaWNrIikpKDkxKSxicmVha3M9c2VxKC01LDUsbGVuZ3RoLm91dCA9IDkyKSwKICAgICAgIGF4ZXM9Rixib3JkZXI9TkEsbWFpbj0iQ1ZMX3YzICsgdGlzc3VlX3YzXG5jb21iaW5lZCIseGxhYj0iIix5bGFiPSIiLGxpbmU9LjQsY2V4Lm1haW49MSxmb250Lm1haW49MSkKIyBhZGRfbGV0dGVyKG15bGV0dGVyKTsgbXlsZXR0ZXIgPC0gbXlsZXR0ZXJbLTFdCnRleHQoICAgc2VxKDAsMSxsZW5ndGgub3V0ID0gbnJvdyh4KSkgLCBwYXIoInVzciIpW2MoMyldICwKICAgIGxhYmVscyA9IHJvd25hbWVzKHgpLCBzcnQgPSA5MCwgYWRqID0gYygxLC41KSwgeHBkID0gVFJVRSwgY2V4PTEpCiMgZW1wdHlfcGxvdCh4YXhzPSJpIix5YXhzPSJpIiwKIyAgICAgICAgICAgIHhsaW09cGFyKCJ1c3IiKVtjKDEsMildLHlsaW09cGFyKCJ1c3IiKVtjKDMsNCldLG1haW49IiAiKQojIHRleHQoICBwYXIoInVzciIpW2MoMSldLHNlcSgxLDAsbGVuZ3RoLm91dCA9IG5jb2woeCkpICwKICAgICAgIyBsYWJlbHMgPSBzdWIoIktFR0dfIiwiIixjb2xuYW1lcyh4KSksIHNydCA9IDAsIGFkaiA9IGMoMCwuNSksIHhwZCA9IFRSVUUsIGNleD0xKQoKCmBgYA==