diff --git a/DESCRIPTION b/DESCRIPTION index e15d0aa..0c6e57c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,11 @@ Imports: shinipsum, mongolite, lubridate, - plotly + plotly, + survminer, + survival, + ggpmisc, + DT Encoding: UTF-8 LazyData: true RoxygenNote: 7.1.1 diff --git a/NAMESPACE b/NAMESPACE index 27dcff5..4da6c0a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(get_issue_trends) +export(get_survival_fit) export(mongo_string) export(run_app) import(ggplot2) @@ -10,6 +11,7 @@ import(shinipsum) import(shiny) import(shinydashboard) importFrom(config,get) +importFrom(dplyr,across) importFrom(dplyr,arrange) importFrom(dplyr,bind_rows) importFrom(dplyr,count) @@ -36,3 +38,8 @@ importFrom(shiny,shinyApp) importFrom(shinydashboard,dashboardBody) importFrom(shinydashboard,dashboardHeader) importFrom(shinydashboard,dashboardSidebar) +importFrom(stringr,str_to_title) +importFrom(survival,Surv) +importFrom(survival,survfit) +importFrom(survminer,ggsurvplot) +importFrom(survminer,surv_median) diff --git a/R/app_lib.R b/R/app_lib.R index 3146e94..c2b9118 100644 --- a/R/app_lib.R +++ b/R/app_lib.R @@ -1,3 +1,21 @@ +#' Takes a list of issues / PRs from Mongo and computes the survival +#' fit for both types +#' +#' @keywords internal +#' @export +#' @importFrom lubridate ymd_hms +#' @importFrom dplyr select mutate +#' @noRd +get_survival_fit <- function(d) { + d %>% + filter(type == 'issue' | baseRefName %in% c('main', 'master')) %>% + mutate(final_time = if_else(is.na(closedAt), Sys.time(), ymd_hms(closedAt)), + time = difftime(final_time, ymd_hms(createdAt), units = 'days'), + status = if_else(state == 'OPEN', 0, 1) + ) %>% + select(time, status, type) +} + #' Takes a list of issues / PRs from Mongo and counts them up by #' day/week/month for both opened (createdAt) and closed (closedAt) values. #' diff --git a/R/app_mongo.R b/R/app_mongo.R new file mode 100644 index 0000000..82f6233 --- /dev/null +++ b/R/app_mongo.R @@ -0,0 +1,60 @@ + +#' @importFrom mongolite mongo +#' @noRd +setup_mongo <- function(collection) { + mongo(collection, url = mongo_string()) +} + +#' @keywords internal +#' @export +#' @importFrom glue glue +#' @noRd +mongo_string <- function() { + DBUSER <- Sys.getenv('DBUSER') + DBPASS <- Sys.getenv('DBPASS') + DBPORT <- Sys.getenv('DBPORT') + DBNAME <- Sys.getenv('DBNAME') + + glue("mongodb://{DBUSER}:{DBPASS}@172.17.0.1:{DBPORT}/{DBNAME}") +} + +#' Takes a repo name and gets the relevant dataframes from Mongo +#' @importFrom glue glue +#' @importFrom dplyr bind_rows +#' @noRd +get_repo_data <- function(repo) { + query <- glue('{{"repository.nameWithOwner":"{repo}"}}') + base_fields <- '{ + "number":true, + "author":true, + "title":true, + "state":true, + "createdAt":true, + "closedAt":true, + "labels":true, + "repository":true + }' + + db_issues <- setup_mongo('issues') + issues <- db_issues$find(query, base_fields) %>% + mutate(type = 'issue') + db_issues$disconnect() ; rm(db_issues) + + # Add extra fields for PRs + new_fields <- jsonlite::parse_json(base_fields) + new_fields$mergedAt <- TRUE + new_fields$merged <- TRUE + new_fields$baseRefName <- TRUE + new_fields <- jsonlite::toJSON(new_fields, auto_unbox = T) + + db_pulls <- setup_mongo('pulls') + pulls <- db_pulls$find(query, new_fields) %>% + mutate(type = 'pull') + db_pulls$disconnect() ; rm(db_pulls) + + bind_rows(issues, pulls) +} + +get_repos <- function() { + # later, use mapreduce +} diff --git a/R/app_server.R b/R/app_server.R index e72e50f..67c2e3f 100644 --- a/R/app_server.R +++ b/R/app_server.R @@ -3,8 +3,11 @@ #' @param input,output,session Internal parameters for {shiny}. #' DO NOT REMOVE. #' @import shiny shinipsum ggplot2 plotly -#' @importFrom dplyr select mutate +#' @importFrom dplyr select mutate across #' @importFrom purrr map +#' @importFrom survival survfit Surv +#' @importFrom survminer ggsurvplot surv_median +#' @importFrom stringr str_to_title #' @noRd app_server <- function( input, output, session ) { @@ -27,8 +30,44 @@ app_server <- function( input, output, session ) { }) output$survival_plot <- renderPlot({ - repo <- input$repo - random_ggplot() + labs(title = repo) + tmp <- repo_data() %>% + get_survival_fit() + + fit <- survfit(Surv(time, status) ~ type, data = tmp) + + plot <- ggsurvplot( + fit, # fitted survfit object + data = tmp, + break.x.by = 10, + xlim = c(0,180), + fun = 'event', + surv.scale = 'percent', + risk.table = FALSE, + conf.int = TRUE, + pval = FALSE, + pval.method = FALSE, + surv.median.line = 'hv', + legend.labs = c('Issues', 'Pull Requests'), + ggtheme = theme_bw() # Change ggplot2 theme + ) + + tbl <- surv_median(fit) %>% mutate(across(is.numeric,round,1)) + tbl$strata <- c('Issues', 'Pull Requests') + colnames(tbl) <- colnames(tbl) %>% str_to_title() + + ttheme <- gridExtra::ttheme_default(base_size = 20) + g <- tibble::tibble(x = 0.95, y = 0.05, tbl = list(tbl)) + + plot$plot <- plot$plot + + theme(text = element_text(size=25)) + + ggpmisc::geom_table_npc(data = g, aes(npcx = x, npcy = y, label = tbl), + table.theme = ttheme) + labs(title = 'Time-to-close for Issues & Pull Requests', + subtitle = 'For PRs, merged & closed are considered equivalent', + x = 'Time (days)', + y = 'Chance to be closed') + + plot }) output$timeseries_plot <- renderPlot({ @@ -58,16 +97,18 @@ app_server <- function( input, output, session ) { layout(yaxis=list(fixedrange=TRUE)) }) - output$summary_table <- renderTable({ + output$summary_table <- DT::renderDT({ req(input$repo) d <- repo_data() req(d$labels) d %>% - tidyr::separate_rows(labels,sep=',') %>% - dplyr::filter(labels != '') %>% + tidyr::unnest(labels) %>% + group_by(state) %>% dplyr::count(labels,sort=T) %>% - head(5) + tidyr::pivot_wider(names_from = state, values_from = n) %>% + rename(Label = labels) + DT::datatable(options = list(pageLength = 5, lengthChange = F, searching = F)) }) output$timeSinceLastUpdate <- renderUI({ @@ -85,63 +126,3 @@ app_server <- function( input, output, session ) { ) }) } - - -#' @importFrom mongolite mongo -#' @noRd -setup_mongo <- function(collection) { - mongo(collection, url = mongo_string()) -} - -#' @keywords internal -#' @export -#' @importFrom glue glue -#' @noRd -mongo_string <- function() { - DBUSER <- Sys.getenv('DBUSER') - DBPASS <- Sys.getenv('DBPASS') - DBPORT <- Sys.getenv('DBPORT') - DBNAME <- Sys.getenv('DBNAME') - - glue("mongodb://{DBUSER}:{DBPASS}@172.17.0.1:{DBPORT}/{DBNAME}") -} - -#' Takes a repo name and gets the relevant dataframes from Mongo -#' @importFrom glue glue -#' @importFrom dplyr bind_rows -#' @noRd -get_repo_data <- function(repo) { - query <- glue('{{"repository.nameWithOwner":"{repo}"}}') - base_fields <- '{ - "number":true, - "author":true, - "title":true, - "state":true, - "createdAt":true, - "closedAt":true, - "labels":true, - "repository":true - }' - - db_issues <- setup_mongo('issues') - issues <- db_issues$find(query, base_fields) %>% - mutate(type = 'issue') - db_issues$disconnect() ; rm(db_issues) - - # Add extra fields for PRs - new_fields <- jsonlite::parse_json(base_fields) - new_fields$mergedAt <- TRUE - new_fields$merged <- TRUE - new_fields <- jsonlite::toJSON(new_fields, auto_unbox = T) - - db_pulls <- setup_mongo('pulls') - pulls <- db_pulls$find(query, new_fields) %>% - mutate(type = 'pull') - db_pulls$disconnect() ; rm(db_pulls) - - bind_rows(issues, pulls) -} - -get_repos <- function() { - # later, use mapreduce -} diff --git a/R/app_ui.R b/R/app_ui.R index 309b498..6f7e0f6 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -38,7 +38,7 @@ ui_body <- function() { ), column(width = 4, box(width = NULL, - tableOutput("summary_table") + DT::dataTableOutput("summary_table") ) ), column(width = 4, diff --git a/renv.lock b/renv.lock index 80a3147..f5e3f70 100644 --- a/renv.lock +++ b/renv.lock @@ -23,6 +23,13 @@ "Repository": "CRAN", "Hash": "85738c69035e67ec4b484a5e02640ef6" }, + "KMsurv": { + "Package": "KMsurv", + "Version": "0.1-5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "aee647d15e5541ad44d157f7b78fda01" + }, "MASS": { "Package": "MASS", "Version": "7.3-51.6", @@ -37,6 +44,13 @@ "Repository": "CRAN", "Hash": "08588806cba69f04797dab50627428ed" }, + "MatrixModels": { + "Package": "MatrixModels", + "Version": "0.4-1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d57ac35220b39c591388ab3a080f9cbe" + }, "R6": { "Package": "R6", "Version": "2.4.1", @@ -58,6 +72,34 @@ "Repository": "CRAN", "Hash": "125dc7a0ed375eb68c0ce533b48d291f" }, + "RcppArmadillo": { + "Package": "RcppArmadillo", + "Version": "0.9.900.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "961e71b714a1ffe58ed651cb6e40b3b1" + }, + "RcppEigen": { + "Package": "RcppEigen", + "Version": "0.3.3.7.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c6faf038ba4346b1de19ad7c99b8f94a" + }, + "SparseM": { + "Package": "SparseM", + "Version": "1.78", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "fbe4ac267bf42a91e495cc68ad3f8b63" + }, + "abind": { + "Package": "abind", + "Version": "1.4-5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4f57884290cc75ab22f4af9e9d4ca862" + }, "askpass": { "Package": "askpass", "Version": "1.1", @@ -93,6 +135,13 @@ "Repository": "CRAN", "Hash": "543776ae6848fde2f48ff3816d0628bc" }, + "boot": { + "Package": "boot", + "Version": "1.3-25", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "bd51734a754b6c2baf28b2d1ebc11e91" + }, "brew": { "Package": "brew", "Version": "1.0-6", @@ -100,6 +149,13 @@ "Repository": "CRAN", "Hash": "92a5f887f9ae3035ac7afde22ba73ee9" }, + "broom": { + "Package": "broom", + "Version": "0.7.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2ca5ae42f3bfd149504d63c833c2be26" + }, "callr": { "Package": "callr", "Version": "3.4.4", @@ -107,6 +163,27 @@ "Repository": "CRAN", "Hash": "e56fe17ffeddfdcfcef40981e41e1c40" }, + "car": { + "Package": "car", + "Version": "3.0-9", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5b4045bd11466d0d3e55c71f81cc1b5f" + }, + "carData": { + "Package": "carData", + "Version": "3.0-4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7ff5c94cec207b3fd9774cfaa5157738" + }, + "cellranger": { + "Package": "cellranger", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" + }, "cli": { "Package": "cli", "Version": "2.0.2", @@ -142,6 +219,27 @@ "Repository": "CRAN", "Hash": "76268942467fa8ba171e9aa34203ee2a" }, + "conquer": { + "Package": "conquer", + "Version": "1.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a31720f692920e635ecef0481d478247" + }, + "corrplot": { + "Package": "corrplot", + "Version": "0.84", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b55c32ae818a84109a51f172290c95f2" + }, + "cowplot": { + "Package": "cowplot", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "870b41daf1a4c3640f2e3407a40c31b9" + }, "cpp11": { "Package": "cpp11", "Version": "0.2.1", @@ -226,6 +324,13 @@ "Repository": "CRAN", "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" }, + "exactRankTests": { + "Package": "exactRankTests", + "Version": "0.8-31", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1cc8cd88a11115c88d8bac0369cf3bf4" + }, "fansi": { "Package": "fansi", "Version": "0.4.1", @@ -247,6 +352,20 @@ "Repository": "CRAN", "Hash": "83ab58a0518afe3d17e41da01af13b60" }, + "forcats": { + "Package": "forcats", + "Version": "0.5.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1cb4279e697650f0bd78cd3601ee7576" + }, + "foreign": { + "Package": "foreign", + "Version": "0.8-80", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ae1b1e15cc6ccb2bc61c0ac33e86d35f" + }, "fs": { "Package": "fs", "Version": "1.5.0", @@ -268,6 +387,41 @@ "Repository": "CRAN", "Hash": "4ded8b439797f7b1693bd3d238d0106b" }, + "ggpmisc": { + "Package": "ggpmisc", + "Version": "0.3.6", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "eaddb71a5a0f1205d1de72fcb6896dde" + }, + "ggpubr": { + "Package": "ggpubr", + "Version": "0.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "77089557d374c69db7cb77e65f0d6ab0" + }, + "ggrepel": { + "Package": "ggrepel", + "Version": "0.8.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c013a50b19695daf04853679e1bc105a" + }, + "ggsci": { + "Package": "ggsci", + "Version": "2.9", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "81ccb8213ed592598210afd10c3a5936" + }, + "ggsignif": { + "Package": "ggsignif", + "Version": "0.6.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3e9b8a51dfdc95395632b25ce3ce8ebc" + }, "gh": { "Package": "gh", "Version": "1.1.0", @@ -296,6 +450,13 @@ "Repository": "CRAN", "Hash": "e3c3f5f3fc65ecdbb2407ea5e0848e4f" }, + "gridExtra": { + "Package": "gridExtra", + "Version": "2.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7d7f283939f563670a697165b2cf5560" + }, "gtable": { "Package": "gtable", "Version": "0.3.0", @@ -303,6 +464,13 @@ "Repository": "CRAN", "Hash": "ac5c6baf7822ce8732b343f14c072c4d" }, + "haven": { + "Package": "haven", + "Version": "2.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "221d0ad75dfa03ebf17b1a4cc5c31dfc" + }, "here": { "Package": "here", "Version": "0.1", @@ -324,6 +492,13 @@ "Repository": "CRAN", "Hash": "4dc5bb88961e347a0f4d8aad597cbfac" }, + "hms": { + "Package": "hms", + "Version": "0.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "726671f634529d470545f9fd1a9d1869" + }, "htmltools": { "Package": "htmltools", "Version": "0.5.0", @@ -373,6 +548,13 @@ "Repository": "CRAN", "Hash": "1ec84e070b88b37ed169f19def40d47c" }, + "km.ci": { + "Package": "km.ci", + "Version": "0.5-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b6090043f6d0b5ffc447be4b3f2811e9" + }, "knitr": { "Package": "knitr", "Version": "1.29", @@ -415,6 +597,13 @@ "Repository": "CRAN", "Hash": "361811f31f71f8a617a9a68bf63f1f42" }, + "lme4": { + "Package": "lme4", + "Version": "1.1-23", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ad24d1fd9ed431543f4633bb083e194a" + }, "lubridate": { "Package": "lubridate", "Version": "1.7.9", @@ -429,6 +618,13 @@ "Repository": "CRAN", "Hash": "1bb58822a20301cee84a41678e25d9b7" }, + "maptools": { + "Package": "maptools", + "Version": "1.0-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1cb5cb7bbab76318944e3794ff2512ae" + }, "markdown": { "Package": "markdown", "Version": "1.1", @@ -436,6 +632,20 @@ "Repository": "CRAN", "Hash": "61e4a10781dd00d7d81dd06ca9b94e95" }, + "matrixStats": { + "Package": "matrixStats", + "Version": "0.56.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d16f18aeb023d7a80c090d9458fc75a6" + }, + "maxstat": { + "Package": "maxstat", + "Version": "0.7-25", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c166f04bd2bbd830ab34b7329104c019" + }, "mgcv": { "Package": "mgcv", "Version": "1.8-31", @@ -450,6 +660,13 @@ "Repository": "CRAN", "Hash": "e87a35ec73b157552814869f45a63aa3" }, + "minqa": { + "Package": "minqa", + "Version": "1.2.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "eaee7d2a6f3ed4491df868611cb064cc" + }, "mongolite": { "Package": "mongolite", "Version": "2.2.0", @@ -464,6 +681,13 @@ "Repository": "CRAN", "Hash": "6dfe8bf774944bd5595785e3229d8771" }, + "mvtnorm": { + "Package": "mvtnorm", + "Version": "1.1-1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "69fa7331e7410c2a2cb3f9868513904f" + }, "nlme": { "Package": "nlme", "Version": "3.1-148", @@ -471,6 +695,20 @@ "Repository": "CRAN", "Hash": "662f52871983ff3e3ef042c62de126df" }, + "nloptr": { + "Package": "nloptr", + "Version": "1.2.2.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2737faeee353704efec5afa1e943dd64" + }, + "nnet": { + "Package": "nnet", + "Version": "7.3-14", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "0d87e50e11394a7151a28873637d799a" + }, "openssl": { "Package": "openssl", "Version": "1.4.3", @@ -478,6 +716,20 @@ "Repository": "CRAN", "Hash": "a399e4773075fc2375b71f45fca186c4" }, + "openxlsx": { + "Package": "openxlsx", + "Version": "4.2.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "406db947a3721d059635aaa04e6d051a" + }, + "pbkrtest": { + "Package": "pbkrtest", + "Version": "0.4-8.6", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d547eab65958fc4f5d68ad0adfacfcf4" + }, "pillar": { "Package": "pillar", "Version": "1.4.6", @@ -513,6 +765,20 @@ "Repository": "CRAN", "Hash": "b08edf378e0e38959a6983e3d5902795" }, + "plyr": { + "Package": "plyr", + "Version": "1.8.6", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ec0e5ab4e5f851f6ef32cd1d1984957f" + }, + "polynom": { + "Package": "polynom", + "Version": "1.4-0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c396592ecfe9e75cee1013533efafe34" + }, "praise": { "Package": "praise", "Version": "1.0.0", @@ -534,6 +800,13 @@ "Repository": "CRAN", "Hash": "03446ed0b8129916f73676726cb3c48f" }, + "progress": { + "Package": "progress", + "Version": "1.2.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" + }, "promises": { "Package": "promises", "Version": "1.1.1", @@ -555,6 +828,34 @@ "Repository": "CRAN", "Hash": "97def703420c8ab10d8f0e6c72101e02" }, + "quantreg": { + "Package": "quantreg", + "Version": "5.67", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5cd37ddc60f523651e84c1332d079ed4" + }, + "readr": { + "Package": "readr", + "Version": "1.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "af8ab99cd936773a148963905736907b" + }, + "readxl": { + "Package": "readxl", + "Version": "1.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "63537c483c2dbec8d9e3183b3735254a" + }, + "rematch": { + "Package": "rematch", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" + }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", @@ -576,6 +877,13 @@ "Repository": "CRAN", "Hash": "7340c71f46a0fd16506cfa804e224e44" }, + "rio": { + "Package": "rio", + "Version": "0.5.16", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4a9aecbe83639be364de13ffe0671bcf" + }, "rlang": { "Package": "rlang", "Version": "0.4.7", @@ -597,6 +905,13 @@ "Repository": "CRAN", "Hash": "f6a407ae5dd21f6f80a6708bbb6eb3ae" }, + "rstatix": { + "Package": "rstatix", + "Version": "0.6.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7eb4d25cb9f8183f0c9e19704a3cf681" + }, "rstudioapi": { "Package": "rstudioapi", "Version": "0.11", @@ -644,6 +959,27 @@ "Repository": "CRAN", "Hash": "947e4e02a79effa5d512473e10f41797" }, + "sp": { + "Package": "sp", + "Version": "1.4-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3290eebc34ba4df5e213878d54c1e623" + }, + "splus2R": { + "Package": "splus2R", + "Version": "1.2-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a992015cf9f68c427adcf7a72b5ce4c0" + }, + "statmod": { + "Package": "statmod", + "Version": "1.4.34", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5b229273695937933bc21ef235e84962" + }, "stringi": { "Package": "stringi", "Version": "1.5.3", @@ -658,6 +994,27 @@ "Repository": "CRAN", "Hash": "0759e6b6c0957edb1311028a49a35e76" }, + "survMisc": { + "Package": "survMisc", + "Version": "0.5.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "566b73db4f3b2f517e707e1c73267325" + }, + "survival": { + "Package": "survival", + "Version": "3.1-12", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1c5bb53bd428f3c42a25b7aeb983d8c7" + }, + "survminer": { + "Package": "survminer", + "Version": "0.4.8", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7ac6bc85f8759d17b9a6ecc6b8bc5c18" + }, "sys": { "Package": "sys", "Version": "3.4", @@ -777,6 +1134,13 @@ "Repository": "CRAN", "Hash": "2826c5d9efb0a88f657c7a679c7106db" }, + "zip": { + "Package": "zip", + "Version": "2.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3bc8405c637d988801ec5ea88372d0c2" + }, "zoo": { "Package": "zoo", "Version": "1.8-8",