├── .Rprofile ├── .gitignore ├── R ├── cards.R ├── stack.R └── tz.R ├── README.md ├── app.R ├── data └── schedule.csv ├── renv.lock ├── renv ├── .gitignore ├── activate.R └── settings.dcf ├── rstudio-global-calendar.Rproj └── www ├── extra.css ├── extra.js └── speakers ├── aaronjacobs.jpg ├── ahmadoudicko.jpg ├── alanfeder.jpg ├── alexcookson.png ├── allisonhorst.png ├── andrewtran.jpg ├── athanasiamowinckel.png ├── barretschloerke.png ├── carsonsievert.png ├── chelseaparlettpelleriti.png ├── daniellesmallsperkins.jpg ├── deanmarchiori.jpg ├── dorrisscott.jpg ├── emilyriederer.jpg ├── ericgunnarcronstrom.jpg ├── garrickadenbuie.jpg ├── grantfleming.png ├── hadleywickham.jpg ├── irenesteves.jpg ├── javierluraschi.jpg ├── jeroenooms.jpg ├── johnburnmurdoch.jpg ├── jooyoungseo.jpg ├── karawoo.jpg ├── katehertweck.jpg ├── lucydagostinomcgowan.png ├── malcolmbarrett.jpg ├── marcusadams.jpg ├── marievendettuoli.jpg ├── mattthomas.jpg ├── mayagans.jpg ├── meganbeckett.jpg ├── michaelchirico.jpg ├── michaelchow.jpg ├── mikepage.jpg ├── minecetinkayarundel.jpg ├── nealrichardson.jpg ├── nicholaspylypiw.jpg ├── nicolekramer.jpg ├── pamelapairo.jpg ├── richardvogg.jpg ├── rivaquiroga.jpg ├── seanlopp.png ├── shelmithkariuki.png ├── simoncouch.jpg ├── sophiebeiers.jpg ├── vickiboykis.jpg ├── wolframking.jpg ├── yaninabellinisaibene.jpg └── zj.jpg /.Rprofile: -------------------------------------------------------------------------------- 1 | source("renv/activate.R") 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | rsconnect 6 | -------------------------------------------------------------------------------- /R/cards.R: -------------------------------------------------------------------------------- 1 | card <- function(title, image, link, ..., class = "p-2 mb-3 border rounded w-100") { 2 | div( 3 | class = "col-sm-6 col-md-4", 4 | div( 5 | class = class, 6 | if (!is.null(image)) { 7 | div( 8 | class = "mb-3", 9 | style = "height: 200px", 10 | tags$img(class = "mx-auto d-block", src = image$src, alt = image$alt, style = "max-height: 200px; max-width: 100%"), 11 | ) 12 | }, 13 | div( 14 | h3(class = "text-uppercase", title), 15 | p(class = "card-text", ...), 16 | a(href = link, title, target = "_blank", class = "btn btn-secondary") 17 | ) 18 | ) 19 | ) 20 | } 21 | 22 | rstudio_hex <- function(pkg) { 23 | list( 24 | src = glue("https://github.com/rstudio/hex-stickers/raw/master/PNG/{pkg}.png"), 25 | alt = glue("{pkg} R package hex sticker") 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /R/stack.R: -------------------------------------------------------------------------------- 1 | Stack <- R6::R6Class( 2 | "stack", 3 | public = list( 4 | stack = "", 5 | initialize = function(x = NULL, label = NULL) { 6 | self$stack <- shiny::reactiveVal(x, label) 7 | }, 8 | add = function(x) { 9 | self$stack(c(self$stack(), x)) 10 | }, 11 | remove = function(x) { 12 | self$stack(setdiff(self$stack(), x)) 13 | }, 14 | clear = function(x) { 15 | self$stack(NULL) 16 | }, 17 | intersect = function(x) { 18 | self$stack(base::intersect(self$stack(), x)) 19 | }, 20 | union = function(x) { 21 | self$stack(base::union(self$stack(), x)) 22 | }, 23 | update = function(x) { 24 | self$stack(x) 25 | } 26 | ) 27 | ) 28 | -------------------------------------------------------------------------------- /R/tz.R: -------------------------------------------------------------------------------- 1 | 2 | available_timezones <- function() { 3 | available_timezones <- OlsonNames() 4 | tz_list <- list() 5 | for (tz in available_timezones) { 6 | if (grepl("/", tz, fixed = TRUE)) { 7 | tz_split <- strsplit(tz, "/", fixed = TRUE)[[1]] 8 | tz_group <- tz_split[1] 9 | tz_name <- paste(tz_split[-1], collapse = "/") 10 | names(tz) <- gsub("_", " ", tz_name) 11 | tz_list[[tz_group]] <- c(tz_list[[tz_group]], tz) 12 | } else { 13 | tz_list[["Other"]] <- c(tz_list[["Other"]], tz) 14 | } 15 | } 16 | tz_list[sort(names(tz_list))] 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # A Talk Explorer for rstudio::global(2021) 3 | 4 | 5 | 6 | 7 | A little Shiny app that makes it easy to build your schedule for [rstudio::global](https://global.rstudio.com). 8 | 9 | Run it locally: 10 | 11 | ```r 12 | shiny::runGitHub("rstudio-global-2021-calendar", "gadenbuie", ref = "main") 13 | ``` 14 | 15 | ## Uses 16 | 17 | - [shiny](https://shiny.rstudio.com) ([dev version](https://github.com/rstudio/shiny)) 18 | - [bslib](https://rstudio.github.io/bslib/) 19 | - [reactable](https://glin.github.io/reactable/) 20 | - [renv](https://rstudio.github.io/renv/) 21 | - [calendar](https://github.com/ATFutures/calendar) 22 | 23 | ## Thanks 24 | 25 | Thanks to Silvia Canelon for outlining how to create a calendar event from the rstudio::global schedule in [spcanelon/rstudio-global-2021-calendar](https://github.com/spcanelon/rstudio-global-2021-calendar). 26 | -------------------------------------------------------------------------------- /app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(bslib) 3 | library(lubridate) 4 | library(calendar) 5 | library(reactable) 6 | library(glue) 7 | source("R/stack.R") 8 | source("R/tz.R") 9 | source("R/cards.R") 10 | 11 | Sys.setenv(TZ = "UTC") 12 | 13 | theme <- bs_theme( 14 | version = 4, 15 | bootswatch = "lux", 16 | primary = "#447099", 17 | secondary = "#75AADB", 18 | success = "#A4C689", 19 | warning = "#fdbe4b", 20 | info = "#CBD4DD", 21 | "font-size-base" = "1rem" 22 | ) 23 | 24 | schedule <- readr::read_csv("data/schedule.csv") 25 | schedule$id <- seq_len(nrow(schedule)) 26 | year(schedule$time_gmt) <- 2021 27 | schedule$name <- gsub("\n", ", ", schedule$name) 28 | 29 | ui <- navbarPage( 30 | 'rstudio::global("schedule")', 31 | theme = theme, 32 | collapsible = TRUE, 33 | tabPanel( 34 | title = "Schedule", 35 | id = "schedule", 36 | # skip link 37 | a( 38 | "If you're using a screen reader, you may find the official ", 39 | "RStudio Global conference website is better suited. Do you want to go there now?", 40 | class = "screenreader-text", 41 | `tab-index` = 1, 42 | href = "https://global.rstudio.com/student/all_events" 43 | ), 44 | div( 45 | class = "container-fluid", 46 | style = "max-width: 1600px", 47 | div( 48 | class = "row", 49 | div( 50 | class = "col-lg-3 order-1 order-lg-2 sidebar", 51 | uiOutput("your_talks"), 52 | selectInput("tz", "Your Timezone", choices = available_timezones(), selected = "UTC", width = "100%"), 53 | div( 54 | class = "row", 55 | div( 56 | class = "col-6 col-lg-12", 57 | textInput("sch_search", "Search", width = "100%"), 58 | radioButtons("sch_day", "Day", c("First" = "one", "Second" = "two", "All" = "all"), inline = TRUE, selected = c("all"), width = "100%"), 59 | sliderInput("sch_hours", "Hours in Your Time Zone", value = c(0, 24), min = 0, max = 24, step = 1, post = ":00", width = "100%") 60 | ), 61 | div( 62 | class = "col-6 col-lg-12", 63 | selectizeInput("sch_type", "Talk Type", choices = sort(unique(schedule$type)), multiple = TRUE, width = "100%"), 64 | selectizeInput("sch_topic", "Talk Topic", choices = sort(unique(schedule$topic)), multiple = TRUE, width = "100%"), 65 | selectizeInput("sch_presenter", "Presenter", choices = sort(unique(schedule$name)), multiple = TRUE, width = "100%") 66 | ) 67 | ) 68 | ), 69 | div( 70 | class = "col-lg-9 order-2 order-lg-1", 71 | reactable::reactableOutput("schedule"), 72 | helpText( 73 | class = "mt-3", 74 | tags$a( 75 | href = "https://global.rstudio.com", 76 | code("rstudio::global") 77 | ), 78 | "will be held Thursday 2021-01-21 and Friday 2021-01-22." 79 | ), 80 | htmltools::htmlDependency( 81 | name = "rstudio-global-calendar", 82 | version = "0.0.1", 83 | src = "www", 84 | script = "extra.js", 85 | stylesheet = "extra.css" 86 | ) 87 | ) 88 | ) 89 | ) 90 | ), 91 | tabPanel( 92 | title = "About", 93 | id = "about", 94 | div( 95 | class = "container-fluid", 96 | style = "max-width: 900px", 97 | h2( 98 | class = "text-monospace", 99 | "community %>% tidyr::gather()" 100 | ), 101 | p("January 21, 2021 at 8am PT / 16:00 GMT / 01:00 JST"), 102 | p( 103 | "Our goal is to make rstudio::global(2021) our most inclusive and", 104 | "global event, making the most of the freedom from geographical and", 105 | "economic constraints that comes with an online event. That means that", 106 | "the conference will be free, designed around participation from every", 107 | "time zone, and have speakers from around the world." 108 | ), 109 | p( 110 | a( 111 | "Register Now", 112 | href = "https://global.rstudio.com/student/authentication/register", 113 | class = "btn btn-primary" 114 | ), 115 | a( 116 | tags$a( 117 | href = "https://global.rstudio.com/student/all_events", 118 | class = "btn btn-success", 119 | "Official Schedule" 120 | ) 121 | ) 122 | ), 123 | tags$hr(class = "my-4"), 124 | h2("About this app", class = "text-monospace"), 125 | p( 126 | HTML("This app was built with ♥️ and ☕ by"), 127 | tags$a(href = "https://www.garrickadenbuie.com", "Garrick Aden-Buie", .noWS = "after"), 128 | ", using the packages listed below. Check out", 129 | tags$a(href = "https://github.com/gadenbuie/rstudio-global-2021-calendar", "the full source code"), 130 | "on Github." 131 | ), 132 | div( 133 | class = "d-flex flex-wrap align-items-stretch justify-content-between", 134 | card( 135 | "shiny", 136 | rstudio_hex("shiny"), 137 | "https://shiny.rstudio.com", 138 | "Shiny is an R package that makes it easy to build interactive web apps straight from R." 139 | ), 140 | card( 141 | "renv", 142 | rstudio_hex("renv"), 143 | "https://rstudio.github.io/renv", 144 | "The renv package helps you create reproducible environments for your R projects. Use renv to make your R projects more: isolated, portable, and reproducible." 145 | ), 146 | card( 147 | "bslib", 148 | list(src = "https://camo.githubusercontent.com/3a4d3fbd6458e2fe5c0f5fb2df62878b9f74c2531c340a37599d875ae43a7d0e/68747470733a2f2f692e696d6775722e636f6d2f4b4c4b793173302e676966", alt = "Animated gif of bslib features"), 149 | "https://rstudio.github.io/bslib/", 150 | "Tools for creating custom Bootstrap themes, making it easier to style Shiny apps & R Markdown documents directly from R without writing unruly CSS and HTML." 151 | ), 152 | card( 153 | "R6", 154 | rstudio_hex("R6"), 155 | "https://r6.r-lib.org/", 156 | "Encapsulated object-oriented programming for R." 157 | ), 158 | card( 159 | "glue", 160 | rstudio_hex("glue"), 161 | "https://glue.tidyverse.org", 162 | "Glue strings to data in R. Small, fast, dependency free interpreted string literals." 163 | ), 164 | card( 165 | "lubridate", 166 | rstudio_hex("lubridate"), 167 | "https://lubridate.tidyverse.org", 168 | "Make working with dates in R just that little bit easier." 169 | ), 170 | card( 171 | "calendar", 172 | NULL, 173 | "https://github.com/ATFutures/calendar", 174 | "Create, read, write, and work with iCalander (.ics, .ical or similar) files in R." 175 | ), 176 | card( 177 | "reactable", 178 | NULL, 179 | "https://glin.github.io/reactable/index.html", 180 | "Interactive data tables for R, based on the React Table library and made with reactR." 181 | ), 182 | card( 183 | "prettyunits", 184 | NULL, 185 | "https://github.com/r-lib/prettyunits", 186 | "Pretty, human readable formatting of quantities." 187 | ), 188 | ) 189 | ) 190 | ) 191 | ) 192 | 193 | server <- function(input, output, session) { 194 | selected_talks <- Stack$new() 195 | selected_in_current_view <- reactiveVal() 196 | 197 | schedule_view <- reactive({ 198 | if (isTruthy(input$sch_day)) { 199 | if (input$sch_day == "one") { 200 | schedule <- schedule[ 201 | schedule$time_gmt < ymd_hms("2021-01-22 04:00:00", tz = "UTC"), 202 | ] 203 | } else if (input$sch_day == "two") { 204 | schedule <- schedule[ 205 | schedule$time_gmt >= ymd_hms("2021-01-22 04:00:00", tz = "UTC"), 206 | ] 207 | } 208 | } 209 | schedule$time <- with_tz(schedule$time_gmt, input$tz) 210 | if (isTruthy(input$sch_hours)) { 211 | schedule <- schedule[ 212 | hour(schedule$time) >= input$sch_hours[1] & hour(schedule$time) <= input$sch_hours[2], 213 | ] 214 | } 215 | if (shiny::isTruthy(input$sch_search)) { 216 | schedule <- schedule[ 217 | grepl(input$sch_search, tolower(paste(schedule$title_text, schedule$abstract_text))), 218 | ] 219 | } 220 | if (isTruthy(input$sch_type)) { 221 | schedule <- schedule[schedule$type %in% input$sch_type, ] 222 | } 223 | if (isTruthy(input$sch_topic)) { 224 | schedule <- schedule[schedule$topic %in% input$sch_topic, ] 225 | } 226 | if (isTruthy(input$sch_presenter)) { 227 | schedule <- schedule[schedule$name %in% input$sch_presenter, ] 228 | } 229 | schedule$info <- schedule$talk_id 230 | common_vars <- c( 231 | "id", "info", "talk_id", "type", "title_text", "name", "time", 232 | "duration", "track", "topic", "url" 233 | ) 234 | schedule <- schedule[, common_vars] 235 | schedule 236 | }) 237 | 238 | selected_by_user_current_view <- reactive(getReactableState("schedule", "selected")) 239 | 240 | observeEvent(selected_by_user_current_view(), { 241 | current <- selected_talks$stack() 242 | on.exit(ignore_schedule_change(FALSE)) 243 | if (!is.null(current) && is.null(selected_by_user_current_view()) && ignore_schedule_change()) { 244 | return() 245 | } 246 | in_view <- intersect(current, schedule_view()$id) 247 | 248 | if (is.null(selected_by_user_current_view()) && length(in_view)) { 249 | selected_talks$remove(in_view) 250 | return() 251 | } 252 | 253 | selected <- schedule_view()$id[selected_by_user_current_view()] 254 | 255 | talks_to_add <- setdiff(selected, current) 256 | talks_to_drop <- setdiff(in_view, selected) 257 | 258 | if (length(talks_to_add)) { 259 | selected_talks$add(talks_to_add) 260 | } 261 | if (length(talks_to_drop)) { 262 | selected_talks$remove(talks_to_drop) 263 | } 264 | }, ignoreNULL = FALSE, ignoreInit = TRUE) 265 | 266 | output$your_talks <- renderUI({ 267 | req(selected_talks$stack()) 268 | tagList( 269 | downloadButton( 270 | "download_calendar", 271 | class = "d-block mb-3 btn-primary", 272 | glue( 273 | "Download Calendar ({n} talk{s})", 274 | n = length(selected_talks$stack()), 275 | s = if (length(selected_talks$stack()) == 1) "" else "s" 276 | ) 277 | ), 278 | p(class = "text-right", actionLink("reset", "Reset Selection")) 279 | ) 280 | }) 281 | 282 | output$download_calendar <- downloadHandler( 283 | filename = "rstudio-global-talks.ics", 284 | content = function(file) { 285 | talks <- schedule[schedule$id %in% selected_talks$stack(), ] 286 | talks$start_time <- with_tz(talks$time_gmt, tzone = input$tz) 287 | talks$end_time <- talks$start_time + seconds(talks$duration) 288 | talk_events <- lapply(seq_len(nrow(talks)), function(idx) { 289 | desc <- paste0("Presenter: ", talks$name[[idx]], "\n\n", talks$abstract_text[[idx]]) 290 | desc <- gsub("\n", "\\n", desc, fixed = TRUE) 291 | desc <- strwrap(desc, 75) 292 | desc <- paste(desc, collapse = " \n ") 293 | desc <- gsub(",", "\\,", desc) 294 | ev <- calendar::ic_event( 295 | start_time = talks$start_time[[idx]], 296 | end_time = talks$end_time[[idx]], 297 | summary = talks$title_text[[idx]], 298 | more_properties = TRUE, 299 | event_properties = c( 300 | DESCRIPTION = desc, 301 | URL = talks$url[[idx]] 302 | ) 303 | ) 304 | ev 305 | }) 306 | calendar::ic_write(do.call(rbind, talk_events), file) 307 | } 308 | ) 309 | 310 | observeEvent(input$reset, { 311 | selected_talks$update(NULL) 312 | reactable::updateReactable( 313 | "schedule", 314 | selected = NA 315 | ) 316 | }) 317 | 318 | ignore_schedule_change <- reactiveVal(FALSE) 319 | 320 | output$schedule <- reactable::renderReactable({ 321 | ignore_schedule_change(TRUE) 322 | reactable( 323 | schedule_view(), 324 | selection = "multiple", 325 | defaultSelected = which(schedule_view()$id %in% isolate(selected_talks$stack())), 326 | highlight = TRUE, 327 | borderless = TRUE, 328 | columns = list( 329 | talk_id = colDef(show = FALSE), 330 | id = colDef(show = FALSE), 331 | url = colDef(show = FALSE), 332 | time = colDef( 333 | name = "Time", 334 | html = TRUE, 335 | cell = function(value) { 336 | strftime( 337 | value, 338 | format = '%a %H:%M', 339 | tz = input$tz 340 | ) 341 | } 342 | ), 343 | duration = colDef( 344 | name = "Length", 345 | minWidth = 80, 346 | cell = function(value, index) prettyunits::pretty_sec((value %/% 60) * 60) 347 | ), 348 | type = colDef( 349 | name = "Type", 350 | html = TRUE, 351 | align = "center", 352 | cell = function(value) { 353 | value <- paste(value) 354 | glue( 355 | '{value}', 356 | type = switch( 357 | value, 358 | keynote = "primary", 359 | lightning = "warning", 360 | talk = "success", 361 | "light" 362 | ), 363 | value = paste0(toupper(substr(value, 1, 1)), substr(value, 2, nchar(value))) 364 | ) 365 | } 366 | ), 367 | track = colDef( 368 | name = "Track", 369 | html = TRUE, 370 | minWidth = 80, 371 | align = "center", 372 | cell = function(value) { 373 | if (!is.na(value)) { 374 | glue( 375 | '{value}', 376 | type = switch( 377 | paste(value), 378 | A = "secondary", 379 | B = "info", 380 | C = "dark", 381 | "light" 382 | ) 383 | ) 384 | } 385 | } 386 | ), 387 | topic = colDef(name = "Topic", minWidth = 100, align = "center"), 388 | name = colDef(name = "Presenter", minWidth = 200), 389 | title_text = colDef( 390 | name = "Title", 391 | minWidth = 300, 392 | html = TRUE, 393 | cell = JS(" 394 | function(cellInfo) { 395 | var url = cellInfo.row['url'] 396 | return url ? 397 | '' + cellInfo.value + '' : 398 | cellInfo.value 399 | } 400 | ") 401 | ), 402 | info = colDef( 403 | name = "", 404 | html = TRUE, 405 | minWidth = 60, 406 | sortable = FALSE, 407 | class = "cell-info-button", 408 | cell = function(value) { 409 | if (!isTruthy(value)) return() 410 | tags$button( 411 | class = "btn btn-light btn-talk-more-info", 412 | `data-value` = value, 413 | title = "More info...", 414 | icon("info") 415 | ) 416 | }, 417 | style = list( 418 | position = "sticky", 419 | left = 30, 420 | background = "#fff", 421 | zIndex = 1, 422 | borderRight = "2px solid #eee" 423 | ), 424 | headerStyle = list( 425 | position = "sticky", 426 | left = 30, 427 | background = "#fff", 428 | zIndex = 1, 429 | borderRight = "2px solid #eee" 430 | ) 431 | ), 432 | .selection = colDef( 433 | width = 30, 434 | style = list( 435 | cursor = "pointer", 436 | position = "sticky", 437 | left = 0, 438 | background = "#fff", 439 | zIndex = 1 440 | ), 441 | headerStyle = list( 442 | cursor = "pointer", 443 | position = "sticky", 444 | left = 0, 445 | background = "#fff", 446 | zIndex = 1 447 | ) 448 | ) 449 | ) 450 | ) 451 | }) 452 | 453 | observeEvent(input$talk_more_info, { 454 | talk <- schedule[!is.na(schedule$talk_id) & schedule$talk_id == as.numeric(input$talk_more_info), ] 455 | req(nrow(talk)) 456 | 457 | speaker_names <- strsplit(talk$name[[1]], ", ")[[1]] 458 | speaker_bios <- strsplit(talk$bio_html[[1]], "\n

\n

")[[1]] 459 | if (length(speaker_bios) == 2) { 460 | speaker_bios[1] <- paste0(speaker_bios[1], "

") 461 | speaker_bios[2] <- paste0("

", speaker_bios[2]) 462 | } 463 | 464 | 465 | html_speaker_bio <- function(idx) { 466 | spkr_name <- speaker_names[idx] 467 | spkr_bio <- speaker_bios[idx] 468 | spkr_img <- tolower(gsub("[ '-]", "", spkr_name)) 469 | spkr_img <- if (file.exists(file.path("www", "speakers", paste0(spkr_img, ".png")))) { 470 | file.path("speakers", paste0(spkr_img, ".png")) 471 | } else if (file.exists(file.path("www", "speakers", paste0(spkr_img, ".jpg")))) { 472 | file.path("speakers", paste0(spkr_img, ".jpg")) 473 | } 474 | tagList( 475 | h2(spkr_name), 476 | if (!is.null(spkr_img)) { 477 | div( 478 | class = "row", 479 | div( 480 | class = "col-sm-3 order-1 order-sm-2", 481 | tags$img( 482 | src = spkr_img, 483 | style = "max-width: 100%", 484 | class = "rounded-lg" 485 | ) 486 | ), 487 | div( 488 | class = "col-sm-9 order-2 order-sm-1", 489 | HTML(spkr_bio) 490 | ) 491 | ) 492 | } else HTML(spkr_bio) 493 | ) 494 | } 495 | 496 | showModal( 497 | modalDialog( 498 | size = "l", 499 | easyClose = TRUE, 500 | title = talk$title_text[[1]], 501 | h2("Abstract"), 502 | HTML(talk$abstract_html[[1]]), 503 | lapply(seq_along(speaker_names), html_speaker_bio), 504 | footer = list( 505 | tags$a( 506 | href = talk$url[[1]], 507 | class = "btn btn-success", 508 | target = "_blank", 509 | "Go To Talk Page" 510 | ), 511 | modalButton("OK") 512 | ) 513 | ) 514 | ) 515 | }) 516 | 517 | observeEvent(input$browser_tz, { 518 | if (input$browser_tz %in% OlsonNames()) { 519 | updateSelectInput(session, "tz", selected = input$browser_tz) 520 | } 521 | }) 522 | } 523 | 524 | shinyApp(ui = ui, server = server) 525 | -------------------------------------------------------------------------------- /renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.0.3", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cran.rstudio.com" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "BH": { 13 | "Package": "BH", 14 | "Version": "1.75.0-0", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Hash": "e4c04affc2cac20c8fec18385cd14691" 18 | }, 19 | "R6": { 20 | "Package": "R6", 21 | "Version": "2.5.0", 22 | "Source": "Repository", 23 | "Repository": "CRAN", 24 | "Hash": "b203113193e70978a696b2809525649d" 25 | }, 26 | "Rcpp": { 27 | "Package": "Rcpp", 28 | "Version": "1.0.6", 29 | "Source": "Repository", 30 | "Repository": "CRAN", 31 | "Hash": "dbb5e436998a7eba5a9d682060533338" 32 | }, 33 | "askpass": { 34 | "Package": "askpass", 35 | "Version": "1.1", 36 | "Source": "Repository", 37 | "Repository": "CRAN", 38 | "Hash": "e8a22846fff485f0be3770c2da758713" 39 | }, 40 | "assertthat": { 41 | "Package": "assertthat", 42 | "Version": "0.2.1", 43 | "Source": "Repository", 44 | "Repository": "CRAN", 45 | "Hash": "50c838a310445e954bc13f26f26a6ecf" 46 | }, 47 | "base64enc": { 48 | "Package": "base64enc", 49 | "Version": "0.1-3", 50 | "Source": "Repository", 51 | "Repository": "CRAN", 52 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 53 | }, 54 | "bslib": { 55 | "Package": "bslib", 56 | "Version": "0.2.3.9000", 57 | "Source": "GitHub", 58 | "Remotes": "rstudio/thematic, rstudio/promises, rstudio/sass,\nrstudio/htmltools, rstudio/shiny", 59 | "RemoteType": "github", 60 | "RemoteHost": "api.github.com", 61 | "RemoteRepo": "bslib", 62 | "RemoteUsername": "rstudio", 63 | "RemoteRef": "HEAD", 64 | "RemoteSha": "80a5059bcef0bec16c9d914b6458f70077d2707b", 65 | "Hash": "54a2f34c3cee722bdb0ec2652a527ce0" 66 | }, 67 | "cachem": { 68 | "Package": "cachem", 69 | "Version": "1.0.0", 70 | "Source": "GitHub", 71 | "RemoteType": "github", 72 | "RemoteHost": "api.github.com", 73 | "RemoteUsername": "r-lib", 74 | "RemoteRepo": "cachem", 75 | "RemoteRef": "master", 76 | "RemoteSha": "ed5936ca6d112ea5d7543fa3a9eef8bd96cd31f3", 77 | "Hash": "07b33ada6d6193919d535ed6079163f2" 78 | }, 79 | "calendar": { 80 | "Package": "calendar", 81 | "Version": "0.0.1", 82 | "Source": "Repository", 83 | "Repository": "CRAN", 84 | "Hash": "ab478f470a5203ff9990e42d916005b0" 85 | }, 86 | "cli": { 87 | "Package": "cli", 88 | "Version": "2.2.0", 89 | "Source": "Repository", 90 | "Repository": "CRAN", 91 | "Hash": "3ef298932294b775fa0a3eeaa3a645b0" 92 | }, 93 | "clipr": { 94 | "Package": "clipr", 95 | "Version": "0.7.1", 96 | "Source": "Repository", 97 | "Repository": "CRAN", 98 | "Hash": "ebaa97ac99cc2daf04e77eecc7b781d7" 99 | }, 100 | "commonmark": { 101 | "Package": "commonmark", 102 | "Version": "1.7", 103 | "Source": "Repository", 104 | "Repository": "CRAN", 105 | "Hash": "0f22be39ec1d141fd03683c06f3a6e67" 106 | }, 107 | "cpp11": { 108 | "Package": "cpp11", 109 | "Version": "0.2.5", 110 | "Source": "Repository", 111 | "Repository": "CRAN", 112 | "Hash": "8b9a10255e862eb99e38fa8b0caa6c0d" 113 | }, 114 | "crayon": { 115 | "Package": "crayon", 116 | "Version": "1.3.4", 117 | "Source": "Repository", 118 | "Repository": "CRAN", 119 | "Hash": "0d57bc8e27b7ba9e45dba825ebc0de6b" 120 | }, 121 | "curl": { 122 | "Package": "curl", 123 | "Version": "4.3", 124 | "Source": "Repository", 125 | "Repository": "CRAN", 126 | "Hash": "2b7d10581cc730804e9ed178c8374bd6" 127 | }, 128 | "digest": { 129 | "Package": "digest", 130 | "Version": "0.6.27", 131 | "Source": "Repository", 132 | "Repository": "CRAN", 133 | "Hash": "a0cbe758a531d054b537d16dff4d58a1" 134 | }, 135 | "ellipsis": { 136 | "Package": "ellipsis", 137 | "Version": "0.3.1", 138 | "Source": "Repository", 139 | "Repository": "CRAN", 140 | "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" 141 | }, 142 | "fansi": { 143 | "Package": "fansi", 144 | "Version": "0.4.2", 145 | "Source": "Repository", 146 | "Repository": "CRAN", 147 | "Hash": "fea074fb67fe4c25d47ad09087da847d" 148 | }, 149 | "fastmap": { 150 | "Package": "fastmap", 151 | "Version": "1.0.1", 152 | "Source": "Repository", 153 | "Repository": "CRAN", 154 | "Hash": "83ab58a0518afe3d17e41da01af13b60" 155 | }, 156 | "fs": { 157 | "Package": "fs", 158 | "Version": "1.5.0", 159 | "Source": "Repository", 160 | "Repository": "CRAN", 161 | "Hash": "44594a07a42e5f91fac9f93fda6d0109" 162 | }, 163 | "generics": { 164 | "Package": "generics", 165 | "Version": "0.1.0", 166 | "Source": "Repository", 167 | "Repository": "CRAN", 168 | "Hash": "4d243a9c10b00589889fe32314ffd902" 169 | }, 170 | "glue": { 171 | "Package": "glue", 172 | "Version": "1.4.2", 173 | "Source": "Repository", 174 | "Repository": "CRAN", 175 | "Hash": "6efd734b14c6471cfe443345f3e35e29" 176 | }, 177 | "hms": { 178 | "Package": "hms", 179 | "Version": "1.0.0", 180 | "Source": "Repository", 181 | "Repository": "CRAN", 182 | "Hash": "bf552cdd96f5969873afdac7311c7d0d" 183 | }, 184 | "htmltools": { 185 | "Package": "htmltools", 186 | "Version": "0.5.1.9000", 187 | "Source": "GitHub", 188 | "RemoteType": "github", 189 | "RemoteHost": "api.github.com", 190 | "RemoteRepo": "htmltools", 191 | "RemoteUsername": "rstudio", 192 | "RemoteRef": "HEAD", 193 | "RemoteSha": "11cfbf3b331387922c0144203cf6e947c8bdaee9", 194 | "Hash": "f316455d3f68c407b48fe5e01861257a" 195 | }, 196 | "htmlwidgets": { 197 | "Package": "htmlwidgets", 198 | "Version": "1.5.3", 199 | "Source": "Repository", 200 | "Repository": "CRAN", 201 | "Hash": "6fdaa86d0700f8b3e92ee3c445a5a10d" 202 | }, 203 | "httpuv": { 204 | "Package": "httpuv", 205 | "Version": "1.5.5", 206 | "Source": "Repository", 207 | "Repository": "CRAN", 208 | "Hash": "b9d5d39be2150cf86538b8488334b8f8" 209 | }, 210 | "jquerylib": { 211 | "Package": "jquerylib", 212 | "Version": "0.1.3", 213 | "Source": "Repository", 214 | "Repository": "CRAN", 215 | "Hash": "5ff50b36f7f0832f8421745af333e73c" 216 | }, 217 | "jsonlite": { 218 | "Package": "jsonlite", 219 | "Version": "1.7.2", 220 | "Source": "Repository", 221 | "Repository": "CRAN", 222 | "Hash": "98138e0994d41508c7a6b84a0600cfcb" 223 | }, 224 | "later": { 225 | "Package": "later", 226 | "Version": "1.1.0.1", 227 | "Source": "Repository", 228 | "Repository": "CRAN", 229 | "Hash": "d0a62b247165aabf397fded504660d8a" 230 | }, 231 | "lifecycle": { 232 | "Package": "lifecycle", 233 | "Version": "0.2.0", 234 | "Source": "Repository", 235 | "Repository": "CRAN", 236 | "Hash": "361811f31f71f8a617a9a68bf63f1f42" 237 | }, 238 | "lubridate": { 239 | "Package": "lubridate", 240 | "Version": "1.7.9.2", 241 | "Source": "Repository", 242 | "Repository": "CRAN", 243 | "Hash": "5b5b02f621d39a499def7923a5aee746" 244 | }, 245 | "magrittr": { 246 | "Package": "magrittr", 247 | "Version": "2.0.1", 248 | "Source": "Repository", 249 | "Repository": "CRAN", 250 | "Hash": "41287f1ac7d28a92f0a286ed507928d3" 251 | }, 252 | "mime": { 253 | "Package": "mime", 254 | "Version": "0.9", 255 | "Source": "Repository", 256 | "Repository": "CRAN", 257 | "Hash": "e87a35ec73b157552814869f45a63aa3" 258 | }, 259 | "openssl": { 260 | "Package": "openssl", 261 | "Version": "1.4.3", 262 | "Source": "Repository", 263 | "Repository": "CRAN", 264 | "Hash": "a399e4773075fc2375b71f45fca186c4" 265 | }, 266 | "packrat": { 267 | "Package": "packrat", 268 | "Version": "0.5.0", 269 | "Source": "Repository", 270 | "Repository": "CRAN", 271 | "Hash": "2ebd34a38f4248281096cc723535b66d" 272 | }, 273 | "pillar": { 274 | "Package": "pillar", 275 | "Version": "1.4.7", 276 | "Source": "Repository", 277 | "Repository": "CRAN", 278 | "Hash": "3b3dd89b2ee115a8b54e93a34cd546b4" 279 | }, 280 | "pkgconfig": { 281 | "Package": "pkgconfig", 282 | "Version": "2.0.3", 283 | "Source": "Repository", 284 | "Repository": "CRAN", 285 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 286 | }, 287 | "prettyunits": { 288 | "Package": "prettyunits", 289 | "Version": "1.1.1", 290 | "Source": "Repository", 291 | "Repository": "CRAN", 292 | "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" 293 | }, 294 | "promises": { 295 | "Package": "promises", 296 | "Version": "1.1.1", 297 | "Source": "Repository", 298 | "Repository": "CRAN", 299 | "Hash": "a8730dcbdd19f9047774909f0ec214a4" 300 | }, 301 | "rappdirs": { 302 | "Package": "rappdirs", 303 | "Version": "0.3.1", 304 | "Source": "Repository", 305 | "Repository": "CRAN", 306 | "Hash": "8c8298583adbbe76f3c2220eef71bebc" 307 | }, 308 | "reactR": { 309 | "Package": "reactR", 310 | "Version": "0.4.3", 311 | "Source": "Repository", 312 | "Repository": "CRAN", 313 | "Hash": "85d50afbf95bf92bda97e9417575e8ff" 314 | }, 315 | "reactable": { 316 | "Package": "reactable", 317 | "Version": "0.2.3", 318 | "Source": "Repository", 319 | "Repository": "CRAN", 320 | "Hash": "ac1afe50d1c77470a72971a07fd146b1" 321 | }, 322 | "readr": { 323 | "Package": "readr", 324 | "Version": "1.4.0", 325 | "Source": "Repository", 326 | "Repository": "CRAN", 327 | "Hash": "2639976851f71f330264a9c9c3d43a61" 328 | }, 329 | "renv": { 330 | "Package": "renv", 331 | "Version": "0.12.3", 332 | "Source": "Repository", 333 | "Repository": "CRAN", 334 | "Hash": "b5510c50c7f31d453c385c7b460af2b9" 335 | }, 336 | "rlang": { 337 | "Package": "rlang", 338 | "Version": "0.4.10", 339 | "Source": "Repository", 340 | "Repository": "CRAN", 341 | "Hash": "599df23c40a4fce9c7b4764f28c37857" 342 | }, 343 | "rsconnect": { 344 | "Package": "rsconnect", 345 | "Version": "0.8.16", 346 | "Source": "Repository", 347 | "Repository": "CRAN", 348 | "Hash": "3924a1c20ce2479e89a08b0ca4c936c6" 349 | }, 350 | "rstudioapi": { 351 | "Package": "rstudioapi", 352 | "Version": "0.13", 353 | "Source": "Repository", 354 | "Repository": "CRAN", 355 | "Hash": "06c85365a03fdaf699966cc1d3cf53ea" 356 | }, 357 | "sass": { 358 | "Package": "sass", 359 | "Version": "0.3.0.9000", 360 | "Source": "GitHub", 361 | "RemoteType": "github", 362 | "RemoteHost": "api.github.com", 363 | "RemoteRepo": "sass", 364 | "RemoteUsername": "rstudio", 365 | "RemoteRef": "HEAD", 366 | "RemoteSha": "d85403dcf8da07f7564b08b0a7ca0934af541687", 367 | "Hash": "0df249c030129899f264b08cde3500de" 368 | }, 369 | "shiny": { 370 | "Package": "shiny", 371 | "Version": "1.5.0.9007", 372 | "Source": "GitHub", 373 | "Remotes": "rstudio/htmltools, rstudio/sass, rstudio/bslib,\nrstudio/shinytest, r-lib/cachem", 374 | "RemoteType": "github", 375 | "RemoteHost": "api.github.com", 376 | "RemoteRepo": "shiny", 377 | "RemoteUsername": "rstudio", 378 | "RemoteRef": "HEAD", 379 | "RemoteSha": "036f923e05b7da06a107cf5943edb40fcb377c79", 380 | "Hash": "8a77c4536ac9edbebcdf74c154f5deb1" 381 | }, 382 | "sourcetools": { 383 | "Package": "sourcetools", 384 | "Version": "0.1.7", 385 | "Source": "Repository", 386 | "Repository": "CRAN", 387 | "Hash": "947e4e02a79effa5d512473e10f41797" 388 | }, 389 | "sys": { 390 | "Package": "sys", 391 | "Version": "3.4", 392 | "Source": "Repository", 393 | "Repository": "CRAN", 394 | "Hash": "b227d13e29222b4574486cfcbde077fa" 395 | }, 396 | "tibble": { 397 | "Package": "tibble", 398 | "Version": "3.0.5", 399 | "Source": "Repository", 400 | "Repository": "CRAN", 401 | "Hash": "a1958587eb651a02273d685fff3819b1" 402 | }, 403 | "utf8": { 404 | "Package": "utf8", 405 | "Version": "1.1.4", 406 | "Source": "Repository", 407 | "Repository": "CRAN", 408 | "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" 409 | }, 410 | "vctrs": { 411 | "Package": "vctrs", 412 | "Version": "0.3.6", 413 | "Source": "Repository", 414 | "Repository": "CRAN", 415 | "Hash": "5cf1957f93076c19fdc81d01409d240b" 416 | }, 417 | "withr": { 418 | "Package": "withr", 419 | "Version": "2.4.0", 420 | "Source": "Repository", 421 | "Repository": "CRAN", 422 | "Hash": "8e07f30a26bc288326edcfe14883fbac" 423 | }, 424 | "xtable": { 425 | "Package": "xtable", 426 | "Version": "1.8-4", 427 | "Source": "Repository", 428 | "Repository": "CRAN", 429 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 430 | }, 431 | "yaml": { 432 | "Package": "yaml", 433 | "Version": "2.2.1", 434 | "Source": "Repository", 435 | "Repository": "CRAN", 436 | "Hash": "2826c5d9efb0a88f657c7a679c7106db" 437 | } 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | lock/ 3 | python/ 4 | staging/ 5 | -------------------------------------------------------------------------------- /renv/activate.R: -------------------------------------------------------------------------------- 1 | 2 | local({ 3 | 4 | # the requested version of renv 5 | version <- "0.12.3" 6 | 7 | # the project directory 8 | project <- getwd() 9 | 10 | # avoid recursion 11 | if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) 12 | return(invisible(TRUE)) 13 | 14 | # signal that we're loading renv during R startup 15 | Sys.setenv("RENV_R_INITIALIZING" = "true") 16 | on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) 17 | 18 | # signal that we've consented to use renv 19 | options(renv.consent = TRUE) 20 | 21 | # load the 'utils' package eagerly -- this ensures that renv shims, which 22 | # mask 'utils' packages, will come first on the search path 23 | library(utils, lib.loc = .Library) 24 | 25 | # check to see if renv has already been loaded 26 | if ("renv" %in% loadedNamespaces()) { 27 | 28 | # if renv has already been loaded, and it's the requested version of renv, 29 | # nothing to do 30 | spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") 31 | if (identical(spec[["version"]], version)) 32 | return(invisible(TRUE)) 33 | 34 | # otherwise, unload and attempt to load the correct version of renv 35 | unloadNamespace("renv") 36 | 37 | } 38 | 39 | # load bootstrap tools 40 | bootstrap <- function(version, library) { 41 | 42 | # read repos (respecting override if set) 43 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) 44 | if (is.na(repos)) 45 | repos <- getOption("repos") 46 | 47 | # fix up repos 48 | on.exit(options(repos = repos), add = TRUE) 49 | repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" 50 | options(repos = repos) 51 | 52 | # attempt to download renv 53 | tarball <- tryCatch(renv_bootstrap_download(version), error = identity) 54 | if (inherits(tarball, "error")) 55 | stop("failed to download renv ", version) 56 | 57 | # now attempt to install 58 | status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) 59 | if (inherits(status, "error")) 60 | stop("failed to install renv ", version) 61 | 62 | } 63 | 64 | renv_bootstrap_download_impl <- function(url, destfile) { 65 | 66 | mode <- "wb" 67 | 68 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 69 | fixup <- 70 | Sys.info()[["sysname"]] == "Windows" && 71 | substring(url, 1L, 5L) == "file:" 72 | 73 | if (fixup) 74 | mode <- "w+b" 75 | 76 | download.file( 77 | url = url, 78 | destfile = destfile, 79 | mode = mode, 80 | quiet = TRUE 81 | ) 82 | 83 | } 84 | 85 | renv_bootstrap_download <- function(version) { 86 | 87 | # if the renv version number has 4 components, assume it must 88 | # be retrieved via github 89 | nv <- numeric_version(version) 90 | components <- unclass(nv)[[1]] 91 | 92 | methods <- if (length(components) == 4L) { 93 | list(renv_bootstrap_download_github) 94 | } else { 95 | list( 96 | renv_bootstrap_download_cran_latest, 97 | renv_bootstrap_download_cran_archive 98 | ) 99 | } 100 | 101 | for (method in methods) { 102 | path <- tryCatch(method(version), error = identity) 103 | if (is.character(path) && file.exists(path)) 104 | return(path) 105 | } 106 | 107 | stop("failed to download renv ", version) 108 | 109 | } 110 | 111 | renv_bootstrap_download_cran_latest <- function(version) { 112 | 113 | repos <- renv_bootstrap_download_cran_latest_find(version) 114 | 115 | message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE) 116 | 117 | info <- tryCatch( 118 | download.packages("renv", repos = repos, destdir = tempdir(), quiet = TRUE), 119 | condition = identity 120 | ) 121 | 122 | if (inherits(info, "condition")) { 123 | message("FAILED") 124 | return(FALSE) 125 | } 126 | 127 | message("OK") 128 | info[1, 2] 129 | 130 | } 131 | 132 | renv_bootstrap_download_cran_latest_find <- function(version) { 133 | 134 | # check for renv on CRAN matching this version 135 | all <- unique(c( 136 | getOption("repos"), 137 | getOption("renv.bootstrap.repos", default = "https://cloud.r-project.org") 138 | )) 139 | 140 | for (repos in all) { 141 | 142 | db <- tryCatch( 143 | as.data.frame(available.packages(repos = repos), stringsAsFactors = FALSE), 144 | error = identity 145 | ) 146 | 147 | if (inherits(db, "error")) 148 | next 149 | 150 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ] 151 | if (nrow(entry) == 0) 152 | next 153 | 154 | return(repos) 155 | 156 | } 157 | 158 | fmt <- "renv %s is not available from your declared package repositories" 159 | stop(sprintf(fmt, version)) 160 | 161 | } 162 | 163 | renv_bootstrap_download_cran_archive <- function(version) { 164 | 165 | name <- sprintf("renv_%s.tar.gz", version) 166 | repos <- getOption("repos") 167 | urls <- file.path(repos, "src/contrib/Archive/renv", name) 168 | destfile <- file.path(tempdir(), name) 169 | 170 | message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE) 171 | 172 | for (url in urls) { 173 | 174 | status <- tryCatch( 175 | renv_bootstrap_download_impl(url, destfile), 176 | condition = identity 177 | ) 178 | 179 | if (identical(status, 0L)) { 180 | message("OK") 181 | return(destfile) 182 | } 183 | 184 | } 185 | 186 | message("FAILED") 187 | return(FALSE) 188 | 189 | } 190 | 191 | renv_bootstrap_download_github <- function(version) { 192 | 193 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") 194 | if (!identical(enabled, "TRUE")) 195 | return(FALSE) 196 | 197 | # prepare download options 198 | pat <- Sys.getenv("GITHUB_PAT") 199 | if (nzchar(Sys.which("curl")) && nzchar(pat)) { 200 | fmt <- "--location --fail --header \"Authorization: token %s\"" 201 | extra <- sprintf(fmt, pat) 202 | saved <- options("download.file.method", "download.file.extra") 203 | options(download.file.method = "curl", download.file.extra = extra) 204 | on.exit(do.call(base::options, saved), add = TRUE) 205 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { 206 | fmt <- "--header=\"Authorization: token %s\"" 207 | extra <- sprintf(fmt, pat) 208 | saved <- options("download.file.method", "download.file.extra") 209 | options(download.file.method = "wget", download.file.extra = extra) 210 | on.exit(do.call(base::options, saved), add = TRUE) 211 | } 212 | 213 | message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) 214 | 215 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) 216 | name <- sprintf("renv_%s.tar.gz", version) 217 | destfile <- file.path(tempdir(), name) 218 | 219 | status <- tryCatch( 220 | renv_bootstrap_download_impl(url, destfile), 221 | condition = identity 222 | ) 223 | 224 | if (!identical(status, 0L)) { 225 | message("FAILED") 226 | return(FALSE) 227 | } 228 | 229 | message("Done!") 230 | return(destfile) 231 | 232 | } 233 | 234 | renv_bootstrap_install <- function(version, tarball, library) { 235 | 236 | # attempt to install it into project library 237 | message("* Installing renv ", version, " ... ", appendLF = FALSE) 238 | dir.create(library, showWarnings = FALSE, recursive = TRUE) 239 | 240 | # invoke using system2 so we can capture and report output 241 | bin <- R.home("bin") 242 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" 243 | r <- file.path(bin, exe) 244 | args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball)) 245 | output <- system2(r, args, stdout = TRUE, stderr = TRUE) 246 | message("Done!") 247 | 248 | # check for successful install 249 | status <- attr(output, "status") 250 | if (is.numeric(status) && !identical(status, 0L)) { 251 | header <- "Error installing renv:" 252 | lines <- paste(rep.int("=", nchar(header)), collapse = "") 253 | text <- c(header, lines, output) 254 | writeLines(text, con = stderr()) 255 | } 256 | 257 | status 258 | 259 | } 260 | 261 | renv_bootstrap_prefix <- function() { 262 | 263 | # construct version prefix 264 | version <- paste(R.version$major, R.version$minor, sep = ".") 265 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") 266 | 267 | # include SVN revision for development versions of R 268 | # (to avoid sharing platform-specific artefacts with released versions of R) 269 | devel <- 270 | identical(R.version[["status"]], "Under development (unstable)") || 271 | identical(R.version[["nickname"]], "Unsuffered Consequences") 272 | 273 | if (devel) 274 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") 275 | 276 | # build list of path components 277 | components <- c(prefix, R.version$platform) 278 | 279 | # include prefix if provided by user 280 | prefix <- Sys.getenv("RENV_PATHS_PREFIX") 281 | if (nzchar(prefix)) 282 | components <- c(prefix, components) 283 | 284 | # build prefix 285 | paste(components, collapse = "/") 286 | 287 | } 288 | 289 | renv_bootstrap_library_root <- function(project) { 290 | 291 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) 292 | if (!is.na(path)) 293 | return(path) 294 | 295 | path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) 296 | if (!is.na(path)) { 297 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) 298 | name <- paste(basename(project), id, sep = "-") 299 | return(file.path(path, name)) 300 | } 301 | 302 | file.path(project, "renv/library") 303 | 304 | } 305 | 306 | renv_bootstrap_validate_version <- function(version) { 307 | 308 | loadedversion <- utils::packageDescription("renv", fields = "Version") 309 | if (version == loadedversion) 310 | return(TRUE) 311 | 312 | # assume four-component versions are from GitHub; three-component 313 | # versions are from CRAN 314 | components <- strsplit(loadedversion, "[.-]")[[1]] 315 | remote <- if (length(components) == 4L) 316 | paste("rstudio/renv", loadedversion, sep = "@") 317 | else 318 | paste("renv", loadedversion, sep = "@") 319 | 320 | fmt <- paste( 321 | "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", 322 | "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", 323 | "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", 324 | sep = "\n" 325 | ) 326 | 327 | msg <- sprintf(fmt, loadedversion, version, remote) 328 | warning(msg, call. = FALSE) 329 | 330 | FALSE 331 | 332 | } 333 | 334 | renv_bootstrap_hash_text <- function(text) { 335 | 336 | hashfile <- tempfile("renv-hash-") 337 | on.exit(unlink(hashfile), add = TRUE) 338 | 339 | writeLines(text, con = hashfile) 340 | tools::md5sum(hashfile) 341 | 342 | } 343 | 344 | renv_bootstrap_load <- function(project, libpath, version) { 345 | 346 | # try to load renv from the project library 347 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) 348 | return(FALSE) 349 | 350 | # warn if the version of renv loaded does not match 351 | renv_bootstrap_validate_version(version) 352 | 353 | # load the project 354 | renv::load(project) 355 | 356 | TRUE 357 | 358 | } 359 | 360 | # construct path to library root 361 | root <- renv_bootstrap_library_root(project) 362 | 363 | # construct library prefix for platform 364 | prefix <- renv_bootstrap_prefix() 365 | 366 | # construct full libpath 367 | libpath <- file.path(root, prefix) 368 | 369 | # attempt to load 370 | if (renv_bootstrap_load(project, libpath, version)) 371 | return(TRUE) 372 | 373 | # load failed; inform user we're about to bootstrap 374 | prefix <- paste("# Bootstrapping renv", version) 375 | postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") 376 | header <- paste(prefix, postfix) 377 | message(header) 378 | 379 | # perform bootstrap 380 | bootstrap(version, libpath) 381 | 382 | # exit early if we're just testing bootstrap 383 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) 384 | return(TRUE) 385 | 386 | # try again to load 387 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { 388 | message("* Successfully installed and loaded renv ", version, ".") 389 | return(renv::load()) 390 | } 391 | 392 | # failed to download or load renv; warn the user 393 | msg <- c( 394 | "Failed to find an renv installation: the project will not be loaded.", 395 | "Use `renv::activate()` to re-initialize the project." 396 | ) 397 | 398 | warning(paste(msg, collapse = "\n"), call. = FALSE) 399 | 400 | }) 401 | -------------------------------------------------------------------------------- /renv/settings.dcf: -------------------------------------------------------------------------------- 1 | external.libraries: 2 | ignored.packages: 3 | package.dependency.fields: Imports, Depends, LinkingTo 4 | r.version: 5 | snapshot.type: implicit 6 | use.cache: TRUE 7 | vcs.ignore.library: TRUE 8 | -------------------------------------------------------------------------------- /rstudio-global-calendar.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | -------------------------------------------------------------------------------- /www/extra.css: -------------------------------------------------------------------------------- 1 | .cell-info-button { 2 | padding: 0; 3 | } 4 | 5 | .cell-info-button > button { 6 | height: 100%; 7 | width: 100%; 8 | } 9 | 10 | .rt-select { 11 | height: 100%; 12 | } 13 | 14 | .screenreader-text { 15 | position: absolute; 16 | left: -999px; 17 | width:1px; 18 | height: 1px; 19 | top: auto; 20 | } 21 | 22 | .screenreader-text:focus { 23 | color: currentColor; 24 | display: inline-block; 25 | height: auto; 26 | width: auto; 27 | position: static; 28 | margin: auto; 29 | } 30 | -------------------------------------------------------------------------------- /www/extra.js: -------------------------------------------------------------------------------- 1 | $(document).on('click', '.btn-talk-more-info, .btn-talk-more-info i', function(ev) { 2 | Shiny.setInputValue('talk_more_info', ev.target.closest('.btn').dataset.value, {priority: 'event'}) 3 | }) 4 | 5 | $().ready(function() { 6 | document.querySelector('.navbar-brand').classList.add('text-monospace') 7 | }) 8 | 9 | $(document).on('shiny:sessioninitialized', function() { 10 | Shiny.setInputValue('browser_tz', Intl.DateTimeFormat().resolvedOptions().timeZone) 11 | }) 12 | -------------------------------------------------------------------------------- /www/speakers/aaronjacobs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/aaronjacobs.jpg -------------------------------------------------------------------------------- /www/speakers/ahmadoudicko.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/ahmadoudicko.jpg -------------------------------------------------------------------------------- /www/speakers/alanfeder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/alanfeder.jpg -------------------------------------------------------------------------------- /www/speakers/alexcookson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/alexcookson.png -------------------------------------------------------------------------------- /www/speakers/allisonhorst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/allisonhorst.png -------------------------------------------------------------------------------- /www/speakers/andrewtran.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/andrewtran.jpg -------------------------------------------------------------------------------- /www/speakers/athanasiamowinckel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/athanasiamowinckel.png -------------------------------------------------------------------------------- /www/speakers/barretschloerke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/barretschloerke.png -------------------------------------------------------------------------------- /www/speakers/carsonsievert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/carsonsievert.png -------------------------------------------------------------------------------- /www/speakers/chelseaparlettpelleriti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/chelseaparlettpelleriti.png -------------------------------------------------------------------------------- /www/speakers/daniellesmallsperkins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/daniellesmallsperkins.jpg -------------------------------------------------------------------------------- /www/speakers/deanmarchiori.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/deanmarchiori.jpg -------------------------------------------------------------------------------- /www/speakers/dorrisscott.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/dorrisscott.jpg -------------------------------------------------------------------------------- /www/speakers/emilyriederer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/emilyriederer.jpg -------------------------------------------------------------------------------- /www/speakers/ericgunnarcronstrom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/ericgunnarcronstrom.jpg -------------------------------------------------------------------------------- /www/speakers/garrickadenbuie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/garrickadenbuie.jpg -------------------------------------------------------------------------------- /www/speakers/grantfleming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/grantfleming.png -------------------------------------------------------------------------------- /www/speakers/hadleywickham.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/hadleywickham.jpg -------------------------------------------------------------------------------- /www/speakers/irenesteves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/irenesteves.jpg -------------------------------------------------------------------------------- /www/speakers/javierluraschi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/javierluraschi.jpg -------------------------------------------------------------------------------- /www/speakers/jeroenooms.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/jeroenooms.jpg -------------------------------------------------------------------------------- /www/speakers/johnburnmurdoch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/johnburnmurdoch.jpg -------------------------------------------------------------------------------- /www/speakers/jooyoungseo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/jooyoungseo.jpg -------------------------------------------------------------------------------- /www/speakers/karawoo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/karawoo.jpg -------------------------------------------------------------------------------- /www/speakers/katehertweck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/katehertweck.jpg -------------------------------------------------------------------------------- /www/speakers/lucydagostinomcgowan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/lucydagostinomcgowan.png -------------------------------------------------------------------------------- /www/speakers/malcolmbarrett.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/malcolmbarrett.jpg -------------------------------------------------------------------------------- /www/speakers/marcusadams.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/marcusadams.jpg -------------------------------------------------------------------------------- /www/speakers/marievendettuoli.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/marievendettuoli.jpg -------------------------------------------------------------------------------- /www/speakers/mattthomas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/mattthomas.jpg -------------------------------------------------------------------------------- /www/speakers/mayagans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/mayagans.jpg -------------------------------------------------------------------------------- /www/speakers/meganbeckett.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/meganbeckett.jpg -------------------------------------------------------------------------------- /www/speakers/michaelchirico.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/michaelchirico.jpg -------------------------------------------------------------------------------- /www/speakers/michaelchow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/michaelchow.jpg -------------------------------------------------------------------------------- /www/speakers/mikepage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/mikepage.jpg -------------------------------------------------------------------------------- /www/speakers/minecetinkayarundel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/minecetinkayarundel.jpg -------------------------------------------------------------------------------- /www/speakers/nealrichardson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/nealrichardson.jpg -------------------------------------------------------------------------------- /www/speakers/nicholaspylypiw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/nicholaspylypiw.jpg -------------------------------------------------------------------------------- /www/speakers/nicolekramer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/nicolekramer.jpg -------------------------------------------------------------------------------- /www/speakers/pamelapairo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/pamelapairo.jpg -------------------------------------------------------------------------------- /www/speakers/richardvogg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/richardvogg.jpg -------------------------------------------------------------------------------- /www/speakers/rivaquiroga.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/rivaquiroga.jpg -------------------------------------------------------------------------------- /www/speakers/seanlopp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/seanlopp.png -------------------------------------------------------------------------------- /www/speakers/shelmithkariuki.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/shelmithkariuki.png -------------------------------------------------------------------------------- /www/speakers/simoncouch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/simoncouch.jpg -------------------------------------------------------------------------------- /www/speakers/sophiebeiers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/sophiebeiers.jpg -------------------------------------------------------------------------------- /www/speakers/vickiboykis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/vickiboykis.jpg -------------------------------------------------------------------------------- /www/speakers/wolframking.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/wolframking.jpg -------------------------------------------------------------------------------- /www/speakers/yaninabellinisaibene.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/yaninabellinisaibene.jpg -------------------------------------------------------------------------------- /www/speakers/zj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gadenbuie/rstudio-global-2021-calendar/c6290d8f2fb45e49f8a33f36e019e80866e05075/www/speakers/zj.jpg --------------------------------------------------------------------------------