diff --git a/01_deploy_via_Docker.sh b/01_deploy_via_Docker.sh
new file mode 100644
index 0000000..2146cc0
--- /dev/null
+++ b/01_deploy_via_Docker.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+source scripts/colored_print.sh
+source scripts/check_and_set_email_credentials.sh
+source scripts/check_CPU_number.sh
+set -e
+
+#################### 1 email
+print_green "1. Configurations of email to send results"
+check_and_set_email_credentials
+
+#################### 2. CPU
+print_green "2. Configuration of CPU number"
+check_cpu_number
+
+#################### 3. Docker build
+print_green "3. Docker building"
+chmod 777 logs result
+docker-compose up -d
diff --git a/deploy_one_bash.sh b/01_deploy_via_bash.sh
similarity index 100%
rename from deploy_one_bash.sh
rename to 01_deploy_via_bash.sh
diff --git a/R/R_packages_installation.log b/R/R_packages_installation.log
new file mode 100644
index 0000000..cb815f9
--- /dev/null
+++ b/R/R_packages_installation.log
@@ -0,0 +1,46 @@
+[1] TRUE
+[1] TRUE
+[1] TRUE
+character(0)
+
+The installed packages are as follows:
+ [1] "av" "bslib"
+ [3] "daattali/shinycssloaders" "daattali/shinydisconnect"
+ [5] "data.table" "datawookie/emayili"
+ [7] "devtools" "dplyr"
+ [9] "dreamRs/shinybusy" "dreamRs/shinyWidgets"
+[11] "DT" "emayili"
+[13] "enrichplot" "future"
+[15] "gapminder" "ggasym"
+[17] "ggplot2" "ggpubr"
+[19] "glue" "Hmisc"
+[21] "httpuv" "jhrcook/ggasym"
+[23] "kableExtra" "magick"
+[25] "merlinoa/shinyFeedback" "msigdbr"
+[27] "openxlsx" "pak"
+[29] "pdftools" "plotly"
+[31] "promises" "pryr"
+[33] "qpdf" "r-lib/ragg"
+[35] "r-lib/rlang" "r-lib/systemfonts"
+[37] "r-lib/textshaping" "r-lib/usethis"
+[39] "r-rust/gifski" "ragg"
+[41] "RcppRoll" "reshape2"
+[43] "RinteRface/fullPage" "rintrojs"
+[45] "rJava" "rlang"
+[47] "rstudio/httpuv" "rsvg"
+[49] "rtracklayer" "scales"
+[51] "seqinr" "shiny"
+[53] "shinyBS" "shinybusy"
+[55] "shinycssloaders" "shinydashboard"
+[57] "shinydisconnect" "shinyFeedback"
+[59] "shinyjs" "shinythemes"
+[61] "shinyvalidate" "shinyWidgets"
+[63] "stringr" "svglite"
+[65] "systemfonts" "tesseract"
+[67] "textshaping" "tibble"
+[69] "tictoc" "tidyverse"
+[71] "usethis" "xfun"
+[73] "xlsxjars" "zip"
+
+The following packages could not be installed:
+[1] "pander"
diff --git a/R/app.R b/R/app.R
index f4c8197..72228bd 100644
--- a/R/app.R
+++ b/R/app.R
@@ -1,3 +1,6 @@
+Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library")
+.libPaths(new = "/usr/local/lib/R/library")
+
source("R/global.R")
ui <- fluidPage(
diff --git a/R/global.R b/R/global.R
index 97f5ce0..c071a88 100644
--- a/R/global.R
+++ b/R/global.R
@@ -1,52 +1,102 @@
+Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library")
+.libPaths(new = "/usr/local/lib/R/library")
+
+options(shiny.maxRequestSize = 30000 * 1024^2)
+
suppressMessages({
- # Used packages
- pacotes <- c(
- "bslib", # customizing the appearance of Shiny applications using Bootstrap.
- "data.table", # fast data manipulation and analysis.
- "DT", # creating interactive and customizable data tables in R.
- "dplyr", # data manipulation and transformation using a consistent grammar.
- "fullPage", # creating full-page scrolling websites.
- "future",
- "ggasym", # creating asymmetric visualizations with ggplot2.
- "ggpubr", # enhancing ggplot2 visualizations with publication-ready themes and annotations.
- "glue", # interpolating strings and expressions in R.
- "jsonify",
- "kableExtra", # creating complex tables in R Markdown documents.
- "openxlsx", # reading, writing, and manipulating Microsoft Excel files.
- "promises", # creating and managing asynchronous programming in R.
- "purrr", # functional programming and iterating over data structures.
- "reshape2", # transforming and restructuring data in R.
- "rintrojs", # creating interactive and guided tours in Shiny applications.
- "rjson", # converts R object into JSON objects and vice-versa.
- "rtracklayer", # read gff3
- "scales", # controlling the scaling of data in R graphics.
- "seqinr", # extract fasta's name
- "shiny", # building interactive web applications in R.
- "shinyBS", # adding additional Bootstrap functionality to Shiny applications.
- "shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools
- "shinydashboard", # creating dashboards with a tabbed layout in Shiny.
- "shinydisconnect", # handling disconnections and reconnections in Shiny applications.
- "shinyFeedback", # providing user feedback and notifications in Shiny applications.
- "shinycssloaders", # adding CSS loaders to Shiny applications.
- "shinyjs", # easily incorporating JavaScript functions and events in Shiny applications.
- "shinythemes", # customizing the appearance of Shiny applications with predefined themes.
- "shinyvalidate", # client-side form validation in Shiny applications.
- "shinyWidgets", # creating custom UI controls and widgets in Shiny.
- "snow", # parallel computing using a simple network of workstations.
- "tibble", # creating and manipulating data frames with enhanced features compared to traditional data frames.
- "tidyverse", # data manipulation, visualization, and analysis.
- "tictoc", # measuring the time taken by R code execution.
- "shinyvalidate", # shinyvalidate adds input validation capabilities to Shiny.
- "zip" # reading, writing, and manipulating ZIP archives in R.
-)
-
- # verify required packages installed or not. If some package
- # is missing, it will be installed automatically
- package.check <- lapply(pacotes, FUN = function(x) {
- if (!require(x, character.only = TRUE)) {
- install.packages(x, dependencies = TRUE)
- }
- })
+# # Used packages
+# pacotes <- c(
+# "emayili",
+# "bslib", # customizing the appearance of Shiny applications using Bootstrap.
+# "data.table", # fast data manipulation and analysis.
+# "DT", # creating interactive and customizable data tables in R.
+# "dplyr", # data manipulation and transformation using a consistent grammar.
+# "fullPage", # creating full-page scrolling websites.
+# "future",
+# "ggasym", # creating asymmetric visualizations with ggplot2.
+# "ggpubr", # enhancing ggplot2 visualizations with publication-ready themes and annotations.
+# "glue", # interpolating strings and expressions in R.
+# "kableExtra", # creating complex tables in R Markdown documents.
+# "openxlsx", # reading, writing, and manipulating Microsoft Excel files.
+# "promises", # creating and managing asynchronous programming in R.
+# "purrr", # functional programming and iterating over data structures.
+# "reshape2", # transforming and restructuring data in R.
+# "rintrojs", # creating interactive and guided tours in Shiny applications.
+# "rjson", # converts R object into JSON objects and vice-versa.
+# "rtracklayer", # read gff3
+# "scales", # controlling the scaling of data in R graphics.
+# "seqinr", # extract fasta's name
+# "shiny", # building interactive web applications in R.
+# "shinyBS", # adding additional Bootstrap functionality to Shiny applications.
+# "shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools
+# "shinydisconnect", # handling disconnections and reconnections in Shiny applications.
+# "shinyFeedback", # providing user feedback and notifications in Shiny applications.
+# "shinycssloaders", # adding CSS loaders to Shiny applications.
+# "shinyjs", # easily incorporating JavaScript functions and events in Shiny applications.
+# "shinythemes", # customizing the appearance of Shiny applications with predefined themes.
+# "shinyvalidate", # client-side form validation in Shiny applications.
+# "shinyWidgets", # creating custom UI controls and widgets in Shiny.
+# "snow", # parallel computing using a simple network of workstations.
+# "tibble", # creating and manipulating data frames with enhanced features compared to traditional data frames.
+# "tidyverse", # data manipulation, visualization, and analysis.
+# "tictoc", # measuring the time taken by R code execution.
+# "shinyvalidate", # shinyvalidate adds input validation capabilities to Shiny.
+# "zip" # reading, writing, and manipulating ZIP archives in R.
+# )
+
+# # # verify required packages installed or not. If some package
+# # # is missing, it will be installed automatically
+# # package.check <- lapply(pacotes, FUN = function(x) {
+# # if (!require(x, character.only = TRUE)) {
+# # print(x)
+# # install.packages(x, dependencies = TRUE)
+# # }
+# # })
+
+# # 循环引入包
+# lapply(pacotes, function(pkg) {
+# requireNamespace(pkg, quietly = TRUE)
+# library(pkg, character.only = TRUE)
+# })
+
+ # 显式地调用packages是因为renv的package管理需要识别library
+ library(jsonlite)
+ library(emayili)
+ library(bslib)
+ library(data.table)
+ library(DT)
+ library(dplyr)
+ library(fullPage)
+ library(future)
+ library(ggasym)
+ library(ggpubr)
+ library(glue)
+ library(kableExtra)
+ library(openxlsx)
+ library(promises)
+ library(purrr)
+ library(reshape2)
+ library(rintrojs)
+ library(rjson)
+ library(rtracklayer)
+ library(scales)
+ library(seqinr)
+ library(shiny)
+ library(shinyBS)
+ library(shinybusy)
+ library(shinydisconnect)
+ library(shinyFeedback)
+ library(shinycssloaders)
+ library(shinyjs)
+ library(shinythemes)
+ library(shinyvalidate)
+ library(shinyWidgets)
+ library(snow)
+ library(tibble)
+ library(tidyverse)
+ library(tictoc)
+ library(shinyvalidate)
+ library(zip)
source("R/utils/utils.R")
source("R/utils/shiny_busy_indicator.R")
@@ -66,23 +116,21 @@ suppressMessages({
source("R/utils/motif_pair_gene_diagonal.R")
})
-options(shiny.maxRequestSize = 30000 * 1024^2)
-plan(multisession)
-
-
-cpu_configuration <- readLines("data/cpu_configuration.txt")
-NCPU <- cpu_configuration[1]
+NCPU <- readLines("data/cpu_configuration.txt")[1]
-# to detect the pre-computed motif-DB data
-# when new daata comes, there is no need to change code.
+# auto detect the pre-computed motif-DB data: when new species or motif database comes, no need to change code.
species <- list.dirs("./data/indexing", recursive=F) %>%
sapply(function(i) {
str <- stringr::str_split_1(i, "/")[4] # %>% tolower() #%>% gsub("(^|\\s)([a-z])", "\\1\\U\\2", ., perl = TRUE) # capitablize first letter
return(str)
})
# > species
-# ./data/indexing/arabidopsis_thaliana ./data/indexing/mais
-# "arabidopsis_thaliana" "mais"
+# ./data/indexing/Arabidopsis_thaliana
+# "Arabidopsis_thaliana"
+# ./data/indexing/Brachypodium_distachyon
+# "Brachypodium_distachyon"
+# ./data/indexing/Brassica_napus
+# "Brassica_napus"
MOTIF_DB <- lapply(species, function(speci) {
@@ -93,10 +141,24 @@ MOTIF_DB <- lapply(species, function(speci) {
for (i in seq(length(motif_dbs))) {
result[[ list_names[i] ]] <- file.path("data/indexing", speci , motif_dbs[i])
}
-
return(result)
}) %>% setNames(unname(species))
+# > MOTIF_DB
+# $Arabidopsis_thaliana
+# $Arabidopsis_thaliana$`CIS-BP2`
+# [1] "data/indexing/Arabidopsis_thaliana/CIS-BP2"
+
+# $Arabidopsis_thaliana$`Franco-Zorrilla et al 2014`
+# [1] "data/indexing/Arabidopsis_thaliana/Franco-Zorrilla_et_al_2014"
+
+# $Arabidopsis_thaliana$`Jaspar plants non redundant 2022`
+# [1] "data/indexing/Arabidopsis_thaliana/Jaspar_plants_non_redundant_2022"
+# $Arabidopsis_thaliana$`Plant Cistrome DB`
+# [1] "data/indexing/Arabidopsis_thaliana/Plant_Cistrome_DB"
+
+# $Arabidopsis_thaliana$PlantTFDB
+# [1] "data/indexing/Arabidopsis_thaliana/PlantTFDB"
SPECIES_LIST <- list()
@@ -105,5 +167,27 @@ for (speci in species) {
SPECIES_LIST[[temp]] <- speci
}
SPECIES_LIST <- list(species = SPECIES_LIST) # to show nothing first of fileInput box
+# > SPECIES_LIST
+# $species
+# $species$`Arabidopsis thaliana`
+# [1] "Arabidopsis_thaliana"
+
+# $species$`Brachypodium distachyon`
+# [1] "Brachypodium_distachyon"
+
+# $species$`Brassica napus`
+# [1] "Brassica_napus"
+
+# $species$`Glycine max`
+# [1] "Glycine_max"
+
+MOTF_DB_META <- rjson::fromJSON(file = "data/motif_db_meta.json")
+# > MOTF_DB_META
+# $Arabidopsis_thaliana
+# $Arabidopsis_thaliana$genome_name
+# [1] "Arabidopsis_thaliana.TAIR10.dna.toplevel.fa"
+
+# $Arabidopsis_thaliana$annotation_name
+# [1] "Arabidopsis_thaliana.TAIR10.56.gff3"
-MOTF_DB_META <- fromJSON(file = "data/motif_db_meta.json")
\ No newline at end of file
+# $Arabidopsis_thaliana$genome_link
diff --git a/R/server/tab_visualize.R b/R/server/tab_visualize.R
index 2f095ba..c1de763 100644
--- a/R/server/tab_visualize.R
+++ b/R/server/tab_visualize.R
@@ -381,3 +381,4 @@ observeEvent(pmet.result.processed(), {
})
server_data("pmet_talble_tab", result)
})
+
diff --git a/R/ui/tab_test.R b/R/ui/tab_test.R
index 6e2949a..5038ec1 100644
--- a/R/ui/tab_test.R
+++ b/R/ui/tab_test.R
@@ -1,3 +1,30 @@
+# tabPanel(
+# title = "Test",
+# value = "Test_tabpanel",
+# tags$head(
+# tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.css"),
+# tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.js")
+# ),
+# tags$script("
+# $(document).ready(function() {
+# new fullpage('#my-fullpage', {
+# // fullPage.js options
+# });
+# });
+# "),
+# div(id = "my-fullpage",
+# div(class = "section",
+# actionButton("a", "a"),
+# h1("Section 1")
+# ),
+# div(class = "section",
+# h1("Section 2")
+# ),
+# div(class = "section",
+# h1("Section 3")
+# )
+# )
+# )
tabPanel(
class = "tabPanel_shiny",
"My Tab",
diff --git a/R/utils/install_packages.R b/R/utils/install_packages.R
index b356a88..64f229b 100755
--- a/R/utils/install_packages.R
+++ b/R/utils/install_packages.R
@@ -1,8 +1,11 @@
# 设置 CRAN 仓库
r <- getOption("repos")
-r["CRAN"] <- "http://cran.us.r-project.org"
+r["CRAN"] <- "https://cloud.r-project.org/"
options(repos = r)
-options(install.packages.compile.from.source = "always")
+options(install.packages.compile.from.source = "auto")
+
+Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library")
+.libPaths(new = "/usr/local/lib/R/library")
################################ install basic packages #################################
# 1. remotes and devtools
@@ -10,12 +13,16 @@ options(install.packages.compile.from.source = "always")
# 3. pak
# 定义一个辅助函数来安装包并在失败时终止程序
install_and_check_func <- function(package) {
- if (!requireNamespace(package, quietly = TRUE)) {
- suppressMessages(install.packages(package, quiet = TRUE))
+ result <- suppressWarnings(suppressMessages(capture.output({
if (!requireNamespace(package, quietly = TRUE)) {
- stop(paste("Failed to install", package, ". Terminating the program."))
+ install.packages(package, quiet = TRUE)
+ if (!requireNamespace(package, quietly = TRUE)) {
+ return(FALSE) # 如果再次检查仍然未安装,返回 FALSE
+ }
}
- }
+ return(TRUE) # 如果已安装或安装成功,返回 TRUE
+ })))
+ return(result)
}
# 安装 devtools remotes 和 BiocManager 包
@@ -24,65 +31,61 @@ install_and_check_func("remotes")
install_and_check_func("BiocManager")
# 尝试安装 pak 包
-if (!requireNamespace("pak", quietly = TRUE)) {
- suppressMessages(install.packages("pak", quiet = TRUE))
+suppressWarnings(suppressMessages(capture.output(
if (!requireNamespace("pak", quietly = TRUE)) {
- suppressMessages(remotes::install_github("r-lib/pak"))
+ install.packages("pak", quiet = TRUE)
if (!requireNamespace("pak", quietly = TRUE)) {
- stop("Failed to install pak from both CRAN and GitHub. Terminating the program.")
+ remotes::install_github("r-lib/pak", quiet = TRUE)
+ if (!requireNamespace("pak", quietly = TRUE)) {
+ stop("Failed to install pak from both CRAN and GitHub. Terminating the program.")
+ }
}
}
-}
+)))
################################ install function #################################
install_package_func <- function(package_name) {
- # 提取包名:如果包名包含 '/', 提取斜线后的部分
package_name_to_check <- ifelse(grepl("/", package_name), sub(".*/", "", package_name), package_name)
-
- # 检查包是否已经安装
if (requireNamespace(package_name_to_check, quietly = TRUE)) {
return(TRUE)
}
- # 定义一个列表,包含尝试安装包的不同函数
install_functions <- list(
- bio_install = function() suppressMessages(BiocManager::install(package_name, ask = FALSE)),
- devtools_install = function() suppressMessages(devtools::install_github(package_name, quiet = TRUE)),
- remotes_install = function() suppressMessages(remotes::install_github(package_name, quiet = TRUE)),
- normal_install = function() suppressMessages(install.packages(package_name, repos = "https://cran.r-project.org", dependencies = TRUE, type = "source", quiet = TRUE)),
- pak_install = function() suppressMessages(pak::pak(package_name))
+ bio_install = function() BiocManager::install(package_name, ask = FALSE, quietly = TRUE),
+ devtools_install = function() devtools::install_github(package_name, quiet = TRUE),
+ remotes_install = function() remotes::install_github(package_name, quiet = TRUE),
+ normal_install = function() install.packages(package_name, repos = "https://cran.r-project.org", dependencies = TRUE, type = "source", quiet = TRUE),
+ pak_install = function() pak::pak(package_name, ask = FALSE)
)
- # 遍历安装函数,尝试安装包
for (install_func in install_functions) {
- tryCatch({
- install_func()
-
- # 检查是否安装成功
- if (requireNamespace(package_name, quietly = TRUE)) {
- return(TRUE) # 成功安装,返回 TRUE
- }
- }, error = function(e) {})
+ suppressWarnings(suppressMessages(capture.output(
+ tryCatch({
+ install_func()
+ if (requireNamespace(package_name, quietly = TRUE)) {
+ return(TRUE)
+ }
+ }, error = function(e) {})
+ )))
}
- # 所有方法尝试完毕,安装失败
return(FALSE)
}
################################ installation ################################
# bio
-packages_bio <- c("rtracklayer", "DESeq2", "WGCNA", "GEOqueary", "limma", "edgeR",
- "GSEABase", "clusterProfiler", "ConsensusClusterPlus", "GSVA",
- "pheatmap", "scFeatureFilter", "AUCell", "ComplexHeatmap")
+# packages_bio <- c("rtracklayer", "DESeq2", "WGCNA", "GEOqueary", "limma", "edgeR",
+# "GSEABase", "clusterProfiler", "ConsensusClusterPlus", "GSVA",
+# "pheatmap", "scFeatureFilter", "AUCell", "ComplexHeatmap")
+packages_bio <- c("rtracklayer")
# normal packages
packages_normal <- c(
- "future",
- "qs",
+ "jsonlite",
+ "jsonify",
"ddpcr",
"rlang",
"pander",
"pacman",
- "pagoda2",
"eulerr",
"Hmisc",
"pryr",
@@ -91,7 +94,6 @@ packages_normal <- c(
"RcppRoll",
"msigdbr",
"xlsxjars",
- "shiny",
"svglite",
"pak",
"devtools",
@@ -108,7 +110,7 @@ packages_normal <- c(
"stringr",
"usethis",
"httpuv",
- "Seurat",
+ "rJava",
"bslib", # Bootstrap themes and styles
"data.table", # efficient handling of large datasets
"DT", # interactive data tables
@@ -119,25 +121,22 @@ packages_normal <- c(
"ggplot2", # creation of beautiful graphics
"ggpubr", # graph publication-ready formatting and annotations
"glue", # string interpolation and formatting
- "jsonify", # JSON data processing and transformation
"kableExtra", # creation of nice tables and adding formatting
- "mailR", # Interface to Apache Commons Email to send emails from R
"openxlsx", # reading and writing Excel files
"promises", # deferred evaluation and asynchronous programming
"reshape2", # data reshaping and transformation
"rintrojs", # interactive tour integration
- "rjson", # Converts R object into JSON objects and vice-versa
"shiny", # creation of interactive web applications
- "rJava",
"shinyBS", # Bootstrap styling
"shinybusy", # Automated (or not) busy indicator for Shiny apps & other progress / notifications tools
- "shinydashboard", # creation of dashboard-style Shiny apps
"shinyFeedback", # user feedback integration
"shinycssloaders", # loading animation integration
"shinyjs", # JavaScript operations
"shinythemes", # theme customization
"shinyvalidate", # form validation
"shinyWidgets", # creation of interactive widgets
+ "shinydisconnect",
+ "shinydashboard",
"scales", # data scaling and transformation
"seqinr", # extract fasta's name
"tibble", # extended data frames
@@ -150,28 +149,21 @@ packages_normal <- c(
pak_packages <- c("r-lib/ragg", "r-lib/usethis", "r-lib/rlang")
# github
packages_github <- c(
- "daattali/shinydisconnect",
- "RinteRface/fullPage",
- "dreamRs/shinybusy",
- "merlinoa/shinyFeedback",
- "daattali/shinycssloaders",
- "dreamRs/shinyWidgets",
- "r-lib/textshaping",
- "r-lib/systemfonts",
- "jhrcook/ggasym",
- "rpremrajGit/mailR",
- "r-lib/textshaping",
- "rstudio/httpuv",
- "r-rust/gifski",
- "jhrcook/ggasym",
- "satijalab/seurat-data",
- "satijalab/azimuth",
- "satijalab/seurat-wrappers",
- "stuart-lab/signac",
- "satijalab/seurat",
- "jhrcook/ggasym",
- "kharchenkolab/pagoda2",
- "NMikolajewicz/scMiko")
+ "jeroen/jsonlite",
+ "kassambara/ggpubr",
+ "SymbolixAU/jsonify",
+ "daattali/shinydisconnect",
+ "datawookie/emayili",
+ "RinteRface/fullPage",
+ "dreamRs/shinybusy",
+ "merlinoa/shinyFeedback",
+ "daattali/shinycssloaders",
+ "dreamRs/shinyWidgets",
+ "r-lib/textshaping",
+ "r-lib/systemfonts",
+ "rstudio/httpuv",
+ "r-rust/gifski",
+ "jhrcook/ggasym")
installed_packages <- character(0)
failed_packages <- character(0)
@@ -207,12 +199,12 @@ for (package in packages) {
############################## summary ############################
# Print installed packages
cat("The installed packages are as follows:\n")
-print(sort(installed_packages))
+print(sort(unique(installed_packages)))
# Print failed packages
if (length(failed_packages) > 0) {
cat("\nThe following packages could not be installed:\n")
- print(failed_packages)
+ print(unique(failed_packages))
} else {
cat("\nAll packages were successfully installed.\n")
}
\ No newline at end of file
diff --git a/R/utils/send_mail.R b/R/utils/send_mail.R
index 8d1ae9f..4f067df 100644
--- a/R/utils/send_mail.R
+++ b/R/utils/send_mail.R
@@ -38,7 +38,6 @@
# result_link <- args[2]
# SendResultMail(recipient = recipient, result_link = result_link)
-library(emayili)
SendResultMail <- function(recipient = NULL, result_link = NULL) {
diff --git a/app.R b/app.R
index 794b40a..6ebdb0a 100644
--- a/app.R
+++ b/app.R
@@ -1,3 +1,6 @@
+Sys.setenv(R_LIBS_USER = "/usr/local/lib/R/library")
+.libPaths(new = "/usr/local/lib/R/library")
+
source("R/app.R")
shinyApp(ui = ui, server = server)
diff --git a/conf/nginx.conf b/conf/nginx.conf
new file mode 100644
index 0000000..dbf6cfa
--- /dev/null
+++ b/conf/nginx.conf
@@ -0,0 +1,12 @@
+server {
+ listen 84;
+ listen [::]:84;
+ server_name localhost_pmet;
+
+ # access_log /var/log/nginx/localhost.access.log;
+
+ location /result {
+ # autoindex on;
+ alias /usr/share/nginx/pmet;
+ }
+}
diff --git a/conf/shiny-server.conf b/conf/shiny-server.conf
new file mode 100644
index 0000000..68d48a1
--- /dev/null
+++ b/conf/shiny-server.conf
@@ -0,0 +1,21 @@
+# Instruct Shiny Server to run applications as the user "shiny"
+run_as shiny;
+
+# Define a server that listens on port 3838
+server {
+ listen 3838;
+
+ # Define a location at the base URL
+ location / {
+ app_idle_timeout 0;
+ # Host the directory of Shiny Apps stored in this directory
+ site_dir /srv/shiny-server;
+
+ # Log all Shiny output to files in this directory
+ log_dir /var/log/shiny-server;
+
+ # When a user visits the base URL rather than a particular application,
+ # an index of the applications available in this directory will be shown.
+ directory_index on;
+ }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..b8ab219
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,35 @@
+x-yml-version: '3.8'
+
+services:
+ shiny-app:
+ build:
+ context: .
+ dockerfile: dockerfiles/Dockerfile.shiny
+ volumes:
+ - ./result:/home/shiny/PMET_docker/result
+ - ./logs:/var/log/shiny-server
+ ports:
+ - "3838:3838"
+ networks:
+ - app-network
+
+ nginx-server:
+ build:
+ context: .
+ dockerfile: dockerfiles/Dockerfile.nginx
+ container_name: test_nginx
+ volumes:
+ - ./result:/usr/share/nginx/pmet
+ ports:
+ - "84:84"
+ restart: always
+ networks:
+ - app-network
+
+
+volumes:
+ logs:
+ result:
+
+networks:
+ app-network:
diff --git a/dockerfiles/Dockerfile.nginx b/dockerfiles/Dockerfile.nginx
new file mode 100644
index 0000000..0af436e
--- /dev/null
+++ b/dockerfiles/Dockerfile.nginx
@@ -0,0 +1,14 @@
+# Use the official Nginx image as the base image
+FROM nginx:latest
+
+# 创建结果目录
+RUN mkdir -p /usr/share/nginx/pmet && \
+ chmod -R 777 /usr/share/nginx/pmet
+
+COPY ./conf/nginx.conf /etc/nginx/conf.d/pmet.conf
+
+# Expose Nginx's default port
+EXPOSE 84
+
+# Start Nginx service
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/dockerfiles/Dockerfile.shiny b/dockerfiles/Dockerfile.shiny
new file mode 100644
index 0000000..c973767
--- /dev/null
+++ b/dockerfiles/Dockerfile.shiny
@@ -0,0 +1,109 @@
+FROM rocker/shiny:4.3.3
+
+############################## 1. shiny setting ###############################
+COPY ./conf/shiny-server.conf /etc/shiny-server/shiny-server.conf
+
+ENV work_dir="/home/shiny/PMET_docker"
+COPY . $work_dir
+
+RUN ln -sf $work_dir /srv/shiny-server/pmet
+
+# Use the find command to find all .sh, .r, .py, .pl files and grant them 755 permissions
+RUN find $work_dir/ \( -name "*.sh" -o -name "*.r" -o -name "*.py" -o -name "*.pl" \) -exec chmod 777 {} \;
+
+
+############################## 2. install linux libs ###############################
+RUN $work_dir/scripts/install_apt_tools.sh
+
+
+# ############################## 3. R libs settings ###############################
+ENV R_LIBS_USER=/usr/local/lib/R/library
+# Set the directory owner and permissions
+RUN mkdir -p $R_LIBS_USER && \
+ chmod -R 777 $R_LIBS_USER
+# Set environment variables in respective user profiles
+RUN echo "export R_LIBS_USER='$R_LIBS_USER'" >> /root/.bashrc && \
+ echo "export R_LIBS_USER='$R_LIBS_USER'" >> /home/shiny/.bashrc && \
+ echo "R_LIBS_USER='$R_LIBS_USER'" >> /root/.Renviron && \
+ echo "R_LIBS_USER='$R_LIBS_USER'" >> /home/shiny/.Renviron
+
+
+############################## 4. install R libs ###############################
+# # Configure Java using R CMD javareconf
+RUN sudo R CMD javareconf
+
+# # renv for package management
+# RUN Rscript -e "install.packages(c('remotes', 'littler', 'docopt', 'renv', 'jsonlite'))"
+# RUN Rscript -e "renv::restore()"
+RUN Rscript $work_dir/R/utils/install_packages.R
+
+RUN rsync -av --ignore-existing /usr/local/lib/R/library/ /usr/local/lib/R/site-library/ && \
+ rsync -av --ignore-existing /usr/local/lib/R/site-library/ /usr/local/lib/R/library/
+
+
+############################## 5. install python libs ###############################
+RUN sudo apt-get update && \
+ apt -y install python3-pip
+RUN $work_dir/scripts/install_python_libs.sh
+
+
+########################## 6. install bedtool and samtools ###########################
+RUN apt -y install bedtools
+
+# Samtools 1.3.1 #
+ENV SAMTOOLS_INSTALL_DIR=/opt/samtools
+ENV HTSLIB_INSTALL_DIR=/opt/htslib
+
+WORKDIR /tmp
+RUN wget https://github.com/samtools/samtools/releases/download/1.17/samtools-1.17.tar.bz2 && \
+ tar -xjf samtools-1.17.tar.bz2 && \
+ cd samtools-1.17 && \
+ ./configure --disable-lzma --prefix=$SAMTOOLS_INSTALL_DIR && \
+ make && \
+ make install && \
+ cd / && \
+ rm -rf /tmp/samtools-1.17 /tmp/samtools-1.17.tar.bz2
+# Set the working directory back to the root directory
+WORKDIR $work_dir
+
+
+################################## 7. compile pmet ###################################
+# meme
+RUN cd $work_dir/PMETdev/src/meme-5.5.3 \
+ && aclocal \
+ && automake \
+ && mkdir -p build \
+ && chmod a+x ./configure \
+ && ./configure --prefix=$work_dir/PMETdev/src/meme-5.5.3/build --enable-build-libxml2 --enable-build-libxslt \
+ && make \
+ && make install \
+ && chmod a+x build/bin/fimo \
+ && cp build/bin/fimo $work_dir/PMETdev/scripts/ \
+ && make distclean \
+ && rm -rf build
+
+# pmetindex
+RUN cd $work_dir/PMETdev/src/indexing \
+ && chmod a+x build.sh \
+ && bash build.sh \
+ && mv bin/pmetindex $work_dir/PMETdev/scripts/
+
+# pmetParallel
+RUN cd $work_dir/PMETdev/src/pmetParallel \
+ && chmod a+x build.sh \
+ && bash build.sh \
+ && mv bin/pmetParallel_linux $work_dir/PMETdev/scripts/
+
+# pmet
+RUN cd $work_dir/PMETdev/src/pmet \
+ && chmod a+x build.sh \
+ && bash build.sh \
+ && mv bin/pmet $work_dir/PMETdev/scripts/
+
+
+############################# 8. download homotypic data ##############################
+RUN $work_dir/scripts/download_pmet_indexing.sh
+
+
+EXPOSE 3838
+CMD ["/usr/bin/shiny-server"]
diff --git a/readme.md b/readme.md
index acbedb4..f0e52af 100644
--- a/readme.md
+++ b/readme.md
@@ -8,7 +8,11 @@ This is a Shiny app developed for PMET.
```shell
.
+├── conf * # configure for shiny server and nginx
+├── data
+├── dockerfiles
├── PMETdev
+├── indexing
├── R
│ ├── app.R
│ ├── global.R
@@ -16,22 +20,30 @@ This is a Shiny app developed for PMET.
│ ├── server
│ ├── ui
│ └── utils
-├── data
-│ ├── indexing
-├── deploy_one_bash.sh * # ONLY to run this bash to deploy
├── result
├── www
+├── 01_deploy_via_bash.sh
+├── 01_deploy_via_Docker.sh * # Recommended installation method
+├── app.R * # Shiny app
+├── docker-compose.yml
├── PMET-Shiny-App.Rproj
-├── app.R
└── readme.md
```
## 2. Quick deployment
+### 2.1 (option one) Install on Docker (Recommended)
+
+```bash
+bash 01_deploy_via_Docker.sh
+```
+
+### 2.2 (option two) Bash install on current Debian-like OS
1. Install `Shiny Server` and `Nginx` [[details](#setup-shiny-server-and-nginx)]
-2. `git clone` or `git pull` in the folder of Shiny Server (default: `/srv/shiny-server`)![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202309191728114.png)
+2. `git clone` in the folder of Shiny Server (default: `/srv/shiny-server`) or git clone anywhere and then create a link under `/srv/shiny-server` as shown below:
+![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202309191728114.png)
-3. Run `deploy_one_bash.sh`
+1. Run `01_deploy_via_bash.sh`
- 1. set email and CPU
- 2. assign execute permissions
@@ -41,10 +53,20 @@ This is a Shiny app developed for PMET.
- 6. install python packages
- 7. Install tools (`GNU Parallel`, `bedtools`, `samtools`, `MEME`...)[[details](#tools)]
```bash
- bash deploy_one_bash.sh
+ bash 01_deploy_via_bash.sh
```
![](https://raw.githubusercontent.com/duocang/images/master/PicGo/202310190148145.png)
+
+
+
+---
+
+**If not necessary, there is no need to read the following content.**
+
+---
+
+
## 3. Pre-computed homotypic motif hits of plant species (PMET indexing data)
Given that the PMET indexing calculation takes a very long time, we have already performed pre-calculation for some plants and several common plant transcription factor databases.
@@ -54,9 +76,6 @@ The data can be accessed by running the script `deploy_one_bash.sh` from [Homoty
```bash
bash deploy_one_bash.sh
-# ...
-# 3. Would you like to download data of homotypic motif hits? [y/N]: Y
-```
```shell
# file tree
@@ -108,7 +127,7 @@ bash binary_compile.sh
After compilation, the executable will be saved in the `PMETdev/scripts` directory for the Shiny app to call.
-## Setup 5. Shiny server and nginx
+## 5. Shiny server and nginx
**5.1 Shiny-server and nginx install**
@@ -143,94 +162,8 @@ server {
}
```
-
-
-## 6. Tools needed
-
-**6.1 Install GNU Parallel**
-
-GNU Parallel helps PMET index (FIMO and PMET index) to run in parallel mode.
-
-```bash
-sudo apt-get install parallel
-
-# Put GNU Parallel silent
-parallel --citation
-```
-
-**6.2 Install The MEME Suite (FIMO and fasta-get-markov)**
-
-```bash
-# cd a folder you want to put the software
-mkdir -p ./tools
-
-cd ./tools
-wget https://meme-suite.org/meme/meme-software/5.5.2/meme-5.5.2.tar.gz
-tar zxf meme-5.5.2.tar.gz
-
-cd meme-5.5.2
-./configure --prefix=$(pwd) --enable-build-libxml2 --enable-build-libxslt
-make
-make install
-
-echo "export PATH=$(pwd)/bin:\$PATH" >> ~/.bashrc
-source ~/.bashrc
-cd ..
-rm meme-5.5.2.tar.gz
-```
-
-
-**6.3 Install samtools**
-Install from conda or mamba:
-
-```bash
-conda install -c bioconda samtools
-```
-
-Install from source:
-
-```bash
-mkdir -p ./tools
-
-cd ./tools
-wget https://github.com/samtools/samtools/releases/download/1.17/samtools-1.17.tar.bz2
-tar -xjf samtools-1.17.tar.bz2
-
-cd samtools-1.17
-./configure --prefix=$(pwd)
-make
-make install
-# Add following into bash profile file or .zshrc (if zsh used).
-echo "export PATH=$(pwd)/bin:\$PATH" >> ~/.bashrc
-source ~/.bashrc
-
-cd ..
-rm samtools-1.17.tar.bz2
-```
-
-**6. 4 Install bedtools**
-```bash
-# Debian/Ubuntu
-apt-get install bedtools
-# Fedora/Centos
-yum install BEDTools
-```
-
-or
-
-```bash
-wget https://github.com/arq5x/bedtools2/releases/download/v2.29.1/bedtools-2.29.1.tar.gz
-tar -zxvf bedtools-2.29.1.tar.gz
-cd bedtools2
-make
-```
+## PMET workflow
![](www/figures/pmet_workflow_with_interval_option.png)
[GitHub Ribbons](https://github.blog/2008-12-19-github-ribbons/)
diff --git a/scripts/bin/install2.r b/scripts/bin/install2.r
new file mode 100644
index 0000000..33cab2c
--- /dev/null
+++ b/scripts/bin/install2.r
@@ -0,0 +1,168 @@
+#!/usr/bin/env r
+#
+# A second example to install one or more packages, now with option parsing
+#
+# Copyright (C) 2011 - 2014 Dirk Eddelbuettel
+# Copyright (C) 2014 - 2017 Carl Boettiger and Dirk Eddelbuettel
+# Copyright (C) 2018 - 2023 Carl Boettiger, Dirk Eddelbuettel, Brandon Bertelsen, and SHIMA Tatsuya
+#
+# Released under GPL (>= 2)
+
+## load docopt package from CRAN
+library(docopt)
+
+## default to first library location in .libPaths()
+libloc <- .libPaths()[1]
+
+## configuration for docopt
+doc <- paste0("Usage: install2.r [-l LIBLOC] [-h] [-x] [-s] [-d DEPS] [-n NCPUS] [-r REPOS...] [-m METHOD] [-t TYPE] [--error] [--skipmissing] [--] [PACKAGES ...]
+
+-l --libloc LIBLOC location in which to install [default: ", libloc, "]
+-d --deps DEPS install suggested dependencies as well [default: NA]
+-n --ncpus NCPUS number of processes to use for parallel install, -1 selects all cores [default: getOption]
+-r --repos REPOS repositor(y|ies) to use, or NULL for file [default: getOption]
+-e --error throw error and halt instead of a warning [default: FALSE]
+--skipmissing use with the --error option, skip the packages missing error [default: FALSE]
+-s --skipinstalled skip installing already installed packages [default: FALSE]
+-m --method METHOD method to be used for downloading files [default: auto]
+-t --type TYPE installation type as used by `install.packages` [default: getOption]
+-h --help show this help text
+-x --usage show help and short example usage")
+opt <- docopt(doc) # docopt parsing
+
+if (opt$usage) {
+ cat(doc, "\n\n")
+ cat("where PACKAGES... can be one or more CRAN package names, or local (binary or source)
+package files (where extensions .tar.gz, .tgz and .zip are recognised). Optional
+arguments understood by R CMD INSTALL can be passed interspersed in the PACKAGES, though
+this requires use of '--'.
+
+Examples:
+ install2.r -l /tmp/lib Rcpp BH # install into given library
+ install2.r -- --with-keep.source drat # keep the source
+ install2.r -- --data-compress=bzip2 stringdist # prefer bz2 compression
+ install2.r \".\" # install package in current directory
+ install2.r -n 6 ggplot2 # parallel install: (6 processes)
+
+install2.r is part of littler which brings 'r' to the command-line.
+See https://dirk.eddelbuettel.com/code/littler.html for more information.\n")
+ q("no")
+}
+
+if (opt$deps == "TRUE" || opt$deps == "FALSE") {
+ opt$deps <- as.logical(opt$deps)
+} else if (opt$deps == "NA") {
+ opt$deps <- NA
+}
+
+## docopt results are characters, so if we meant NULL we have to set NULL
+if (length(opt$repos) == 1 && "NULL" %in% opt$repos) {
+ opt$repos <- NULL
+}
+
+if ("getOption" %in% opt$repos) {
+ ## as littler can now read ~/.littler.r and/or /etc/littler.r we can preset elsewhere
+ opt$repos <- c(opt$repos[which(opt$repos != "getOption")], getOption("repos"))
+}
+
+if (opt$ncpus == "getOption") {
+ opt$ncpus <- getOption("Ncpus", 1L)
+} else if (opt$ncpus == "-1") {
+ ## parallel comes with R 2.14+
+ opt$ncpus <- max(1L, parallel::detectCores())
+}
+
+## type should reflects bspm where available
+if (opt$type == "getOption") {
+ opt$type <- getOption("pkgType")
+ #if (requireNamespace("bspm", quietly=TRUE) && Sys.info()[["sysname"]] == "Linux") opt$type <- "binary-source"
+
+}
+
+## ensure installation is stripped
+Sys.setenv("_R_SHLIB_STRIP_"="true")
+
+install_packages2 <- function(pkgs, ..., error = FALSE, skipmissing = FALSE, skipinstalled = FALSE) {
+ e <- NULL
+ capture <- function(e) {
+ if (error) {
+ catch <-
+ grepl("(download|installation) of package .* failed", e$message) ||
+ (grepl("(dependenc|package).*(is|are) not available", e$message) && !skipmissing) ||
+ grepl("installation of package.*had non-zero exit status", e$message) ||
+ grepl("installation of .+ package(|s) failed", e$message)
+ if (catch) {
+ e <<- e
+ }
+ }
+ }
+ if (skipinstalled) {
+ pkgs <- setdiff(pkgs, installed.packages()[,1])
+ }
+ if (length(pkgs) > 0) {
+ withCallingHandlers(install.packages(pkgs, ...), warning = capture)
+ if (!is.null(e)) {
+ stop(e$message, call. = FALSE)
+ }
+ }
+}
+
+## helper function to for existing files with matching extension
+isMatchingFile <- function(f) (file.exists(f) && grepl("(\\.tar\\.gz|\\.tgz|\\.zip)$", f)) || (f == ".")
+
+## helper function which switches to local (ie NULL) repo if matching file is presented
+installArg <- function(f, lib, rep, dep, iopts, error, skipmissing, skipinstalled, ncpus, method, type) {
+ install_packages2(pkgs=f,
+ lib=lib,
+ repos=if (isMatchingFile(f)) NULL else rep,
+ dependencies=dep,
+ INSTALL_opts=iopts,
+ Ncpus = ncpus,
+ method = method,
+ type = type,
+ error = error,
+ skipmissing = skipmissing,
+ skipinstalled = skipinstalled)
+}
+
+## strip out arguments to be passed to R CMD INSTALL
+isArg <- grepl('^--',opt$PACKAGES)
+installOpts <- opt$PACKAGES[isArg]
+opt$PACKAGES <- opt$PACKAGES[!isArg]
+
+if (length(opt$PACKAGES)==0 && file.exists("DESCRIPTION") && file.exists("NAMESPACE")) {
+ ## we are in a source directory, so build it
+ message("* installing *source* package found in current working directory ...")
+ opt$PACKAGES <- "."
+}
+
+## helper function to for existing files with matching extension
+isMatchingFile <-
+ function(f) (file.exists(f) &&
+ grepl("(\\.tar\\.gz|\\.tgz|\\.zip)$", f)) || (f == ".")
+
+## check arguments for local files -- if none, then we can pass vector on
+isLocal <- sapply(opt$PACKAGES, isMatchingFile)
+
+## for any local sources loop explicitly as before, otherwise for remote
+## packages pass vector to install_packages2 which does the rest (and
+## possibly in parallel using up to ncpus)
+if (any(isLocal)) {
+ sapply(opt$PACKAGES, installArg, opt$libloc, opt$repos, opt$deps,
+ installOpts, opt$error, opt$skipmissing, opt$skipinstalled, opt$ncpus, opt$method, opt$type)
+} else {
+ install_packages2(pkgs = opt$PACKAGES,
+ lib = opt$libloc,
+ repos = opt$repos,
+ dependencies = opt$deps,
+ INSTALL_opts = installOpts,
+ Ncpus = opt$ncpus,
+ method = opt$method,
+ type = opt$type,
+ error = opt$error,
+ skipmissing = opt$skipmissing,
+ skipinstalled = opt$skipinstalled)
+}
+
+## clean up any temp file containing CRAN directory information
+sapply(list.files(path=tempdir(), pattern="^(repos|libloc).*\\.rds$", full.names=TRUE), unlink)
diff --git a/scripts/check_CPU_number.sh b/scripts/check_CPU_number.sh
new file mode 100644
index 0000000..b906902
--- /dev/null
+++ b/scripts/check_CPU_number.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+source scripts/colored_print.sh
+
+# Function to get user input for CPU number
+get_cpu_number() {
+ while true; do
+ print_fluorescent_yellow_no_br " Please enter a number for CPU configuration: "
+ read cpu_number
+ if [[ "$cpu_number" =~ ^[0-9]+$ ]]; then
+ echo "$cpu_number" > "$file_path"
+ echo " CPU number: $cpu_number"
+ break
+ else
+ print_red " Invalid input. Please enter a numeric value."
+ fi
+ done
+}
+
+# 函数:检查CPU配置文件是否存在,并提示用户
+check_cpu_number() {
+ file_path="data/cpu_configuration.txt"
+
+ # 检查文件是否存在且不为空
+ if [ ! -f "$file_path" ] || [ ! -s "$file_path" ]; then
+ get_cpu_number
+ else
+ cpu_number=$(cat "$file_path")
+ # print_orange " Check your CPU number in $file_path"
+ echo " Number of CPU: $cpu_number"
+
+ # 询问用户是否要修改CPU数量
+ while true; do
+ print_orange_no_br " Do you want to modify the CPU number? [y/N]: "
+ read modify
+
+ modify=${modify:-N} # 默认为'N',如果没有提供输入
+ case "$modify" in
+ [Yy]* )
+ get_cpu_number
+ break
+ ;;
+ [Nn]* )
+ # echo "Keeping the existing CPU configuration: $cpu_number"
+ break
+ ;;
+ * )
+ print_red "Please answer yes (y) or no (n)."
+ ;;
+ esac
+ done
+ fi
+}
+
+# 导出函数,以便在source a.sh后可以被调用
+export -f get_cpu_number
+export -f check_cpu_number
diff --git a/scripts/check_and_set_email_credentials.sh b/scripts/check_and_set_email_credentials.sh
new file mode 100644
index 0000000..a94ec54
--- /dev/null
+++ b/scripts/check_and_set_email_credentials.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+source scripts/colored_print.sh
+
+# 定义函数 check_and_set_email_credentials
+check_and_set_email_credentials() {
+
+ credential_path="data/email_credential.txt"
+
+ # 初始化 file_flag 为 F,表示默认情况下文件状态为不满足条件
+ file_flag="F"
+ # 检查文件是否存在,且至少有5行非空内容
+ if [[ -f "$credential_path" ]] && [[ $(grep -v '^[[:blank:]]*$' "$credential_path" | wc -l) -ge 5 ]]; then
+ print_orange " Please check your email credential in $credential_path"
+ # 读取文件内容到变量
+ readarray -t lines < "$credential_path"
+ username="${lines[0]}"
+ password="${lines[1]}"
+ address="${lines[2]}"
+ smtp_link="${lines[3]}"
+ ssl_port="${lines[4]}"
+ echo " User name (email): $username"
+ echo " Password : $password"
+ echo " Address : $address"
+ echo " SMTP Link : $smtp_link"
+ echo " SSL Port : $ssl_port"
+
+ print_orange_no_br " Is this information correct? (Y/n): "
+ read confirmation
+ confirmation=${confirmation:-Y} # 如果用户没有输入任何内容,则将 confirmation 设置为 'Y'
+ if [[ "$confirmation" =~ ^[Yy]$ ]]; then
+ file_flag="T"
+ else
+ file_flag="F"
+ fi
+ else
+ current_date=$(date '+%Y%m%d%H%M')
+
+ # 检查文件是否存在
+ if [[ -f "$credential_path" ]]; then
+ # 构造新的文件名
+ new_filename="data/email_credential_${current_date}.txt"
+
+ mv "$credential_path" "$new_filename"
+ print_red " Invalid email credential: $credential_path"
+ print_red " The file has been renamed to '$new_filename'."
+ else
+ print_red " Email credential '$credential_path' does not exist."
+ fi
+
+ file_flag="F"
+ fi
+
+ # 根据 file_flag 做进一步操作
+ if [[ "$file_flag" == "F" ]]; then
+ print_orange " Please provide the required information."
+ rm -rf "$credential_path"
+ touch "$credential_path"
+ # 循环直到输入非空的用户名
+ while true; do
+ read -p " User name (email): " username
+ # 检查用户名是否非空
+ if [[ -z "$username" ]]; then
+ print_red " Email (User name) cannot be empty. Please try again."
+ else
+ break # 用户名非空,跳出循环
+ fi
+ done
+ # 循环直到输入非空的密码
+ while true; do
+ read -p " Password : " password
+ if [[ -z "$password" ]]; then
+ print_red " Password cannot be empty. Please try again."
+ else
+ break # 密码非空,跳出循环
+ fi
+ done
+ # 循环直到输入非空的address
+ while true; do
+ read -p " Address (email): " address
+ # 检查用户名是否非空
+ if [[ -z "$address" ]]; then
+ print_red " Address (email) cannot be empty. Please try again."
+ else
+ break # 用户名非空,跳出循环
+ fi
+ done
+ # 接收并验证 SMTP 链接
+ while true; do
+ read -p " SMTP link: " smtp_link
+ if [[ -n "$smtp_link" ]]; then
+ break
+ else
+ print_red " SMTP link cannot be empty. Please try again."
+ fi
+ done
+ # 接收并验证 SSL 端口号
+ while true; do
+ read -p " SSL Port : " ssl_port
+ if [[ -n "$ssl_port" ]] && [[ "$ssl_port" -ne 0 ]]; then
+ break
+ else
+ print_red " SSL Port cannot be zero or empty. Please try again."
+ fi
+ done
+ echo
+
+ # 存储信息到文件 Store information to file
+ echo "$username" >> "$credential_path"
+ echo "$password" >> "$credential_path"
+ echo "$address" >> "$credential_path"
+ echo "$smtp_link" >> "$credential_path"
+ echo "$ssl_port" >> "$credential_path"
+ # show message
+ {
+ read -r username
+ read -r password
+ read -r address
+ read -r smtp_link
+ read -r ssl_port
+ } < "$credential_path"
+ print_green " User name: $username"
+ print_green " Password : $password"
+ print_green " Address : $address"
+ print_green " User name: $smtp_link"
+ print_green " Password : $ssl_port"
+ fi
+}
+
+# 导出函数,使其在source a.sh后可以被调用
+export -f check_and_set_email_credentials
diff --git a/scripts/cleanup_Docker.sh b/scripts/cleanup_Docker.sh
new file mode 100644
index 0000000..23ef95e
--- /dev/null
+++ b/scripts/cleanup_Docker.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# 停止所有运行中的容器
+echo "Stopping all running containers..."
+docker stop $(docker ps -q)
+
+# 删除所有容器
+echo "Removing all containers..."
+docker rm $(docker ps -aq)
+
+# 删除所有镜像
+echo "Removing all images..."
+docker rmi $(docker images -q)
+
+# 可选:删除所有悬空镜像(dangling images)
+echo "Removing all dangling images..."
+docker image prune -af
+
+# 可选:删除所有未使用的容器、镜像、卷和网络
+echo "Pruning all unused containers, images, volumes, and networks..."
+docker system prune --volumes
+
+# 可选:清理构建缓存
+echo "Pruning build cache..."
+docker builder prune --all
+
+echo "Cleanup is complete."
diff --git a/scripts/colored_print.sh b/scripts/colored_print.sh
new file mode 100644
index 0000000..e9caeca
--- /dev/null
+++ b/scripts/colored_print.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+if [ true ]; then
+ print_red(){
+ RED='\033[0;31m'
+ NC='\033[0m' # No Color
+ printf "${RED}$1${NC}\n"
+ }
+ print_green(){
+ GREEN='\033[0;32m'
+ NC='\033[0m' # No Color
+ printf "${GREEN}$1${NC}\n"
+ }
+ print_green_no_br(){
+ GREEN='\033[0;32m'
+ NC='\033[0m' # No Color
+ printf "${GREEN}$1${NC}"
+ }
+ print_orange(){
+ ORANGE='\033[0;33m'
+ NC='\033[0m' # No Color
+ printf "${ORANGE}$1${NC}\n"
+ }
+ print_orange_no_br(){
+ ORANGE='\033[0;33m'
+ NC='\033[0m' # No Color
+ printf "${ORANGE}$1${NC}"
+ }
+ print_fluorescent_yellow(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ printf "${FLUORESCENT_YELLOW}$1${NC}\n"
+ }
+ print_fluorescent_yellow_no_br(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ printf "${FLUORESCENT_YELLOW}$1${NC}"
+ }
+ print_white(){
+ WHITE='\033[1;37m'
+ NC='\033[0m' # No Color
+ printf "${WHITE}$1${NC}"
+ }
+ print_middle(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ # 获取终端的宽度
+ COLUMNS=$(tput cols)
+ # 遍历每一行
+ while IFS= read -r line; do
+ # 计算需要的空格数来居中文本
+ padding=$(( (COLUMNS - ${#line}) / 2 ))
+ printf "%${padding}s" ''
+ printf "${FLUORESCENT_YELLOW}${line}${NC}\n"
+ done <<< "$1"
+ }
+fi
diff --git a/scripts/download_pmet_indexing.sh b/scripts/download_pmet_indexing.sh
new file mode 100644
index 0000000..fc19d53
--- /dev/null
+++ b/scripts/download_pmet_indexing.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+if [ true ]; then
+ print_red(){
+ RED='\033[0;31m'
+ NC='\033[0m' # No Color
+ printf "${RED}$1${NC}\n"
+ }
+
+ print_green(){
+ GREEN='\033[0;32m'
+ NC='\033[0m' # No Color
+ printf "${GREEN}$1${NC}\n"
+ }
+
+ print_green_no_br(){
+ GREEN='\033[0;32m'
+ NC='\033[0m' # No Color
+ printf "${GREEN}$1${NC}"
+ }
+
+ print_orange(){
+ ORANGE='\033[0;33m'
+ NC='\033[0m' # No Color
+ printf "${ORANGE}$1${NC}\n"
+ }
+ print_orange_no_br(){
+ ORANGE='\033[0;33m'
+ NC='\033[0m' # No Color
+ printf "${ORANGE}$1${NC}"
+ }
+
+ print_fluorescent_yellow(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ printf "${FLUORESCENT_YELLOW}$1${NC}\n"
+ }
+ print_fluorescent_yellow_no_br(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ printf "${FLUORESCENT_YELLOW}$1${NC}"
+ }
+
+ print_white(){
+ WHITE='\033[1;37m'
+ NC='\033[0m' # No Color
+ printf "${WHITE}$1${NC}"
+ }
+
+ print_middle(){
+ FLUORESCENT_YELLOW='\033[1;33m'
+ NC='\033[0m' # No Color
+ # 获取终端的宽度
+ COLUMNS=$(tput cols)
+ # 遍历每一行
+ while IFS= read -r line; do
+ # 计算需要的空格数来居中文本
+ padding=$(( (COLUMNS - ${#line}) / 2 ))
+ printf "%${padding}s" ''
+ printf "${FLUORESCENT_YELLOW}${line}${NC}\n"
+ done <<< "$1"
+ }
+fi
+
+############################# 17. download homotypic data ##############################
+if [ true ]; then
+ data_path="data/indexing"
+
+ print_orange "Data path: $data_path"
+ urls=(
+ "https://zenodo.org/record/8435321/files/Arabidopsis_thaliana.tar.gz"
+ "https://zenodo.org/record/8435321/files/Brachypodium_distachyon.tar.gz"
+ "https://zenodo.org/record/8435321/files/Brassica_napus.tar.gz"
+ "https://zenodo.org/record/8435321/files/Glycine_max.tar.gz"
+ "https://zenodo.org/record/8435321/files/Hordeum_vulgare_goldenpromise.tar.gz"
+ "https://zenodo.org/record/8435321/files/Hordeum_vulgare_Morex_V3.tar.gz"
+ "https://zenodo.org/record/8435321/files/Hordeum_vulgare_R1.tar.gz"
+ "https://zenodo.org/record/8435321/files/Hordeum_vulgare_v082214v1.tar.gz"
+ "https://zenodo.org/record/8435321/files/Medicago_truncatula.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_9311.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_IR8.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_MH63.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_indica_ZS97.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Ensembl.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Kitaake.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_Nipponbare.tar.gz"
+ "https://zenodo.org/record/8435321/files/Oryza_sativa_japonica_V7.1.tar.gz"
+ "https://zenodo.org/record/8435321/files/Solanum_lycopersicum.tar.gz"
+ "https://zenodo.org/record/8435321/files/Solanum_tuberosum.tar.gz"
+ "https://zenodo.org/record/8435321/files/Triticum_aestivum.tar.gz"
+ "https://zenodo.org/record/8435321/files/Zea_mays.tar.gz"
+ )
+
+ mkdir -p $data_path
+ # download and unzip
+ for url in "${urls[@]}"; do
+ filename=$(basename $url .tar.gz)
+ print_orange "Downloading homotypic motifs hits of ${filename//_/ }"
+ wget $url
+ tar -xzvf "$filename.tar.gz" -C data/indexing > /dev/null 2>&1
+ rm "$filename.tar.gz"
+ done
+fi
diff --git a/scripts/glue_sys_reqs.R b/scripts/glue_sys_reqs.R
new file mode 100644
index 0000000..2c1b71b
--- /dev/null
+++ b/scripts/glue_sys_reqs.R
@@ -0,0 +1,42 @@
+glue_sys_reqs <- function(pkgs) {
+ rlang::check_installed("curl")
+ rspm = Sys.getenv("RSPM_ROOT", "https://packagemanager.rstudio.com")
+ rspm_repo_id = Sys.getenv("RSPM_REPO_ID", 1)
+ rspm_repo_url = glue::glue("{rspm}/__api__/repos/{rspm_repo_id}")
+
+ pkgnames = glue::glue_collapse(unique(pkgs), sep = "&pkgname=")
+
+ req_url = glue::glue(
+ "{rspm_repo_url}/sysreqs?all=false",
+ "&pkgname={pkgnames}&distribution=ubuntu&release=22.04"
+ )
+ res = curl::curl_fetch_memory(req_url)
+ sys_reqs = jsonlite::fromJSON(rawToChar(res$content), simplifyVector = FALSE)
+ if (!is.null(sys_reqs$error)) rlang::abort(sys_reqs$error)
+
+ sys_reqs = purrr::map(sys_reqs$requirements, purrr::pluck, "requirements", "packages")
+ sys_reqs = sort(unique(unlist(sys_reqs)))
+ sys_reqs = glue::glue_collapse(sys_reqs, sep = " \\\n ")
+ glue::glue(
+ "RUN apt-get update -qq && \\ \n",
+ " apt-get install -y --no-install-recommends \\\n ",
+ sys_reqs,
+ "\ && \\\n",
+ " apt-get clean && \\ \n",
+ " rm -rf /var/lib/apt/lists/*",
+ .trim = FALSE
+ )
+}
+
+# glue_sys_reqs(c("shiny", "dplyr"))
+# #> RUN apt-get update -qq && \
+# #> apt-get install -y --no-install-recommends \
+# #> make \
+# #> zlib1g-dev && \
+# #> apt-get clean && \
+# #> rm -rf /var/lib/apt/lists/*
+
+# appdir = "app/"
+# pkgs = renv::dependencies(appdir)$Package
+# sys_reqs = glue_sys_reqs(pkgs)
+# https://www.jumpingrivers.com/blog/shiny-auto-docker/
diff --git a/scripts/init_set_env.sh b/scripts/init_set_env.sh
new file mode 100644
index 0000000..51125fb
--- /dev/null
+++ b/scripts/init_set_env.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/with-contenv bash
+# shellcheck shell=bash
+
+## Set our dynamic variables in Renviron.site to be reflected by RStudio Server or Shiny Server
+exclude_vars="HOME PASSWORD RSTUDIO_VERSION BATCH_USER_CREATION"
+for file in /var/run/s6/container_environment/*; do
+ sed -i "/^${file##*/}=/d" "${R_HOME}/etc/Renviron.site"
+ regex="(^| )${file##*/}($| )"
+ [[ ! $exclude_vars =~ $regex ]] && echo "${file##*/}=$(cat "${file}")" >>"${R_HOME}/etc/Renviron.site" || echo "skipping ${file}"
+done
+
+## only file-owner (root) should read container_environment files:
+chmod 600 /var/run/s6/container_environment/*
diff --git a/scripts/install_R_source.sh b/scripts/install_R_source.sh
new file mode 100644
index 0000000..31460d8
--- /dev/null
+++ b/scripts/install_R_source.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+
+## Install R from source.
+##
+## In order of preference, first argument of the script, the R_VERSION variable.
+## ex. latest, devel, patched, 4.0.0
+##
+## 'devel' means the prerelease development version (Latest daily snapshot of development version).
+## 'patched' means the prerelease patched version (Latest daily snapshot of patched version).
+
+set -e
+
+R_VERSION=${1:-${R_VERSION:-"latest"}}
+PURGE_BUILDDEPS=${PURGE_BUILDDEPS:-"true"}
+
+# shellcheck source=/dev/null
+source /etc/os-release
+
+apt-get update
+apt-get -y install locales
+
+## Configure default locale
+LANG=${LANG:-"en_US.UTF-8"}
+/usr/sbin/locale-gen --lang "${LANG}"
+/usr/sbin/update-locale --reset LANG="${LANG}"
+
+export DEBIAN_FRONTEND=noninteractive
+
+R_HOME=${R_HOME:-"/usr/local/lib/R"}
+
+READLINE_VERSION=8
+if [ "${UBUNTU_CODENAME}" == "bionic" ]; then
+ READLINE_VERSION=7
+fi
+
+# libjpeg-turbo* \
+# libpangocairo-* \
+apt-get install -y --no-install-recommends \
+ bash-completion \
+ ca-certificates \
+ file \
+ fonts-texgyre \
+ g++ \
+ gfortran \
+ gsfonts \
+ libblas-dev \
+ libbz2-* \
+ libcurl4 \
+ "libicu[0-9][0-9]" \
+ liblapack-dev \
+ libpcre2* \
+ libpng16* \
+ "libreadline${READLINE_VERSION}" \
+ libtiff* \
+ liblzma* \
+ libxt6 \
+ make \
+ tzdata \
+ unzip \
+ zip \
+ zlib1g
+
+# default-jdk \
+BUILDDEPS="curl \
+ devscripts \
+ libbz2-dev \
+ libcairo2-dev \
+ libcurl4-openssl-dev \
+ libpango1.0-dev \
+ libjpeg-dev \
+ libicu-dev \
+ libpcre2-dev \
+ libpng-dev \
+ libreadline-dev \
+ libtiff5-dev \
+ liblzma-dev \
+ libx11-dev \
+ libxt-dev \
+ perl \
+ rsync \
+ subversion \
+ tcl-dev \
+ tk-dev \
+ texinfo \
+ texlive-extra-utils \
+ texlive-fonts-recommended \
+ texlive-fonts-extra \
+ texlive-latex-recommended \
+ texlive-latex-extra \
+ x11proto-core-dev \
+ xauth \
+ xfonts-base \
+ xvfb \
+ wget \
+ zlib1g-dev"
+
+# shellcheck disable=SC2086
+apt-get install -y --no-install-recommends ${BUILDDEPS}
+
+# ## Download R from 0-Cloud CRAN mirror or CRAN
+function download_r_src() {
+ wget "https://cloud.r-project.org/src/$1" -O "R.tar.gz" ||
+ wget "https://cran.r-project.org/src/$1" -O "R.tar.gz" ||
+ wget "https://cran.rstudio.com/src/$1" -O "R.tar.gz"
+}
+
+if [ "$R_VERSION" == "devel" ]; then
+ download_r_src "base-prerelease/R-devel.tar.gz"
+elif [ "$R_VERSION" == "patched" ]; then
+ download_r_src "base-prerelease/R-latest.tar.gz"
+elif [ "$R_VERSION" == "latest" ]; then
+ download_r_src "base/R-latest.tar.gz"
+else
+ download_r_src "base/R-${R_VERSION%%.*}/R-${R_VERSION}.tar.gz"
+fi
+
+tar xzf "R.tar.gz"
+cd R-*/
+
+R_PAPERSIZE=letter \
+ R_BATCHSAVE="--no-save --no-restore" \
+ R_BROWSER=xdg-open \
+ PAGER=/usr/bin/pager \
+ PERL=/usr/bin/perl \
+ R_UNZIPCMD=/usr/bin/unzip \
+ R_ZIPCMD=/usr/bin/zip \
+ R_PRINTCMD=/usr/bin/lpr \
+ LIBnn=lib \
+ AWK=/usr/bin/awk \
+ CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g" \
+ CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g" \
+ ./configure --enable-R-shlib \
+ --enable-memory-profiling \
+ --with-readline \
+ --with-blas \
+ --with-lapack \
+ --with-tcltk \
+ --with-recommended-packages
+
+make
+make install
+make clean
+
+## Add a library directory (for user-installed packages)
+mkdir -p "${R_HOME}/site-library"
+chown root:staff "${R_HOME}/site-library"
+chmod g+ws "${R_HOME}/site-library"
+
+## Fix library path
+echo "R_LIBS=\${R_LIBS-'${R_HOME}/site-library:${R_HOME}/library'}" >>"${R_HOME}/etc/Renviron.site"
+
+## Clean up from R source install
+cd ..
+rm -rf /tmp/*
+rm -rf R-*/
+rm -rf "R.tar.gz"
+
+## Copy the checkbashisms script to local before remove devscripts package.
+## https://github.com/rocker-org/rocker-versioned2/issues/510
+cp /usr/bin/checkbashisms /usr/local/bin/checkbashisms
+
+# shellcheck disable=SC2086
+if [ "${PURGE_BUILDDEPS}" != "false" ]; then
+ apt-get remove --purge -y ${BUILDDEPS}
+fi
+apt-get autoremove -y
+apt-get autoclean -y
+rm -rf /var/lib/apt/lists/*
+
+# Check the R info
+echo -e "Check the R info...\n"
+
+R -q -e "sessionInfo()"
+
+echo -e "\nInstall R from source, done!"
diff --git a/scripts/install_apt_tools.sh b/scripts/install_apt_tools.sh
new file mode 100644
index 0000000..1dcfeb7
--- /dev/null
+++ b/scripts/install_apt_tools.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+set -e
+
+apt update && apt upgrade -y
+
+# update-alternatives --config libblas.so.3-$(arch)-linux-gnu
+echo "deb http://security.ubuntu.com/ubuntu focal-security main" | tee /etc/apt/sources.list.d/focal-security.list
+
+apt -y install libcurl4-openssl-dev
+apt -y install curl
+apt -y install vim
+apt -y install wget bzip2
+apt -y install openjdk-21-jdk
+apt -y install r-cran-rjava
+apt -y install build-essential
+
+apt -y install autotools-dev
+apt -y install automake
+apt -y install nodejs
+apt -y install libssl-dev
+apt -y install libxml2-dev
+apt -y install libxml2
+apt -y install cmake
+apt -y install libharfbuzz-dev
+apt -y install libfribidi-dev
+apt -y install libncurses5-dev
+apt -y install libncursesw5-dev
+apt -y install libbz2-dev
+apt -y install parallel
+apt -y install ufw
+
+apt -y install libjpeg-dev
+apt -y install librsvg2-dev
+apt -y install libpoppler-cpp-dev
+apt -y install freetype2-demos
+apt -y install cargo
+apt -y install libxslt-dev
+apt -y install zlib1g-dev
+apt -y install libgdbm-dev
+apt -y install npm
+apt -y install libtesseract-dev
+apt -y install libleptonica-dev
+apt -y install tesseract-ocr-eng
+apt -y install libmagick++-dev
+apt -y install libavfilter-dev
+apt -y install zip
+apt -y install libpcre2-dev
+apt -y install libreadline-dev
+apt -y install glibc-source
+apt -y install libstdc++6
+apt -y install genometools
+# apt -y install libssl1.1
+apt -y install libopenblas-dev
+apt -y install gfortran
+
+apt -y install rsync
+
+wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb
+sudo dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb
+rm libssl1.1_1.1.0g-2ubuntu4_amd64.deb
+
+export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
+export PATH=$PATH:$JAVA_HOME/bin
+
+apt-get clean && rm -rf /var/lib/apt/lists/*
diff --git a/scripts/install_pandoc.sh b/scripts/install_pandoc.sh
new file mode 100644
index 0000000..9f19071
--- /dev/null
+++ b/scripts/install_pandoc.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+## Install pandoc or symlinks pandoc, pandoc-citeproc so they are available system-wide.
+##
+## In order of preference, first argument of the script, the PANDOC_VERSION variable.
+## ex. latest, default
+##
+## 'default' means the version bundled with RStudio if RStudio is installed, but 'latest' otherwise.
+## 'latest' means installing the latest release version.
+
+set -e
+
+PANDOC_VERSION=${1:-${PANDOC_VERSION:-"default"}}
+ARCH=$(dpkg --print-architecture)
+
+# a function to install apt packages only if they are not installed
+function apt_install() {
+ if ! dpkg -s "$@" >/dev/null 2>&1; then
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ apt-get install -y --no-install-recommends "$@"
+ fi
+}
+
+apt_install wget ca-certificates
+
+if [ -x "$(command -v pandoc)" ]; then
+ INSTALLED_PANDOC_VERSION=$(pandoc --version 2>/dev/null | head -n 1 | grep -oP '[\d\.]+$')
+fi
+
+if [ -f "/usr/lib/rstudio-server/bin/pandoc/pandoc" ]; then
+ BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/pandoc/pandoc"
+elif [ -f "/usr/lib/rstudio-server/bin/quarto/bin/pandoc" ]; then
+ BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/quarto/bin/pandoc"
+elif [ -f "/usr/lib/rstudio-server/bin/quarto/bin/tools/pandoc" ]; then
+ BUNDLED_PANDOC="/usr/lib/rstudio-server/bin/quarto/bin/tools/pandoc"
+fi
+
+if [ -n "$BUNDLED_PANDOC" ]; then
+ BUNDLED_PANDOC_VERSION="$($BUNDLED_PANDOC --version | head -n 1 | grep -oP '[\d\.]+$')"
+fi
+
+if [ "$PANDOC_VERSION" != "$INSTALLED_PANDOC_VERSION" ]; then
+
+ if [ "$PANDOC_VERSION" = "default" ] && [ -z "$BUNDLED_PANDOC" ]; then
+ PANDOC_VERSION="latest"
+ fi
+
+ if [ "$PANDOC_VERSION" = "$BUNDLED_PANDOC_VERSION" ] || [ "$PANDOC_VERSION" = "default" ]; then
+ ln -fs "$BUNDLED_PANDOC" /usr/local/bin
+ if [ -f "${BUNDLED_PANDOC}-citeproc" ]; then
+ ln -fs "${BUNDLED_PANDOC}-citeproc" /usr/local/bin
+ fi
+ else
+ if [ -L "/usr/local/bin/pandoc" ]; then
+ unlink /usr/local/bin/pandoc
+ fi
+ if [ -L "/usr/local/bin/pandoc-citeproc" ]; then
+ unlink /usr/local/bin/pandoc-citeproc
+ fi
+
+ if [ "$PANDOC_VERSION" = "latest" ]; then
+ PANDOC_DL_URL=$(wget -qO- https://api.github.com/repos/jgm/pandoc/releases/latest | grep -oP "(?<=\"browser_download_url\":\s\")https.*${ARCH}\.deb")
+ else
+ PANDOC_DL_URL="https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-1-${ARCH}.deb"
+ fi
+ wget "$PANDOC_DL_URL" -O pandoc.deb
+ dpkg -i pandoc.deb
+ rm pandoc.deb
+ fi
+
+ ## Symlink pandoc & standard pandoc templates for use system-wide
+ PANDOC_TEMPLATES_VERSION=$(pandoc -v | grep -oP "(?<=pandoc\s)[0-9\.]+$")
+ wget "https://github.com/jgm/pandoc-templates/archive/${PANDOC_TEMPLATES_VERSION}.tar.gz" -O pandoc-templates.tar.gz
+ rm -fr /opt/pandoc/templates
+ mkdir -p /opt/pandoc/templates
+ tar xvf pandoc-templates.tar.gz
+ cp -r pandoc-templates*/* /opt/pandoc/templates && rm -rf pandoc-templates*
+ rm -fr /root/.pandoc
+ mkdir /root/.pandoc && ln -s /opt/pandoc/templates /root/.pandoc/templates
+fi
+
+# Clean up
+rm -rf /var/lib/apt/lists/*
+
+# Check the pandoc version
+echo -e "Check the pandoc version...\n"
+pandoc --version
+echo -e "\nInstall pandoc, done!"
diff --git a/scripts/install_python.sh b/scripts/install_python.sh
new file mode 100644
index 0000000..373b6bd
--- /dev/null
+++ b/scripts/install_python.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+set -e
+
+## build ARGs
+NCPUS=${NCPUS:--1}
+
+# a function to install apt packages only if they are not installed
+function apt_install() {
+ if ! dpkg -s "$@" >/dev/null 2>&1; then
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ apt-get install -y --no-install-recommends "$@"
+ fi
+}
+
+apt_install \
+ libpng-dev \
+ libpython3-dev \
+ python3-dev \
+ python3-pip \
+ python3-venv \
+ swig
+
+# Setup a virtualenv to install things into
+
+# Put things under /opt/venv, if nothing else is specified
+export VIRTUAL_ENV="${VIRTUAL_ENV:=/opt/venv}"
+export PATH="${VIRTUAL_ENV}/bin:${PATH}"
+
+# Make sure that Rstudio sees these env vars too
+echo "PATH=${PATH}" >>"${R_HOME}/etc/Renviron.site"
+echo "VIRTUAL_ENV=${VIRTUAL_ENV}" >>"${R_HOME}/etc/Renviron.site"
+
+python3 -m venv "${VIRTUAL_ENV}"
+
+# Upgrade version of pip inside the virtualenv
+python3 -m pip --no-cache-dir install --upgrade \
+ pip
+
+# Make the venv owned by the staff group, so users can install packages
+# without having to be root
+chown -R root:staff "${VIRTUAL_ENV}"
+chmod -R g+ws "${VIRTUAL_ENV}"
+
+scripts/bin/install2.r --error --skipmissing --skipinstalled -n "$NCPUS" reticulate
+
+# Clean up
+rm -rf /var/lib/apt/lists/*
+rm -rf /tmp/downloaded_packages
+
+## Strip binary installed lybraries from RSPM
+## https://github.com/rocker-org/rocker-versioned2/issues/340
+strip /usr/local/lib/R/library/*/libs/*.so
+
+## Don't use OpenBLAS with reticulate on Ubuntu 20.04
+## https://github.com/rocker-org/rocker-versioned2/issues/471
+source /etc/os-release
+if [ "${UBUNTU_CODENAME}" == "focal" ]; then
+ if R -q -e 'sessionInfo()' | grep -q openblas; then
+ ARCH=$(uname -m)
+ echo "Switching BLAS (Details: https://github.com/rocker-org/rocker-versioned2/issues/471)"
+ update-alternatives --set "libblas.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/blas/libblas.so.3"
+ update-alternatives --set "liblapack.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/lapack/liblapack.so.3"
+ fi
+fi
+
+# Check that python and python3 point to correct places
+echo "Check python, python3 and pip executables point to the correct place..."
+echo "python -> $(which python)"
+echo "python3 -> $(which python3)"
+echo "pip -> $(which pip)"
+
+# Check Python version
+echo -e "Check the Python to use with reticulate...\n"
+
+R -q -e 'reticulate::py_discover_config(required_module = NULL, use_environment = NULL)'
+
+echo -e "\nInstall Python, done!"
diff --git a/scripts/install_python_libs.sh b/scripts/install_python_libs.sh
new file mode 100644
index 0000000..8ea9ed8
--- /dev/null
+++ b/scripts/install_python_libs.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+pip3 install leidenalg
+pip3 install python-igraph
+pip3 install numpy
+pip3 install pandas
+# pip3 install scipy
+python3 -m pip install scipy
+pip3 install bio
+pip3 install biopython
diff --git a/scripts/install_s6init.sh b/scripts/install_s6init.sh
new file mode 100644
index 0000000..475c388
--- /dev/null
+++ b/scripts/install_s6init.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+set -e
+
+### Sets up S6 supervisor.
+
+S6_VERSION=${1:-${S6_VERSION:-"v2.1.0.2"}}
+
+# a function to install apt packages only if they are not installed
+function apt_install() {
+ if ! dpkg -s "$@" >/dev/null 2>&1; then
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ apt-get install -y --no-install-recommends "$@"
+ fi
+}
+
+ARCH=$(dpkg --print-architecture)
+
+if [ "$ARCH" = "arm64" ]; then
+ ARCH=aarch64
+fi
+
+DOWNLOAD_FILE=s6-overlay-${ARCH}.tar.gz
+
+apt_install wget ca-certificates
+
+## Set up S6 init system
+if [ -f "scripts/.s6_version" ] && [ "$S6_VERSION" = "$(cat scripts/.s6_version)" ]; then
+ echo "S6 already installed"
+else
+ wget -P /tmp/ "https://github.com/just-containers/s6-overlay/releases/download/${S6_VERSION}/${DOWNLOAD_FILE}"
+
+ ## need the modified double tar now, see https://github.com/just-containers/s6-overlay/issues/288
+ tar hzxf /tmp/$DOWNLOAD_FILE -C / --exclude=usr/bin/execlineb
+ tar hzxf /tmp/$DOWNLOAD_FILE -C /usr ./bin/execlineb
+
+ echo "$S6_VERSION" > scripts/.s6_version
+fi
+
+# Clean up
+rm -rf /var/lib/apt/lists/*
+rm -f /tmp/$DOWNLOAD_FILE
diff --git a/scripts/install_shiny_server.sh b/scripts/install_shiny_server.sh
new file mode 100644
index 0000000..fd1e56c
--- /dev/null
+++ b/scripts/install_shiny_server.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+set -e
+
+SHINY_SERVER_VERSION=${1:-${SHINY_SERVER_VERSION:-latest}}
+
+## build ARGs
+NCPUS=${NCPUS:--1}
+
+# a function to install apt packages only if they are not installed
+function apt_install() {
+ if ! dpkg -s "$@" >/dev/null 2>&1; then
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ apt-get install -y --no-install-recommends "$@"
+ fi
+}
+
+apt_install \
+ sudo \
+ gdebi-core \
+ lsb-release \
+ libcurl4-openssl-dev \
+ libcairo2-dev \
+ libxt-dev \
+ xtail \
+ wget
+
+# Run dependency scripts
+scripts/install_s6init.sh
+scripts/install_pandoc.sh
+
+# Install Shiny server
+
+if [ "$SHINY_SERVER_VERSION" = "latest" ]; then
+ SHINY_SERVER_VERSION=$(wget -qO- https://download3.rstudio.org/ubuntu-18.04/x86_64/VERSION)
+fi
+
+wget --no-verbose "https://download3.rstudio.org/ubuntu-18.04/x86_64/shiny-server-${SHINY_SERVER_VERSION}-amd64.deb" -O ss-latest.deb
+gdebi -n ss-latest.deb
+rm ss-latest.deb
+
+# Get R packages
+scripts/bin/install2.r --error --skipinstalled -n "$NCPUS" shiny rmarkdown
+
+# Set up directories and permissions
+if [ -x "$(command -v rstudio-server)" ]; then
+ DEFAULT_USER=${DEFAULT_USER:-rstudio}
+ adduser "${DEFAULT_USER}" shiny
+fi
+
+cp -R /usr/local/lib/R/library/shiny/examples/* /srv/shiny-server/
+chown shiny:shiny /var/lib/shiny-server
+mkdir -p /var/log/shiny-server
+chown shiny:shiny /var/log/shiny-server
+
+# create init scripts
+mkdir -p /etc/services.d/shiny-server
+cat <<"EOF" >/etc/services.d/shiny-server/run
+#!/usr/bin/with-contenv bash
+## load /etc/environment vars first:
+for line in $( cat /etc/environment ) ; do export $line > /dev/null; done
+if [ "$APPLICATION_LOGS_TO_STDOUT" != "false" ]; then
+ exec xtail /var/log/shiny-server/ &
+fi
+exec shiny-server 2>&1
+EOF
+chmod +x /etc/services.d/shiny-server/run
+
+# install init script
+cp scripts/init_set_env.sh /etc/cont-init.d/01_set_env
+
+# Clean up
+rm -rf /var/lib/apt/lists/*
+rm -rf /tmp/downloaded_packages
+
+## Strip binary installed lybraries from RSPM
+## https://github.com/rocker-org/rocker-versioned2/issues/340
+strip /usr/local/lib/R/library/*/libs/*.so
diff --git a/scripts/setup_R.sh b/scripts/setup_R.sh
new file mode 100644
index 0000000..3ec5b7e
--- /dev/null
+++ b/scripts/setup_R.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+
+## Update configuration files for R and install some libraries.
+##
+## The URL of the default repository for R packages written to Rprofile.site,
+## refers to the CRAN environment variable or to the first argument of this script.
+## In order of preference, first argument of the script, the CRAN variable.
+## ex. https://cloud.r-project.org, https://cran.r-project.org
+
+set -e
+
+CRAN=${1:-${CRAN:-"https://cran.r-project.org"}}
+PURGE_BUILDDEPS=${PURGE_BUILDDEPS:-"true"}
+
+ARCH=$(uname -m)
+
+# shellcheck source=/dev/null
+source /etc/os-release
+
+# a function to install apt packages only if they are not installed
+function apt_install() {
+ if ! dpkg -s "$@" >/dev/null 2>&1; then
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ apt-get install -y --no-install-recommends "$@"
+ fi
+}
+
+## mechanism to force source installs if we're using RSPM
+CRAN_SOURCE=${CRAN/"__linux__/${UBUNTU_CODENAME}/"/""}
+
+## source install if using RSPM and arm64 image
+if [ "$ARCH" = "aarch64" ]; then
+ CRAN=$CRAN_SOURCE
+fi
+
+## Add a default CRAN mirror
+echo "options(repos = c(CRAN = '${CRAN}'), download.file.method = 'libcurl')" >>"${R_HOME}/etc/Rprofile.site"
+
+## Set HTTPUserAgent for RSPM (https://github.com/rocker-org/rocker/issues/400)
+cat <>"${R_HOME}/etc/Rprofile.site"
+# https://docs.rstudio.com/rspm/admin/serving-binaries/#binaries-r-configuration-linux
+options(HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste(getRversion(), R.version["platform"], R.version["arch"], R.version["os"])))
+EOF
+
+## Install OpenBLAS and hot-switching to it
+## https://github.com/rocker-org/rocker-versioned2/issues/390
+if ! dpkg -l | grep -q libopenblas-dev; then
+ apt_install libopenblas-dev
+ update-alternatives --set "libblas.so.3-${ARCH}-linux-gnu" "/usr/lib/${ARCH}-linux-gnu/openblas-pthread/libblas.so.3"
+fi
+
+## Install littler
+if [ ! -x "$(command -v r)" ]; then
+ BUILDDEPS="libpcre2-dev \
+ libdeflate-dev \
+ liblzma-dev \
+ libbz2-dev \
+ zlib1g-dev \
+ libicu-dev"
+
+ if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
+ apt-get update
+ fi
+ # shellcheck disable=SC2086
+ apt_install ${BUILDDEPS}
+ Rscript -e "install.packages(c('littler', 'docopt'), repos='${CRAN_SOURCE}')"
+
+ # Clean up
+ # shellcheck disable=SC2086
+ if [ "${PURGE_BUILDDEPS}" != "false" ]; then
+ apt-get remove --purge -y ${BUILDDEPS}
+ fi
+ apt-get autoremove -y
+ apt-get autoclean -y
+fi
+
+## Symlink littler and littler's installation scripts
+ln -sf "${R_HOME}/site-library/littler/bin/r" /usr/local/bin/r
+ln -sf "${R_HOME}/site-library/littler/examples/installGithub.r" /usr/local/bin/installGithub.r
+
+## Use rocker scripts version install2.r if it exists
+if [ -f "scripts/bin/install2.r" ]; then
+ ln -sf scripts/bin/install2.r /usr/local/bin/install2.r
+else
+ ln -sf "${R_HOME}/site-library/littler/examples/install2.r" /usr/local/bin/install2.r
+fi
+
+# Clean up
+rm -rf /var/lib/apt/lists/*
+
+# Check the R info
+echo -e "Check the littler info...\n"
+
+R --version
+
+echo -e "Check the R info...\n"
+
+R -q -e "sessionInfo()"
+
+echo -e "Setup R, done!"
diff --git a/scripts/shiny-server.sh b/scripts/shiny-server.sh
new file mode 100644
index 0000000..f1b0877
--- /dev/null
+++ b/scripts/shiny-server.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# # Make sure the directory for individual app logs exists
+# mkdir -p /var/log/shiny-server
+# chown shiny.shiny /var/log/shiny-server
+
+exec shiny-server >> /var/log/shiny-server/shiny-server.log 2>&1
diff --git a/www/shiny.css b/www/shiny.css
index f4fac19..0ae40a6 100644
--- a/www/shiny.css
+++ b/www/shiny.css
@@ -352,3 +352,4 @@ text.text-hover {
.tab-pane {
margin-top: 5px;
}
+