diff --git a/DESCRIPTION b/DESCRIPTION index 0a50f30..cda87c2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: Breedverse Title: Collection of R Shiny Packages From Breeding Insight -Version: 0.2.0 +Version: 0.3.0 Authors@R: c(person(given='Cristiane', family='Taniguti', email = 'ctaniguti@ufl.edu', @@ -18,7 +18,7 @@ Authors@R: c(person(given='Cristiane', family='Insight', role = 'aut') ) -Description: Provides an interface for users to add modules from BIGapp, Qploidy, familia and AlloMate packages. +Description: Provides an interface for users to add modules from BIGapp, Qploidy, familia, GenoBrew and AlloMate packages. License: Apache License 2.0 Depends: R (>= 3.6.0) biocViews: @@ -43,12 +43,13 @@ Suggests: Qploidy, BIGapp, familia, - AlloMate + GenoBrew Remotes: Cristianetaniguti/Qploidy, Breeding-Insight/BIGapp, Breeding-Insight/familia, - Breeding-Insight/AlloMate@development + Breeding-Insight/AlloMate@development, + Breeding-Insight/GenoBrew@development URL: https://github.com/Breeding-Insight/Breedverse BugReports: https://github.com/Breeding-Insight/Breedverse/issues LazyData: true diff --git a/NEWS.md b/NEWS.md index 6ce636e..e74ee9e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # breedverse NEWS +## breedverse 0.3.0 + +* Add GenoBrew + ## breedverse 0.2.0 * Collapse packages modules into a single collapsible menuItem in the left side menu diff --git a/R/app_server.R b/R/app_server.R index f345899..9ab8415 100644 --- a/R/app_server.R +++ b/R/app_server.R @@ -17,24 +17,30 @@ app_server <- function(input, output, session) { output$qploidyInstalled <- reactive({ "Qploidy" %in% rownames(installed.packages()) }) - + output$BIGappInstalled <- reactive({ "BIGapp" %in% rownames(installed.packages()) }) - + output$familiaInstalled <- reactive({ "familia" %in% rownames(installed.packages()) }) - + output$allomateInstalled <- reactive({ "AlloMate" %in% rownames(installed.packages()) }) - + + output$genobrewInstalled <- reactive({ + "GenoBrew" %in% rownames(installed.packages()) + }) + # Expose the value to JS even when panel is hidden outputOptions(output, "qploidyInstalled", suspendWhenHidden = FALSE) outputOptions(output, "BIGappInstalled", suspendWhenHidden = FALSE) outputOptions(output, "familiaInstalled", suspendWhenHidden = FALSE) outputOptions(output, "allomateInstalled", suspendWhenHidden = FALSE) + outputOptions(output, "genobrewInstalled", suspendWhenHidden = FALSE) + ## Modules @@ -47,17 +53,17 @@ app_server <- function(input, output, session) { callModule(mod_install_server, "install_1", parent_session = session) - + ## Qploidy if(isTRUE(requireNamespace("Qploidy", quietly = TRUE))) { do.call("library", list("Qploidy")) callModule(getFromNamespace("mod_qploidy_server", "Qploidy"), "qploidy_1", parent_session = session) - } - + } + ## BIGapp - + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) { do.call("library", list("BIGapp")) callModule(getFromNamespace("mod_DosageCall_server", "BIGapp"), @@ -85,9 +91,9 @@ app_server <- function(input, output, session) { "GS_1", parent_session = session) } - + ##familia - + if(isTRUE(requireNamespace("familia", quietly = TRUE))) { do.call("library", list("familia")) callModule(getFromNamespace("mod_SNMF_server", "familia"), @@ -97,7 +103,7 @@ app_server <- function(input, output, session) { "PolyBreedTools_1", parent_session = session) } - + ## AlloMate if(isTRUE(requireNamespace("AlloMate", quietly = TRUE))) { do.call("library", list("AlloMate")) @@ -105,8 +111,19 @@ app_server <- function(input, output, session) { "allomate_1", parent_session = session ) - } - + } + + ## GenoBrew + if(isTRUE(requireNamespace("GenoBrew", quietly = TRUE))) { + do.call("library", list("GenoBrew")) + callModule(getFromNamespace("mod_mk_select_server", "GenoBrew"), + "mk_select_1", + parent_session = session) + callModule(getFromNamespace("mod_cnv_server", "GenoBrew"), + "cnv_1", + parent_session = session) + } + #Session info popup observeEvent(input$session_info_button, { showModal(modalDialog( @@ -122,13 +139,13 @@ app_server <- function(input, output, session) { ) )) }) - + #Check for updates from GitHub for Breedverse get_latest_github_commit <- function(repo, owner) { url <- paste0("https://api.github.com/repos/", owner, "/", repo, "/releases/latest") response <- GET(url) content <- content(response, "parsed") - + if (status_code(response) == 200) { tag_name <- content$tag_name clean_tag_name <- sub("-.*", "", tag_name) @@ -138,7 +155,7 @@ app_server <- function(input, output, session) { return(NULL) } } - + is_internet_connected <- function() { handle <- new_handle() success <- tryCatch({ @@ -149,7 +166,7 @@ app_server <- function(input, output, session) { }) return(success) } - + observeEvent(input$updates_info_button, { # Check internet connectivity if (!is_internet_connected()) { @@ -164,17 +181,17 @@ app_server <- function(input, output, session) { )) return() } - + package_name <- "Breedverse" repo_name <- "Breedverse" # GitHub repo name repo_owner <- "Breeding-Insight" # User or organization name - + # Get the installed version installed_version <- as.character(packageVersion(package_name)) - + # Get the latest version from GitHub (can be tag version or latest commit) latest_commit <- get_latest_github_commit(repo_name, repo_owner) - + # Compare versions and prepare message if (latest_commit > installed_version) { update_status <- "A new version is available. Please update your package." @@ -194,7 +211,7 @@ app_server <- function(input, output, session) { update_status ) } - + # Display message in a Shiny modal showModal(modalDialog( title = "Breedverse Updates", diff --git a/R/app_ui.R b/R/app_ui.R index ca5ce9c..02905db 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -57,13 +57,13 @@ app_ui <- function(request) { tags$li(class = "header", style = "color: grey; margin-top: 10px; margin-bottom: 10px; padding-left: 15px;", "Menu"), menuItem("Home", tabName = "welcome", icon = icon("house"),startExpanded = FALSE), menuItem("Install modules", tabName = "install", icon = icon("share-from-square")), - + conditionalPanel( condition = "output.qploidyInstalled == true", tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Ploidy Estimation"), menuItem("Qploidy", tabName = "qploidy", icon = icon("dna")), ), - + conditionalPanel( condition = "output.familiaInstalled == true", tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Ancestry (R/familia)"), @@ -75,13 +75,13 @@ app_ui <- function(request) { menuSubItem("Unsupervised", tabName = "polybreedtools", icon = icon("share-from-square")) ) ), - + conditionalPanel( condition = "output.allomateInstalled == true", tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Mating Estimation (R/AlloMate)"), menuItem("AlloMate", tabName = "allomate", icon = icon("diagram-project")) ), - + conditionalPanel( condition = "output.BIGappInstalled == true", tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Genotype Processing"), @@ -100,7 +100,18 @@ app_ui <- function(request) { menuSubItem("Genomic Prediction", tabName = "prediction", icon = icon("angles-right")) ) ), - + conditionalPanel( + condition = "output.genobrewInstalled == true", + tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Marker Panel Test &\n CNV Profiles"), + menuItem( + "GenoBrew", + icon = icon("dna"), + startExpanded = FALSE, + menuSubItem("Select Markers", tabName = "mk_select", icon = icon("magnifying-glass")), + menuSubItem("CNV profiles", tabName = "cnv", icon = icon("dna")) + ) + ), + tags$li(class = "header", style = "color: grey; margin-top: 18px; margin-bottom: 10px; padding-left: 15px;", "Information"), menuItem("Source Code", icon = icon("circle-info"), href = "https://www.github.com/Breeding-Insight/Genomics_Shiny_App"), menuItem("Help", tabName = "help", icon = icon("circle-question")) @@ -128,7 +139,7 @@ app_ui <- function(request) { ) ), left = div( - style = "display: flex; align-items: center; height: 100%;", + style = "display: flex; align-items: center; height: 100%;", sprintf("v%s", as.character(utils::packageVersion("Breedverse")))) ), dashboardBody( @@ -155,70 +166,80 @@ app_ui <- function(request) { tabName = "install", mod_install_ui("install_1") ), tabItem( - tabName = "qploidy", - if(isTRUE(requireNamespace("Qploidy", quietly = TRUE))) + tabName = "qploidy", + if(isTRUE(requireNamespace("Qploidy", quietly = TRUE))) getFromNamespace("mod_qploidy_ui", "Qploidy")("qploidy_1") ), tabItem( - tabName = "snmf", - if(isTRUE(requireNamespace("familia", quietly = TRUE))) + tabName = "snmf", + if(isTRUE(requireNamespace("familia", quietly = TRUE))) getFromNamespace("mod_SNMF_ui", "familia")("SNMF_1") ), tabItem( - tabName = "polybreedtools", - if(isTRUE(requireNamespace("familia", quietly = TRUE))) + tabName = "polybreedtools", + if(isTRUE(requireNamespace("familia", quietly = TRUE))) getFromNamespace("mod_polybreedtools_ui", "familia")("PolyBreedTools_1") ), tabItem( - tabName = "allomate", - if(isTRUE(requireNamespace("AlloMate", quietly = TRUE))) + tabName = "allomate", + if(isTRUE(requireNamespace("AlloMate", quietly = TRUE))) getFromNamespace("mod_allomate_ui", "AlloMate")("allomate_1") ), tabItem( - tabName = "filtering", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "filtering", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_Filtering_ui", "BIGapp")("Filtering_1") ), tabItem( - tabName = "updog", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "updog", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_DosageCall_ui", "BIGapp")("DosageCall_1") ), tabItem( - tabName = "dosage2vcf", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "dosage2vcf", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_dosage2vcf_ui", "BIGapp")("dosage2vcf_1") ), tabItem( - tabName = "pca", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "pca", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_PCA_ui", "BIGapp")("PCA_1") ), tabItem( - tabName = "dapc", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "dapc", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_dapc_ui", "BIGapp")("dapc_1") ), tabItem( - tabName = "gwas", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "gwas", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_gwas_ui", "BIGapp")("gwas_1") ), tabItem( - tabName = "diversity", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "diversity", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_diversity_ui", "BIGapp")("diversity_1") ), tabItem( tabName = "prediction_accuracy", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_GSAcc_ui", "BIGapp")("GSAcc_1") ), tabItem( - tabName = "prediction", - if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) + tabName = "prediction", + if(isTRUE(requireNamespace("BIGapp", quietly = TRUE))) getFromNamespace("mod_GS_ui", "BIGapp")("GS_1") ), + tabItem( + tabName = "mk_select", + if(isTRUE(requireNamespace("GenoBrew", quietly = TRUE))) + getFromNamespace("mod_mk_select_ui", "GenoBrew")("mk_select_1") + ), + tabItem( + tabName = "cnv", + if(isTRUE(requireNamespace("GenoBrew", quietly = TRUE))) + getFromNamespace("mod_cnv_ui", "GenoBrew")("cnv_1") + ), tabItem( tabName = "help", mod_help_ui("help_1") ) @@ -241,7 +262,7 @@ golem_add_external_resources <- function() { "www", app_sys("app/www") ) - + tags$head( favicon(), bundle_resources( diff --git a/R/mod_install.R b/R/mod_install.R index 5bd1214..f27e6a2 100644 --- a/R/mod_install.R +++ b/R/mod_install.R @@ -10,7 +10,7 @@ #' @importFrom utils install.packages mod_install_ui <- function(id) { ns <- NS(id) - + tagList( # Small CSS to style the cards and badges tags$style(HTML(" @@ -67,7 +67,7 @@ mod_install_ui <- function(id) { border-radius: 4px; } ")), - + fluidPage( fluidRow( class = "install-row", @@ -76,7 +76,7 @@ mod_install_ui <- function(id) { width = 6, div( class = "install-card", - + # Already installed conditionalPanel( condition = sprintf("output['%s'] == true", ns("qploidyInstalled")), @@ -110,7 +110,7 @@ mod_install_ui <- function(id) { ), p("Qploidy is installed. You can access ploidy estimation features in the app.") ), - + # Not installed conditionalPanel( condition = sprintf("output['%s'] == false", ns("qploidyInstalled")), @@ -152,7 +152,7 @@ mod_install_ui <- function(id) { ) ) ), - + # Log (always visible) tags$label("Installation log"), div( @@ -161,13 +161,13 @@ mod_install_ui <- function(id) { ) ) ), - + # --- BIGapp card ----------------------------------------------------- column( width = 6, div( class = "install-card", - + # Already installed conditionalPanel( condition = sprintf("output['%s'] == true", ns("BIGappInstalled")), @@ -202,7 +202,7 @@ mod_install_ui <- function(id) { ), p("BIGapp is installed. You can access BIGapp features in the app.") ), - + # Not installed conditionalPanel( condition = sprintf("output['%s'] == false", ns("BIGappInstalled")), @@ -245,7 +245,7 @@ mod_install_ui <- function(id) { ) ) ), - + # Log (always visible) tags$label("Installation log"), div( @@ -262,7 +262,7 @@ mod_install_ui <- function(id) { width = 6, div( class = "install-card", - + # Already installed conditionalPanel( condition = sprintf("output['%s'] == true", ns("familiaInstalled")), @@ -296,7 +296,7 @@ mod_install_ui <- function(id) { ), p("Familia is installed. You can access ancestry estimation features in the app.") ), - + # Not installed conditionalPanel( condition = sprintf("output['%s'] == false", ns("familiaInstalled")), @@ -337,7 +337,7 @@ mod_install_ui <- function(id) { ) ) ), - + # Log (always visible) tags$label("Installation log"), div( @@ -346,13 +346,13 @@ mod_install_ui <- function(id) { ) ) ), - + # --- AlloMate Card ----------------------------------------------------- column( width = 6, div( class = "install-card", - + # Already installed conditionalPanel( condition = sprintf("output['%s'] == true", ns("allomateInstalled")), @@ -386,7 +386,7 @@ mod_install_ui <- function(id) { ), p("AlloMate is installed. You can access mating estimation features in the app.") ), - + # Not installed conditionalPanel( condition = sprintf("output['%s'] == false", ns("allomateInstalled")), @@ -428,7 +428,7 @@ mod_install_ui <- function(id) { ) ) ), - + # Log (always visible) tags$label("Installation log"), div( @@ -436,6 +436,96 @@ mod_install_ui <- function(id) { uiOutput(ns("install_log_allomate")) ) ) + ), + # --- GenoBrew card ---------------------------------------------------- + column( + width = 6, + div( + class = "install-card", + + # Already installed + conditionalPanel( + condition = sprintf("output['%s'] == true", ns("genobrewInstalled")), + div( + class = "install-header", + h3(class = "install-title", div( + class = "install-header", + tags$div( + style = "display:flex; align-items:center;", + tags$img( + src = "www/GenoBrew_logo.png", + height = "100px", + style = "margin-right:8px;" + ), + h3(class = "install-title", "GenoBrew") + ), + )), + span("Installed", class = "install-status-badge install-status-ok") + ), + p(tags$a(href = "https://github.com/Breeding-Insight/GenoBrew", target = "_blank", + icon("github"), " GitHub Repository")), + tagList( + p("Features:"), + tags$ul( + tags$li("Allele intensities/read counts standardization"), + tags$li("Sample ploidy estimation"), + tags$li("Aneuploidy detection"), + tags$li("Multipoint (HMM) copy number estimation (beta)") + ), + br() + ), + p("GenoBrew is installed. You can access ploidy estimation features in the app.") + ), + + # Not installed + conditionalPanel( + condition = sprintf("output['%s'] == false", ns("genobrewInstalled")), + div( + class = "install-header", + h3(class = "install-title", div( + class = "install-header", + tags$div( + style = "display:flex; align-items:center;", + tags$img( + src = "www/Qploidy_logo.png", + height = "100px", + style = "margin-right:8px;" + ), + h3(class = "install-title", "GenoBrew") + ), + )), + span("Not installed", class = "install-status-badge install-status-missing") + ), + p(tags$a(href = "https://github.com/Breeding-Insight/GenoBrew", target = "_blank", + icon("github"), " GitHub Repository")), + tagList( + p("Features:"), + tags$ul( + tags$li("Test marker panel performance with historical data"), + tags$li("Markers basic filters"), + tags$li("Interactive visualization of Qploidy2 CNV profiles results"), + tags$li("Find copy number variation hostspots in the genome") + ), + br() + ), + p("Install the GenoBrew package to enable marker panel tests and CNV visualization workflows."), + div( + style = "margin-top: 12px; margin-bottom: 10px;", + actionButton( + ns("install_genobrew"), + "Install GenoBrew", + icon = icon("download") + ) + ) + ), + + # Log (always visible) + tags$label("Installation log"), + div( + class = "install-log", + uiOutput(ns("install_log_genobrew")) + ) + ) ) ) #Closing fluidrow parentheses ) @@ -446,9 +536,9 @@ mod_install_ui <- function(id) { #' #' @noRd mod_install_server <- function(input, output, session, parent_session){ - + ns <- session$ns - + # --- reactive installation flags --------------------------------------- qploidy_installed <- reactiveVal( requireNamespace("Qploidy", quietly = TRUE) @@ -462,25 +552,33 @@ mod_install_server <- function(input, output, session, parent_session){ allomate_installed <- reactiveVal( requireNamespace("AlloMate", quietly = TRUE) ) - + genobrew_installed <- reactiveVal( + requireNamespace("GenoBrew", quietly = TRUE) + ) + output$qploidyInstalled <- reactive({ qploidy_installed() }) outputOptions(output, "qploidyInstalled", suspendWhenHidden = FALSE) - + output$familiaInstalled <- reactive({ familia_installed() }) outputOptions(output, "familiaInstalled", suspendWhenHidden = FALSE) - + output$BIGappInstalled <- reactive({ bigapp_installed() }) outputOptions(output, "BIGappInstalled", suspendWhenHidden = FALSE) - + output$allomateInstalled <- reactive({ allomate_installed() }) outputOptions(output, "allomateInstalled", suspendWhenHidden = FALSE) - + + output$genobrewInstalled <- reactive({ genobrew_installed() }) + outputOptions(output, "genobrewInstalled", suspendWhenHidden = FALSE) + # Initialize logs as empty output$install_log_qploidy <- renderUI(NULL) output$install_log_BIGapp <- renderUI(NULL) output$install_log_familia <- renderUI(NULL) output$install_log_allomate <- renderUI(NULL) - + output$install_log_genobrew <- renderUI(NULL) + + # --- Qploidy installation ---------------------------------------------- observeEvent(input$install_qploidy, { err_msg <- NULL @@ -538,7 +636,7 @@ mod_install_server <- function(input, output, session, parent_session){ ) } }) - + # --- Familia installation ---------------------------------------------- observeEvent(input$install_familia, { err_msg <- NULL @@ -596,7 +694,7 @@ mod_install_server <- function(input, output, session, parent_session){ ) } }) - + # --- AlloMate installation ---------------------------------------------- observeEvent(input$install_allomate, { err_msg <- NULL @@ -655,7 +753,7 @@ mod_install_server <- function(input, output, session, parent_session){ ) } }) - + # --- BIGapp installation ----------------------------------------------- observeEvent(input$install_bigapp, { err_msg <- NULL @@ -713,6 +811,66 @@ mod_install_server <- function(input, output, session, parent_session){ ) } }) + + # --- GenoBrew installation ---------------------------------------------- + observeEvent(input$install_genobrew, { + err_msg <- NULL + ok <- FALSE + log_lines <- character(0) + + output$install_log_genobrew <- renderUI(NULL) + + withProgress(message = "Installing GenoBrew", value = 0, { + + capture_msg <- function(m) { + log_lines <<- c(log_lines, conditionMessage(m)) + output$install_log_genobrew <- renderUI( + pre(style = "font-size:11px; white-space:pre-wrap;", + paste(log_lines, collapse = "")) + ) + invokeRestart("muffleMessage") + } + + withCallingHandlers( + tryCatch({ + if (!requireNamespace("remotes", quietly = TRUE)) { + incProgress(0.05, detail = "Installing remotes...") + install.packages("remotes") + } + incProgress(0.1, detail = "Contacting GitHub...") + remotes::install_github( + "Breeding-Insight/GenoBrew", + upgrade = "never", + quiet = FALSE + ) + incProgress(0.9, detail = "Verifying...") + ok <- requireNamespace("GenoBrew", quietly = TRUE) + incProgress(1, detail = "Done") + }, error = function(e) { + err_msg <<- conditionMessage(e) + }), + message = capture_msg + ) + }) + + if (ok) { + genobrew_installed(TRUE) + showNotification("GenoBrew installed successfully.", type = "message", duration = 8) + output$install_log_genobrew <- renderUI(HTML( + paste0(if (length(log_lines)) paste0('
', paste(log_lines, collapse=""), '
'), + 'GenoBrew installation completed. Restart the app to load GenoBrew features.') + )) + } else { + showNotification("GenoBrew installation failed. See log below.", type = "error", duration = NULL) + output$install_log_genobrew <- renderUI( + pre(style = "font-size:11px; white-space:pre-wrap; color:#c62828;", + if (is.null(err_msg)) "Unknown error (check server permissions/logs)." else + paste(c(log_lines, err_msg), collapse = "")) + ) + } + }) + + } ## To be copied in the UI diff --git a/README.md b/README.md index e222a9a..c5346ad 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,19 @@ Modules are installed from within the app via the **Install Modules** page. Each --- +### GenoBrew — Interactive Marker Panel Evaluation and CNV Visualization + +> GitHub: [`Breeding-Insight/GenoBrew`](https://github.com/Breeding-Insight/GenoBrew) + +| Feature | Description | +|---|---| +| Marker Panel Tests | Test marker panel performance with historical data | +| Interactive filters | Markers basic filters | +| CNV profiles | Interactive visualization of Qploidy2 CNV profiles results | +| CNV hotspots | Find copy number variation hostspots in the genome | + +--- + ## Requirements - R ≥ 3.6.0 diff --git a/inst/app/www/GenoBrew_logo.png b/inst/app/www/GenoBrew_logo.png new file mode 100644 index 0000000..d385831 Binary files /dev/null and b/inst/app/www/GenoBrew_logo.png differ