00. Envirenment Settings

Load the bioinformatics analysis results from the previous steps

load("CheckPoint.RData")
options(install.packages.compile.from.source = "always")
list.packages <- c(
  "readxl", "ggplot2", "ggpubr", "matrixStats", "ggrepel", "reshape2", "dplyr", "stringr",
  "grid", "tcltk", "parallel", "doParallel", "doSNOW", "data.table", "gplots",
  "randomcoloR", "factoextra", "RColorBrewer", "grDevices", "gmp", "xtable", "latex2exp",
  "httr", "jsonlite", "curl", "RCurl", "magrittr", "rlist", "pipeR", "plyr",
  "xml2", "rvest", "knn.covertree", "knitr", "rlang", "visNetwork", "hwriter", "htmltools"
)
bio.list.packages <- c(
  "limma", "ExperimentHub", "clusterProfiler", "GO.db",
  "org.Mm.eg.db", "pathview", "enrichplot", "org.Hs.eg.db"
)
new.packages <- list.packages[!list.packages %in% installed.packages()]
bio.new.packages <- bio.list.packages[!bio.list.packages %in% installed.packages()]
# Packages that does not install yet
if (!requireNamespace("BiocManager", quietly = TRUE)) {
  update.packages(ask = FALSE)
  install.packages("BiocManager", repos="https://cloud.r-project.org")
}
if (length(new.packages)) {
  install.packages(new.packages)
  devtools::install_github("grimbough/biomaRt", force = FALSE)
}
if (length(bio.new.packages)) {
  update.packages(ask = FALSE)
  BiocManager::install(bio.new.packages)
}
# Loading all packages & functions
invisible(lapply(c(list.packages, bio.list.packages, "biomaRt"), library, character.only = TRUE))

Attaching package: ‘dplyr’

The following object is masked from ‘package:matrixStats’:

    count

The following object is masked from ‘package:biomaRt’:

    select

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Loading required package: foreach
Loading required package: iterators
Loading required package: snow

Attaching package: ‘snow’

The following objects are masked from ‘package:parallel’:

    clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap, clusterSplit, makeCluster, parApply, parCapply, parLapply,
    parRapply, parSapply, splitIndices, stopCluster

data.table 1.14.8 using 64 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: ‘data.table’

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following objects are masked from ‘package:reshape2’:

    dcast, melt


Attaching package: ‘gplots’

The following object is masked from ‘package:stats’:

    lowess

Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa

Attaching package: ‘gmp’

The following objects are masked from ‘package:base’:

    %*%, apply, crossprod, matrix, tcrossprod


Attaching package: ‘httr’

The following object is masked _by_ ‘.GlobalEnv’:

    progress

Using libcurl 7.81.0 with OpenSSL/3.0.2

Attaching package: ‘curl’

The following object is masked from ‘package:httr’:

    handle_reset

---------------------------------------------------------------------------------------------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Attaching package: ‘plyr’

The following objects are masked from ‘package:dplyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following object is masked from ‘package:matrixStats’:

    count

The following object is masked from ‘package:ggpubr’:

    mutate


Attaching package: ‘rlang’

The following object is masked from ‘package:xml2’:

    as_list

The following object is masked from ‘package:magrittr’:

    set_names

The following objects are masked from ‘package:jsonlite’:

    flatten, unbox

The following object is masked from ‘package:data.table’:

    :=

Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following object is masked from ‘package:limma’:

    plotMA

The following objects are masked from ‘package:gmp’:

    which.max, which.min

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, aperm, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep,
    grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce,
    rownames, sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max, which.min

Loading required package: AnnotationHub
Loading required package: BiocFileCache
Loading required package: dbplyr

Attaching package: ‘dbplyr’

The following objects are masked from ‘package:dplyr’:

    ident, sql

clusterProfiler v4.6.2  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/

If you use clusterProfiler in published research, please cite:
T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal enrichment tool for interpreting omics data. The Innovation. 2021, 2(3):100141

Attaching package: ‘clusterProfiler’

The following objects are masked from ‘package:plyr’:

    arrange, mutate, rename, summarise

The following object is masked from ‘package:biomaRt’:

    select

The following object is masked from ‘package:stats’:

    filter

Loading required package: AnnotationDbi
Loading required package: stats4
Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see 'citation("Biobase")', and for packages
    'citation("pkgname")'.


Attaching package: ‘Biobase’

The following object is masked from ‘package:ExperimentHub’:

    cache

The following object is masked from ‘package:AnnotationHub’:

    cache

The following object is masked from ‘package:rlang’:

    exprs

The following object is masked from ‘package:httr’:

    content

The following objects are masked from ‘package:matrixStats’:

    anyMissing, rowMedians

Loading required package: IRanges
Loading required package: S4Vectors

Attaching package: ‘S4Vectors’

The following object is masked from ‘package:clusterProfiler’:

    rename

The following object is masked from ‘package:plyr’:

    rename

The following object is masked from ‘package:rlist’:

    List

The following object is masked from ‘package:gplots’:

    space

The following objects are masked from ‘package:data.table’:

    first, second

The following objects are masked from ‘package:dplyr’:

    first, rename

The following objects are masked from ‘package:base’:

    expand.grid, I, unname


Attaching package: ‘IRanges’

The following object is masked from ‘package:clusterProfiler’:

    slice

The following object is masked from ‘package:plyr’:

    desc

The following object is masked from ‘package:data.table’:

    shift

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice


Attaching package: ‘AnnotationDbi’

The following object is masked from ‘package:clusterProfiler’:

    select

The following object is masked from ‘package:dplyr’:

    select



##############################################################################
Pathview is an open source software package distributed under GNU General
Public License version 3 (GPLv3). Details of GPLv3 is available at
http://www.gnu.org/licenses/gpl-3.0.html. Particullary, users are required to
formally cite the original Pathview paper (not just mention it) in publications
or products. For details, do citation("pathview") within R.

The pathview downloads and uses KEGG data. Non-academic uses may require a KEGG
license agreement (details at http://www.kegg.jp/kegg/legal.html).
##############################################################################

Attaching package: ‘enrichplot’

The following object is masked from ‘package:ggpubr’:

    color_palette
options(rgl.useNULL = F, ggrepel.max.overlaps = Inf)
#Load literature mining functions#
RetrieveEntrezID <- function(
    Homologues=FALSE,
    Homo_species=Homo_species,
    Par_species=Par_species,
    Par_species.Uniprot=Par_species.Uniprot,
    GenesLs=GenesLs,
    updateProgress = NULL
){
  attempt_max<-12
  #|----Set up Biomart parameters----|####
  Ann_0mart<-NULL
  attempt<-1
  while(is.null(Ann_0mart)&&attempt<attempt_max){
    if(attempt%in%seq(from=1,to=attempt_max,3)){
      url<-"https://useast.ensembl.org"
    }else if(attempt%in%seq(from=2,to=attempt_max,3)){
      url<-"https://www.ensembl.org"
    }else if(attempt%in%seq(from=3,to=attempt_max,3)){
      url<-"https://useast.ensembl.org/"
    }else if(attempt%in%seq(from=4,to=attempt_max,3)){
      url<-"https://asia.ensembl.org/"
    }
    try({
      Ann_0mart <- useMart("ENSEMBL_MART_ENSEMBL", host=url) %>%
        useDataset(Par_species, .)
    }, silent = TRUE)
    attempt<-attempt+1
    if(is.null(Ann_0mart)){Sys.sleep(0.5)}
  }
  if(Homologues){
    if (is.function(updateProgress)) {
      text <- paste0("Get Homologoeus Gene in ", Homo_species) 
      updateProgress(detail = text)
    }
    #listAttributes(Ann_0mart)%>%View()
    temp <- NULL
    attempt<-1
    while(is.null(temp)&&attempt<attempt_max){
      try({
        temp <- getBM(
          mart=Ann_0mart,
          attributes=c("ensembl_gene_id",
                       Homo_species),
          filter="ensembl_gene_id",
          values=GenesLs,
          uniqueRows = T)
      }, silent = TRUE)
      attempt<-attempt+1
      if(is.null(temp)){Sys.sleep(0.5)}
    }
    closeAllConnections()
    temp<-temp[!temp[,2]%in%"",]
    temp<-temp[!duplicated(temp[,2]),]
    NaMapping<-temp[,1]
    names(NaMapping)<-temp[,2]
    print(Homo_species)
    if(is_empty(temp)|nrow(temp)<1){
      return(NA)
    }
    #print("Set up Biomart parameters")
    #|----Set up Biomart parameters----|####
    if(Homo_species == "hsapiens_homolog_ensembl_gene"){
      Par_species <- "hsapiens_gene_ensembl"
    }else if(Homo_species == "mmusculus_homolog_ensembl_gene"){
      Par_species <- "mmusculus_gene_ensembl"
    }else if(Homo_species == "rnorvegicus_homolog_ensembl_gene"){
      Par_species <- "rnorvegicus_gene_ensembl"
    }else if(Homo_species == "sscrofa_homolog_ensembl_gene"){
      Par_species <- "sscrofa_gene_ensembl"
    }
    Ann_0mart<-NULL
    attempt<-1
    while(is.null(Ann_0mart)&&attempt<attempt_max){
      if(attempt%in%seq(from=1,to=attempt_max,3)){
        url<-"https://useast.ensembl.org"
      }else if(attempt%in%seq(from=2,to=attempt_max,3)){
        url<-"https://www.ensembl.org"
      }else if(attempt%in%seq(from=3,to=attempt_max,3)){
        url<-"https://useast.ensembl.org/"
      }else if(attempt%in%seq(from=4,to=attempt_max,3)){
        url<-"https://asia.ensembl.org/"
      }
      try({
        Ann_0mart <- useMart("ENSEMBL_MART_ENSEMBL", host=url) %>%
          useDataset(Par_species, .)
      }, silent = TRUE)
      attempt<-attempt+1
      if(is.null(Ann_0mart)){Sys.sleep(0.5)}
    }
    Anno_gene <- NULL
    attempt<-1
    while(is.null(Anno_gene)&&attempt<attempt_max){
      try({
        Anno_gene <- getBM(
          mart=Ann_0mart,
          attributes=c("ensembl_gene_id","entrezgene_id","gene_biotype",
                       "external_gene_name","description"),
          filter="ensembl_gene_id",
          values=temp[,2],
          uniqueRows = T)
      }, silent = TRUE)
      attempt<-attempt+1
      if(is.null(Anno_gene)){Sys.sleep(0.5)}
    }
    rm(temp)
  }else{
    print("getBM")
    if (is.function(updateProgress)) {
      text <- "Get PubMed Gene ID"
      updateProgress(detail = text)
    }
    Anno_gene <- NULL
    attempt<-1
    while(is.null(Anno_gene)&&attempt<attempt_max){
      try({
        Anno_gene <- getBM(
          mart=Ann_0mart,
          attributes=c("ensembl_gene_id","entrezgene_id","gene_biotype",
                       "external_gene_name","description"),
          filter="ensembl_gene_id",
          values=GenesLs,
          uniqueRows = T)
      }, silent = TRUE)
      attempt<-attempt+1
      if(is.null(Anno_gene)){Sys.sleep(0.5)}
    }
  }
  Anno<-Anno_gene[!duplicated(Anno_gene$ensembl_gene_id),]
  rownames(Anno)<-Anno$ensembl_gene_id
  Anno<-data.frame(
    ensembl_gene_id=Anno$ensembl_gene_id,
    entrezgene_id=Anno$entrezgene_id,
    external_gene_name=Anno$external_gene_name,
    gene_biotype=Anno$gene_biotype,
    row.names = rownames(Anno)
  )
  Anno2<-Anno[!is.na(Anno$entrezgene_id),] #For EntrezGeneID
  Anno2<-Anno2[!duplicated(Anno2[,'ensembl_gene_id']),] #For EntrezGeneID
  rownames(Anno2)<-Anno2$ensembl_gene_id
  temp<-Anno[is.na(Anno$entrezgene_id),"ensembl_gene_id"]
  print("Check EntrezGeneID again")
  #|----Check EntrezGeneID again----|####
  if(!is_empty(temp)){
    if(length(temp)<2){
      NCBIcheck<-read_html(
        paste0(
          "https://www.ncbi.nlm.nih.gov/gene/?term=",
          temp
        )
      )%>%xml_find_all(., ".//span")%>%xml_text()%>%
        grep("Gene ID",.,value = TRUE)
      if(!isEmpty(NCBIcheck)){
        NCBIcheck<-NCBIcheck%>%unlist()%>%
          str_extract_all(.,"(\\d)+")%>%.[[1]]%>%.[1]
      }else{
        NCBIcheck<-NA
      }
      out<-data.frame(
        ensembl_gene_id=temp,
        entrezgene_id=NCBIcheck
      )%>%as.data.frame()
      temp2<-out
    }else{
      Par_cl<-makeCluster(parallelly::freeConnections()-1)
      registerDoSNOW(Par_cl)
      Par_pb <- txtProgressBar(min=1, max=length(temp), style = 3)
      progress <- function(n) setTxtProgressBar(Par_pb, n)
      Par_opts<-list(progress = progress)
      #Refer here for all column names for Entrez API (https://www.ncbi.nlm.nih.gov/books/NBK25501/)
      temp2<-foreach(i=1:length(temp), .combine=rbind, .errorhandling = "pass", .inorder=FALSE,
                     .options.snow=Par_opts, .packages = c("dplyr","utils","xml2","S4Vectors","stringr","BiocGenerics")) %dopar% {
                       NCBIcheck<-read_html(
                         paste0(
                           "https://www.ncbi.nlm.nih.gov/gene/?term=",
                           temp[i]
                         )
                       )%>%xml_find_all(., ".//span")%>%xml_text()%>%
                         grep("Gene ID",.,value = TRUE)
                       if(!isEmpty(NCBIcheck)){
                         NCBIcheck<-NCBIcheck%>%unlist()%>%
                           str_extract_all(.,"(\\d)+")%>%.[[1]]%>%.[1]
                       }else{
                         NCBIcheck<-NA
                       }
                       out<-data.frame(
                         ensembl_gene_id=temp[i],
                         entrezgene_id=NCBIcheck
                       )%>%as.data.frame()
                       return(out)
                     }
      stopCluster(Par_cl)
    }
    temp2<-temp2[!is.na(temp2$entrezgene_id),]
    temp2<-temp2[!duplicated(temp2$ensembl_gene_id),]
    rownames(temp2)<-temp2$ensembl_gene_id
    temp2<-cbind(
      temp2,
      Anno[temp2$ensembl_gene_id,c(3:4)]
    )
    #sum(Anno2$ensembl_gene_id%in%temp2$ensembl_gene_id)==0
    Anno2<-rbind(
      Anno2,
      temp2
    )
  }
  if(Homologues){
    Anno2<-cbind(mapping=NaMapping[Anno2$ensembl_gene_id],Anno2)
    Anno2<-Anno2[!duplicated(Anno2$mapping),]
    rownames(Anno2) <- NaMapping[Anno2$ensembl_gene_id]
    Anno2<-Anno2[,-1]
  }
  print("end")
  if (is.function(updateProgress)) {
    text <- paste0("ID Convert Done ") 
    updateProgress(detail = text)
  }
  return(Anno2)
}

pseudoLog10 <- function(x){ asinh(x/2)/log(10) }

WZY_GetSummaryText<-function(p){
  pdata <- data.frame(name = p$data$label, color2 = p$data$group)
  pdata <- pdata[!is.na(pdata$name), ]
  cluster_color <- unique(pdata$color2)
  
  cluster_label <- sapply(
    cluster_color, enrichplot:::get_wordcloud,
    ggData = pdata, nWords = 4
  ) %>% paste0(.,collapse = " ") %>% str_split(., " ") %>% unlist()
  return(cluster_label)
}

WZY_literatureMining<-function(GenesLs=GenesLs, Mesh_term4Interesting=Mesh_term4Interesting, Species=Species, updateProgress = NULL){
  out<-list()
  N<-paste0(#To search for the total number of PubMed citations, enter all[sb] in the search box.(20210506)
    "https://pubmed.ncbi.nlm.nih.gov/?term=",
    URLencode('all[sb]'),
    "&sort=date"
  )%>%read_html()%>%html_nodes(".value")%>%html_text()%>%.[1]%>%gsub(",","",.)%>%as.numeric()
  K<-paste0(#the amounts of literature related to osteoblast differentiation #20210506# PubMed Query: 
    "https://pubmed.ncbi.nlm.nih.gov/?term=",
    URLencode(Mesh_term4Interesting),
    "&sort=date"
  )%>%read_html()%>%html_nodes(".value")%>%html_text()%>%.[1]%>%gsub(",","",.)%>%as.numeric()
  Thresh<-K/N*10
  
  ####|prepare gene-related articles|####
  # hsapiens_gene_ensembl; mmusculus_gene_ensembl; rnorvegicus_gene_ensembl; sscrofa_gene_ensembl
  # Homo sapiens (Human) [9606]; Mus musculus (Mouse) [10090]; Rattus norvegicus (rat) [10116]; Sus scrofa (pig) [9823]
  # (human) Homo sapiens (human) [hsa]; (mouse) Mus musculus (mouse) [mmu]; (rat) Rattus norvegicus [rno]; (pig) Sus scrofa [ssc]
  # hsapiens_homolog_ensembl_gene; mmusculus_homolog_ensembl_gene; rnorvegicus_homolog_ensembl_gene; sscrofa_homolog_ensembl_gene
  print(GenesLs)
  print(Mesh_term4Interesting)
  print(Species)
  if (is.function(updateProgress)) {
    text <- "Get All Homologoeus Genes"
    updateProgress(detail = text)
  }
  if(Species == "Hsa"){
    Par_species <- "hsapiens_gene_ensembl"
    Par_species.Uniprot <- "9606"
    Homo_species <- c(
      "mmusculus_homolog_ensembl_gene",
      "rnorvegicus_homolog_ensembl_gene",
      "sscrofa_homolog_ensembl_gene"
    )
  }else if(Species == "Mus"){
    Par_species <- "mmusculus_gene_ensembl"
    Par_species.Uniprot <- "10090"
    Homo_species <- c(
      "hsapiens_homolog_ensembl_gene",
      "rnorvegicus_homolog_ensembl_gene",
      "sscrofa_homolog_ensembl_gene"
    )
  }else if(Species == "Rno"){
    Par_species <- "rnorvegicus_gene_ensembl"
    Par_species.Uniprot <- "10116"
    Homo_species <- c(
      "mmusculus_homolog_ensembl_gene",
      "hsapiens_homolog_ensembl_gene",
      "sscrofa_homolog_ensembl_gene"
    )
  }else if(Species == "Ssc"){
    Par_species <- "sscrofa_gene_ensembl"
    Par_species.Uniprot <- "9823"
    Homo_species <- c(
      "mmusculus_homolog_ensembl_gene",
      "rnorvegicus_homolog_ensembl_gene",
      "hsapiens_homolog_ensembl_gene"
    )
  }
  print(Par_species)
  print(Par_species.Uniprot)
  query.res<-RetrieveEntrezID(Par_species=Par_species, Par_species.Uniprot=Par_species.Uniprot, GenesLs=GenesLs)
  homologeus1 <- RetrieveEntrezID(
    Homologues=TRUE, Homo_species=Homo_species[1], Par_species=Par_species,
    Par_species.Uniprot=Par_species.Uniprot, GenesLs=GenesLs, updateProgress = updateProgress
  )
  homologeus2 <- RetrieveEntrezID(
    Homologues=TRUE, Homo_species=Homo_species[2], Par_species=Par_species,
    Par_species.Uniprot=Par_species.Uniprot, GenesLs=GenesLs, updateProgress = updateProgress
  )
  homologeus3 <- RetrieveEntrezID(
    Homologues=TRUE, Homo_species=Homo_species[3], Par_species=Par_species,
    Par_species.Uniprot=Par_species.Uniprot, GenesLs=GenesLs, updateProgress = updateProgress
  )
  
  #Calculate results and construct the literature mining table
  literature.mining<-data.frame(matrix(nrow = 0, ncol=14))
  colnames(literature.mining)<-c("ensembl_gene_id","entrezgene_id","GeneSymbol",
                                 "gene_biotype", "N", "K", "n", "k", "R", "10x Background of R","P.value",
                                 "Gene related PMID", "Overlapped PMID", "Overlapped Genes [Article No]")
  # Par_pb <- txtProgressBar(min=1, max=nrow(query.res), style = 3)
  print("StartLoop")
  list.packages <- c(
    "readxl", "ggplot2", "ggpubr", "matrixStats", "ggrepel", "reshape2", "dplyr", "stringr",
    "grid", "tcltk", "parallel", "doParallel", "doSNOW", "data.table", "gplots",
    "randomcoloR", "factoextra", "RColorBrewer", "grDevices", "gmp", "xtable", "latex2exp",
    "httr", "jsonlite", "curl", "RCurl", "magrittr", "rlist", "pipeR", "plyr",
    "xml2", "rvest", "knn.covertree", "knitr", "rlang", "visNetwork", "hwriter", "htmltools"
  )
  bio.list.packages <- c(
    "limma", "ExperimentHub", "clusterProfiler", "GO.db",
    "org.Mm.eg.db", "pathview", "enrichplot", "org.Hs.eg.db"
  )
  wzy_mainloop <- function(
    query.res = query.res, attempt_max = 5, Thresh = Thresh,
    K = K, N = N, i = i
  ){
    GeneID<-c(
      query.res$entrezgene_id[i],
      homologeus1[query.res$ensembl_gene_id[i],"entrezgene_id"],
      homologeus2[query.res$ensembl_gene_id[i],"entrezgene_id"],
      homologeus3[query.res$ensembl_gene_id[i],"entrezgene_id"]
    )
    #### Calculate n
    # Get UID number that within interested MeSH term
    uid.res<-c()
    for(a in GeneID){
      # Retrieve PMID of gene-related articles
      # https://www.ncbi.nlm.nih.gov/books/NBK25497/table/chapter2.T._entrez_unique_identifiers_ui/?report=objectonly
      # https://www.ncbi.nlm.nih.gov/books/NBK25499/
      # https://dataguide.nlm.nih.gov/eutilities/utilities.html
      # https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi?dbfrom=gene&db=pubmed&id=68389&linkname=homologene_pubmed
      # https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi?dbfrom=gene&db=pubmed&id=12393
      URL_temp<-NULL
      attempt<-1
      url <- paste0(
        "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi?dbfrom=gene&db=pubmed&id=",
        a
      )
      while(is.null(URL_temp)&&attempt<attempt_max){
        try({
          url <- url(url, "rb")
          if(class(url)[1]=="url"){
            URL_temp <- read_xml(
              url
            )%>%xml_find_all(., ".//Id")%>%xml_text()
            close(url)
          }
        }, silent = TRUE)
        attempt<-attempt+1
        if(is.null(URL_temp)){Sys.sleep(round(runif(1,10,180),1))}
      }
      uid.res<-c(
        uid.res,
        URL_temp
      )
    }
    uid.res<-unique(uid.res)
    n<-length(uid.res)
    #### Calculate k
    maxlimit<-125
    if(n>maxlimit){
      step<-n%/%maxlimit
      mod<-n%%maxlimit
      start<-seq(from=1, to=maxlimit*step, by=maxlimit)
      end<-seq(from=maxlimit, to=maxlimit*step, by=maxlimit)
      if(mod>0){
        start<-c(start, tail(end, 1)+1)
        end<-c(end, n)
      }
      step<-length(start)
    }else{
      step<-1
      start<-1
      end<-n
    }
    k<-0
    overlapped.uid<-c()
    for(a in 1:step){
      URL_temp<-NULL
      attempt<-1
      url <- URLencode(
        paste0(
          "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=",
          paste(uid.res[start[a]:end[a]],collapse=","),"[UID]+AND+(",URLencode(Mesh_term4Interesting),")",
          "&rettype=count"
        )
      )
      while(is.null(URL_temp)&&attempt<attempt_max){
        try({
          url <- url(url, "rb")
          if(class(url)[1]=="url"){
            URL_temp <- read_xml(#the amounts of articles of each gene on interested MeSH term:
              url
            )%>%xml_find_all(., ".//Count")%>%xml_text()%>%.[1]%>%as.numeric()
            close(url)
          }
        }, silent = TRUE)
        attempt<-attempt+1
        if(is.null(URL_temp)){Sys.sleep(round(runif(1,10,180),1))}
      }
      if(is.null(URL_temp)){URL_temp <- 0}
      k<-k+URL_temp
      URL_temp<-NULL
      attempt<-1
      url <- URLencode(
        paste0(
          "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=",
          paste(uid.res[start[a]:end[a]],collapse=","),"[UID]+AND+(",URLencode(Mesh_term4Interesting),")",
          "&rettype=unlist"
        )
      )
      while(is.null(URL_temp)&&attempt<attempt_max){
        try({
          url <- url(url, "rb")
          if(class(url)[1]=="url"){
            URL_temp <- read_xml(#the amounts of articles of each gene on interested MeSH term:
              url
            )%>%xml_find_all(., ".//Id")%>%xml_text()
            close(url)
          }
        }, silent = TRUE)
        attempt<-attempt+1
        if(is.null(URL_temp)){Sys.sleep(round(runif(1,10,180),1))}
      }
      overlapped.uid<-c(
        overlapped.uid,
        URL_temp
      )
    }
    if(is.na(k)){k<-0}
    #### Calculate P
    R<-k/n
    P<-0
    if(k<1){
      P<-0
    }else{
      for (a in 0:(k-1)) {
        P<-P+((chooseZ(K,a)*chooseZ(N-K,n-a))/chooseZ(N,n))
      }
    }
    P<-asNumeric(1-P)
    if(P==0){P<-1*10^-300}
    temp<-data.frame(
      ensembl_gene_id=query.res$ensembl_gene_id[i],
      entrezgene_id=query.res$entrezgene_id[i],
      GeneSymbol=query.res$external_gene_name[i],
      gene_biotype=query.res$gene_biotype[i],
      N=N,K=K,n=n,k=k,R=R,Thresh=Thresh,P=P,
      GenePMID=uid.res%>%paste(.,collapse = ","),
      OverlapPMID=overlapped.uid%>%paste(.,collapse = ",")
    )
    colnames(temp)<-c("ensembl_gene_id","entrezgene_id","GeneSymbol",
                      "gene_biotype", "N", "K", "n", "k", "R", "10x Background of R","P.value",
                      "Gene related PMID", "Overlapped PMID")
    return(temp)
  }
  Par_cl<-makeCluster(parallelly::freeConnections()-2)
  registerDoSNOW(Par_cl)
  Par_pb <- txtProgressBar(min=1, max=nrow(query.res), style = 3)
  progress <- function(n) setTxtProgressBar(Par_pb, n)
  Par_opts<-list(progress = progress)
  #Refer here for all column names for Entrez API (https://www.ncbi.nlm.nih.gov/books/NBK25501/)
  temp<-foreach(
    i=1:nrow(query.res), .combine=rbind, .errorhandling = "remove", .inorder=FALSE, .verbose = FALSE,
    .options.snow=Par_opts, .packages = c(list.packages, bio.list.packages)
  ) %dopar% {
    temp3 <- NULL
    temp3 <- wzy_mainloop(query.res = query.res, attempt_max = 5, Thresh = Thresh, K = K, N = N, i = i)
    if(is.null(temp3)){
      temp3<-data.frame(
        ensembl_gene_id=query.res$ensembl_gene_id[i],
        entrezgene_id=query.res$entrezgene_id[i],
        GeneSymbol=query.res$external_gene_name[i],
        gene_biotype=query.res$gene_biotype[i],
        N=NA,K=NA,n=NA,k=NA,R=NA,Thresh=NA,P=NA,
        GenePMID=NA,
        OverlapPMID=NA
      )
      colnames(temp3)<-c("ensembl_gene_id","entrezgene_id","GeneSymbol",
                         "gene_biotype", "N", "K", "n", "k", "R", "10x Background of R","P.value",
                         "Gene related PMID", "Overlapped PMID")
    }
    return(temp3)
  }
  stopCluster(Par_cl)
  literature.mining<-rbind(literature.mining,temp)
  rm(temp)
  gc()
  print("EndLoop")
  #Correcting P-value for multiple testing
  literature.mining<-cbind(literature.mining[,1:11], 
                           p.adj=p.adjust(as.numeric(literature.mining$P.value),method = "BH"),
                           literature.mining[,12:13])
  out<-list(
    literature.mining=literature.mining,
    query.res=query.res,
    homologeus1=homologeus1,
    homologeus2=homologeus2,
    homologeus3=homologeus3
  )
  print("end")
  return(out)
}

literatureMiningPlot<-function(
    literature.mining=out$literature.mining, Thresh.R=NULL,
    use.Padj = FALSE, Thresh.P=0.05, label=TRUE, label_n=5
){
  # print("Plotting")
  # Plotting Results
  literature.mining$n<-as.numeric(literature.mining$n)
  literature.mining$k<-as.numeric(literature.mining$k)
  literature.mining$R<-as.numeric(literature.mining$R)
  if(is.null(Thresh.R)){
    Thresh<-literature.mining$`10x Background of R`[1]
  }else{
    Thresh<-Thresh.R
  }
  df<-literature.mining[,1:12] 
  df$R<-df$R*1000
  df$n<-log10(df$n)
  df$R<-pseudoLog10(df$R)
  df$p.adj<-pseudoLog10(log(1/df$p.adj,2))
  df$P.value<-pseudoLog10(log(1/df$P.value,2))
  df <- df[order(df$P.value), ]
  maxR<-(max(df$R, na.rm=T)+0.3)%>%round(., digits = 1)
  maxP<-(max(df$p.adj, na.rm=T)+0.3)%>%round(., digits = 1)
  RepL_R<-length(rep(0:maxR, each = 9))%/%9
  RepL_P<-length(rep(0:maxP, each = 9))%/%9
  if(use.Padj){
    gplot<-ggplot(df,aes(x=p.adj, y=R, colour=n, size=k ))
  }else{
    gplot<-ggplot(df,aes(x=P.value, y=R, colour=n, size=k ))
  }
  gplot<-gplot +
    geom_point() +
    expand_limits(x=0) +
    scale_y_continuous(
      limits = c(0,maxR),
      breaks = 0:maxR,
      guide = "prism_offset_minor",
      minor_breaks = pseudoLog10(rep(1:9, RepL_R)*(10^rep(0:maxR, each = 9))),
      labels =  function(lab){
        do.call(
          expression,
          lapply(paste(lab), function(x) {
            if(x==0){bquote(bold("0"))}else{bquote(bold("10"^.(x)))}
          })
        )
      }
    )+
    scale_x_continuous(
      limits = c(0,maxP),
      breaks = 0:maxP,
      guide = "prism_offset_minor",
      minor_breaks = pseudoLog10(rep(1:9, RepL_P)*(10^rep(0:maxP, each = 9))),
      labels = function(lab){
        do.call(
          expression,
          lapply(paste(lab), function(x) {
            if(x==0){bquote(bold("0"))}else{bquote(bold("10"^.(x)))}
          })
        )
      }
    )+
    scale_size(range = c(0,20))+
    theme(
      axis.text=element_text(size=12),
      axis.title=element_text(size=14,face="bold"),
      axis.ticks.length = unit(5,"pt"),
      axis.ticks = element_line(size = 0.7),
    )+
    coord_cartesian(clip = "off")+
    geom_hline(yintercept=pseudoLog10(Thresh*1000), linetype="dashed", 
               color = "red", size=0.4)+
    geom_vline(xintercept=pseudoLog10(log(1/Thresh.P,2)), linetype="dashed", 
               color = "red", size=0.4)+
    labs(x="log2(1/P.value)", 
         y="R (‰)", 
         title="",
         colour="log10(Gene Related Articles No.)", size="Topics\nRelated Articles No.")+
    annotation_custom(
      grob = grid::linesGrob(gp=gpar(lwd=2)),
      xmin = -Inf,
      xmax = -Inf,
      ymin = 0,
      ymax = maxR
    )+
    annotation_custom(
      grob = grid::linesGrob(gp=gpar(lwd=2)),
      xmin = 0,
      xmax = maxP,
      ymin = -Inf,
      ymax = -Inf
    )
  #print("PlottingEnd")
  if(label_n == "All"){
    label_n <- nrow(df) 
  }
  if(label){
    if(use.Padj){
      df <- df[df$R>=pseudoLog10(Thresh*1000) & df$p.adj>=pseudoLog10(log(1/Thresh.P,2)), ]
    }else{
      df <- df[df$R>=pseudoLog10(Thresh*1000) & df$P.value>=pseudoLog10(log(1/Thresh.P,2)), ]
    }
    df <- df[order(df$P.value, decreasing = TRUE), ]
    gplot <- gplot + geom_text_repel(
      data = df[1:label_n, ],
      aes(label=GeneSymbol),hjust=0, vjust=0, size=8, color="darkred"
    )
  }
  return(gplot)
}

literatureMiningOverlappedGenes<-function(out, updateProgress = NULL){
  
  literature.mining<-out$literature.mining
  query.res<-out$query.res
  homologeus1<-out$homologeus1
  homologeus2<-out$homologeus2
  homologeus3<-out$homologeus3
  
  outls<-c()
  
  for(i in 1:nrow(query.res)){
    print(paste0(i,"/",nrow(query.res)))
    if (is.function(updateProgress)) {
      text <- paste0(i," in ",nrow(query.res))
      updateProgress(message = text, detail = text)
    }
    GeneID<-c(
      query.res$entrezgene_id[i],
      homologeus1[query.res$ensembl_gene_id[i],"entrezgene_id"],
      homologeus2[query.res$ensembl_gene_id[i],"entrezgene_id"],
      homologeus3[query.res$ensembl_gene_id[i],"entrezgene_id"]
    )%>%.[!is.na(.)]
    
    overlapped.uid<-literature.mining$`Overlapped PMID`[i]%>%str_split(.,",")%>%unlist()
    
    overlapped.genes<-data.frame(matrix(nrow = 0, ncol=3))
    colnames(overlapped.genes)<-c("GeneSymbol","entrezgene_id","Overlapped_PMID")
    if(overlapped.uid[1]!=""){
      
      for(uid in overlapped.uid){
        
        print(paste0("PMID:", uid, " (", which(overlapped.uid==uid)," of ",length(overlapped.uid), ")"))
        temp.gene<-read_xml(
          paste0(
            "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi?dbfrom=pubmed&db=gene&id=",
            uid
          )
        )%>%xml_find_all(., ".//Id")%>%xml_text()%>%.[-1]%>%unique()%>%.[!.%in%GeneID]
        
        if(is_empty(temp.gene)){next}
        if(length(temp.gene)>500){next}
        
        a.n<-length(temp.gene)
        maxlimit<-50
        if(a.n>maxlimit){
          step<-a.n%/%maxlimit
          mod<-a.n%%maxlimit
          start<-seq(from=1, to=maxlimit*step, by=maxlimit)
          end<-seq(from=maxlimit, to=maxlimit*step, by=maxlimit)
          if(mod>0){
            start<-c(start, tail(end, 1)+1)
            end<-c(end, a.n)
          }
          step<-length(start)
        }else{
          step<-1
          start<-1
          end<-a.n
        }
        
        if(step>1){
          pb <- txtProgressBar(min=1, max=step, style = 3)
        }
        
        removeIdx<-c()
        GeneSymbol<-c()
        for(a in 1:step){
          #print(paste0("b:",which(temp.gene==b),";",length(temp.gene)))
          GSB<-read_html(
            paste0(
              "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=gene&id=",
              temp.gene[start[a]:end[a]]%>%paste(.,collapse = ","),
              "&rettype=unlist"
            )
          )
          lh<-(end[a]-start[a]+1)
          if(lh==1){
            test<-xml_child(xml_child(xml_child(xml_child(xml_child(GSB, 1), 1), 1), 1), 2)%>%xml_text()%>%grep("Official Symbol:",.)
            if(!is_empty(test)){
              GeneSymbol<-c(
                GeneSymbol,
                xml_child(xml_child(xml_child(xml_child(xml_child(xml_child(xml_child(GSB, 1), 1), 1), 1), 2), 2), 2)%>%xml_text()
              )
            }else{
              removeIdx<-c(
                removeIdx,1
              )
            }
          }else{
            for(b in 1:lh){
              test<-xml_child(xml_child(xml_child(xml_child(xml_child(GSB, 1), 1), 1), b), 2)%>%xml_text()%>%grep("Official Symbol:",.)
              if(!is_empty(test)){
                GeneSymbol<-c(
                  GeneSymbol,
                  xml_child(xml_child(xml_child(xml_child(xml_child(xml_child(xml_child(xml_child(GSB, 1), 1), 1), b), 2), 2), 2), 2)%>%xml_text()
                )
              }else{
                removeIdx<-c(
                  removeIdx,(b+start[a]-1)
                )
              }
            }
          }
          
          if(step>1){
            setTxtProgressBar(pb, a)
          }
          if(is.function(updateProgress)) {
            text <- paste0(a," in ",step)
            updateProgress(message = paste0(i," in ",nrow(query.res)), detail = text)
          }
        }
        if(step>1){close(pb)}
        if(!is_empty(removeIdx)){
          temp.gene<-temp.gene[-removeIdx]
        }
        
        if(!is_empty(temp.gene)){
          temp<-data.frame(
            GeneSymbol=GeneSymbol%>%str_to_title(),
            entrezgene_id=temp.gene,
            Overlapped_PMID=rep(uid,length(temp.gene))
          )
          overlapped.genes<-rbind(
            overlapped.genes,
            temp
          )
        }
      }
    }
    
    temp<-c()
    OrderID<-c()
    for(a in overlapped.genes$GeneSymbol%>%unique()){
      temp2<-overlapped.genes[overlapped.genes$GeneSymbol==a,]
      OrderID<-c(
        OrderID,
        length(temp2$Overlapped_PMID%>%unique())
      )
      temp<-c(
        temp,
        paste0(
          temp2$GeneSymbol[1],
          " (EntrezID:", temp2$entrezgene_id[1], ";",
          "Overlapped_PMID[", tail(OrderID,1), "]:", paste(temp2$Overlapped_PMID%>%unique(),collapse = ","),")" 
        )
      )
    }
    OrderID<-as.numeric(OrderID)
    OrderID<-order(x=OrderID, decreasing=TRUE, na.last=T)
    overlapped.genes<-temp%>%.[OrderID]%>%paste(.,collapse = " ")
    outls<-c(
      outls,overlapped.genes
    )
  }
  
  overlapped.genes<-cbind(
    literature.mining[,1:4],
    overlapped.genes=outls
  )
  
  return(overlapped.genes)
  
}
library(rlang)
library(ggprism)

01. Literature-mining

Get the target genes of the final 10 TFs in the gene regulatory network.

Targets <- c()
for (i in TFs.Mesh.keep$GeneSymbol) {
  Targets <- c(
    Targets,
    TFLink$NCBI.GeneID.Target[TFLink$Name.TF %in% i] %>% str_split(., ";") %>% 
      unlist() %>% as.vector() %>% unique() %>% {.[.[]!="-"]}
  )
}
Targets <- table(Targets) %>% as.data.frame()
Targets <- Targets[Targets$Freq > 7, ]
colnames(Targets) <- c("ENTREZID", "Freq")
Anno <- select(org.Hs.eg.db, keys = as.character(Targets$ENTREZID), columns = c("ENTREZID", "ENSEMBL", "SYMBOL"), keytype = "ENTREZID")
'select()' returned 1:many mapping between keys and columns
Anno <- Anno[!duplicated(Anno$ENTREZID),]
Targets <- merge(Targets, Anno, by="ENTREZID")
Targets <- Targets[order(Targets$Freq, decreasing = TRUE),]
rownames(Targets)<-c(1:nrow(Targets)) %>% as.character()
head(Targets,10)

Now let’s get the targets related to both Mitochondria and Endoplasmic Reticulum

Mesh_term4Interesting <- '"Mitochondria"[Mesh] AND "Endoplasmic Reticulum"[Mesh]'
GenesLs <- Targets$ENSEMBL
Species <- "Hsa" # Hsa Mus Rno Ssc
Targets.Mesh<-WZY_literatureMining(GenesLs=GenesLs, Mesh_term4Interesting=Mesh_term4Interesting, Species=Species, updateProgress = NULL)

   [1] "ENSG00000173334" "ENSG00000023330" "ENSG00000132326" "ENSG00000101473" "ENSG00000113552" "ENSG00000229833" "ENSG00000249915" "ENSG00000213999"
   [9] "ENSG00000251201" "ENSG00000232838" "ENSG00000248643" "ENSG00000215472" "ENSG00000270757" "ENSG00000259112" "ENSG00000288602" "ENSG00000163156"
  [17] "ENSG00000033050" "ENSG00000140497" "ENSG00000111229" "ENSG00000115091" "ENSG00000145337" "ENSG00000095906" "ENSG00000169018" "ENSG00000115073"
  [25] "ENSG00000122644" "ENSG00000126602" "ENSG00000145907" "ENSG00000214160" "ENSG00000131467" "ENSG00000124383" "ENSG00000167186" "ENSG00000102738"
  [33] "ENSG00000136933" "ENSG00000136807" "ENSG00000115145" "ENSG00000116752" "ENSG00000103507" "ENSG00000174446" "ENSG00000140743" "ENSG00000118680"
  [41] "ENSG00000133027" "ENSG00000239306" "ENSG00000120992" "ENSG00000187778" "ENSG00000143575" "ENSG00000171960" "ENSG00000104980" "ENSG00000167863"
  [49] "ENSG00000140396" "ENSG00000172977" "ENSG00000149428" "ENSG00000107959" "ENSG00000135624" "ENSG00000115163" "ENSG00000175550" "ENSG00000112667"
  [57] "ENSG00000183751" "ENSG00000186141" "ENSG00000101608" "ENSG00000265972" "ENSG00000111247" "ENSG00000128654" "ENSG00000120063" "ENSG00000156261"
  [65] "ENSG00000145979" "ENSG00000168883" "ENSG00000134262" "ENSG00000066923" "ENSG00000065911" "ENSG00000184640" "ENSG00000188747" "ENSG00000104881"
  [73] "ENSG00000117877" "ENSG00000174851" "ENSG00000135148" "ENSG00000113649" "ENSG00000006634" "ENSG00000086598" "ENSG00000169223" "ENSG00000255154"
  [81] "ENSG00000083807" "ENSG00000099203" "ENSG00000182134" "ENSG00000125868" "ENSG00000284917" "ENSG00000160207" "ENSG00000105323" "ENSG00000163684"
  [89] "ENSG00000111615" "ENSG00000148606" "ENSG00000147475" "ENSG00000198554" "ENSG00000104814" "ENSG00000110721" "ENSG00000197150" "ENSG00000183765"
  [97] "ENSG00000143507" "ENSG00000114686" "ENSG00000136942" "ENSG00000170881" "ENSG00000177239" "ENSG00000101417" "ENSG00000168488" "ENSG00000161013"
 [105] "ENSG00000140006" "ENSG00000166788" "ENSG00000198231" "ENSG00000063244" "ENSG00000163312" "ENSG00000167700" "ENSG00000285292" "ENSG00000141447"
 [113] "ENSG00000133466" "ENSG00000148225" "ENSG00000099622" "ENSG00000158246" "ENSG00000142459" "ENSG00000158717" "ENSG00000243667" "ENSG00000153989"
 [121] "ENSG00000159445" "ENSG00000223496" "ENSG00000011021" "ENSG00000179988" "ENSG00000148690" "ENSG00000166275" "ENSG00000188603" "ENSG00000170946"
 [129] "ENSG00000074201" "ENSG00000139370" "ENSG00000197837" "ENSG00000157837" "ENSG00000180008" "ENSG00000166455" "ENSG00000158545" "ENSG00000141371"
 [137] "ENSG00000167740" "ENSG00000177150" "ENSG00000143458" "ENSG00000143353" "ENSG00000203705" "ENSG00000197296" "ENSG00000167037" "ENSG00000158411"
 [145] "ENSG00000160124" "ENSG00000122218" "ENSG00000057019" "ENSG00000067082" "ENSG00000156110" "ENSG00000189308" "ENSG00000157426" "ENSG00000189007"
 [153] "ENSG00000168303" "ENSG00000080819" "ENSG00000180938" "ENSG00000111269" "ENSG00000148331" "ENSG00000132801" "ENSG00000149646" "ENSG00000197530"
 [161] "ENSG00000182359" "ENSG00000179119" "ENSG00000213920" "ENSG00000175662" "ENSG00000167302" "ENSG00000244045" "ENSG00000197380" "ENSG00000143578"
 [169] "ENSG00000044115" "ENSG00000100209" "ENSG00000173163" "ENSG00000177917" "ENSG00000257923" "ENSG00000184178" "ENSG00000164463" "ENSG00000151304"
 [177] "ENSG00000184661" "ENSG00000168672" "ENSG00000132549" "ENSG00000166348" "ENSG00000179588" "ENSG00000173875" "ENSG00000162852" "ENSG00000166747"
 [185] "ENSG00000177683" "ENSG00000182903" "ENSG00000102967" "ENSG00000131504" "ENSG00000119689" "ENSG00000079805" "ENSG00000108591" "ENSG00000136827"
 [193] "ENSG00000169016" "ENSG00000247077" "ENSG00000143486" "ENSG00000189079" "ENSG00000111361" "ENSG00000166262" "ENSG00000161960" "ENSG00000063046"
 [201] "ENSG00000009780" "ENSG00000158711" "ENSG00000221944" "ENSG00000185909" "ENSG00000154803" "ENSG00000205208" "ENSG00000119231" "ENSG00000140009"
 [209] "ENSG00000171503" "ENSG00000158169" "ENSG00000169710" "ENSG00000156603" "ENSG00000197345" "ENSG00000166199" "ENSG00000165487" "ENSG00000197037"
 [217] "ENSG00000146776" "ENSG00000128536" "ENSG00000180233" "ENSG00000135775" "ENSG00000181789" "ENSG00000143033" "ENSG00000107864" "ENSG00000164715"
 [225] "ENSG00000126775" "ENSG00000179912" "ENSG00000100442" "ENSG00000047056" "ENSG00000132680" "ENSG00000099246" "ENSG00000080371" "ENSG00000135108"
 [233] "ENSG00000127663" "ENSG00000077254" "ENSG00000111206" "ENSG00000174306" "ENSG00000103351" "ENSG00000180357" "ENSG00000133789" "ENSG00000160208"
 [241] "ENSG00000102763" "ENSG00000100354" "ENSG00000143442" "ENSG00000074755" "ENSG00000109184" "ENSG00000100304" "ENSG00000089902" "ENSG00000169180"
 [249] "ENSG00000117523" "ENSG00000119042" "ENSG00000074054" "ENSG00000091157" "ENSG00000139641" "ENSG00000156931" "ENSG00000162402" "ENSG00000198952"
 [257] "ENSG00000162736" "ENSG00000015676" "ENSG00000011376" "ENSG00000181274" "ENSG00000096717" "ENSG00000120948" "ENSG00000094916" "ENSG00000105755"
 [265] "ENSG00000072121" "ENSG00000039123" "ENSG00000156650" "ENSG00000114331" "ENSG00000113638" "ENSG00000110880" "ENSG00000075975" "ENSG00000101040"
 [273] "ENSG00000133265" "ENSG00000014138" "ENSG00000196652" "ENSG00000104205" "ENSG00000109919" "ENSG00000166997" "ENSG00000198793" "ENSG00000119537"
 [281] "ENSG00000177311" "ENSG00000133065" "ENSG00000171298" "ENSG00000155714" "ENSG00000214212" "ENSG00000161860" "ENSG00000234545" "ENSG00000110844"
 [289] "ENSG00000054611" "ENSG00000151014" "ENSG00000137094" "ENSG00000137207" "ENSG00000114098" "ENSG00000141012" "ENSG00000176225" "ENSG00000130935"
 [297] "ENSG00000038219" "ENSG00000117697" "ENSG00000129493" "ENSG00000117614" "ENSG00000214013" "ENSG00000178188" "ENSG00000129460" "ENSG00000198862"
 [305] "ENSG00000004142" "ENSG00000119599" "ENSG00000181722" "ENSG00000101181" "ENSG00000164880" "ENSG00000123505" "ENSG00000118564" "ENSG00000106336"
 [313] "ENSG00000114023" "ENSG00000148200" "ENSG00000100575" "ENSG00000057608" "ENSG00000137040" "ENSG00000105856" "ENSG00000105821" "ENSG00000117597"
 [321] "ENSG00000197157" "ENSG00000172167" "ENSG00000105289" "ENSG00000169230" "ENSG00000265491" "ENSG00000068912" "ENSG00000076321" "ENSG00000173905"
 [329] "ENSG00000178982" "ENSG00000120800" "ENSG00000100294" "ENSG00000197045" "ENSG00000114353" "ENSG00000172354" "ENSG00000176422" "ENSG00000171262"
 [337] "ENSG00000174109" "ENSG00000182173" "ENSG00000120071" "ENSG00000224877" "ENSG00000181035" "ENSG00000174151" "ENSG00000155744" "ENSG00000144455"
 [345] "ENSG00000154813" "ENSG00000169570" "ENSG00000205765" "ENSG00000164304" "ENSG00000146223" "ENSG00000156831" "ENSG00000156162" "ENSG00000173611"
 [353] "ENSG00000125388" "ENSG00000198055" "ENSG00000087884" "ENSG00000177646" "ENSG00000133315" "ENSG00000156802" "ENSG00000168228" "ENSG00000123545"
 [361] "ENSG00000133773" "ENSG00000137547" "ENSG00000113360" "ENSG00000070761" "ENSG00000161526" "ENSG00000167522" "ENSG00000188342" "ENSG00000111358"
 [369] "ENSG00000122034" "ENSG00000025770" "ENSG00000071894" "ENSG00000164548" "ENSG00000110025" "ENSG00000111727" "ENSG00000147164" "ENSG00000135018"
 [377] "ENSG00000141873" "ENSG00000136856" "ENSG00000172638" "ENSG00000196455" "ENSG00000175449" "ENSG00000135486" "ENSG00000092199" "ENSG00000104824"
 [385] "ENSG00000174775" "ENSG00000126457" "ENSG00000114315" "ENSG00000089685" "ENSG00000080824" "ENSG00000115541" "ENSG00000204237" "ENSG00000185298"
 [393] "ENSG00000198520" "ENSG00000224470" "ENSG00000137434" "ENSG00000174177" "ENSG00000120253" "ENSG00000132740" "ENSG00000239521" "ENSG00000198931"
 [401] "ENSG00000143621" "ENSG00000153487" "ENSG00000134910" "ENSG00000128928" "ENSG00000219626" "ENSG00000172244" "ENSG00000188177" "ENSG00000124208"
 [409] "ENSG00000188811" "ENSG00000189114" "ENSG00000162460" "ENSG00000163155" "ENSG00000163170" "ENSG00000178385" "ENSG00000188186" "ENSG00000183808"
 [417] "ENSG00000175220" "ENSG00000169756" "ENSG00000197136" "ENSG00000077454" "ENSG00000254996" "ENSG00000135387" "ENSG00000162385" "ENSG00000143384"
 [425] "ENSG00000128590" "ENSG00000146701" "ENSG00000198625" "ENSG00000213999" "ENSG00000027001" "ENSG00000076242" "ENSG00000006432" "ENSG00000173327"
 [433] "ENSG00000020426" "ENSG00000198356" "ENSG00000204869" "ENSG00000085760" "ENSG00000167508" "ENSG00000136997" "ENSG00000189043" "ENSG00000004779"
 [441] "ENSG00000099795" "ENSG00000147684" "ENSG00000158864" "ENSG00000185721" "ENSG00000198755" "ENSG00000100968" "ENSG00000158793" "ENSG00000069849"
 [449] "ENSG00000213281" "ENSG00000198836" "ENSG00000048392" "ENSG00000168092" "ENSG00000158006" "ENSG00000106366" "ENSG00000135241" "ENSG00000197457"
 [457] "ENSG00000173599" "ENSG00000144034" "ENSG00000134970" "ENSG00000067533" "ENSG00000163319" "ENSG00000162191" "ENSG00000112651" "ENSG00000105364"
 [465] "ENSG00000213593" "ENSG00000137806" "ENSG00000132646" "ENSG00000176623" "ENSG00000167113" "ENSG00000114744" "ENSG00000136636" "ENSG00000189050"
 [473] "ENSG00000138663" "ENSG00000111653" "ENSG00000213015" "ENSG00000160948" "ENSG00000113851" "ENSG00000136463" "ENSG00000128463" "ENSG00000133983"
 [481] "ENSG00000154781" "ENSG00000145979" "ENSG00000185414" "ENSG00000006837" "ENSG00000161217" "ENSG00000176624" "ENSG00000179965" "ENSG00000071994"
 [489] "ENSG00000012174" "ENSG00000111832" "ENSG00000225921" "ENSG00000114735" "ENSG00000065989" "ENSG00000089053" "ENSG00000135945" "ENSG00000156973"
 [497] "ENSG00000149196" "ENSG00000022277" "ENSG00000073417" "ENSG00000111843" "ENSG00000050130" "ENSG00000091732" "ENSG00000171425" "ENSG00000111696"
 [505] "ENSG00000111802" "ENSG00000089048" "ENSG00000087087" "ENSG00000159199" "ENSG00000010165" "ENSG00000013306" "ENSG00000115128" "ENSG00000155957"
 [513] "ENSG00000181610" "ENSG00000141378" "ENSG00000101391" "ENSG00000127952" "ENSG00000131153" "ENSG00000154269" "ENSG00000087095" "ENSG00000197857"
 [521] "ENSG00000164307" "ENSG00000103528" "ENSG00000179094" "ENSG00000127980" "ENSG00000162928" "ENSG00000113068" "ENSG00000102893" "ENSG00000155097"
 [529] "ENSG00000143393" "ENSG00000134575" "ENSG00000160199" "ENSG00000126003" "ENSG00000124181" "ENSG00000197943" "ENSG00000138750" "ENSG00000033627"
 [537] "ENSG00000141682" "ENSG00000240344" "ENSG00000169118" "ENSG00000185658" "ENSG00000159055" "ENSG00000100941" "ENSG00000154719" "ENSG00000177084"
 [545] "ENSG00000181222" "ENSG00000147669" "ENSG00000109534" "ENSG00000167977" "ENSG00000266472" "ENSG00000073536" "ENSG00000033100" "ENSG00000128191"
 [553] "ENSG00000175054" "ENSG00000067248" "ENSG00000091127" "ENSG00000134461" "ENSG00000095203" "ENSG00000107021" "ENSG00000133316" "ENSG00000198060"
 [561] "ENSG00000104731" "ENSG00000104756" "ENSG00000148842" "ENSG00000167491" "ENSG00000092439" "ENSG00000141376" "ENSG00000127452" "ENSG00000174227"
 [569] "ENSG00000074603" "ENSG00000131503" "ENSG00000273559" "ENSG00000108375" "ENSG00000174173" "ENSG00000187609" "ENSG00000166902" "ENSG00000157181"
 [577] "ENSG00000075131" "ENSG00000198146" "ENSG00000176371" "ENSG00000111845" "ENSG00000155906" "ENSG00000171103" "ENSG00000186298" "ENSG00000106080"
 [585] "ENSG00000164830" "ENSG00000156795" "ENSG00000119285" "ENSG00000106344" "ENSG00000136247" "ENSG00000198301" "ENSG00000104442" "ENSG00000168411"
 [593] "ENSG00000065665" "ENSG00000089091" "ENSG00000114120" "ENSG00000174718" "ENSG00000134108" "ENSG00000081177" "ENSG00000204178" "ENSG00000122692"
 [601] "ENSG00000095485" "ENSG00000154001" "ENSG00000104221" "ENSG00000110075" "ENSG00000138814" "ENSG00000168872" "ENSG00000162517" "ENSG00000198498"
 [609] "ENSG00000082213" "ENSG00000041802" "ENSG00000108829" "ENSG00000270276" "ENSG00000196782" "ENSG00000028203" "ENSG00000139116" "ENSG00000004766"
 [617] "ENSG00000104907" "ENSG00000153786" "ENSG00000066557" "ENSG00000135956" "ENSG00000072062" "ENSG00000196504" "ENSG00000106993" "ENSG00000100796"
 [625] "ENSG00000152683" "ENSG00000086589" "ENSG00000105248" "ENSG00000013503" "ENSG00000198700" "ENSG00000123444" "ENSG00000119906" "ENSG00000007923"
 [633] "ENSG00000112685" "ENSG00000036054" "ENSG00000180263" "ENSG00000167601" "ENSG00000272886" "ENSG00000160695" "ENSG00000125037" "ENSG00000163558"
 [641] "ENSG00000254999" "ENSG00000111203" "ENSG00000112304" "ENSG00000178028" "ENSG00000128833" "ENSG00000184752" "ENSG00000101084" "ENSG00000075303"
 [649] "ENSG00000169032" "ENSG00000034152" "ENSG00000076984" "ENSG00000126460" "ENSG00000163577" "ENSG00000063176" "ENSG00000197622" "ENSG00000215717"
 [657] "ENSG00000115946" "ENSG00000277791" "ENSG00000077348" "ENSG00000159377" "ENSG00000142507" "ENSG00000076924" "ENSG00000136930" "ENSG00000264522"
 [665] "ENSG00000137817" "ENSG00000104047" "ENSG00000100216" "ENSG00000100764" "ENSG00000165916" "ENSG00000108344" "ENSG00000047621" "ENSG00000148300"
 [673] "ENSG00000095261" "ENSG00000111581" "ENSG00000255112" "ENSG00000170471" "ENSG00000197170" "ENSG00000171862" "ENSG00000149474" "ENSG00000115760"
 [681] "ENSG00000143614" "ENSG00000188033" "ENSG00000124608" "ENSG00000177303" "ENSG00000101213" "ENSG00000108256" "ENSG00000144959" "ENSG00000092421"
 [689] "ENSG00000266074" "ENSG00000174282" "ENSG00000171448" "ENSG00000078687" "ENSG00000111364" "ENSG00000187790" "ENSG00000145388" "ENSG00000152223"
 [697] "ENSG00000157259" "ENSG00000119725" "ENSG00000087088" "ENSG00000144579" "ENSG00000174483" "ENSG00000176894" "ENSG00000105298" "ENSG00000105552"
 [705] "ENSG00000153201" "ENSG00000198258" "ENSG00000117222" "ENSG00000248098" "ENSG00000049541" "ENSG00000188672" "ENSG00000119986" "ENSG00000061794"
 [713] "ENSG00000127870" "ENSG00000138621" "ENSG00000196290" "ENSG00000137500" "ENSG00000215251" "ENSG00000135249" "ENSG00000132394" "ENSG00000117748"
 [721] "ENSG00000089009" "ENSG00000167526" "ENSG00000265681" "ENSG00000105640" "ENSG00000131469" "ENSG00000162244" "ENSG00000145592" "ENSG00000172809"
 [729] "ENSG00000089157" "ENSG00000145425" "ENSG00000175634" "ENSG00000171863" "ENSG00000105193" "ENSG00000125864" "ENSG00000132581" "ENSG00000115970"
 [737] "ENSG00000178234" "ENSG00000157020" "ENSG00000162851" "ENSG00000136527" "ENSG00000106479" "ENSG00000120725" "ENSG00000144848" "ENSG00000115282"
 [745] "ENSG00000144524" "ENSG00000181026" "ENSG00000173614" "ENSG00000118655" "ENSG00000185664" "ENSG00000153044" "ENSG00000185608" "ENSG00000136603"
 [753] "ENSG00000143436" "ENSG00000135900" "ENSG00000139719" "ENSG00000081692" "ENSG00000117394" "ENSG00000139514" "ENSG00000113734" "ENSG00000104852"
 [761] "ENSG00000131876" "ENSG00000125870" "ENSG00000124562" "ENSG00000167088" "ENSG00000182004" "ENSG00000185591" "ENSG00000167182" "ENSG00000172845"
 [769] "ENSG00000012048" "ENSG00000116747" "ENSG00000168610" "ENSG00000087586" "ENSG00000196235" "ENSG00000109111" "ENSG00000151694" "ENSG00000064313"
 [777] "ENSG00000148835" "ENSG00000141556" "ENSG00000139372" "ENSG00000139644" "ENSG00000109079" "ENSG00000141510" "ENSG00000101150" "ENSG00000047410"
 [785] "ENSG00000120798" "ENSG00000087077" "ENSG00000211460" "ENSG00000032389" "ENSG00000243725" "ENSG00000178952" "ENSG00000204954" "ENSG00000100084"
 [793] "ENSG00000254901" "ENSG00000150991" "ENSG00000114491" "ENSG00000156467" "ENSG00000198382" "ENSG00000082898" "ENSG00000205923" "ENSG00000170027"
 [801] "ENSG00000147789" "ENSG00000172262" "ENSG00000063180" "ENSG00000197279" "ENSG00000156983" "ENSG00000075785" "ENSG00000130733" "ENSG00000122783"
 [809] "ENSG00000084774" "ENSG00000107874" "ENSG00000163156" "ENSG00000139579" "ENSG00000123064" "ENSG00000135974" "ENSG00000007255" "ENSG00000149179"
 [817] "ENSG00000101247" "ENSG00000126254" "ENSG00000124120" "ENSG00000178927" "ENSG00000176473" "ENSG00000100483" "ENSG00000146476" "ENSG00000126106"
 [825] "ENSG00000175895" "ENSG00000083223" "ENSG00000083093" "ENSG00000179941" "ENSG00000167394" "ENSG00000127989" "ENSG00000175600" "ENSG00000103264"
 [833] "ENSG00000111412" "ENSG00000175213" "ENSG00000138780" "ENSG00000123607" "ENSG00000166908" "ENSG00000105792" "ENSG00000170260" "ENSG00000125450"
 [841] "ENSG00000123815" "ENSG00000105948" "ENSG00000107960" "ENSG00000119965" "ENSG00000152082" "ENSG00000140451" "ENSG00000163462" "ENSG00000120685"
 [849] "ENSG00000143374" "ENSG00000176783" "ENSG00000005238" "ENSG00000118579" "ENSG00000160688" "ENSG00000111271" "ENSG00000103018" "ENSG00000185085"
 [857] "ENSG00000164118" "ENSG00000094914" "ENSG00000127337" "ENSG00000101294" "ENSG00000138614" "ENSG00000143401" "ENSG00000140941" "ENSG00000179526"
 [865] "ENSG00000136950" "ENSG00000276180" "ENSG00000087008" "ENSG00000089234" "ENSG00000115274" "ENSG00000120820" "ENSG00000278637" "ENSG00000171056"
 [873] "ENSG00000277157" "ENSG00000274618" "ENSG00000273542" "ENSG00000197238" "ENSG00000175573" "ENSG00000197061" "ENSG00000158406" "ENSG00000278705"
 [881] "ENSG00000276966" "ENSG00000275126" "ENSG00000270882" "ENSG00000165632" "ENSG00000172382" "ENSG00000178093" "ENSG00000136492" "ENSG00000127993"
 [889] "ENSG00000186501" "ENSG00000160908" "ENSG00000106346" "ENSG00000127720" "ENSG00000131653" "ENSG00000179632" "ENSG00000127249" "ENSG00000132004"
 [897] "ENSG00000135617" "ENSG00000163472" "ENSG00000175376" "ENSG00000131475" "ENSG00000162441" "ENSG00000130165" "ENSG00000170903" "ENSG00000166847"
 [905] "ENSG00000108094" "ENSG00000124370" "ENSG00000106086" "ENSG00000135093" "ENSG00000135482" "ENSG00000144026" "ENSG00000138600" "ENSG00000134452"
 [913] "ENSG00000154144" "ENSG00000143248" "ENSG00000135119" "ENSG00000176953" "ENSG00000129472" "ENSG00000189376" "ENSG00000139405" "ENSG00000171877"
 [921] "ENSG00000178449" "ENSG00000138629" "ENSG00000134490" "ENSG00000034693" "ENSG00000171617" "ENSG00000128159" "ENSG00000166181" "ENSG00000160256"
 [929] "ENSG00000089022" "ENSG00000165630" "ENSG00000160214" "ENSG00000088247" "ENSG00000087269" "ENSG00000175792" "ENSG00000064490" "ENSG00000107581"
 [937] "ENSG00000130811" "ENSG00000124222" "ENSG00000101654" "ENSG00000105402" "ENSG00000166224" "ENSG00000130177" "ENSG00000088205" "ENSG00000070785"
 [945] "ENSG00000100038" "ENSG00000113732" "ENSG00000103168" "ENSG00000163900" "ENSG00000109083" "ENSG00000179271" "ENSG00000142444" "ENSG00000240230"
 [953] "ENSG00000011347" "ENSG00000258890" "ENSG00000164169" "ENSG00000162032" "ENSG00000175467" "ENSG00000036672" "ENSG00000138592" "ENSG00000159720"
 [961] "ENSG00000100258" "ENSG00000117360" "ENSG00000182087" "ENSG00000076928" "ENSG00000078699" "ENSG00000173214" "ENSG00000221838" "ENSG00000074621"
 [969] "ENSG00000140450" "ENSG00000169359" "ENSG00000154814" "ENSG00000166197" "ENSG00000151276" "ENSG00000185236" "ENSG00000148187" "ENSG00000135127"
 [977] "ENSG00000125821" "ENSG00000163444" "ENSG00000177946" "ENSG00000116754" "ENSG00000143315" "ENSG00000125733" "ENSG00000103671" "ENSG00000119041"
 [985] "ENSG00000099940" "ENSG00000108883" "ENSG00000105676" "ENSG00000168175" "ENSG00000108469" "ENSG00000132485" "ENSG00000172057" "ENSG00000112282"
 [993] "ENSG00000075391" "ENSG00000108474" "ENSG00000121075" "ENSG00000105819" "ENSG00000108587" "ENSG00000166170" "ENSG00000011132" "ENSG00000265808"
 [ reached getOption("max.print") -- omitted 3703 entries ]
[1] "\"Mitochondria\"[Mesh] AND \"Endoplasmic Reticulum\"[Mesh]"
[1] "Hsa"
[1] "hsapiens_gene_ensembl"
[1] "9606"
[1] "getBM"
[1] "Check EntrezGeneID again"
[1] "end"
[1] "mmusculus_homolog_ensembl_gene"
[1] "Check EntrezGeneID again"

  |=============================================================================================================================================================| 100%[1] "end"
[1] "rnorvegicus_homolog_ensembl_gene"
[1] "Check EntrezGeneID again"

  |============================================================================================================================================================ | 100%
  |=============================================================================================================================================================| 100%[1] "end"
[1] "sscrofa_homolog_ensembl_gene"
[1] "Check EntrezGeneID again"

  |=====================================================================================================================================                        |  85%error calling combine function:
<simpleError in rbind(deparse.level, ...): invalid list argument: all variables should have the same length>

  |=======================================================================================================================================================      |  96%error calling combine function:
<simpleError in rbind(deparse.level, ...): invalid list argument: all variables should have the same length>

  |============================================================================================================================================================ | 100%error calling combine function:
<simpleError in rbind(deparse.level, ...): invalid list argument: all variables should have the same length>

  |=============================================================================================================================================================| 100%[1] "end"
[1] "StartLoop"

  |============================================================================================================================================================ | 100%
  |=============================================================================================================================================================| 100%[1] "EndLoop"
[1] "end"

Results

Plot out results

gp <- literatureMiningPlot(
  literature.mining=Targets.Mesh$literature.mining, Thresh.R=0.002,
  use.Padj = FALSE, Thresh.P=0.05, label=TRUE, label_n = 10
)
svg(filename = file.path(".", "01.PlotOut", "LiteratureMiningRes_03.svg"), width = 12, height = 8, pointsize = 12)
print(gp)
dev.off()
null device 
          1 
graphics.off()
knitr::opts_knit$set(global.device = TRUE)
print(gp)

knitr::opts_knit$set(global.device = FALSE)

02. Supplementary

save.image("./CheckPoint2.RData")
sessionInfo()
R version 4.2.2 (2022-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=ja_JP.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=ja_JP.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=ja_JP.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=ja_JP.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
 [1] stats4    parallel  tcltk     grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggprism_1.0.4         org.Hs.eg.db_3.16.0   enrichplot_1.18.4     pathview_1.38.0       org.Mm.eg.db_3.16.0   GO.db_3.16.0         
 [7] AnnotationDbi_1.60.2  IRanges_2.32.0        S4Vectors_0.36.2      Biobase_2.58.0        clusterProfiler_4.6.2 ExperimentHub_2.6.0  
[13] AnnotationHub_3.6.0   BiocFileCache_2.6.1   dbplyr_2.3.2          BiocGenerics_0.44.0   limma_3.54.2          htmltools_0.5.5      
[19] hwriter_1.3.2.1       visNetwork_2.1.2      rlang_1.1.1           knitr_1.43            knn.covertree_1.0     rvest_1.0.3          
[25] xml2_1.3.4            plyr_1.8.8            pipeR_0.6.1.3         rlist_0.4.6.2         magrittr_2.0.3        RCurl_1.98-1.12      
[31] curl_5.0.1            jsonlite_1.8.5        httr_1.4.6            latex2exp_0.9.6       xtable_1.8-4          gmp_0.7-1            
[37] RColorBrewer_1.1-3    factoextra_1.0.7      randomcoloR_1.1.0.1   gplots_3.1.3          data.table_1.14.8     doSNOW_1.0.20        
[43] snow_0.4-4            doParallel_1.0.17     iterators_1.0.14      foreach_1.5.2         stringr_1.5.0         dplyr_1.1.2          
[49] reshape2_1.4.4        ggrepel_0.9.3         matrixStats_1.0.0     ggpubr_0.6.0          ggplot2_3.4.2         readxl_1.4.2         
[55] biomaRt_2.55.3       

loaded via a namespace (and not attached):
  [1] utf8_1.2.3                    tidyselect_1.2.0              RSQLite_2.3.1                 htmlwidgets_1.6.2            
  [5] BiocParallel_1.32.6           Rtsne_0.16                    devtools_2.4.5                scatterpie_0.2.1             
  [9] munsell_0.5.0                 codetools_0.2-18              miniUI_0.1.1.1                withr_2.5.0                  
 [13] colorspace_2.1-0              GOSemSim_2.24.0               filelock_1.0.2                rstudioapi_0.14              
 [17] ggsignif_0.6.4                DOSE_3.24.2                   labeling_0.4.2                KEGGgraph_1.58.3             
 [21] GenomeInfoDbData_1.2.9        polyclip_1.10-4               bit64_4.0.5                   farver_2.1.1                 
 [25] downloader_0.4                parallelly_1.36.0             vctrs_0.6.2                   treeio_1.22.0                
 [29] generics_0.1.3                gson_0.1.0                    xfun_0.39                     R6_2.5.1                     
 [33] GenomeInfoDb_1.34.9           graphlayouts_1.0.0            RcppEigen_0.3.3.9.3           bitops_1.0-7                 
 [37] cachem_1.0.8                  fgsea_1.24.0                  gridGraphics_0.5-1            promises_1.2.0.1             
 [41] scales_1.2.1                  ggraph_2.1.0                  gtable_0.3.3                  processx_3.8.1               
 [45] tidygraph_1.2.3               splines_4.2.2                 rstatix_0.7.2                 lazyeval_0.2.2               
 [49] selectr_0.4-2                 broom_1.0.5                   BiocManager_1.30.21           yaml_2.3.7                   
 [53] abind_1.4-5                   backports_1.4.1               httpuv_1.6.11                 qvalue_2.30.0                
 [57] tools_4.2.2                   usethis_2.2.0                 ggplotify_0.1.0               ellipsis_0.3.2               
 [61] jquerylib_0.1.4               sessioninfo_1.2.2             Rcpp_1.0.10                   progress_1.2.2               
 [65] zlibbioc_1.44.0               purrr_1.0.1                   ps_1.7.5                      prettyunits_1.1.1            
 [69] viridis_0.6.3                 cowplot_1.1.1                 urlchecker_1.0.1              cluster_2.1.4                
 [73] fs_1.6.2                      ggnewscale_0.4.9              pkgload_1.3.2                 hms_1.1.3                    
 [77] patchwork_1.1.2               mime_0.12                     evaluate_0.21                 HDO.db_0.99.1                
 [81] XML_3.99-0.14                 gridExtra_2.3                 compiler_4.2.2                tibble_3.2.1                 
 [85] KernSmooth_2.23-20            V8_4.3.0                      crayon_1.5.2                  shadowtext_0.1.2             
 [89] ggfun_0.0.9                   later_1.3.1                   tidyr_1.3.0                   aplot_0.1.10                 
 [93] DBI_1.1.3                     tweenr_2.0.2                  MASS_7.3-58.1                 rappdirs_0.3.3               
 [97] Matrix_1.5-4.1                car_3.1-2                     cli_3.6.1                     igraph_1.4.3                 
[101] pkgconfig_2.0.3               ggtree_3.6.2                  bslib_0.5.0                   XVector_0.38.0               
[105] yulab.utils_0.0.6             callr_3.7.3                   digest_0.6.31                 graph_1.76.0                 
[109] Biostrings_2.66.0             rmarkdown_2.22                cellranger_1.1.0              fastmatch_1.1-3              
[113] tidytree_0.4.2                shiny_1.7.4                   gtools_3.9.4                  lifecycle_1.0.3              
[117] nlme_3.1-162                  carData_3.0-5                 viridisLite_0.4.2             fansi_1.0.4                  
[121] pillar_1.9.0                  lattice_0.20-45               KEGGREST_1.38.0               fastmap_1.1.1                
[125] pkgbuild_1.4.0                interactiveDisplayBase_1.36.0 glue_1.6.2                    remotes_2.4.2                
[129] png_0.1-8                     Rgraphviz_2.42.0              BiocVersion_3.16.0            bit_4.0.5                    
[133] ggforce_0.4.1                 stringi_1.7.12                sass_0.4.6                    profvis_0.3.8                
[137] blob_1.2.4                    caTools_1.18.2                memoise_2.0.1                 ape_5.7-1                    
LS0tCnRpdGxlOiAiTy1HbGNOQWMgcmVndWxhdGVkIEVSLU1pdG9jaG9uZHJpYSBjb3VwbGluZyIKYXV0aG9yOiAiV1pZIgpkYXRlOiAiMjAyMy0wOS0wMSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgY3NzOiAuL0hUTUxfc291cmNlL3N0eWxlLmNzcwotLS0KCiMgMDAuIEVudmlyZW5tZW50IFNldHRpbmdzCgpMb2FkIHRoZSBiaW9pbmZvcm1hdGljcyBhbmFseXNpcyByZXN1bHRzIGZyb20gdGhlIHByZXZpb3VzIHN0ZXBzCgpgYGB7ciBMb2FkIFJlc3VsdHN9CmxvYWQoIkNoZWNrUG9pbnQuUkRhdGEiKQpgYGAKCmBgYHtyIEVudmlyZW5tZW50IFNldHRpbmdzfQpvcHRpb25zKGluc3RhbGwucGFja2FnZXMuY29tcGlsZS5mcm9tLnNvdXJjZSA9ICJhbHdheXMiKQpsaXN0LnBhY2thZ2VzIDwtIGMoCiAgInJlYWR4bCIsICJnZ3Bsb3QyIiwgImdncHViciIsICJtYXRyaXhTdGF0cyIsICJnZ3JlcGVsIiwgInJlc2hhcGUyIiwgImRwbHlyIiwgInN0cmluZ3IiLAogICJncmlkIiwgInRjbHRrIiwgInBhcmFsbGVsIiwgImRvUGFyYWxsZWwiLCAiZG9TTk9XIiwgImRhdGEudGFibGUiLCAiZ3Bsb3RzIiwKICAicmFuZG9tY29sb1IiLCAiZmFjdG9leHRyYSIsICJSQ29sb3JCcmV3ZXIiLCAiZ3JEZXZpY2VzIiwgImdtcCIsICJ4dGFibGUiLCAibGF0ZXgyZXhwIiwKICAiaHR0ciIsICJqc29ubGl0ZSIsICJjdXJsIiwgIlJDdXJsIiwgIm1hZ3JpdHRyIiwgInJsaXN0IiwgInBpcGVSIiwgInBseXIiLAogICJ4bWwyIiwgInJ2ZXN0IiwgImtubi5jb3ZlcnRyZWUiLCAia25pdHIiLCAicmxhbmciLCAidmlzTmV0d29yayIsICJod3JpdGVyIiwgImh0bWx0b29scyIKKQpiaW8ubGlzdC5wYWNrYWdlcyA8LSBjKAogICJsaW1tYSIsICJFeHBlcmltZW50SHViIiwgImNsdXN0ZXJQcm9maWxlciIsICJHTy5kYiIsCiAgIm9yZy5NbS5lZy5kYiIsICJwYXRodmlldyIsICJlbnJpY2hwbG90IiwgIm9yZy5Icy5lZy5kYiIKKQpuZXcucGFja2FnZXMgPC0gbGlzdC5wYWNrYWdlc1shbGlzdC5wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpXQpiaW8ubmV3LnBhY2thZ2VzIDwtIGJpby5saXN0LnBhY2thZ2VzWyFiaW8ubGlzdC5wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpXQojIFBhY2thZ2VzIHRoYXQgZG9lcyBub3QgaW5zdGFsbCB5ZXQKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkgewogIHVwZGF0ZS5wYWNrYWdlcyhhc2sgPSBGQUxTRSkKICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIsIHJlcG9zPSJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKQp9CmlmIChsZW5ndGgobmV3LnBhY2thZ2VzKSkgewogIGluc3RhbGwucGFja2FnZXMobmV3LnBhY2thZ2VzKQogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiZ3JpbWJvdWdoL2Jpb21hUnQiLCBmb3JjZSA9IEZBTFNFKQp9CmlmIChsZW5ndGgoYmlvLm5ldy5wYWNrYWdlcykpIHsKICB1cGRhdGUucGFja2FnZXMoYXNrID0gRkFMU0UpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoYmlvLm5ldy5wYWNrYWdlcykKfQojIExvYWRpbmcgYWxsIHBhY2thZ2VzICYgZnVuY3Rpb25zCmludmlzaWJsZShsYXBwbHkoYyhsaXN0LnBhY2thZ2VzLCBiaW8ubGlzdC5wYWNrYWdlcywgImJpb21hUnQiKSwgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkKb3B0aW9ucyhyZ2wudXNlTlVMTCA9IEYsIGdncmVwZWwubWF4Lm92ZXJsYXBzID0gSW5mKQojTG9hZCBsaXRlcmF0dXJlIG1pbmluZyBmdW5jdGlvbnMjClJldHJpZXZlRW50cmV6SUQgPC0gZnVuY3Rpb24oCiAgICBIb21vbG9ndWVzPUZBTFNFLAogICAgSG9tb19zcGVjaWVzPUhvbW9fc3BlY2llcywKICAgIFBhcl9zcGVjaWVzPVBhcl9zcGVjaWVzLAogICAgUGFyX3NwZWNpZXMuVW5pcHJvdD1QYXJfc3BlY2llcy5Vbmlwcm90LAogICAgR2VuZXNMcz1HZW5lc0xzLAogICAgdXBkYXRlUHJvZ3Jlc3MgPSBOVUxMCil7CiAgYXR0ZW1wdF9tYXg8LTEyCiAgI3wtLS0tU2V0IHVwIEJpb21hcnQgcGFyYW1ldGVycy0tLS18IyMjIwogIEFubl8wbWFydDwtTlVMTAogIGF0dGVtcHQ8LTEKICB3aGlsZShpcy5udWxsKEFubl8wbWFydCkmJmF0dGVtcHQ8YXR0ZW1wdF9tYXgpewogICAgaWYoYXR0ZW1wdCVpbiVzZXEoZnJvbT0xLHRvPWF0dGVtcHRfbWF4LDMpKXsKICAgICAgdXJsPC0iaHR0cHM6Ly91c2Vhc3QuZW5zZW1ibC5vcmciCiAgICB9ZWxzZSBpZihhdHRlbXB0JWluJXNlcShmcm9tPTIsdG89YXR0ZW1wdF9tYXgsMykpewogICAgICB1cmw8LSJodHRwczovL3d3dy5lbnNlbWJsLm9yZyIKICAgIH1lbHNlIGlmKGF0dGVtcHQlaW4lc2VxKGZyb209Myx0bz1hdHRlbXB0X21heCwzKSl7CiAgICAgIHVybDwtImh0dHBzOi8vdXNlYXN0LmVuc2VtYmwub3JnLyIKICAgIH1lbHNlIGlmKGF0dGVtcHQlaW4lc2VxKGZyb209NCx0bz1hdHRlbXB0X21heCwzKSl7CiAgICAgIHVybDwtImh0dHBzOi8vYXNpYS5lbnNlbWJsLm9yZy8iCiAgICB9CiAgICB0cnkoewogICAgICBBbm5fMG1hcnQgPC0gdXNlTWFydCgiRU5TRU1CTF9NQVJUX0VOU0VNQkwiLCBob3N0PXVybCkgJT4lCiAgICAgICAgdXNlRGF0YXNldChQYXJfc3BlY2llcywgLikKICAgIH0sIHNpbGVudCA9IFRSVUUpCiAgICBhdHRlbXB0PC1hdHRlbXB0KzEKICAgIGlmKGlzLm51bGwoQW5uXzBtYXJ0KSl7U3lzLnNsZWVwKDAuNSl9CiAgfQogIGlmKEhvbW9sb2d1ZXMpewogICAgaWYgKGlzLmZ1bmN0aW9uKHVwZGF0ZVByb2dyZXNzKSkgewogICAgICB0ZXh0IDwtIHBhc3RlMCgiR2V0IEhvbW9sb2dvZXVzIEdlbmUgaW4gIiwgSG9tb19zcGVjaWVzKSAKICAgICAgdXBkYXRlUHJvZ3Jlc3MoZGV0YWlsID0gdGV4dCkKICAgIH0KICAgICNsaXN0QXR0cmlidXRlcyhBbm5fMG1hcnQpJT4lVmlldygpCiAgICB0ZW1wIDwtIE5VTEwKICAgIGF0dGVtcHQ8LTEKICAgIHdoaWxlKGlzLm51bGwodGVtcCkmJmF0dGVtcHQ8YXR0ZW1wdF9tYXgpewogICAgICB0cnkoewogICAgICAgIHRlbXAgPC0gZ2V0Qk0oCiAgICAgICAgICBtYXJ0PUFubl8wbWFydCwKICAgICAgICAgIGF0dHJpYnV0ZXM9YygiZW5zZW1ibF9nZW5lX2lkIiwKICAgICAgICAgICAgICAgICAgICAgICBIb21vX3NwZWNpZXMpLAogICAgICAgICAgZmlsdGVyPSJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgdmFsdWVzPUdlbmVzTHMsCiAgICAgICAgICB1bmlxdWVSb3dzID0gVCkKICAgICAgfSwgc2lsZW50ID0gVFJVRSkKICAgICAgYXR0ZW1wdDwtYXR0ZW1wdCsxCiAgICAgIGlmKGlzLm51bGwodGVtcCkpe1N5cy5zbGVlcCgwLjUpfQogICAgfQogICAgY2xvc2VBbGxDb25uZWN0aW9ucygpCiAgICB0ZW1wPC10ZW1wWyF0ZW1wWywyXSVpbiUiIixdCiAgICB0ZW1wPC10ZW1wWyFkdXBsaWNhdGVkKHRlbXBbLDJdKSxdCiAgICBOYU1hcHBpbmc8LXRlbXBbLDFdCiAgICBuYW1lcyhOYU1hcHBpbmcpPC10ZW1wWywyXQogICAgcHJpbnQoSG9tb19zcGVjaWVzKQogICAgaWYoaXNfZW1wdHkodGVtcCl8bnJvdyh0ZW1wKTwxKXsKICAgICAgcmV0dXJuKE5BKQogICAgfQogICAgI3ByaW50KCJTZXQgdXAgQmlvbWFydCBwYXJhbWV0ZXJzIikKICAgICN8LS0tLVNldCB1cCBCaW9tYXJ0IHBhcmFtZXRlcnMtLS0tfCMjIyMKICAgIGlmKEhvbW9fc3BlY2llcyA9PSAiaHNhcGllbnNfaG9tb2xvZ19lbnNlbWJsX2dlbmUiKXsKICAgICAgUGFyX3NwZWNpZXMgPC0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIKICAgIH1lbHNlIGlmKEhvbW9fc3BlY2llcyA9PSAibW11c2N1bHVzX2hvbW9sb2dfZW5zZW1ibF9nZW5lIil7CiAgICAgIFBhcl9zcGVjaWVzIDwtICJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIgogICAgfWVsc2UgaWYoSG9tb19zcGVjaWVzID09ICJybm9ydmVnaWN1c19ob21vbG9nX2Vuc2VtYmxfZ2VuZSIpewogICAgICBQYXJfc3BlY2llcyA8LSAicm5vcnZlZ2ljdXNfZ2VuZV9lbnNlbWJsIgogICAgfWVsc2UgaWYoSG9tb19zcGVjaWVzID09ICJzc2Nyb2ZhX2hvbW9sb2dfZW5zZW1ibF9nZW5lIil7CiAgICAgIFBhcl9zcGVjaWVzIDwtICJzc2Nyb2ZhX2dlbmVfZW5zZW1ibCIKICAgIH0KICAgIEFubl8wbWFydDwtTlVMTAogICAgYXR0ZW1wdDwtMQogICAgd2hpbGUoaXMubnVsbChBbm5fMG1hcnQpJiZhdHRlbXB0PGF0dGVtcHRfbWF4KXsKICAgICAgaWYoYXR0ZW1wdCVpbiVzZXEoZnJvbT0xLHRvPWF0dGVtcHRfbWF4LDMpKXsKICAgICAgICB1cmw8LSJodHRwczovL3VzZWFzdC5lbnNlbWJsLm9yZyIKICAgICAgfWVsc2UgaWYoYXR0ZW1wdCVpbiVzZXEoZnJvbT0yLHRvPWF0dGVtcHRfbWF4LDMpKXsKICAgICAgICB1cmw8LSJodHRwczovL3d3dy5lbnNlbWJsLm9yZyIKICAgICAgfWVsc2UgaWYoYXR0ZW1wdCVpbiVzZXEoZnJvbT0zLHRvPWF0dGVtcHRfbWF4LDMpKXsKICAgICAgICB1cmw8LSJodHRwczovL3VzZWFzdC5lbnNlbWJsLm9yZy8iCiAgICAgIH1lbHNlIGlmKGF0dGVtcHQlaW4lc2VxKGZyb209NCx0bz1hdHRlbXB0X21heCwzKSl7CiAgICAgICAgdXJsPC0iaHR0cHM6Ly9hc2lhLmVuc2VtYmwub3JnLyIKICAgICAgfQogICAgICB0cnkoewogICAgICAgIEFubl8wbWFydCA8LSB1c2VNYXJ0KCJFTlNFTUJMX01BUlRfRU5TRU1CTCIsIGhvc3Q9dXJsKSAlPiUKICAgICAgICAgIHVzZURhdGFzZXQoUGFyX3NwZWNpZXMsIC4pCiAgICAgIH0sIHNpbGVudCA9IFRSVUUpCiAgICAgIGF0dGVtcHQ8LWF0dGVtcHQrMQogICAgICBpZihpcy5udWxsKEFubl8wbWFydCkpe1N5cy5zbGVlcCgwLjUpfQogICAgfQogICAgQW5ub19nZW5lIDwtIE5VTEwKICAgIGF0dGVtcHQ8LTEKICAgIHdoaWxlKGlzLm51bGwoQW5ub19nZW5lKSYmYXR0ZW1wdDxhdHRlbXB0X21heCl7CiAgICAgIHRyeSh7CiAgICAgICAgQW5ub19nZW5lIDwtIGdldEJNKAogICAgICAgICAgbWFydD1Bbm5fMG1hcnQsCiAgICAgICAgICBhdHRyaWJ1dGVzPWMoImVuc2VtYmxfZ2VuZV9pZCIsImVudHJlemdlbmVfaWQiLCJnZW5lX2Jpb3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICJleHRlcm5hbF9nZW5lX25hbWUiLCJkZXNjcmlwdGlvbiIpLAogICAgICAgICAgZmlsdGVyPSJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgdmFsdWVzPXRlbXBbLDJdLAogICAgICAgICAgdW5pcXVlUm93cyA9IFQpCiAgICAgIH0sIHNpbGVudCA9IFRSVUUpCiAgICAgIGF0dGVtcHQ8LWF0dGVtcHQrMQogICAgICBpZihpcy5udWxsKEFubm9fZ2VuZSkpe1N5cy5zbGVlcCgwLjUpfQogICAgfQogICAgcm0odGVtcCkKICB9ZWxzZXsKICAgIHByaW50KCJnZXRCTSIpCiAgICBpZiAoaXMuZnVuY3Rpb24odXBkYXRlUHJvZ3Jlc3MpKSB7CiAgICAgIHRleHQgPC0gIkdldCBQdWJNZWQgR2VuZSBJRCIKICAgICAgdXBkYXRlUHJvZ3Jlc3MoZGV0YWlsID0gdGV4dCkKICAgIH0KICAgIEFubm9fZ2VuZSA8LSBOVUxMCiAgICBhdHRlbXB0PC0xCiAgICB3aGlsZShpcy5udWxsKEFubm9fZ2VuZSkmJmF0dGVtcHQ8YXR0ZW1wdF9tYXgpewogICAgICB0cnkoewogICAgICAgIEFubm9fZ2VuZSA8LSBnZXRCTSgKICAgICAgICAgIG1hcnQ9QW5uXzBtYXJ0LAogICAgICAgICAgYXR0cmlidXRlcz1jKCJlbnNlbWJsX2dlbmVfaWQiLCJlbnRyZXpnZW5lX2lkIiwiZ2VuZV9iaW90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAiZXh0ZXJuYWxfZ2VuZV9uYW1lIiwiZGVzY3JpcHRpb24iKSwKICAgICAgICAgIGZpbHRlcj0iZW5zZW1ibF9nZW5lX2lkIiwKICAgICAgICAgIHZhbHVlcz1HZW5lc0xzLAogICAgICAgICAgdW5pcXVlUm93cyA9IFQpCiAgICAgIH0sIHNpbGVudCA9IFRSVUUpCiAgICAgIGF0dGVtcHQ8LWF0dGVtcHQrMQogICAgICBpZihpcy5udWxsKEFubm9fZ2VuZSkpe1N5cy5zbGVlcCgwLjUpfQogICAgfQogIH0KICBBbm5vPC1Bbm5vX2dlbmVbIWR1cGxpY2F0ZWQoQW5ub19nZW5lJGVuc2VtYmxfZ2VuZV9pZCksXQogIHJvd25hbWVzKEFubm8pPC1Bbm5vJGVuc2VtYmxfZ2VuZV9pZAogIEFubm88LWRhdGEuZnJhbWUoCiAgICBlbnNlbWJsX2dlbmVfaWQ9QW5ubyRlbnNlbWJsX2dlbmVfaWQsCiAgICBlbnRyZXpnZW5lX2lkPUFubm8kZW50cmV6Z2VuZV9pZCwKICAgIGV4dGVybmFsX2dlbmVfbmFtZT1Bbm5vJGV4dGVybmFsX2dlbmVfbmFtZSwKICAgIGdlbmVfYmlvdHlwZT1Bbm5vJGdlbmVfYmlvdHlwZSwKICAgIHJvdy5uYW1lcyA9IHJvd25hbWVzKEFubm8pCiAgKQogIEFubm8yPC1Bbm5vWyFpcy5uYShBbm5vJGVudHJlemdlbmVfaWQpLF0gI0ZvciBFbnRyZXpHZW5lSUQKICBBbm5vMjwtQW5ubzJbIWR1cGxpY2F0ZWQoQW5ubzJbLCdlbnNlbWJsX2dlbmVfaWQnXSksXSAjRm9yIEVudHJlekdlbmVJRAogIHJvd25hbWVzKEFubm8yKTwtQW5ubzIkZW5zZW1ibF9nZW5lX2lkCiAgdGVtcDwtQW5ub1tpcy5uYShBbm5vJGVudHJlemdlbmVfaWQpLCJlbnNlbWJsX2dlbmVfaWQiXQogIHByaW50KCJDaGVjayBFbnRyZXpHZW5lSUQgYWdhaW4iKQogICN8LS0tLUNoZWNrIEVudHJlekdlbmVJRCBhZ2Fpbi0tLS18IyMjIwogIGlmKCFpc19lbXB0eSh0ZW1wKSl7CiAgICBpZihsZW5ndGgodGVtcCk8Mil7CiAgICAgIE5DQkljaGVjazwtcmVhZF9odG1sKAogICAgICAgIHBhc3RlMCgKICAgICAgICAgICJodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2dlbmUvP3Rlcm09IiwKICAgICAgICAgIHRlbXAKICAgICAgICApCiAgICAgICklPiV4bWxfZmluZF9hbGwoLiwgIi4vL3NwYW4iKSU+JXhtbF90ZXh0KCklPiUKICAgICAgICBncmVwKCJHZW5lIElEIiwuLHZhbHVlID0gVFJVRSkKICAgICAgaWYoIWlzRW1wdHkoTkNCSWNoZWNrKSl7CiAgICAgICAgTkNCSWNoZWNrPC1OQ0JJY2hlY2slPiV1bmxpc3QoKSU+JQogICAgICAgICAgc3RyX2V4dHJhY3RfYWxsKC4sIihcXGQpKyIpJT4lLltbMV1dJT4lLlsxXQogICAgICB9ZWxzZXsKICAgICAgICBOQ0JJY2hlY2s8LU5BCiAgICAgIH0KICAgICAgb3V0PC1kYXRhLmZyYW1lKAogICAgICAgIGVuc2VtYmxfZ2VuZV9pZD10ZW1wLAogICAgICAgIGVudHJlemdlbmVfaWQ9TkNCSWNoZWNrCiAgICAgICklPiVhcy5kYXRhLmZyYW1lKCkKICAgICAgdGVtcDI8LW91dAogICAgfWVsc2V7CiAgICAgIFBhcl9jbDwtbWFrZUNsdXN0ZXIocGFyYWxsZWxseTo6ZnJlZUNvbm5lY3Rpb25zKCktMSkKICAgICAgcmVnaXN0ZXJEb1NOT1coUGFyX2NsKQogICAgICBQYXJfcGIgPC0gdHh0UHJvZ3Jlc3NCYXIobWluPTEsIG1heD1sZW5ndGgodGVtcCksIHN0eWxlID0gMykKICAgICAgcHJvZ3Jlc3MgPC0gZnVuY3Rpb24obikgc2V0VHh0UHJvZ3Jlc3NCYXIoUGFyX3BiLCBuKQogICAgICBQYXJfb3B0czwtbGlzdChwcm9ncmVzcyA9IHByb2dyZXNzKQogICAgICAjUmVmZXIgaGVyZSBmb3IgYWxsIGNvbHVtbiBuYW1lcyBmb3IgRW50cmV6IEFQSSAoaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9ib29rcy9OQksyNTUwMS8pCiAgICAgIHRlbXAyPC1mb3JlYWNoKGk9MTpsZW5ndGgodGVtcCksIC5jb21iaW5lPXJiaW5kLCAuZXJyb3JoYW5kbGluZyA9ICJwYXNzIiwgLmlub3JkZXI9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIC5vcHRpb25zLnNub3c9UGFyX29wdHMsIC5wYWNrYWdlcyA9IGMoImRwbHlyIiwidXRpbHMiLCJ4bWwyIiwiUzRWZWN0b3JzIiwic3RyaW5nciIsIkJpb2NHZW5lcmljcyIpKSAlZG9wYXIlIHsKICAgICAgICAgICAgICAgICAgICAgICBOQ0JJY2hlY2s8LXJlYWRfaHRtbCgKICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgImh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VuZS8/dGVybT0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0ZW1wW2ldCiAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgKSU+JXhtbF9maW5kX2FsbCguLCAiLi8vc3BhbiIpJT4leG1sX3RleHQoKSU+JQogICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcCgiR2VuZSBJRCIsLix2YWx1ZSA9IFRSVUUpCiAgICAgICAgICAgICAgICAgICAgICAgaWYoIWlzRW1wdHkoTkNCSWNoZWNrKSl7CiAgICAgICAgICAgICAgICAgICAgICAgICBOQ0JJY2hlY2s8LU5DQkljaGVjayU+JXVubGlzdCgpJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9leHRyYWN0X2FsbCguLCIoXFxkKSsiKSU+JS5bWzFdXSU+JS5bMV0KICAgICAgICAgICAgICAgICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgICAgICAgICAgICAgIE5DQkljaGVjazwtTkEKICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgb3V0PC1kYXRhLmZyYW1lKAogICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9nZW5lX2lkPXRlbXBbaV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBlbnRyZXpnZW5lX2lkPU5DQkljaGVjawogICAgICAgICAgICAgICAgICAgICAgICklPiVhcy5kYXRhLmZyYW1lKCkKICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ob3V0KQogICAgICAgICAgICAgICAgICAgICB9CiAgICAgIHN0b3BDbHVzdGVyKFBhcl9jbCkKICAgIH0KICAgIHRlbXAyPC10ZW1wMlshaXMubmEodGVtcDIkZW50cmV6Z2VuZV9pZCksXQogICAgdGVtcDI8LXRlbXAyWyFkdXBsaWNhdGVkKHRlbXAyJGVuc2VtYmxfZ2VuZV9pZCksXQogICAgcm93bmFtZXModGVtcDIpPC10ZW1wMiRlbnNlbWJsX2dlbmVfaWQKICAgIHRlbXAyPC1jYmluZCgKICAgICAgdGVtcDIsCiAgICAgIEFubm9bdGVtcDIkZW5zZW1ibF9nZW5lX2lkLGMoMzo0KV0KICAgICkKICAgICNzdW0oQW5ubzIkZW5zZW1ibF9nZW5lX2lkJWluJXRlbXAyJGVuc2VtYmxfZ2VuZV9pZCk9PTAKICAgIEFubm8yPC1yYmluZCgKICAgICAgQW5ubzIsCiAgICAgIHRlbXAyCiAgICApCiAgfQogIGlmKEhvbW9sb2d1ZXMpewogICAgQW5ubzI8LWNiaW5kKG1hcHBpbmc9TmFNYXBwaW5nW0Fubm8yJGVuc2VtYmxfZ2VuZV9pZF0sQW5ubzIpCiAgICBBbm5vMjwtQW5ubzJbIWR1cGxpY2F0ZWQoQW5ubzIkbWFwcGluZyksXQogICAgcm93bmFtZXMoQW5ubzIpIDwtIE5hTWFwcGluZ1tBbm5vMiRlbnNlbWJsX2dlbmVfaWRdCiAgICBBbm5vMjwtQW5ubzJbLC0xXQogIH0KICBwcmludCgiZW5kIikKICBpZiAoaXMuZnVuY3Rpb24odXBkYXRlUHJvZ3Jlc3MpKSB7CiAgICB0ZXh0IDwtIHBhc3RlMCgiSUQgQ29udmVydCBEb25lICIpIAogICAgdXBkYXRlUHJvZ3Jlc3MoZGV0YWlsID0gdGV4dCkKICB9CiAgcmV0dXJuKEFubm8yKQp9Cgpwc2V1ZG9Mb2cxMCA8LSBmdW5jdGlvbih4KXsgYXNpbmgoeC8yKS9sb2coMTApIH0KCldaWV9HZXRTdW1tYXJ5VGV4dDwtZnVuY3Rpb24ocCl7CiAgcGRhdGEgPC0gZGF0YS5mcmFtZShuYW1lID0gcCRkYXRhJGxhYmVsLCBjb2xvcjIgPSBwJGRhdGEkZ3JvdXApCiAgcGRhdGEgPC0gcGRhdGFbIWlzLm5hKHBkYXRhJG5hbWUpLCBdCiAgY2x1c3Rlcl9jb2xvciA8LSB1bmlxdWUocGRhdGEkY29sb3IyKQogIAogIGNsdXN0ZXJfbGFiZWwgPC0gc2FwcGx5KAogICAgY2x1c3Rlcl9jb2xvciwgZW5yaWNocGxvdDo6OmdldF93b3JkY2xvdWQsCiAgICBnZ0RhdGEgPSBwZGF0YSwgbldvcmRzID0gNAogICkgJT4lIHBhc3RlMCguLGNvbGxhcHNlID0gIiAiKSAlPiUgc3RyX3NwbGl0KC4sICIgIikgJT4lIHVubGlzdCgpCiAgcmV0dXJuKGNsdXN0ZXJfbGFiZWwpCn0KCldaWV9saXRlcmF0dXJlTWluaW5nPC1mdW5jdGlvbihHZW5lc0xzPUdlbmVzTHMsIE1lc2hfdGVybTRJbnRlcmVzdGluZz1NZXNoX3Rlcm00SW50ZXJlc3RpbmcsIFNwZWNpZXM9U3BlY2llcywgdXBkYXRlUHJvZ3Jlc3MgPSBOVUxMKXsKICBvdXQ8LWxpc3QoKQogIE48LXBhc3RlMCgjVG8gc2VhcmNoIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIFB1Yk1lZCBjaXRhdGlvbnMsIGVudGVyIGFsbFtzYl0gaW4gdGhlIHNlYXJjaCBib3guKDIwMjEwNTA2KQogICAgImh0dHBzOi8vcHVibWVkLm5jYmkubmxtLm5paC5nb3YvP3Rlcm09IiwKICAgIFVSTGVuY29kZSgnYWxsW3NiXScpLAogICAgIiZzb3J0PWRhdGUiCiAgKSU+JXJlYWRfaHRtbCgpJT4laHRtbF9ub2RlcygiLnZhbHVlIiklPiVodG1sX3RleHQoKSU+JS5bMV0lPiVnc3ViKCIsIiwiIiwuKSU+JWFzLm51bWVyaWMoKQogIEs8LXBhc3RlMCgjdGhlIGFtb3VudHMgb2YgbGl0ZXJhdHVyZSByZWxhdGVkIHRvIG9zdGVvYmxhc3QgZGlmZmVyZW50aWF0aW9uICMyMDIxMDUwNiMgUHViTWVkIFF1ZXJ5OiAKICAgICJodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292Lz90ZXJtPSIsCiAgICBVUkxlbmNvZGUoTWVzaF90ZXJtNEludGVyZXN0aW5nKSwKICAgICImc29ydD1kYXRlIgogICklPiVyZWFkX2h0bWwoKSU+JWh0bWxfbm9kZXMoIi52YWx1ZSIpJT4laHRtbF90ZXh0KCklPiUuWzFdJT4lZ3N1YigiLCIsIiIsLiklPiVhcy5udW1lcmljKCkKICBUaHJlc2g8LUsvTioxMAogIAogICMjIyN8cHJlcGFyZSBnZW5lLXJlbGF0ZWQgYXJ0aWNsZXN8IyMjIwogICMgaHNhcGllbnNfZ2VuZV9lbnNlbWJsOyBtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsOyBybm9ydmVnaWN1c19nZW5lX2Vuc2VtYmw7IHNzY3JvZmFfZ2VuZV9lbnNlbWJsCiAgIyBIb21vIHNhcGllbnMgKEh1bWFuKSBbOTYwNl07IE11cyBtdXNjdWx1cyAoTW91c2UpIFsxMDA5MF07IFJhdHR1cyBub3J2ZWdpY3VzIChyYXQpIFsxMDExNl07IFN1cyBzY3JvZmEgKHBpZykgWzk4MjNdCiAgIyAoaHVtYW4pIEhvbW8gc2FwaWVucyAoaHVtYW4pIFtoc2FdOyAobW91c2UpIE11cyBtdXNjdWx1cyAobW91c2UpIFttbXVdOyAocmF0KSBSYXR0dXMgbm9ydmVnaWN1cyBbcm5vXTsgKHBpZykgU3VzIHNjcm9mYSBbc3NjXQogICMgaHNhcGllbnNfaG9tb2xvZ19lbnNlbWJsX2dlbmU7IG1tdXNjdWx1c19ob21vbG9nX2Vuc2VtYmxfZ2VuZTsgcm5vcnZlZ2ljdXNfaG9tb2xvZ19lbnNlbWJsX2dlbmU7IHNzY3JvZmFfaG9tb2xvZ19lbnNlbWJsX2dlbmUKICBwcmludChHZW5lc0xzKQogIHByaW50KE1lc2hfdGVybTRJbnRlcmVzdGluZykKICBwcmludChTcGVjaWVzKQogIGlmIChpcy5mdW5jdGlvbih1cGRhdGVQcm9ncmVzcykpIHsKICAgIHRleHQgPC0gIkdldCBBbGwgSG9tb2xvZ29ldXMgR2VuZXMiCiAgICB1cGRhdGVQcm9ncmVzcyhkZXRhaWwgPSB0ZXh0KQogIH0KICBpZihTcGVjaWVzID09ICJIc2EiKXsKICAgIFBhcl9zcGVjaWVzIDwtICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiCiAgICBQYXJfc3BlY2llcy5Vbmlwcm90IDwtICI5NjA2IgogICAgSG9tb19zcGVjaWVzIDwtIGMoCiAgICAgICJtbXVzY3VsdXNfaG9tb2xvZ19lbnNlbWJsX2dlbmUiLAogICAgICAicm5vcnZlZ2ljdXNfaG9tb2xvZ19lbnNlbWJsX2dlbmUiLAogICAgICAic3Njcm9mYV9ob21vbG9nX2Vuc2VtYmxfZ2VuZSIKICAgICkKICB9ZWxzZSBpZihTcGVjaWVzID09ICJNdXMiKXsKICAgIFBhcl9zcGVjaWVzIDwtICJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIgogICAgUGFyX3NwZWNpZXMuVW5pcHJvdCA8LSAiMTAwOTAiCiAgICBIb21vX3NwZWNpZXMgPC0gYygKICAgICAgImhzYXBpZW5zX2hvbW9sb2dfZW5zZW1ibF9nZW5lIiwKICAgICAgInJub3J2ZWdpY3VzX2hvbW9sb2dfZW5zZW1ibF9nZW5lIiwKICAgICAgInNzY3JvZmFfaG9tb2xvZ19lbnNlbWJsX2dlbmUiCiAgICApCiAgfWVsc2UgaWYoU3BlY2llcyA9PSAiUm5vIil7CiAgICBQYXJfc3BlY2llcyA8LSAicm5vcnZlZ2ljdXNfZ2VuZV9lbnNlbWJsIgogICAgUGFyX3NwZWNpZXMuVW5pcHJvdCA8LSAiMTAxMTYiCiAgICBIb21vX3NwZWNpZXMgPC0gYygKICAgICAgIm1tdXNjdWx1c19ob21vbG9nX2Vuc2VtYmxfZ2VuZSIsCiAgICAgICJoc2FwaWVuc19ob21vbG9nX2Vuc2VtYmxfZ2VuZSIsCiAgICAgICJzc2Nyb2ZhX2hvbW9sb2dfZW5zZW1ibF9nZW5lIgogICAgKQogIH1lbHNlIGlmKFNwZWNpZXMgPT0gIlNzYyIpewogICAgUGFyX3NwZWNpZXMgPC0gInNzY3JvZmFfZ2VuZV9lbnNlbWJsIgogICAgUGFyX3NwZWNpZXMuVW5pcHJvdCA8LSAiOTgyMyIKICAgIEhvbW9fc3BlY2llcyA8LSBjKAogICAgICAibW11c2N1bHVzX2hvbW9sb2dfZW5zZW1ibF9nZW5lIiwKICAgICAgInJub3J2ZWdpY3VzX2hvbW9sb2dfZW5zZW1ibF9nZW5lIiwKICAgICAgImhzYXBpZW5zX2hvbW9sb2dfZW5zZW1ibF9nZW5lIgogICAgKQogIH0KICBwcmludChQYXJfc3BlY2llcykKICBwcmludChQYXJfc3BlY2llcy5Vbmlwcm90KQogIHF1ZXJ5LnJlczwtUmV0cmlldmVFbnRyZXpJRChQYXJfc3BlY2llcz1QYXJfc3BlY2llcywgUGFyX3NwZWNpZXMuVW5pcHJvdD1QYXJfc3BlY2llcy5Vbmlwcm90LCBHZW5lc0xzPUdlbmVzTHMpCiAgaG9tb2xvZ2V1czEgPC0gUmV0cmlldmVFbnRyZXpJRCgKICAgIEhvbW9sb2d1ZXM9VFJVRSwgSG9tb19zcGVjaWVzPUhvbW9fc3BlY2llc1sxXSwgUGFyX3NwZWNpZXM9UGFyX3NwZWNpZXMsCiAgICBQYXJfc3BlY2llcy5Vbmlwcm90PVBhcl9zcGVjaWVzLlVuaXByb3QsIEdlbmVzTHM9R2VuZXNMcywgdXBkYXRlUHJvZ3Jlc3MgPSB1cGRhdGVQcm9ncmVzcwogICkKICBob21vbG9nZXVzMiA8LSBSZXRyaWV2ZUVudHJleklEKAogICAgSG9tb2xvZ3Vlcz1UUlVFLCBIb21vX3NwZWNpZXM9SG9tb19zcGVjaWVzWzJdLCBQYXJfc3BlY2llcz1QYXJfc3BlY2llcywKICAgIFBhcl9zcGVjaWVzLlVuaXByb3Q9UGFyX3NwZWNpZXMuVW5pcHJvdCwgR2VuZXNMcz1HZW5lc0xzLCB1cGRhdGVQcm9ncmVzcyA9IHVwZGF0ZVByb2dyZXNzCiAgKQogIGhvbW9sb2dldXMzIDwtIFJldHJpZXZlRW50cmV6SUQoCiAgICBIb21vbG9ndWVzPVRSVUUsIEhvbW9fc3BlY2llcz1Ib21vX3NwZWNpZXNbM10sIFBhcl9zcGVjaWVzPVBhcl9zcGVjaWVzLAogICAgUGFyX3NwZWNpZXMuVW5pcHJvdD1QYXJfc3BlY2llcy5Vbmlwcm90LCBHZW5lc0xzPUdlbmVzTHMsIHVwZGF0ZVByb2dyZXNzID0gdXBkYXRlUHJvZ3Jlc3MKICApCiAgCiAgI0NhbGN1bGF0ZSByZXN1bHRzIGFuZCBjb25zdHJ1Y3QgdGhlIGxpdGVyYXR1cmUgbWluaW5nIHRhYmxlCiAgbGl0ZXJhdHVyZS5taW5pbmc8LWRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAwLCBuY29sPTE0KSkKICBjb2xuYW1lcyhsaXRlcmF0dXJlLm1pbmluZyk8LWMoImVuc2VtYmxfZ2VuZV9pZCIsImVudHJlemdlbmVfaWQiLCJHZW5lU3ltYm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdlbmVfYmlvdHlwZSIsICJOIiwgIksiLCAibiIsICJrIiwgIlIiLCAiMTB4IEJhY2tncm91bmQgb2YgUiIsIlAudmFsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZSByZWxhdGVkIFBNSUQiLCAiT3ZlcmxhcHBlZCBQTUlEIiwgIk92ZXJsYXBwZWQgR2VuZXMgW0FydGljbGUgTm9dIikKICAjIFBhcl9wYiA8LSB0eHRQcm9ncmVzc0JhcihtaW49MSwgbWF4PW5yb3cocXVlcnkucmVzKSwgc3R5bGUgPSAzKQogIHByaW50KCJTdGFydExvb3AiKQogIGxpc3QucGFja2FnZXMgPC0gYygKICAgICJyZWFkeGwiLCAiZ2dwbG90MiIsICJnZ3B1YnIiLCAibWF0cml4U3RhdHMiLCAiZ2dyZXBlbCIsICJyZXNoYXBlMiIsICJkcGx5ciIsICJzdHJpbmdyIiwKICAgICJncmlkIiwgInRjbHRrIiwgInBhcmFsbGVsIiwgImRvUGFyYWxsZWwiLCAiZG9TTk9XIiwgImRhdGEudGFibGUiLCAiZ3Bsb3RzIiwKICAgICJyYW5kb21jb2xvUiIsICJmYWN0b2V4dHJhIiwgIlJDb2xvckJyZXdlciIsICJnckRldmljZXMiLCAiZ21wIiwgInh0YWJsZSIsICJsYXRleDJleHAiLAogICAgImh0dHIiLCAianNvbmxpdGUiLCAiY3VybCIsICJSQ3VybCIsICJtYWdyaXR0ciIsICJybGlzdCIsICJwaXBlUiIsICJwbHlyIiwKICAgICJ4bWwyIiwgInJ2ZXN0IiwgImtubi5jb3ZlcnRyZWUiLCAia25pdHIiLCAicmxhbmciLCAidmlzTmV0d29yayIsICJod3JpdGVyIiwgImh0bWx0b29scyIKICApCiAgYmlvLmxpc3QucGFja2FnZXMgPC0gYygKICAgICJsaW1tYSIsICJFeHBlcmltZW50SHViIiwgImNsdXN0ZXJQcm9maWxlciIsICJHTy5kYiIsCiAgICAib3JnLk1tLmVnLmRiIiwgInBhdGh2aWV3IiwgImVucmljaHBsb3QiLCAib3JnLkhzLmVnLmRiIgogICkKICB3enlfbWFpbmxvb3AgPC0gZnVuY3Rpb24oCiAgICBxdWVyeS5yZXMgPSBxdWVyeS5yZXMsIGF0dGVtcHRfbWF4ID0gNSwgVGhyZXNoID0gVGhyZXNoLAogICAgSyA9IEssIE4gPSBOLCBpID0gaQogICl7CiAgICBHZW5lSUQ8LWMoCiAgICAgIHF1ZXJ5LnJlcyRlbnRyZXpnZW5lX2lkW2ldLAogICAgICBob21vbG9nZXVzMVtxdWVyeS5yZXMkZW5zZW1ibF9nZW5lX2lkW2ldLCJlbnRyZXpnZW5lX2lkIl0sCiAgICAgIGhvbW9sb2dldXMyW3F1ZXJ5LnJlcyRlbnNlbWJsX2dlbmVfaWRbaV0sImVudHJlemdlbmVfaWQiXSwKICAgICAgaG9tb2xvZ2V1czNbcXVlcnkucmVzJGVuc2VtYmxfZ2VuZV9pZFtpXSwiZW50cmV6Z2VuZV9pZCJdCiAgICApCiAgICAjIyMjIENhbGN1bGF0ZSBuCiAgICAjIEdldCBVSUQgbnVtYmVyIHRoYXQgd2l0aGluIGludGVyZXN0ZWQgTWVTSCB0ZXJtCiAgICB1aWQucmVzPC1jKCkKICAgIGZvcihhIGluIEdlbmVJRCl7CiAgICAgICMgUmV0cmlldmUgUE1JRCBvZiBnZW5lLXJlbGF0ZWQgYXJ0aWNsZXMKICAgICAgIyBodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2Jvb2tzL05CSzI1NDk3L3RhYmxlL2NoYXB0ZXIyLlQuX2VudHJlel91bmlxdWVfaWRlbnRpZmllcnNfdWkvP3JlcG9ydD1vYmplY3Rvbmx5CiAgICAgICMgaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9ib29rcy9OQksyNTQ5OS8KICAgICAgIyBodHRwczovL2RhdGFndWlkZS5ubG0ubmloLmdvdi9ldXRpbGl0aWVzL3V0aWxpdGllcy5odG1sCiAgICAgICMgaHR0cHM6Ly9ldXRpbHMubmNiaS5ubG0ubmloLmdvdi9lbnRyZXovZXV0aWxzL2VsaW5rLmZjZ2k/ZGJmcm9tPWdlbmUmZGI9cHVibWVkJmlkPTY4Mzg5JmxpbmtuYW1lPWhvbW9sb2dlbmVfcHVibWVkCiAgICAgICMgaHR0cHM6Ly9ldXRpbHMubmNiaS5ubG0ubmloLmdvdi9lbnRyZXovZXV0aWxzL2VsaW5rLmZjZ2k/ZGJmcm9tPWdlbmUmZGI9cHVibWVkJmlkPTEyMzkzCiAgICAgIFVSTF90ZW1wPC1OVUxMCiAgICAgIGF0dGVtcHQ8LTEKICAgICAgdXJsIDwtIHBhc3RlMCgKICAgICAgICAiaHR0cHM6Ly9ldXRpbHMubmNiaS5ubG0ubmloLmdvdi9lbnRyZXovZXV0aWxzL2VsaW5rLmZjZ2k/ZGJmcm9tPWdlbmUmZGI9cHVibWVkJmlkPSIsCiAgICAgICAgYQogICAgICApCiAgICAgIHdoaWxlKGlzLm51bGwoVVJMX3RlbXApJiZhdHRlbXB0PGF0dGVtcHRfbWF4KXsKICAgICAgICB0cnkoewogICAgICAgICAgdXJsIDwtIHVybCh1cmwsICJyYiIpCiAgICAgICAgICBpZihjbGFzcyh1cmwpWzFdPT0idXJsIil7CiAgICAgICAgICAgIFVSTF90ZW1wIDwtIHJlYWRfeG1sKAogICAgICAgICAgICAgIHVybAogICAgICAgICAgICApJT4leG1sX2ZpbmRfYWxsKC4sICIuLy9JZCIpJT4leG1sX3RleHQoKQogICAgICAgICAgICBjbG9zZSh1cmwpCiAgICAgICAgICB9CiAgICAgICAgfSwgc2lsZW50ID0gVFJVRSkKICAgICAgICBhdHRlbXB0PC1hdHRlbXB0KzEKICAgICAgICBpZihpcy5udWxsKFVSTF90ZW1wKSl7U3lzLnNsZWVwKHJvdW5kKHJ1bmlmKDEsMTAsMTgwKSwxKSl9CiAgICAgIH0KICAgICAgdWlkLnJlczwtYygKICAgICAgICB1aWQucmVzLAogICAgICAgIFVSTF90ZW1wCiAgICAgICkKICAgIH0KICAgIHVpZC5yZXM8LXVuaXF1ZSh1aWQucmVzKQogICAgbjwtbGVuZ3RoKHVpZC5yZXMpCiAgICAjIyMjIENhbGN1bGF0ZSBrCiAgICBtYXhsaW1pdDwtMTI1CiAgICBpZihuPm1heGxpbWl0KXsKICAgICAgc3RlcDwtbiUvJW1heGxpbWl0CiAgICAgIG1vZDwtbiUlbWF4bGltaXQKICAgICAgc3RhcnQ8LXNlcShmcm9tPTEsIHRvPW1heGxpbWl0KnN0ZXAsIGJ5PW1heGxpbWl0KQogICAgICBlbmQ8LXNlcShmcm9tPW1heGxpbWl0LCB0bz1tYXhsaW1pdCpzdGVwLCBieT1tYXhsaW1pdCkKICAgICAgaWYobW9kPjApewogICAgICAgIHN0YXJ0PC1jKHN0YXJ0LCB0YWlsKGVuZCwgMSkrMSkKICAgICAgICBlbmQ8LWMoZW5kLCBuKQogICAgICB9CiAgICAgIHN0ZXA8LWxlbmd0aChzdGFydCkKICAgIH1lbHNlewogICAgICBzdGVwPC0xCiAgICAgIHN0YXJ0PC0xCiAgICAgIGVuZDwtbgogICAgfQogICAgazwtMAogICAgb3ZlcmxhcHBlZC51aWQ8LWMoKQogICAgZm9yKGEgaW4gMTpzdGVwKXsKICAgICAgVVJMX3RlbXA8LU5VTEwKICAgICAgYXR0ZW1wdDwtMQogICAgICB1cmwgPC0gVVJMZW5jb2RlKAogICAgICAgIHBhc3RlMCgKICAgICAgICAgICJodHRwczovL2V1dGlscy5uY2JpLm5sbS5uaWguZ292L2VudHJlei9ldXRpbHMvZXNlYXJjaC5mY2dpP2RiPXB1Ym1lZCZ0ZXJtPSIsCiAgICAgICAgICBwYXN0ZSh1aWQucmVzW3N0YXJ0W2FdOmVuZFthXV0sY29sbGFwc2U9IiwiKSwiW1VJRF0rQU5EKygiLFVSTGVuY29kZShNZXNoX3Rlcm00SW50ZXJlc3RpbmcpLCIpIiwKICAgICAgICAgICImcmV0dHlwZT1jb3VudCIKICAgICAgICApCiAgICAgICkKICAgICAgd2hpbGUoaXMubnVsbChVUkxfdGVtcCkmJmF0dGVtcHQ8YXR0ZW1wdF9tYXgpewogICAgICAgIHRyeSh7CiAgICAgICAgICB1cmwgPC0gdXJsKHVybCwgInJiIikKICAgICAgICAgIGlmKGNsYXNzKHVybClbMV09PSJ1cmwiKXsKICAgICAgICAgICAgVVJMX3RlbXAgPC0gcmVhZF94bWwoI3RoZSBhbW91bnRzIG9mIGFydGljbGVzIG9mIGVhY2ggZ2VuZSBvbiBpbnRlcmVzdGVkIE1lU0ggdGVybToKICAgICAgICAgICAgICB1cmwKICAgICAgICAgICAgKSU+JXhtbF9maW5kX2FsbCguLCAiLi8vQ291bnQiKSU+JXhtbF90ZXh0KCklPiUuWzFdJT4lYXMubnVtZXJpYygpCiAgICAgICAgICAgIGNsb3NlKHVybCkKICAgICAgICAgIH0KICAgICAgICB9LCBzaWxlbnQgPSBUUlVFKQogICAgICAgIGF0dGVtcHQ8LWF0dGVtcHQrMQogICAgICAgIGlmKGlzLm51bGwoVVJMX3RlbXApKXtTeXMuc2xlZXAocm91bmQocnVuaWYoMSwxMCwxODApLDEpKX0KICAgICAgfQogICAgICBpZihpcy5udWxsKFVSTF90ZW1wKSl7VVJMX3RlbXAgPC0gMH0KICAgICAgazwtaytVUkxfdGVtcAogICAgICBVUkxfdGVtcDwtTlVMTAogICAgICBhdHRlbXB0PC0xCiAgICAgIHVybCA8LSBVUkxlbmNvZGUoCiAgICAgICAgcGFzdGUwKAogICAgICAgICAgImh0dHBzOi8vZXV0aWxzLm5jYmkubmxtLm5paC5nb3YvZW50cmV6L2V1dGlscy9lc2VhcmNoLmZjZ2k/ZGI9cHVibWVkJnRlcm09IiwKICAgICAgICAgIHBhc3RlKHVpZC5yZXNbc3RhcnRbYV06ZW5kW2FdXSxjb2xsYXBzZT0iLCIpLCJbVUlEXStBTkQrKCIsVVJMZW5jb2RlKE1lc2hfdGVybTRJbnRlcmVzdGluZyksIikiLAogICAgICAgICAgIiZyZXR0eXBlPXVubGlzdCIKICAgICAgICApCiAgICAgICkKICAgICAgd2hpbGUoaXMubnVsbChVUkxfdGVtcCkmJmF0dGVtcHQ8YXR0ZW1wdF9tYXgpewogICAgICAgIHRyeSh7CiAgICAgICAgICB1cmwgPC0gdXJsKHVybCwgInJiIikKICAgICAgICAgIGlmKGNsYXNzKHVybClbMV09PSJ1cmwiKXsKICAgICAgICAgICAgVVJMX3RlbXAgPC0gcmVhZF94bWwoI3RoZSBhbW91bnRzIG9mIGFydGljbGVzIG9mIGVhY2ggZ2VuZSBvbiBpbnRlcmVzdGVkIE1lU0ggdGVybToKICAgICAgICAgICAgICB1cmwKICAgICAgICAgICAgKSU+JXhtbF9maW5kX2FsbCguLCAiLi8vSWQiKSU+JXhtbF90ZXh0KCkKICAgICAgICAgICAgY2xvc2UodXJsKQogICAgICAgICAgfQogICAgICAgIH0sIHNpbGVudCA9IFRSVUUpCiAgICAgICAgYXR0ZW1wdDwtYXR0ZW1wdCsxCiAgICAgICAgaWYoaXMubnVsbChVUkxfdGVtcCkpe1N5cy5zbGVlcChyb3VuZChydW5pZigxLDEwLDE4MCksMSkpfQogICAgICB9CiAgICAgIG92ZXJsYXBwZWQudWlkPC1jKAogICAgICAgIG92ZXJsYXBwZWQudWlkLAogICAgICAgIFVSTF90ZW1wCiAgICAgICkKICAgIH0KICAgIGlmKGlzLm5hKGspKXtrPC0wfQogICAgIyMjIyBDYWxjdWxhdGUgUAogICAgUjwtay9uCiAgICBQPC0wCiAgICBpZihrPDEpewogICAgICBQPC0wCiAgICB9ZWxzZXsKICAgICAgZm9yIChhIGluIDA6KGstMSkpIHsKICAgICAgICBQPC1QKygoY2hvb3NlWihLLGEpKmNob29zZVooTi1LLG4tYSkpL2Nob29zZVooTixuKSkKICAgICAgfQogICAgfQogICAgUDwtYXNOdW1lcmljKDEtUCkKICAgIGlmKFA9PTApe1A8LTEqMTBeLTMwMH0KICAgIHRlbXA8LWRhdGEuZnJhbWUoCiAgICAgIGVuc2VtYmxfZ2VuZV9pZD1xdWVyeS5yZXMkZW5zZW1ibF9nZW5lX2lkW2ldLAogICAgICBlbnRyZXpnZW5lX2lkPXF1ZXJ5LnJlcyRlbnRyZXpnZW5lX2lkW2ldLAogICAgICBHZW5lU3ltYm9sPXF1ZXJ5LnJlcyRleHRlcm5hbF9nZW5lX25hbWVbaV0sCiAgICAgIGdlbmVfYmlvdHlwZT1xdWVyeS5yZXMkZ2VuZV9iaW90eXBlW2ldLAogICAgICBOPU4sSz1LLG49bixrPWssUj1SLFRocmVzaD1UaHJlc2gsUD1QLAogICAgICBHZW5lUE1JRD11aWQucmVzJT4lcGFzdGUoLixjb2xsYXBzZSA9ICIsIiksCiAgICAgIE92ZXJsYXBQTUlEPW92ZXJsYXBwZWQudWlkJT4lcGFzdGUoLixjb2xsYXBzZSA9ICIsIikKICAgICkKICAgIGNvbG5hbWVzKHRlbXApPC1jKCJlbnNlbWJsX2dlbmVfaWQiLCJlbnRyZXpnZW5lX2lkIiwiR2VuZVN5bWJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAiZ2VuZV9iaW90eXBlIiwgIk4iLCAiSyIsICJuIiwgImsiLCAiUiIsICIxMHggQmFja2dyb3VuZCBvZiBSIiwiUC52YWx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAiR2VuZSByZWxhdGVkIFBNSUQiLCAiT3ZlcmxhcHBlZCBQTUlEIikKICAgIHJldHVybih0ZW1wKQogIH0KICBQYXJfY2w8LW1ha2VDbHVzdGVyKHBhcmFsbGVsbHk6OmZyZWVDb25uZWN0aW9ucygpLTIpCiAgcmVnaXN0ZXJEb1NOT1coUGFyX2NsKQogIFBhcl9wYiA8LSB0eHRQcm9ncmVzc0JhcihtaW49MSwgbWF4PW5yb3cocXVlcnkucmVzKSwgc3R5bGUgPSAzKQogIHByb2dyZXNzIDwtIGZ1bmN0aW9uKG4pIHNldFR4dFByb2dyZXNzQmFyKFBhcl9wYiwgbikKICBQYXJfb3B0czwtbGlzdChwcm9ncmVzcyA9IHByb2dyZXNzKQogICNSZWZlciBoZXJlIGZvciBhbGwgY29sdW1uIG5hbWVzIGZvciBFbnRyZXogQVBJIChodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2Jvb2tzL05CSzI1NTAxLykKICB0ZW1wPC1mb3JlYWNoKAogICAgaT0xOm5yb3cocXVlcnkucmVzKSwgLmNvbWJpbmU9cmJpbmQsIC5lcnJvcmhhbmRsaW5nID0gInJlbW92ZSIsIC5pbm9yZGVyPUZBTFNFLCAudmVyYm9zZSA9IEZBTFNFLAogICAgLm9wdGlvbnMuc25vdz1QYXJfb3B0cywgLnBhY2thZ2VzID0gYyhsaXN0LnBhY2thZ2VzLCBiaW8ubGlzdC5wYWNrYWdlcykKICApICVkb3BhciUgewogICAgdGVtcDMgPC0gTlVMTAogICAgdGVtcDMgPC0gd3p5X21haW5sb29wKHF1ZXJ5LnJlcyA9IHF1ZXJ5LnJlcywgYXR0ZW1wdF9tYXggPSA1LCBUaHJlc2ggPSBUaHJlc2gsIEsgPSBLLCBOID0gTiwgaSA9IGkpCiAgICBpZihpcy5udWxsKHRlbXAzKSl7CiAgICAgIHRlbXAzPC1kYXRhLmZyYW1lKAogICAgICAgIGVuc2VtYmxfZ2VuZV9pZD1xdWVyeS5yZXMkZW5zZW1ibF9nZW5lX2lkW2ldLAogICAgICAgIGVudHJlemdlbmVfaWQ9cXVlcnkucmVzJGVudHJlemdlbmVfaWRbaV0sCiAgICAgICAgR2VuZVN5bWJvbD1xdWVyeS5yZXMkZXh0ZXJuYWxfZ2VuZV9uYW1lW2ldLAogICAgICAgIGdlbmVfYmlvdHlwZT1xdWVyeS5yZXMkZ2VuZV9iaW90eXBlW2ldLAogICAgICAgIE49TkEsSz1OQSxuPU5BLGs9TkEsUj1OQSxUaHJlc2g9TkEsUD1OQSwKICAgICAgICBHZW5lUE1JRD1OQSwKICAgICAgICBPdmVybGFwUE1JRD1OQQogICAgICApCiAgICAgIGNvbG5hbWVzKHRlbXAzKTwtYygiZW5zZW1ibF9nZW5lX2lkIiwiZW50cmV6Z2VuZV9pZCIsIkdlbmVTeW1ib2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgImdlbmVfYmlvdHlwZSIsICJOIiwgIksiLCAibiIsICJrIiwgIlIiLCAiMTB4IEJhY2tncm91bmQgb2YgUiIsIlAudmFsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkdlbmUgcmVsYXRlZCBQTUlEIiwgIk92ZXJsYXBwZWQgUE1JRCIpCiAgICB9CiAgICByZXR1cm4odGVtcDMpCiAgfQogIHN0b3BDbHVzdGVyKFBhcl9jbCkKICBsaXRlcmF0dXJlLm1pbmluZzwtcmJpbmQobGl0ZXJhdHVyZS5taW5pbmcsdGVtcCkKICBybSh0ZW1wKQogIGdjKCkKICBwcmludCgiRW5kTG9vcCIpCiAgI0NvcnJlY3RpbmcgUC12YWx1ZSBmb3IgbXVsdGlwbGUgdGVzdGluZwogIGxpdGVyYXR1cmUubWluaW5nPC1jYmluZChsaXRlcmF0dXJlLm1pbmluZ1ssMToxMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkaj1wLmFkanVzdChhcy5udW1lcmljKGxpdGVyYXR1cmUubWluaW5nJFAudmFsdWUpLG1ldGhvZCA9ICJCSCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaXRlcmF0dXJlLm1pbmluZ1ssMTI6MTNdKQogIG91dDwtbGlzdCgKICAgIGxpdGVyYXR1cmUubWluaW5nPWxpdGVyYXR1cmUubWluaW5nLAogICAgcXVlcnkucmVzPXF1ZXJ5LnJlcywKICAgIGhvbW9sb2dldXMxPWhvbW9sb2dldXMxLAogICAgaG9tb2xvZ2V1czI9aG9tb2xvZ2V1czIsCiAgICBob21vbG9nZXVzMz1ob21vbG9nZXVzMwogICkKICBwcmludCgiZW5kIikKICByZXR1cm4ob3V0KQp9CgpsaXRlcmF0dXJlTWluaW5nUGxvdDwtZnVuY3Rpb24oCiAgICBsaXRlcmF0dXJlLm1pbmluZz1vdXQkbGl0ZXJhdHVyZS5taW5pbmcsIFRocmVzaC5SPU5VTEwsCiAgICB1c2UuUGFkaiA9IEZBTFNFLCBUaHJlc2guUD0wLjA1LCBsYWJlbD1UUlVFLCBsYWJlbF9uPTUKKXsKICAjIHByaW50KCJQbG90dGluZyIpCiAgIyBQbG90dGluZyBSZXN1bHRzCiAgbGl0ZXJhdHVyZS5taW5pbmckbjwtYXMubnVtZXJpYyhsaXRlcmF0dXJlLm1pbmluZyRuKQogIGxpdGVyYXR1cmUubWluaW5nJGs8LWFzLm51bWVyaWMobGl0ZXJhdHVyZS5taW5pbmckaykKICBsaXRlcmF0dXJlLm1pbmluZyRSPC1hcy5udW1lcmljKGxpdGVyYXR1cmUubWluaW5nJFIpCiAgaWYoaXMubnVsbChUaHJlc2guUikpewogICAgVGhyZXNoPC1saXRlcmF0dXJlLm1pbmluZyRgMTB4IEJhY2tncm91bmQgb2YgUmBbMV0KICB9ZWxzZXsKICAgIFRocmVzaDwtVGhyZXNoLlIKICB9CiAgZGY8LWxpdGVyYXR1cmUubWluaW5nWywxOjEyXSAKICBkZiRSPC1kZiRSKjEwMDAKICBkZiRuPC1sb2cxMChkZiRuKQogIGRmJFI8LXBzZXVkb0xvZzEwKGRmJFIpCiAgZGYkcC5hZGo8LXBzZXVkb0xvZzEwKGxvZygxL2RmJHAuYWRqLDIpKQogIGRmJFAudmFsdWU8LXBzZXVkb0xvZzEwKGxvZygxL2RmJFAudmFsdWUsMikpCiAgZGYgPC0gZGZbb3JkZXIoZGYkUC52YWx1ZSksIF0KICBtYXhSPC0obWF4KGRmJFIsIG5hLnJtPVQpKzAuMyklPiVyb3VuZCguLCBkaWdpdHMgPSAxKQogIG1heFA8LShtYXgoZGYkcC5hZGosIG5hLnJtPVQpKzAuMyklPiVyb3VuZCguLCBkaWdpdHMgPSAxKQogIFJlcExfUjwtbGVuZ3RoKHJlcCgwOm1heFIsIGVhY2ggPSA5KSklLyU5CiAgUmVwTF9QPC1sZW5ndGgocmVwKDA6bWF4UCwgZWFjaCA9IDkpKSUvJTkKICBpZih1c2UuUGFkail7CiAgICBncGxvdDwtZ2dwbG90KGRmLGFlcyh4PXAuYWRqLCB5PVIsIGNvbG91cj1uLCBzaXplPWsgKSkKICB9ZWxzZXsKICAgIGdwbG90PC1nZ3Bsb3QoZGYsYWVzKHg9UC52YWx1ZSwgeT1SLCBjb2xvdXI9biwgc2l6ZT1rICkpCiAgfQogIGdwbG90PC1ncGxvdCArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZXhwYW5kX2xpbWl0cyh4PTApICsKICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgbGltaXRzID0gYygwLG1heFIpLAogICAgICBicmVha3MgPSAwOm1heFIsCiAgICAgIGd1aWRlID0gInByaXNtX29mZnNldF9taW5vciIsCiAgICAgIG1pbm9yX2JyZWFrcyA9IHBzZXVkb0xvZzEwKHJlcCgxOjksIFJlcExfUikqKDEwXnJlcCgwOm1heFIsIGVhY2ggPSA5KSkpLAogICAgICBsYWJlbHMgPSAgZnVuY3Rpb24obGFiKXsKICAgICAgICBkby5jYWxsKAogICAgICAgICAgZXhwcmVzc2lvbiwKICAgICAgICAgIGxhcHBseShwYXN0ZShsYWIpLCBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgIGlmKHg9PTApe2JxdW90ZShib2xkKCIwIikpfWVsc2V7YnF1b3RlKGJvbGQoIjEwIl4uKHgpKSl9CiAgICAgICAgICB9KQogICAgICAgICkKICAgICAgfQogICAgKSsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgbGltaXRzID0gYygwLG1heFApLAogICAgICBicmVha3MgPSAwOm1heFAsCiAgICAgIGd1aWRlID0gInByaXNtX29mZnNldF9taW5vciIsCiAgICAgIG1pbm9yX2JyZWFrcyA9IHBzZXVkb0xvZzEwKHJlcCgxOjksIFJlcExfUCkqKDEwXnJlcCgwOm1heFAsIGVhY2ggPSA5KSkpLAogICAgICBsYWJlbHMgPSBmdW5jdGlvbihsYWIpewogICAgICAgIGRvLmNhbGwoCiAgICAgICAgICBleHByZXNzaW9uLAogICAgICAgICAgbGFwcGx5KHBhc3RlKGxhYiksIGZ1bmN0aW9uKHgpIHsKICAgICAgICAgICAgaWYoeD09MCl7YnF1b3RlKGJvbGQoIjAiKSl9ZWxzZXticXVvdGUoYm9sZCgiMTAiXi4oeCkpKX0KICAgICAgICAgIH0pCiAgICAgICAgKQogICAgICB9CiAgICApKwogICAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMCwyMCkpKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFjZT0iYm9sZCIpLAogICAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoNSwicHQiKSwKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ld2lkdGggPSAwLjcpLAogICAgKSsKICAgIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PXBzZXVkb0xvZzEwKFRocmVzaCoxMDAwKSwgbGluZXR5cGU9ImRhc2hlZCIsIAogICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplPTAuNCkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9cHNldWRvTG9nMTAobG9nKDEvVGhyZXNoLlAsMikpLCBsaW5ldHlwZT0iZGFzaGVkIiwgCiAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHNpemU9MC40KSsKICAgIGxhYnMoeD0ibG9nMigxL1AudmFsdWUpIiwgCiAgICAgICAgIHk9IlIgKOKAsCkiLCAKICAgICAgICAgdGl0bGU9IiIsCiAgICAgICAgIGNvbG91cj0ibG9nMTAoR2VuZSBSZWxhdGVkIEFydGljbGVzIE5vLikiLCBzaXplPSJUb3BpY3NcblJlbGF0ZWQgQXJ0aWNsZXMgTm8uIikrCiAgICBhbm5vdGF0aW9uX2N1c3RvbSgKICAgICAgZ3JvYiA9IGdyaWQ6OmxpbmVzR3JvYihncD1ncGFyKGx3ZD0yKSksCiAgICAgIHhtaW4gPSAtSW5mLAogICAgICB4bWF4ID0gLUluZiwKICAgICAgeW1pbiA9IDAsCiAgICAgIHltYXggPSBtYXhSCiAgICApKwogICAgYW5ub3RhdGlvbl9jdXN0b20oCiAgICAgIGdyb2IgPSBncmlkOjpsaW5lc0dyb2IoZ3A9Z3Bhcihsd2Q9MikpLAogICAgICB4bWluID0gMCwKICAgICAgeG1heCA9IG1heFAsCiAgICAgIHltaW4gPSAtSW5mLAogICAgICB5bWF4ID0gLUluZgogICAgKQogICNwcmludCgiUGxvdHRpbmdFbmQiKQogIGlmKGxhYmVsX24gPT0gIkFsbCIpewogICAgbGFiZWxfbiA8LSBucm93KGRmKSAKICB9CiAgaWYobGFiZWwpewogICAgaWYodXNlLlBhZGopewogICAgICBkZiA8LSBkZltkZiRSPj1wc2V1ZG9Mb2cxMChUaHJlc2gqMTAwMCkgJiBkZiRwLmFkaj49cHNldWRvTG9nMTAobG9nKDEvVGhyZXNoLlAsMikpLCBdCiAgICB9ZWxzZXsKICAgICAgZGYgPC0gZGZbZGYkUj49cHNldWRvTG9nMTAoVGhyZXNoKjEwMDApICYgZGYkUC52YWx1ZT49cHNldWRvTG9nMTAobG9nKDEvVGhyZXNoLlAsMikpLCBdCiAgICB9CiAgICBkZiA8LSBkZltvcmRlcihkZiRQLnZhbHVlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KICAgIGdwbG90IDwtIGdwbG90ICsgZ2VvbV90ZXh0X3JlcGVsKAogICAgICBkYXRhID0gZGZbMTpsYWJlbF9uLCBdLAogICAgICBhZXMobGFiZWw9R2VuZVN5bWJvbCksaGp1c3Q9MCwgdmp1c3Q9MCwgc2l6ZT04LCBjb2xvcj0iZGFya3JlZCIKICAgICkKICB9CiAgcmV0dXJuKGdwbG90KQp9CgpsaXRlcmF0dXJlTWluaW5nT3ZlcmxhcHBlZEdlbmVzPC1mdW5jdGlvbihvdXQsIHVwZGF0ZVByb2dyZXNzID0gTlVMTCl7CiAgCiAgbGl0ZXJhdHVyZS5taW5pbmc8LW91dCRsaXRlcmF0dXJlLm1pbmluZwogIHF1ZXJ5LnJlczwtb3V0JHF1ZXJ5LnJlcwogIGhvbW9sb2dldXMxPC1vdXQkaG9tb2xvZ2V1czEKICBob21vbG9nZXVzMjwtb3V0JGhvbW9sb2dldXMyCiAgaG9tb2xvZ2V1czM8LW91dCRob21vbG9nZXVzMwogIAogIG91dGxzPC1jKCkKICAKICBmb3IoaSBpbiAxOm5yb3cocXVlcnkucmVzKSl7CiAgICBwcmludChwYXN0ZTAoaSwiLyIsbnJvdyhxdWVyeS5yZXMpKSkKICAgIGlmIChpcy5mdW5jdGlvbih1cGRhdGVQcm9ncmVzcykpIHsKICAgICAgdGV4dCA8LSBwYXN0ZTAoaSwiIGluICIsbnJvdyhxdWVyeS5yZXMpKQogICAgICB1cGRhdGVQcm9ncmVzcyhtZXNzYWdlID0gdGV4dCwgZGV0YWlsID0gdGV4dCkKICAgIH0KICAgIEdlbmVJRDwtYygKICAgICAgcXVlcnkucmVzJGVudHJlemdlbmVfaWRbaV0sCiAgICAgIGhvbW9sb2dldXMxW3F1ZXJ5LnJlcyRlbnNlbWJsX2dlbmVfaWRbaV0sImVudHJlemdlbmVfaWQiXSwKICAgICAgaG9tb2xvZ2V1czJbcXVlcnkucmVzJGVuc2VtYmxfZ2VuZV9pZFtpXSwiZW50cmV6Z2VuZV9pZCJdLAogICAgICBob21vbG9nZXVzM1txdWVyeS5yZXMkZW5zZW1ibF9nZW5lX2lkW2ldLCJlbnRyZXpnZW5lX2lkIl0KICAgICklPiUuWyFpcy5uYSguKV0KICAgIAogICAgb3ZlcmxhcHBlZC51aWQ8LWxpdGVyYXR1cmUubWluaW5nJGBPdmVybGFwcGVkIFBNSURgW2ldJT4lc3RyX3NwbGl0KC4sIiwiKSU+JXVubGlzdCgpCiAgICAKICAgIG92ZXJsYXBwZWQuZ2VuZXM8LWRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAwLCBuY29sPTMpKQogICAgY29sbmFtZXMob3ZlcmxhcHBlZC5nZW5lcyk8LWMoIkdlbmVTeW1ib2wiLCJlbnRyZXpnZW5lX2lkIiwiT3ZlcmxhcHBlZF9QTUlEIikKICAgIGlmKG92ZXJsYXBwZWQudWlkWzFdIT0iIil7CiAgICAgIAogICAgICBmb3IodWlkIGluIG92ZXJsYXBwZWQudWlkKXsKICAgICAgICAKICAgICAgICBwcmludChwYXN0ZTAoIlBNSUQ6IiwgdWlkLCAiICgiLCB3aGljaChvdmVybGFwcGVkLnVpZD09dWlkKSwiIG9mICIsbGVuZ3RoKG92ZXJsYXBwZWQudWlkKSwgIikiKSkKICAgICAgICB0ZW1wLmdlbmU8LXJlYWRfeG1sKAogICAgICAgICAgcGFzdGUwKAogICAgICAgICAgICAiaHR0cHM6Ly9ldXRpbHMubmNiaS5ubG0ubmloLmdvdi9lbnRyZXovZXV0aWxzL2VsaW5rLmZjZ2k/ZGJmcm9tPXB1Ym1lZCZkYj1nZW5lJmlkPSIsCiAgICAgICAgICAgIHVpZAogICAgICAgICAgKQogICAgICAgICklPiV4bWxfZmluZF9hbGwoLiwgIi4vL0lkIiklPiV4bWxfdGV4dCgpJT4lLlstMV0lPiV1bmlxdWUoKSU+JS5bIS4laW4lR2VuZUlEXQogICAgICAgIAogICAgICAgIGlmKGlzX2VtcHR5KHRlbXAuZ2VuZSkpe25leHR9CiAgICAgICAgaWYobGVuZ3RoKHRlbXAuZ2VuZSk+NTAwKXtuZXh0fQogICAgICAgIAogICAgICAgIGEubjwtbGVuZ3RoKHRlbXAuZ2VuZSkKICAgICAgICBtYXhsaW1pdDwtNTAKICAgICAgICBpZihhLm4+bWF4bGltaXQpewogICAgICAgICAgc3RlcDwtYS5uJS8lbWF4bGltaXQKICAgICAgICAgIG1vZDwtYS5uJSVtYXhsaW1pdAogICAgICAgICAgc3RhcnQ8LXNlcShmcm9tPTEsIHRvPW1heGxpbWl0KnN0ZXAsIGJ5PW1heGxpbWl0KQogICAgICAgICAgZW5kPC1zZXEoZnJvbT1tYXhsaW1pdCwgdG89bWF4bGltaXQqc3RlcCwgYnk9bWF4bGltaXQpCiAgICAgICAgICBpZihtb2Q+MCl7CiAgICAgICAgICAgIHN0YXJ0PC1jKHN0YXJ0LCB0YWlsKGVuZCwgMSkrMSkKICAgICAgICAgICAgZW5kPC1jKGVuZCwgYS5uKQogICAgICAgICAgfQogICAgICAgICAgc3RlcDwtbGVuZ3RoKHN0YXJ0KQogICAgICAgIH1lbHNlewogICAgICAgICAgc3RlcDwtMQogICAgICAgICAgc3RhcnQ8LTEKICAgICAgICAgIGVuZDwtYS5uCiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmKHN0ZXA+MSl7CiAgICAgICAgICBwYiA8LSB0eHRQcm9ncmVzc0JhcihtaW49MSwgbWF4PXN0ZXAsIHN0eWxlID0gMykKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgcmVtb3ZlSWR4PC1jKCkKICAgICAgICBHZW5lU3ltYm9sPC1jKCkKICAgICAgICBmb3IoYSBpbiAxOnN0ZXApewogICAgICAgICAgI3ByaW50KHBhc3RlMCgiYjoiLHdoaWNoKHRlbXAuZ2VuZT09YiksIjsiLGxlbmd0aCh0ZW1wLmdlbmUpKSkKICAgICAgICAgIEdTQjwtcmVhZF9odG1sKAogICAgICAgICAgICBwYXN0ZTAoCiAgICAgICAgICAgICAgImh0dHBzOi8vZXV0aWxzLm5jYmkubmxtLm5paC5nb3YvZW50cmV6L2V1dGlscy9lZmV0Y2guZmNnaT9kYj1nZW5lJmlkPSIsCiAgICAgICAgICAgICAgdGVtcC5nZW5lW3N0YXJ0W2FdOmVuZFthXV0lPiVwYXN0ZSguLGNvbGxhcHNlID0gIiwiKSwKICAgICAgICAgICAgICAiJnJldHR5cGU9dW5saXN0IgogICAgICAgICAgICApCiAgICAgICAgICApCiAgICAgICAgICBsaDwtKGVuZFthXS1zdGFydFthXSsxKQogICAgICAgICAgaWYobGg9PTEpewogICAgICAgICAgICB0ZXN0PC14bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoeG1sX2NoaWxkKEdTQiwgMSksIDEpLCAxKSwgMSksIDIpJT4leG1sX3RleHQoKSU+JWdyZXAoIk9mZmljaWFsIFN5bWJvbDoiLC4pCiAgICAgICAgICAgIGlmKCFpc19lbXB0eSh0ZXN0KSl7CiAgICAgICAgICAgICAgR2VuZVN5bWJvbDwtYygKICAgICAgICAgICAgICAgIEdlbmVTeW1ib2wsCiAgICAgICAgICAgICAgICB4bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoR1NCLCAxKSwgMSksIDEpLCAxKSwgMiksIDIpLCAyKSU+JXhtbF90ZXh0KCkKICAgICAgICAgICAgICApCiAgICAgICAgICAgIH1lbHNlewogICAgICAgICAgICAgIHJlbW92ZUlkeDwtYygKICAgICAgICAgICAgICAgIHJlbW92ZUlkeCwxCiAgICAgICAgICAgICAgKQogICAgICAgICAgICB9CiAgICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgZm9yKGIgaW4gMTpsaCl7CiAgICAgICAgICAgICAgdGVzdDwteG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZChHU0IsIDEpLCAxKSwgMSksIGIpLCAyKSU+JXhtbF90ZXh0KCklPiVncmVwKCJPZmZpY2lhbCBTeW1ib2w6IiwuKQogICAgICAgICAgICAgIGlmKCFpc19lbXB0eSh0ZXN0KSl7CiAgICAgICAgICAgICAgICBHZW5lU3ltYm9sPC1jKAogICAgICAgICAgICAgICAgICBHZW5lU3ltYm9sLAogICAgICAgICAgICAgICAgICB4bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoeG1sX2NoaWxkKHhtbF9jaGlsZCh4bWxfY2hpbGQoeG1sX2NoaWxkKEdTQiwgMSksIDEpLCAxKSwgYiksIDIpLCAyKSwgMiksIDIpJT4leG1sX3RleHQoKQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgIH1lbHNlewogICAgICAgICAgICAgICAgcmVtb3ZlSWR4PC1jKAogICAgICAgICAgICAgICAgICByZW1vdmVJZHgsKGIrc3RhcnRbYV0tMSkKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIAogICAgICAgICAgaWYoc3RlcD4xKXsKICAgICAgICAgICAgc2V0VHh0UHJvZ3Jlc3NCYXIocGIsIGEpCiAgICAgICAgICB9CiAgICAgICAgICBpZihpcy5mdW5jdGlvbih1cGRhdGVQcm9ncmVzcykpIHsKICAgICAgICAgICAgdGV4dCA8LSBwYXN0ZTAoYSwiIGluICIsc3RlcCkKICAgICAgICAgICAgdXBkYXRlUHJvZ3Jlc3MobWVzc2FnZSA9IHBhc3RlMChpLCIgaW4gIixucm93KHF1ZXJ5LnJlcykpLCBkZXRhaWwgPSB0ZXh0KQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZihzdGVwPjEpe2Nsb3NlKHBiKX0KICAgICAgICBpZighaXNfZW1wdHkocmVtb3ZlSWR4KSl7CiAgICAgICAgICB0ZW1wLmdlbmU8LXRlbXAuZ2VuZVstcmVtb3ZlSWR4XQogICAgICAgIH0KICAgICAgICAKICAgICAgICBpZighaXNfZW1wdHkodGVtcC5nZW5lKSl7CiAgICAgICAgICB0ZW1wPC1kYXRhLmZyYW1lKAogICAgICAgICAgICBHZW5lU3ltYm9sPUdlbmVTeW1ib2wlPiVzdHJfdG9fdGl0bGUoKSwKICAgICAgICAgICAgZW50cmV6Z2VuZV9pZD10ZW1wLmdlbmUsCiAgICAgICAgICAgIE92ZXJsYXBwZWRfUE1JRD1yZXAodWlkLGxlbmd0aCh0ZW1wLmdlbmUpKQogICAgICAgICAgKQogICAgICAgICAgb3ZlcmxhcHBlZC5nZW5lczwtcmJpbmQoCiAgICAgICAgICAgIG92ZXJsYXBwZWQuZ2VuZXMsCiAgICAgICAgICAgIHRlbXAKICAgICAgICAgICkKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIAogICAgdGVtcDwtYygpCiAgICBPcmRlcklEPC1jKCkKICAgIGZvcihhIGluIG92ZXJsYXBwZWQuZ2VuZXMkR2VuZVN5bWJvbCU+JXVuaXF1ZSgpKXsKICAgICAgdGVtcDI8LW92ZXJsYXBwZWQuZ2VuZXNbb3ZlcmxhcHBlZC5nZW5lcyRHZW5lU3ltYm9sPT1hLF0KICAgICAgT3JkZXJJRDwtYygKICAgICAgICBPcmRlcklELAogICAgICAgIGxlbmd0aCh0ZW1wMiRPdmVybGFwcGVkX1BNSUQlPiV1bmlxdWUoKSkKICAgICAgKQogICAgICB0ZW1wPC1jKAogICAgICAgIHRlbXAsCiAgICAgICAgcGFzdGUwKAogICAgICAgICAgdGVtcDIkR2VuZVN5bWJvbFsxXSwKICAgICAgICAgICIgKEVudHJleklEOiIsIHRlbXAyJGVudHJlemdlbmVfaWRbMV0sICI7IiwKICAgICAgICAgICJPdmVybGFwcGVkX1BNSURbIiwgdGFpbChPcmRlcklELDEpLCAiXToiLCBwYXN0ZSh0ZW1wMiRPdmVybGFwcGVkX1BNSUQlPiV1bmlxdWUoKSxjb2xsYXBzZSA9ICIsIiksIikiIAogICAgICAgICkKICAgICAgKQogICAgfQogICAgT3JkZXJJRDwtYXMubnVtZXJpYyhPcmRlcklEKQogICAgT3JkZXJJRDwtb3JkZXIoeD1PcmRlcklELCBkZWNyZWFzaW5nPVRSVUUsIG5hLmxhc3Q9VCkKICAgIG92ZXJsYXBwZWQuZ2VuZXM8LXRlbXAlPiUuW09yZGVySURdJT4lcGFzdGUoLixjb2xsYXBzZSA9ICIgIikKICAgIG91dGxzPC1jKAogICAgICBvdXRscyxvdmVybGFwcGVkLmdlbmVzCiAgICApCiAgfQogIAogIG92ZXJsYXBwZWQuZ2VuZXM8LWNiaW5kKAogICAgbGl0ZXJhdHVyZS5taW5pbmdbLDE6NF0sCiAgICBvdmVybGFwcGVkLmdlbmVzPW91dGxzCiAgKQogIAogIHJldHVybihvdmVybGFwcGVkLmdlbmVzKQogIAp9CmxpYnJhcnkocmxhbmcpCmxpYnJhcnkoZ2dwcmlzbSkKYGBgCgojIDAxLiBMaXRlcmF0dXJlLW1pbmluZwoKR2V0IHRoZSB0YXJnZXQgZ2VuZXMgb2YgdGhlIGZpbmFsIDEwIFRGcyBpbiB0aGUgZ2VuZSByZWd1bGF0b3J5IG5ldHdvcmsuCgpgYGB7ciAwMS0wMX0KVGFyZ2V0cyA8LSBjKCkKZm9yIChpIGluIFRGcy5NZXNoLmtlZXAkR2VuZVN5bWJvbCkgewogIFRhcmdldHMgPC0gYygKICAgIFRhcmdldHMsCiAgICBURkxpbmskTkNCSS5HZW5lSUQuVGFyZ2V0W1RGTGluayROYW1lLlRGICVpbiUgaV0gJT4lIHN0cl9zcGxpdCguLCAiOyIpICU+JSAKICAgICAgdW5saXN0KCkgJT4lIGFzLnZlY3RvcigpICU+JSB1bmlxdWUoKSAlPiUgey5bLltdIT0iLSJdfQogICkKfQpUYXJnZXRzIDwtIHRhYmxlKFRhcmdldHMpICU+JSBhcy5kYXRhLmZyYW1lKCkKVGFyZ2V0cyA8LSBUYXJnZXRzW1RhcmdldHMkRnJlcSA+IDcsIF0KY29sbmFtZXMoVGFyZ2V0cykgPC0gYygiRU5UUkVaSUQiLCAiRnJlcSIpCkFubm8gPC0gc2VsZWN0KG9yZy5Icy5lZy5kYiwga2V5cyA9IGFzLmNoYXJhY3RlcihUYXJnZXRzJEVOVFJFWklEKSwgY29sdW1ucyA9IGMoIkVOVFJFWklEIiwgIkVOU0VNQkwiLCAiU1lNQk9MIiksIGtleXR5cGUgPSAiRU5UUkVaSUQiKQpBbm5vIDwtIEFubm9bIWR1cGxpY2F0ZWQoQW5ubyRFTlRSRVpJRCksXQpUYXJnZXRzIDwtIG1lcmdlKFRhcmdldHMsIEFubm8sIGJ5PSJFTlRSRVpJRCIpClRhcmdldHMgPC0gVGFyZ2V0c1tvcmRlcihUYXJnZXRzJEZyZXEsIGRlY3JlYXNpbmcgPSBUUlVFKSxdCnJvd25hbWVzKFRhcmdldHMpPC1jKDE6bnJvdyhUYXJnZXRzKSkgJT4lIGFzLmNoYXJhY3RlcigpCmhlYWQoVGFyZ2V0cywxMCkKYGBgCgpOb3cgbGV0J3MgZ2V0IHRoZSB0YXJnZXRzIHJlbGF0ZWQgdG8gYm90aCBNaXRvY2hvbmRyaWEgYW5kIEVuZG9wbGFzbWljIFJldGljdWx1bQoKYGBge3IgMDEtMDJ9Ck1lc2hfdGVybTRJbnRlcmVzdGluZyA8LSAnIk1pdG9jaG9uZHJpYSJbTWVzaF0gQU5EICJFbmRvcGxhc21pYyBSZXRpY3VsdW0iW01lc2hdJwpHZW5lc0xzIDwtIFRhcmdldHMkRU5TRU1CTApTcGVjaWVzIDwtICJIc2EiICMgSHNhIE11cyBSbm8gU3NjClRhcmdldHMuTWVzaDwtV1pZX2xpdGVyYXR1cmVNaW5pbmcoR2VuZXNMcz1HZW5lc0xzLCBNZXNoX3Rlcm00SW50ZXJlc3Rpbmc9TWVzaF90ZXJtNEludGVyZXN0aW5nLCBTcGVjaWVzPVNwZWNpZXMsIHVwZGF0ZVByb2dyZXNzID0gTlVMTCkKYGBgCgojIyBSZXN1bHRzCgpQbG90IG91dCByZXN1bHRzCgpgYGB7ciAwMS0wMywgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTgsIG91dC53aWR0aD0iMTAwJSJ9CmdwIDwtIGxpdGVyYXR1cmVNaW5pbmdQbG90KAogIGxpdGVyYXR1cmUubWluaW5nPVRhcmdldHMuTWVzaCRsaXRlcmF0dXJlLm1pbmluZywgVGhyZXNoLlI9MC4wMDIsCiAgdXNlLlBhZGogPSBGQUxTRSwgVGhyZXNoLlA9MC4wNSwgbGFiZWw9VFJVRSwgbGFiZWxfbiA9IDEwCikKc3ZnKGZpbGVuYW1lID0gZmlsZS5wYXRoKCIuIiwgIjAxLlBsb3RPdXQiLCAiTGl0ZXJhdHVyZU1pbmluZ1Jlc18wMy5zdmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOCwgcG9pbnRzaXplID0gMTIpCnByaW50KGdwKQpkZXYub2ZmKCkKZ3JhcGhpY3Mub2ZmKCkKa25pdHI6Om9wdHNfa25pdCRzZXQoZ2xvYmFsLmRldmljZSA9IFRSVUUpCnByaW50KGdwKQprbml0cjo6b3B0c19rbml0JHNldChnbG9iYWwuZGV2aWNlID0gRkFMU0UpCmBgYAoKIyAwMi4gU3VwcGxlbWVudGFyeQoKYGBge3IgMDMuU3VwcGxlbWVudGFyeX0Kc2F2ZS5pbWFnZSgiLi9DaGVja1BvaW50Mi5SRGF0YSIpCnNlc3Npb25JbmZvKCkKYGBgCg==