├── README.md ├── task1 └── README.md ├── task2 ├── .Rprofile ├── .lintr ├── .renvignore ├── .rscignore ├── IMAGES │ ├── apples.jpg │ ├── bananas.jpg │ ├── cherries.jpg │ ├── cucumbers.jpg │ ├── onions.jpg │ ├── potatoes.jpg │ └── tomatoes.jpg ├── README.md ├── app.R ├── app │ ├── js │ │ └── index.js │ ├── logic │ │ ├── __init__.R │ │ ├── const.R │ │ └── reverse.R │ ├── main.R │ ├── static │ │ └── favicon.ico │ ├── styles │ │ └── main.scss │ └── view │ │ ├── __init__.R │ │ ├── favorites.R │ │ ├── hello.R │ │ └── reverse.R ├── config.yml ├── dependencies.R ├── renv.lock ├── renv │ ├── .gitignore │ ├── activate.R │ └── settings.json ├── rhino.yml ├── task2.Rproj └── tests │ ├── cypress.config.js │ ├── cypress │ ├── .gitignore │ └── e2e │ │ └── app.cy.js │ └── testthat │ └── test-main.R ├── task3 ├── .Rprofile ├── .gitignore ├── .lintr ├── .renvignore ├── .rscignore ├── README.md ├── app.R ├── app │ ├── js │ │ └── index.js │ ├── logic │ │ ├── __init__.R │ │ ├── data.R │ │ └── db.R │ ├── main.R │ ├── static │ │ └── favicon.ico │ ├── styles │ │ └── main.scss │ └── view │ │ ├── __init__.R │ │ ├── filters.R │ │ └── table.R ├── config.yml ├── dependencies.R ├── dev.sqlite3 ├── renv.lock ├── renv │ ├── .gitignore │ ├── activate.R │ └── settings.json ├── rhino.yml ├── task3.Rproj └── tests │ ├── cypress.config.js │ ├── cypress │ ├── .gitignore │ └── e2e │ │ └── app.cy.js │ └── testthat │ └── test-main.R ├── task4 ├── .Rprofile ├── .lintr ├── .renvignore ├── .rscignore ├── README.md ├── app.R ├── app │ ├── js │ │ └── index.js │ ├── logic │ │ └── __init__.R │ ├── main.R │ ├── static │ │ └── favicon.ico │ ├── styles │ │ ├── _base.scss │ │ └── main.scss │ └── view │ │ └── __init__.R ├── config.yml ├── dependencies.R ├── renv.lock ├── renv │ ├── .gitignore │ ├── activate.R │ └── settings.json ├── rhino.yml ├── task4.Rproj └── tests │ ├── cypress.config.js │ ├── cypress │ ├── .gitignore │ └── e2e │ │ └── app.cy.js │ └── testthat │ └── test-main.R └── task5 ├── .Rprofile ├── .lintr ├── .renvignore ├── .rhino ├── .eslintrc.json ├── .gitignore ├── .stylelintrc.json ├── babel.config.json ├── package-lock.json ├── package.json └── webpack.config.js ├── .rscignore ├── README.md ├── app.R ├── app ├── js │ └── index.js ├── logic │ └── __init__.R ├── main.R ├── static │ └── favicon.ico ├── styles │ └── main.scss └── view │ └── __init__.R ├── config.yml ├── dependencies.R ├── renv.lock ├── renv ├── .gitignore ├── activate.R └── settings.json ├── rhino.yml ├── task5.Rproj └── tests ├── cypress.config.js ├── cypress ├── .gitignore └── e2e │ └── app.cy.js └── testthat └── test-main.R /README.md: -------------------------------------------------------------------------------- 1 | # Rhino Masterclass 2 | 3 | This repository contains all the tasks from the Rhino Masterclass workshop 4 | held during Appsilon ShinyConf 2024. 5 | 6 | Each task is described in a `README.md` file in its corresponding directory. 7 | You can lookup the solutions on branch 8 | [solved](https://github.com/Appsilon/rhino-masterclass/tree/solved). 9 | 10 | In task 1 you initialize your own Rhino app. 11 | The other tasks have Rhino apps already prepared for you with blanks to fill in. 12 | 13 | ### Tasks summary 14 | 15 | * [**Task 1:**](task1/README.md) Foundations, working with R. 16 | * [**Task 2:**](task2/README.md) Modules, static files. 17 | * [**Task 3:**](task3/README.md) Config, environments, using DB. 18 | * [**Task 4:**](task4/README.md) Styling with Sass. 19 | * [**Task 5:**](task5/README.md) End-to-end testing with Cypress. 20 | -------------------------------------------------------------------------------- /task1/README.md: -------------------------------------------------------------------------------- 1 | # Task 1 2 | 3 | ### Step 1 4 | 5 | Use [`rhino::init()`](https://appsilon.github.io/rhino/reference/init.html) 6 | to create a new Rhino app in `task1` directory. 7 | 8 | ### Step 2 9 | 10 | * Enable automatic reloading with 11 | [`shiny::devmode()`](https://shiny.posit.co/r/reference/shiny/latest/devmode.html). 12 | * Run the app with 13 | [`shiny::runApp()`](https://shiny.posit.co/r/reference/shiny/latest/runapp). 14 | * Edit the displayed message in `app/main.R` and see how the app automatically reloads. 15 | 16 | ### Step 3 17 | 18 | Copy over the following code to `main.R`: 19 | ```r 20 | box::use( 21 | shiny, 22 | shiny.fluent[...], 23 | ) 24 | 25 | #' @export 26 | ui = function(id) { 27 | ns <- shiny$NS(id) 28 | shiny$tagList( 29 | ColorPicker.shinyInput(ns("color"), value="#0000FF"), 30 | shiny$verbatimTextOutput(ns("text"))) 31 | } 32 | 33 | #' @export 34 | server <- function(id) { 35 | shiny$moduleServer(id, function(input, output, session) { 36 | output$text <- shiny$renderText({ 37 | paste("Color:", input$color) 38 | }) 39 | }) 40 | } 41 | ``` 42 | 43 | Install the missing dependencies with 44 | [`rhino::pkg_install()`](https://appsilon.github.io/rhino/reference/dependencies.html) 45 | and run the app. 46 | 47 | ### Step 4 48 | 49 | * Lint the project with 50 | [`rhino::lint_r()`](https://appsilon.github.io/rhino/reference/lint_r.html). 51 | * Format the code with 52 | [`rhino::format_r()`](https://appsilon.github.io/rhino/reference/format_r.html). 53 | * Lint the project again and fix remaining errors. 54 | 55 | ### Step 5 56 | 57 | Rename `main.R` to `app.R` and copy over the following code: 58 | ```r 59 | library(shiny) 60 | library(shiny.fluent) 61 | 62 | ui <- div( 63 | Calendar.shinyInput("date"), 64 | verbatimTextOutput("text"), 65 | ) 66 | 67 | server <- function(input, output, session) { 68 | output$text <- renderText({ 69 | paste("Date:", input$date) 70 | }) 71 | } 72 | 73 | shinyApp(ui = ui, server = server) 74 | ``` 75 | 76 | Set [`legacy_entrypoint: app_dir`](https://appsilon.github.io/rhino/reference/app.html#legacy-entrypoint) 77 | in `rhino.yml` and rerun the app. 78 | 79 | ### Step 6 80 | 81 | * Rename `app/app.R` back to `app/main.R`. 82 | * Remove the `shinyApp(ui = ui, server = server)` line. 83 | * Set `legacy_entrypoint: source` and rerun the app. 84 | 85 | ### Step 7 86 | 87 | * Replace `library()` calls with `box::use()`. 88 | * Set `legacy_entrypoint: box_top_level` and rerun the app. 89 | 90 | ### Step 8 91 | 92 | * Modify the `ui` and `server` to make them into a 93 | [Shiny module](https://shiny.posit.co/r/articles/improve/modules/). 94 | * Remove the `legacy_entrypoint` setting and rerun the app. 95 | -------------------------------------------------------------------------------- /task2/.Rprofile: -------------------------------------------------------------------------------- 1 | if (file.exists("renv")) { 2 | source("renv/activate.R") 3 | } else { 4 | # The `renv` directory is automatically skipped when deploying with rsconnect. 5 | message("No 'renv' directory found; renv won't be activated.") 6 | } 7 | 8 | # Allow absolute module imports (relative to the app root). 9 | options(box.path = getwd()) 10 | -------------------------------------------------------------------------------- /task2/.lintr: -------------------------------------------------------------------------------- 1 | linters: 2 | linters_with_defaults( 3 | line_length_linter = line_length_linter(100), 4 | box_func_import_count_linter = rhino::box_func_import_count_linter(), 5 | box_separate_calls_linter = rhino::box_separate_calls_linter(), 6 | box_trailing_commas_linter = rhino::box_trailing_commas_linter(), 7 | box_universal_import_linter = rhino::box_universal_import_linter(), 8 | object_usage_linter = NULL # Does not work with `box::use()`. 9 | ) 10 | -------------------------------------------------------------------------------- /task2/.renvignore: -------------------------------------------------------------------------------- 1 | # Only use `dependencies.R` to infer project dependencies. 2 | * 3 | !dependencies.R 4 | -------------------------------------------------------------------------------- /task2/.rscignore: -------------------------------------------------------------------------------- 1 | .github 2 | .lintr 3 | .renvignore 4 | .Renviron 5 | .rhino 6 | .rscignore 7 | tests 8 | -------------------------------------------------------------------------------- /task2/IMAGES/apples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/apples.jpg -------------------------------------------------------------------------------- /task2/IMAGES/bananas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/bananas.jpg -------------------------------------------------------------------------------- /task2/IMAGES/cherries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/cherries.jpg -------------------------------------------------------------------------------- /task2/IMAGES/cucumbers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/cucumbers.jpg -------------------------------------------------------------------------------- /task2/IMAGES/onions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/onions.jpg -------------------------------------------------------------------------------- /task2/IMAGES/potatoes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/potatoes.jpg -------------------------------------------------------------------------------- /task2/IMAGES/tomatoes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/IMAGES/tomatoes.jpg -------------------------------------------------------------------------------- /task2/README.md: -------------------------------------------------------------------------------- 1 | # Task 2 2 | 3 | ### Step 1 4 | 5 | * Use [`renv::restore()`](https://rstudio.github.io/renv/reference/restore.html) 6 | to install the necessary dependencies. 7 | * Enable devmode and run the app. 8 | 9 | ### Step 2 10 | 11 | * Take a look at `app/view/hello.R`. 12 | * Add `hello$ui(ns("hello"))` to the UI in `main.R`. 13 | * Call `hello$server("hello")` in the server in `main.R`. 14 | * See if the app displayes "Hello" text. 15 | 16 | **Remember:** 17 | In the UI, the ID must be wrapped in `ns()`, 18 | but in the server the namespace is applied automatically. 19 | Learn more in 20 | [Modularizing Shiny app code](https://shiny.posit.co/r/articles/improve/modules/) 21 | 22 | ### Step 3 23 | 24 | * Open `app/view/hello.R`. 25 | * Add a 26 | [`textInput`](https://shiny.posit.co/r/reference/shiny/latest/textinput) with label "What is your name?". 27 | * See if the input appears in the app. 28 | 29 | ### Step 4 30 | 31 | * Add a [`textOutput`](https://shiny.posit.co/r/reference/shiny/latest/textoutput) 32 | to the module UI. 33 | * Use [`renderText`](https://shiny.posit.co/r/reference/shiny/latest/renderprint) to greet the user with their name. 34 | * Type "Rhino" into the field and check if "Hello Rhino!" appears. 35 | 36 | ### Step 5 37 | 38 | * Import the `logic/const` and `view/favorites` modules in `main.R`. 39 | * Add the `favorites` module to the app. 40 | Use `category = "fruits"` and `choices = const$fruits`. 41 | 42 | ### Step 6 43 | 44 | Add another instance of the `favorites` module. 45 | Use `category = "vegetables"` and `choices = const$vegetables` this time. 46 | 47 | ### Step 7 48 | 49 | * Add a [`checkboxGroupInput`](https://shiny.posit.co/r/reference/shiny/latest/checkboxgroupinput) 50 | to the UI of the favorites module. 51 | * Use the module parameters to define `choices` and a nice `label`. 52 | 53 | ### Step 8 54 | 55 | * Copy over the files from `IMAGES` directory to `app/static/img`. 56 | * Fill in the missing part the in `images()` function. 57 | You need to translate image `name` to path with `/static/` prefix. 58 | * Use [`uiOutput()`](https://shiny.posit.co/r/reference/shiny/latest/htmloutput) 59 | and [`renderUI()`](https://shiny.posit.co/r/reference/shiny/latest/renderui) 60 | to render the `images()` based on user's selection. 61 | 62 | ### Step 9 63 | 64 | * Define the `app/view/reverse` module. 65 | It should let the user type some text 66 | and display it with words in reverse order. 67 | * Fill in and use the `reverse_words()` function from `app/logic/reverse`. 68 | * Add the module to the app. 69 | -------------------------------------------------------------------------------- /task2/app.R: -------------------------------------------------------------------------------- 1 | # Rhino / shinyApp entrypoint. Do not edit. 2 | rhino::app() 3 | -------------------------------------------------------------------------------- /task2/app/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/app/js/index.js -------------------------------------------------------------------------------- /task2/app/logic/__init__.R: -------------------------------------------------------------------------------- 1 | # Logic: application code independent from Shiny. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task2/app/logic/const.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | fruits <- c("apples", "bananas", "cherries") 3 | 4 | #' @export 5 | vegetables <- c("cucumbers", "onions", "potatoes", "tomatoes") 6 | -------------------------------------------------------------------------------- /task2/app/logic/reverse.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | reverse_words <- function(text) { 3 | # Step 9: 4 | # ? 5 | } 6 | -------------------------------------------------------------------------------- /task2/app/main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | box::use( 5 | # Step 5: 6 | # ? 7 | 8 | app/view/hello, 9 | 10 | # Step 9: 11 | # ? 12 | ) 13 | 14 | #' @export 15 | ui <- function(id) { 16 | ns <- shiny$NS(id) 17 | shiny$fluidPage( 18 | # Step 2: 19 | # ? 20 | 21 | # Step 5: 22 | # ? 23 | 24 | # Step 6: 25 | # ? 26 | 27 | # Step 9: 28 | # ? 29 | ) 30 | } 31 | 32 | #' @export 33 | server <- function(id) { 34 | shiny$moduleServer(id, function(input, output, session) { 35 | # Step 2: 36 | # ? 37 | 38 | # Step 5: 39 | # ? 40 | 41 | # Step 6: 42 | # ? 43 | 44 | # Step 9: 45 | # ? 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /task2/app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/app/static/favicon.ico -------------------------------------------------------------------------------- /task2/app/styles/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task2/app/styles/main.scss -------------------------------------------------------------------------------- /task2/app/view/__init__.R: -------------------------------------------------------------------------------- 1 | # View: Shiny modules and related code. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task2/app/view/favorites.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | 5 | images <- function(filenames) { 6 | lapply(filenames, function(name) { 7 | shiny$img( 8 | # Step 8: 9 | # src = ? 10 | ) 11 | }) 12 | } 13 | 14 | #' @export 15 | ui <- function(id, category, choices) { 16 | ns <- shiny$NS(id) 17 | shiny$div( 18 | shiny$h1(paste("Favorite", category)) 19 | 20 | # Step 7: 21 | # ? 22 | 23 | # Step 8: 24 | # ? 25 | ) 26 | } 27 | 28 | #' @export 29 | server <- function(id) { 30 | shiny$moduleServer(id, function(input, output, session) { 31 | # Step 8: 32 | # ? 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /task2/app/view/hello.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | 5 | #' @export 6 | ui <- function(id) { 7 | ns <- shiny$NS(id) 8 | shiny$div( 9 | shiny$h1("Hello") 10 | 11 | # Step 3: 12 | # ? 13 | 14 | # Step 4: 15 | # ? 16 | ) 17 | } 18 | 19 | #' @export 20 | server <- function(id) { 21 | shiny$moduleServer(id, function(input, output, session) { 22 | # Step 4: 23 | # ? 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /task2/app/view/reverse.R: -------------------------------------------------------------------------------- 1 | # Step 9: 2 | # ? 3 | -------------------------------------------------------------------------------- /task2/config.yml: -------------------------------------------------------------------------------- 1 | default: 2 | rhino_log_level: !expr Sys.getenv("RHINO_LOG_LEVEL", "INFO") 3 | rhino_log_file: !expr Sys.getenv("RHINO_LOG_FILE", NA) 4 | -------------------------------------------------------------------------------- /task2/dependencies.R: -------------------------------------------------------------------------------- 1 | # This file allows packrat (used by rsconnect during deployment) to pick up dependencies. 2 | library(rhino) 3 | -------------------------------------------------------------------------------- /task2/renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.1.2", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cloud.r-project.org" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "R.cache": { 13 | "Package": "R.cache", 14 | "Version": "0.16.0", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Requirements": [ 18 | "R", 19 | "R.methodsS3", 20 | "R.oo", 21 | "R.utils", 22 | "digest", 23 | "utils" 24 | ], 25 | "Hash": "fe539ca3f8efb7410c3ae2cf5fe6c0f8" 26 | }, 27 | "R.methodsS3": { 28 | "Package": "R.methodsS3", 29 | "Version": "1.8.2", 30 | "Source": "Repository", 31 | "Repository": "CRAN", 32 | "Requirements": [ 33 | "R", 34 | "utils" 35 | ], 36 | "Hash": "278c286fd6e9e75d0c2e8f731ea445c8" 37 | }, 38 | "R.oo": { 39 | "Package": "R.oo", 40 | "Version": "1.26.0", 41 | "Source": "Repository", 42 | "Repository": "CRAN", 43 | "Requirements": [ 44 | "R", 45 | "R.methodsS3", 46 | "methods", 47 | "utils" 48 | ], 49 | "Hash": "4fed809e53ddb5407b3da3d0f572e591" 50 | }, 51 | "R.utils": { 52 | "Package": "R.utils", 53 | "Version": "2.12.3", 54 | "Source": "Repository", 55 | "Repository": "CRAN", 56 | "Requirements": [ 57 | "R", 58 | "R.methodsS3", 59 | "R.oo", 60 | "methods", 61 | "tools", 62 | "utils" 63 | ], 64 | "Hash": "3dc2829b790254bfba21e60965787651" 65 | }, 66 | "R6": { 67 | "Package": "R6", 68 | "Version": "2.5.1", 69 | "Source": "Repository", 70 | "Repository": "CRAN", 71 | "Requirements": [ 72 | "R" 73 | ], 74 | "Hash": "470851b6d5d0ac559e9d01bb352b4021" 75 | }, 76 | "Rcpp": { 77 | "Package": "Rcpp", 78 | "Version": "1.0.12", 79 | "Source": "Repository", 80 | "Repository": "CRAN", 81 | "Requirements": [ 82 | "methods", 83 | "utils" 84 | ], 85 | "Hash": "5ea2700d21e038ace58269ecdbeb9ec0" 86 | }, 87 | "backports": { 88 | "Package": "backports", 89 | "Version": "1.4.1", 90 | "Source": "Repository", 91 | "Repository": "CRAN", 92 | "Requirements": [ 93 | "R" 94 | ], 95 | "Hash": "c39fbec8a30d23e721980b8afb31984c" 96 | }, 97 | "base64enc": { 98 | "Package": "base64enc", 99 | "Version": "0.1-3", 100 | "Source": "Repository", 101 | "Repository": "CRAN", 102 | "Requirements": [ 103 | "R" 104 | ], 105 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 106 | }, 107 | "box": { 108 | "Package": "box", 109 | "Version": "1.2.0", 110 | "Source": "Repository", 111 | "Repository": "CRAN", 112 | "Requirements": [ 113 | "R", 114 | "tools" 115 | ], 116 | "Hash": "d94049c1d9446b0abb413fde9e82a505" 117 | }, 118 | "brio": { 119 | "Package": "brio", 120 | "Version": "1.1.4", 121 | "Source": "Repository", 122 | "Repository": "CRAN", 123 | "Requirements": [ 124 | "R" 125 | ], 126 | "Hash": "68bd2b066e1fe780bbf62fc8bcc36de3" 127 | }, 128 | "bslib": { 129 | "Package": "bslib", 130 | "Version": "0.7.0", 131 | "Source": "Repository", 132 | "Repository": "CRAN", 133 | "Requirements": [ 134 | "R", 135 | "base64enc", 136 | "cachem", 137 | "fastmap", 138 | "grDevices", 139 | "htmltools", 140 | "jquerylib", 141 | "jsonlite", 142 | "lifecycle", 143 | "memoise", 144 | "mime", 145 | "rlang", 146 | "sass" 147 | ], 148 | "Hash": "8644cc53f43828f19133548195d7e59e" 149 | }, 150 | "cachem": { 151 | "Package": "cachem", 152 | "Version": "1.0.8", 153 | "Source": "Repository", 154 | "Repository": "CRAN", 155 | "Requirements": [ 156 | "fastmap", 157 | "rlang" 158 | ], 159 | "Hash": "c35768291560ce302c0a6589f92e837d" 160 | }, 161 | "callr": { 162 | "Package": "callr", 163 | "Version": "3.7.6", 164 | "Source": "Repository", 165 | "Repository": "CRAN", 166 | "Requirements": [ 167 | "R", 168 | "R6", 169 | "processx", 170 | "utils" 171 | ], 172 | "Hash": "d7e13f49c19103ece9e58ad2d83a7354" 173 | }, 174 | "cli": { 175 | "Package": "cli", 176 | "Version": "3.6.2", 177 | "Source": "Repository", 178 | "Repository": "CRAN", 179 | "Requirements": [ 180 | "R", 181 | "utils" 182 | ], 183 | "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" 184 | }, 185 | "codetools": { 186 | "Package": "codetools", 187 | "Version": "0.2-20", 188 | "Source": "Repository", 189 | "Repository": "CRAN", 190 | "Requirements": [ 191 | "R" 192 | ], 193 | "Hash": "61e097f35917d342622f21cdc79c256e" 194 | }, 195 | "commonmark": { 196 | "Package": "commonmark", 197 | "Version": "1.9.1", 198 | "Source": "Repository", 199 | "Repository": "CRAN", 200 | "Hash": "5d8225445acb167abf7797de48b2ee3c" 201 | }, 202 | "config": { 203 | "Package": "config", 204 | "Version": "0.3.2", 205 | "Source": "Repository", 206 | "Repository": "CRAN", 207 | "Requirements": [ 208 | "yaml" 209 | ], 210 | "Hash": "8b7222e9d9eb5178eea545c0c4d33fc2" 211 | }, 212 | "crayon": { 213 | "Package": "crayon", 214 | "Version": "1.5.2", 215 | "Source": "Repository", 216 | "Repository": "CRAN", 217 | "Requirements": [ 218 | "grDevices", 219 | "methods", 220 | "utils" 221 | ], 222 | "Hash": "e8a1e41acf02548751f45c718d55aa6a" 223 | }, 224 | "cyclocomp": { 225 | "Package": "cyclocomp", 226 | "Version": "1.1.1", 227 | "Source": "Repository", 228 | "Repository": "CRAN", 229 | "Requirements": [ 230 | "callr", 231 | "crayon", 232 | "desc", 233 | "remotes", 234 | "withr" 235 | ], 236 | "Hash": "cdc4a473222b0112d4df0bcfbed12d44" 237 | }, 238 | "desc": { 239 | "Package": "desc", 240 | "Version": "1.4.3", 241 | "Source": "Repository", 242 | "Repository": "CRAN", 243 | "Requirements": [ 244 | "R", 245 | "R6", 246 | "cli", 247 | "utils" 248 | ], 249 | "Hash": "99b79fcbd6c4d1ce087f5c5c758b384f" 250 | }, 251 | "diffobj": { 252 | "Package": "diffobj", 253 | "Version": "0.3.5", 254 | "Source": "Repository", 255 | "Repository": "CRAN", 256 | "Requirements": [ 257 | "R", 258 | "crayon", 259 | "methods", 260 | "stats", 261 | "tools", 262 | "utils" 263 | ], 264 | "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8" 265 | }, 266 | "digest": { 267 | "Package": "digest", 268 | "Version": "0.6.35", 269 | "Source": "Repository", 270 | "Repository": "CRAN", 271 | "Requirements": [ 272 | "R", 273 | "utils" 274 | ], 275 | "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" 276 | }, 277 | "evaluate": { 278 | "Package": "evaluate", 279 | "Version": "0.23", 280 | "Source": "Repository", 281 | "Repository": "CRAN", 282 | "Requirements": [ 283 | "R", 284 | "methods" 285 | ], 286 | "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" 287 | }, 288 | "fansi": { 289 | "Package": "fansi", 290 | "Version": "1.0.6", 291 | "Source": "Repository", 292 | "Repository": "CRAN", 293 | "Requirements": [ 294 | "R", 295 | "grDevices", 296 | "utils" 297 | ], 298 | "Hash": "962174cf2aeb5b9eea581522286a911f" 299 | }, 300 | "fastmap": { 301 | "Package": "fastmap", 302 | "Version": "1.1.1", 303 | "Source": "Repository", 304 | "Repository": "CRAN", 305 | "Hash": "f7736a18de97dea803bde0a2daaafb27" 306 | }, 307 | "fontawesome": { 308 | "Package": "fontawesome", 309 | "Version": "0.5.2", 310 | "Source": "Repository", 311 | "Repository": "CRAN", 312 | "Requirements": [ 313 | "R", 314 | "htmltools", 315 | "rlang" 316 | ], 317 | "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" 318 | }, 319 | "fs": { 320 | "Package": "fs", 321 | "Version": "1.6.3", 322 | "Source": "Repository", 323 | "Repository": "CRAN", 324 | "Requirements": [ 325 | "R", 326 | "methods" 327 | ], 328 | "Hash": "47b5f30c720c23999b913a1a635cf0bb" 329 | }, 330 | "glue": { 331 | "Package": "glue", 332 | "Version": "1.7.0", 333 | "Source": "Repository", 334 | "Repository": "CRAN", 335 | "Requirements": [ 336 | "R", 337 | "methods" 338 | ], 339 | "Hash": "e0b3a53876554bd45879e596cdb10a52" 340 | }, 341 | "highr": { 342 | "Package": "highr", 343 | "Version": "0.10", 344 | "Source": "Repository", 345 | "Repository": "CRAN", 346 | "Requirements": [ 347 | "R", 348 | "xfun" 349 | ], 350 | "Hash": "06230136b2d2b9ba5805e1963fa6e890" 351 | }, 352 | "htmltools": { 353 | "Package": "htmltools", 354 | "Version": "0.5.8.1", 355 | "Source": "Repository", 356 | "Repository": "CRAN", 357 | "Requirements": [ 358 | "R", 359 | "base64enc", 360 | "digest", 361 | "fastmap", 362 | "grDevices", 363 | "rlang", 364 | "utils" 365 | ], 366 | "Hash": "81d371a9cc60640e74e4ab6ac46dcedc" 367 | }, 368 | "httpuv": { 369 | "Package": "httpuv", 370 | "Version": "1.6.15", 371 | "Source": "Repository", 372 | "Repository": "CRAN", 373 | "Requirements": [ 374 | "R", 375 | "R6", 376 | "Rcpp", 377 | "later", 378 | "promises", 379 | "utils" 380 | ], 381 | "Hash": "d55aa087c47a63ead0f6fc10f8fa1ee0" 382 | }, 383 | "jquerylib": { 384 | "Package": "jquerylib", 385 | "Version": "0.1.4", 386 | "Source": "Repository", 387 | "Repository": "CRAN", 388 | "Requirements": [ 389 | "htmltools" 390 | ], 391 | "Hash": "5aab57a3bd297eee1c1d862735972182" 392 | }, 393 | "jsonlite": { 394 | "Package": "jsonlite", 395 | "Version": "1.8.8", 396 | "Source": "Repository", 397 | "Repository": "CRAN", 398 | "Requirements": [ 399 | "methods" 400 | ], 401 | "Hash": "e1b9c55281c5adc4dd113652d9e26768" 402 | }, 403 | "knitr": { 404 | "Package": "knitr", 405 | "Version": "1.46", 406 | "Source": "Repository", 407 | "Repository": "CRAN", 408 | "Requirements": [ 409 | "R", 410 | "evaluate", 411 | "highr", 412 | "methods", 413 | "tools", 414 | "xfun", 415 | "yaml" 416 | ], 417 | "Hash": "6e008ab1d696a5283c79765fa7b56b47" 418 | }, 419 | "later": { 420 | "Package": "later", 421 | "Version": "1.3.2", 422 | "Source": "Repository", 423 | "Repository": "CRAN", 424 | "Requirements": [ 425 | "Rcpp", 426 | "rlang" 427 | ], 428 | "Hash": "a3e051d405326b8b0012377434c62b37" 429 | }, 430 | "lazyeval": { 431 | "Package": "lazyeval", 432 | "Version": "0.2.2", 433 | "Source": "Repository", 434 | "Repository": "CRAN", 435 | "Requirements": [ 436 | "R" 437 | ], 438 | "Hash": "d908914ae53b04d4c0c0fd72ecc35370" 439 | }, 440 | "lifecycle": { 441 | "Package": "lifecycle", 442 | "Version": "1.0.4", 443 | "Source": "Repository", 444 | "Repository": "CRAN", 445 | "Requirements": [ 446 | "R", 447 | "cli", 448 | "glue", 449 | "rlang" 450 | ], 451 | "Hash": "b8552d117e1b808b09a832f589b79035" 452 | }, 453 | "lintr": { 454 | "Package": "lintr", 455 | "Version": "3.1.2", 456 | "Source": "Repository", 457 | "Repository": "CRAN", 458 | "Requirements": [ 459 | "R", 460 | "backports", 461 | "codetools", 462 | "cyclocomp", 463 | "digest", 464 | "glue", 465 | "knitr", 466 | "rex", 467 | "stats", 468 | "utils", 469 | "xml2", 470 | "xmlparsedata" 471 | ], 472 | "Hash": "08cff46381a242d44c0d8dd0aabd9f71" 473 | }, 474 | "logger": { 475 | "Package": "logger", 476 | "Version": "0.3.0", 477 | "Source": "Repository", 478 | "Repository": "CRAN", 479 | "Requirements": [ 480 | "utils" 481 | ], 482 | "Hash": "c145edf05cc128e6ffcfa5d872c46329" 483 | }, 484 | "magrittr": { 485 | "Package": "magrittr", 486 | "Version": "2.0.3", 487 | "Source": "Repository", 488 | "Repository": "CRAN", 489 | "Requirements": [ 490 | "R" 491 | ], 492 | "Hash": "7ce2733a9826b3aeb1775d56fd305472" 493 | }, 494 | "memoise": { 495 | "Package": "memoise", 496 | "Version": "2.0.1", 497 | "Source": "Repository", 498 | "Repository": "CRAN", 499 | "Requirements": [ 500 | "cachem", 501 | "rlang" 502 | ], 503 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" 504 | }, 505 | "mime": { 506 | "Package": "mime", 507 | "Version": "0.12", 508 | "Source": "Repository", 509 | "Repository": "CRAN", 510 | "Requirements": [ 511 | "tools" 512 | ], 513 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104" 514 | }, 515 | "pillar": { 516 | "Package": "pillar", 517 | "Version": "1.9.0", 518 | "Source": "Repository", 519 | "Repository": "CRAN", 520 | "Requirements": [ 521 | "cli", 522 | "fansi", 523 | "glue", 524 | "lifecycle", 525 | "rlang", 526 | "utf8", 527 | "utils", 528 | "vctrs" 529 | ], 530 | "Hash": "15da5a8412f317beeee6175fbc76f4bb" 531 | }, 532 | "pkgbuild": { 533 | "Package": "pkgbuild", 534 | "Version": "1.4.4", 535 | "Source": "Repository", 536 | "Repository": "CRAN", 537 | "Requirements": [ 538 | "R", 539 | "R6", 540 | "callr", 541 | "cli", 542 | "desc", 543 | "processx" 544 | ], 545 | "Hash": "a29e8e134a460a01e0ca67a4763c595b" 546 | }, 547 | "pkgconfig": { 548 | "Package": "pkgconfig", 549 | "Version": "2.0.3", 550 | "Source": "Repository", 551 | "Repository": "CRAN", 552 | "Requirements": [ 553 | "utils" 554 | ], 555 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 556 | }, 557 | "pkgload": { 558 | "Package": "pkgload", 559 | "Version": "1.3.4", 560 | "Source": "Repository", 561 | "Repository": "CRAN", 562 | "Requirements": [ 563 | "R", 564 | "cli", 565 | "crayon", 566 | "desc", 567 | "fs", 568 | "glue", 569 | "methods", 570 | "pkgbuild", 571 | "rlang", 572 | "rprojroot", 573 | "utils", 574 | "withr" 575 | ], 576 | "Hash": "876c618df5ae610be84356d5d7a5d124" 577 | }, 578 | "praise": { 579 | "Package": "praise", 580 | "Version": "1.0.0", 581 | "Source": "Repository", 582 | "Repository": "CRAN", 583 | "Hash": "a555924add98c99d2f411e37e7d25e9f" 584 | }, 585 | "processx": { 586 | "Package": "processx", 587 | "Version": "3.8.4", 588 | "Source": "Repository", 589 | "Repository": "CRAN", 590 | "Requirements": [ 591 | "R", 592 | "R6", 593 | "ps", 594 | "utils" 595 | ], 596 | "Hash": "0c90a7d71988856bad2a2a45dd871bb9" 597 | }, 598 | "promises": { 599 | "Package": "promises", 600 | "Version": "1.3.0", 601 | "Source": "Repository", 602 | "Repository": "CRAN", 603 | "Requirements": [ 604 | "R6", 605 | "Rcpp", 606 | "fastmap", 607 | "later", 608 | "magrittr", 609 | "rlang", 610 | "stats" 611 | ], 612 | "Hash": "434cd5388a3979e74be5c219bcd6e77d" 613 | }, 614 | "ps": { 615 | "Package": "ps", 616 | "Version": "1.7.6", 617 | "Source": "Repository", 618 | "Repository": "CRAN", 619 | "Requirements": [ 620 | "R", 621 | "utils" 622 | ], 623 | "Hash": "dd2b9319ee0656c8acf45c7f40c59de7" 624 | }, 625 | "purrr": { 626 | "Package": "purrr", 627 | "Version": "1.0.2", 628 | "Source": "Repository", 629 | "Repository": "CRAN", 630 | "Requirements": [ 631 | "R", 632 | "cli", 633 | "lifecycle", 634 | "magrittr", 635 | "rlang", 636 | "vctrs" 637 | ], 638 | "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" 639 | }, 640 | "rappdirs": { 641 | "Package": "rappdirs", 642 | "Version": "0.3.3", 643 | "Source": "Repository", 644 | "Repository": "CRAN", 645 | "Requirements": [ 646 | "R" 647 | ], 648 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d" 649 | }, 650 | "rematch2": { 651 | "Package": "rematch2", 652 | "Version": "2.1.2", 653 | "Source": "Repository", 654 | "Repository": "CRAN", 655 | "Requirements": [ 656 | "tibble" 657 | ], 658 | "Hash": "76c9e04c712a05848ae7a23d2f170a40" 659 | }, 660 | "remotes": { 661 | "Package": "remotes", 662 | "Version": "2.5.0", 663 | "Source": "Repository", 664 | "Repository": "CRAN", 665 | "Requirements": [ 666 | "R", 667 | "methods", 668 | "stats", 669 | "tools", 670 | "utils" 671 | ], 672 | "Hash": "3ee025083e66f18db6cf27b56e23e141" 673 | }, 674 | "renv": { 675 | "Package": "renv", 676 | "Version": "1.0.7", 677 | "Source": "Repository", 678 | "Repository": "CRAN", 679 | "Requirements": [ 680 | "utils" 681 | ], 682 | "Hash": "397b7b2a265bc5a7a06852524dabae20" 683 | }, 684 | "rex": { 685 | "Package": "rex", 686 | "Version": "1.2.1", 687 | "Source": "Repository", 688 | "Repository": "CRAN", 689 | "Requirements": [ 690 | "lazyeval" 691 | ], 692 | "Hash": "ae34cd56890607370665bee5bd17812f" 693 | }, 694 | "rhino": { 695 | "Package": "rhino", 696 | "Version": "1.7.0", 697 | "Source": "Repository", 698 | "Repository": "CRAN", 699 | "Requirements": [ 700 | "R", 701 | "box", 702 | "cli", 703 | "config", 704 | "fs", 705 | "glue", 706 | "lintr", 707 | "logger", 708 | "purrr", 709 | "renv", 710 | "rstudioapi", 711 | "sass", 712 | "shiny", 713 | "styler", 714 | "testthat", 715 | "utils", 716 | "withr", 717 | "xml2", 718 | "yaml" 719 | ], 720 | "Hash": "59ee79b26dd590b08dd1a3111d093832" 721 | }, 722 | "rlang": { 723 | "Package": "rlang", 724 | "Version": "1.1.3", 725 | "Source": "Repository", 726 | "Repository": "CRAN", 727 | "Requirements": [ 728 | "R", 729 | "utils" 730 | ], 731 | "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" 732 | }, 733 | "rprojroot": { 734 | "Package": "rprojroot", 735 | "Version": "2.0.4", 736 | "Source": "Repository", 737 | "Repository": "CRAN", 738 | "Requirements": [ 739 | "R" 740 | ], 741 | "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144" 742 | }, 743 | "rstudioapi": { 744 | "Package": "rstudioapi", 745 | "Version": "0.16.0", 746 | "Source": "Repository", 747 | "Repository": "CRAN", 748 | "Hash": "96710351d642b70e8f02ddeb237c46a7" 749 | }, 750 | "sass": { 751 | "Package": "sass", 752 | "Version": "0.4.9", 753 | "Source": "Repository", 754 | "Repository": "CRAN", 755 | "Requirements": [ 756 | "R6", 757 | "fs", 758 | "htmltools", 759 | "rappdirs", 760 | "rlang" 761 | ], 762 | "Hash": "d53dbfddf695303ea4ad66f86e99b95d" 763 | }, 764 | "shiny": { 765 | "Package": "shiny", 766 | "Version": "1.8.1.1", 767 | "Source": "Repository", 768 | "Repository": "CRAN", 769 | "Requirements": [ 770 | "R", 771 | "R6", 772 | "bslib", 773 | "cachem", 774 | "commonmark", 775 | "crayon", 776 | "fastmap", 777 | "fontawesome", 778 | "glue", 779 | "grDevices", 780 | "htmltools", 781 | "httpuv", 782 | "jsonlite", 783 | "later", 784 | "lifecycle", 785 | "methods", 786 | "mime", 787 | "promises", 788 | "rlang", 789 | "sourcetools", 790 | "tools", 791 | "utils", 792 | "withr", 793 | "xtable" 794 | ], 795 | "Hash": "54b26646816af9960a4c64d8ceec75d6" 796 | }, 797 | "sourcetools": { 798 | "Package": "sourcetools", 799 | "Version": "0.1.7-1", 800 | "Source": "Repository", 801 | "Repository": "CRAN", 802 | "Requirements": [ 803 | "R" 804 | ], 805 | "Hash": "5f5a7629f956619d519205ec475fe647" 806 | }, 807 | "styler": { 808 | "Package": "styler", 809 | "Version": "1.10.3", 810 | "Source": "Repository", 811 | "Repository": "CRAN", 812 | "Requirements": [ 813 | "R", 814 | "R.cache", 815 | "cli", 816 | "magrittr", 817 | "purrr", 818 | "rlang", 819 | "rprojroot", 820 | "tools", 821 | "vctrs", 822 | "withr" 823 | ], 824 | "Hash": "93a2b1beac2437bdcc4724f8bf867e2c" 825 | }, 826 | "testthat": { 827 | "Package": "testthat", 828 | "Version": "3.2.1.1", 829 | "Source": "Repository", 830 | "Repository": "CRAN", 831 | "Requirements": [ 832 | "R", 833 | "R6", 834 | "brio", 835 | "callr", 836 | "cli", 837 | "desc", 838 | "digest", 839 | "evaluate", 840 | "jsonlite", 841 | "lifecycle", 842 | "magrittr", 843 | "methods", 844 | "pkgload", 845 | "praise", 846 | "processx", 847 | "ps", 848 | "rlang", 849 | "utils", 850 | "waldo", 851 | "withr" 852 | ], 853 | "Hash": "3f6e7e5e2220856ff865e4834766bf2b" 854 | }, 855 | "tibble": { 856 | "Package": "tibble", 857 | "Version": "3.2.1", 858 | "Source": "Repository", 859 | "Repository": "CRAN", 860 | "Requirements": [ 861 | "R", 862 | "fansi", 863 | "lifecycle", 864 | "magrittr", 865 | "methods", 866 | "pillar", 867 | "pkgconfig", 868 | "rlang", 869 | "utils", 870 | "vctrs" 871 | ], 872 | "Hash": "a84e2cc86d07289b3b6f5069df7a004c" 873 | }, 874 | "utf8": { 875 | "Package": "utf8", 876 | "Version": "1.2.4", 877 | "Source": "Repository", 878 | "Repository": "CRAN", 879 | "Requirements": [ 880 | "R" 881 | ], 882 | "Hash": "62b65c52671e6665f803ff02954446e9" 883 | }, 884 | "vctrs": { 885 | "Package": "vctrs", 886 | "Version": "0.6.5", 887 | "Source": "Repository", 888 | "Repository": "CRAN", 889 | "Requirements": [ 890 | "R", 891 | "cli", 892 | "glue", 893 | "lifecycle", 894 | "rlang" 895 | ], 896 | "Hash": "c03fa420630029418f7e6da3667aac4a" 897 | }, 898 | "waldo": { 899 | "Package": "waldo", 900 | "Version": "0.5.2", 901 | "Source": "Repository", 902 | "Repository": "CRAN", 903 | "Requirements": [ 904 | "R", 905 | "cli", 906 | "diffobj", 907 | "fansi", 908 | "glue", 909 | "methods", 910 | "rematch2", 911 | "rlang", 912 | "tibble" 913 | ], 914 | "Hash": "c7d3fd6d29ab077cbac8f0e2751449e6" 915 | }, 916 | "withr": { 917 | "Package": "withr", 918 | "Version": "3.0.0", 919 | "Source": "Repository", 920 | "Repository": "CRAN", 921 | "Requirements": [ 922 | "R", 923 | "grDevices", 924 | "graphics" 925 | ], 926 | "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" 927 | }, 928 | "xfun": { 929 | "Package": "xfun", 930 | "Version": "0.43", 931 | "Source": "Repository", 932 | "Repository": "CRAN", 933 | "Requirements": [ 934 | "grDevices", 935 | "stats", 936 | "tools" 937 | ], 938 | "Hash": "ab6371d8653ce5f2f9290f4ec7b42a8e" 939 | }, 940 | "xml2": { 941 | "Package": "xml2", 942 | "Version": "1.3.6", 943 | "Source": "Repository", 944 | "Repository": "CRAN", 945 | "Requirements": [ 946 | "R", 947 | "cli", 948 | "methods", 949 | "rlang" 950 | ], 951 | "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61" 952 | }, 953 | "xmlparsedata": { 954 | "Package": "xmlparsedata", 955 | "Version": "1.0.5", 956 | "Source": "Repository", 957 | "Repository": "CRAN", 958 | "Requirements": [ 959 | "R" 960 | ], 961 | "Hash": "45e4bf3c46476896e821fc0a408fb4fc" 962 | }, 963 | "xtable": { 964 | "Package": "xtable", 965 | "Version": "1.8-4", 966 | "Source": "Repository", 967 | "Repository": "CRAN", 968 | "Requirements": [ 969 | "R", 970 | "stats", 971 | "utils" 972 | ], 973 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 974 | }, 975 | "yaml": { 976 | "Package": "yaml", 977 | "Version": "2.3.8", 978 | "Source": "Repository", 979 | "Repository": "CRAN", 980 | "Hash": "29240487a071f535f5e5d5a323b7afbd" 981 | } 982 | } 983 | } 984 | -------------------------------------------------------------------------------- /task2/renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | local/ 3 | cellar/ 4 | lock/ 5 | python/ 6 | sandbox/ 7 | staging/ 8 | -------------------------------------------------------------------------------- /task2/renv/activate.R: -------------------------------------------------------------------------------- 1 | 2 | local({ 3 | 4 | # the requested version of renv 5 | version <- "1.0.7" 6 | attr(version, "sha") <- NULL 7 | 8 | # the project directory 9 | project <- Sys.getenv("RENV_PROJECT") 10 | if (!nzchar(project)) 11 | project <- getwd() 12 | 13 | # use start-up diagnostics if enabled 14 | diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") 15 | if (diagnostics) { 16 | start <- Sys.time() 17 | profile <- tempfile("renv-startup-", fileext = ".Rprof") 18 | utils::Rprof(profile) 19 | on.exit({ 20 | utils::Rprof(NULL) 21 | elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) 22 | writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) 23 | writeLines(sprintf("- Profile: %s", profile)) 24 | print(utils::summaryRprof(profile)) 25 | }, add = TRUE) 26 | } 27 | 28 | # figure out whether the autoloader is enabled 29 | enabled <- local({ 30 | 31 | # first, check config option 32 | override <- getOption("renv.config.autoloader.enabled") 33 | if (!is.null(override)) 34 | return(override) 35 | 36 | # if we're being run in a context where R_LIBS is already set, 37 | # don't load -- presumably we're being run as a sub-process and 38 | # the parent process has already set up library paths for us 39 | rcmd <- Sys.getenv("R_CMD", unset = NA) 40 | rlibs <- Sys.getenv("R_LIBS", unset = NA) 41 | if (!is.na(rlibs) && !is.na(rcmd)) 42 | return(FALSE) 43 | 44 | # next, check environment variables 45 | # TODO: prefer using the configuration one in the future 46 | envvars <- c( 47 | "RENV_CONFIG_AUTOLOADER_ENABLED", 48 | "RENV_AUTOLOADER_ENABLED", 49 | "RENV_ACTIVATE_PROJECT" 50 | ) 51 | 52 | for (envvar in envvars) { 53 | envval <- Sys.getenv(envvar, unset = NA) 54 | if (!is.na(envval)) 55 | return(tolower(envval) %in% c("true", "t", "1")) 56 | } 57 | 58 | # enable by default 59 | TRUE 60 | 61 | }) 62 | 63 | # bail if we're not enabled 64 | if (!enabled) { 65 | 66 | # if we're not enabled, we might still need to manually load 67 | # the user profile here 68 | profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") 69 | if (file.exists(profile)) { 70 | cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") 71 | if (tolower(cfg) %in% c("true", "t", "1")) 72 | sys.source(profile, envir = globalenv()) 73 | } 74 | 75 | return(FALSE) 76 | 77 | } 78 | 79 | # avoid recursion 80 | if (identical(getOption("renv.autoloader.running"), TRUE)) { 81 | warning("ignoring recursive attempt to run renv autoloader") 82 | return(invisible(TRUE)) 83 | } 84 | 85 | # signal that we're loading renv during R startup 86 | options(renv.autoloader.running = TRUE) 87 | on.exit(options(renv.autoloader.running = NULL), add = TRUE) 88 | 89 | # signal that we've consented to use renv 90 | options(renv.consent = TRUE) 91 | 92 | # load the 'utils' package eagerly -- this ensures that renv shims, which 93 | # mask 'utils' packages, will come first on the search path 94 | library(utils, lib.loc = .Library) 95 | 96 | # unload renv if it's already been loaded 97 | if ("renv" %in% loadedNamespaces()) 98 | unloadNamespace("renv") 99 | 100 | # load bootstrap tools 101 | `%||%` <- function(x, y) { 102 | if (is.null(x)) y else x 103 | } 104 | 105 | catf <- function(fmt, ..., appendLF = TRUE) { 106 | 107 | quiet <- getOption("renv.bootstrap.quiet", default = FALSE) 108 | if (quiet) 109 | return(invisible()) 110 | 111 | msg <- sprintf(fmt, ...) 112 | cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") 113 | 114 | invisible(msg) 115 | 116 | } 117 | 118 | header <- function(label, 119 | ..., 120 | prefix = "#", 121 | suffix = "-", 122 | n = min(getOption("width"), 78)) 123 | { 124 | label <- sprintf(label, ...) 125 | n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) 126 | if (n <= 0) 127 | return(paste(prefix, label)) 128 | 129 | tail <- paste(rep.int(suffix, n), collapse = "") 130 | paste0(prefix, " ", label, " ", tail) 131 | 132 | } 133 | 134 | heredoc <- function(text, leave = 0) { 135 | 136 | # remove leading, trailing whitespace 137 | trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) 138 | 139 | # split into lines 140 | lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] 141 | 142 | # compute common indent 143 | indent <- regexpr("[^[:space:]]", lines) 144 | common <- min(setdiff(indent, -1L)) - leave 145 | paste(substring(lines, common), collapse = "\n") 146 | 147 | } 148 | 149 | startswith <- function(string, prefix) { 150 | substring(string, 1, nchar(prefix)) == prefix 151 | } 152 | 153 | bootstrap <- function(version, library) { 154 | 155 | friendly <- renv_bootstrap_version_friendly(version) 156 | section <- header(sprintf("Bootstrapping renv %s", friendly)) 157 | catf(section) 158 | 159 | # attempt to download renv 160 | catf("- Downloading renv ... ", appendLF = FALSE) 161 | withCallingHandlers( 162 | tarball <- renv_bootstrap_download(version), 163 | error = function(err) { 164 | catf("FAILED") 165 | stop("failed to download:\n", conditionMessage(err)) 166 | } 167 | ) 168 | catf("OK") 169 | on.exit(unlink(tarball), add = TRUE) 170 | 171 | # now attempt to install 172 | catf("- Installing renv ... ", appendLF = FALSE) 173 | withCallingHandlers( 174 | status <- renv_bootstrap_install(version, tarball, library), 175 | error = function(err) { 176 | catf("FAILED") 177 | stop("failed to install:\n", conditionMessage(err)) 178 | } 179 | ) 180 | catf("OK") 181 | 182 | # add empty line to break up bootstrapping from normal output 183 | catf("") 184 | 185 | return(invisible()) 186 | } 187 | 188 | renv_bootstrap_tests_running <- function() { 189 | getOption("renv.tests.running", default = FALSE) 190 | } 191 | 192 | renv_bootstrap_repos <- function() { 193 | 194 | # get CRAN repository 195 | cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") 196 | 197 | # check for repos override 198 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) 199 | if (!is.na(repos)) { 200 | 201 | # check for RSPM; if set, use a fallback repository for renv 202 | rspm <- Sys.getenv("RSPM", unset = NA) 203 | if (identical(rspm, repos)) 204 | repos <- c(RSPM = rspm, CRAN = cran) 205 | 206 | return(repos) 207 | 208 | } 209 | 210 | # check for lockfile repositories 211 | repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) 212 | if (!inherits(repos, "error") && length(repos)) 213 | return(repos) 214 | 215 | # retrieve current repos 216 | repos <- getOption("repos") 217 | 218 | # ensure @CRAN@ entries are resolved 219 | repos[repos == "@CRAN@"] <- cran 220 | 221 | # add in renv.bootstrap.repos if set 222 | default <- c(FALLBACK = "https://cloud.r-project.org") 223 | extra <- getOption("renv.bootstrap.repos", default = default) 224 | repos <- c(repos, extra) 225 | 226 | # remove duplicates that might've snuck in 227 | dupes <- duplicated(repos) | duplicated(names(repos)) 228 | repos[!dupes] 229 | 230 | } 231 | 232 | renv_bootstrap_repos_lockfile <- function() { 233 | 234 | lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") 235 | if (!file.exists(lockpath)) 236 | return(NULL) 237 | 238 | lockfile <- tryCatch(renv_json_read(lockpath), error = identity) 239 | if (inherits(lockfile, "error")) { 240 | warning(lockfile) 241 | return(NULL) 242 | } 243 | 244 | repos <- lockfile$R$Repositories 245 | if (length(repos) == 0) 246 | return(NULL) 247 | 248 | keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) 249 | vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) 250 | names(vals) <- keys 251 | 252 | return(vals) 253 | 254 | } 255 | 256 | renv_bootstrap_download <- function(version) { 257 | 258 | sha <- attr(version, "sha", exact = TRUE) 259 | 260 | methods <- if (!is.null(sha)) { 261 | 262 | # attempting to bootstrap a development version of renv 263 | c( 264 | function() renv_bootstrap_download_tarball(sha), 265 | function() renv_bootstrap_download_github(sha) 266 | ) 267 | 268 | } else { 269 | 270 | # attempting to bootstrap a release version of renv 271 | c( 272 | function() renv_bootstrap_download_tarball(version), 273 | function() renv_bootstrap_download_cran_latest(version), 274 | function() renv_bootstrap_download_cran_archive(version) 275 | ) 276 | 277 | } 278 | 279 | for (method in methods) { 280 | path <- tryCatch(method(), error = identity) 281 | if (is.character(path) && file.exists(path)) 282 | return(path) 283 | } 284 | 285 | stop("All download methods failed") 286 | 287 | } 288 | 289 | renv_bootstrap_download_impl <- function(url, destfile) { 290 | 291 | mode <- "wb" 292 | 293 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 294 | fixup <- 295 | Sys.info()[["sysname"]] == "Windows" && 296 | substring(url, 1L, 5L) == "file:" 297 | 298 | if (fixup) 299 | mode <- "w+b" 300 | 301 | args <- list( 302 | url = url, 303 | destfile = destfile, 304 | mode = mode, 305 | quiet = TRUE 306 | ) 307 | 308 | if ("headers" %in% names(formals(utils::download.file))) 309 | args$headers <- renv_bootstrap_download_custom_headers(url) 310 | 311 | do.call(utils::download.file, args) 312 | 313 | } 314 | 315 | renv_bootstrap_download_custom_headers <- function(url) { 316 | 317 | headers <- getOption("renv.download.headers") 318 | if (is.null(headers)) 319 | return(character()) 320 | 321 | if (!is.function(headers)) 322 | stopf("'renv.download.headers' is not a function") 323 | 324 | headers <- headers(url) 325 | if (length(headers) == 0L) 326 | return(character()) 327 | 328 | if (is.list(headers)) 329 | headers <- unlist(headers, recursive = FALSE, use.names = TRUE) 330 | 331 | ok <- 332 | is.character(headers) && 333 | is.character(names(headers)) && 334 | all(nzchar(names(headers))) 335 | 336 | if (!ok) 337 | stop("invocation of 'renv.download.headers' did not return a named character vector") 338 | 339 | headers 340 | 341 | } 342 | 343 | renv_bootstrap_download_cran_latest <- function(version) { 344 | 345 | spec <- renv_bootstrap_download_cran_latest_find(version) 346 | type <- spec$type 347 | repos <- spec$repos 348 | 349 | baseurl <- utils::contrib.url(repos = repos, type = type) 350 | ext <- if (identical(type, "source")) 351 | ".tar.gz" 352 | else if (Sys.info()[["sysname"]] == "Windows") 353 | ".zip" 354 | else 355 | ".tgz" 356 | name <- sprintf("renv_%s%s", version, ext) 357 | url <- paste(baseurl, name, sep = "/") 358 | 359 | destfile <- file.path(tempdir(), name) 360 | status <- tryCatch( 361 | renv_bootstrap_download_impl(url, destfile), 362 | condition = identity 363 | ) 364 | 365 | if (inherits(status, "condition")) 366 | return(FALSE) 367 | 368 | # report success and return 369 | destfile 370 | 371 | } 372 | 373 | renv_bootstrap_download_cran_latest_find <- function(version) { 374 | 375 | # check whether binaries are supported on this system 376 | binary <- 377 | getOption("renv.bootstrap.binary", default = TRUE) && 378 | !identical(.Platform$pkgType, "source") && 379 | !identical(getOption("pkgType"), "source") && 380 | Sys.info()[["sysname"]] %in% c("Darwin", "Windows") 381 | 382 | types <- c(if (binary) "binary", "source") 383 | 384 | # iterate over types + repositories 385 | for (type in types) { 386 | for (repos in renv_bootstrap_repos()) { 387 | 388 | # retrieve package database 389 | db <- tryCatch( 390 | as.data.frame( 391 | utils::available.packages(type = type, repos = repos), 392 | stringsAsFactors = FALSE 393 | ), 394 | error = identity 395 | ) 396 | 397 | if (inherits(db, "error")) 398 | next 399 | 400 | # check for compatible entry 401 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ] 402 | if (nrow(entry) == 0) 403 | next 404 | 405 | # found it; return spec to caller 406 | spec <- list(entry = entry, type = type, repos = repos) 407 | return(spec) 408 | 409 | } 410 | } 411 | 412 | # if we got here, we failed to find renv 413 | fmt <- "renv %s is not available from your declared package repositories" 414 | stop(sprintf(fmt, version)) 415 | 416 | } 417 | 418 | renv_bootstrap_download_cran_archive <- function(version) { 419 | 420 | name <- sprintf("renv_%s.tar.gz", version) 421 | repos <- renv_bootstrap_repos() 422 | urls <- file.path(repos, "src/contrib/Archive/renv", name) 423 | destfile <- file.path(tempdir(), name) 424 | 425 | for (url in urls) { 426 | 427 | status <- tryCatch( 428 | renv_bootstrap_download_impl(url, destfile), 429 | condition = identity 430 | ) 431 | 432 | if (identical(status, 0L)) 433 | return(destfile) 434 | 435 | } 436 | 437 | return(FALSE) 438 | 439 | } 440 | 441 | renv_bootstrap_download_tarball <- function(version) { 442 | 443 | # if the user has provided the path to a tarball via 444 | # an environment variable, then use it 445 | tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) 446 | if (is.na(tarball)) 447 | return() 448 | 449 | # allow directories 450 | if (dir.exists(tarball)) { 451 | name <- sprintf("renv_%s.tar.gz", version) 452 | tarball <- file.path(tarball, name) 453 | } 454 | 455 | # bail if it doesn't exist 456 | if (!file.exists(tarball)) { 457 | 458 | # let the user know we weren't able to honour their request 459 | fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." 460 | msg <- sprintf(fmt, tarball) 461 | warning(msg) 462 | 463 | # bail 464 | return() 465 | 466 | } 467 | 468 | catf("- Using local tarball '%s'.", tarball) 469 | tarball 470 | 471 | } 472 | 473 | renv_bootstrap_download_github <- function(version) { 474 | 475 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") 476 | if (!identical(enabled, "TRUE")) 477 | return(FALSE) 478 | 479 | # prepare download options 480 | pat <- Sys.getenv("GITHUB_PAT") 481 | if (nzchar(Sys.which("curl")) && nzchar(pat)) { 482 | fmt <- "--location --fail --header \"Authorization: token %s\"" 483 | extra <- sprintf(fmt, pat) 484 | saved <- options("download.file.method", "download.file.extra") 485 | options(download.file.method = "curl", download.file.extra = extra) 486 | on.exit(do.call(base::options, saved), add = TRUE) 487 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { 488 | fmt <- "--header=\"Authorization: token %s\"" 489 | extra <- sprintf(fmt, pat) 490 | saved <- options("download.file.method", "download.file.extra") 491 | options(download.file.method = "wget", download.file.extra = extra) 492 | on.exit(do.call(base::options, saved), add = TRUE) 493 | } 494 | 495 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) 496 | name <- sprintf("renv_%s.tar.gz", version) 497 | destfile <- file.path(tempdir(), name) 498 | 499 | status <- tryCatch( 500 | renv_bootstrap_download_impl(url, destfile), 501 | condition = identity 502 | ) 503 | 504 | if (!identical(status, 0L)) 505 | return(FALSE) 506 | 507 | renv_bootstrap_download_augment(destfile) 508 | 509 | return(destfile) 510 | 511 | } 512 | 513 | # Add Sha to DESCRIPTION. This is stop gap until #890, after which we 514 | # can use renv::install() to fully capture metadata. 515 | renv_bootstrap_download_augment <- function(destfile) { 516 | sha <- renv_bootstrap_git_extract_sha1_tar(destfile) 517 | if (is.null(sha)) { 518 | return() 519 | } 520 | 521 | # Untar 522 | tempdir <- tempfile("renv-github-") 523 | on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) 524 | untar(destfile, exdir = tempdir) 525 | pkgdir <- dir(tempdir, full.names = TRUE)[[1]] 526 | 527 | # Modify description 528 | desc_path <- file.path(pkgdir, "DESCRIPTION") 529 | desc_lines <- readLines(desc_path) 530 | remotes_fields <- c( 531 | "RemoteType: github", 532 | "RemoteHost: api.github.com", 533 | "RemoteRepo: renv", 534 | "RemoteUsername: rstudio", 535 | "RemotePkgRef: rstudio/renv", 536 | paste("RemoteRef: ", sha), 537 | paste("RemoteSha: ", sha) 538 | ) 539 | writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) 540 | 541 | # Re-tar 542 | local({ 543 | old <- setwd(tempdir) 544 | on.exit(setwd(old), add = TRUE) 545 | 546 | tar(destfile, compression = "gzip") 547 | }) 548 | invisible() 549 | } 550 | 551 | # Extract the commit hash from a git archive. Git archives include the SHA1 552 | # hash as the comment field of the tarball pax extended header 553 | # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) 554 | # For GitHub archives this should be the first header after the default one 555 | # (512 byte) header. 556 | renv_bootstrap_git_extract_sha1_tar <- function(bundle) { 557 | 558 | # open the bundle for reading 559 | # We use gzcon for everything because (from ?gzcon) 560 | # > Reading from a connection which does not supply a 'gzip' magic 561 | # > header is equivalent to reading from the original connection 562 | conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) 563 | on.exit(close(conn)) 564 | 565 | # The default pax header is 512 bytes long and the first pax extended header 566 | # with the comment should be 51 bytes long 567 | # `52 comment=` (11 chars) + 40 byte SHA1 hash 568 | len <- 0x200 + 0x33 569 | res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) 570 | 571 | if (grepl("^52 comment=", res)) { 572 | sub("52 comment=", "", res) 573 | } else { 574 | NULL 575 | } 576 | } 577 | 578 | renv_bootstrap_install <- function(version, tarball, library) { 579 | 580 | # attempt to install it into project library 581 | dir.create(library, showWarnings = FALSE, recursive = TRUE) 582 | output <- renv_bootstrap_install_impl(library, tarball) 583 | 584 | # check for successful install 585 | status <- attr(output, "status") 586 | if (is.null(status) || identical(status, 0L)) 587 | return(status) 588 | 589 | # an error occurred; report it 590 | header <- "installation of renv failed" 591 | lines <- paste(rep.int("=", nchar(header)), collapse = "") 592 | text <- paste(c(header, lines, output), collapse = "\n") 593 | stop(text) 594 | 595 | } 596 | 597 | renv_bootstrap_install_impl <- function(library, tarball) { 598 | 599 | # invoke using system2 so we can capture and report output 600 | bin <- R.home("bin") 601 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" 602 | R <- file.path(bin, exe) 603 | 604 | args <- c( 605 | "--vanilla", "CMD", "INSTALL", "--no-multiarch", 606 | "-l", shQuote(path.expand(library)), 607 | shQuote(path.expand(tarball)) 608 | ) 609 | 610 | system2(R, args, stdout = TRUE, stderr = TRUE) 611 | 612 | } 613 | 614 | renv_bootstrap_platform_prefix <- function() { 615 | 616 | # construct version prefix 617 | version <- paste(R.version$major, R.version$minor, sep = ".") 618 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") 619 | 620 | # include SVN revision for development versions of R 621 | # (to avoid sharing platform-specific artefacts with released versions of R) 622 | devel <- 623 | identical(R.version[["status"]], "Under development (unstable)") || 624 | identical(R.version[["nickname"]], "Unsuffered Consequences") 625 | 626 | if (devel) 627 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") 628 | 629 | # build list of path components 630 | components <- c(prefix, R.version$platform) 631 | 632 | # include prefix if provided by user 633 | prefix <- renv_bootstrap_platform_prefix_impl() 634 | if (!is.na(prefix) && nzchar(prefix)) 635 | components <- c(prefix, components) 636 | 637 | # build prefix 638 | paste(components, collapse = "/") 639 | 640 | } 641 | 642 | renv_bootstrap_platform_prefix_impl <- function() { 643 | 644 | # if an explicit prefix has been supplied, use it 645 | prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) 646 | if (!is.na(prefix)) 647 | return(prefix) 648 | 649 | # if the user has requested an automatic prefix, generate it 650 | auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) 651 | if (is.na(auto) && getRversion() >= "4.4.0") 652 | auto <- "TRUE" 653 | 654 | if (auto %in% c("TRUE", "True", "true", "1")) 655 | return(renv_bootstrap_platform_prefix_auto()) 656 | 657 | # empty string on failure 658 | "" 659 | 660 | } 661 | 662 | renv_bootstrap_platform_prefix_auto <- function() { 663 | 664 | prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) 665 | if (inherits(prefix, "error") || prefix %in% "unknown") { 666 | 667 | msg <- paste( 668 | "failed to infer current operating system", 669 | "please file a bug report at https://github.com/rstudio/renv/issues", 670 | sep = "; " 671 | ) 672 | 673 | warning(msg) 674 | 675 | } 676 | 677 | prefix 678 | 679 | } 680 | 681 | renv_bootstrap_platform_os <- function() { 682 | 683 | sysinfo <- Sys.info() 684 | sysname <- sysinfo[["sysname"]] 685 | 686 | # handle Windows + macOS up front 687 | if (sysname == "Windows") 688 | return("windows") 689 | else if (sysname == "Darwin") 690 | return("macos") 691 | 692 | # check for os-release files 693 | for (file in c("/etc/os-release", "/usr/lib/os-release")) 694 | if (file.exists(file)) 695 | return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) 696 | 697 | # check for redhat-release files 698 | if (file.exists("/etc/redhat-release")) 699 | return(renv_bootstrap_platform_os_via_redhat_release()) 700 | 701 | "unknown" 702 | 703 | } 704 | 705 | renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { 706 | 707 | # read /etc/os-release 708 | release <- utils::read.table( 709 | file = file, 710 | sep = "=", 711 | quote = c("\"", "'"), 712 | col.names = c("Key", "Value"), 713 | comment.char = "#", 714 | stringsAsFactors = FALSE 715 | ) 716 | 717 | vars <- as.list(release$Value) 718 | names(vars) <- release$Key 719 | 720 | # get os name 721 | os <- tolower(sysinfo[["sysname"]]) 722 | 723 | # read id 724 | id <- "unknown" 725 | for (field in c("ID", "ID_LIKE")) { 726 | if (field %in% names(vars) && nzchar(vars[[field]])) { 727 | id <- vars[[field]] 728 | break 729 | } 730 | } 731 | 732 | # read version 733 | version <- "unknown" 734 | for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { 735 | if (field %in% names(vars) && nzchar(vars[[field]])) { 736 | version <- vars[[field]] 737 | break 738 | } 739 | } 740 | 741 | # join together 742 | paste(c(os, id, version), collapse = "-") 743 | 744 | } 745 | 746 | renv_bootstrap_platform_os_via_redhat_release <- function() { 747 | 748 | # read /etc/redhat-release 749 | contents <- readLines("/etc/redhat-release", warn = FALSE) 750 | 751 | # infer id 752 | id <- if (grepl("centos", contents, ignore.case = TRUE)) 753 | "centos" 754 | else if (grepl("redhat", contents, ignore.case = TRUE)) 755 | "redhat" 756 | else 757 | "unknown" 758 | 759 | # try to find a version component (very hacky) 760 | version <- "unknown" 761 | 762 | parts <- strsplit(contents, "[[:space:]]")[[1L]] 763 | for (part in parts) { 764 | 765 | nv <- tryCatch(numeric_version(part), error = identity) 766 | if (inherits(nv, "error")) 767 | next 768 | 769 | version <- nv[1, 1] 770 | break 771 | 772 | } 773 | 774 | paste(c("linux", id, version), collapse = "-") 775 | 776 | } 777 | 778 | renv_bootstrap_library_root_name <- function(project) { 779 | 780 | # use project name as-is if requested 781 | asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") 782 | if (asis) 783 | return(basename(project)) 784 | 785 | # otherwise, disambiguate based on project's path 786 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) 787 | paste(basename(project), id, sep = "-") 788 | 789 | } 790 | 791 | renv_bootstrap_library_root <- function(project) { 792 | 793 | prefix <- renv_bootstrap_profile_prefix() 794 | 795 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) 796 | if (!is.na(path)) 797 | return(paste(c(path, prefix), collapse = "/")) 798 | 799 | path <- renv_bootstrap_library_root_impl(project) 800 | if (!is.null(path)) { 801 | name <- renv_bootstrap_library_root_name(project) 802 | return(paste(c(path, prefix, name), collapse = "/")) 803 | } 804 | 805 | renv_bootstrap_paths_renv("library", project = project) 806 | 807 | } 808 | 809 | renv_bootstrap_library_root_impl <- function(project) { 810 | 811 | root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) 812 | if (!is.na(root)) 813 | return(root) 814 | 815 | type <- renv_bootstrap_project_type(project) 816 | if (identical(type, "package")) { 817 | userdir <- renv_bootstrap_user_dir() 818 | return(file.path(userdir, "library")) 819 | } 820 | 821 | } 822 | 823 | renv_bootstrap_validate_version <- function(version, description = NULL) { 824 | 825 | # resolve description file 826 | # 827 | # avoid passing lib.loc to `packageDescription()` below, since R will 828 | # use the loaded version of the package by default anyhow. note that 829 | # this function should only be called after 'renv' is loaded 830 | # https://github.com/rstudio/renv/issues/1625 831 | description <- description %||% packageDescription("renv") 832 | 833 | # check whether requested version 'version' matches loaded version of renv 834 | sha <- attr(version, "sha", exact = TRUE) 835 | valid <- if (!is.null(sha)) 836 | renv_bootstrap_validate_version_dev(sha, description) 837 | else 838 | renv_bootstrap_validate_version_release(version, description) 839 | 840 | if (valid) 841 | return(TRUE) 842 | 843 | # the loaded version of renv doesn't match the requested version; 844 | # give the user instructions on how to proceed 845 | dev <- identical(description[["RemoteType"]], "github") 846 | remote <- if (dev) 847 | paste("rstudio/renv", description[["RemoteSha"]], sep = "@") 848 | else 849 | paste("renv", description[["Version"]], sep = "@") 850 | 851 | # display both loaded version + sha if available 852 | friendly <- renv_bootstrap_version_friendly( 853 | version = description[["Version"]], 854 | sha = if (dev) description[["RemoteSha"]] 855 | ) 856 | 857 | fmt <- heredoc(" 858 | renv %1$s was loaded from project library, but this project is configured to use renv %2$s. 859 | - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. 860 | - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. 861 | ") 862 | catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) 863 | 864 | FALSE 865 | 866 | } 867 | 868 | renv_bootstrap_validate_version_dev <- function(version, description) { 869 | expected <- description[["RemoteSha"]] 870 | is.character(expected) && startswith(expected, version) 871 | } 872 | 873 | renv_bootstrap_validate_version_release <- function(version, description) { 874 | expected <- description[["Version"]] 875 | is.character(expected) && identical(expected, version) 876 | } 877 | 878 | renv_bootstrap_hash_text <- function(text) { 879 | 880 | hashfile <- tempfile("renv-hash-") 881 | on.exit(unlink(hashfile), add = TRUE) 882 | 883 | writeLines(text, con = hashfile) 884 | tools::md5sum(hashfile) 885 | 886 | } 887 | 888 | renv_bootstrap_load <- function(project, libpath, version) { 889 | 890 | # try to load renv from the project library 891 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) 892 | return(FALSE) 893 | 894 | # warn if the version of renv loaded does not match 895 | renv_bootstrap_validate_version(version) 896 | 897 | # execute renv load hooks, if any 898 | hooks <- getHook("renv::autoload") 899 | for (hook in hooks) 900 | if (is.function(hook)) 901 | tryCatch(hook(), error = warnify) 902 | 903 | # load the project 904 | renv::load(project) 905 | 906 | TRUE 907 | 908 | } 909 | 910 | renv_bootstrap_profile_load <- function(project) { 911 | 912 | # if RENV_PROFILE is already set, just use that 913 | profile <- Sys.getenv("RENV_PROFILE", unset = NA) 914 | if (!is.na(profile) && nzchar(profile)) 915 | return(profile) 916 | 917 | # check for a profile file (nothing to do if it doesn't exist) 918 | path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) 919 | if (!file.exists(path)) 920 | return(NULL) 921 | 922 | # read the profile, and set it if it exists 923 | contents <- readLines(path, warn = FALSE) 924 | if (length(contents) == 0L) 925 | return(NULL) 926 | 927 | # set RENV_PROFILE 928 | profile <- contents[[1L]] 929 | if (!profile %in% c("", "default")) 930 | Sys.setenv(RENV_PROFILE = profile) 931 | 932 | profile 933 | 934 | } 935 | 936 | renv_bootstrap_profile_prefix <- function() { 937 | profile <- renv_bootstrap_profile_get() 938 | if (!is.null(profile)) 939 | return(file.path("profiles", profile, "renv")) 940 | } 941 | 942 | renv_bootstrap_profile_get <- function() { 943 | profile <- Sys.getenv("RENV_PROFILE", unset = "") 944 | renv_bootstrap_profile_normalize(profile) 945 | } 946 | 947 | renv_bootstrap_profile_set <- function(profile) { 948 | profile <- renv_bootstrap_profile_normalize(profile) 949 | if (is.null(profile)) 950 | Sys.unsetenv("RENV_PROFILE") 951 | else 952 | Sys.setenv(RENV_PROFILE = profile) 953 | } 954 | 955 | renv_bootstrap_profile_normalize <- function(profile) { 956 | 957 | if (is.null(profile) || profile %in% c("", "default")) 958 | return(NULL) 959 | 960 | profile 961 | 962 | } 963 | 964 | renv_bootstrap_path_absolute <- function(path) { 965 | 966 | substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( 967 | substr(path, 1L, 1L) %in% c(letters, LETTERS) && 968 | substr(path, 2L, 3L) %in% c(":/", ":\\") 969 | ) 970 | 971 | } 972 | 973 | renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { 974 | renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") 975 | root <- if (renv_bootstrap_path_absolute(renv)) NULL else project 976 | prefix <- if (profile) renv_bootstrap_profile_prefix() 977 | components <- c(root, renv, prefix, ...) 978 | paste(components, collapse = "/") 979 | } 980 | 981 | renv_bootstrap_project_type <- function(path) { 982 | 983 | descpath <- file.path(path, "DESCRIPTION") 984 | if (!file.exists(descpath)) 985 | return("unknown") 986 | 987 | desc <- tryCatch( 988 | read.dcf(descpath, all = TRUE), 989 | error = identity 990 | ) 991 | 992 | if (inherits(desc, "error")) 993 | return("unknown") 994 | 995 | type <- desc$Type 996 | if (!is.null(type)) 997 | return(tolower(type)) 998 | 999 | package <- desc$Package 1000 | if (!is.null(package)) 1001 | return("package") 1002 | 1003 | "unknown" 1004 | 1005 | } 1006 | 1007 | renv_bootstrap_user_dir <- function() { 1008 | dir <- renv_bootstrap_user_dir_impl() 1009 | path.expand(chartr("\\", "/", dir)) 1010 | } 1011 | 1012 | renv_bootstrap_user_dir_impl <- function() { 1013 | 1014 | # use local override if set 1015 | override <- getOption("renv.userdir.override") 1016 | if (!is.null(override)) 1017 | return(override) 1018 | 1019 | # use R_user_dir if available 1020 | tools <- asNamespace("tools") 1021 | if (is.function(tools$R_user_dir)) 1022 | return(tools$R_user_dir("renv", "cache")) 1023 | 1024 | # try using our own backfill for older versions of R 1025 | envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") 1026 | for (envvar in envvars) { 1027 | root <- Sys.getenv(envvar, unset = NA) 1028 | if (!is.na(root)) 1029 | return(file.path(root, "R/renv")) 1030 | } 1031 | 1032 | # use platform-specific default fallbacks 1033 | if (Sys.info()[["sysname"]] == "Windows") 1034 | file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") 1035 | else if (Sys.info()[["sysname"]] == "Darwin") 1036 | "~/Library/Caches/org.R-project.R/R/renv" 1037 | else 1038 | "~/.cache/R/renv" 1039 | 1040 | } 1041 | 1042 | renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { 1043 | sha <- sha %||% attr(version, "sha", exact = TRUE) 1044 | parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) 1045 | paste(parts, collapse = "") 1046 | } 1047 | 1048 | renv_bootstrap_exec <- function(project, libpath, version) { 1049 | if (!renv_bootstrap_load(project, libpath, version)) 1050 | renv_bootstrap_run(version, libpath) 1051 | } 1052 | 1053 | renv_bootstrap_run <- function(version, libpath) { 1054 | 1055 | # perform bootstrap 1056 | bootstrap(version, libpath) 1057 | 1058 | # exit early if we're just testing bootstrap 1059 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) 1060 | return(TRUE) 1061 | 1062 | # try again to load 1063 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { 1064 | return(renv::load(project = getwd())) 1065 | } 1066 | 1067 | # failed to download or load renv; warn the user 1068 | msg <- c( 1069 | "Failed to find an renv installation: the project will not be loaded.", 1070 | "Use `renv::activate()` to re-initialize the project." 1071 | ) 1072 | 1073 | warning(paste(msg, collapse = "\n"), call. = FALSE) 1074 | 1075 | } 1076 | 1077 | renv_json_read <- function(file = NULL, text = NULL) { 1078 | 1079 | jlerr <- NULL 1080 | 1081 | # if jsonlite is loaded, use that instead 1082 | if ("jsonlite" %in% loadedNamespaces()) { 1083 | 1084 | json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) 1085 | if (!inherits(json, "error")) 1086 | return(json) 1087 | 1088 | jlerr <- json 1089 | 1090 | } 1091 | 1092 | # otherwise, fall back to the default JSON reader 1093 | json <- tryCatch(renv_json_read_default(file, text), error = identity) 1094 | if (!inherits(json, "error")) 1095 | return(json) 1096 | 1097 | # report an error 1098 | if (!is.null(jlerr)) 1099 | stop(jlerr) 1100 | else 1101 | stop(json) 1102 | 1103 | } 1104 | 1105 | renv_json_read_jsonlite <- function(file = NULL, text = NULL) { 1106 | text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") 1107 | jsonlite::fromJSON(txt = text, simplifyVector = FALSE) 1108 | } 1109 | 1110 | renv_json_read_default <- function(file = NULL, text = NULL) { 1111 | 1112 | # find strings in the JSON 1113 | text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") 1114 | pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' 1115 | locs <- gregexpr(pattern, text, perl = TRUE)[[1]] 1116 | 1117 | # if any are found, replace them with placeholders 1118 | replaced <- text 1119 | strings <- character() 1120 | replacements <- character() 1121 | 1122 | if (!identical(c(locs), -1L)) { 1123 | 1124 | # get the string values 1125 | starts <- locs 1126 | ends <- locs + attr(locs, "match.length") - 1L 1127 | strings <- substring(text, starts, ends) 1128 | 1129 | # only keep those requiring escaping 1130 | strings <- grep("[[\\]{}:]", strings, perl = TRUE, value = TRUE) 1131 | 1132 | # compute replacements 1133 | replacements <- sprintf('"\032%i\032"', seq_along(strings)) 1134 | 1135 | # replace the strings 1136 | mapply(function(string, replacement) { 1137 | replaced <<- sub(string, replacement, replaced, fixed = TRUE) 1138 | }, strings, replacements) 1139 | 1140 | } 1141 | 1142 | # transform the JSON into something the R parser understands 1143 | transformed <- replaced 1144 | transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE) 1145 | transformed <- gsub("[[{]", "list(", transformed, perl = TRUE) 1146 | transformed <- gsub("[]}]", ")", transformed, perl = TRUE) 1147 | transformed <- gsub(":", "=", transformed, fixed = TRUE) 1148 | text <- paste(transformed, collapse = "\n") 1149 | 1150 | # parse it 1151 | json <- parse(text = text, keep.source = FALSE, srcfile = NULL)[[1L]] 1152 | 1153 | # construct map between source strings, replaced strings 1154 | map <- as.character(parse(text = strings)) 1155 | names(map) <- as.character(parse(text = replacements)) 1156 | 1157 | # convert to list 1158 | map <- as.list(map) 1159 | 1160 | # remap strings in object 1161 | remapped <- renv_json_read_remap(json, map) 1162 | 1163 | # evaluate 1164 | eval(remapped, envir = baseenv()) 1165 | 1166 | } 1167 | 1168 | renv_json_read_remap <- function(json, map) { 1169 | 1170 | # fix names 1171 | if (!is.null(names(json))) { 1172 | lhs <- match(names(json), names(map), nomatch = 0L) 1173 | rhs <- match(names(map), names(json), nomatch = 0L) 1174 | names(json)[rhs] <- map[lhs] 1175 | } 1176 | 1177 | # fix values 1178 | if (is.character(json)) 1179 | return(map[[json]] %||% json) 1180 | 1181 | # handle true, false, null 1182 | if (is.name(json)) { 1183 | text <- as.character(json) 1184 | if (text == "true") 1185 | return(TRUE) 1186 | else if (text == "false") 1187 | return(FALSE) 1188 | else if (text == "null") 1189 | return(NULL) 1190 | } 1191 | 1192 | # recurse 1193 | if (is.recursive(json)) { 1194 | for (i in seq_along(json)) { 1195 | json[i] <- list(renv_json_read_remap(json[[i]], map)) 1196 | } 1197 | } 1198 | 1199 | json 1200 | 1201 | } 1202 | 1203 | # load the renv profile, if any 1204 | renv_bootstrap_profile_load(project) 1205 | 1206 | # construct path to library root 1207 | root <- renv_bootstrap_library_root(project) 1208 | 1209 | # construct library prefix for platform 1210 | prefix <- renv_bootstrap_platform_prefix() 1211 | 1212 | # construct full libpath 1213 | libpath <- file.path(root, prefix) 1214 | 1215 | # run bootstrap code 1216 | renv_bootstrap_exec(project, libpath, version) 1217 | 1218 | invisible() 1219 | 1220 | }) 1221 | -------------------------------------------------------------------------------- /task2/renv/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "bioconductor.version": null, 3 | "external.libraries": [], 4 | "ignored.packages": [], 5 | "package.dependency.fields": [ 6 | "Imports", 7 | "Depends", 8 | "LinkingTo" 9 | ], 10 | "ppm.enabled": null, 11 | "ppm.ignored.urls": [], 12 | "r.version": null, 13 | "snapshot.type": "implicit", 14 | "use.cache": true, 15 | "vcs.ignore.cellar": true, 16 | "vcs.ignore.library": true, 17 | "vcs.ignore.local": true, 18 | "vcs.manage.ignores": true 19 | } 20 | -------------------------------------------------------------------------------- /task2/rhino.yml: -------------------------------------------------------------------------------- 1 | sass: node 2 | -------------------------------------------------------------------------------- /task2/task2.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 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 | LineEndingConversion: Posix 18 | -------------------------------------------------------------------------------- /task2/tests/cypress.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | e2e: { 3 | setupNodeEvents(on, config) {}, 4 | baseUrl: 'http://localhost:3333', 5 | supportFile: false, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /task2/tests/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | /screenshots/ 2 | /videos/ 3 | -------------------------------------------------------------------------------- /task2/tests/cypress/e2e/app.cy.js: -------------------------------------------------------------------------------- 1 | describe('app', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | it('starts', () => {}) 7 | }) 8 | -------------------------------------------------------------------------------- /task2/tests/testthat/test-main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny[testServer], 3 | testthat[expect_true, test_that], 4 | ) 5 | box::use( 6 | app/main[server, ui], 7 | ) 8 | 9 | test_that("main server works", { 10 | testServer(server, { 11 | expect_true(grepl(x = output$message$html, pattern = "Check out Rhino docs!")) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /task3/.Rprofile: -------------------------------------------------------------------------------- 1 | if (file.exists("renv")) { 2 | source("renv/activate.R") 3 | } else { 4 | # The `renv` directory is automatically skipped when deploying with rsconnect. 5 | message("No 'renv' directory found; renv won't be activated.") 6 | } 7 | 8 | # Allow absolute module imports (relative to the app root). 9 | options(box.path = getwd()) 10 | -------------------------------------------------------------------------------- /task3/.gitignore: -------------------------------------------------------------------------------- 1 | .Renviron 2 | -------------------------------------------------------------------------------- /task3/.lintr: -------------------------------------------------------------------------------- 1 | linters: 2 | linters_with_defaults( 3 | line_length_linter = line_length_linter(100), 4 | box_func_import_count_linter = rhino::box_func_import_count_linter(), 5 | box_separate_calls_linter = rhino::box_separate_calls_linter(), 6 | box_trailing_commas_linter = rhino::box_trailing_commas_linter(), 7 | box_universal_import_linter = rhino::box_universal_import_linter(), 8 | object_usage_linter = NULL # Does not work with `box::use()`. 9 | ) 10 | -------------------------------------------------------------------------------- /task3/.renvignore: -------------------------------------------------------------------------------- 1 | # Only use `dependencies.R` to infer project dependencies. 2 | * 3 | !dependencies.R 4 | -------------------------------------------------------------------------------- /task3/.rscignore: -------------------------------------------------------------------------------- 1 | .github 2 | .lintr 3 | .renvignore 4 | .Renviron 5 | .rhino 6 | .rscignore 7 | dev.sqlite3 8 | tests 9 | -------------------------------------------------------------------------------- /task3/README.md: -------------------------------------------------------------------------------- 1 | # Task 3 2 | 3 | ### Step 1 4 | 5 | Run `renv::restore()` and `shiny::runApp()`. 6 | 7 | ### Step 2 8 | 9 | Add the folling snippet to `config.yml`: 10 | ```yml 11 | dev: 12 | db_driver: sqlite 13 | db_args: 14 | dbname: dev.sqlite3 15 | ``` 16 | 17 | * Run [`config::get()`](https://rstudio.github.io/config/reference/get.html). 18 | * Compare with `config::get(config = "dev")`. 19 | 20 | ### Step 3 21 | 22 | Create a `.Renviron` file with this content: 23 | ``` 24 | R_CONFIG_ACTIVE=dev 25 | ``` 26 | 27 | * Restart your R session. 28 | * Try `config::get()` now. 29 | 30 | ### Step 4 31 | 32 | * Open `app/logic/db.R`. 33 | * Use the `create_pool()` function to define an exported `pool` object. 34 | * Run `box::use(app/logic/db)` followed by `DBI::dbReadTable(db$pool, "favorites")`. 35 | 36 | ### Step 5 37 | 38 | * Use `log$info()` to show a message when creating a DB pool. 39 | * Run `box::reload(db)` and check if you get a message. 40 | 41 | ### Step 6 42 | 43 | * Restart your R session and notice the warnings from pool. 44 | * Add the following snippet to `db.R`: 45 | ```r 46 | reg.finalizer(pool, close_pool, onexit = TRUE) 47 | .on_unload <- function(ns) { 48 | close_pool(pool) 49 | } 50 | ``` 51 | * Play with steps 4-6 and see that the warnings are gone. 52 | 53 | ### Step 7 54 | 55 | * Fill in the `fetch_favorites()` and `filter_favorites()` functions in `app/logic/data.R`. 56 | * Use `tbl()`, `filter()`, and `collect()` 57 | from [dplyr](https://dplyr.tidyverse.org/reference/index.html). 58 | 59 | ### Step 8 60 | 61 | Use the defined functions to fetch and filter the data 62 | in the `app/view/filters` module. 63 | 64 | ### Step 9 65 | 66 | * Add the `app/view/filters` module to the app. 67 | * Display the returned data using the `app/view/table` module. 68 | -------------------------------------------------------------------------------- /task3/app.R: -------------------------------------------------------------------------------- 1 | # Rhino / shinyApp entrypoint. Do not edit. 2 | rhino::app() 3 | -------------------------------------------------------------------------------- /task3/app/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task3/app/js/index.js -------------------------------------------------------------------------------- /task3/app/logic/__init__.R: -------------------------------------------------------------------------------- 1 | # Logic: application code independent from Shiny. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task3/app/logic/data.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | dplyr, 3 | ) 4 | box::use( 5 | app/logic/db, 6 | ) 7 | 8 | #' @export 9 | fetch_groups <- function() { 10 | dplyr$tbl(pool, "favorites") |> 11 | dplyr$distinct(group) |> 12 | dplyr$pull(group) 13 | } 14 | 15 | #' @export 16 | fetch_favorites <- function(group) { 17 | # Step 7: 18 | # ? 19 | } 20 | 21 | #' @export 22 | filter_favorites <- function(favorites, min_age) { 23 | # Step 7: 24 | # ? 25 | } 26 | -------------------------------------------------------------------------------- /task3/app/logic/db.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | config, 3 | pool[dbPool, poolClose], 4 | rhino[log], 5 | RSQLite[SQLite], 6 | ) 7 | 8 | create_pool <- function(conf) { 9 | driver <- switch(conf$db_driver, 10 | sqlite = SQLite(), 11 | stop() 12 | ) 13 | args <- c(list(driver), conf$db_args) 14 | 15 | # Step 5: 16 | # ? 17 | 18 | do.call(dbPool, args) 19 | } 20 | 21 | close_pool <- function(pool) { 22 | if (pool$valid) { 23 | log$info("Closing DB pool") 24 | poolClose(pool) 25 | } 26 | } 27 | 28 | # Step 4: 29 | # ? 30 | 31 | # Step 6: 32 | # ? 33 | -------------------------------------------------------------------------------- /task3/app/main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | box::use( 5 | app/view/filters, 6 | app/view/table, 7 | ) 8 | 9 | #' @export 10 | ui <- function(id) { 11 | ns <- shiny$NS(id) 12 | shiny$fluidPage( 13 | shiny$titlePanel("Favorites"), 14 | shiny$sidebarLayout( 15 | shiny$sidebarPanel( 16 | # Step 9: 17 | # ? 18 | ), 19 | shiny$mainPanel( 20 | # Step 9: 21 | # ? 22 | ), 23 | position = "right" 24 | ) 25 | ) 26 | } 27 | 28 | #' @export 29 | server <- function(id) { 30 | shiny$moduleServer(id, function(input, output, session) { 31 | # Step 9: 32 | # ? 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /task3/app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task3/app/static/favicon.ico -------------------------------------------------------------------------------- /task3/app/styles/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task3/app/styles/main.scss -------------------------------------------------------------------------------- /task3/app/view/__init__.R: -------------------------------------------------------------------------------- 1 | # View: Shiny modules and related code. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task3/app/view/filters.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | box::use( 5 | app/logic/data, 6 | ) 7 | 8 | #' @export 9 | ui <- function(id) { 10 | ns <- shiny$NS(id) 11 | shiny$tagList( 12 | shiny$sliderInput(ns("min_age"), "Minimum age", min = 20, max = 70, value = 20) 13 | ) 14 | } 15 | 16 | #' @export 17 | server <- function(id) { 18 | shiny$moduleServer(id, function(input, output, session) { 19 | # Step 8: 20 | # ? 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /task3/app/view/table.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | DT[DTOutput, renderDT], 3 | shiny, 4 | ) 5 | 6 | #' @export 7 | ui <- function(id) { 8 | ns <- shiny$NS(id) 9 | DTOutput(ns("table")) 10 | } 11 | 12 | #' @export 13 | server <- function(id, favorites) { 14 | shiny$moduleServer(id, function(input, output, session) { 15 | output$table <- renderDT(favorites()) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /task3/config.yml: -------------------------------------------------------------------------------- 1 | default: 2 | rhino_log_level: !expr Sys.getenv("RHINO_LOG_LEVEL", "INFO") 3 | rhino_log_file: !expr Sys.getenv("RHINO_LOG_FILE", NA) 4 | 5 | # Step 2: 6 | # ? 7 | -------------------------------------------------------------------------------- /task3/dependencies.R: -------------------------------------------------------------------------------- 1 | # This file allows packrat (used by rsconnect during deployment) to pick up dependencies. 2 | library(dbplyr) 3 | library(dplyr) 4 | library(DT) 5 | library(pool) 6 | library(rhino) 7 | library(RSQLite) 8 | -------------------------------------------------------------------------------- /task3/dev.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task3/dev.sqlite3 -------------------------------------------------------------------------------- /task3/renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.1.2", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cloud.r-project.org" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "DBI": { 13 | "Package": "DBI", 14 | "Version": "1.2.2", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Requirements": [ 18 | "R", 19 | "methods" 20 | ], 21 | "Hash": "164809cd72e1d5160b4cb3aa57f510fe" 22 | }, 23 | "DT": { 24 | "Package": "DT", 25 | "Version": "0.33", 26 | "Source": "Repository", 27 | "Repository": "CRAN", 28 | "Requirements": [ 29 | "crosstalk", 30 | "htmltools", 31 | "htmlwidgets", 32 | "httpuv", 33 | "jquerylib", 34 | "jsonlite", 35 | "magrittr", 36 | "promises" 37 | ], 38 | "Hash": "64ff3427f559ce3f2597a4fe13255cb6" 39 | }, 40 | "R.cache": { 41 | "Package": "R.cache", 42 | "Version": "0.16.0", 43 | "Source": "Repository", 44 | "Repository": "CRAN", 45 | "Requirements": [ 46 | "R", 47 | "R.methodsS3", 48 | "R.oo", 49 | "R.utils", 50 | "digest", 51 | "utils" 52 | ], 53 | "Hash": "fe539ca3f8efb7410c3ae2cf5fe6c0f8" 54 | }, 55 | "R.methodsS3": { 56 | "Package": "R.methodsS3", 57 | "Version": "1.8.2", 58 | "Source": "Repository", 59 | "Repository": "CRAN", 60 | "Requirements": [ 61 | "R", 62 | "utils" 63 | ], 64 | "Hash": "278c286fd6e9e75d0c2e8f731ea445c8" 65 | }, 66 | "R.oo": { 67 | "Package": "R.oo", 68 | "Version": "1.26.0", 69 | "Source": "Repository", 70 | "Repository": "CRAN", 71 | "Requirements": [ 72 | "R", 73 | "R.methodsS3", 74 | "methods", 75 | "utils" 76 | ], 77 | "Hash": "4fed809e53ddb5407b3da3d0f572e591" 78 | }, 79 | "R.utils": { 80 | "Package": "R.utils", 81 | "Version": "2.12.3", 82 | "Source": "Repository", 83 | "Repository": "CRAN", 84 | "Requirements": [ 85 | "R", 86 | "R.methodsS3", 87 | "R.oo", 88 | "methods", 89 | "tools", 90 | "utils" 91 | ], 92 | "Hash": "3dc2829b790254bfba21e60965787651" 93 | }, 94 | "R6": { 95 | "Package": "R6", 96 | "Version": "2.5.1", 97 | "Source": "Repository", 98 | "Repository": "CRAN", 99 | "Requirements": [ 100 | "R" 101 | ], 102 | "Hash": "470851b6d5d0ac559e9d01bb352b4021" 103 | }, 104 | "RSQLite": { 105 | "Package": "RSQLite", 106 | "Version": "2.3.6", 107 | "Source": "Repository", 108 | "Repository": "CRAN", 109 | "Requirements": [ 110 | "DBI", 111 | "R", 112 | "bit64", 113 | "blob", 114 | "cpp11", 115 | "memoise", 116 | "methods", 117 | "pkgconfig", 118 | "plogr", 119 | "rlang" 120 | ], 121 | "Hash": "ae4a925e0f6bb1b7e5fa96b739c5221a" 122 | }, 123 | "Rcpp": { 124 | "Package": "Rcpp", 125 | "Version": "1.0.12", 126 | "Source": "Repository", 127 | "Repository": "CRAN", 128 | "Requirements": [ 129 | "methods", 130 | "utils" 131 | ], 132 | "Hash": "5ea2700d21e038ace58269ecdbeb9ec0" 133 | }, 134 | "backports": { 135 | "Package": "backports", 136 | "Version": "1.4.1", 137 | "Source": "Repository", 138 | "Repository": "CRAN", 139 | "Requirements": [ 140 | "R" 141 | ], 142 | "Hash": "c39fbec8a30d23e721980b8afb31984c" 143 | }, 144 | "base64enc": { 145 | "Package": "base64enc", 146 | "Version": "0.1-3", 147 | "Source": "Repository", 148 | "Repository": "CRAN", 149 | "Requirements": [ 150 | "R" 151 | ], 152 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 153 | }, 154 | "bit": { 155 | "Package": "bit", 156 | "Version": "4.0.5", 157 | "Source": "Repository", 158 | "Repository": "RSPM", 159 | "Requirements": [ 160 | "R" 161 | ], 162 | "Hash": "d242abec29412ce988848d0294b208fd" 163 | }, 164 | "bit64": { 165 | "Package": "bit64", 166 | "Version": "4.0.5", 167 | "Source": "Repository", 168 | "Repository": "RSPM", 169 | "Requirements": [ 170 | "R", 171 | "bit", 172 | "methods", 173 | "stats", 174 | "utils" 175 | ], 176 | "Hash": "9fe98599ca456d6552421db0d6772d8f" 177 | }, 178 | "blob": { 179 | "Package": "blob", 180 | "Version": "1.2.4", 181 | "Source": "Repository", 182 | "Repository": "RSPM", 183 | "Requirements": [ 184 | "methods", 185 | "rlang", 186 | "vctrs" 187 | ], 188 | "Hash": "40415719b5a479b87949f3aa0aee737c" 189 | }, 190 | "box": { 191 | "Package": "box", 192 | "Version": "1.2.0", 193 | "Source": "Repository", 194 | "Repository": "CRAN", 195 | "Requirements": [ 196 | "R", 197 | "tools" 198 | ], 199 | "Hash": "d94049c1d9446b0abb413fde9e82a505" 200 | }, 201 | "brio": { 202 | "Package": "brio", 203 | "Version": "1.1.4", 204 | "Source": "Repository", 205 | "Repository": "CRAN", 206 | "Requirements": [ 207 | "R" 208 | ], 209 | "Hash": "68bd2b066e1fe780bbf62fc8bcc36de3" 210 | }, 211 | "bslib": { 212 | "Package": "bslib", 213 | "Version": "0.7.0", 214 | "Source": "Repository", 215 | "Repository": "CRAN", 216 | "Requirements": [ 217 | "R", 218 | "base64enc", 219 | "cachem", 220 | "fastmap", 221 | "grDevices", 222 | "htmltools", 223 | "jquerylib", 224 | "jsonlite", 225 | "lifecycle", 226 | "memoise", 227 | "mime", 228 | "rlang", 229 | "sass" 230 | ], 231 | "Hash": "8644cc53f43828f19133548195d7e59e" 232 | }, 233 | "cachem": { 234 | "Package": "cachem", 235 | "Version": "1.0.8", 236 | "Source": "Repository", 237 | "Repository": "CRAN", 238 | "Requirements": [ 239 | "fastmap", 240 | "rlang" 241 | ], 242 | "Hash": "c35768291560ce302c0a6589f92e837d" 243 | }, 244 | "callr": { 245 | "Package": "callr", 246 | "Version": "3.7.6", 247 | "Source": "Repository", 248 | "Repository": "CRAN", 249 | "Requirements": [ 250 | "R", 251 | "R6", 252 | "processx", 253 | "utils" 254 | ], 255 | "Hash": "d7e13f49c19103ece9e58ad2d83a7354" 256 | }, 257 | "cli": { 258 | "Package": "cli", 259 | "Version": "3.6.2", 260 | "Source": "Repository", 261 | "Repository": "CRAN", 262 | "Requirements": [ 263 | "R", 264 | "utils" 265 | ], 266 | "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" 267 | }, 268 | "codetools": { 269 | "Package": "codetools", 270 | "Version": "0.2-20", 271 | "Source": "Repository", 272 | "Repository": "CRAN", 273 | "Requirements": [ 274 | "R" 275 | ], 276 | "Hash": "61e097f35917d342622f21cdc79c256e" 277 | }, 278 | "commonmark": { 279 | "Package": "commonmark", 280 | "Version": "1.9.1", 281 | "Source": "Repository", 282 | "Repository": "CRAN", 283 | "Hash": "5d8225445acb167abf7797de48b2ee3c" 284 | }, 285 | "config": { 286 | "Package": "config", 287 | "Version": "0.3.2", 288 | "Source": "Repository", 289 | "Repository": "CRAN", 290 | "Requirements": [ 291 | "yaml" 292 | ], 293 | "Hash": "8b7222e9d9eb5178eea545c0c4d33fc2" 294 | }, 295 | "cpp11": { 296 | "Package": "cpp11", 297 | "Version": "0.4.7", 298 | "Source": "Repository", 299 | "Repository": "RSPM", 300 | "Requirements": [ 301 | "R" 302 | ], 303 | "Hash": "5a295d7d963cc5035284dcdbaf334f4e" 304 | }, 305 | "crayon": { 306 | "Package": "crayon", 307 | "Version": "1.5.2", 308 | "Source": "Repository", 309 | "Repository": "CRAN", 310 | "Requirements": [ 311 | "grDevices", 312 | "methods", 313 | "utils" 314 | ], 315 | "Hash": "e8a1e41acf02548751f45c718d55aa6a" 316 | }, 317 | "crosstalk": { 318 | "Package": "crosstalk", 319 | "Version": "1.2.1", 320 | "Source": "Repository", 321 | "Repository": "RSPM", 322 | "Requirements": [ 323 | "R6", 324 | "htmltools", 325 | "jsonlite", 326 | "lazyeval" 327 | ], 328 | "Hash": "ab12c7b080a57475248a30f4db6298c0" 329 | }, 330 | "cyclocomp": { 331 | "Package": "cyclocomp", 332 | "Version": "1.1.1", 333 | "Source": "Repository", 334 | "Repository": "CRAN", 335 | "Requirements": [ 336 | "callr", 337 | "crayon", 338 | "desc", 339 | "remotes", 340 | "withr" 341 | ], 342 | "Hash": "cdc4a473222b0112d4df0bcfbed12d44" 343 | }, 344 | "dbplyr": { 345 | "Package": "dbplyr", 346 | "Version": "2.5.0", 347 | "Source": "Repository", 348 | "Repository": "CRAN", 349 | "Requirements": [ 350 | "DBI", 351 | "R", 352 | "R6", 353 | "blob", 354 | "cli", 355 | "dplyr", 356 | "glue", 357 | "lifecycle", 358 | "magrittr", 359 | "methods", 360 | "pillar", 361 | "purrr", 362 | "rlang", 363 | "tibble", 364 | "tidyr", 365 | "tidyselect", 366 | "utils", 367 | "vctrs", 368 | "withr" 369 | ], 370 | "Hash": "39b2e002522bfd258039ee4e889e0fd1" 371 | }, 372 | "desc": { 373 | "Package": "desc", 374 | "Version": "1.4.3", 375 | "Source": "Repository", 376 | "Repository": "CRAN", 377 | "Requirements": [ 378 | "R", 379 | "R6", 380 | "cli", 381 | "utils" 382 | ], 383 | "Hash": "99b79fcbd6c4d1ce087f5c5c758b384f" 384 | }, 385 | "diffobj": { 386 | "Package": "diffobj", 387 | "Version": "0.3.5", 388 | "Source": "Repository", 389 | "Repository": "CRAN", 390 | "Requirements": [ 391 | "R", 392 | "crayon", 393 | "methods", 394 | "stats", 395 | "tools", 396 | "utils" 397 | ], 398 | "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8" 399 | }, 400 | "digest": { 401 | "Package": "digest", 402 | "Version": "0.6.35", 403 | "Source": "Repository", 404 | "Repository": "CRAN", 405 | "Requirements": [ 406 | "R", 407 | "utils" 408 | ], 409 | "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" 410 | }, 411 | "dplyr": { 412 | "Package": "dplyr", 413 | "Version": "1.1.4", 414 | "Source": "Repository", 415 | "Repository": "CRAN", 416 | "Requirements": [ 417 | "R", 418 | "R6", 419 | "cli", 420 | "generics", 421 | "glue", 422 | "lifecycle", 423 | "magrittr", 424 | "methods", 425 | "pillar", 426 | "rlang", 427 | "tibble", 428 | "tidyselect", 429 | "utils", 430 | "vctrs" 431 | ], 432 | "Hash": "fedd9d00c2944ff00a0e2696ccf048ec" 433 | }, 434 | "evaluate": { 435 | "Package": "evaluate", 436 | "Version": "0.23", 437 | "Source": "Repository", 438 | "Repository": "CRAN", 439 | "Requirements": [ 440 | "R", 441 | "methods" 442 | ], 443 | "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" 444 | }, 445 | "fansi": { 446 | "Package": "fansi", 447 | "Version": "1.0.6", 448 | "Source": "Repository", 449 | "Repository": "CRAN", 450 | "Requirements": [ 451 | "R", 452 | "grDevices", 453 | "utils" 454 | ], 455 | "Hash": "962174cf2aeb5b9eea581522286a911f" 456 | }, 457 | "fastmap": { 458 | "Package": "fastmap", 459 | "Version": "1.1.1", 460 | "Source": "Repository", 461 | "Repository": "CRAN", 462 | "Hash": "f7736a18de97dea803bde0a2daaafb27" 463 | }, 464 | "fontawesome": { 465 | "Package": "fontawesome", 466 | "Version": "0.5.2", 467 | "Source": "Repository", 468 | "Repository": "CRAN", 469 | "Requirements": [ 470 | "R", 471 | "htmltools", 472 | "rlang" 473 | ], 474 | "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" 475 | }, 476 | "fs": { 477 | "Package": "fs", 478 | "Version": "1.6.3", 479 | "Source": "Repository", 480 | "Repository": "CRAN", 481 | "Requirements": [ 482 | "R", 483 | "methods" 484 | ], 485 | "Hash": "47b5f30c720c23999b913a1a635cf0bb" 486 | }, 487 | "generics": { 488 | "Package": "generics", 489 | "Version": "0.1.3", 490 | "Source": "Repository", 491 | "Repository": "CRAN", 492 | "Requirements": [ 493 | "R", 494 | "methods" 495 | ], 496 | "Hash": "15e9634c0fcd294799e9b2e929ed1b86" 497 | }, 498 | "glue": { 499 | "Package": "glue", 500 | "Version": "1.7.0", 501 | "Source": "Repository", 502 | "Repository": "CRAN", 503 | "Requirements": [ 504 | "R", 505 | "methods" 506 | ], 507 | "Hash": "e0b3a53876554bd45879e596cdb10a52" 508 | }, 509 | "highr": { 510 | "Package": "highr", 511 | "Version": "0.10", 512 | "Source": "Repository", 513 | "Repository": "CRAN", 514 | "Requirements": [ 515 | "R", 516 | "xfun" 517 | ], 518 | "Hash": "06230136b2d2b9ba5805e1963fa6e890" 519 | }, 520 | "htmltools": { 521 | "Package": "htmltools", 522 | "Version": "0.5.8.1", 523 | "Source": "Repository", 524 | "Repository": "CRAN", 525 | "Requirements": [ 526 | "R", 527 | "base64enc", 528 | "digest", 529 | "fastmap", 530 | "grDevices", 531 | "rlang", 532 | "utils" 533 | ], 534 | "Hash": "81d371a9cc60640e74e4ab6ac46dcedc" 535 | }, 536 | "htmlwidgets": { 537 | "Package": "htmlwidgets", 538 | "Version": "1.6.4", 539 | "Source": "Repository", 540 | "Repository": "RSPM", 541 | "Requirements": [ 542 | "grDevices", 543 | "htmltools", 544 | "jsonlite", 545 | "knitr", 546 | "rmarkdown", 547 | "yaml" 548 | ], 549 | "Hash": "04291cc45198225444a397606810ac37" 550 | }, 551 | "httpuv": { 552 | "Package": "httpuv", 553 | "Version": "1.6.15", 554 | "Source": "Repository", 555 | "Repository": "CRAN", 556 | "Requirements": [ 557 | "R", 558 | "R6", 559 | "Rcpp", 560 | "later", 561 | "promises", 562 | "utils" 563 | ], 564 | "Hash": "d55aa087c47a63ead0f6fc10f8fa1ee0" 565 | }, 566 | "jquerylib": { 567 | "Package": "jquerylib", 568 | "Version": "0.1.4", 569 | "Source": "Repository", 570 | "Repository": "CRAN", 571 | "Requirements": [ 572 | "htmltools" 573 | ], 574 | "Hash": "5aab57a3bd297eee1c1d862735972182" 575 | }, 576 | "jsonlite": { 577 | "Package": "jsonlite", 578 | "Version": "1.8.8", 579 | "Source": "Repository", 580 | "Repository": "CRAN", 581 | "Requirements": [ 582 | "methods" 583 | ], 584 | "Hash": "e1b9c55281c5adc4dd113652d9e26768" 585 | }, 586 | "knitr": { 587 | "Package": "knitr", 588 | "Version": "1.46", 589 | "Source": "Repository", 590 | "Repository": "CRAN", 591 | "Requirements": [ 592 | "R", 593 | "evaluate", 594 | "highr", 595 | "methods", 596 | "tools", 597 | "xfun", 598 | "yaml" 599 | ], 600 | "Hash": "6e008ab1d696a5283c79765fa7b56b47" 601 | }, 602 | "later": { 603 | "Package": "later", 604 | "Version": "1.3.2", 605 | "Source": "Repository", 606 | "Repository": "CRAN", 607 | "Requirements": [ 608 | "Rcpp", 609 | "rlang" 610 | ], 611 | "Hash": "a3e051d405326b8b0012377434c62b37" 612 | }, 613 | "lazyeval": { 614 | "Package": "lazyeval", 615 | "Version": "0.2.2", 616 | "Source": "Repository", 617 | "Repository": "CRAN", 618 | "Requirements": [ 619 | "R" 620 | ], 621 | "Hash": "d908914ae53b04d4c0c0fd72ecc35370" 622 | }, 623 | "lifecycle": { 624 | "Package": "lifecycle", 625 | "Version": "1.0.4", 626 | "Source": "Repository", 627 | "Repository": "CRAN", 628 | "Requirements": [ 629 | "R", 630 | "cli", 631 | "glue", 632 | "rlang" 633 | ], 634 | "Hash": "b8552d117e1b808b09a832f589b79035" 635 | }, 636 | "lintr": { 637 | "Package": "lintr", 638 | "Version": "3.1.2", 639 | "Source": "Repository", 640 | "Repository": "CRAN", 641 | "Requirements": [ 642 | "R", 643 | "backports", 644 | "codetools", 645 | "cyclocomp", 646 | "digest", 647 | "glue", 648 | "knitr", 649 | "rex", 650 | "stats", 651 | "utils", 652 | "xml2", 653 | "xmlparsedata" 654 | ], 655 | "Hash": "08cff46381a242d44c0d8dd0aabd9f71" 656 | }, 657 | "logger": { 658 | "Package": "logger", 659 | "Version": "0.3.0", 660 | "Source": "Repository", 661 | "Repository": "CRAN", 662 | "Requirements": [ 663 | "utils" 664 | ], 665 | "Hash": "c145edf05cc128e6ffcfa5d872c46329" 666 | }, 667 | "magrittr": { 668 | "Package": "magrittr", 669 | "Version": "2.0.3", 670 | "Source": "Repository", 671 | "Repository": "CRAN", 672 | "Requirements": [ 673 | "R" 674 | ], 675 | "Hash": "7ce2733a9826b3aeb1775d56fd305472" 676 | }, 677 | "memoise": { 678 | "Package": "memoise", 679 | "Version": "2.0.1", 680 | "Source": "Repository", 681 | "Repository": "CRAN", 682 | "Requirements": [ 683 | "cachem", 684 | "rlang" 685 | ], 686 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" 687 | }, 688 | "mime": { 689 | "Package": "mime", 690 | "Version": "0.12", 691 | "Source": "Repository", 692 | "Repository": "CRAN", 693 | "Requirements": [ 694 | "tools" 695 | ], 696 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104" 697 | }, 698 | "pillar": { 699 | "Package": "pillar", 700 | "Version": "1.9.0", 701 | "Source": "Repository", 702 | "Repository": "CRAN", 703 | "Requirements": [ 704 | "cli", 705 | "fansi", 706 | "glue", 707 | "lifecycle", 708 | "rlang", 709 | "utf8", 710 | "utils", 711 | "vctrs" 712 | ], 713 | "Hash": "15da5a8412f317beeee6175fbc76f4bb" 714 | }, 715 | "pkgbuild": { 716 | "Package": "pkgbuild", 717 | "Version": "1.4.4", 718 | "Source": "Repository", 719 | "Repository": "CRAN", 720 | "Requirements": [ 721 | "R", 722 | "R6", 723 | "callr", 724 | "cli", 725 | "desc", 726 | "processx" 727 | ], 728 | "Hash": "a29e8e134a460a01e0ca67a4763c595b" 729 | }, 730 | "pkgconfig": { 731 | "Package": "pkgconfig", 732 | "Version": "2.0.3", 733 | "Source": "Repository", 734 | "Repository": "CRAN", 735 | "Requirements": [ 736 | "utils" 737 | ], 738 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 739 | }, 740 | "pkgload": { 741 | "Package": "pkgload", 742 | "Version": "1.3.4", 743 | "Source": "Repository", 744 | "Repository": "CRAN", 745 | "Requirements": [ 746 | "R", 747 | "cli", 748 | "crayon", 749 | "desc", 750 | "fs", 751 | "glue", 752 | "methods", 753 | "pkgbuild", 754 | "rlang", 755 | "rprojroot", 756 | "utils", 757 | "withr" 758 | ], 759 | "Hash": "876c618df5ae610be84356d5d7a5d124" 760 | }, 761 | "plogr": { 762 | "Package": "plogr", 763 | "Version": "0.2.0", 764 | "Source": "Repository", 765 | "Repository": "RSPM", 766 | "Hash": "09eb987710984fc2905c7129c7d85e65" 767 | }, 768 | "pool": { 769 | "Package": "pool", 770 | "Version": "1.0.3", 771 | "Source": "Repository", 772 | "Repository": "CRAN", 773 | "Requirements": [ 774 | "DBI", 775 | "R", 776 | "R6", 777 | "later", 778 | "methods", 779 | "rlang" 780 | ], 781 | "Hash": "b336b9f1b3cc72033258c70dc17edbf1" 782 | }, 783 | "praise": { 784 | "Package": "praise", 785 | "Version": "1.0.0", 786 | "Source": "Repository", 787 | "Repository": "CRAN", 788 | "Hash": "a555924add98c99d2f411e37e7d25e9f" 789 | }, 790 | "processx": { 791 | "Package": "processx", 792 | "Version": "3.8.4", 793 | "Source": "Repository", 794 | "Repository": "CRAN", 795 | "Requirements": [ 796 | "R", 797 | "R6", 798 | "ps", 799 | "utils" 800 | ], 801 | "Hash": "0c90a7d71988856bad2a2a45dd871bb9" 802 | }, 803 | "promises": { 804 | "Package": "promises", 805 | "Version": "1.3.0", 806 | "Source": "Repository", 807 | "Repository": "CRAN", 808 | "Requirements": [ 809 | "R6", 810 | "Rcpp", 811 | "fastmap", 812 | "later", 813 | "magrittr", 814 | "rlang", 815 | "stats" 816 | ], 817 | "Hash": "434cd5388a3979e74be5c219bcd6e77d" 818 | }, 819 | "ps": { 820 | "Package": "ps", 821 | "Version": "1.7.6", 822 | "Source": "Repository", 823 | "Repository": "CRAN", 824 | "Requirements": [ 825 | "R", 826 | "utils" 827 | ], 828 | "Hash": "dd2b9319ee0656c8acf45c7f40c59de7" 829 | }, 830 | "purrr": { 831 | "Package": "purrr", 832 | "Version": "1.0.2", 833 | "Source": "Repository", 834 | "Repository": "CRAN", 835 | "Requirements": [ 836 | "R", 837 | "cli", 838 | "lifecycle", 839 | "magrittr", 840 | "rlang", 841 | "vctrs" 842 | ], 843 | "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" 844 | }, 845 | "rappdirs": { 846 | "Package": "rappdirs", 847 | "Version": "0.3.3", 848 | "Source": "Repository", 849 | "Repository": "CRAN", 850 | "Requirements": [ 851 | "R" 852 | ], 853 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d" 854 | }, 855 | "rematch2": { 856 | "Package": "rematch2", 857 | "Version": "2.1.2", 858 | "Source": "Repository", 859 | "Repository": "CRAN", 860 | "Requirements": [ 861 | "tibble" 862 | ], 863 | "Hash": "76c9e04c712a05848ae7a23d2f170a40" 864 | }, 865 | "remotes": { 866 | "Package": "remotes", 867 | "Version": "2.5.0", 868 | "Source": "Repository", 869 | "Repository": "CRAN", 870 | "Requirements": [ 871 | "R", 872 | "methods", 873 | "stats", 874 | "tools", 875 | "utils" 876 | ], 877 | "Hash": "3ee025083e66f18db6cf27b56e23e141" 878 | }, 879 | "renv": { 880 | "Package": "renv", 881 | "Version": "1.0.7", 882 | "Source": "Repository", 883 | "Repository": "CRAN", 884 | "Requirements": [ 885 | "utils" 886 | ], 887 | "Hash": "397b7b2a265bc5a7a06852524dabae20" 888 | }, 889 | "rex": { 890 | "Package": "rex", 891 | "Version": "1.2.1", 892 | "Source": "Repository", 893 | "Repository": "CRAN", 894 | "Requirements": [ 895 | "lazyeval" 896 | ], 897 | "Hash": "ae34cd56890607370665bee5bd17812f" 898 | }, 899 | "rhino": { 900 | "Package": "rhino", 901 | "Version": "1.7.0", 902 | "Source": "Repository", 903 | "Repository": "CRAN", 904 | "Requirements": [ 905 | "R", 906 | "box", 907 | "cli", 908 | "config", 909 | "fs", 910 | "glue", 911 | "lintr", 912 | "logger", 913 | "purrr", 914 | "renv", 915 | "rstudioapi", 916 | "sass", 917 | "shiny", 918 | "styler", 919 | "testthat", 920 | "utils", 921 | "withr", 922 | "xml2", 923 | "yaml" 924 | ], 925 | "Hash": "59ee79b26dd590b08dd1a3111d093832" 926 | }, 927 | "rlang": { 928 | "Package": "rlang", 929 | "Version": "1.1.3", 930 | "Source": "Repository", 931 | "Repository": "CRAN", 932 | "Requirements": [ 933 | "R", 934 | "utils" 935 | ], 936 | "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" 937 | }, 938 | "rmarkdown": { 939 | "Package": "rmarkdown", 940 | "Version": "2.26", 941 | "Source": "Repository", 942 | "Repository": "CRAN", 943 | "Requirements": [ 944 | "R", 945 | "bslib", 946 | "evaluate", 947 | "fontawesome", 948 | "htmltools", 949 | "jquerylib", 950 | "jsonlite", 951 | "knitr", 952 | "methods", 953 | "tinytex", 954 | "tools", 955 | "utils", 956 | "xfun", 957 | "yaml" 958 | ], 959 | "Hash": "9b148e7f95d33aac01f31282d49e4f44" 960 | }, 961 | "rprojroot": { 962 | "Package": "rprojroot", 963 | "Version": "2.0.4", 964 | "Source": "Repository", 965 | "Repository": "CRAN", 966 | "Requirements": [ 967 | "R" 968 | ], 969 | "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144" 970 | }, 971 | "rstudioapi": { 972 | "Package": "rstudioapi", 973 | "Version": "0.16.0", 974 | "Source": "Repository", 975 | "Repository": "CRAN", 976 | "Hash": "96710351d642b70e8f02ddeb237c46a7" 977 | }, 978 | "sass": { 979 | "Package": "sass", 980 | "Version": "0.4.9", 981 | "Source": "Repository", 982 | "Repository": "CRAN", 983 | "Requirements": [ 984 | "R6", 985 | "fs", 986 | "htmltools", 987 | "rappdirs", 988 | "rlang" 989 | ], 990 | "Hash": "d53dbfddf695303ea4ad66f86e99b95d" 991 | }, 992 | "shiny": { 993 | "Package": "shiny", 994 | "Version": "1.8.1.1", 995 | "Source": "Repository", 996 | "Repository": "CRAN", 997 | "Requirements": [ 998 | "R", 999 | "R6", 1000 | "bslib", 1001 | "cachem", 1002 | "commonmark", 1003 | "crayon", 1004 | "fastmap", 1005 | "fontawesome", 1006 | "glue", 1007 | "grDevices", 1008 | "htmltools", 1009 | "httpuv", 1010 | "jsonlite", 1011 | "later", 1012 | "lifecycle", 1013 | "methods", 1014 | "mime", 1015 | "promises", 1016 | "rlang", 1017 | "sourcetools", 1018 | "tools", 1019 | "utils", 1020 | "withr", 1021 | "xtable" 1022 | ], 1023 | "Hash": "54b26646816af9960a4c64d8ceec75d6" 1024 | }, 1025 | "sourcetools": { 1026 | "Package": "sourcetools", 1027 | "Version": "0.1.7-1", 1028 | "Source": "Repository", 1029 | "Repository": "CRAN", 1030 | "Requirements": [ 1031 | "R" 1032 | ], 1033 | "Hash": "5f5a7629f956619d519205ec475fe647" 1034 | }, 1035 | "stringi": { 1036 | "Package": "stringi", 1037 | "Version": "1.8.3", 1038 | "Source": "Repository", 1039 | "Repository": "RSPM", 1040 | "Requirements": [ 1041 | "R", 1042 | "stats", 1043 | "tools", 1044 | "utils" 1045 | ], 1046 | "Hash": "058aebddea264f4c99401515182e656a" 1047 | }, 1048 | "stringr": { 1049 | "Package": "stringr", 1050 | "Version": "1.5.1", 1051 | "Source": "Repository", 1052 | "Repository": "RSPM", 1053 | "Requirements": [ 1054 | "R", 1055 | "cli", 1056 | "glue", 1057 | "lifecycle", 1058 | "magrittr", 1059 | "rlang", 1060 | "stringi", 1061 | "vctrs" 1062 | ], 1063 | "Hash": "960e2ae9e09656611e0b8214ad543207" 1064 | }, 1065 | "styler": { 1066 | "Package": "styler", 1067 | "Version": "1.10.3", 1068 | "Source": "Repository", 1069 | "Repository": "CRAN", 1070 | "Requirements": [ 1071 | "R", 1072 | "R.cache", 1073 | "cli", 1074 | "magrittr", 1075 | "purrr", 1076 | "rlang", 1077 | "rprojroot", 1078 | "tools", 1079 | "vctrs", 1080 | "withr" 1081 | ], 1082 | "Hash": "93a2b1beac2437bdcc4724f8bf867e2c" 1083 | }, 1084 | "testthat": { 1085 | "Package": "testthat", 1086 | "Version": "3.2.1.1", 1087 | "Source": "Repository", 1088 | "Repository": "CRAN", 1089 | "Requirements": [ 1090 | "R", 1091 | "R6", 1092 | "brio", 1093 | "callr", 1094 | "cli", 1095 | "desc", 1096 | "digest", 1097 | "evaluate", 1098 | "jsonlite", 1099 | "lifecycle", 1100 | "magrittr", 1101 | "methods", 1102 | "pkgload", 1103 | "praise", 1104 | "processx", 1105 | "ps", 1106 | "rlang", 1107 | "utils", 1108 | "waldo", 1109 | "withr" 1110 | ], 1111 | "Hash": "3f6e7e5e2220856ff865e4834766bf2b" 1112 | }, 1113 | "tibble": { 1114 | "Package": "tibble", 1115 | "Version": "3.2.1", 1116 | "Source": "Repository", 1117 | "Repository": "CRAN", 1118 | "Requirements": [ 1119 | "R", 1120 | "fansi", 1121 | "lifecycle", 1122 | "magrittr", 1123 | "methods", 1124 | "pillar", 1125 | "pkgconfig", 1126 | "rlang", 1127 | "utils", 1128 | "vctrs" 1129 | ], 1130 | "Hash": "a84e2cc86d07289b3b6f5069df7a004c" 1131 | }, 1132 | "tidyr": { 1133 | "Package": "tidyr", 1134 | "Version": "1.3.1", 1135 | "Source": "Repository", 1136 | "Repository": "CRAN", 1137 | "Requirements": [ 1138 | "R", 1139 | "cli", 1140 | "cpp11", 1141 | "dplyr", 1142 | "glue", 1143 | "lifecycle", 1144 | "magrittr", 1145 | "purrr", 1146 | "rlang", 1147 | "stringr", 1148 | "tibble", 1149 | "tidyselect", 1150 | "utils", 1151 | "vctrs" 1152 | ], 1153 | "Hash": "915fb7ce036c22a6a33b5a8adb712eb1" 1154 | }, 1155 | "tidyselect": { 1156 | "Package": "tidyselect", 1157 | "Version": "1.2.1", 1158 | "Source": "Repository", 1159 | "Repository": "CRAN", 1160 | "Requirements": [ 1161 | "R", 1162 | "cli", 1163 | "glue", 1164 | "lifecycle", 1165 | "rlang", 1166 | "vctrs", 1167 | "withr" 1168 | ], 1169 | "Hash": "829f27b9c4919c16b593794a6344d6c0" 1170 | }, 1171 | "tinytex": { 1172 | "Package": "tinytex", 1173 | "Version": "0.50", 1174 | "Source": "Repository", 1175 | "Repository": "CRAN", 1176 | "Requirements": [ 1177 | "xfun" 1178 | ], 1179 | "Hash": "be7a76845222ad20adb761f462eed3ea" 1180 | }, 1181 | "utf8": { 1182 | "Package": "utf8", 1183 | "Version": "1.2.4", 1184 | "Source": "Repository", 1185 | "Repository": "CRAN", 1186 | "Requirements": [ 1187 | "R" 1188 | ], 1189 | "Hash": "62b65c52671e6665f803ff02954446e9" 1190 | }, 1191 | "vctrs": { 1192 | "Package": "vctrs", 1193 | "Version": "0.6.5", 1194 | "Source": "Repository", 1195 | "Repository": "CRAN", 1196 | "Requirements": [ 1197 | "R", 1198 | "cli", 1199 | "glue", 1200 | "lifecycle", 1201 | "rlang" 1202 | ], 1203 | "Hash": "c03fa420630029418f7e6da3667aac4a" 1204 | }, 1205 | "waldo": { 1206 | "Package": "waldo", 1207 | "Version": "0.5.2", 1208 | "Source": "Repository", 1209 | "Repository": "CRAN", 1210 | "Requirements": [ 1211 | "R", 1212 | "cli", 1213 | "diffobj", 1214 | "fansi", 1215 | "glue", 1216 | "methods", 1217 | "rematch2", 1218 | "rlang", 1219 | "tibble" 1220 | ], 1221 | "Hash": "c7d3fd6d29ab077cbac8f0e2751449e6" 1222 | }, 1223 | "withr": { 1224 | "Package": "withr", 1225 | "Version": "3.0.0", 1226 | "Source": "Repository", 1227 | "Repository": "CRAN", 1228 | "Requirements": [ 1229 | "R", 1230 | "grDevices", 1231 | "graphics" 1232 | ], 1233 | "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" 1234 | }, 1235 | "xfun": { 1236 | "Package": "xfun", 1237 | "Version": "0.43", 1238 | "Source": "Repository", 1239 | "Repository": "CRAN", 1240 | "Requirements": [ 1241 | "grDevices", 1242 | "stats", 1243 | "tools" 1244 | ], 1245 | "Hash": "ab6371d8653ce5f2f9290f4ec7b42a8e" 1246 | }, 1247 | "xml2": { 1248 | "Package": "xml2", 1249 | "Version": "1.3.6", 1250 | "Source": "Repository", 1251 | "Repository": "CRAN", 1252 | "Requirements": [ 1253 | "R", 1254 | "cli", 1255 | "methods", 1256 | "rlang" 1257 | ], 1258 | "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61" 1259 | }, 1260 | "xmlparsedata": { 1261 | "Package": "xmlparsedata", 1262 | "Version": "1.0.5", 1263 | "Source": "Repository", 1264 | "Repository": "CRAN", 1265 | "Requirements": [ 1266 | "R" 1267 | ], 1268 | "Hash": "45e4bf3c46476896e821fc0a408fb4fc" 1269 | }, 1270 | "xtable": { 1271 | "Package": "xtable", 1272 | "Version": "1.8-4", 1273 | "Source": "Repository", 1274 | "Repository": "CRAN", 1275 | "Requirements": [ 1276 | "R", 1277 | "stats", 1278 | "utils" 1279 | ], 1280 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 1281 | }, 1282 | "yaml": { 1283 | "Package": "yaml", 1284 | "Version": "2.3.8", 1285 | "Source": "Repository", 1286 | "Repository": "CRAN", 1287 | "Hash": "29240487a071f535f5e5d5a323b7afbd" 1288 | } 1289 | } 1290 | } 1291 | -------------------------------------------------------------------------------- /task3/renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | local/ 3 | cellar/ 4 | lock/ 5 | python/ 6 | sandbox/ 7 | staging/ 8 | -------------------------------------------------------------------------------- /task3/renv/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "bioconductor.version": null, 3 | "external.libraries": [], 4 | "ignored.packages": [], 5 | "package.dependency.fields": [ 6 | "Imports", 7 | "Depends", 8 | "LinkingTo" 9 | ], 10 | "ppm.enabled": null, 11 | "ppm.ignored.urls": [], 12 | "r.version": null, 13 | "snapshot.type": "implicit", 14 | "use.cache": true, 15 | "vcs.ignore.cellar": true, 16 | "vcs.ignore.library": true, 17 | "vcs.ignore.local": true, 18 | "vcs.manage.ignores": true 19 | } 20 | -------------------------------------------------------------------------------- /task3/rhino.yml: -------------------------------------------------------------------------------- 1 | sass: node 2 | -------------------------------------------------------------------------------- /task3/task3.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 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 | LineEndingConversion: Posix 18 | -------------------------------------------------------------------------------- /task3/tests/cypress.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | e2e: { 3 | setupNodeEvents(on, config) {}, 4 | baseUrl: 'http://localhost:3333', 5 | supportFile: false, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /task3/tests/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | /screenshots/ 2 | /videos/ 3 | -------------------------------------------------------------------------------- /task3/tests/cypress/e2e/app.cy.js: -------------------------------------------------------------------------------- 1 | describe('app', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | it('starts', () => {}) 7 | }) 8 | -------------------------------------------------------------------------------- /task3/tests/testthat/test-main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny[testServer], 3 | testthat[expect_true, test_that], 4 | ) 5 | box::use( 6 | app/main[server, ui], 7 | ) 8 | 9 | test_that("main server works", { 10 | testServer(server, { 11 | expect_true(grepl(x = output$message$html, pattern = "Check out Rhino docs!")) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /task4/.Rprofile: -------------------------------------------------------------------------------- 1 | if (file.exists("renv")) { 2 | source("renv/activate.R") 3 | } else { 4 | # The `renv` directory is automatically skipped when deploying with rsconnect. 5 | message("No 'renv' directory found; renv won't be activated.") 6 | } 7 | 8 | # Allow absolute module imports (relative to the app root). 9 | options(box.path = getwd()) 10 | -------------------------------------------------------------------------------- /task4/.lintr: -------------------------------------------------------------------------------- 1 | linters: 2 | linters_with_defaults( 3 | line_length_linter = line_length_linter(100), 4 | box_func_import_count_linter = rhino::box_func_import_count_linter(), 5 | box_separate_calls_linter = rhino::box_separate_calls_linter(), 6 | box_trailing_commas_linter = rhino::box_trailing_commas_linter(), 7 | box_universal_import_linter = rhino::box_universal_import_linter(), 8 | object_usage_linter = NULL # Does not work with `box::use()`. 9 | ) 10 | -------------------------------------------------------------------------------- /task4/.renvignore: -------------------------------------------------------------------------------- 1 | # Only use `dependencies.R` to infer project dependencies. 2 | * 3 | !dependencies.R 4 | -------------------------------------------------------------------------------- /task4/.rscignore: -------------------------------------------------------------------------------- 1 | .github 2 | .lintr 3 | .renvignore 4 | .Renviron 5 | .rhino 6 | .rscignore 7 | tests 8 | -------------------------------------------------------------------------------- /task4/README.md: -------------------------------------------------------------------------------- 1 | # Task 4 2 | 3 | The [Sass Basics](https://sass-lang.com/guide/) articles 4 | will help you with these tasks. 5 | 6 | ### Step 1 7 | 8 | * Open `main.R`. 9 | * Move `style` to the `center` class in `app/styles/main.scss`. 10 | * Run `rhino::build_sass()` and check that the text is still centered. 11 | 12 | ### Step 2 13 | 14 | * Run `rhino::lint_sass()`. 15 | * Run `lint_sass(fix = TRUE)`. 16 | 17 | ### Step 3 18 | 19 | * Add `@use 'base';` to import the `_base.scss` module. 20 | * Use the variables defined in that module to set `font` and `color` on `body`. 21 | 22 | ### Step 4 23 | 24 | * Add some background to `body` with the `gradient` mixin. 25 | -------------------------------------------------------------------------------- /task4/app.R: -------------------------------------------------------------------------------- 1 | # Rhino / shinyApp entrypoint. Do not edit. 2 | rhino::app() 3 | -------------------------------------------------------------------------------- /task4/app/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task4/app/js/index.js -------------------------------------------------------------------------------- /task4/app/logic/__init__.R: -------------------------------------------------------------------------------- 1 | # Logic: application code independent from Shiny. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task4/app/main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | shiny[tags], 4 | ) 5 | 6 | #' @export 7 | ui <- function(id) { 8 | ns <- shiny$NS(id) 9 | shiny$fluidPage( 10 | shiny$div( 11 | # Step 1: 12 | style = "display: flex; justify-content: center; align-items: center; height: 100vh;", 13 | tags$h1("Hello!") 14 | ) 15 | ) 16 | } 17 | 18 | #' @export 19 | server <- function(id) { 20 | shiny$moduleServer(id, function(input, output, session) { 21 | 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /task4/app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task4/app/static/favicon.ico -------------------------------------------------------------------------------- /task4/app/styles/_base.scss: -------------------------------------------------------------------------------- 1 | $font-stack: Courier, monospace; 2 | $primary-color: #9d0000; 3 | 4 | @mixin gradient($theme: DarkGray) { 5 | background: radial-gradient(circle, $theme 30%, Black 100%); 6 | } 7 | -------------------------------------------------------------------------------- /task4/app/styles/main.scss: -------------------------------------------------------------------------------- 1 | // Step 3: 2 | // ? 3 | 4 | .center { 5 | // Step 1: 6 | // ? 7 | } 8 | 9 | body { 10 | // Step 4: 11 | // ? 12 | 13 | // Step 3: 14 | // ? 15 | } 16 | -------------------------------------------------------------------------------- /task4/app/view/__init__.R: -------------------------------------------------------------------------------- 1 | # View: Shiny modules and related code. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task4/config.yml: -------------------------------------------------------------------------------- 1 | default: 2 | rhino_log_level: !expr Sys.getenv("RHINO_LOG_LEVEL", "INFO") 3 | rhino_log_file: !expr Sys.getenv("RHINO_LOG_FILE", NA) 4 | -------------------------------------------------------------------------------- /task4/dependencies.R: -------------------------------------------------------------------------------- 1 | # This file allows packrat (used by rsconnect during deployment) to pick up dependencies. 2 | library(rhino) 3 | -------------------------------------------------------------------------------- /task4/renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.1.2", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cloud.r-project.org" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "R.cache": { 13 | "Package": "R.cache", 14 | "Version": "0.16.0", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Requirements": [ 18 | "R", 19 | "R.methodsS3", 20 | "R.oo", 21 | "R.utils", 22 | "digest", 23 | "utils" 24 | ], 25 | "Hash": "fe539ca3f8efb7410c3ae2cf5fe6c0f8" 26 | }, 27 | "R.methodsS3": { 28 | "Package": "R.methodsS3", 29 | "Version": "1.8.2", 30 | "Source": "Repository", 31 | "Repository": "CRAN", 32 | "Requirements": [ 33 | "R", 34 | "utils" 35 | ], 36 | "Hash": "278c286fd6e9e75d0c2e8f731ea445c8" 37 | }, 38 | "R.oo": { 39 | "Package": "R.oo", 40 | "Version": "1.26.0", 41 | "Source": "Repository", 42 | "Repository": "CRAN", 43 | "Requirements": [ 44 | "R", 45 | "R.methodsS3", 46 | "methods", 47 | "utils" 48 | ], 49 | "Hash": "4fed809e53ddb5407b3da3d0f572e591" 50 | }, 51 | "R.utils": { 52 | "Package": "R.utils", 53 | "Version": "2.12.3", 54 | "Source": "Repository", 55 | "Repository": "CRAN", 56 | "Requirements": [ 57 | "R", 58 | "R.methodsS3", 59 | "R.oo", 60 | "methods", 61 | "tools", 62 | "utils" 63 | ], 64 | "Hash": "3dc2829b790254bfba21e60965787651" 65 | }, 66 | "R6": { 67 | "Package": "R6", 68 | "Version": "2.5.1", 69 | "Source": "Repository", 70 | "Repository": "CRAN", 71 | "Requirements": [ 72 | "R" 73 | ], 74 | "Hash": "470851b6d5d0ac559e9d01bb352b4021" 75 | }, 76 | "Rcpp": { 77 | "Package": "Rcpp", 78 | "Version": "1.0.12", 79 | "Source": "Repository", 80 | "Repository": "CRAN", 81 | "Requirements": [ 82 | "methods", 83 | "utils" 84 | ], 85 | "Hash": "5ea2700d21e038ace58269ecdbeb9ec0" 86 | }, 87 | "backports": { 88 | "Package": "backports", 89 | "Version": "1.4.1", 90 | "Source": "Repository", 91 | "Repository": "CRAN", 92 | "Requirements": [ 93 | "R" 94 | ], 95 | "Hash": "c39fbec8a30d23e721980b8afb31984c" 96 | }, 97 | "base64enc": { 98 | "Package": "base64enc", 99 | "Version": "0.1-3", 100 | "Source": "Repository", 101 | "Repository": "CRAN", 102 | "Requirements": [ 103 | "R" 104 | ], 105 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 106 | }, 107 | "box": { 108 | "Package": "box", 109 | "Version": "1.2.0", 110 | "Source": "Repository", 111 | "Repository": "CRAN", 112 | "Requirements": [ 113 | "R", 114 | "tools" 115 | ], 116 | "Hash": "d94049c1d9446b0abb413fde9e82a505" 117 | }, 118 | "brio": { 119 | "Package": "brio", 120 | "Version": "1.1.4", 121 | "Source": "Repository", 122 | "Repository": "CRAN", 123 | "Requirements": [ 124 | "R" 125 | ], 126 | "Hash": "68bd2b066e1fe780bbf62fc8bcc36de3" 127 | }, 128 | "bslib": { 129 | "Package": "bslib", 130 | "Version": "0.7.0", 131 | "Source": "Repository", 132 | "Repository": "CRAN", 133 | "Requirements": [ 134 | "R", 135 | "base64enc", 136 | "cachem", 137 | "fastmap", 138 | "grDevices", 139 | "htmltools", 140 | "jquerylib", 141 | "jsonlite", 142 | "lifecycle", 143 | "memoise", 144 | "mime", 145 | "rlang", 146 | "sass" 147 | ], 148 | "Hash": "8644cc53f43828f19133548195d7e59e" 149 | }, 150 | "cachem": { 151 | "Package": "cachem", 152 | "Version": "1.0.8", 153 | "Source": "Repository", 154 | "Repository": "CRAN", 155 | "Requirements": [ 156 | "fastmap", 157 | "rlang" 158 | ], 159 | "Hash": "c35768291560ce302c0a6589f92e837d" 160 | }, 161 | "callr": { 162 | "Package": "callr", 163 | "Version": "3.7.6", 164 | "Source": "Repository", 165 | "Repository": "CRAN", 166 | "Requirements": [ 167 | "R", 168 | "R6", 169 | "processx", 170 | "utils" 171 | ], 172 | "Hash": "d7e13f49c19103ece9e58ad2d83a7354" 173 | }, 174 | "cli": { 175 | "Package": "cli", 176 | "Version": "3.6.2", 177 | "Source": "Repository", 178 | "Repository": "CRAN", 179 | "Requirements": [ 180 | "R", 181 | "utils" 182 | ], 183 | "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" 184 | }, 185 | "codetools": { 186 | "Package": "codetools", 187 | "Version": "0.2-20", 188 | "Source": "Repository", 189 | "Repository": "CRAN", 190 | "Requirements": [ 191 | "R" 192 | ], 193 | "Hash": "61e097f35917d342622f21cdc79c256e" 194 | }, 195 | "commonmark": { 196 | "Package": "commonmark", 197 | "Version": "1.9.1", 198 | "Source": "Repository", 199 | "Repository": "CRAN", 200 | "Hash": "5d8225445acb167abf7797de48b2ee3c" 201 | }, 202 | "config": { 203 | "Package": "config", 204 | "Version": "0.3.2", 205 | "Source": "Repository", 206 | "Repository": "CRAN", 207 | "Requirements": [ 208 | "yaml" 209 | ], 210 | "Hash": "8b7222e9d9eb5178eea545c0c4d33fc2" 211 | }, 212 | "crayon": { 213 | "Package": "crayon", 214 | "Version": "1.5.2", 215 | "Source": "Repository", 216 | "Repository": "CRAN", 217 | "Requirements": [ 218 | "grDevices", 219 | "methods", 220 | "utils" 221 | ], 222 | "Hash": "e8a1e41acf02548751f45c718d55aa6a" 223 | }, 224 | "cyclocomp": { 225 | "Package": "cyclocomp", 226 | "Version": "1.1.1", 227 | "Source": "Repository", 228 | "Repository": "CRAN", 229 | "Requirements": [ 230 | "callr", 231 | "crayon", 232 | "desc", 233 | "remotes", 234 | "withr" 235 | ], 236 | "Hash": "cdc4a473222b0112d4df0bcfbed12d44" 237 | }, 238 | "desc": { 239 | "Package": "desc", 240 | "Version": "1.4.3", 241 | "Source": "Repository", 242 | "Repository": "CRAN", 243 | "Requirements": [ 244 | "R", 245 | "R6", 246 | "cli", 247 | "utils" 248 | ], 249 | "Hash": "99b79fcbd6c4d1ce087f5c5c758b384f" 250 | }, 251 | "diffobj": { 252 | "Package": "diffobj", 253 | "Version": "0.3.5", 254 | "Source": "Repository", 255 | "Repository": "CRAN", 256 | "Requirements": [ 257 | "R", 258 | "crayon", 259 | "methods", 260 | "stats", 261 | "tools", 262 | "utils" 263 | ], 264 | "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8" 265 | }, 266 | "digest": { 267 | "Package": "digest", 268 | "Version": "0.6.35", 269 | "Source": "Repository", 270 | "Repository": "CRAN", 271 | "Requirements": [ 272 | "R", 273 | "utils" 274 | ], 275 | "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" 276 | }, 277 | "evaluate": { 278 | "Package": "evaluate", 279 | "Version": "0.23", 280 | "Source": "Repository", 281 | "Repository": "CRAN", 282 | "Requirements": [ 283 | "R", 284 | "methods" 285 | ], 286 | "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" 287 | }, 288 | "fansi": { 289 | "Package": "fansi", 290 | "Version": "1.0.6", 291 | "Source": "Repository", 292 | "Repository": "CRAN", 293 | "Requirements": [ 294 | "R", 295 | "grDevices", 296 | "utils" 297 | ], 298 | "Hash": "962174cf2aeb5b9eea581522286a911f" 299 | }, 300 | "fastmap": { 301 | "Package": "fastmap", 302 | "Version": "1.1.1", 303 | "Source": "Repository", 304 | "Repository": "CRAN", 305 | "Hash": "f7736a18de97dea803bde0a2daaafb27" 306 | }, 307 | "fontawesome": { 308 | "Package": "fontawesome", 309 | "Version": "0.5.2", 310 | "Source": "Repository", 311 | "Repository": "CRAN", 312 | "Requirements": [ 313 | "R", 314 | "htmltools", 315 | "rlang" 316 | ], 317 | "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" 318 | }, 319 | "fs": { 320 | "Package": "fs", 321 | "Version": "1.6.3", 322 | "Source": "Repository", 323 | "Repository": "CRAN", 324 | "Requirements": [ 325 | "R", 326 | "methods" 327 | ], 328 | "Hash": "47b5f30c720c23999b913a1a635cf0bb" 329 | }, 330 | "glue": { 331 | "Package": "glue", 332 | "Version": "1.7.0", 333 | "Source": "Repository", 334 | "Repository": "CRAN", 335 | "Requirements": [ 336 | "R", 337 | "methods" 338 | ], 339 | "Hash": "e0b3a53876554bd45879e596cdb10a52" 340 | }, 341 | "highr": { 342 | "Package": "highr", 343 | "Version": "0.10", 344 | "Source": "Repository", 345 | "Repository": "CRAN", 346 | "Requirements": [ 347 | "R", 348 | "xfun" 349 | ], 350 | "Hash": "06230136b2d2b9ba5805e1963fa6e890" 351 | }, 352 | "htmltools": { 353 | "Package": "htmltools", 354 | "Version": "0.5.8.1", 355 | "Source": "Repository", 356 | "Repository": "CRAN", 357 | "Requirements": [ 358 | "R", 359 | "base64enc", 360 | "digest", 361 | "fastmap", 362 | "grDevices", 363 | "rlang", 364 | "utils" 365 | ], 366 | "Hash": "81d371a9cc60640e74e4ab6ac46dcedc" 367 | }, 368 | "httpuv": { 369 | "Package": "httpuv", 370 | "Version": "1.6.15", 371 | "Source": "Repository", 372 | "Repository": "CRAN", 373 | "Requirements": [ 374 | "R", 375 | "R6", 376 | "Rcpp", 377 | "later", 378 | "promises", 379 | "utils" 380 | ], 381 | "Hash": "d55aa087c47a63ead0f6fc10f8fa1ee0" 382 | }, 383 | "jquerylib": { 384 | "Package": "jquerylib", 385 | "Version": "0.1.4", 386 | "Source": "Repository", 387 | "Repository": "CRAN", 388 | "Requirements": [ 389 | "htmltools" 390 | ], 391 | "Hash": "5aab57a3bd297eee1c1d862735972182" 392 | }, 393 | "jsonlite": { 394 | "Package": "jsonlite", 395 | "Version": "1.8.8", 396 | "Source": "Repository", 397 | "Repository": "CRAN", 398 | "Requirements": [ 399 | "methods" 400 | ], 401 | "Hash": "e1b9c55281c5adc4dd113652d9e26768" 402 | }, 403 | "knitr": { 404 | "Package": "knitr", 405 | "Version": "1.46", 406 | "Source": "Repository", 407 | "Repository": "CRAN", 408 | "Requirements": [ 409 | "R", 410 | "evaluate", 411 | "highr", 412 | "methods", 413 | "tools", 414 | "xfun", 415 | "yaml" 416 | ], 417 | "Hash": "6e008ab1d696a5283c79765fa7b56b47" 418 | }, 419 | "later": { 420 | "Package": "later", 421 | "Version": "1.3.2", 422 | "Source": "Repository", 423 | "Repository": "CRAN", 424 | "Requirements": [ 425 | "Rcpp", 426 | "rlang" 427 | ], 428 | "Hash": "a3e051d405326b8b0012377434c62b37" 429 | }, 430 | "lazyeval": { 431 | "Package": "lazyeval", 432 | "Version": "0.2.2", 433 | "Source": "Repository", 434 | "Repository": "CRAN", 435 | "Requirements": [ 436 | "R" 437 | ], 438 | "Hash": "d908914ae53b04d4c0c0fd72ecc35370" 439 | }, 440 | "lifecycle": { 441 | "Package": "lifecycle", 442 | "Version": "1.0.4", 443 | "Source": "Repository", 444 | "Repository": "CRAN", 445 | "Requirements": [ 446 | "R", 447 | "cli", 448 | "glue", 449 | "rlang" 450 | ], 451 | "Hash": "b8552d117e1b808b09a832f589b79035" 452 | }, 453 | "lintr": { 454 | "Package": "lintr", 455 | "Version": "3.1.2", 456 | "Source": "Repository", 457 | "Repository": "CRAN", 458 | "Requirements": [ 459 | "R", 460 | "backports", 461 | "codetools", 462 | "cyclocomp", 463 | "digest", 464 | "glue", 465 | "knitr", 466 | "rex", 467 | "stats", 468 | "utils", 469 | "xml2", 470 | "xmlparsedata" 471 | ], 472 | "Hash": "08cff46381a242d44c0d8dd0aabd9f71" 473 | }, 474 | "logger": { 475 | "Package": "logger", 476 | "Version": "0.3.0", 477 | "Source": "Repository", 478 | "Repository": "CRAN", 479 | "Requirements": [ 480 | "utils" 481 | ], 482 | "Hash": "c145edf05cc128e6ffcfa5d872c46329" 483 | }, 484 | "magrittr": { 485 | "Package": "magrittr", 486 | "Version": "2.0.3", 487 | "Source": "Repository", 488 | "Repository": "CRAN", 489 | "Requirements": [ 490 | "R" 491 | ], 492 | "Hash": "7ce2733a9826b3aeb1775d56fd305472" 493 | }, 494 | "memoise": { 495 | "Package": "memoise", 496 | "Version": "2.0.1", 497 | "Source": "Repository", 498 | "Repository": "CRAN", 499 | "Requirements": [ 500 | "cachem", 501 | "rlang" 502 | ], 503 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" 504 | }, 505 | "mime": { 506 | "Package": "mime", 507 | "Version": "0.12", 508 | "Source": "Repository", 509 | "Repository": "CRAN", 510 | "Requirements": [ 511 | "tools" 512 | ], 513 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104" 514 | }, 515 | "pillar": { 516 | "Package": "pillar", 517 | "Version": "1.9.0", 518 | "Source": "Repository", 519 | "Repository": "CRAN", 520 | "Requirements": [ 521 | "cli", 522 | "fansi", 523 | "glue", 524 | "lifecycle", 525 | "rlang", 526 | "utf8", 527 | "utils", 528 | "vctrs" 529 | ], 530 | "Hash": "15da5a8412f317beeee6175fbc76f4bb" 531 | }, 532 | "pkgbuild": { 533 | "Package": "pkgbuild", 534 | "Version": "1.4.4", 535 | "Source": "Repository", 536 | "Repository": "CRAN", 537 | "Requirements": [ 538 | "R", 539 | "R6", 540 | "callr", 541 | "cli", 542 | "desc", 543 | "processx" 544 | ], 545 | "Hash": "a29e8e134a460a01e0ca67a4763c595b" 546 | }, 547 | "pkgconfig": { 548 | "Package": "pkgconfig", 549 | "Version": "2.0.3", 550 | "Source": "Repository", 551 | "Repository": "CRAN", 552 | "Requirements": [ 553 | "utils" 554 | ], 555 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 556 | }, 557 | "pkgload": { 558 | "Package": "pkgload", 559 | "Version": "1.3.4", 560 | "Source": "Repository", 561 | "Repository": "CRAN", 562 | "Requirements": [ 563 | "R", 564 | "cli", 565 | "crayon", 566 | "desc", 567 | "fs", 568 | "glue", 569 | "methods", 570 | "pkgbuild", 571 | "rlang", 572 | "rprojroot", 573 | "utils", 574 | "withr" 575 | ], 576 | "Hash": "876c618df5ae610be84356d5d7a5d124" 577 | }, 578 | "praise": { 579 | "Package": "praise", 580 | "Version": "1.0.0", 581 | "Source": "Repository", 582 | "Repository": "CRAN", 583 | "Hash": "a555924add98c99d2f411e37e7d25e9f" 584 | }, 585 | "processx": { 586 | "Package": "processx", 587 | "Version": "3.8.4", 588 | "Source": "Repository", 589 | "Repository": "CRAN", 590 | "Requirements": [ 591 | "R", 592 | "R6", 593 | "ps", 594 | "utils" 595 | ], 596 | "Hash": "0c90a7d71988856bad2a2a45dd871bb9" 597 | }, 598 | "promises": { 599 | "Package": "promises", 600 | "Version": "1.3.0", 601 | "Source": "Repository", 602 | "Repository": "CRAN", 603 | "Requirements": [ 604 | "R6", 605 | "Rcpp", 606 | "fastmap", 607 | "later", 608 | "magrittr", 609 | "rlang", 610 | "stats" 611 | ], 612 | "Hash": "434cd5388a3979e74be5c219bcd6e77d" 613 | }, 614 | "ps": { 615 | "Package": "ps", 616 | "Version": "1.7.6", 617 | "Source": "Repository", 618 | "Repository": "CRAN", 619 | "Requirements": [ 620 | "R", 621 | "utils" 622 | ], 623 | "Hash": "dd2b9319ee0656c8acf45c7f40c59de7" 624 | }, 625 | "purrr": { 626 | "Package": "purrr", 627 | "Version": "1.0.2", 628 | "Source": "Repository", 629 | "Repository": "CRAN", 630 | "Requirements": [ 631 | "R", 632 | "cli", 633 | "lifecycle", 634 | "magrittr", 635 | "rlang", 636 | "vctrs" 637 | ], 638 | "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" 639 | }, 640 | "rappdirs": { 641 | "Package": "rappdirs", 642 | "Version": "0.3.3", 643 | "Source": "Repository", 644 | "Repository": "CRAN", 645 | "Requirements": [ 646 | "R" 647 | ], 648 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d" 649 | }, 650 | "rematch2": { 651 | "Package": "rematch2", 652 | "Version": "2.1.2", 653 | "Source": "Repository", 654 | "Repository": "CRAN", 655 | "Requirements": [ 656 | "tibble" 657 | ], 658 | "Hash": "76c9e04c712a05848ae7a23d2f170a40" 659 | }, 660 | "remotes": { 661 | "Package": "remotes", 662 | "Version": "2.5.0", 663 | "Source": "Repository", 664 | "Repository": "CRAN", 665 | "Requirements": [ 666 | "R", 667 | "methods", 668 | "stats", 669 | "tools", 670 | "utils" 671 | ], 672 | "Hash": "3ee025083e66f18db6cf27b56e23e141" 673 | }, 674 | "renv": { 675 | "Package": "renv", 676 | "Version": "1.0.7", 677 | "Source": "Repository", 678 | "Repository": "CRAN", 679 | "Requirements": [ 680 | "utils" 681 | ], 682 | "Hash": "397b7b2a265bc5a7a06852524dabae20" 683 | }, 684 | "rex": { 685 | "Package": "rex", 686 | "Version": "1.2.1", 687 | "Source": "Repository", 688 | "Repository": "CRAN", 689 | "Requirements": [ 690 | "lazyeval" 691 | ], 692 | "Hash": "ae34cd56890607370665bee5bd17812f" 693 | }, 694 | "rhino": { 695 | "Package": "rhino", 696 | "Version": "1.7.0", 697 | "Source": "Repository", 698 | "Repository": "CRAN", 699 | "Requirements": [ 700 | "R", 701 | "box", 702 | "cli", 703 | "config", 704 | "fs", 705 | "glue", 706 | "lintr", 707 | "logger", 708 | "purrr", 709 | "renv", 710 | "rstudioapi", 711 | "sass", 712 | "shiny", 713 | "styler", 714 | "testthat", 715 | "utils", 716 | "withr", 717 | "xml2", 718 | "yaml" 719 | ], 720 | "Hash": "59ee79b26dd590b08dd1a3111d093832" 721 | }, 722 | "rlang": { 723 | "Package": "rlang", 724 | "Version": "1.1.3", 725 | "Source": "Repository", 726 | "Repository": "CRAN", 727 | "Requirements": [ 728 | "R", 729 | "utils" 730 | ], 731 | "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" 732 | }, 733 | "rprojroot": { 734 | "Package": "rprojroot", 735 | "Version": "2.0.4", 736 | "Source": "Repository", 737 | "Repository": "CRAN", 738 | "Requirements": [ 739 | "R" 740 | ], 741 | "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144" 742 | }, 743 | "rstudioapi": { 744 | "Package": "rstudioapi", 745 | "Version": "0.16.0", 746 | "Source": "Repository", 747 | "Repository": "CRAN", 748 | "Hash": "96710351d642b70e8f02ddeb237c46a7" 749 | }, 750 | "sass": { 751 | "Package": "sass", 752 | "Version": "0.4.9", 753 | "Source": "Repository", 754 | "Repository": "CRAN", 755 | "Requirements": [ 756 | "R6", 757 | "fs", 758 | "htmltools", 759 | "rappdirs", 760 | "rlang" 761 | ], 762 | "Hash": "d53dbfddf695303ea4ad66f86e99b95d" 763 | }, 764 | "shiny": { 765 | "Package": "shiny", 766 | "Version": "1.8.1.1", 767 | "Source": "Repository", 768 | "Repository": "CRAN", 769 | "Requirements": [ 770 | "R", 771 | "R6", 772 | "bslib", 773 | "cachem", 774 | "commonmark", 775 | "crayon", 776 | "fastmap", 777 | "fontawesome", 778 | "glue", 779 | "grDevices", 780 | "htmltools", 781 | "httpuv", 782 | "jsonlite", 783 | "later", 784 | "lifecycle", 785 | "methods", 786 | "mime", 787 | "promises", 788 | "rlang", 789 | "sourcetools", 790 | "tools", 791 | "utils", 792 | "withr", 793 | "xtable" 794 | ], 795 | "Hash": "54b26646816af9960a4c64d8ceec75d6" 796 | }, 797 | "sourcetools": { 798 | "Package": "sourcetools", 799 | "Version": "0.1.7-1", 800 | "Source": "Repository", 801 | "Repository": "CRAN", 802 | "Requirements": [ 803 | "R" 804 | ], 805 | "Hash": "5f5a7629f956619d519205ec475fe647" 806 | }, 807 | "styler": { 808 | "Package": "styler", 809 | "Version": "1.10.3", 810 | "Source": "Repository", 811 | "Repository": "CRAN", 812 | "Requirements": [ 813 | "R", 814 | "R.cache", 815 | "cli", 816 | "magrittr", 817 | "purrr", 818 | "rlang", 819 | "rprojroot", 820 | "tools", 821 | "vctrs", 822 | "withr" 823 | ], 824 | "Hash": "93a2b1beac2437bdcc4724f8bf867e2c" 825 | }, 826 | "testthat": { 827 | "Package": "testthat", 828 | "Version": "3.2.1.1", 829 | "Source": "Repository", 830 | "Repository": "CRAN", 831 | "Requirements": [ 832 | "R", 833 | "R6", 834 | "brio", 835 | "callr", 836 | "cli", 837 | "desc", 838 | "digest", 839 | "evaluate", 840 | "jsonlite", 841 | "lifecycle", 842 | "magrittr", 843 | "methods", 844 | "pkgload", 845 | "praise", 846 | "processx", 847 | "ps", 848 | "rlang", 849 | "utils", 850 | "waldo", 851 | "withr" 852 | ], 853 | "Hash": "3f6e7e5e2220856ff865e4834766bf2b" 854 | }, 855 | "tibble": { 856 | "Package": "tibble", 857 | "Version": "3.2.1", 858 | "Source": "Repository", 859 | "Repository": "CRAN", 860 | "Requirements": [ 861 | "R", 862 | "fansi", 863 | "lifecycle", 864 | "magrittr", 865 | "methods", 866 | "pillar", 867 | "pkgconfig", 868 | "rlang", 869 | "utils", 870 | "vctrs" 871 | ], 872 | "Hash": "a84e2cc86d07289b3b6f5069df7a004c" 873 | }, 874 | "utf8": { 875 | "Package": "utf8", 876 | "Version": "1.2.4", 877 | "Source": "Repository", 878 | "Repository": "CRAN", 879 | "Requirements": [ 880 | "R" 881 | ], 882 | "Hash": "62b65c52671e6665f803ff02954446e9" 883 | }, 884 | "vctrs": { 885 | "Package": "vctrs", 886 | "Version": "0.6.5", 887 | "Source": "Repository", 888 | "Repository": "CRAN", 889 | "Requirements": [ 890 | "R", 891 | "cli", 892 | "glue", 893 | "lifecycle", 894 | "rlang" 895 | ], 896 | "Hash": "c03fa420630029418f7e6da3667aac4a" 897 | }, 898 | "waldo": { 899 | "Package": "waldo", 900 | "Version": "0.5.2", 901 | "Source": "Repository", 902 | "Repository": "CRAN", 903 | "Requirements": [ 904 | "R", 905 | "cli", 906 | "diffobj", 907 | "fansi", 908 | "glue", 909 | "methods", 910 | "rematch2", 911 | "rlang", 912 | "tibble" 913 | ], 914 | "Hash": "c7d3fd6d29ab077cbac8f0e2751449e6" 915 | }, 916 | "withr": { 917 | "Package": "withr", 918 | "Version": "3.0.0", 919 | "Source": "Repository", 920 | "Repository": "CRAN", 921 | "Requirements": [ 922 | "R", 923 | "grDevices", 924 | "graphics" 925 | ], 926 | "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" 927 | }, 928 | "xfun": { 929 | "Package": "xfun", 930 | "Version": "0.43", 931 | "Source": "Repository", 932 | "Repository": "CRAN", 933 | "Requirements": [ 934 | "grDevices", 935 | "stats", 936 | "tools" 937 | ], 938 | "Hash": "ab6371d8653ce5f2f9290f4ec7b42a8e" 939 | }, 940 | "xml2": { 941 | "Package": "xml2", 942 | "Version": "1.3.6", 943 | "Source": "Repository", 944 | "Repository": "CRAN", 945 | "Requirements": [ 946 | "R", 947 | "cli", 948 | "methods", 949 | "rlang" 950 | ], 951 | "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61" 952 | }, 953 | "xmlparsedata": { 954 | "Package": "xmlparsedata", 955 | "Version": "1.0.5", 956 | "Source": "Repository", 957 | "Repository": "CRAN", 958 | "Requirements": [ 959 | "R" 960 | ], 961 | "Hash": "45e4bf3c46476896e821fc0a408fb4fc" 962 | }, 963 | "xtable": { 964 | "Package": "xtable", 965 | "Version": "1.8-4", 966 | "Source": "Repository", 967 | "Repository": "CRAN", 968 | "Requirements": [ 969 | "R", 970 | "stats", 971 | "utils" 972 | ], 973 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 974 | }, 975 | "yaml": { 976 | "Package": "yaml", 977 | "Version": "2.3.8", 978 | "Source": "Repository", 979 | "Repository": "CRAN", 980 | "Hash": "29240487a071f535f5e5d5a323b7afbd" 981 | } 982 | } 983 | } 984 | -------------------------------------------------------------------------------- /task4/renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | local/ 3 | cellar/ 4 | lock/ 5 | python/ 6 | sandbox/ 7 | staging/ 8 | -------------------------------------------------------------------------------- /task4/renv/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "bioconductor.version": null, 3 | "external.libraries": [], 4 | "ignored.packages": [], 5 | "package.dependency.fields": [ 6 | "Imports", 7 | "Depends", 8 | "LinkingTo" 9 | ], 10 | "ppm.enabled": null, 11 | "ppm.ignored.urls": [], 12 | "r.version": null, 13 | "snapshot.type": "implicit", 14 | "use.cache": true, 15 | "vcs.ignore.cellar": true, 16 | "vcs.ignore.library": true, 17 | "vcs.ignore.local": true, 18 | "vcs.manage.ignores": true 19 | } 20 | -------------------------------------------------------------------------------- /task4/rhino.yml: -------------------------------------------------------------------------------- 1 | sass: node 2 | -------------------------------------------------------------------------------- /task4/task4.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 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 | LineEndingConversion: Posix 18 | -------------------------------------------------------------------------------- /task4/tests/cypress.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | e2e: { 3 | setupNodeEvents(on, config) {}, 4 | baseUrl: 'http://localhost:3333', 5 | supportFile: false, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /task4/tests/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | /screenshots/ 2 | /videos/ 3 | -------------------------------------------------------------------------------- /task4/tests/cypress/e2e/app.cy.js: -------------------------------------------------------------------------------- 1 | describe('app', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | it('starts', () => {}) 7 | }) 8 | -------------------------------------------------------------------------------- /task4/tests/testthat/test-main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny[testServer], 3 | testthat[expect_true, test_that], 4 | ) 5 | box::use( 6 | app/main[server, ui], 7 | ) 8 | 9 | test_that("main server works", { 10 | testServer(server, { 11 | expect_true(grepl(x = output$message$html, pattern = "Check out Rhino docs!")) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /task5/.Rprofile: -------------------------------------------------------------------------------- 1 | if (file.exists("renv")) { 2 | source("renv/activate.R") 3 | } else { 4 | # The `renv` directory is automatically skipped when deploying with rsconnect. 5 | message("No 'renv' directory found; renv won't be activated.") 6 | } 7 | 8 | # Allow absolute module imports (relative to the app root). 9 | options(box.path = getwd()) 10 | -------------------------------------------------------------------------------- /task5/.lintr: -------------------------------------------------------------------------------- 1 | linters: 2 | linters_with_defaults( 3 | line_length_linter = line_length_linter(100), 4 | box_func_import_count_linter = rhino::box_func_import_count_linter(), 5 | box_separate_calls_linter = rhino::box_separate_calls_linter(), 6 | box_trailing_commas_linter = rhino::box_trailing_commas_linter(), 7 | box_universal_import_linter = rhino::box_universal_import_linter(), 8 | object_usage_linter = NULL # Does not work with `box::use()`. 9 | ) 10 | -------------------------------------------------------------------------------- /task5/.renvignore: -------------------------------------------------------------------------------- 1 | # Only use `dependencies.R` to infer project dependencies. 2 | * 3 | !dependencies.R 4 | -------------------------------------------------------------------------------- /task5/.rhino/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@babel/eslint-parser", 3 | "extends": ["airbnb"], 4 | "env": { 5 | "browser": true 6 | }, 7 | "globals": { 8 | "$": "readonly", 9 | "Rhino": "readonly", 10 | "Shiny": "readonly" 11 | }, 12 | "rules": { 13 | "import/prefer-default-export": "off", 14 | "no-alert": "off", 15 | "no-console": "off" 16 | }, 17 | "settings": { 18 | "react": { 19 | "version": "17.0" // React is attached by shiny.react, so its version cannot be detected. 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /task5/.rhino/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /task5/.rhino/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard-scss", 3 | "rules": { 4 | "at-rule-no-unknown": null, 5 | "no-empty-source": null, 6 | "scss/at-rule-no-unknown": true, 7 | "selector-id-pattern": [ 8 | "^([a-z][a-z0-9]*)([-_][a-z0-9]+)*$", 9 | { 10 | "message": "Expected ID selector to be kebab-snake_case" 11 | } 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /task5/.rhino/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /task5/.rhino/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build-js": "webpack", 5 | "build-sass": "sass --no-source-map --style=compressed ../app/styles/main.scss:../app/static/css/app.min.css", 6 | "lint-js": "eslint --config .eslintrc.json ../app/js", 7 | "lint-sass": "stylelint ../app/styles", 8 | "run-app": "cd .. && Rscript -e \"shiny::runApp(port = 3333)\"", 9 | "run-cypress": "cypress run --project ../tests", 10 | "open-cypress": "cypress open --project ../tests", 11 | "test-e2e": "start-server-and-test run-app http-get://localhost:3333 run-cypress", 12 | "test-e2e-interactive": "start-server-and-test run-app http-get://localhost:3333 open-cypress" 13 | }, 14 | "devDependencies": { 15 | "@babel/core": "^7.23.7", 16 | "@babel/eslint-parser": "^7.23.3", 17 | "@babel/preset-env": "^7.23.7", 18 | "@babel/preset-react": "^7.23.3", 19 | "babel-loader": "^9.1.3", 20 | "cypress": "^13.6.2", 21 | "eslint": "^8.56.0", 22 | "eslint-config-airbnb": "^19.0.4", 23 | "eslint-import-resolver-webpack": "^0.13.8", 24 | "eslint-plugin-import": "^2.29.1", 25 | "sass": "^1.69.7", 26 | "start-server-and-test": "^2.0.3", 27 | "stylelint": "^14.16.1", 28 | "stylelint-config-standard-scss": "^6.1.0", 29 | "webpack": "^5.89.0", 30 | "webpack-cli": "^5.1.4" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /task5/.rhino/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path'); 2 | 3 | const appDir = join(__dirname, '..', 'app'); 4 | 5 | module.exports = { 6 | mode: 'production', 7 | entry: join(appDir, 'js', 'index.js'), 8 | output: { 9 | library: 'App', 10 | path: join(appDir, 'static', 'js'), 11 | filename: 'app.min.js', 12 | }, 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.(js|jsx)$/, 17 | use: 'babel-loader', 18 | }, 19 | ], 20 | }, 21 | resolve: { 22 | extensions: ['.js', '.jsx'], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /task5/.rscignore: -------------------------------------------------------------------------------- 1 | .github 2 | .lintr 3 | .renvignore 4 | .Renviron 5 | .rhino 6 | .rscignore 7 | tests 8 | -------------------------------------------------------------------------------- /task5/README.md: -------------------------------------------------------------------------------- 1 | # Task 5 2 | 3 | [Introduction to Cypress](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress) will help you with this task. 4 | 5 | ### Step 1 6 | 7 | * Run `rhino::test_e2e()`. 8 | * Run `rhino::test_e2e(interactive = TRUE)`. 9 | 10 | ### Step 2 11 | 12 | Create a test to check if the page displays a title. 13 | 14 | ### Step 3 15 | 16 | Uncomment the code in the test and write Cypress code to make it pass: 17 | Type name and check if the app greets the user. 18 | 19 | ### Step 4 20 | 21 | Uncomment the code in the test and write Cypress code to make it pass: 22 | Check all boxes and find a congratulations message. 23 | -------------------------------------------------------------------------------- /task5/app.R: -------------------------------------------------------------------------------- 1 | # Rhino / shinyApp entrypoint. Do not edit. 2 | rhino::app() 3 | -------------------------------------------------------------------------------- /task5/app/js/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task5/app/js/index.js -------------------------------------------------------------------------------- /task5/app/logic/__init__.R: -------------------------------------------------------------------------------- 1 | # Logic: application code independent from Shiny. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task5/app/main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny, 3 | ) 4 | 5 | choices <- c("one", "two", "three", "four", "five")[2:sample(2:5, 1)] 6 | 7 | #' @export 8 | ui <- function(id) { 9 | ns <- shiny$NS(id) 10 | shiny$fluidPage( 11 | shiny$titlePanel("Rhino App"), 12 | shiny$textInput(ns("name"), "What is your name?"), 13 | shiny$textOutput(ns("greeting")), 14 | shiny$checkboxGroupInput(ns("choices"), "Check all:", choices), 15 | shiny$textOutput(ns("done")) 16 | ) 17 | } 18 | 19 | #' @export 20 | server <- function(id) { 21 | shiny$moduleServer(id, function(input, output, session) { 22 | output$greeting <- shiny$renderText(paste0("Hello ", shiny$req(input$name), "!")) 23 | output$done <- shiny$renderText({ 24 | shiny$req(identical(input$choices, choices)) 25 | "Well done!" 26 | }) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /task5/app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task5/app/static/favicon.ico -------------------------------------------------------------------------------- /task5/app/styles/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Appsilon/rhino-masterclass/23dc2c623c937f6dca58fc76d8ee0d26f55100bc/task5/app/styles/main.scss -------------------------------------------------------------------------------- /task5/app/view/__init__.R: -------------------------------------------------------------------------------- 1 | # View: Shiny modules and related code. 2 | # https://go.appsilon.com/rhino-project-structure 3 | -------------------------------------------------------------------------------- /task5/config.yml: -------------------------------------------------------------------------------- 1 | default: 2 | rhino_log_level: !expr Sys.getenv("RHINO_LOG_LEVEL", "INFO") 3 | rhino_log_file: !expr Sys.getenv("RHINO_LOG_FILE", NA) 4 | -------------------------------------------------------------------------------- /task5/dependencies.R: -------------------------------------------------------------------------------- 1 | # This file allows packrat (used by rsconnect during deployment) to pick up dependencies. 2 | library(rhino) 3 | -------------------------------------------------------------------------------- /task5/renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.1.2", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cloud.r-project.org" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "R.cache": { 13 | "Package": "R.cache", 14 | "Version": "0.16.0", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Requirements": [ 18 | "R", 19 | "R.methodsS3", 20 | "R.oo", 21 | "R.utils", 22 | "digest", 23 | "utils" 24 | ], 25 | "Hash": "fe539ca3f8efb7410c3ae2cf5fe6c0f8" 26 | }, 27 | "R.methodsS3": { 28 | "Package": "R.methodsS3", 29 | "Version": "1.8.2", 30 | "Source": "Repository", 31 | "Repository": "CRAN", 32 | "Requirements": [ 33 | "R", 34 | "utils" 35 | ], 36 | "Hash": "278c286fd6e9e75d0c2e8f731ea445c8" 37 | }, 38 | "R.oo": { 39 | "Package": "R.oo", 40 | "Version": "1.26.0", 41 | "Source": "Repository", 42 | "Repository": "CRAN", 43 | "Requirements": [ 44 | "R", 45 | "R.methodsS3", 46 | "methods", 47 | "utils" 48 | ], 49 | "Hash": "4fed809e53ddb5407b3da3d0f572e591" 50 | }, 51 | "R.utils": { 52 | "Package": "R.utils", 53 | "Version": "2.12.3", 54 | "Source": "Repository", 55 | "Repository": "CRAN", 56 | "Requirements": [ 57 | "R", 58 | "R.methodsS3", 59 | "R.oo", 60 | "methods", 61 | "tools", 62 | "utils" 63 | ], 64 | "Hash": "3dc2829b790254bfba21e60965787651" 65 | }, 66 | "R6": { 67 | "Package": "R6", 68 | "Version": "2.5.1", 69 | "Source": "Repository", 70 | "Repository": "CRAN", 71 | "Requirements": [ 72 | "R" 73 | ], 74 | "Hash": "470851b6d5d0ac559e9d01bb352b4021" 75 | }, 76 | "Rcpp": { 77 | "Package": "Rcpp", 78 | "Version": "1.0.12", 79 | "Source": "Repository", 80 | "Repository": "CRAN", 81 | "Requirements": [ 82 | "methods", 83 | "utils" 84 | ], 85 | "Hash": "5ea2700d21e038ace58269ecdbeb9ec0" 86 | }, 87 | "backports": { 88 | "Package": "backports", 89 | "Version": "1.4.1", 90 | "Source": "Repository", 91 | "Repository": "CRAN", 92 | "Requirements": [ 93 | "R" 94 | ], 95 | "Hash": "c39fbec8a30d23e721980b8afb31984c" 96 | }, 97 | "base64enc": { 98 | "Package": "base64enc", 99 | "Version": "0.1-3", 100 | "Source": "Repository", 101 | "Repository": "CRAN", 102 | "Requirements": [ 103 | "R" 104 | ], 105 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 106 | }, 107 | "box": { 108 | "Package": "box", 109 | "Version": "1.2.0", 110 | "Source": "Repository", 111 | "Repository": "CRAN", 112 | "Requirements": [ 113 | "R", 114 | "tools" 115 | ], 116 | "Hash": "d94049c1d9446b0abb413fde9e82a505" 117 | }, 118 | "brio": { 119 | "Package": "brio", 120 | "Version": "1.1.4", 121 | "Source": "Repository", 122 | "Repository": "CRAN", 123 | "Requirements": [ 124 | "R" 125 | ], 126 | "Hash": "68bd2b066e1fe780bbf62fc8bcc36de3" 127 | }, 128 | "bslib": { 129 | "Package": "bslib", 130 | "Version": "0.7.0", 131 | "Source": "Repository", 132 | "Repository": "CRAN", 133 | "Requirements": [ 134 | "R", 135 | "base64enc", 136 | "cachem", 137 | "fastmap", 138 | "grDevices", 139 | "htmltools", 140 | "jquerylib", 141 | "jsonlite", 142 | "lifecycle", 143 | "memoise", 144 | "mime", 145 | "rlang", 146 | "sass" 147 | ], 148 | "Hash": "8644cc53f43828f19133548195d7e59e" 149 | }, 150 | "cachem": { 151 | "Package": "cachem", 152 | "Version": "1.0.8", 153 | "Source": "Repository", 154 | "Repository": "CRAN", 155 | "Requirements": [ 156 | "fastmap", 157 | "rlang" 158 | ], 159 | "Hash": "c35768291560ce302c0a6589f92e837d" 160 | }, 161 | "callr": { 162 | "Package": "callr", 163 | "Version": "3.7.6", 164 | "Source": "Repository", 165 | "Repository": "CRAN", 166 | "Requirements": [ 167 | "R", 168 | "R6", 169 | "processx", 170 | "utils" 171 | ], 172 | "Hash": "d7e13f49c19103ece9e58ad2d83a7354" 173 | }, 174 | "cli": { 175 | "Package": "cli", 176 | "Version": "3.6.2", 177 | "Source": "Repository", 178 | "Repository": "CRAN", 179 | "Requirements": [ 180 | "R", 181 | "utils" 182 | ], 183 | "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" 184 | }, 185 | "codetools": { 186 | "Package": "codetools", 187 | "Version": "0.2-20", 188 | "Source": "Repository", 189 | "Repository": "CRAN", 190 | "Requirements": [ 191 | "R" 192 | ], 193 | "Hash": "61e097f35917d342622f21cdc79c256e" 194 | }, 195 | "commonmark": { 196 | "Package": "commonmark", 197 | "Version": "1.9.1", 198 | "Source": "Repository", 199 | "Repository": "CRAN", 200 | "Hash": "5d8225445acb167abf7797de48b2ee3c" 201 | }, 202 | "config": { 203 | "Package": "config", 204 | "Version": "0.3.2", 205 | "Source": "Repository", 206 | "Repository": "CRAN", 207 | "Requirements": [ 208 | "yaml" 209 | ], 210 | "Hash": "8b7222e9d9eb5178eea545c0c4d33fc2" 211 | }, 212 | "crayon": { 213 | "Package": "crayon", 214 | "Version": "1.5.2", 215 | "Source": "Repository", 216 | "Repository": "CRAN", 217 | "Requirements": [ 218 | "grDevices", 219 | "methods", 220 | "utils" 221 | ], 222 | "Hash": "e8a1e41acf02548751f45c718d55aa6a" 223 | }, 224 | "cyclocomp": { 225 | "Package": "cyclocomp", 226 | "Version": "1.1.1", 227 | "Source": "Repository", 228 | "Repository": "CRAN", 229 | "Requirements": [ 230 | "callr", 231 | "crayon", 232 | "desc", 233 | "remotes", 234 | "withr" 235 | ], 236 | "Hash": "cdc4a473222b0112d4df0bcfbed12d44" 237 | }, 238 | "desc": { 239 | "Package": "desc", 240 | "Version": "1.4.3", 241 | "Source": "Repository", 242 | "Repository": "CRAN", 243 | "Requirements": [ 244 | "R", 245 | "R6", 246 | "cli", 247 | "utils" 248 | ], 249 | "Hash": "99b79fcbd6c4d1ce087f5c5c758b384f" 250 | }, 251 | "diffobj": { 252 | "Package": "diffobj", 253 | "Version": "0.3.5", 254 | "Source": "Repository", 255 | "Repository": "CRAN", 256 | "Requirements": [ 257 | "R", 258 | "crayon", 259 | "methods", 260 | "stats", 261 | "tools", 262 | "utils" 263 | ], 264 | "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8" 265 | }, 266 | "digest": { 267 | "Package": "digest", 268 | "Version": "0.6.35", 269 | "Source": "Repository", 270 | "Repository": "CRAN", 271 | "Requirements": [ 272 | "R", 273 | "utils" 274 | ], 275 | "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" 276 | }, 277 | "evaluate": { 278 | "Package": "evaluate", 279 | "Version": "0.23", 280 | "Source": "Repository", 281 | "Repository": "CRAN", 282 | "Requirements": [ 283 | "R", 284 | "methods" 285 | ], 286 | "Hash": "daf4a1246be12c1fa8c7705a0935c1a0" 287 | }, 288 | "fansi": { 289 | "Package": "fansi", 290 | "Version": "1.0.6", 291 | "Source": "Repository", 292 | "Repository": "CRAN", 293 | "Requirements": [ 294 | "R", 295 | "grDevices", 296 | "utils" 297 | ], 298 | "Hash": "962174cf2aeb5b9eea581522286a911f" 299 | }, 300 | "fastmap": { 301 | "Package": "fastmap", 302 | "Version": "1.1.1", 303 | "Source": "Repository", 304 | "Repository": "CRAN", 305 | "Hash": "f7736a18de97dea803bde0a2daaafb27" 306 | }, 307 | "fontawesome": { 308 | "Package": "fontawesome", 309 | "Version": "0.5.2", 310 | "Source": "Repository", 311 | "Repository": "CRAN", 312 | "Requirements": [ 313 | "R", 314 | "htmltools", 315 | "rlang" 316 | ], 317 | "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" 318 | }, 319 | "fs": { 320 | "Package": "fs", 321 | "Version": "1.6.3", 322 | "Source": "Repository", 323 | "Repository": "CRAN", 324 | "Requirements": [ 325 | "R", 326 | "methods" 327 | ], 328 | "Hash": "47b5f30c720c23999b913a1a635cf0bb" 329 | }, 330 | "glue": { 331 | "Package": "glue", 332 | "Version": "1.7.0", 333 | "Source": "Repository", 334 | "Repository": "CRAN", 335 | "Requirements": [ 336 | "R", 337 | "methods" 338 | ], 339 | "Hash": "e0b3a53876554bd45879e596cdb10a52" 340 | }, 341 | "highr": { 342 | "Package": "highr", 343 | "Version": "0.10", 344 | "Source": "Repository", 345 | "Repository": "CRAN", 346 | "Requirements": [ 347 | "R", 348 | "xfun" 349 | ], 350 | "Hash": "06230136b2d2b9ba5805e1963fa6e890" 351 | }, 352 | "htmltools": { 353 | "Package": "htmltools", 354 | "Version": "0.5.8.1", 355 | "Source": "Repository", 356 | "Repository": "CRAN", 357 | "Requirements": [ 358 | "R", 359 | "base64enc", 360 | "digest", 361 | "fastmap", 362 | "grDevices", 363 | "rlang", 364 | "utils" 365 | ], 366 | "Hash": "81d371a9cc60640e74e4ab6ac46dcedc" 367 | }, 368 | "httpuv": { 369 | "Package": "httpuv", 370 | "Version": "1.6.15", 371 | "Source": "Repository", 372 | "Repository": "CRAN", 373 | "Requirements": [ 374 | "R", 375 | "R6", 376 | "Rcpp", 377 | "later", 378 | "promises", 379 | "utils" 380 | ], 381 | "Hash": "d55aa087c47a63ead0f6fc10f8fa1ee0" 382 | }, 383 | "jquerylib": { 384 | "Package": "jquerylib", 385 | "Version": "0.1.4", 386 | "Source": "Repository", 387 | "Repository": "CRAN", 388 | "Requirements": [ 389 | "htmltools" 390 | ], 391 | "Hash": "5aab57a3bd297eee1c1d862735972182" 392 | }, 393 | "jsonlite": { 394 | "Package": "jsonlite", 395 | "Version": "1.8.8", 396 | "Source": "Repository", 397 | "Repository": "CRAN", 398 | "Requirements": [ 399 | "methods" 400 | ], 401 | "Hash": "e1b9c55281c5adc4dd113652d9e26768" 402 | }, 403 | "knitr": { 404 | "Package": "knitr", 405 | "Version": "1.46", 406 | "Source": "Repository", 407 | "Repository": "CRAN", 408 | "Requirements": [ 409 | "R", 410 | "evaluate", 411 | "highr", 412 | "methods", 413 | "tools", 414 | "xfun", 415 | "yaml" 416 | ], 417 | "Hash": "6e008ab1d696a5283c79765fa7b56b47" 418 | }, 419 | "later": { 420 | "Package": "later", 421 | "Version": "1.3.2", 422 | "Source": "Repository", 423 | "Repository": "CRAN", 424 | "Requirements": [ 425 | "Rcpp", 426 | "rlang" 427 | ], 428 | "Hash": "a3e051d405326b8b0012377434c62b37" 429 | }, 430 | "lazyeval": { 431 | "Package": "lazyeval", 432 | "Version": "0.2.2", 433 | "Source": "Repository", 434 | "Repository": "CRAN", 435 | "Requirements": [ 436 | "R" 437 | ], 438 | "Hash": "d908914ae53b04d4c0c0fd72ecc35370" 439 | }, 440 | "lifecycle": { 441 | "Package": "lifecycle", 442 | "Version": "1.0.4", 443 | "Source": "Repository", 444 | "Repository": "CRAN", 445 | "Requirements": [ 446 | "R", 447 | "cli", 448 | "glue", 449 | "rlang" 450 | ], 451 | "Hash": "b8552d117e1b808b09a832f589b79035" 452 | }, 453 | "lintr": { 454 | "Package": "lintr", 455 | "Version": "3.1.2", 456 | "Source": "Repository", 457 | "Repository": "CRAN", 458 | "Requirements": [ 459 | "R", 460 | "backports", 461 | "codetools", 462 | "cyclocomp", 463 | "digest", 464 | "glue", 465 | "knitr", 466 | "rex", 467 | "stats", 468 | "utils", 469 | "xml2", 470 | "xmlparsedata" 471 | ], 472 | "Hash": "08cff46381a242d44c0d8dd0aabd9f71" 473 | }, 474 | "logger": { 475 | "Package": "logger", 476 | "Version": "0.3.0", 477 | "Source": "Repository", 478 | "Repository": "CRAN", 479 | "Requirements": [ 480 | "utils" 481 | ], 482 | "Hash": "c145edf05cc128e6ffcfa5d872c46329" 483 | }, 484 | "magrittr": { 485 | "Package": "magrittr", 486 | "Version": "2.0.3", 487 | "Source": "Repository", 488 | "Repository": "CRAN", 489 | "Requirements": [ 490 | "R" 491 | ], 492 | "Hash": "7ce2733a9826b3aeb1775d56fd305472" 493 | }, 494 | "memoise": { 495 | "Package": "memoise", 496 | "Version": "2.0.1", 497 | "Source": "Repository", 498 | "Repository": "CRAN", 499 | "Requirements": [ 500 | "cachem", 501 | "rlang" 502 | ], 503 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" 504 | }, 505 | "mime": { 506 | "Package": "mime", 507 | "Version": "0.12", 508 | "Source": "Repository", 509 | "Repository": "CRAN", 510 | "Requirements": [ 511 | "tools" 512 | ], 513 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104" 514 | }, 515 | "pillar": { 516 | "Package": "pillar", 517 | "Version": "1.9.0", 518 | "Source": "Repository", 519 | "Repository": "CRAN", 520 | "Requirements": [ 521 | "cli", 522 | "fansi", 523 | "glue", 524 | "lifecycle", 525 | "rlang", 526 | "utf8", 527 | "utils", 528 | "vctrs" 529 | ], 530 | "Hash": "15da5a8412f317beeee6175fbc76f4bb" 531 | }, 532 | "pkgbuild": { 533 | "Package": "pkgbuild", 534 | "Version": "1.4.4", 535 | "Source": "Repository", 536 | "Repository": "CRAN", 537 | "Requirements": [ 538 | "R", 539 | "R6", 540 | "callr", 541 | "cli", 542 | "desc", 543 | "processx" 544 | ], 545 | "Hash": "a29e8e134a460a01e0ca67a4763c595b" 546 | }, 547 | "pkgconfig": { 548 | "Package": "pkgconfig", 549 | "Version": "2.0.3", 550 | "Source": "Repository", 551 | "Repository": "CRAN", 552 | "Requirements": [ 553 | "utils" 554 | ], 555 | "Hash": "01f28d4278f15c76cddbea05899c5d6f" 556 | }, 557 | "pkgload": { 558 | "Package": "pkgload", 559 | "Version": "1.3.4", 560 | "Source": "Repository", 561 | "Repository": "CRAN", 562 | "Requirements": [ 563 | "R", 564 | "cli", 565 | "crayon", 566 | "desc", 567 | "fs", 568 | "glue", 569 | "methods", 570 | "pkgbuild", 571 | "rlang", 572 | "rprojroot", 573 | "utils", 574 | "withr" 575 | ], 576 | "Hash": "876c618df5ae610be84356d5d7a5d124" 577 | }, 578 | "praise": { 579 | "Package": "praise", 580 | "Version": "1.0.0", 581 | "Source": "Repository", 582 | "Repository": "CRAN", 583 | "Hash": "a555924add98c99d2f411e37e7d25e9f" 584 | }, 585 | "processx": { 586 | "Package": "processx", 587 | "Version": "3.8.4", 588 | "Source": "Repository", 589 | "Repository": "CRAN", 590 | "Requirements": [ 591 | "R", 592 | "R6", 593 | "ps", 594 | "utils" 595 | ], 596 | "Hash": "0c90a7d71988856bad2a2a45dd871bb9" 597 | }, 598 | "promises": { 599 | "Package": "promises", 600 | "Version": "1.3.0", 601 | "Source": "Repository", 602 | "Repository": "CRAN", 603 | "Requirements": [ 604 | "R6", 605 | "Rcpp", 606 | "fastmap", 607 | "later", 608 | "magrittr", 609 | "rlang", 610 | "stats" 611 | ], 612 | "Hash": "434cd5388a3979e74be5c219bcd6e77d" 613 | }, 614 | "ps": { 615 | "Package": "ps", 616 | "Version": "1.7.6", 617 | "Source": "Repository", 618 | "Repository": "CRAN", 619 | "Requirements": [ 620 | "R", 621 | "utils" 622 | ], 623 | "Hash": "dd2b9319ee0656c8acf45c7f40c59de7" 624 | }, 625 | "purrr": { 626 | "Package": "purrr", 627 | "Version": "1.0.2", 628 | "Source": "Repository", 629 | "Repository": "CRAN", 630 | "Requirements": [ 631 | "R", 632 | "cli", 633 | "lifecycle", 634 | "magrittr", 635 | "rlang", 636 | "vctrs" 637 | ], 638 | "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" 639 | }, 640 | "rappdirs": { 641 | "Package": "rappdirs", 642 | "Version": "0.3.3", 643 | "Source": "Repository", 644 | "Repository": "CRAN", 645 | "Requirements": [ 646 | "R" 647 | ], 648 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d" 649 | }, 650 | "rematch2": { 651 | "Package": "rematch2", 652 | "Version": "2.1.2", 653 | "Source": "Repository", 654 | "Repository": "CRAN", 655 | "Requirements": [ 656 | "tibble" 657 | ], 658 | "Hash": "76c9e04c712a05848ae7a23d2f170a40" 659 | }, 660 | "remotes": { 661 | "Package": "remotes", 662 | "Version": "2.5.0", 663 | "Source": "Repository", 664 | "Repository": "CRAN", 665 | "Requirements": [ 666 | "R", 667 | "methods", 668 | "stats", 669 | "tools", 670 | "utils" 671 | ], 672 | "Hash": "3ee025083e66f18db6cf27b56e23e141" 673 | }, 674 | "renv": { 675 | "Package": "renv", 676 | "Version": "1.0.7", 677 | "Source": "Repository", 678 | "Repository": "CRAN", 679 | "Requirements": [ 680 | "utils" 681 | ], 682 | "Hash": "397b7b2a265bc5a7a06852524dabae20" 683 | }, 684 | "rex": { 685 | "Package": "rex", 686 | "Version": "1.2.1", 687 | "Source": "Repository", 688 | "Repository": "CRAN", 689 | "Requirements": [ 690 | "lazyeval" 691 | ], 692 | "Hash": "ae34cd56890607370665bee5bd17812f" 693 | }, 694 | "rhino": { 695 | "Package": "rhino", 696 | "Version": "1.7.0", 697 | "Source": "Repository", 698 | "Repository": "CRAN", 699 | "Requirements": [ 700 | "R", 701 | "box", 702 | "cli", 703 | "config", 704 | "fs", 705 | "glue", 706 | "lintr", 707 | "logger", 708 | "purrr", 709 | "renv", 710 | "rstudioapi", 711 | "sass", 712 | "shiny", 713 | "styler", 714 | "testthat", 715 | "utils", 716 | "withr", 717 | "xml2", 718 | "yaml" 719 | ], 720 | "Hash": "59ee79b26dd590b08dd1a3111d093832" 721 | }, 722 | "rlang": { 723 | "Package": "rlang", 724 | "Version": "1.1.3", 725 | "Source": "Repository", 726 | "Repository": "CRAN", 727 | "Requirements": [ 728 | "R", 729 | "utils" 730 | ], 731 | "Hash": "42548638fae05fd9a9b5f3f437fbbbe2" 732 | }, 733 | "rprojroot": { 734 | "Package": "rprojroot", 735 | "Version": "2.0.4", 736 | "Source": "Repository", 737 | "Repository": "CRAN", 738 | "Requirements": [ 739 | "R" 740 | ], 741 | "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144" 742 | }, 743 | "rstudioapi": { 744 | "Package": "rstudioapi", 745 | "Version": "0.16.0", 746 | "Source": "Repository", 747 | "Repository": "CRAN", 748 | "Hash": "96710351d642b70e8f02ddeb237c46a7" 749 | }, 750 | "sass": { 751 | "Package": "sass", 752 | "Version": "0.4.9", 753 | "Source": "Repository", 754 | "Repository": "CRAN", 755 | "Requirements": [ 756 | "R6", 757 | "fs", 758 | "htmltools", 759 | "rappdirs", 760 | "rlang" 761 | ], 762 | "Hash": "d53dbfddf695303ea4ad66f86e99b95d" 763 | }, 764 | "shiny": { 765 | "Package": "shiny", 766 | "Version": "1.8.1.1", 767 | "Source": "Repository", 768 | "Repository": "CRAN", 769 | "Requirements": [ 770 | "R", 771 | "R6", 772 | "bslib", 773 | "cachem", 774 | "commonmark", 775 | "crayon", 776 | "fastmap", 777 | "fontawesome", 778 | "glue", 779 | "grDevices", 780 | "htmltools", 781 | "httpuv", 782 | "jsonlite", 783 | "later", 784 | "lifecycle", 785 | "methods", 786 | "mime", 787 | "promises", 788 | "rlang", 789 | "sourcetools", 790 | "tools", 791 | "utils", 792 | "withr", 793 | "xtable" 794 | ], 795 | "Hash": "54b26646816af9960a4c64d8ceec75d6" 796 | }, 797 | "sourcetools": { 798 | "Package": "sourcetools", 799 | "Version": "0.1.7-1", 800 | "Source": "Repository", 801 | "Repository": "CRAN", 802 | "Requirements": [ 803 | "R" 804 | ], 805 | "Hash": "5f5a7629f956619d519205ec475fe647" 806 | }, 807 | "styler": { 808 | "Package": "styler", 809 | "Version": "1.10.3", 810 | "Source": "Repository", 811 | "Repository": "CRAN", 812 | "Requirements": [ 813 | "R", 814 | "R.cache", 815 | "cli", 816 | "magrittr", 817 | "purrr", 818 | "rlang", 819 | "rprojroot", 820 | "tools", 821 | "vctrs", 822 | "withr" 823 | ], 824 | "Hash": "93a2b1beac2437bdcc4724f8bf867e2c" 825 | }, 826 | "testthat": { 827 | "Package": "testthat", 828 | "Version": "3.2.1.1", 829 | "Source": "Repository", 830 | "Repository": "CRAN", 831 | "Requirements": [ 832 | "R", 833 | "R6", 834 | "brio", 835 | "callr", 836 | "cli", 837 | "desc", 838 | "digest", 839 | "evaluate", 840 | "jsonlite", 841 | "lifecycle", 842 | "magrittr", 843 | "methods", 844 | "pkgload", 845 | "praise", 846 | "processx", 847 | "ps", 848 | "rlang", 849 | "utils", 850 | "waldo", 851 | "withr" 852 | ], 853 | "Hash": "3f6e7e5e2220856ff865e4834766bf2b" 854 | }, 855 | "tibble": { 856 | "Package": "tibble", 857 | "Version": "3.2.1", 858 | "Source": "Repository", 859 | "Repository": "CRAN", 860 | "Requirements": [ 861 | "R", 862 | "fansi", 863 | "lifecycle", 864 | "magrittr", 865 | "methods", 866 | "pillar", 867 | "pkgconfig", 868 | "rlang", 869 | "utils", 870 | "vctrs" 871 | ], 872 | "Hash": "a84e2cc86d07289b3b6f5069df7a004c" 873 | }, 874 | "utf8": { 875 | "Package": "utf8", 876 | "Version": "1.2.4", 877 | "Source": "Repository", 878 | "Repository": "CRAN", 879 | "Requirements": [ 880 | "R" 881 | ], 882 | "Hash": "62b65c52671e6665f803ff02954446e9" 883 | }, 884 | "vctrs": { 885 | "Package": "vctrs", 886 | "Version": "0.6.5", 887 | "Source": "Repository", 888 | "Repository": "CRAN", 889 | "Requirements": [ 890 | "R", 891 | "cli", 892 | "glue", 893 | "lifecycle", 894 | "rlang" 895 | ], 896 | "Hash": "c03fa420630029418f7e6da3667aac4a" 897 | }, 898 | "waldo": { 899 | "Package": "waldo", 900 | "Version": "0.5.2", 901 | "Source": "Repository", 902 | "Repository": "CRAN", 903 | "Requirements": [ 904 | "R", 905 | "cli", 906 | "diffobj", 907 | "fansi", 908 | "glue", 909 | "methods", 910 | "rematch2", 911 | "rlang", 912 | "tibble" 913 | ], 914 | "Hash": "c7d3fd6d29ab077cbac8f0e2751449e6" 915 | }, 916 | "withr": { 917 | "Package": "withr", 918 | "Version": "3.0.0", 919 | "Source": "Repository", 920 | "Repository": "CRAN", 921 | "Requirements": [ 922 | "R", 923 | "grDevices", 924 | "graphics" 925 | ], 926 | "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" 927 | }, 928 | "xfun": { 929 | "Package": "xfun", 930 | "Version": "0.43", 931 | "Source": "Repository", 932 | "Repository": "CRAN", 933 | "Requirements": [ 934 | "grDevices", 935 | "stats", 936 | "tools" 937 | ], 938 | "Hash": "ab6371d8653ce5f2f9290f4ec7b42a8e" 939 | }, 940 | "xml2": { 941 | "Package": "xml2", 942 | "Version": "1.3.6", 943 | "Source": "Repository", 944 | "Repository": "CRAN", 945 | "Requirements": [ 946 | "R", 947 | "cli", 948 | "methods", 949 | "rlang" 950 | ], 951 | "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61" 952 | }, 953 | "xmlparsedata": { 954 | "Package": "xmlparsedata", 955 | "Version": "1.0.5", 956 | "Source": "Repository", 957 | "Repository": "CRAN", 958 | "Requirements": [ 959 | "R" 960 | ], 961 | "Hash": "45e4bf3c46476896e821fc0a408fb4fc" 962 | }, 963 | "xtable": { 964 | "Package": "xtable", 965 | "Version": "1.8-4", 966 | "Source": "Repository", 967 | "Repository": "CRAN", 968 | "Requirements": [ 969 | "R", 970 | "stats", 971 | "utils" 972 | ], 973 | "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" 974 | }, 975 | "yaml": { 976 | "Package": "yaml", 977 | "Version": "2.3.8", 978 | "Source": "Repository", 979 | "Repository": "CRAN", 980 | "Hash": "29240487a071f535f5e5d5a323b7afbd" 981 | } 982 | } 983 | } 984 | -------------------------------------------------------------------------------- /task5/renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | local/ 3 | cellar/ 4 | lock/ 5 | python/ 6 | sandbox/ 7 | staging/ 8 | -------------------------------------------------------------------------------- /task5/renv/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "bioconductor.version": null, 3 | "external.libraries": [], 4 | "ignored.packages": [], 5 | "package.dependency.fields": [ 6 | "Imports", 7 | "Depends", 8 | "LinkingTo" 9 | ], 10 | "ppm.enabled": null, 11 | "ppm.ignored.urls": [], 12 | "r.version": null, 13 | "snapshot.type": "implicit", 14 | "use.cache": true, 15 | "vcs.ignore.cellar": true, 16 | "vcs.ignore.library": true, 17 | "vcs.ignore.local": true, 18 | "vcs.manage.ignores": true 19 | } 20 | -------------------------------------------------------------------------------- /task5/rhino.yml: -------------------------------------------------------------------------------- 1 | sass: node 2 | -------------------------------------------------------------------------------- /task5/task5.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 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 | LineEndingConversion: Posix 18 | -------------------------------------------------------------------------------- /task5/tests/cypress.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | e2e: { 3 | setupNodeEvents(on, config) {}, 4 | baseUrl: 'http://localhost:3333', 5 | supportFile: false, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /task5/tests/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | /screenshots/ 2 | /videos/ 3 | -------------------------------------------------------------------------------- /task5/tests/cypress/e2e/app.cy.js: -------------------------------------------------------------------------------- 1 | describe('app', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('displays a title', () => { 7 | // Step 2: 8 | // ? 9 | }); 10 | 11 | it('greets user with their name', () => { 12 | // Step 3: 13 | // ? 14 | 15 | // cy.get('#app-greeting') 16 | // .contains('Hello Rhino!'); 17 | }); 18 | 19 | it('congratulates for checking all', () => { 20 | // Step 4: 21 | // ? 22 | 23 | // cy.get('#app-done') 24 | // .contains('Well done!'); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /task5/tests/testthat/test-main.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | shiny[testServer], 3 | testthat[expect_true, test_that], 4 | ) 5 | box::use( 6 | app/main[server, ui], 7 | ) 8 | 9 | test_that("main server works", { 10 | testServer(server, { 11 | expect_true(grepl(x = output$message$html, pattern = "Check out Rhino docs!")) 12 | }) 13 | }) 14 | --------------------------------------------------------------------------------