From e4c72f4809b502a812547c5c99bc6ae5eed44b36 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 20:34:11 -0500 Subject: [PATCH 01/25] wrap removed from knitr --- common.R | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/common.R b/common.R index 59ed2b2e..d31f1b94 100644 --- a/common.R +++ b/common.R @@ -26,9 +26,9 @@ knitr::opts_chunk$set( fig.retina = 0.8, # figures are either vectors or 300 dpi diagrams dpi = 300, out.width = "70%", - fig.align = 'center', + fig.align = "center", fig.width = 6, - fig.asp = 0.618, # 1 / phi + fig.asp = 0.618, # 1 / phi fig.show = "hold" ) @@ -57,23 +57,6 @@ knitr::knit_hooks$set( } ) -# Make error messages closer to base R -registerS3method("wrap", "error", envir = asNamespace("knitr"), - function(x, options) { - msg <- conditionMessage(x) - - call <- conditionCall(x) - if (is.null(call)) { - msg <- paste0("Error: ", msg) - } else { - msg <- paste0("Error in ", deparse(call)[[1]], ": ", msg) - } - - msg <- error_wrap(msg) - knitr:::msg_wrap(msg, "error", options) - } -) - error_wrap <- function(x, width = getOption("width")) { lines <- strsplit(x, "\n", fixed = TRUE)[[1]] paste(strwrap(lines, width = width), collapse = "\n") From 4f0e71ea0b530eb4a2249ba16d2af76f36e71a9a Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 20:34:29 -0500 Subject: [PATCH 02/25] fun factories: fix tibble dimensions --- 10_Function_factories.Rmd | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/10_Function_factories.Rmd b/10_Function_factories.Rmd index 2f1024b7..47d068d4 100755 --- a/10_Function_factories.Rmd +++ b/10_Function_factories.Rmd @@ -145,7 +145,7 @@ __[A]{.solved}__: In this exercise `pick(i)` acts as a function factory, which r ```{r} pick <- function(i) { force(i) - + function(x) x[[i]] } @@ -173,15 +173,15 @@ __[A]{.solved}__: The first moment is closely related to the mean and describes ```{r} moment <- function(i) { force(i) - - function(x) sum((x - mean(x)) ^ i) / length(x) + + function(x) sum((x - mean(x))^i) / length(x) } m1 <- moment(1) m2 <- moment(2) x <- runif(100) -all.equal(m1(x), 0) # removed stopifnot() for clarity +all.equal(m1(x), 0) # removed stopifnot() for clarity all.equal(m2(x), var(x) * 99 / 100) ``` @@ -253,11 +253,11 @@ boot_model <- function(df, formula) { fitted <- unname(fitted(mod)) resid <- unname(resid(mod)) rm(mod) - + function() { fitted + sample(resid) } -} +} ``` __[Q2]{.Q}__: Why might you formulate the Box-Cox transformation like this? @@ -268,9 +268,9 @@ boxcox3 <- function(x) { if (lambda == 0) { log(x) } else { - (x ^ lambda - 1) / lambda + (x^lambda - 1) / lambda } - } + } } ``` @@ -293,7 +293,7 @@ __[A]{.solved}__: `boot_permute()` is defined in *Advanced R* as: boot_permute <- function(df, var) { n <- nrow(df) force(var) - + function() { col <- df[[var]] col[sample(n, replace = TRUE)] @@ -318,7 +318,7 @@ __[A]{.solved}__: Let us recall the definitions of `ll_poisson1()`, `ll_poisson2 ```{r} ll_poisson1 <- function(x) { n <- length(x) - + function(lambda) { log(lambda) * sum(x) - n * lambda - sum(lfactorial(x)) } @@ -328,7 +328,7 @@ ll_poisson2 <- function(x) { n <- length(x) sum_x <- sum(x) c <- sum(lfactorial(x)) - + function(lambda) { log(lambda) * sum_x - n * lambda - c } @@ -351,7 +351,7 @@ As the redundant calculations within `ll_poisson1()` become more expensive with ```{r, message = FALSE, warning = FALSE} bench_poisson <- function(x_length) { x <- rpois(x_length, 100L) - + bench::mark( llp1 = optimise(ll_poisson1(x), c(0, 100), maximum = TRUE), llp2 = optimise(ll_poisson2(x), c(0, 100), maximum = TRUE), @@ -363,7 +363,7 @@ performances <- map_dfr(10^(1:5), bench_poisson) df_perf <- tibble( x_length = rep(10^(1:5), each = 2), - method = rep(attr(performances$expression, "description"), 5), + method = attr(performances$expression, "description"), median = performances$median ) @@ -416,7 +416,7 @@ mean <- function(x) stop("Hi!") detach(funs) env_bind(globalenv(), !!!funs) -mean <- function(x) stop("Hi!") +mean <- function(x) stop("Hi!") env_unbind(globalenv(), names(funs)) ``` From 9992837a1d8b86402b0d0bd991da35a43210d212 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 20:34:41 -0500 Subject: [PATCH 03/25] fix DESCRIPTION warning --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index c4861f01..26734c95 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -178,4 +178,4 @@ Imports: bslib Suggests: downlit, - xml2 \ No newline at end of file + xml2 From 2268729db6e780cc821ed79426bf5a3fd54cad49 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 20:41:34 -0500 Subject: [PATCH 04/25] explicitly install emo:: from github --- DESCRIPTION | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 26734c95..3c811820 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -21,7 +21,7 @@ Imports: AnnotationDbi, askpass, assertthat, - backports, + backports, base64enc, bench, BH, @@ -29,7 +29,7 @@ Imports: bindr, bindrcpp, Biobase, - BiocGenerics, + BiocGenerics, BiocManager, bit, bit64, @@ -41,55 +41,55 @@ Imports: caTools, cellranger, checkmate, - cli, + cli, clipr, clisymbols, colorspace, crayon, crosstalk, - curl, + curl, data.table, DBI, DEoptimR, desc, devtools, - dichromat, + dichromat, digest, doParallel, dplyr, dynamicTreeCut, - ellipsis, + ellipsis, evaluate, fansi, fastcluster, fastmatch, - fit.models, + fit.models, forcats, foreach, Formula, fs, generics, - ggplot2, + ggplot2, gh, git2r, glue, GO.db, gridExtra, gtable, - hexbin, + hexbin, highr, Hmisc, hms, htmlTable, htmltools, - htmlwidgets, + htmlwidgets, httpuv, httr, impute, ini, IRanges, iterators, - jsonlite, + jsonlite, knitr, labeling, later, @@ -101,81 +101,82 @@ Imports: markdown, matrixStats, memoise, - microbenchmark, + microbenchmark, mime, mnormt, munsell, mvtnorm, openssl, - packrat, + packrat, pcaPP, pillar, pkgbuild, pkgconfig, pkgload, - plogr, + plogr, plotly, plyr, preprocessCore, prettyunits, - processx, + processx, profmem, profvis, progress, promises, pryr, ps, - psych, + psych, purrr, R6, rcmdcheck, RColorBrewer, Rcpp, RcppEigen, - RcppRoll, + RcppRoll, readxl, rematch, remotes, reshape2, rlang, - rmarkdown, + rmarkdown, robust, robustbase, rprojroot, rrcov, RSQLite, - rstudioapi, + rstudioapi, S4Vectors, scales, sessioninfo, shiny, sloop, slider, - sourcetools, + sourcetools, speedglm, stringi, stringr, sys, tibble, tidyr, - tidyselect, + tidyselect, tinytex, TTR, usethis, utf8, viridis, - viridisLite, + viridisLite, WGCNA, whisker, withr, xfun, xopen, xtable, - xts, + xts, yaml, zoo, palmerpenguins, - bslib + bslib, + emo (>= 0.0.0.9000) Suggests: downlit, xml2 From 93afcaa486929aad9804bd37ac196bcf35002e3d Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 20:45:20 -0500 Subject: [PATCH 05/25] add Pacha to aut --- DESCRIPTION | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3c811820..7da1bd82 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -6,7 +6,11 @@ Authors@R: c(person("Malte", "Grosser", email = "malte.grosser@gmail.com", person("Henning", "Bumann", email = "henningway@posteo.org", role = c("aut", "cre")), person("Hadley", "Wickham", email = "hadley@rstudio.com", - role = c("aut", "cre")) + role = c("aut", "cre")), + person("Mauricio", "Vargas Sepulveda", + email = "m.sepulveda@mail.utoronto.ca", + role = c("aut"), + comment = c(ORCID = "0000-0003-1017-7574"))) Description: Provides Solutions to Advanced R. See http://advanced-r-solutions.rbind.io/ for rendered version. Depends: R (>= 4.0.0) License: CC BY-NC-SA 4.0 From 5e102b676847fe972529478a46c5c85ab17fe7da Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Mon, 22 Jan 2024 21:49:49 -0500 Subject: [PATCH 06/25] quarto ok up to S4 --- .gitignore | 4 + .travis.yml | 41 -- 000_Backpage_old.Rmd | 364 ------------------ 00_Backpage.Rmd | 34 -- 01_Preface.Rmd => 01_Preface.qmd | 16 +- ..._and_values.Rmd => 02_Names_and_values.qmd | 65 ++-- 03_Vectors.Rmd => 03_Vectors.qmd | 67 ++-- 04_Subsetting.Rmd => 04_Subsetting.qmd | 10 +- 05_Control_flow.Rmd => 05_Control_flow.qmd | 13 +- 06_Functions.Rmd => 06_Functions.qmd | 82 ++-- 07_Environments.Rmd => 07_Environments.qmd | 21 +- 08_Conditions.Rmd => 08_Conditions.qmd | 56 +-- 09_Functionals.Rmd => 09_Functionals.qmd | 59 ++- ...factories.Rmd => 10_Function_factories.qmd | 11 +- ...operators.Rmd => 11_Function_operators.qmd | 47 +-- 13_S3.Rmd => 12_S3.qmd | 17 +- 14_R6.Rmd => 13_R6.qmd | 14 +- 15_S4.Rmd => 14_S4.qmd | 58 +-- 99-rename-rmd-to-qmd.sh | 6 + _bookdown.yml | 35 -- _metadata.yml | 5 + _quarto.yml | 35 ++ index.Rmd => index.qmd | 25 +- 23 files changed, 323 insertions(+), 762 deletions(-) delete mode 100644 .travis.yml delete mode 100644 000_Backpage_old.Rmd delete mode 100644 00_Backpage.Rmd rename 01_Preface.Rmd => 01_Preface.qmd (98%) rename 02_Names_and_values.Rmd => 02_Names_and_values.qmd (92%) rename 03_Vectors.Rmd => 03_Vectors.qmd (93%) rename 04_Subsetting.Rmd => 04_Subsetting.qmd (98%) rename 05_Control_flow.Rmd => 05_Control_flow.qmd (97%) rename 06_Functions.Rmd => 06_Functions.qmd (97%) rename 07_Environments.Rmd => 07_Environments.qmd (97%) rename 08_Conditions.Rmd => 08_Conditions.qmd (94%) rename 09_Functionals.Rmd => 09_Functionals.qmd (96%) rename 10_Function_factories.Rmd => 10_Function_factories.qmd (99%) rename 11_Function_operators.Rmd => 11_Function_operators.qmd (95%) rename 13_S3.Rmd => 12_S3.qmd (99%) rename 14_R6.Rmd => 13_R6.qmd (99%) rename 15_S4.Rmd => 14_S4.qmd (93%) create mode 100644 99-rename-rmd-to-qmd.sh delete mode 100755 _bookdown.yml create mode 100644 _metadata.yml create mode 100644 _quarto.yml rename index.Rmd => index.qmd (78%) diff --git a/.gitignore b/.gitignore index 487c846b..afac1dc7 100755 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ libs .Rbuildignore .idea _main.docx + +/.quarto/ +_freeze +_cache$ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4c4fd226..00000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: R -r_github_packages: - - r-lib/lobstr - - allisonhorst/palmerpenguins -r: bioc-release -sudo: false - -cache: - packages: true - directories: - - $TRAVIS_BUILD_DIR/_bookdown_files - - $HOME/.npm - -addons: - apt: - packages: - - libgit2-dev - -before_install: - - mkdir ~/.R - - cp Makevars ~/.R - - nvm install stable - - npm install netlify-cli -g - -script: - - Rscript -e 'bookdown::render_book("index.Rmd")' - - Rscript -e 'file.copy("_redirects", bookdown:::output_dirname(NULL))' - -pandoc_version: 2.9.2.1 - -deploy: - provider: script - script: netlify deploy --dir="_book/" --prod - skip_cleanup: true - on: - branch: main - -notifications: - email: - - $EMAIL_TAZ - - $EMAIL_HB \ No newline at end of file diff --git a/000_Backpage_old.Rmd b/000_Backpage_old.Rmd deleted file mode 100644 index d142e0c5..00000000 --- a/000_Backpage_old.Rmd +++ /dev/null @@ -1,364 +0,0 @@ -# Book Cover old - -# Backpage -## Requirements/ Guidance from C&H -- First one or two paragraphs should present background, aims and scope, and what sets the book apart. -- Third (or second, if only one above) paragraph is actually a bulleted list of the key features (try to be as specific as possible). -- Final paragraph is a summary including audience (although this may feature at the beginning). -- If there is room, you can include a short author bio at the end. - -## gemeinsames Proposal -> “I learned a lot working through their solutions — it's a great way to broaden and deepen your understanding of R. (I should probably go through it again...)” - -- Greg Wilson | RStudio, PBC - - -### Paragraph 1/2 -This book provides solutions to the exercises contained in the 2nd Edition of Advanced R (Wickham, 2019). Advanced R introduces programmers and R users to various aspects of modern R programming. Additionally, it includes many challenging exercises to internalize and expand the content. - -This solutions manual will help you to make the most out of these exercises, and offers a convenient point of reference. The entire content has been carefully prepared and revised with the help of Hadley Wickham. - -### specific key features -This book will support your study of the R language and -- provide worked solutions to all 284 exercises presented in Advanced R -- discuss implementation details and alternative solutions -- help you stay motivated and avoid getting stuck -- serves as a reference to check your own solutions -- summarise our own experience and learnings with the content - -### summary and audience -This book can act a helpful resource for anyone interested in improving their understanding of programming and the R language through Advanced R. - -# Author Bios (75-100 words long each) -### Malte Grosser -Malte Grosser is a business mathematician from Hamburg, who has been programming in R regularly since the beginning of his career. He is currently finishing his PhD on machine learning for stroke outcome prediction from medical images and develops solutions in business as a Data Scientist. Malte likes to promote and engage in the local R community and is the author of the snakecase package, which converts strings into arbitrary cases. - - - -### Henning Bumann -As a psychologist and statistician Henning enjoys making sense of data and is motivated to build data-driven solutions that are both beautiful and meaningful. He prefers free programming tools to support effective and transparent collaboration. He is happy to be an active member of the Hamburg R community and considers learning to code one of the most fortunate junctions in his professional life. Away from the computer Henning likes to take it easy and spend time in nature and with family and friends. - -### Hadley Wickham (from Adv R) -Hadley Wickham is Chief Scientist at RStudio, an Adjunct Professor at Stanford University and the University of Auckland, and a member of the R Foundation. He is the lead developer of the tidyverse, a collection of R packages, including ggplot2 and dplyr, designed to support data science. He is also the author of R for Data Science (with Garrett Grolemund), R Packages, and ggplot2: Elegant Graphics for Data Analysis. - - -# Maltes initiales Proposal für die Backpage - -- First one or two paragraphs should present background, aims and scope, and what sets the book apart. -- Third (or second, if only one above) paragraph is actually a bulleted list of the key features (try to be as specific as possible). -- Final paragraph is a summary including audience (although this may feature at the beginning). -- If there is room, you can include a short author bio at the end. - -Do you want to deepen your R-skills and build up knowledge to master the application of R from the bottom up? Advanced R Solutions gives you a great boost to fully internalise Hadley Wickham's Advanced R and benefit enormously from it in your everyday work. - -Advanced R provides programmers from all backgrounds with a comprehensive introduction into the world of professional R programming. It shows that, “despite its sometimes frustrating quirks, R is, at its heart, an elegant and beautiful language, well tailored for data science”. It gives you an entry to dive into the material yourself with almost 300(!) exercises, which are provided throughout its chapters. - -Advanced R Solutions supports you on this journey with appropriately detailed solutions for each of these exercises. The entire content, including the R-code, has been carefully prepared and revised with the help of Hadley Wickham. - -Working through the exercises and their solutions will give you a deep understanding of a variety of programming problems, many of which you might encounter again in your daily work. It will give you a great set of tools to solve these problems not only technically but also conceptually. In the process, you’ll developed a good sense of identifying meaningful measures to compare different approaches. While in some situations you will be able to transfer certain programming schemes directly, in many others far more elegant options might open up to you. As a positive side effect, your fluency in this language will notably increase. - - -# Meta data (for Advanced R and our book) - -# Requirements: -# * 150-200 words per chapter - -## 2. Names and values -In R, it is important to understand the distinction between an object and its name. Doing so will help you: - -* More accurately predict the performance and memory usage of your code. -* Write faster code by avoiding accidental copies, a major source of slow code. -* Better understand R’s functional programming tools. - -The goal of this chapter is to help you understand the distinction between names and values, and when R will copy an object. - -## 3. Vectors -This chapter discusses the most important family of data types in base R: vectors. While you’ve probably already used many (if not all) of the different types of vectors, you may not have thought deeply about how they’re interrelated. In this chapter, I won’t cover individual vector types in too much detail, but I will show you how all the types fit together as a whole. If you need more details, you can find them in R’s documentation. - -## 4. Subsetting -R’s subsetting operators are fast and powerful. Mastering them allows you to succinctly perform complex operations in a way that few other languages can match. Subsetting in R is easy to learn but hard to master because you need to internalise a number of interrelated concepts: - -* There are six ways to subset atomic vectors. -* There are three subsetting operators, [[, [, and $. -* Subsetting operators interact differently with different vector types (e.g., atomic vectors, lists, factors, matrices, and data frames). -* Subsetting can be combined with assignment. - -## 5. Control Flow -There are two primary tools of control flow: choices and loops. Choices, like if statements and switch() calls, allow you to run different code depending on the input. Loops, like for and while, allow you to repeatedly run code, typically with changing options. I’d expect that you’re already familiar with the basics of these functions so I’ll briefly cover some technical details and then introduce some useful, but lesser known, features. - -The condition system (messages, warnings, and errors), which you’ll learn about in Chapter 8, also provides non-local control flow. - -## 6. Functions -If you’re reading this book, you’ve probably already created many R functions and know how to use them to reduce duplication in your code. In this chapter, you’ll learn how to turn that informal, working knowledge into more rigorous, theoretical understanding. And while you’ll see some interesting tricks and techniques along the way, keep in mind that what you’ll learn here will be important for understanding the more advanced topics discussed later in the book. - -## 7. Environments -The environment is the data structure that powers scoping. This chapter dives deep into environments, describing their structure in depth, and using them to improve your understanding of the four scoping rules described in Section 6.4. Understanding environments is not necessary for day-to-day use of R. But they are important to understand because they power many important R features like lexical scoping, namespaces, and R6 classes, and interact with evaluation to give you powerful tools for making domain specific languages, like dplyr and ggplot2. - -## 8. Conditions -The condition system provides a paired set of tools that allow the author of a function to indicate that something unusual is happening, and the user of that function to deal with it. The function author signals conditions with functions like stop() (for errors), warning() (for warnings), and message() (for messages), then the function user can handle them with functions like tryCatch() and withCallingHandlers(). Understanding the condition system is important because you’ll often need to play both roles: signalling conditions from the functions you create, and handle conditions signalled by the functions you call. - -R offers a very powerful condition system based on ideas from Common Lisp. Like R’s approach to object-oriented programming, it is rather different to currently popular programming languages so it is easy to misunderstand, and there has been relatively little written about how to use it effectively. Historically, this has meant that few people (myself included) have taken full advantage of its power. The goal of this chapter is to remedy that situation. Here you will learn about the big ideas of R’s condition system, as well as learning a bunch of practical tools that will make your code stronger. - -I found two resources particularly useful when writing this chapter. You may also want to read them if you want to learn more about the inspirations and motivations for the system: - - A prototype of a condition system for R by Robert Gentleman and Luke Tierney. This describes an early version of R’s condition system. While the implementation has changed somewhat since this document was written, it provides a good overview of how the pieces fit together, and some motivation for its design. - -Beyond exception handling: conditions and restarts by Peter Seibel. This describes exception handling in Lisp, which happens to be very similar to R’s approach. It provides useful motivation and more sophisticated examples. I have provided an R translation of the chapter at http://adv-r.had.co.nz/beyond-exception-handling.html. - -I also found it helpful to work through the underlying C code that implements these ideas. If you’re interested in understanding how it all works, you might find my notes to be useful. - -## 9. Functionals - -A functional is a function that takes a function as an input and returns a vector as output. Here’s a simple functional: it calls the function provided as input with 1000 random uniform numbers. - -randomise <- function(f) f(runif(1e3)) -randomise(mean) -#> [1] 0.506 -randomise(mean) -#> [1] 0.501 -randomise(sum) -#> [1] 489 - -The chances are that you’ve already used a functional. You might have used for-loop replacements like base R’s lapply(), apply(), and tapply(); or purrr’s map(); or maybe you’ve used a mathematical functional like integrate() or optim(). - -A common use of functionals is as an alternative to for loops. For loops have a bad rap in R because many people believe they are slow51, but the real downside of for loops is that they’re very flexible: a loop conveys that you’re iterating, but not what should be done with the results. Just as it’s better to use while than repeat, and it’s better to use for than while (Section 5.3.2), it’s better to use a functional than for. Each functional is tailored for a specific task, so when you recognise the functional you immediately know why it’s being used. - -If you’re an experienced for loop user, switching to functionals is typically a pattern matching exercise. You look at the for loop and find a functional that matches the basic form. If one doesn’t exist, don’t try and torture an existing functional to fit the form you need. Instead, just leave it as a for loop! (Or once you’ve repeated the same loop two or more times, maybe think about writing your own functional). -Outline - -This chapter will focus on functionals provided by the purrr package.52 These functions have a consistent interface that makes it easier to understand the key ideas than their base equivalents, which have grown organically over many years. I’ll compare and contrast base R functions as we go, and then wrap up the chapter with a discussion of base functionals that don’t have purrr equivalents. - -## 10. Function factories - -A function factory is a function that makes functions. Here’s a very simple example: we use a function factory (power1()) to make two child functions (square() and cube()): - - power1 <- function(exp) { - function(x) { - x ^ exp - } - } - -square <- power1(2) -cube <- power1(3) - -Don’t worry if this doesn’t make sense yet, it should by the end of the chapter! - -I’ll call square() and cube() manufactured functions, but this is just a term to ease communication with other humans: from R’s perspective they are no different to functions created any other way. - -square(3) -#> [1] 9 -cube(3) -#> [1] 27 - -You have already learned about the individual components that make function factories possible: - - In Section 6.2.3, you learned about R’s first-class functions. In R, you bind a function to a name in the same way as you bind any object to a name: with <-. - -In Section 7.4.2, you learned that a function captures (encloses) the environment in which it is created. - -In Section 7.4.4, you learned that a function creates a new execution environment every time it is run. This environment is usually ephemeral, but here it becomes the enclosing environment of the manufactured function. - -In this chapter, you’ll learn how the non-obvious combination of these three features leads to the function factory. You’ll also see examples of their usage in visualisation and statistics. - -Of the three main functional programming tools (functionals, function factories, and function operators), function factories are the least used. Generally, they don’t tend to reduce overall code complexity but instead partition complexity into more easily digested chunks. Function factories are also an important building block for the very useful function operators, which you’ll learn about in Chapter 11. - -## 11. Function operators -In this chapter, you’ll learn about function operators. A function operator is a function that takes one (or more) functions as input and returns a function as output. The following code shows a simple function operator, chatty(). It wraps a function, making a new function that prints out its first argument. You might create a function like this because it gives you a window to see how functionals, like map_int(), work. - -chatty <- function(f) { - force(f) - - function(x, ...) { - res <- f(x, ...) - cat("Processing ", x, "\n", sep = "") - res - } -} -f <- function(x) x ^ 2 -s <- c(3, 2, 1) - -purrr::map_dbl(s, chatty(f)) -#> Processing 3 -#> Processing 2 -#> Processing 1 -#> [1] 9 4 1 - -Function operators are closely related to function factories; indeed they’re just a function factory that takes a function as input. Like factories, there’s nothing you can’t do without them, but they often allow you to factor out complexity in order to make your code more readable and reusable. - -Function operators are typically paired with functionals. If you’re using a for-loop, there’s rarely a reason to use a function operator, as it will make your code more complex for little gain. - -If you’re familiar with Python, decorators is just another name for function operators. - -## 12. Base types - -To talk about objects and OOP in R we first need to clear up a fundamental confusion about two uses of the word “object”. So far in this book, we’ve used the word in the general sense captured by John Chambers’ pithy quote: “Everything that exists in R is an object”. However, while everything is an object, not everything is object-oriented. This confusion arises because the base objects come from S, and were developed before anyone thought that S might need an OOP system. The tools and nomenclature evolved organically over many years without a single guiding principle. - -Most of the time, the distinction between objects and object-oriented objects is not important. But here we need to get into the nitty gritty details so we’ll use the terms base objects and OO objects to distinguish them. -Outline - -## 13. S3 -S3 is R’s first and simplest OO system. S3 is informal and ad hoc, but there is a certain elegance in its minimalism: you can’t take away any part of it and still have a useful OO system. For these reasons, you should use it, unless you have a compelling reason to do otherwise. S3 is the only OO system used in the base and stats packages, and it’s the most commonly used system in CRAN packages. - -S3 is very flexible, which means it allows you to do things that are quite ill-advised. If you’re coming from a strict environment like Java this will seem pretty frightening, but it gives R programmers a tremendous amount of freedom. It may be very difficult to prevent people from doing something you don’t want them to do, but your users will never be held back because there is something you haven’t implemented yet. Since S3 has few built-in constraints, the key to its successful use is applying the constraints yourself. This chapter will therefore teach you the conventions you should (almost) always follow. - -The goal of this chapter is to show you how the S3 system works, not how to use it effectively to create new classes and generics. I’d recommend coupling the theoretical knowledge from this chapter with the practical knowledge encoded in the vctrs package. - -## 14. R6 - -This chapter describes the R6 OOP system. R6 has two special properties: - -It uses the encapsulated OOP paradigm, which means that methods belong to objects, not generics, and you call them like object$method(). - -R6 objects are mutable, which means that they are modified in place, and hence have reference semantics. - -If you’ve learned OOP in another programming language, it’s likely that R6 will feel very natural, and you’ll be inclined to prefer it over S3. Resist the temptation to follow the path of least resistance: in most cases R6 will lead you to non-idiomatic R code. We’ll come back to this theme in Section 16.3. - -R6 is very similar to a base OOP system called reference classes, or RC for short. I describe why I teach R6 and not RC in Section 14.5. - -## 15. S4 - -S4 provides a formal approach to functional OOP. The underlying ideas are similar to S3 (the topic of Chapter 13), but implementation is much stricter and makes use of specialised functions for creating classes (setClass()), generics (setGeneric()), and methods (setMethod()). Additionally, S4 provides both multiple inheritance (i.e. a class can have multiple parents) and multiple dispatch (i.e. method dispatch can use the class of multiple arguments). - -An important new component of S4 is the slot, a named component of the object that is accessed using the specialised subsetting operator @ (pronounced at). The set of slots, and their classes, forms an important part of the definition of an S4 class. - -## 16. Trade-offs -You now know about the three most important OOP toolkits available in R. Now that you understand their basic operation and the principles that underlie them, we can start to compare and contrast the systems in order to understand their strengths and weaknesses. This will help you pick the system that is most likely to solve new problems. - -Overall, when picking an OO system, I recommend that you default to S3. S3 is simple, and widely used throughout base R and CRAN. While it’s far from perfect, its idiosyncrasies are well understood and there are known approaches to overcome most shortcomings. If you have an existing background in programming you are likely to lean towards R6, because it will feel familiar. I think you should resist this tendency for two reasons. Firstly, if you use R6 it’s very easy to create a non-idiomatic API that will feel very odd to native R users, and will have surprising pain points because of the reference semantics. Secondly, if you stick to R6, you’ll lose out on learning a new way of thinking about OOP that gives you a new set of tools for solving problems. - -## 17. Big picture -Metaprogramming is the hardest topic in this book because it brings together many formerly unrelated topics and forces you grapple with issues that you probably haven’t thought about before. You’ll also need to learn a lot of new vocabulary, and at first it will seem like every new term is defined by three other terms that you haven’t heard of. Even if you’re an experienced programmer in another language, your existing skills are unlikely to be much help as few modern popular languages expose the level of metaprogramming that R provides. So don’t be surprised if you’re frustrated or confused at first; this is a natural part of the process that happens to everyone! - -But I think it’s easier to learn metaprogramming now than ever before. Over the last few years, the theory and practice have matured substantially, providing a strong foundation paired with tools that allow you to solve common problems. In this chapter, you’ll get the big picture of all the main pieces and how they fit together. - -## 18. Expressions -To compute on the language, we first need to understand its structure. That requires some new vocabulary, some new tools, and some new ways of thinking about R code. The first of these is the distinction between an operation and its result. Take the following code, which multiplies a variable x by 10 and saves the result to a new variable called y. It doesn’t work because we haven’t defined a variable called x: - - y <- x * 10 -#> Error in eval(expr, envir, enclos): object 'x' not found - -It would be nice if we could capture the intent of the code without executing it. In other words, how can we separate our description of the action from the action itself? - - One way is to use rlang::expr(): - - z <- rlang::expr(y <- x * 10) -z -#> y <- x * 10 - -expr() returns an expression, an object that captures the structure of the code without evaluating it (i.e. running it). If you have an expression, you can evaluate it with base::eval(): - - x <- 4 -eval(z) -y -#> [1] 40 - -The focus of this chapter is the data structures that underlie expressions. Mastering this knowledge will allow you to inspect and modify captured code, and to generate code with code. We’ll come back to expr() in Chapter 19, and to eval() in Chapter 20. - -## 19. Quasiquotation -Now that you understand the tree structure of R code, it’s time to return to one of the fundamental ideas that make expr() and ast() work: quotation. In tidy evaluation, all quoting functions are actually quasiquoting functions because they also support unquoting. Where quotation is the act of capturing an unevaluated expression, unquotation is the ability to selectively evaluate parts of an otherwise quoted expression. Together, this is called quasiquotation. Quasiquotation makes it easy to create functions that combine code written by the function’s author with code written by the function’s user. This helps to solve a wide variety of challenging problems. - -Quasiquotation is one of the three pillars of tidy evaluation. You’ll learn about the other two (quosures and the data mask) in Chapter 20. When used alone, quasiquotation is most useful for programming, particularly for generating code. But when it’s combined with the other techniques, tidy evaluation becomes a powerful tool for data analysis. - -## 20. Evaluation -The user-facing inverse of quotation is unquotation: it gives the user the ability to selectively evaluate parts of an otherwise quoted argument. The developer-facing complement of quotation is evaluation: this gives the developer the ability to evaluate quoted expressions in custom environments to achieve specific goals. - -This chapter begins with a discussion of evaluation in its purest form. You’ll learn how eval() evaluates an expression in an environment, and then how it can be used to implement a number of important base R functions. Once you have the basics under your belt, you’ll learn extensions to evaluation that are needed for robustness. There are two big new ideas: - - The quosure: a data structure that captures an expression along with its associated environment, as found in function arguments. - -The data mask, which makes it easier to evaluate an expression in the context of a data frame. This introduces potential evaluation ambiguity which we’ll then resolve with data pronouns. - -Together, quasiquotation, quosures, and data masks form what we call tidy evaluation, or tidy eval for short. Tidy eval provides a principled approach to non-standard evaluation that makes it possible to use such functions both interactively and embedded with other functions. Tidy evaluation is the most important practical implication of all this theory so we’ll spend a little time exploring the implications. The chapter finishes off with a discussion of the closest related approaches in base R, and how you can program around their drawbacks. - -## 21. Translating R code -The combination of first-class environments, lexical scoping, and metaprogramming gives us a powerful toolkit for translating R code into other languages. One fully-fledged example of this idea is dbplyr, which powers the database backends for dplyr, allowing you to express data manipulation in R and automatically translate it into SQL. You can see the key idea in translate_sql() which takes R code and returns the equivalent SQL: - - library(dbplyr) -translate_sql(x ^ 2) -#> POWER(`x`, 2.0) -translate_sql(x < 5 & !is.na(x)) -#> `x` < 5.0 AND NOT(((`x`) IS NULL)) -translate_sql(!first %in% c("John", "Roger", "Robert")) -#> NOT(`first` IN ('John', 'Roger', 'Robert')) -translate_sql(select == 7) -#> `select` = 7.0 - -Translating R to SQL is complex because of the many idiosyncrasies of SQL dialects, so here I’ll develop two simple, but useful, domain specific languages (DSL): one to generate HTML, and the other to generate mathematical equations in LaTeX. - -If you’re interested in learning more about domain specific languages in general, I highly recommend Domain Specific Languages.106 It discusses many options for creating a DSL and provides many examples of different languages. - -## 22. Debugging -What do you do when R code throws an unexpected error? What tools do you have to find and fix the problem? This chapter will teach you the art and science of debugging, starting with a general strategy, then following up with specific tools. - -I’ll show the tools provided by both R and the RStudio IDE. I recommend using RStudio’s tools if possible, but I’ll also show you the equivalents that work everywhere. You may also want to refer to the official RStudio debugging documentation which always reflects the latest version of RStudio. - -NB: You shouldn’t need to use these tools when writing new functions. If you find yourself using them frequently with new code, reconsider your approach. Instead of trying to write one big function all at once, work interactively on small pieces. If you start small, you can quickly identify why something doesn’t work, and don’t need sophisticated debugging tools. - -## 23. Measuring performance -Before you can make your code faster, you first need to figure out what’s making it slow. This sounds easy, but it’s not. Even experienced programmers have a hard time identifying bottlenecks in their code. So instead of relying on your intuition, you should profile your code: measure the run-time of each line of code using realistic inputs. - -Once you’ve identified bottlenecks you’ll need to carefully experiment with alternatives to find faster code that is still equivalent. In Chapter 24 you’ll learn a bunch of ways to speed up code, but first you need to learn how to microbenchmark so that you can precisely measure the difference in performance. - -## 24. Improving performance -Once you’ve used profiling to identify a bottleneck, you need to make it faster. It’s difficult to provide general advice on improving performance, but I try my best with four techniques that can be applied in many situations. I’ll also suggest a general strategy for performance optimisation that helps ensure that your faster code is still correct. - -It’s easy to get caught up in trying to remove all bottlenecks. Don’t! Your time is valuable and is better spent analysing your data, not eliminating possible inefficiencies in your code. Be pragmatic: don’t spend hours of your time to save seconds of computer time. To enforce this advice, you should set a goal time for your code and optimise only up to that goal. This means you will not eliminate all bottlenecks. Some you will not get to because you’ve met your goal. Others you may need to pass over and accept either because there is no quick and easy solution or because the code is already well optimised and no significant improvement is possible. Accept these possibilities and move on to the next candidate. - -If you’d like to learn more about the performance characteristics of the R language, I’d highly recommend Evaluating the Design of the R Language.111 It draws conclusions by combining a modified R interpreter with a wide set of code found in the wild. - -## 25. Rewriting R code in C++ -Sometimes R code just isn’t fast enough. You’ve used profiling to figure out where your bottlenecks are, and you’ve done everything you can in R, but your code still isn’t fast enough. In this chapter you’ll learn how to improve performance by rewriting key functions in C++. This magic comes by way of the Rcpp package117 (with key contributions by Doug Bates, John Chambers, and JJ Allaire). - -Rcpp makes it very simple to connect C++ to R. While it is possible to write C or Fortran code for use in R, it will be painful by comparison. Rcpp provides a clean, approachable API that lets you write high-performance code, insulated from R’s complex C API. - -Typical bottlenecks that C++ can address include: - - Loops that can’t be easily vectorised because subsequent iterations depend on previous ones. - -Recursive functions, or problems which involve calling functions millions of times. The overhead of calling a function in C++ is much lower than in R. - -Problems that require advanced data structures and algorithms that R doesn’t provide. Through the standard template library (STL), C++ has efficient implementations of many important data structures, from ordered maps to double-ended queues. - -The aim of this chapter is to discuss only those aspects of C++ and Rcpp that are absolutely necessary to help you eliminate bottlenecks in your code. We won’t spend much time on advanced features like object-oriented programming or templates because the focus is on writing small, self-contained functions, not big programs. A working knowledge of C++ is helpful, but not essential. Many good tutorials and references are freely available, including http://www.learncpp.com/ and https://en.cppreference.com/w/cpp. For more advanced topics, the Effective C++ series by Scott Meyers is a popular choice. - - -## Next iteration: - -## Backpage -> “I learned a lot working through their solutions — it's a great way to broaden and deepen your understanding of R. (I should probably go through it again...)” - -- Greg Wilson | RStudio, PBC - - -This book offers solutions to the 284 exercises in Advanced R. It is based on our own efforts to work through Advanced R to learn the R programming language in an efficient and sustainable way. To this end, we have carefully documented all our solutions and made them as accessible and clear as possible. All solutions were carefully reviewed by Hadley Wickham, who also provided guidance when some exercises seemed unsolvable at first. - -Working through the exercises and their solutions will give you a deep understanding of a variety of programming challenges, many of which are relevant to everyday work. This will expand your set of tools to solve these problems on a technical and conceptual level. You will develop your ability to identify and compare different solution approaches. In some situations you may be able to transfer a specific programming scheme directly, in others far more elegant alternatives may open up to you. As a positive side effect, your fluency in R will notably improve. - -From a technical and R-specific perspective, you will learn about: - -* When R makes copies, how this affects memory and performance, and how to address this. -* The characteristics of base R's vector data types and the implications. -* How to choose between R's different subsetting options. -* Everything you could ever want to know about functions in R. -* How to use rlang to work with environments and how to recurse over environments. -* The differences between calling and exiting handlers. -* How to employ functional programming to efficiently solve modular tasks involving, e.g. iterations or parametrizations. -* The mechanics, usage and limitations of R's commonly used and highly pragmatic S3 OO system. -* When and how to work with the R6 OO system, which takes a more classical and structured approach to OO programming and should feel very natural if you already know OO programming from other languages. -* Working with R's S4 OO system, which extends S3 with multiple dispatch and inheritance and much stricter formalities. -* How R parses expressions into abstract syntax trees and evaluates their elements. -* How you can modify these elements and even change their environments within this process. -* How to use this technique to create domain specific languages such as HTML or LaTeX purely based on systematic conversion of R code. -* How to identify performance bottlenecks via profiling and to compare different approaches via benchmarks. -* Different strategies for optimising R code, such as using pre-optimised functions, vectorisation, using solutions from e.g. algebra or simply reducing the scope of a function. -* Rewriting R code in C++ via the Rcpp package. - -Malte Grosser is a business mathematician from Hamburg, who has been programming in R regularly since the beginning of his career. He is currently finishing his PhD on machine learning for stroke outcome prediction from medical images and develops solutions in business as a Data Scientist. Malte likes to promote and engage in the local R community and is the author of the snakecase package, which converts strings into arbitrary cases. - -Henning Bumann is a psychologist and statistician who enjoys making sense of data and is motivated to build data-driven solutions that are beautiful and meaningful. He prefers free programming tools to support effective and transparent collaboration. He is happy to be an active member of the Hamburg R community and considers learning to code one of the most fortunate junctions in his professional life. Away from the computer Henning likes to take it easy and spend time in nature and with family and friends. - -Hadley Wickham is the original author of Advanced R, created all the exercises and supported this project by reviewing all the proposed answers. - -## (Or longer version from Advanced R) - -Hadley Wickham is Chief Scientist at RStudio, an Adjunct Professor at Stanford University and the University of Auckland, and a member of the R Foundation. He is the lead developer of the tidyverse, a collection of R packages, including ggplot2 and dplyr, designed to support data science. He is also the author of R for Data Science (with Garrett Grolemund), R Packages, and ggplot2: Elegant Graphics for Data Analysis. \ No newline at end of file diff --git a/00_Backpage.Rmd b/00_Backpage.Rmd deleted file mode 100644 index a2a4ce26..00000000 --- a/00_Backpage.Rmd +++ /dev/null @@ -1,34 +0,0 @@ -# Advanced R Solutions -“I learned a lot working through their solutions — it's a great way to broaden and deepen your -understanding of R. (I should probably go through it again...)” -- Greg Wilson, RStudio - -This book offers solutions to all 284 exercises in ___Advanced R, Second Edition___. All the solutions have been -carefully documented, and made to be as clear and accessible as possible. Working through the -exercises and their solutions will give you a deeper understanding of a variety of programming -challenges, many of which are relevant to everyday work. This will expand your set of tools on a -technical and conceptual level. You will be able to transfer many of the specific programming schemes -directly, and will discover far more elegant solutions to everyday problems. - -Features: -* When R creates copies, and how it affects memory usage and code performance -* Everything you could ever want to know about functions -* The differences between calling and exiting handlers -* How to employ functional programming to solve modular tasks -* The motivation, mechanics, usage, and limitations of R's highly pragmatic S3 OO system -* The R6 OO system, which is more like OO programming in other languages -* The rules that R uses to parse and evaluate expressions -* How to use metaprogramming to generate HTML or LaTeX with elegant R code -* How to identify and resolve performance bottlenecks - -Malte Grosser is a business mathematician from Hamburg, who has been programming in R regularly -since the beginning of his career. He is currently finishing his PhD on machine learning for stroke -outcome prediction and develops solutions in business as a data scientist. - -Henning Bumann is a psychologist and statistician who enjoys making sense of data and is motivated to -build data-driven solutions that are beautiful and meaningful. He prefers free programming tools to -support effective and transparent collaboration. - -Hadley Wickham is Chief Scientist at RStudio, an Adjunct Professor at Stanford University and the -University of Auckland, and a member of the R Foundation. He is the lead developer of the tidyverse, a -collection of R packages, including ggplot2 and dplyr, designed to support data science. \ No newline at end of file diff --git a/01_Preface.Rmd b/01_Preface.qmd similarity index 98% rename from 01_Preface.Rmd rename to 01_Preface.qmd index 25b81ae8..1f591e55 100644 --- a/01_Preface.Rmd +++ b/01_Preface.qmd @@ -1,3 +1,7 @@ +--- +bibliography: references.bib +--- + # Preface {-} Welcome to *Advanced R Solutions*! @@ -72,7 +76,7 @@ contribs_all <- contribs_all %>% unique() # Get info for all contributors needed_json <- map( - contribs_all$login, + contribs_all$login, ~ gh::gh("/users/:username", username = .x) ) info_all <- tibble( @@ -88,15 +92,15 @@ write_csv(info_all, "contributors.csv") library(dplyr) contributors <- read.csv("contributors.csv", encoding = "UTF-8") -contributors <- contributors %>% - filter(!login %in% c("hadley", "henningsway", "Tazinho", "toebR")) %>% +contributors <- contributors %>% + filter(!login %in% c("hadley", "henningsway", "Tazinho", "toebR")) %>% mutate( login = paste0("\\@", login), desc = ifelse(is.na(name), login, paste0(name, " (", login, ")")) - ) %>% + ) %>% arrange(login) -cat(glue::glue_collapse(contributors$desc, sep = ", ", last = ", and ")) +cat(glue::glue_collapse(contributors$desc, sep = ", ", last = ", and ")) cat(".\n") ``` @@ -140,3 +144,5 @@ See you around! Malte Grosser [`@malte_grosser`](https://twitter.com/malte_grosser) Henning Bumann [`@henningsway`](https://twitter.com/henningsway) + +Mauricio Vargas Sepulveda `m.sepulveda@mail.utoronto.ca` diff --git a/02_Names_and_values.Rmd b/02_Names_and_values.qmd similarity index 92% rename from 02_Names_and_values.Rmd rename to 02_Names_and_values.qmd index 28f68e8b..a699ff02 100755 --- a/02_Names_and_values.Rmd +++ b/02_Names_and_values.qmd @@ -1,27 +1,22 @@ -\mainmatter +--- +bibliography: references.bib +--- ```{r, include = FALSE} source("common.R") ``` -# (PART) Foundations {-} - -\stepcounter{chapter} # Names and values - ## Prerequisites {-} - In this chapter we will use the `{lobstr}` package [@lobstr] to help answer questions regarding the internal representation of R objects. ```{r setup, message = FALSE} -library(lobstr) +library(lobstr) ``` -\stepcounter{section} ## Binding basics - __[Q1]{.Q}__: Explain the relationship between `a`, `b`, `c`, and `d` in the following code: @@ -76,27 +71,27 @@ Three main mechanisms ensure syntactically valid names (see `?make.names`): 1. Names that do not start with a letter or a dot will be prepended with an `"X"`. ```{r} - make.names("") # prepending "x" +make.names("") # prepending "x" ``` The same holds for names that begin with a dot followed by a number. ```{r} - make.names(".1") # prepending "X" +make.names(".1") # prepending "X" ``` 2. Additionally, non-valid characters are replaced by a dot. ```{r} - make.names("non-valid") # "." replacement - make.names("@") # prepending "X" + "." replacement - make.names(" R") # prepending "X" + ".." replacement +make.names("non-valid") # "." replacement +make.names("@") # prepending "X" + "." replacement +make.names(" R") # prepending "X" + ".." replacement ``` 3. Reserved R keywords (see `?reserved`) are suffixed by a dot. ```{r} - make.names("if") # "." suffix +make.names("if") # "." suffix ``` Interestingly, some of these transformations are influenced by the current locale. From `?make.names`: @@ -108,14 +103,13 @@ __[Q5]{.Q}__: I slightly simplified the rules that govern syntactic names. Why i __[A]{.solved}__: `.123e1` is not a syntactic name, because it starts with one dot which is followed by a number. This makes it a double, `1.23`. ## Copy-on-modify - __[Q1]{.Q}__: Why is `tracemem(1:10)` not useful? __[A]{.solved}__: When `1:10` is called an object with an address in memory is created, but it is not bound to a name. Therefore, the object cannot be called or manipulated from R. As no copies will be made, it is not useful to track the object for copying. ```{r} -obj_addr(1:10) # the object exists, but has no name +obj_addr(1:10) # the object exists, but has no name ``` __[Q2]{.Q}__: Explain why `tracemem()` shows two copies when you run this code. Hint: carefully look at the difference between this code and the code shown earlier in the section. @@ -135,7 +129,7 @@ tracemem(x) #> <0x66a4a70> x[[3]] <- 4 -#> tracemem[0x55eec7b3af38 -> 0x55eec774cc18]: +#> tracemem[0x55eec7b3af38 -> 0x55eec774cc18]: ``` We can avoid the copy by sub-assigning an integer instead of a double: @@ -162,7 +156,8 @@ __[A]{.solved}__: `a` contains a reference to an address with the value `1:10`. ```{r, echo = FALSE, out.width='180pt'} knitr::include_graphics("images/names_values/copy_on_modify_fig3.png", - dpi = 300) + dpi = 300 +) ``` We can confirm these relationships by inspecting the reference tree in R. @@ -192,13 +187,14 @@ __[A]{.solved}__: The initial reference tree of `x` shows that the name `x` bind x <- list(1:10) ref(x) -#> █ [1:0x55853b74ff40] -#> └─[2:0x534t3abffad8] +#> █ [1:0x55853b74ff40] +#> └─[2:0x534t3abffad8] ``` ```{r, echo = FALSE, out.width='135pt'} knitr::include_graphics("images/names_values/copy_on_modify_fig1.png", - dpi = 300) + dpi = 300 +) ``` When `x` is assigned to an element of itself, copy-on-modify takes place and the list is copied to a new address in memory. @@ -213,15 +209,16 @@ The list object previously bound to `x` is now referenced in the newly created l ```{r, eval = FALSE} ref(x) -#> █ [1:0x5d553bacdcd8] -#> ├─[2:0x534t3abffad8] -#> └─█ [3:0x55853b74ff40] -#> └─[2:0x534t3abffad8] +#> █ [1:0x5d553bacdcd8] +#> ├─[2:0x534t3abffad8] +#> └─█ [3:0x55853b74ff40] +#> └─[2:0x534t3abffad8] ``` ```{r, echo = FALSE, out.width = '150pt'} knitr::include_graphics("images/names_values/copy_on_modify_fig2.png", - dpi = 300) + dpi = 300 +) ``` ## Object size @@ -349,7 +346,7 @@ obj_size(b) The second element of `b` still references the same address as `a`, so the combined size of `a` and `b` is the same as `b`. ```{r} -obj_size(a, b) +obj_size(a, b) ref(a, b) ``` @@ -357,14 +354,14 @@ When we modify the second element of `b`, this element will also point to a new ```{r} b[[2]][[1]] <- 10 -obj_size(b) +obj_size(b) ``` However, as `b` doesn't share references with `a` anymore, the memory usage of the combined objects increases. ```{r} ref(a, b) -obj_size(a, b) +obj_size(a, b) ``` ## Modify-in-place @@ -380,18 +377,18 @@ x[[1]] <- x __[A]{.solved}__: In this situation copy-on-modify prevents the creation of a circular list. Let us step through the details: ```{r, eval = FALSE} -x <- list() # creates initial object +x <- list() # creates initial object obj_addr(x) #> [1] "0x55862f23ab80" tracemem(x) #> [1] "<0x55862f23ab80>" -x[[1]] <- x # Copy-on-modify triggers new copy +x[[1]] <- x # Copy-on-modify triggers new copy #> tracemem[0x55862f23ab80 -> 0x55862e8ce028]: -obj_addr(x) # copied object has new memory address +obj_addr(x) # copied object has new memory address #> [1] "0x55862e8ce028" -obj_addr(x[[1]]) # list element contains old memory address +obj_addr(x[[1]]) # list element contains old memory address #> [1] "0x55862f23ab80" ``` diff --git a/03_Vectors.Rmd b/03_Vectors.qmd similarity index 93% rename from 03_Vectors.Rmd rename to 03_Vectors.qmd index 115fca4b..5d09ca1e 100755 --- a/03_Vectors.Rmd +++ b/03_Vectors.qmd @@ -1,13 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Vectors - -\stepcounter{section} ## Atomic vectors - __[Q1]{.Q}__: How do you create raw and complex scalars? (See `?raw` and `?complex`.) @@ -31,9 +32,9 @@ You can create purely imaginary numbers (e.g.) `1i`, but there is no way to crea __[Q2]{.Q}__: Test your knowledge of vector coercion rules by predicting the output of the following uses of `c()`: ```{r, eval = FALSE} -c(1, FALSE) # will be coerced to double -> 1 0 -c("a", 1) # will be coerced to character -> "a" "1" -c(TRUE, 1L) # will be coerced to integer -> 1 1 +c(1, FALSE) # will be coerced to double -> 1 0 +c("a", 1) # will be coerced to character -> "a" "1" +c(TRUE, 1L) # will be coerced to integer -> 1 1 ``` __[Q3]{.Q}__: Why is `1 == "1"` true? Why is `-1 < FALSE` true? Why is `"one" < 2` false? @@ -55,7 +56,6 @@ __[A]{.solved}__: The documentation states that: Atomic vectors are defined in *Advanced R* as objects of type logical, integer, double, complex, character or raw. Vectors are defined as atomic vectors or lists. ## Attributes - __[Q1]{.Q}__: How is `setNames()` implemented? How is `unname()` implemented? Read the source code. @@ -71,17 +71,19 @@ setNames <- function(object = nm, nm) { Because the data argument comes first, `setNames()` also works well with the magrittr-pipe operator. When no first argument is given, the result is a named vector (this is rather untypical as required arguments usually come first): ```{r} -setNames( , c("a", "b", "c")) +setNames(, c("a", "b", "c")) ``` `unname()` is implemented in the following way: ```{r, eval = FALSE} unname <- function(obj, force = FALSE) { - if (!is.null(names(obj))) + if (!is.null(names(obj))) { names(obj) <- NULL - if (!is.null(dimnames(obj)) && (force || !is.data.frame(obj))) + } + if (!is.null(dimnames(obj)) && (force || !is.data.frame(obj))) { dimnames(obj) <- NULL + } obj } ``` @@ -111,9 +113,9 @@ NCOL(x) __[Q3]{.Q}__: How would you describe the following three objects? What makes them different to `1:5`? ```{r} -x1 <- array(1:5, c(1, 1, 5)) # 1 row, 1 column, 5 in third dim. -x2 <- array(1:5, c(1, 5, 1)) # 1 row, 5 columns, 1 in third dim. -x3 <- array(1:5, c(5, 1, 1)) # 5 rows, 1 column, 1 in third dim. +x1 <- array(1:5, c(1, 1, 5)) # 1 row, 1 column, 5 in third dim. +x2 <- array(1:5, c(1, 5, 1)) # 1 row, 5 columns, 1 in third dim. +x3 <- array(1:5, c(5, 1, 1)) # 5 rows, 1 column, 1 in third dim. ``` __[A]{.solved}__: These are all "one dimensional". If you imagine a 3d cube, `x1` is in the x-dimension, `x2` is in the y-dimension, and `x3` is in the z-dimension. In contrast to `1:5`, `x1`, `x2` and `x3` have a `dim` attribute. @@ -144,7 +146,6 @@ attr(foo, which = "comment") ``` ## S3 atomic vectors - __[Q1]{.Q}__: What sort of object does `table()` return? What is its type? What attributes does it have? How does the dimensionality change as you tabulate more variables? @@ -157,8 +158,8 @@ typeof(x) attributes(x) # Subset x like it's an array -x[ , , 1] -x[ , , 2] +x[, , 1] +x[, , 2] ``` __[Q2]{.Q}__: What happens to a factor when you modify its levels? @@ -201,7 +202,6 @@ as.integer(f3) ``` ## Lists - __[Q1]{.Q}__: List all the ways that a list differs from an atomic vector. @@ -212,20 +212,20 @@ __[A]{.solved}__: To summarise: - Atomic vectors point to one address in memory, while lists contain a separate reference for each element. (This was described in the list sections of the [vectors](https://adv-r.hadley.nz/vectors-chap.html#lists) and the [names and values](https://adv-r.hadley.nz/names-values.html#list-references) chapters.) ```{r} - lobstr::ref(1:2) - lobstr::ref(list(1:2, 2)) +lobstr::ref(1:2) +lobstr::ref(list(1:2, 2)) ``` - Subsetting with out-of-bounds and `NA` values leads to different output. For example, `[` returns `NA` for atomics and `NULL` for lists. (This is described in more detail within the [subsetting chapter](https://adv-r.hadley.nz/subsetting.html).) ```{r} - # Subsetting atomic vectors - (1:2)[3] - (1:2)[NA] - - # Subsetting lists - as.list(1:2)[3] - as.list(1:2)[NA] +# Subsetting atomic vectors +(1:2)[3] +(1:2)[NA] + +# Subsetting lists +as.list(1:2)[3] +as.list(1:2)[NA] ``` __[Q2]{.Q}__: Why do you need to use `unlist()` to convert a list to an atomic vector? Why doesn't `as.vector()` work? @@ -244,7 +244,7 @@ __[Q3]{.Q}__: Compare and contrast `c()` and `unlist()` when combining a date an __[A]{.solved}__: Date and date-time objects are both built upon doubles. While dates store the number of days since the reference date 1970-01-01 (also known as “the Epoch”) in days, date-time-objects (POSIXct) store the time difference to this date in seconds. ```{r} -date <- as.Date("1970-01-02") +date <- as.Date("1970-01-02") dttm_ct <- as.POSIXct("1970-01-01 01:00", tz = "UTC") # Internal representations @@ -256,9 +256,9 @@ As the `c()` generic only dispatches on its first argument, combining date and d ```{r, eval = FALSE} # Output in R version 3.6.2 -c(date, dttm_ct) # equal to c.Date(date, dttm_ct) +c(date, dttm_ct) # equal to c.Date(date, dttm_ct) #> [1] "1970-01-02" "1979-11-10" -c(dttm_ct, date) # equal to c.POSIXct(date, dttm_ct) +c(dttm_ct, date) # equal to c.POSIXct(date, dttm_ct) #> [1] "1970-01-01 02:00:00 CET" "1970-01-01 01:00:01 CET" ``` @@ -268,7 +268,7 @@ We can highlight these mechanics by the following code: ```{r, eval = FALSE} # Output in R version 3.6.2 -unclass(c(date, dttm_ct)) # internal representation +unclass(c(date, dttm_ct)) # internal representation #> [1] 1 3600 date + 3599 #> "1979-11-10" @@ -297,7 +297,7 @@ Let's look at `unlist()`, which operates on list input. ```{r} # Attributes are stripped -unlist(list(date, dttm_ct)) +unlist(list(date, dttm_ct)) ``` We see again that dates and date-times are internally stored as doubles. Unfortunately, this is all we are left with, when unlist strips the attributes of the list. @@ -305,7 +305,6 @@ We see again that dates and date-times are internally stored as doubles. Unfortu To summarise: `c()` coerces types and strips time zones. Errors may have occurred in older R versions because of inappropriate method dispatch/immature methods. `unlist()` strips attributes. ## Data frames and tibbles - __[Q1]{.Q}__: Can you have a data frame with zero rows? What about zero columns? @@ -316,7 +315,7 @@ Create a 0-row, 0-column, or an empty data frame directly: ```{r} data.frame(a = integer(), b = logical()) -data.frame(row.names = 1:3) # or data.frame()[1:3, ] +data.frame(row.names = 1:3) # or data.frame()[1:3, ] data.frame() ``` @@ -326,7 +325,7 @@ Create similar data frames via subsetting the respective dimension with either ` ```{r} mtcars[0, ] -mtcars[ , 0] # or mtcars[0] +mtcars[, 0] # or mtcars[0] mtcars[0, 0] ``` diff --git a/04_Subsetting.Rmd b/04_Subsetting.qmd similarity index 98% rename from 04_Subsetting.Rmd rename to 04_Subsetting.qmd index f6eb3da0..0a567fca 100755 --- a/04_Subsetting.Rmd +++ b/04_Subsetting.qmd @@ -1,13 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Subsetting - -\stepcounter{section} ## Selecting multiple elements - __[Q1]{.Q}__: Fix each of the following common data frame subsetting errors: @@ -83,7 +84,6 @@ __[Q6]{.Q}__: What does `df[is.na(df)] <- 0` do? How does it work? __[A]{.solved}__: This expression replaces the `NA`s in `df` with `0`. Here `is.na(df)` returns a logical matrix that encodes the position of the missing values in `df`. Subsetting and assignment are then combined to replace only the missing values. ## Selecting a single element - __[Q1]{.Q}__: Brainstorm as many ways as possible to extract the third value from the `cyl` variable in the `mtcars` dataset. @@ -126,9 +126,7 @@ summary(mod)$r.squared (Tip: The [`{broom}` package](https://github.com/tidymodels/broom) [@broom] provides a very useful approach to work with models in a tidy way.) -\stepcounter{section} ## Applications - __[Q1]{.Q}__: How would you randomly permute the columns of a data frame? (This is an important technique in random forests.) Can you simultaneously permute the rows and columns in one step? diff --git a/05_Control_flow.Rmd b/05_Control_flow.qmd similarity index 97% rename from 05_Control_flow.Rmd rename to 05_Control_flow.qmd index b366395a..cde80a6b 100644 --- a/05_Control_flow.Rmd +++ b/05_Control_flow.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Control flow - -\stepcounter{section} + ## Choices - __[Q1]{.Q}__: What type of vector does each of the following calls to `ifelse()` return? @@ -47,7 +49,6 @@ if (length(x)) "not empty" else "empty" __[A]{.solved}__: `if()` expects a logical condition, but also accepts a numeric vector where `0` is treated as `FALSE` and all other numbers are treated as `TRUE`. Numerical missing values (including `NaN`) lead to an error in the same way that a logical missing, `NA`, does. ## Loops - __[Q1]{.Q}__: Why does this code succeed without errors or warnings? @@ -55,7 +56,7 @@ __[Q1]{.Q}__: Why does this code succeed without errors or warnings? x <- numeric() out <- vector("list", length(x)) for (i in 1:length(x)) { - out[i] <- x[i] ^ 2 + out[i] <- x[i]^2 } out ``` @@ -89,7 +90,7 @@ __[Q3]{.Q}__: What does the following code tell you about when the index is upda ```{r} for (i in 1:3) { i <- i * 2 - print(i) + print(i) } ``` diff --git a/06_Functions.Rmd b/06_Functions.qmd similarity index 97% rename from 06_Functions.Rmd rename to 06_Functions.qmd index bceacd53..6694c5f3 100755 --- a/06_Functions.Rmd +++ b/06_Functions.qmd @@ -1,13 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Functions - -\stepcounter{section} ## Function fundamentals - __[Q1]{.Q}__: Given a name, like `"mean"`, `match.fun()` lets you find a function. Given a function, can you find its name? Why doesn't that make sense in R? @@ -72,40 +73,40 @@ __[A]{.solved}__: Let's look at each sub-question separately: a. To find the function with the most arguments, we first compute the length of `formals()`. ```{r, message = FALSE} - library(purrr) - - n_args <- funs %>% - map(formals) %>% - map_int(length) +library(purrr) + +n_args <- funs %>% + map(formals) %>% + map_int(length) ``` Then we sort `n_args` in decreasing order and look at its first entries. ```{r, eval = FALSE} - n_args %>% - sort(decreasing = TRUE) %>% - head() - #> scan format.default source - #> 22 16 16 - #> formatC library merge.data.frame - #> 15 13 13 +n_args %>% + sort(decreasing = TRUE) %>% + head() +#> scan format.default source +#> 22 16 16 +#> formatC library merge.data.frame +#> 15 13 13 ``` b. We can further use `n_args` to find the number of functions with no arguments: ```{r} - sum(n_args == 0) +sum(n_args == 0) ``` However, this over counts because `formals()` returns `NULL` for primitive functions, and `length(NULL)` is 0. To fix this, we can first remove the primitive functions: ```{r} - n_args2 <- funs %>% - discard(is.primitive) %>% - map(formals) %>% - map_int(length) - - sum(n_args2 == 0) +n_args2 <- funs %>% + discard(is.primitive) %>% + map(formals) %>% + map_int(length) + +sum(n_args2 == 0) ``` Indeed, most of the functions with no arguments are actually primitive functions. @@ -113,8 +114,8 @@ b. We can further use `n_args` to find the number of functions with no arguments c. To find all primitive functions, we can change the predicate in `Filter()` from `is.function()` to `is.primitive()`: ```{r} - funs <- Filter(is.primitive, objs) - length(funs) +funs <- Filter(is.primitive, objs) +length(funs) ``` __[Q6]{.Q}__: What are the three important components of a function? @@ -127,9 +128,7 @@ __[Q7]{.Q}__: When does printing a function not show what environment it was cre __[A]{.solved}__: Primitive functions and functions created in the global environment do not print their environment. -\stepcounter{section} ## Lexical scoping - __[Q1]{.Q}__: What does the following code return? Why? Describe how each of the three `c`’s is interpreted. @@ -155,7 +154,7 @@ __[Q3]{.Q}__: What does the following function return? Make a prediction before f <- function(x) { f <- function(x) { f <- function() { - x ^ 2 + x^2 } f() + 1 } @@ -167,7 +166,6 @@ f(10) __[A]{.solved}__: Within this nested function two more functions also named `f` are defined and called. Because the functions are each executed in their own environment R will look up and use the functions defined last in these environments. The innermost `f()` is called last, though it is the first function to return a value. Therefore, the order of the calculation passes "from the inside to the outside" and the function returns `((10 ^ 2) + 1) * 2`, i.e. 202. ## Lazy evaluation - __[Q1]{.Q}__: What important property of `&&` makes `x_ok()` work? @@ -218,7 +216,10 @@ __[Q3]{.Q}__: What does this function return? Why? Which principle does it illus ```{r, eval = FALSE} y <- 10 -f1 <- function(x = {y <- 1; 2}, y = 0) { +f1 <- function(x = { + y <- 1 + 2 + }, y = 0) { c(x, y) } f1() @@ -272,7 +273,6 @@ str(formals(library)) ``` ## `...` (dot-dot-dot) - __[Q1]{.Q}__: Explain the following results: @@ -333,7 +333,6 @@ localTitle <- function(..., col, bg, pch, cex, lty, lwd) title(...) The call to `localTitle()` passes the `col` parameter as part of the `...` argument to `title()`. `?title` tells us that the `title()` function specifies four parts of the plot: Main (title of the plot), sub (sub-title of the plot) and both axis labels. Therefore, it would introduce ambiguity inside `title()` to use `col` directly. Instead, one has the option to supply `col` via the `...` argument, via `col.lab` or as part of `xlab` in the form `xlab = list(c("index"), col = "red")` (similar for `ylab`). ## Exiting a function - __[Q1]{.Q}__: What does `load()` return? Why don’t you normally see these values? @@ -351,7 +350,7 @@ __[A]{.solved}__: The `with_dir()` approach was given in *Advanced R* as: with_dir <- function(dir, code) { old <- setwd(dir) on.exit(setwd(old)) - + force(code) } ``` @@ -378,10 +377,10 @@ __[Q5]{.Q}__: We can use `on.exit()` to implement a simple version of `capture.o capture.output2 <- function(code) { temp <- tempfile() on.exit(file.remove(temp), add = TRUE, after = TRUE) - + sink(temp) on.exit(sink(), add = TRUE, after = TRUE) - + force(code) readLines(temp) } @@ -397,12 +396,15 @@ In `capture_output2()` the code is simply forced, and the output is caught via ` The main difference is that `capture.output()` calls print, i.e. compare the output of these two calls: ```{r, warning = FALSE} -capture.output({1}) -capture.output2({1}) +capture.output({ + 1 +}) +capture.output2({ + 1 +}) ``` ## Function forms - __[Q1]{.Q}__: Rewrite the following code snippets into prefix form: @@ -463,7 +465,7 @@ R internally transforms the code, and the transformed code reproduces the error ```{r, eval = FALSE} get("x") <- `modify<-`(get("x"), 1, 10) -#> Error in get("x") <- `modify<-`(get("x"), 1, 10) : +#> Error in get("x") <- `modify<-`(get("x"), 1, 10) : #> target of assignment expands to non-language object ``` @@ -509,7 +511,7 @@ __[A]{.solved}__: To achieve this behaviour, we need to override the `+` operato } # Test -+ 1 ++1 1 + 2 "a" + "b" @@ -537,7 +539,7 @@ To find out which of these functions are primitives, we first search for these f ```{r} repls_base_prim <- mget(repls_base, envir = baseenv()) %>% - Filter(is.primitive, .) %>% + Filter(is.primitive, .) %>% names() repls_base_prim diff --git a/07_Environments.Rmd b/07_Environments.qmd similarity index 97% rename from 07_Environments.Rmd rename to 07_Environments.qmd index b78651ad..b99a7279 100755 --- a/07_Environments.Rmd +++ b/07_Environments.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Environments - ## Prerequisites {-} - Just like in *Advanced R*, we mainly use the `{rlang}` package [@rlang] to work with environments. @@ -16,7 +18,6 @@ library(rlang) \stepcounter{section} ## Environment basics - __[Q1]{.Q}__: List three ways in which an environment differs from a list. @@ -33,7 +34,8 @@ __[Q2]{.Q}__: Create an environment as illustrated by this picture. ```{r echo = FALSE, out.width = '200pt'} knitr::include_graphics("images/environments/recursive-1.png", - dpi = 300) + dpi = 300 +) ``` __[A]{.solved}__: Let's create an environment that contains itself. @@ -53,7 +55,8 @@ __[Q3]{.Q}__: Create a pair of environments as illustrated by this picture. ```{r, echo = FALSE, out.width = '200pt'} knitr::include_graphics("images/environments/recursive-2.png", - dpi = 300) + dpi = 300 +) ``` __[A]{.solved}__: These two environments contain each other: @@ -62,7 +65,7 @@ __[A]{.solved}__: These two environments contain each other: e1 <- env() e2 <- env() -e1$loop <- e2 +e1$loop <- e2 e2$dedoop <- e1 lobstr::ref(e1) @@ -125,7 +128,6 @@ a __[A]{.solved}__: The primary difference between `rebind()` and `<<-` is that `rebind()` will only carry out an assignment when it finds an existing binding; unlike `<<-` it will never create a new one in the global environment. This behaviour of `<<-` is usually undesirable because global variables introduce non-obvious dependencies between functions. ## Recursing over environments - __[Q1]{.Q}__: Modify `where()` to return _all_ environments that contain a binding for `name`. Carefully think through what type of object the function will need to return. @@ -205,7 +207,6 @@ fget("mean", inherits = TRUE) ``` ## Special environments - __[Q1]{.Q}__: How is `search_envs()` different to `env_parents(global_env())`? @@ -244,7 +245,8 @@ The following diagram visualises the relations between the function environments ```{r, echo = FALSE, out.width='350pt'} knitr::include_graphics( - "images/environments/function_environments_corrected.png", dpi = 300 + "images/environments/function_environments_corrected.png", + dpi = 300 ) ``` @@ -314,7 +316,6 @@ fstr("mean") Once you have learned about tidy evaluation, you could rewrite `fstr()` to use `enquo()` so that you'd call it more like `str()`, i.e. `fstr(sum)`. ## Call stacks - __[Q1]{.Q}__: Write a function that lists all the variables defined in the environment in which it was called. It should return the same results as `ls()`. diff --git a/08_Conditions.Rmd b/08_Conditions.qmd similarity index 94% rename from 08_Conditions.Rmd rename to 08_Conditions.qmd index 95dfe8c8..efb42158 100755 --- a/08_Conditions.Rmd +++ b/08_Conditions.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Conditions - ## Prerequisites {-} - Similar to the environments chapter, we also use functions from the `{rlang}` package to work with conditions. @@ -14,9 +16,7 @@ Similar to the environments chapter, we also use functions from the `{rlang}` pa library(rlang) ``` -\stepcounter{section} ## Signalling conditions - __[Q1]{.Q}__: Write a wrapper around `file.remove()` that throws an error if the file to be deleted does not exist. @@ -25,9 +25,9 @@ __[A]{.solved}__: We prefer the following solution for its clarity and simplicit ```{r, error = TRUE} file_remove_strict <- function(path) { if (!file.exists(path)) { - stop("Can't delete the file \"", path, - "\" because it doesn't exist.", - call. = FALSE + stop("Can't delete the file \"", path, + "\" because it doesn't exist.", + call. = FALSE ) } file.remove(path) @@ -61,9 +61,7 @@ multiline_msg(appendLF = FALSE) Comparable behaviour regarding line breaks for `cat()` can be achieved via setting its `sep` argument to `"\n"`. -\stepcounter{section} ## Handling conditions - __[Q1]{.Q}__: What extra information does the condition generated by `abort()` contain compared to the condition generated by `stop()`, i.e. what's the difference between these two objects? Read the help for `?abort` to learn more. @@ -123,9 +121,9 @@ show_condition <- function(code) { __[A]{.solved}__: The first three examples are straightforward: ```{r} -show_condition(stop("!")) # stop raises an error -show_condition(10) # no condition is signalled -show_condition(warning("?!")) # warning raises a warning +show_condition(stop("!")) # stop raises an error +show_condition(10) # no condition is signalled +show_condition(warning("?!")) # warning raises a warning ``` The last example is the most interesting and makes us aware of the exiting qualities of `tryCatch()`; it will terminate the evaluation of the code as soon as it is called. @@ -141,9 +139,9 @@ show_condition({ __[Q3]{.Q}__: Explain the results of running this code: ```{r} -withCallingHandlers( # (1) +withCallingHandlers( # (1) message = function(cnd) message("b"), - withCallingHandlers( # (2) + withCallingHandlers( # (2) message = function(cnd) message("a"), message("c") ) @@ -184,9 +182,15 @@ __[A]{.solved}__: `show_condition()` was defined in one of the previous question show_condition2 <- function(code) { tryCatch( condition = function(cnd) { - if (inherits(cnd, "error")) return("error") - if (inherits(cnd, "warning")) return("warning") - if (inherits(cnd, "message")) return("message") + if (inherits(cnd, "error")) { + return("error") + } + if (inherits(cnd, "warning")) { + return("warning") + } + if (inherits(cnd, "message")) { + return("message") + } }, { code @@ -209,7 +213,6 @@ show_condition2({ `tryCatch()` executes the code and captures any condition raised. The function provided as the `condition` handles this condition. In this case it dispatches on the class of the condition. ## Custom conditions - __[Q1]{.Q}__: Inside a package, it’s occasionally useful to check that a package is installed before using it. Write a function that checks if a package is installed (with `requireNamespace("pkg", quietly = FALSE))` and if not, throws a custom condition that includes the package name in the metadata. @@ -237,7 +240,6 @@ __[Q2]{.Q}__: Inside a package you often need to stop with an error when somethi __[A]{.solved}__: Instead of returning an error it might be preferable to throw a customised condition and place a standardised error message inside the metadata. Then the downstream package could check for the class of the condition, rather than inspecting the message. ## Applications - __[Q1]{.Q}__: Create `suppressConditions()` that works like `suppressMessages()` and `suppressWarnings()` but suppresses everything. Think carefully about how you should handle errors. @@ -300,11 +302,15 @@ message2error1 <- function(code) { withCallingHandlers(code, message = function(e) stop("error")) } -message2error1({1; message("hidden error"); NULL}) +message2error1({ + 1 + message("hidden error") + NULL +}) #> Error in (function (e) : error traceback() #> 9: stop("error") at #2 -#> 8: (function (e) +#> 8: (function (e) #> stop("error"))(list(message = "hidden error\n", #> call = message("hidden error"))) #> 7: signalCondition(cond) @@ -329,7 +335,11 @@ message2error2 <- function(code) { tryCatch(code, message = function(e) (stop("error"))) } -message2error2({1; stop("hidden error"); NULL}) +message2error2({ + 1 + stop("hidden error") + NULL +}) #> Error in value[[3L]](cond) : error traceback() #> 6: stop("error") at #2 @@ -417,7 +427,7 @@ bottles_of_beer() #> Take one down, pass it around, 97 bottles of beer on the wall. #> Take one down, pass it around, 96 bottles of beer on the wall. #> Take one down, pass it around, 95 bottles of beer on the wall. -#> +#> ``` At this point you'll probably recognise how hard it is to get the number of bottles down from `99` to `0`. There's no way to break out of the function because we're capturing the interrupt that you'd usually use! diff --git a/09_Functionals.Rmd b/09_Functionals.qmd similarity index 96% rename from 09_Functionals.Rmd rename to 09_Functionals.qmd index 04fe8a7d..5c5cbfa1 100755 --- a/09_Functionals.Rmd +++ b/09_Functionals.qmd @@ -1,14 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` -# (PART) Functional programming {-} - # Functionals - ## Prerequisites {-} - For the functional programming part of the book, we will mainly use functions from the `{purrr}` package [@purrr]. @@ -16,9 +16,7 @@ For the functional programming part of the book, we will mainly use functions fr library(purrr) ``` -\stepcounter{section} ## My first functional: `map()` - __[Q1]{.Q}__: Use `as_mapper()` to explore how `{purrr}` generates anonymous functions for the integer, character, and list helpers. What helper allows you to extract attributes? Read the documentation to find out. @@ -29,9 +27,9 @@ Given character, numeric or list input `as_mapper()` will create an extractor fu The extractor function is implemented as a call to `purrr::pluck()`, which accepts a list of accessors (accessors "access" some part of your data object). ```{r} -as_mapper(c(1, 2)) # equivalent to function(x) x[[1]][[2]] -as_mapper(c("a", "b")) # equivalent to function(x) x[["a"]][["b]] -as_mapper(list(1, "b")) # equivalent to function(x) x[[1]][["b]] +as_mapper(c(1, 2)) # equivalent to function(x) x[[1]][[2]] +as_mapper(c("a", "b")) # equivalent to function(x) x[["a"]][["b]] +as_mapper(list(1, "b")) # equivalent to function(x) x[[1]][["b]] ``` Besides mixing positions and names, it is also possible to pass along an accessor function. This is basically an anonymous function that gets information about some aspect of the input data. You are free to define your own accessor functions. @@ -95,7 +93,7 @@ df_trials <- tibble::tibble(p_value = map_dbl(trials, "p.value")) df_trials %>% ggplot(aes(x = p_value, fill = p_value < 0.05)) + - geom_dotplot(binwidth = .01) + # geom_histogram() as alternative + geom_dotplot(binwidth = .01) + # geom_histogram() as alternative theme( axis.text.y = element_blank(), axis.ticks.y = element_blank(), @@ -166,9 +164,7 @@ bootstraps %>% map_dbl("r.squared") ``` -\stepcounter{section} ## Map variants - __[Q1]{.Q}__: Explain the results of `modify(mtcars, 1)`. @@ -257,9 +253,7 @@ paths <- file.path(tempdir(), paste0("cyl-", names(cyls), ".csv")) map2(cyls, paths, write.csv) ``` -\stepcounter{section} ## Predicate functionals - __[Q1]{.Q}__: Why isn't `is.na()` a predicate function? What base R function is closest to being a predicate version of `is.na()`? @@ -290,9 +284,13 @@ Therefore, subsetting length-0 and length-1 vectors via `[[` will lead to a *sub ```{r} simple_reduce <- function(x, f, default) { - if (length(x) == 0L) return(default) - if (length(x) == 1L) return(x[[1L]]) - + if (length(x) == 0L) { + return(default) + } + if (length(x) == 1L) { + return(x[[1L]]) + } + out <- x[[1]] for (i in seq(2, length(x))) { out <- f(out, x[[i]]) @@ -321,29 +319,29 @@ data(mtcars) ```{r} span_r <- function(x, f) { idx <- unname(map_lgl(x, ~ f(.x))) - rle <- rle(idx) - + rle <- rle(idx) + # Check if the predicate is never true if (!any(rle$values)) { return(integer(0)) } - + # Find the length of the longest sequence of true values longest <- max(rle$lengths[rle$values]) # Find the positition of the (first) longest run in rle longest_idx <- which(rle$values & rle$lengths == longest)[1] - + # Add up all lengths in rle before the longest run ind_before_longest <- sum(rle$lengths[seq_len(longest_idx - 1)]) - + out_start <- ind_before_longest + 1L out_end <- ind_before_longest + longest out_start:out_end } # Check that it works -span_r(c(0, 0, 0, 0, 0), is.na) -span_r(c(NA, 0, 0, 0, 0), is.na) +span_r(c(0, 0, 0, 0, 0), is.na) +span_r(c(NA, 0, 0, 0, 0), is.na) span_r(c(NA, 0, NA, NA, NA), is.na) ``` @@ -362,8 +360,8 @@ arg_min <- function(x, f) { x[y == min(y)] } -arg_max(-10:5, function(x) x ^ 2) -arg_min(-10:5, function(x) x ^ 2) +arg_max(-10:5, function(x) x^2) +arg_min(-10:5, function(x) x^2) ``` __[Q5]{.Q}__: The function below scales a vector so it falls in the range [0, 1]. How would you apply it to every column of a data frame? How would you apply it to every numeric column in a data frame? @@ -382,7 +380,6 @@ modify_if(mtcars, is.numeric, scale01) ``` ## Base functionals - __[Q1]{.Q}__: How does `apply()` arrange the output? Read the documentation and perform some experiments. @@ -424,22 +421,22 @@ fixed_point <- function(f, x_init, n_max = 10000, tol = 0.0001) { n <- 0 x <- x_init y <- f(x) - + is_fixed_point <- function(x, y) { abs(x - y) < tol } - + while (!is_fixed_point(x, y)) { x <- y y <- f(y) - + # Make sure we eventually stop n <- n + 1 if (n > n_max) { stop("Failed to converge.", call. = FALSE) } } - + x } diff --git a/10_Function_factories.Rmd b/10_Function_factories.qmd similarity index 99% rename from 10_Function_factories.Rmd rename to 10_Function_factories.qmd index 47d068d4..e96455a9 100755 --- a/10_Function_factories.Rmd +++ b/10_Function_factories.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Function factories - ## Prerequisites {-} - For most of this chapter base R [@RLanguage] is sufficient. Just a few exercises require the `{rlang}` [@rlang], `{dplyr}` [@dplyr], `{purrr}` [@purrr] and `{ggplot2}` [@ggplot2] packages. @@ -17,9 +19,7 @@ library(purrr) library(ggplot2) ``` -\stepcounter{section} ## Factory fundamentals - __[Q1]{.Q}__: The definition of `force()` is simple: @@ -230,7 +230,6 @@ new_counter_3() ``` ## Graphical factories - __[Q1]{.Q}__: Compare and contrast `ggplot2::label_bquote()` with `scales::number_format()`. @@ -241,7 +240,6 @@ __[A]{.solved}__: Both functions will help you in styling your output, e.g. in y `scales::number_format()` initially `force()`s the computation of all parameters. It's essentially a parametrised wrapper around `scales::number()` and will help you format numbers appropriately. It will return a simple function. ## Statistical factories - __[Q1]{.Q}__: In `boot_model()`, why don't I need to force the evaluation of `df` or `model`? @@ -380,7 +378,6 @@ ggplot(df_perf, aes(x_length, median, col = method)) + ``` ## Function factories + functionals - __[Q1]{.Q}__: Which of the following commands is equivalent to `with(x, f(z))`? diff --git a/11_Function_operators.Rmd b/11_Function_operators.qmd similarity index 95% rename from 11_Function_operators.Rmd rename to 11_Function_operators.qmd index 302e0a0e..5bedcfd5 100755 --- a/11_Function_operators.Rmd +++ b/11_Function_operators.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # Function operators - ## Prerequisites {-} - Also in the third chapter on functional programming, we make relatively frequent use of the {purrr} package. @@ -14,9 +16,7 @@ Also in the third chapter on functional programming, we make relatively frequent library(purrr) ``` -\stepcounter{section} ## Existing function operators - __[Q1]{.Q}__: Base R provides a function operator in the form of `Vectorize()`. What does it do? When might you use it? @@ -29,15 +29,15 @@ Let's take a look at an example from the documentation: ```{r, eval=FALSE} vrep <- Vectorize(rep.int) vrep -#> function (x, times) +#> function (x, times) #> { #> args <- lapply(as.list(match.call())[-1L], eval, parent.frame()) -#> names <- if (is.null(names(args))) +#> names <- if (is.null(names(args))) #> character(length(args)) #> else names(args) #> dovec <- names %in% vectorize.args #> do.call("mapply", c(FUN = FUN, args[dovec], -#> MoreArgs = list(args[!dovec]), +#> MoreArgs = list(args[!dovec]), #> SIMPLIFY = SIMPLIFY, USE.NAMES = USE.NAMES)) #> } #> @@ -84,7 +84,6 @@ purrr:::capture_error Take a look at *Advanced R* or the documentation of `safely()` to see how you can take advantage of this behaviour, e.g. when fitting many models. ## Case study: Creating your own function operators - __[Q1]{.Q}__: Weigh the pros and cons of `download.file %>% dot_every(10) %>% delay_by(0.1)` versus `download.file %>% delay_by(0.1) %>% dot_every(10)`. @@ -109,14 +108,18 @@ dir_compare <- function(old, new) { if (setequal(old, new)) { return() } - + added <- setdiff(new, old) removed <- setdiff(old, new) - + changes <- c( if (length(added) > 0) paste0(" * '", added, "' was added"), - if (length(removed) > 0) paste0(" * '", removed , - "' was removed") + if (length(removed) > 0) { + paste0( + " * '", removed, + "' was removed" + ) + } ) message(paste(changes, collapse = "\n")) } @@ -133,7 +136,7 @@ track_dir <- function(f) { function(...) { dir_old <- dir() on.exit(dir_compare(dir_old, dir()), add = TRUE) - + f(...) } } @@ -163,14 +166,14 @@ __[Q4]{.Q}__: Write a function operator that logs a timestamp and message to a f __[A]{.solved}__: Our `logger()` function operator takes a function and a file path as input. One timestamp is written to the file under `log_path` when we call `logger()` and another timestamp is written to the same file each time the new function gets called. ```{r} -append_line <- function(path, ...) { +append_line <- function(path, ...) { cat(..., "\n", sep = "", file = path, append = TRUE) } logger <- function(f, log_path) { force(f) force(log_path) - + append_line(log_path, "created at: ", as.character(Sys.time())) function(...) { append_line(log_path, "called at: ", as.character(Sys.time())) @@ -185,7 +188,7 @@ Now, let's check if our `logger()` works as intended and apply it to the `mean() log_path <- tempfile() mean2 <- logger(mean, log_path) Sys.sleep(5) -mean2(1:4) +mean2(1:4) Sys.sleep(1) mean2(1:4) @@ -200,7 +203,7 @@ __[A]{.solved}__: `delay_by()` was defined in *Advanced R* as: delay_by <- function(f, amount) { force(f) force(amount) - + function(...) { Sys.sleep(amount) f(...) @@ -214,10 +217,10 @@ To ensure that the function created by `delay_by()` waits that a certain amount delay_atleast <- function(amount, f) { force(f) force(amount) - + # Store the last time the function was run last_time <- NULL - + # Return modified "delay-aware" function function(...) { if (!is.null(last_time)) { @@ -226,10 +229,10 @@ delay_atleast <- function(amount, f) { Sys.sleep(wait) } } - + # Update the time after the function has finished - on.exit(last_time <<- Sys.time()) - + on.exit(last_time <<- Sys.time()) + f(...) } } diff --git a/13_S3.Rmd b/12_S3.qmd similarity index 99% rename from 13_S3.Rmd rename to 12_S3.qmd index 4d324ca5..a50d8714 100755 --- a/13_S3.Rmd +++ b/12_S3.qmd @@ -1,15 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` -# (PART) Object-oriented programming {-} -\stepcounter{chapter} - # S3 - ## Prerequisites {-} - To interact with S3 objects, we will mainly use the `{sloop}` package [@sloop]. @@ -17,10 +16,7 @@ To interact with S3 objects, we will mainly use the `{sloop}` package [@sloop]. library(sloop) ``` - -\stepcounter{section} ## Basics - __[Q1]{.Q}__: Describe the difference between `t.test()` and `t.data.frame()`? When is each function called? @@ -105,7 +101,6 @@ attributes(x) ``` ## Classes - __[Q1]{.Q}__: Write a constructor for `data.frame` objects. What base type is a data frame built on? What attributes does it use? What are the restrictions placed on the individual elements? What about the names? @@ -286,7 +281,6 @@ roman(0) ``` ## Generics and methods - __[Q1]{.Q}__: Read the source code for `t()` and `t.test()` and confirm that `t.test()` is an S3 generic and not an S3 method. What happens if you create an object with class `test` and call `t()` with it? Why? @@ -467,7 +461,6 @@ s3_methods_generic("[") %>% ``` ## Object styles - __[Q1]{.Q}__: Categorise the objects returned by `lm()`, `factor()`, `table()`, `as.Date()`, `as.POSIXct()`, `ecdf()`, `ordered()`, `I()` into the styles described above. @@ -537,7 +530,6 @@ new_lm <- function( ``` ## Inheritance - __[Q1]{.Q}__: How does `[.Date` support subclasses? How does it fail to support subclasses? @@ -633,7 +625,6 @@ generic2(structure(list(), class = c("b", "a2"))) ``` ## Dispatch details - __[Q1]{.Q}__: Explain the differences in dispatch below: diff --git a/14_R6.Rmd b/13_R6.qmd similarity index 99% rename from 14_R6.Rmd rename to 13_R6.qmd index 57d37db6..6187d546 100755 --- a/14_R6.Rmd +++ b/13_R6.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # R6 - ## Prerequisites {-} - To solve the exercises in this chapter we will have to create R6 objects, which are implemented in the `{R6}` package [@R6]. @@ -14,9 +16,7 @@ To solve the exercises in this chapter we will have to create R6 objects, which library(R6) ``` -\stepcounter{section} ## Classes and methods - __[Q1]{.Q}__: Create a bank account R6 class that stores a balance and allows you to deposit and withdraw money. Create a subclass that throws an error if you attempt to go into overdraft. Create another subclass that allows you to go into overdraft, but charges you a fee. @@ -24,7 +24,7 @@ __[A]{.solved}__: Let's start with a basic bank account, similar to the `Accumul ```{r} BankAccount <- R6Class( - classname = "BankAccount", + classname = "BankAccount", public = list( balance = 0, deposit = function(dep = 0) { @@ -238,7 +238,6 @@ __[Q7]{.Q}__: What base type are R6 objects built on top of? What attributes do __[A]{.solved}__: R6 objects are built on top of environments. They have a `class` attribute, which is a character vector containing the class name, the name of any super classes (if existent) and the string `"R6"` as the last element. ## Controlling access - __[Q1]{.Q}__: Create a bank account class that prevents you from directly setting the account balance, but that you can still withdraw from and deposit to. Throw an error if you attempt to go into overdraft. @@ -384,7 +383,6 @@ B$new()$test() We conclude that subclasses can access private methods from their superclasses, but not private fields. ## Reference semantics - __[Q1]{.Q}__: Create a class that allows you to write a line to a specified file. You should open a connection to the file in `$initialize()`, append a line using `cat()` in `$append_line()`, and close the connection in `$finalize()`. @@ -398,11 +396,9 @@ FileWriter <- R6::R6Class( initialize = function(filename) { self$con <- file(filename, open = "a") }, - finalize = function() { close(self$con) }, - append_line = function(x) { cat(x, "\n", sep = "", file = self$con) } diff --git a/15_S4.Rmd b/14_S4.qmd similarity index 93% rename from 15_S4.Rmd rename to 14_S4.qmd index 18bee240..409ba0b4 100755 --- a/15_S4.Rmd +++ b/14_S4.qmd @@ -1,12 +1,14 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` # S4 - ## Prerequisites {-} - We load the `{methods}` package [@RLanguage] as it contains the S4 object-oriented programming system. @@ -14,9 +16,7 @@ We load the `{methods}` package [@RLanguage] as it contains the S4 object-orient library(methods) ``` -\stepcounter{section} ## Basics - __[Q1]{.Q}__: `lubridate::period()` returns an S4 class. What slots does it have? What class is each slot? What accessors does it provide? @@ -26,7 +26,7 @@ As a short example, we create a period of 1 second, 2 minutes, 3 hours, 4 days a ```{r} example_12345 <- lubridate::period( - c(1, 2, 3, 4, 5), + c(1, 2, 3, 4, 5), c("second", "minute", "hour", "day", "week") ) ``` @@ -52,7 +52,6 @@ __[A]{.solved}__: Besides adding `?` in front of a function call (i.e. `?method( - documentation for a specific method via `ClassName?methodName`. ## Classes - __[Q1]{.Q}__: Extend the Person class with fields to match `utils::person()`. Think about what slots you will need, what class each slot should have, and what you’ll need to check in your validity method. @@ -102,28 +101,32 @@ Person <- function(given, family, # Validator to ensure that each slot is of length one setValidity("Person", function(object) { invalids <- c() - if (length(object@age) != 1 || - length(object@given) != 1 || - length(object@family) != 1 || - length(object@email) != 1 || - length(object@comment) != 1) { - invalids <- paste0("@name, @age, @given, @family, @email, ", - "@comment must be of length 1") - } - + if (length(object@age) != 1 || + length(object@given) != 1 || + length(object@family) != 1 || + length(object@email) != 1 || + length(object@comment) != 1) { + invalids <- paste0( + "@name, @age, @given, @family, @email, ", + "@comment must be of length 1" + ) + } + known_roles <- c( NA_character_, "aut", "com", "cph", "cre", "ctb", "ctr", "dtc", "fnd", "rev", "ths", "trl" ) - + if (!all(object@role %in% known_roles)) { paste( - "@role(s) must be one of", + "@role(s) must be one of", paste(known_roles, collapse = ", ") ) } - - if (length(invalids)) return(invalids) + + if (length(invalids)) { + return(invalids) + } TRUE }) ``` @@ -200,7 +203,6 @@ new("DataFrame", data = list(a = 1, b = 2)) ``` ## Generics and methods - __[Q1]{.Q}__: Add `age()` accessors for the `Person` class. @@ -283,7 +285,6 @@ setMethod("show", "Person", function(object, y) { ``` ## Method dispatch - ```{r, include=FALSE} source("emoji.R") @@ -311,7 +312,6 @@ __[Q3]{.Q}__: Take the last example which shows multiple dispatch over two class __[A]{.solved}__: We will introduce ambiguity, since one class has distance 2 to all terminal nodes and the other four have distance 1 to two terminal nodes each. To resolve this ambiguity we have to define five more methods, one per class combination. ## S4 and S3 - __[Q1]{.Q}__: What would a full `setOldClass()` definition look like for an ordered factor (i.e. add `slots` and `prototype` to the definition above)? @@ -320,19 +320,19 @@ __[A]{.solved}__: The purpose of `setOldClass()` lies in registering an S3 class Let's build an S4 `OrderedFactor` on top of the S3 factor in such a way. ```{r} -setOldClass("factor") # use build-in definition for brevity +setOldClass("factor") # use build-in definition for brevity OrderedFactor <- setClass( "OrderedFactor", - contains = "factor", # inherit from registered S3 class + contains = "factor", # inherit from registered S3 class slots = c( levels = "character", - ordered = "logical" # add logical order slot + ordered = "logical" # add logical order slot ), prototype = structure( integer(), levels = character(), - ordered = logical() # add default value + ordered = logical() # add default value ) ) ``` @@ -355,6 +355,8 @@ __[Q2]{.Q}__: Define a `length` method for the `Person` class. __[A]{.solved}__: We keep things simple and will just return `"180cm"` when the `length()` method is called on a `Person` object. The method can be defined either as an S3 or S4 method. ```{r} -length.Person <- function(x) "180cm" # S3 -setMethod("length", "Person", function(x) "180cm") # S4 +length.Person <- function(x) "180cm" # S3 +setMethod("length", "Person", function(x) "180cm") # S4 ``` + +## References diff --git a/99-rename-rmd-to-qmd.sh b/99-rename-rmd-to-qmd.sh new file mode 100644 index 00000000..c496ec6d --- /dev/null +++ b/99-rename-rmd-to-qmd.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# rename all Rmd files to qmd +for f in *.Rmd; do + mv -- "$f" "${f%.Rmd}.qmd" +done diff --git a/_bookdown.yml b/_bookdown.yml deleted file mode 100755 index 85bb5e67..00000000 --- a/_bookdown.yml +++ /dev/null @@ -1,35 +0,0 @@ -new_session: yes -delete_merged_file: yes - -rmd_files: - [ - "index.Rmd" - , "01_Preface.Rmd" - - , "02_Names_and_values.Rmd" - , "03_Vectors.Rmd" - , "04_Subsetting.Rmd" - , "05_Control_flow.Rmd" - , "06_Functions.Rmd" - , "07_Environments.Rmd" - , "08_Conditions.Rmd" - - , "09_Functionals.Rmd" - , "10_Function_factories.Rmd" - , "11_Function_operators.Rmd" - - , "13_S3.Rmd" - , "14_R6.Rmd" - , "15_S4.Rmd" - - , "18_Expressions.Rmd" - , "19_Quasiquotation.Rmd" - , "20_Evaluation.Rmd" - , "21_Translating_R_code.Rmd" - - , "23_Measuring_performance.Rmd" - , "24_Improving_performance.Rmd" - , "25_Rewriting_R_code_in_Cpp.Rmd" - - # , "26_Deprecated_exercises.Rmd" - ] diff --git a/_metadata.yml b/_metadata.yml new file mode 100644 index 00000000..aec63b62 --- /dev/null +++ b/_metadata.yml @@ -0,0 +1,5 @@ +# options specified here will apply to all posts in this folder + +# freeze computational output +# (see https://quarto.org/docs/projects/code-execution.html#freeze) +freeze: auto diff --git a/_quarto.yml b/_quarto.yml new file mode 100644 index 00000000..77245e93 --- /dev/null +++ b/_quarto.yml @@ -0,0 +1,35 @@ +project: + type: book + output-dir: docs + +book: + title: "Advanced R Solutions" + author: "Malte Grosser, Henning Bumann, Hadley Wickham & Mauricio Vargas Sepulveda" + description: "Solutions to the Exercises in Hadley Wickham's book 'Advanced R'." + date: "2024-01-22" + chapters: + - index.qmd + - 01_Preface.qmd + - part: "Foundations" + chapters: + - 02_Names_and_values.qmd + - 03_Vectors.qmd + - 04_Subsetting.qmd + - 05_Control_flow.qmd + - 06_Functions.qmd + - 07_Environments.qmd + - 08_Conditions.qmd + - part: "Functional programming" + chapters: + - 09_Functionals.qmd + - 10_Function_factories.qmd + - 11_Function_operators.qmd + - part: "Object-oriented programming" + chapters: + - 12_S3.qmd + - 13_R6.qmd + - 14_S4.qmd + +format: + html: + theme: cosmo diff --git a/index.Rmd b/index.qmd similarity index 78% rename from index.Rmd rename to index.qmd index 0b9996fc..fd74615a 100755 --- a/index.Rmd +++ b/index.qmd @@ -1,22 +1,7 @@ ---- -title: "Advanced R Solutions" -author: "Malte Grosser, Henning Bumann & Hadley Wickham" -description: "Solutions to the Exercises in Hadley Wickham's book 'Advanced R'." -site: bookdown::bookdown_site - -documentclass: krantz -bibliography: book.bib -csl: chicago-fullnote-bibliography.csl -suppress-bibliography: true -nocite: '@*' ---- - -`r if (knitr::is_latex_output()) ''` From ab6875c71e6b2eed924e17685470ec52f0def3ff Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Tue, 23 Jan 2024 21:16:31 -0500 Subject: [PATCH 07/25] final part except cpp chapter --- 18_Expressions.Rmd => 15_Expressions.qmd | 91 ++++++++-------- ...uasiquotation.Rmd => 16_Quasiquotation.qmd | 100 +++++++++--------- 20_Evaluation.Rmd => 17_Evaluation.qmd | 76 ++++++------- ...ng_R_code.Rmd => 18_Translating_R_code.qmd | 5 - ...rmance.Rmd => 23_Measuring_performance.qmd | 34 +++--- ...rmance.Rmd => 24_Improving_performance.qmd | 60 ++++++----- 6 files changed, 176 insertions(+), 190 deletions(-) rename 18_Expressions.Rmd => 15_Expressions.qmd (93%) rename 19_Quasiquotation.Rmd => 16_Quasiquotation.qmd (87%) rename 20_Evaluation.Rmd => 17_Evaluation.qmd (94%) rename 21_Translating_R_code.Rmd => 18_Translating_R_code.qmd (99%) rename 23_Measuring_performance.Rmd => 23_Measuring_performance.qmd (90%) rename 24_Improving_performance.Rmd => 24_Improving_performance.qmd (94%) diff --git a/18_Expressions.Rmd b/15_Expressions.qmd similarity index 93% rename from 18_Expressions.Rmd rename to 15_Expressions.qmd index 97b1fc75..01a4db12 100755 --- a/18_Expressions.Rmd +++ b/15_Expressions.qmd @@ -2,15 +2,9 @@ source("common.R") ``` -# (PART) Metaprogramming {-} -\stepcounter{chapter} -\stepcounter{chapter} - # Expressions - ## Prerequisites {-} - To capture and compute on expressions, and to visualise them, we will load the `{rlang}` [@rlang] and the `{lobstr}` [@lobstr] packages. @@ -19,9 +13,7 @@ library(rlang) library(lobstr) ``` -\stepcounter{section} ## Abstract syntax trees - __[Q1]{.Q}__: Reconstruct the code represented by the trees below: @@ -65,14 +57,14 @@ __[Q3]{.Q}__: What's happening with the ASTs below? (Hint: carefully read `?"^"` ```{r} ast(`x` + `y`) -ast(x ** y) +ast(x**y) ast(1 -> x) ``` __[A]{.solved}__: ASTs start function calls with the name of the function. This is why the call in the first expression is translated into its prefix form. In the second case, `**` is translated by R's parser into `^`. In the last AST, the expression is flipped when R parses it: ```{r} -str(expr(x ** y)) +str(expr(x**y)) str(expr(a -> b)) ``` @@ -104,14 +96,15 @@ We can see the structure more clearly if we avoid the curly braces: ```{r} ast( - if (FALSE) 1 - else if (FALSE) 2 - else if (TRUE) 3 + if (FALSE) { + 1 + } else if (FALSE) { + 2 + } else if (TRUE) 3 ) ``` ## Expressions - __[Q1]{.Q}__: Which two of the six types of atomic vector can't appear in an expression? Why? Similarly, why can't you create an expression that contains an atomic vector of length greater than one? @@ -224,7 +217,6 @@ ast(`if`(x > 1, "a", "b")) ``` ## Parsing and grammar - __[Q1]{.Q}__: R uses parentheses in two slightly different ways as illustrated by these two calls: @@ -260,7 +252,7 @@ __[Q2]{.Q}__: `=` can also be used in two ways. Construct a simple example that __[A]{.solved}__: `=` is used both for assignment, and for naming arguments in function calls: ```{r} -b = c(c = 1) +b <- c(c = 1) ``` So, when we play with `ast()`, we can directly see that the following is not possible: @@ -274,7 +266,9 @@ We get an error because `b = ` makes R looking for an argument called `b`. Since The easiest way around this problem is to wrap this line in `{}`. ```{r} -ast({b = c(c = 1)}) +ast({ + b <- c(c = 1) +}) ``` When we ignore the braces and compare the trees, we can see that the first `=` is used for assignment and the second `=` is part of the syntax of function calls. @@ -336,7 +330,7 @@ ast(x + y %+% z) Here `y %+% z` will be calculated first and the result will be added to `x`. ```{r} -ast(x ^ y %+% z) +ast(x^y %+% z) ``` Here `x ^ y` will be calculated first, and the result will be used as first argument to `%+%()`. @@ -368,8 +362,8 @@ parse(text = "f())") __[Q9]{.Q}__: `deparse()` produces vectors when the input is long. For example, the following call produces a vector of length two: ```{r, eval = FALSE} -expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + - n + o + p + q + r + s + t + u + v + w + x + y + z)) +expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + + n + o + p + q + r + s + t + u + v + w + x + y + z)) deparse(expr) ``` @@ -379,13 +373,13 @@ What does `expr_text()` do instead? __[A]{.solved}__: `expr_text()` will paste the results from `deparse(expr)` together and use a linebreak (`\n`) as separator. ```{r, eval = FALSE} -expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + - n + o + p + q + r + s + t + u + v + w + x + y + z)) +expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + + n + o + p + q + r + s + t + u + v + w + x + y + z)) deparse(expr) #> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n + " #> [2] "o + p + q + r + s + t + u + v + w + x + y + z)" expr_text(expr) -#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n +#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n #> + \n o + p + q + r + s + t + u + v + w + x + y + z)" ``` @@ -396,16 +390,16 @@ __[A]{.solved}__: The function `pairwise.t.test()` captures its data arguments ( ```{r, eval = FALSE} # Output in R version 3.6.2 d <- 1 -pairwise.t.test(2, d + d + d + d + d + d + d + d + - d + d + d + d + d + d + d + d + d) -#> Pairwise comparisons using t tests with pooled SD -#> +pairwise.t.test(2, d + d + d + d + d + d + d + d + + d + d + d + d + d + d + d + d + d) +#> Pairwise comparisons using t tests with pooled SD +#> #> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d -#> + d + d + 2 and d -#> +#> + d + d + 2 and d +#> #> <0 x 0 matrix> -#> -#> P value adjustment method: holm +#> +#> P value adjustment method: holm ``` In [R 4.0.0](https://cran.r-project.org/doc/manuals/r-release/NEWS.html) `pairwise.t.test()` was updated to use the newly introduced `deparse1()`, which serves as a wrapper around `deparse()`. @@ -415,20 +409,19 @@ In [R 4.0.0](https://cran.r-project.org/doc/manuals/r-release/NEWS.html) `pairwi ```{r, eval = FALSE} # Output since R 4.0.0 d <- 1 -pairwise.t.test(2, d + d + d + d + d + d + d + d + - d + d + d + d + d + d + d + d + d) -#> Pairwise comparisons using t tests with pooled SD -#> +pairwise.t.test(2, d + d + d + d + d + d + d + d + + d + d + d + d + d + d + d + d + d) +#> Pairwise comparisons using t tests with pooled SD +#> #> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d #> + d + d + d -#> +#> #> <0 x 0 matrix> -#> -#> P value adjustment method: holm +#> +#> P value adjustment method: holm ``` ## Walking AST with recursive functions {#ast-funs} - __[Q1]{.Q}__: `logical_abbr()` returns `TRUE` for `T(1, 2, 3)`. How could you modify `logical_abbr_rec()` so that it ignores function calls that use `T` or `F`? @@ -451,9 +444,12 @@ expr_type <- function(x) { switch_expr <- function(x, ...) { switch(expr_type(x), - ..., - stop("Don't know how to handle type ", - typeof(x), call. = FALSE)) + ..., + stop("Don't know how to handle type ", + typeof(x), + call. = FALSE + ) + ) } ``` @@ -473,7 +469,7 @@ logical_abbr_rec <- function(x) { # Base cases constant = FALSE, symbol = as_string(x) %in% c("F", "T"), - + # Recursive cases pairlist = purrr::some(x, logical_abbr_rec), call = find_T_call(x) @@ -551,8 +547,9 @@ find_assign_call <- function(x) { } else { lhs <- character() children <- as.list(x) - }} - + } + } + c(lhs, flat_map_chr(children, find_assign_rec)) } @@ -560,7 +557,7 @@ find_assign_rec <- function(x) { switch_expr( x, # Base cases - constant = ,symbol = character(), + constant = , symbol = character(), # Recursive cases pairlist = flat_map_chr(x, find_assign_rec), call = find_assign_call(x) @@ -588,7 +585,7 @@ find_assign_call <- function(x) { lhs <- character() children <- as.list(x) } - + c(lhs, flat_map_chr(children, find_assign_rec)) } diff --git a/19_Quasiquotation.Rmd b/16_Quasiquotation.qmd similarity index 87% rename from 19_Quasiquotation.Rmd rename to 16_Quasiquotation.qmd index 6e704de2..2817330f 100755 --- a/19_Quasiquotation.Rmd +++ b/16_Quasiquotation.qmd @@ -3,10 +3,8 @@ source("common.R") ``` # Quasiquotation - ## Prerequisites {-} - To continue computing on the language, we keep using the `{rlang}` package in this chapter. @@ -14,9 +12,7 @@ To continue computing on the language, we keep using the `{rlang}` package in th library(rlang) ``` -\stepcounter{section} ## Motivation - __[Q1]{.Q}__: For each function in the following base R code, identify which arguments are quoted and which are evaluated. @@ -34,26 +30,26 @@ rm(mtcars2) __[A]{.solved}__: For each argument we first follow the advice from *Advanced R* and execute the argument outside of the respective function. Since `MASS`, `cyl`, `vs` and `am` are not objects contained in the global environment, their execution raises an "Object not found" error. This way we confirm that the respective function arguments are quoted. For the other arguments, we may inspect the source code (and the documentation) to check if any quoting mechanisms are applied or the arguments are evaluated. ```{r, eval = FALSE} -library(MASS) # MASS -> quoted +library(MASS) # MASS -> quoted ``` `library()` also accepts character vectors and doesn't quote when `character.only` is set to `TRUE`, so `library(MASS, character.only = TRUE)` would raise an error. ```{r, eval = FALSE} -mtcars2 <- subset(mtcars, cyl == 4) # mtcars -> evaluated +mtcars2 <- subset(mtcars, cyl == 4) # mtcars -> evaluated # cyl -> quoted -with(mtcars2, sum(vs)) # mtcars2 -> evaluated +with(mtcars2, sum(vs)) # mtcars2 -> evaluated # sum(vs) -> quoted -sum(mtcars2$am) # matcars$am -> evaluated -# am -> quoted by $() +sum(mtcars2$am) # matcars$am -> evaluated +# am -> quoted by $() ``` When we inspect the source code of `rm()`, we notice that `rm()` catches its `...` argument as an unevaluated call (in this case a pairlist) via `match.call()`. This call is then converted into a string for further evaluation. ```{r, eval = FALSE} -rm(mtcars2) # mtcars2 -> quoted +rm(mtcars2) # mtcars2 -> quoted ``` __[Q2]{.Q}__: For each function in the following tidyverse code, identify which arguments are quoted and which are evaluated. @@ -66,22 +62,23 @@ by_cyl <- mtcars %>% group_by(cyl) %>% summarise(mean = mean(mpg)) -ggplot(by_cyl, aes(cyl, mean)) + geom_point() +ggplot(by_cyl, aes(cyl, mean)) + + geom_point() ``` __[A]{.solved}__: From the previous exercise we've already learned that `library()` quotes its first argument. ```{r, eval = FALSE} -library(dplyr) # dplyr -> quoted -library(ggplot2) # ggplot2 -> quoted +library(dplyr) # dplyr -> quoted +library(ggplot2) # ggplot2 -> quoted ``` In similar fashion, it becomes clear that `cyl` is quoted by `group_by()`. ```{r, eval = FALSE} -by_cyl <- mtcars %>% # mtcars -> evaluated - group_by(cyl) %>% # cyl -> quoted - summarise(mean = mean(mpg)) # mean = mean(mpg) -> quoted +by_cyl <- mtcars %>% # mtcars -> evaluated + group_by(cyl) %>% # cyl -> quoted + summarise(mean = mean(mpg)) # mean = mean(mpg) -> quoted ``` To find out what happens in `summarise()`, we inspect the source code. Tracing down the S3-dispatch of `summarise()`, we see that the `...` argument is quoted in `dplyr:::summarise_cols()` which is called in the underlying `summarise.data.frame()` method. @@ -96,7 +93,7 @@ dplyr:::summarise.data.frame ```{r, eval = FALSE} dplyr:::summarise_cols -#> function (.data, ...) +#> function (.data, ...) #> { #> mask <- DataMask$new(.data, caller_env()) #> dots <- enquos(...) @@ -106,7 +103,7 @@ dplyr:::summarise_cols #> sizes <- 1L #> chunks <- vector("list", length(dots)) #> types <- vector("list", length(dots)) -#> +#> #> ## function definition abbreviated for clarity ## #> } #> @@ -116,10 +113,12 @@ dplyr:::summarise_cols In the following `{ggplot2}` expression the `cyl`- and `mean`-objects are quoted. ```{r, eval = FALSE} -ggplot(by_cyl, # by_cyl -> evaluated - aes(cyl, mean)) + # aes() -> evaluated +ggplot( + by_cyl, # by_cyl -> evaluated + aes(cyl, mean) +) + # aes() -> evaluated # cyl, mean -> quoted (via aes) - geom_point() + geom_point() ``` We can confirm this also by inspecting `aes()`'s source code. @@ -129,7 +128,6 @@ ggplot2::aes ``` ## Quoting - __[Q1]{.Q}__: How is `expr()` implemented? Look at its source code. @@ -169,14 +167,18 @@ __[Q3]{.Q}__: What happens if you try to use `enexpr()` with an expression (i.e. __[A]{.solved}__: In the first case an error is thrown: ```{r, error = TRUE} -on_expr <- function(x) {enexpr(expr(x))} +on_expr <- function(x) { + enexpr(expr(x)) +} on_expr(x + y) ``` In the second case a missing argument is returned: ```{r} -on_missing <- function(x) {enexpr(x)} +on_missing <- function(x) { + enexpr(x) +} on_missing() is_missing(on_missing()) ``` @@ -239,7 +241,6 @@ substitute(x, .GlobalEnv) ``` ## Unquoting - __[Q1]{.Q}__: Given the following components: @@ -253,34 +254,34 @@ abc <- exprs(a, b, c) Use quasiquotation to construct the following calls: ```{r, eval = FALSE} -(x + y) / (y + z) # (1) --(x + z) ^ (y + z) # (2) -(x + y) + (y + z) - (x + y) # (3) -atan2(x + y, y + z) # (4) -sum(x + y, x + y, y + z) # (5) -sum(a, b, c) # (6) -mean(c(a, b, c), na.rm = TRUE) # (7) -foo(a = x + y, b = y + z) # (8) +(x + y) / (y + z) # (1) +-(x + z)^(y + z) # (2) +(x + y) + (y + z) - (x + y) # (3) +atan2(x + y, y + z) # (4) +sum(x + y, x + y, y + z) # (5) +sum(a, b, c) # (6) +mean(c(a, b, c), na.rm = TRUE) # (7) +foo(a = x + y, b = y + z) # (8) ``` __[A]{.solved}__: We combine and unquote the given quoted expressions to construct the desired calls like this: ```{r} -expr(!!xy / !!yz) # (1) +expr(!!xy / !!yz) # (1) -expr(-(!!xz)^(!!yz)) # (2) +expr(-(!!xz)^(!!yz)) # (2) -expr(((!!xy)) + !!yz-!!xy) # (3) +expr(((!!xy)) + !!yz - !!xy) # (3) -expr(atan2(!!xy, !!yz)) # (4) +expr(atan2(!!xy, !!yz)) # (4) -expr(sum(!!xy, !!xy, !!yz)) # (5) +expr(sum(!!xy, !!xy, !!yz)) # (5) -expr(sum(!!!abc)) # (6) +expr(sum(!!!abc)) # (6) -expr(mean(c(!!!abc), na.rm = TRUE)) # (7) +expr(mean(c(!!!abc), na.rm = TRUE)) # (7) -expr(foo(a = !!xy, b = !!yz)) # (8) +expr(foo(a = !!xy, b = !!yz)) # (8) ``` __[Q2]{.Q}__: The following two calls print the same, but are actually different: @@ -304,9 +305,7 @@ In the expression `mean(!!(1:10))` the call `1:10` is evaluated to an integer ve The first version (`mean(1:10)`) seems more natural. It captures lazy evaluation, with a promise that is evaluated when the function is called. The second version (`mean(!!(1:10))`) inlines a vector directly into a call. -\stepcounter{section} ## `...` (dot-dot-dot) - __[Q1]{.Q}__: One way to implement `exec()` is shown below. Describe how it works. What are the key ideas? @@ -327,8 +326,8 @@ __[A]{.solved}__: All three functions capture the dots via `args <- list(...)`. ```{r} # Both calls create the same output -interaction( a = c("a", "b", "c", "d"), b = c("e", "f")) # dots -interaction(list(a = c("a", "b", "c", "d"), b = c("e", "f"))) # list +interaction(a = c("a", "b", "c", "d"), b = c("e", "f")) # dots +interaction(list(a = c("a", "b", "c", "d"), b = c("e", "f"))) # list ``` `expand.grid()` uses the same strategy and also assigns `args <- args[[1]]` in case of `length(args) == 1 && is.list(args[[1]])`. @@ -353,7 +352,7 @@ However, we may name the first argument `.x`, which seems clearer and less likel ```{r} set_attr <- function(.x, ...) { attr <- rlang::list2(...) - + attributes(.x) <- attr .x } @@ -362,7 +361,6 @@ set_attr(1:10, x = 10) ``` ## Case studies {#expr-case-studies} - __[Q1]{.Q}__: In the linear-model example, we could replace the `expr()` in `reduce(summands, ~ expr(!!.x + !!.y))` with `call2()`: `reduce(summands, call2, "+")`. Compare and contrast the two approaches. Which do you think is easier to read? @@ -375,7 +373,7 @@ bc <- function(lambda) { if (lambda == 0) { function(x) log(x) } else { - function(x) (x ^ lambda - 1) / lambda + function(x) (x^lambda - 1) / lambda } } ``` @@ -385,11 +383,11 @@ __[A]{.solved}__: Here `new_function()` allows us to create a function factory u ```{r} bc2 <- function(lambda) { lambda <- enexpr(lambda) - + if (!!lambda == 0) { new_function(exprs(x = ), expr(log(x))) } else { - new_function(exprs(x = ), expr((x ^ (!!lambda) - 1) / !!lambda)) + new_function(exprs(x = ), expr((x^(!!lambda) - 1) / !!lambda)) } } @@ -412,7 +410,7 @@ __[A]{.solved}__: The implementation is fairly straightforward, even though a lo compose2 <- function(f, g) { f <- enexpr(f) g <- enexpr(g) - + new_function(exprs(... = ), expr((!!f)((!!g)(...)))) } diff --git a/20_Evaluation.Rmd b/17_Evaluation.qmd similarity index 94% rename from 20_Evaluation.Rmd rename to 17_Evaluation.qmd index df4c7dd1..2798f1af 100755 --- a/20_Evaluation.Rmd +++ b/17_Evaluation.qmd @@ -3,10 +3,8 @@ source("common.R") ``` # Evaluation - ## Prerequisites {-} - On our journey through R's metaprogramming, we continue to use the functions from the `{rlang}` package. @@ -14,9 +12,7 @@ On our journey through R's metaprogramming, we continue to use the functions fro library(rlang) ``` -\stepcounter{section} ## Evaluation basics - __[Q1]{.Q}__: Carefully read the documentation for `source()`. What environment does it use by default? What if you supply `local = TRUE`? How do you provide a custom environment? @@ -37,7 +33,7 @@ locate_evaluation <- function(file, local) { } # Where will source() evaluate the code? -locate_evaluation(tmp_file, local = FALSE) # default +locate_evaluation(tmp_file, local = FALSE) # default locate_evaluation(tmp_file, local = env2) locate_evaluation(tmp_file, local = TRUE) ``` @@ -45,9 +41,9 @@ locate_evaluation(tmp_file, local = TRUE) __[Q2]{.Q}__: Predict the results of the following lines of code: ```{r, eval = FALSE} -eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1) -eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2) -expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3) +eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1) +eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2) +expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3) ``` __[A]{.solved}__: Let's look at a quote from the [first edition of *Advanced R*](http://adv-r.had.co.nz/Computing-on-the-language.html#subset): @@ -57,9 +53,9 @@ __[A]{.solved}__: Let's look at a quote from the [first edition of *Advanced R*] In general, `eval(expr(x))` evaluates to `x`. Therefore, (1) evaluates to $2 + 2 = 4$. Adding another `eval()` doesn't have impact here. So, also (2) evaluates to `4`. However, when wrapping (1) into `expr()` the whole expression will be quoted. ```{r} -eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1) -eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2) -expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3) +eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1) +eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2) +expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3) ``` __[Q3]{.Q}__: Fill in the function bodies below to re-implement `get()` using `sym()` and `eval()`, and `assign()` using `sym()`, `expr()`, and `eval()`. Don't worry about the multiple ways of choosing an environment that `get()` and `assign()` support; assume that the user supplies it explicitly. @@ -119,14 +115,14 @@ In order to highlight the modifications in our new `source2()` function, we've p source2 <- function(path, env = caller_env()) { file <- paste(readLines(path, warn = FALSE), collapse = "\n") exprs <- parse_exprs(file) - + # res <- NULL # for (i in seq_along(exprs)) { # res[[i]] <- eval(exprs[[i]], env) # } - + res <- purrr::map(exprs, eval, env) - + invisible(res) } ``` @@ -188,7 +184,6 @@ exists("x") ``` ## Quosures - __[Q1]{.Q}__: Predict what evaluating each of the following quosures will return if evaluated. @@ -231,7 +226,6 @@ capture_env(x) ``` ## Data masks - __[Q1]{.Q}__: Why did I use a for loop in `transform2()` instead of `map()`? Consider `transform2(df, x = x * 2, x = x * 2)`. @@ -275,7 +269,7 @@ subset2 <- function(data, rows) { rows <- enquo(rows) rows_val <- eval_tidy(rows, data) stopifnot(is.logical(rows_val)) - + data[rows_val, , drop = FALSE] } ``` @@ -308,12 +302,12 @@ __[Q3]{.Q}__: The following function implements the basics of `dplyr::arrange()` ```{r} arrange2 <- function(.df, ..., .na.last = TRUE) { args <- enquos(...) - + order_call <- expr(order(!!!args, na.last = !!.na.last)) - + ord <- eval_tidy(order_call, .df) stopifnot(length(ord) == nrow(.df)) - + .df[ord, , drop = FALSE] } ``` @@ -323,20 +317,20 @@ __[A]{.solved}__: `arrange2()` basically reorders a data frame by one or more of ```{r} arrange2 <- function(.df, ..., .na.last = TRUE) { # Capture and quote arguments, which determine the order - args <- enquos(...) - + args <- enquos(...) + # `!!!`: unquote-splice arguments into order() # `!!.na.last`: pass option for treatment of NAs to order() # return expression-object order_call <- expr(order(!!!args, na.last = !!.na.last)) - + # Evaluate order_call within .df - ord <- eval_tidy(order_call, .df) + ord <- eval_tidy(order_call, .df) # Ensure that no rows are dropped - stopifnot(length(ord) == nrow(.df)) - + stopifnot(length(ord) == nrow(.df)) + # Reorder rows via integer subsetting - .df[ord, , drop = FALSE] + .df[ord, , drop = FALSE] } ``` @@ -352,14 +346,13 @@ expr(order(..., na.last = .na.last)) ``` ## Using tidy evaluation - __[Q1]{.Q}__: I've included an alternative implementation of `threshold_var()` below. What makes it different to the approach I used above? What makes it harder? ```{r} threshold_var2 <- function(df, var, val) { var <- ensym(var) - + subset2(df, `$`(.data, !!var) >= !!val) } ``` @@ -384,14 +377,13 @@ threshold_var2(df, x, 8) ``` ## Base evaluation - __[Q1]{.Q}__: Why does this function fail? ```{r, error = TRUE} lm3a <- function(formula, data) { formula <- enexpr(formula) - + lm_call <- expr(lm(!!formula, data = data)) eval(lm_call, caller_env()) } @@ -404,13 +396,13 @@ __[A]{.solved}__: In this function, `lm_call` is evaluated in the caller environ # Change evaluation environment lm3b <- function(formula, data) { formula <- enexpr(formula) - + lm_call <- expr(lm(!!formula, data = data)) eval(lm_call, current_env()) } lm3b(mpg ~ disp, mtcars)$call -lm3b(mpg ~ disp, data)$call #reproduces original error +lm3b(mpg ~ disp, data)$call # reproduces original error ``` When we want to unquote an argument within a function, we first need to capture the user-input (by `enexpr()`). @@ -420,7 +412,7 @@ When we want to unquote an argument within a function, we first need to capture lm3c <- function(formula, data) { formula <- enexpr(formula) data_quo <- enexpr(data) - + lm_call <- expr(lm(!!formula, data = !!data_quo)) eval(lm_call, caller_env()) } @@ -438,12 +430,12 @@ lm(mpg ~ disp * cyl, data = mtcars) __[A]{.solved}__: In our wrapper `lm_wrap()`, we provide `mpg` and `mtcars` as default response and data. This seems to give us a good mix of usability and flexibility. ```{r} -lm_wrap <- function(pred, resp = mpg, data = mtcars, +lm_wrap <- function(pred, resp = mpg, data = mtcars, env = caller_env()) { pred <- enexpr(pred) resp <- enexpr(resp) data <- enexpr(data) - + formula <- expr(!!resp ~ !!pred) lm_call <- expr(lm(!!formula, data = !!data)) eval(lm_call, envir = env) @@ -469,13 +461,13 @@ This approach takes advantage of R's lazy evaluation of function arguments, by m ```{r} resample_lm <- function( - formula, data, - resample_data = data[sample(nrow(data), replace = TRUE), , - drop = FALSE], - env = current_env()) { - + formula, data, + resample_data = data[sample(nrow(data), replace = TRUE), , + drop = FALSE + ], + env = current_env()) { formula <- enexpr(formula) - + lm_call <- expr(lm(!!formula, data = resample_data)) expr_print(lm_call) eval(lm_call, env) diff --git a/21_Translating_R_code.Rmd b/18_Translating_R_code.qmd similarity index 99% rename from 21_Translating_R_code.Rmd rename to 18_Translating_R_code.qmd index a52a0dd2..d486b19f 100755 --- a/21_Translating_R_code.Rmd +++ b/18_Translating_R_code.qmd @@ -3,10 +3,8 @@ source("common.R") ``` # Translating R code - ## Prerequisites {-} - In this chapter we combine R's metaprogramming and functional programming capabilities and therefore load both the `{rlang}` and the `{purrr}` package. @@ -15,9 +13,7 @@ library(rlang) library(purrr) ``` -\stepcounter{section} ## HTML - __[Q1]{.Q}__: The escaping rules for `` so that the tag isn't closed too early. For example, `script("''")`, shouldn't generate this: @@ -490,7 +486,6 @@ with_html( ``` ## LaTeX - __[Q1]{.Q}__: Add escaping. The special symbols that should be escaped by adding a backslash in front of them are `\`, `$`, and `%`. Just as with HTML, you'll need to make sure you don't end up double-escaping. So, you'll need to create a small S3 class and then use that in function operators. That will also allow you to embed arbitrary LaTeX if needed. diff --git a/23_Measuring_performance.Rmd b/23_Measuring_performance.qmd similarity index 90% rename from 23_Measuring_performance.Rmd rename to 23_Measuring_performance.qmd index d2e653b7..965406e7 100755 --- a/23_Measuring_performance.Rmd +++ b/23_Measuring_performance.qmd @@ -3,14 +3,10 @@ source("common.R") ``` # (PART) Techniques {-} -\stepcounter{chapter} # Measuring performance - -\stepcounter{section} ## Profiling - __[Q1]{.Q}__: Profile the following function with `torture = TRUE`. What is surprising? Read the source code of `rm()` to figure out what's going on. @@ -38,21 +34,24 @@ Surprisingly, profiling `f()` like this takes a very long time. What could be th We follow the hint in the question and inspect the source code of `rm()`: ```{r,eval = FALSE} -function (..., list = character(), pos = -1, - envir = as.environment(pos), - inherits = FALSE) -{ +function(..., list = character(), pos = -1, + envir = as.environment(pos), + inherits = FALSE) { dots <- match.call(expand.dots = FALSE)$... if ( length(dots) && !all( - vapply(dots, function(x) is.symbol(x) || - is.character(x), NA, USE.NAMES = FALSE) + vapply(dots, function(x) { + is.symbol(x) || + is.character(x) + }, NA, USE.NAMES = FALSE) ) - ) + ) { stop("... must contain names or character strings") + } names <- vapply(dots, as.character, "") - if (length(names) == 0L) + if (length(names) == 0L) { names <- character() + } list <- .Primitive("c")(list, names) .Internal(remove(list, envir, inherits)) } @@ -77,14 +76,13 @@ Anecdotally, one of the authors once finished the profiling under an older R ver In conclusion, this question appears to be unanswerable for us, even for Hadley. ## Microbenchmarking - __[Q1]{.Q}__: Instead of using `bench::mark()`, you could use the built-in function `system.time()`. But `system.time()` is much less precise, so you'll need to repeat each operation many times with a loop, and then divide to find the average time of each operation, as in the code below. ```{r, eval = FALSE} n <- 1e6 system.time(for (i in 1:n) sqrt(x)) / n -system.time(for (i in 1:n) x ^ 0.5) / n +system.time(for (i in 1:n) x^0.5) / n ``` How do the estimates from `system.time()` compare to those from `bench::mark()`? Why are they different? @@ -96,8 +94,8 @@ n <- 1e6 x <- runif(100) bench_df <- bench::mark( - sqrt(x), - x ^ 0.5, + sqrt(x), + x^0.5, iterations = n ) @@ -111,7 +109,7 @@ t1_bench <- mean(unlist(bench_df[1, "time"])) t2_bench <- mean(unlist(bench_df[2, "time"])) t1_systime <- system.time(for (i in 1:n) sqrt(x)) / n -t2_systime <- system.time(for (i in 1:n) x ^ 0.5) / n +t2_systime <- system.time(for (i in 1:n) x^0.5) / n ``` We see, that both approaches get the order of magnitude right. We assume, that the `bench::mark()`-results may be a little more accurate, because of its high precision timer. There may also be overhead introduced by the for loop in the `system.time()`-approach. @@ -130,7 +128,7 @@ Side Note: take a look at `?proc.time` if you want to learn about the difference __[Q2]{.Q}__: Here are two other ways to compute the square root of a vector. Which do you think will be fastest? Which will be slowest? Use microbenchmarking to test your answers. ```{r, eval = FALSE} -x ^ (1 / 2) +x^(1 / 2) exp(log(x) / 2) ``` diff --git a/24_Improving_performance.Rmd b/24_Improving_performance.qmd similarity index 94% rename from 24_Improving_performance.Rmd rename to 24_Improving_performance.qmd index e5ca03d2..8daf5424 100755 --- a/24_Improving_performance.Rmd +++ b/24_Improving_performance.qmd @@ -3,11 +3,8 @@ source("common.R") ``` # Improving performance - -\addtocounter{section}{2} ## Checking for existing solutions - __[Q1]{.Q}__: What are faster alternatives to `lm`? Which are specifically designed to work with larger datasets? @@ -20,16 +17,20 @@ penguins <- palmerpenguins::penguins bench::mark( "lm" = lm( - body_mass_g ~ bill_length_mm + species, data = penguins + body_mass_g ~ bill_length_mm + species, + data = penguins ) %>% coef(), "biglm" = biglm::biglm( - body_mass_g ~ bill_length_mm + species, data = penguins + body_mass_g ~ bill_length_mm + species, + data = penguins ) %>% coef(), "speedglm" = speedglm::speedlm( - body_mass_g ~ bill_length_mm + species, data = penguins + body_mass_g ~ bill_length_mm + species, + data = penguins ) %>% coef(), "fastLm" = RcppEigen::fastLm( - body_mass_g ~ bill_length_mm + species, data = penguins + body_mass_g ~ bill_length_mm + species, + data = penguins ) %>% coef() ) ``` @@ -68,7 +69,7 @@ x <- sample(table, 10000, replace = TRUE) bench::mark( match = match(x, table), fastmatch = fastmatch::fmatch(x, table) -) +) ``` __[Q3]{.Q}__: List four functions (not just those in base R) that convert a string into a date time object. What are their strengths and weaknesses? @@ -101,7 +102,7 @@ date_lt2 <- rep(date_lt, 10000) date_ct2 <- rep(date_ct, 10000) bench::mark( - date_lt2 - date_lt2, + date_lt2 - date_lt2, date_ct2 - date_ct2, date_ct2 - date_lt2 ) @@ -111,7 +112,8 @@ bench::mark( ```{r} date_str <- strptime("2020-01-01 12:30:25", - format = "%Y-%m-%d %H:%M:%S") + format = "%Y-%m-%d %H:%M:%S" +) identical(date_lt, date_str) ``` @@ -156,8 +158,10 @@ slider::slide_dbl(x, mean, .before = 1, .complete = TRUE) bench::mark( caTools = caTools::runmean(x, k = 2, endrule = "NA"), data.table = data.table::frollmean(x, 2), - RcppRoll = RcppRoll::roll_mean(x, n = 2, fill = NA, - align = "right"), + RcppRoll = RcppRoll::roll_mean(x, + n = 2, fill = NA, + align = "right" + ), slider = slider::slide_dbl(x, mean, .before = 1, .complete = TRUE), TTR = TTR::SMA(x, 2), zoo_apply = zoo::rollapply(x, 2, mean, fill = NA, align = "right"), @@ -195,7 +199,6 @@ For more general alternatives, the appropriate choice highly depends on the type - `{DEoptim}` [@Deoptim] provides a global optimiser based on the Differential Evolution algorithm. ## Doing as little as possible - __[Q1]{.Q}__: What's the difference between `rowSums()` and `.rowSums()`? @@ -249,7 +252,7 @@ a <- 21:25 b <- seq(21, 29, 2) m <- cbind(a, b) -chisq.test(m) %>% print(digits=5) +chisq.test(m) %>% print(digits = 5) chisq.test2(a, b) bench::mark( @@ -266,25 +269,24 @@ __[A]{.solved}__: When analysing the source code of `table()` we aim to omit eve First, we calculate the dimensions and names of the output table. Then we use `fastmatch::fmatch()` to map the elements of each vector to their position within the vector itself (i.e. the smallest value is mapped to `1L`, the second smallest value to `2L`, etc.). Following the logic within `table()` we combine and shift these values to create a mapping of the integer pairs in our data to the index of the output table. After applying these lookups `tabulate()` counts the values and returns an integer vector with counts for each position in the table. As a last step, we reuse the code from `table()` to assign the correct dimension and class. ```{r} -table2 <- function(a, b){ - +table2 <- function(a, b) { a_s <- sort(unique(a)) b_s <- sort(unique(b)) - + a_l <- length(a_s) b_l <- length(b_s) - + dims <- c(a_l, b_l) pr <- a_l * b_l dn <- list(a = a_s, b = b_s) - + bin <- fastmatch::fmatch(a, a_s) + a_l * fastmatch::fmatch(b, b_s) - a_l y <- tabulate(bin, pr) - + y <- array(y, dim = dims, dimnames = dn) class(y) <- "table" - + y } @@ -300,7 +302,6 @@ bench::mark( Since we didn't use `table()` in our `chisq.test2()`-implementation, we cannot benefit from the slight performance gain from `table2()`. ## Vectorise - __[Q1]{.Q}__: The density functions, e.g. `dnorm()`, have a common interface. Which arguments are vectorised over? What does `rnorm(10, mean = 10:1)` do? @@ -339,11 +340,14 @@ rowsums %>% summary() %>% dplyr::mutate(Approach = as.character(expression)) %>% ggplot( - aes(p, median, color = Approach, group = Approach)) + + aes(p, median, color = Approach, group = Approach) + ) + geom_point() + geom_line() + - labs(x = "Number of Rows and Columns", - y = "Median (s)") + + labs( + x = "Number of Rows and Columns", + y = "Median (s)" + ) + theme(legend.position = "top") ``` @@ -379,7 +383,9 @@ weightedsum %>% ggplot(aes(n, median, color = Approach, group = Approach)) + geom_point() + geom_line() + - labs(x = "Vector length (millions)", - y = "Median (s)") + + labs( + x = "Vector length (millions)", + y = "Median (s)" + ) + theme(legend.position = "top") ``` From 3261d63321607cdc26379bb290b348ffc6a597ba Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Tue, 23 Jan 2024 21:16:43 -0500 Subject: [PATCH 08/25] cpp chapter --- 25_Rewriting_R_code_in_Cpp.Rmd | 641 ------------------------ 25_Rewriting_R_code_in_Cpp.qmd | 886 +++++++++++++++++++++++++++++++++ 2 files changed, 886 insertions(+), 641 deletions(-) delete mode 100755 25_Rewriting_R_code_in_Cpp.Rmd create mode 100755 25_Rewriting_R_code_in_Cpp.qmd diff --git a/25_Rewriting_R_code_in_Cpp.Rmd b/25_Rewriting_R_code_in_Cpp.Rmd deleted file mode 100755 index 12123f4e..00000000 --- a/25_Rewriting_R_code_in_Cpp.Rmd +++ /dev/null @@ -1,641 +0,0 @@ -```{r, include = FALSE} -source("common.R") -``` - -# Rewriting R code in C++ - - -\stepcounter{section} -## Getting started with C++ - - -__[Q1]{.Q}__: With the basics of C++ in hand, it's now a great time to practice by reading and writing some simple C++ functions. For each of the following functions, read the code and figure out what the corresponding base R function is. You might not understand every part of the code yet, but you should be able to figure out the basics of what the function does. - -```{Rcpp, eval = FALSE} -double f1(NumericVector x) { - int n = x.size(); - double y = 0; - - for(int i = 0; i < n; ++i) { - y += x[i] / n; - } - return y; -} - -NumericVector f2(NumericVector x) { - int n = x.size(); - NumericVector out(n); - - out[0] = x[0]; - for(int i = 1; i < n; ++i) { - out[i] = out[i - 1] + x[i]; - } - return out; -} - -bool f3(LogicalVector x) { - int n = x.size(); - - for(int i = 0; i < n; ++i) { - if (x[i]) return true; - } - return false; -} - -int f4(Function pred, List x) { - int n = x.size(); - - for(int i = 0; i < n; ++i) { - LogicalVector res = pred(x[i]); - if (res[0]) return i + 1; - } - return 0; -} - -NumericVector f5(NumericVector x, NumericVector y) { - int n = std::max(x.size(), y.size()); - NumericVector x1 = rep_len(x, n); - NumericVector y1 = rep_len(y, n); - - NumericVector out(n); - - for (int i = 0; i < n; ++i) { - out[i] = std::min(x1[i], y1[i]); - } - - return out; -} -``` - -__[A]{.solved}__: The code above corresponds to the following base R functions: - -- f1: `mean()` -- f2: `cumsum()` -- f3: `any()` -- f4: `Position()` -- f5: `pmin()` - -__[Q2]{.Q}__: To practice your function writing skills, convert the following functions into C++. For now, assume the inputs have no missing values. - -1. `all()`. - -2. `cumprod()`, `cummin()`, `cummax()`. - -3. `diff()`. Start by assuming lag 1, and then generalise for lag `n`. - -4. `range()`. - -5. `var()`. Read about the approaches you can take on [Wikipedia](http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance). Whenever implementing a numerical algorithm, it's always good to check what is already known about the problem. - -__[A]{.solved}__: Let's port these functions to C++. - -1. `all()` - - ```{Rcpp, eval = FALSE} - bool allC(LogicalVector x) { - int n = x.size(); - - for (int i = 0; i < n; ++i) { - if (!x[i]) return false; - } - return true; - } - ``` - -2. `cumprod()`, `cummin()`, `cummax()`. - - ```{Rcpp, eval = FALSE} - NumericVector cumprodC(NumericVector x) { - int n = x.size(); - NumericVector out(n); - - out[0] = x[0]; - for (int i = 1; i < n; ++i) { - out[i] = out[i - 1] * x[i]; - } - return out; - } - - NumericVector cumminC(NumericVector x) { - int n = x.size(); - NumericVector out(n); - - out[0] = x[0]; - for (int i = 1; i < n; ++i) { - out[i] = std::min(out[i - 1], x[i]); - } - return out; - } - - NumericVector cummaxC(NumericVector x) { - int n = x.size(); - NumericVector out(n); - - out[0] = x[0]; - for (int i = 1; i < n; ++i) { - out[i] = std::max(out[i - 1], x[i]); - } - return out; - } - ``` - -3. `diff()` (Start by assuming lag 1, and then generalise for lag `n`.) - - ```{Rcpp, eval = FALSE} - NumericVector diffC(NumericVector x) { - int n = x.size(); - NumericVector out(n - 1); - - for (int i = 1; i < n; i++) { - out[i - 1] = x[i] - x[i - 1]; - } - return out ; - } - - NumericVector difflagC(NumericVector x, int lag = 1) { - int n = x.size(); - - if (lag >= n) stop("`lag` must be less than `length(x)`."); - - NumericVector out(n - lag); - - for (int i = lag; i < n; i++) { - out[i - lag] = x[i] - x[i - lag]; - } - return out; - } - ``` - -4. `range()` - - ```{Rcpp, eval = FALSE} - NumericVector rangeC(NumericVector x) { - double omin = x[0], omax = x[0]; - int n = x.size(); - - if (n == 0) stop("`length(x)` must be greater than 0."); - - for (int i = 1; i < n; i++) { - omin = std::min(x[i], omin); - omax = std::max(x[i], omax); - } - - NumericVector out(2); - out[0] = omin; - out[1] = omax; - return out; - } - ``` - -5. `var()` - - ```{Rcpp, eval = FALSE} - double varC(NumericVector x) { - int n = x.size(); - - if (n < 2) { - return NA_REAL; - } - - double mx = 0; - for (int i = 0; i < n; ++i) { - mx += x[i] / n; - } - - double out = 0; - for (int i = 0; i < n; ++i) { - out += pow(x[i] - mx, 2); - } - - return out / (n - 1); - } - ``` - -\stepcounter{section} -## Missing values - - -__[Q1]{.Q}__: Rewrite any of the functions from the first exercise to deal with missing values. If `na.rm` is true, ignore the missing values. If `na.rm` is false, return a missing value if the input contains any missing values. Some good functions to practice with are `min()`, `max()`, `range()`, `mean()`, and `var()`. - -__[A]{.solved}__: For this exercise we start with `minC()` and extend it so it can deal with missing values. We introduce an `na_rm` argument to make `minC()` aware of `NA`s. In case `x` contains exclusively `NA` values `minC()` should return `Inf` for `na_rm = TRUE`. For the return values vector data types are used to avoid irregular type conversions. - -```{Rcpp} -#include -using namespace Rcpp; - -// [[Rcpp::export]] -NumericVector minC(NumericVector x, bool na_rm = false) { - int n = x.size(); - NumericVector out = NumericVector::create(R_PosInf); - - if (na_rm) { - for (int i = 0; i < n; ++i) { - if (x[i] == NA_REAL) { - continue; - } - if (x[i] < out[0]) { - out[0] = x[i]; - } - } - } else { - for (int i = 0; i < n; ++i) { - if (NumericVector::is_na(x[i])) { - out[0] = NA_REAL; - return out; - } - if (x[i] < out[0]) { - out[0] = x[i]; - } - } - } - - return out; -} -``` - -```{r} -minC(c(2:4, NA)) -minC(c(2:4, NA), na_rm = TRUE) -minC(c(NA, NA), na_rm = TRUE) -``` - -We also extend `anyC()` so it can deal with missing values. Please note that this (again) introduces some code duplication. This could be avoided by moving the check for missing values to the inner loop at the expense of a slight decrease of performance. Here we use `LogicalVector` as return type. If we would use `bool` instead, the C++ `NA_LOGICAL` would be converted into R's logical `TRUE`. - -```{Rcpp} -#include -using namespace Rcpp; - -// [[Rcpp::export]] -LogicalVector anyC(LogicalVector x, bool na_rm = false) { - int n = x.size(); - LogicalVector out = LogicalVector::create(false); - - if (na_rm == false) { - for (int i = 0; i < n; ++i) { - if (LogicalVector::is_na(x[i])) { - out[0] = NA_LOGICAL; - return out; - } else { - if (x[i]) { - out[0] = true; - } - } - } - } - - if (na_rm) { - for (int i = 0; i < n; ++i) { - if (LogicalVector::is_na(x[i])) { - continue; - } - if (x[i]) { - out[0] = true; - return out; - } - } - } - - return out; -} -``` - -```{r} -anyC(c(NA, TRUE)) # any(c(NA, TRUE)) would return TRUE in this case -anyC(c(NA, TRUE), na_rm = TRUE) -``` - -__[Q2]{.Q}__: Rewrite `cumsum()` and `diff()` so they can handle missing values. Note that these functions have slightly more complicated behaviour. - -__[A]{.solved}__: Our `NA`-aware `cumsumC()` function will return a vector of the same length as `x`. By default (`na_rm = FALSE`) all values following the first `NA` input value will be set to `NA`, because they depend on the unknown missing value. In case of `na_rm = FALSE` the `NA` values are treated like zeros. - -```{Rcpp} -#include -using namespace Rcpp; - -// [[Rcpp::export]] -NumericVector cumsumC(NumericVector x, bool na_rm = false) { - int n = x.size(); - NumericVector out(n); - LogicalVector is_missing = is_na(x); - - if (!na_rm) { - out[0] = x[0]; - for (int i = 1; i < n; ++i) { - if (is_missing[i - 1]) { - out[i] = NA_REAL; - } else{ - out[i] = out[i - 1] + x[i]; - } - } - } - - if (na_rm) { - if (is_missing[0]) { - out[0] = 0; - } else { - out[0] = x[0]; - } - for (int i = 1; i < n; ++i) { - if (is_missing[i]) { - out[i] = out[i-1] + 0; - } else { - out[i] = out[i-1] + x[i]; - } - } - } - - return out; -} -``` - -```{r} -cumsumC(c(1, NA, 2, 4)) -cumsumC(c(1, NA, 2, 4), na_rm = TRUE) -``` - -The `diffC()` implementation will return an `NA` vector of length `length(x) - lag`, if the input vector contains a missing value. In case of `na_rm = TRUE`, the function will return an `NA` for every difference with at least one `NA` as input. - -```{Rcpp} -#include -using namespace Rcpp; - -// [[Rcpp::export]] -NumericVector diffC(NumericVector x, int lag = 1, - bool na_rm = false) { - int n = x.size(); - - if (lag >= n) stop("`lag` must be less than `length(x)`."); - - NumericVector out(n - lag); - - for (int i = lag; i < n; i++) { - if (NumericVector::is_na(x[i]) || - NumericVector::is_na(x[i - lag])) { - if (!na_rm) { - return rep(NumericVector::create(NA_REAL), n - lag); - } - out[i - lag] = NA_REAL; - continue; - } - out[i - lag] = x[i] - x[i - lag]; - } - - return out; -} -``` - - - -```{r, eval = FALSE} -diffC(c(1, 3, NA, 10)) -#> [1] NA NA NA -diffC(c(1, 3, NA, 10), na_rm = TRUE) -#> [1] 2 NA NA -``` - -## Standard Template Library - - -To practice using the STL algorithms and data structures, implement the following using R functions in C++, using the hints provided: - -__[Q1]{.Q}__: `median.default()` using `partial_sort`. - -__[A]{.solved}__: The median is computed differently for even or odd vectors, which we allow for in the function below. - -```{Rcpp} -#include -#include -using namespace Rcpp; - -// [[Rcpp::export]] -double medianC(NumericVector x) { - int n = x.size(); - - if (n % 2 == 0) { - std::partial_sort (x.begin(), x.begin() + n / 2 + 1, x.end()); - return (x[n / 2 - 1] + x[n / 2]) / 2; - } else { - std::partial_sort (x.begin(), x.begin() + (n + 1) / 2, x.end()); - return x[(n + 1) / 2 - 1]; - } -} -``` - -__[Q2]{.Q}__: `%in%` using `unordered_set` and the `find()` or `count()` methods. - -__[A]{.solved}__: We use the `find()` method and loop through the `unordered_set` until we find a match or have scanned the entire set. - -```{Rcpp, eval = FALSE} -#include -#include -using namespace Rcpp; - -// [[Rcpp::export]] -LogicalVector inC(CharacterVector x, CharacterVector table) { - std::unordered_set seen; - seen.insert(table.begin(), table.end()); - - int n = x.size(); - LogicalVector out(n); - for (int i = 0; i < n; ++i) { - out[i] = seen.find(x[i]) != seen.end(); - } - - return out; -} -``` - -__[Q3]{.Q}__: `unique()` using an `unordered_set` (challenge: do it in one line!). - -__[A]{.solved}__: The `insert()`-method will return if an equivalent element already exists. If a new element is inserted, we will add it to the (unique) return vector of our function. - -```{Rcpp, eval = FALSE} -#include -#include -using namespace Rcpp; - -// [[Rcpp::export]] -NumericVector uniqueC(NumericVector x) { - std::unordered_set seen; - int n = x.size(); - - std::vector out; - for (int i = 0; i < n; ++i) { - if (seen.insert(x[i]).second) out.push_back(x[i]); - } - - return wrap(out); -} - - -// As a one-liner -// [[Rcpp::export]] -std::unordered_set uniqueCC(NumericVector x) { - return std::unordered_set(x.begin(), x.end()); -} -``` - -__[Q4]{.Q}__: `min()` using `std::min()`, or `max()` using `std::max()`. - -__[A]{.solved}__: We will implement `min()` by iterating over the vector and recursively comparing each element to the current minimum value. - -```{Rcpp} -#include -using namespace Rcpp; - -// [[Rcpp::export]] -double minC(NumericVector x) { - int n = x.size(); - double out = x[0]; - - for (int i = 0; i < n; i++) { - out = std::min(out, x[i]); - } - - return out; -} -``` - -__[Q5]{.Q}__: `which.min()` using `min_element`, or `which.max()` using `max_element`. - -__[A]{.solved}__: To implement `which.min()`, we will first locate the `min_element` and then compute the `distance()` to it (starting from the beginning of the vector). - -```{Rcpp} -#include -#include -#include -using namespace Rcpp; - -// [[Rcpp::export]] -double which_minC(NumericVector x) { - int out = std::distance( - x.begin(), std::min_element(x.begin(), x.end()) - ); - - return out + 1; -} -``` - -__[Q6]{.Q}__: `setdiff()`, `union()`, and `intersect()` for integers using sorted ranges and `set_union`, `set_intersection` and `set_difference`. - -__[A]{.solved}__: The structure of the three functions will be very similar. - -We first sort both input vectors. Then we apply the respective `set_union`, `set_intersection` or `set_difference` function. After that, the result will be between the iterators `tmp.begin()` and `out_end`. To retrieve the result, we loop once through the range between `tmp.begin()` and `out_end` in the last part of each function. - -The set operations in base R will discard duplicated values in the arguments. We achieve a similar behaviour by introducing a deduplication step, which omits values that match their predecessor. For the symmetric set functions `unionC` and `intersectC` this step is implemented for the output vector. For `setdiffC` the deduplication is applied to the first input vector. - -```{Rcpp} -#include -#include -#include -using namespace Rcpp; - -// [[Rcpp::plugins(cpp11)]] -// [[Rcpp::export]] -IntegerVector unionC(IntegerVector x, IntegerVector y) { - int nx = x.size(); - int ny = y.size(); - - IntegerVector tmp(nx + ny); - - std::sort(x.begin(), x.end()); // unique - std::sort(y.begin(), y.end()); - - IntegerVector::iterator out_end = std::set_union( - x.begin(), x.end(), y.begin(), y.end(), tmp.begin() - ); - - int prev_value = 0; - IntegerVector out; - for (IntegerVector::iterator it = tmp.begin(); - it != out_end; ++it) { - if ((it != tmp.begin()) && (prev_value == *it)) continue; - - out.push_back(*it); - - prev_value = *it; - } - - return out; -} - -// [[Rcpp::export]] -IntegerVector intersectC(IntegerVector x, IntegerVector y) { - int nx = x.size(); - int ny = y.size(); - - IntegerVector tmp(std::min(nx, ny)); - - std::sort(x.begin(), x.end()); - std::sort(y.begin(), y.end()); - - IntegerVector::iterator out_end = std::set_intersection( - x.begin(), x.end(), y.begin(), y.end(), tmp.begin() - ); - - int prev_value = 0; - IntegerVector out; - for (IntegerVector::iterator it = tmp.begin(); - it != out_end; ++it) { - if ((it != tmp.begin()) && (prev_value == *it)) continue; - - out.push_back(*it); - - prev_value = *it; - } - - return out; -} - -// [[Rcpp::export]] -IntegerVector setdiffC(IntegerVector x, IntegerVector y) { - int nx = x.size(); - int ny = y.size(); - - IntegerVector tmp(nx); - - std::sort(x.begin(), x.end()); - - int prev_value = 0; - IntegerVector x_dedup; - for (IntegerVector::iterator it = x.begin(); - it != x.end(); ++it) { - if ((it != x.begin()) && (prev_value == *it)) continue; - - x_dedup.push_back(*it); - - prev_value = *it; - } - - std::sort(y.begin(), y.end()); - - IntegerVector::iterator out_end = std::set_difference( - x_dedup.begin(), x_dedup.end(), y.begin(), y.end(), tmp.begin() - ); - - IntegerVector out; - for (IntegerVector::iterator it = tmp.begin(); - it != out_end; ++it) { - out.push_back(*it); - } - - return out; -} -``` - -Let's verify, that these functions work as intended. - -```{r} -# input vectors include duplicates -x <- c(1, 2, 3, 3, 3) -y <- c(3, 3, 2, 5) - -union(x, y) -unionC(x, y) - -intersect(x, y) -intersectC(x, y) - -setdiff(x, y) -setdiffC(x, y) -``` diff --git a/25_Rewriting_R_code_in_Cpp.qmd b/25_Rewriting_R_code_in_Cpp.qmd new file mode 100755 index 00000000..3647c201 --- /dev/null +++ b/25_Rewriting_R_code_in_Cpp.qmd @@ -0,0 +1,886 @@ +```{r, include = FALSE} +source("common.R") +``` + +# Rewriting R code in C++ + +## Getting started with C++ + +__[Q1]{.Q}__: With the basics of C++ in hand, it's now a great time to practice +by reading and writing some simple C++ functions. For each of the following +functions, read the code and figure out what the corresponding base R function +is. You might not understand every part of the code yet, but you should be able +to figure out the basics of what the function does. + +Pay attention to the parts where we use `writable::doubles` instead of +`doubles`, in C++ objects can be read-only, which is different from R +(or Python). + +Unlike R, C++ indexes start at 0, not 1. This is a common source of bugs when +porting code from R to C++. + +```{cpp, eval = FALSE} +double f1_(doubles x) { + int n = x.size(); + double y = 0; + + for(int i = 0; i < n; ++i) { + y += x[i] / n; + } + return y; +} + +doubles f2_(doubles x) { + int n = x.size(); + writable::doubles out(n); + + out[0] = x[0]; + for(int i = 1; i < n; ++i) { + out[i] = out[i - 1] + x[i]; + } + return out; +} + +bool f3_(logicals x) { + int n = x.size(); + + for(int i = 0; i < n; ++i) { + if (x[i]) return true; + } + return false; +} + +int f4_(function pred, list x) { + int n = x.size(); + + for(int i = 0; i < n; ++i) { + logicals res = pred(x[i]); + if (res[0]) return i + 1; + } + return 0; +} + +doubles f5_(doubles x, doubles y) { + int n = std::max(x.size(), y.size()); + vector x1(n); + vector y1(n); + + for (int i = 0; i < n; ++i) { + x1[i] = x[i % x.size()]; + y1[i] = y[i % y.size()]; + } + + writable::doubles out(n); + + for (int i = 0; i < n; ++i) { + out[i] = std::min(x1[i], y1[i]); + } + + return out; +} +``` + +__[A]{.solved}__: The code above corresponds to the following base R functions: + +- f1_: `mean()` +- f2_: `cumsum()` +- f3_: `any()` +- f4_: `Position()` +- f5_: `pmin()` + +__[Q2]{.Q}__: To practice your function writing skills, convert the following +functions into C++. For now, assume the inputs have no missing values. + +1. `all()`. + +2. `cumprod()`, `cummin()`, `cummax()`. + +3. `diff()`. Start by assuming lag 1, and then generalise for lag `n`. + +4. `range()`. + +5. `var()`. Read about the approaches you can take on +[Wikipedia](http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance). +Whenever implementing a numerical algorithm, it's always good to check what is +already known about the problem. + +__[A]{.solved}__: Let's port these functions to C++. + +1. `all()` + + ```{cpp, eval = FALSE} + bool all_cpp_(logicals x) { + int n = x.size(); + for(int i = 0; i < n; ++i) { + if (x[i] == false) { + return false; + } + } + return true; + } + ``` + +2. `cumprod()`, `cummin()`, `cummax()`. + + ```{cpp, eval = FALSE} + doubles cumprod_cpp_(doubles x) { + int n = x.size(); + writable::doubles out(n); + out[0] = x[0]; + for(int i = 1; i < n; ++i) { + out[i] = out[i - 1] * x[i]; + } + return out; + } + + doubles cummin_cpp_(doubles x) { + int n = x.size(); + writable::doubles out(n); + + out[0] = x[0]; + for (int i = 1; i < n; ++i) { + double x1 = out[i - 1]; + double x2 = x[i]; + out[i] = std::min(x1, x2); + } + + return out; + } + + doubles cummax_cpp_(doubles x) { + int n = x.size(); + writable::doubles out(n); + + out[0] = x[0]; + for (int i = 1; i < n; ++i) { + double x1 = out[i - 1]; + double x2 = x[i]; + out[i] = std::max(x1, x2); + } + return out; + } + ``` + +3. `diff()` (Start by assuming lag 1, and then generalise for lag `n`.) + + ```{cpp, eval = FALSE} + doubles diff_cpp_(doubles x) { + int n = x.size(); + writable::doubles out(n - 1); + + for (int i = 1; i < n; i++) { + out[i - 1] = x[i] - x[i - 1]; + } + return out ; + } + + doubles diff_lag_cpp_(doubles x, int lag) { + int n = x.size(); + + if (lag >= n) stop("`lag` must be less than `length(x)`."); + + writable::doubles out(n - lag); + + for (int i = lag; i < n; i++) { + out[i - lag] = x[i] - x[i - lag]; + } + return out; + } + ``` + +4. `range()` + + ```{cpp, eval = FALSE} + doubles range_cpp_(doubles x) { + double omin = x[0], omax = x[0]; + int n = x.size(); + + if (n == 0) stop("`length(x)` must be greater than 0."); + + for (int i = 1; i < n; i++) { + omin = std::min(x[i], omin); + omax = std::max(x[i], omax); + } + + writable::doubles out(2); + out[0] = omin; + out[1] = omax; + return out; + } + ``` + +5. `var()` + + ```{cpp, eval = FALSE} + double var_cpp_(doubles x) { + int n = x.size(); + + if (n < 2) { + return NA_REAL; + } + + double mx = 0; + for (int i = 0; i < n; ++i) { + mx += x[i] / n; + } + + double out = 0; + for (int i = 0; i < n; ++i) { + out += pow(x[i] - mx, 2); + } + + return out / (n - 1); + } + ``` + +## Missing values + +__[Q1]{.Q}__: Rewrite any of the functions from the first exercise to deal with +missing values. If `na.rm` is true, ignore the missing values. If `na.rm` is +false, return a missing value if the input contains any missing values. Some +good functions to practice with are `min()`, `max()`, `range()`, `mean()`, and `var()`. + +__[A]{.solved}__: For this exercise we start with `min_cpp_()` and extend it so +it can deal with missing values. We introduce an `na_rm` argument to make +`min_cpp_()` aware of `NA`s. In case `x` contains exclusively `NA` values +`min_cpp_()` should return `Inf` for `na_rm = TRUE`. For the return values +vector data types are used to avoid irregular type conversions. + +We use expressions provided by `#include ` to simplify the code: + +* `R_PosInf`, which is pure C++ this would be + `std::numeric_limits::infinity();` and requires `#include `. +* `is_na(x[i])`, which is the same as `x[i] == NA_REAL`. + +```{cpp} +#include + +using namespace cpp11; + +[[cpp11::register]] doubles min_cpp_(cpp11::doubles x, bool na_rm) { + int n = x.size(); + writable::doubles out = {R_PosInf}; + + if (na_rm) { + for (int i = 0; i < n; ++i) { + if (x[i] == NA_REAL) { + continue; + } + if (x[i] < out[0]) { + out[0] = x[i]; + } + } + } else { + for (int i = 0; i < n; ++i) { + if (is_na(x[i])) { + out[0] = NA_REAL; + return out; + } + if (x[i] < out[0]) { + out[0] = x[i]; + } + } + } + + return out; +} +``` + +```{r} +min_cpp_(as.double(c(2:4, NA)), FALSE) +min_cpp_(as.double(c(2:4, NA)), TRUE) +min_cpp_(as.double(c(NA, NA)), TRUE) +``` + +Note that we added explicit values and types for each parameter. This is +necessary because `cpp11` does not automatically cast integers (i.e., `2:4`) +to doubles and does not allow default parameters in the function. This is +because R (and Python) automatically cast `1L` to `1.0` depending on the +context, which is not the case for C++. Run `min_cpp_(c(2:4, NA), FALSE)` and +read the error message carefully. + +To simplify things for the end user, you can provide a wrapper function that +calls `min_cpp_()` with the correct types and default values. + +```{r} +min_cpp <- function(x, na_rm = FALSE) { + if (!is.double(x)) { + x <- as.double(x) + } + min_cpp_(x, na_rm) +} + +min_cpp(c(2:4, NA)) +``` + +We also extend `any_cpp_()` so it can deal with missing values. Please note that +this (again) introduces some code duplication. This could be avoided by moving +the check for missing values to the inner loop at the expense of a slight +decrease of performance. Here we use `logicals` as return type. If we would use +`bool` instead, the C++ `NA_LOGICAL` would be converted into R's logical `TRUE`. + +```{cpp} +#include + +using namespace cpp11; + +[[cpp11::register]] logicals any_cpp_(logicals x, bool na_rm) { + int n = x.size(); + writable::logicals out = {false}; + + if (na_rm == false) { + for (int i = 0; i < n; ++i) { + if (is_na(x[i])) { + out[0] = NA_LOGICAL; + return out; + } else { + if (x[i]) { + out[0] = true; + } + } + } + } + + if (na_rm) { + for (int i = 0; i < n; ++i) { + if (is_na(x[i])) { + continue; + } + if (x[i]) { + out[0] = true; + return out; + } + } + } + + return out; +} +``` + +```{r} +any_cpp_(c(NA, TRUE), F) # any(c(NA, TRUE)) would return TRUE in this case +any_cpp_(c(NA, TRUE), T) +``` + +__[Q2]{.Q}__: Rewrite `cumsum()` and `diff()` so they can handle missing values. +Note that these functions have slightly more complicated behaviour. + +__[A]{.solved}__: Our `NA`-aware `cumsum_cpp_()` function will return a vector +of the same length as `x`. By default (`na_rm = FALSE`) all values following the +first `NA` input value will be set to `NA`, because they depend on the unknown +missing value. In case of `na_rm = FALSE` the `NA` values are treated like +zeros. + +```{cpp} +#include + +using namespace cpp11; + +[[cpp11::register]] doubles cumsum_cpp_(doubles x, bool na_rm = false) { + int n = x.size(); + + writable::doubles out(n); + out[0] = x[0]; + + if (na_rm == true) { + for (int i = 1; i < n; ++i) { + double y1 = out[i - 1], y2 = x[i]; + if (ISNAN(y2)) { + out[i] = y1; + } else { + if (ISNAN(y1)) { + out[i] = y2; + } else { + out[i] = y1 + y2; + } + } + } + } else { + for (int i = 1; i < n; ++i) { + double y1 = out[i - 1], y2 = x[i]; + if (ISNAN(y2)) { + out[i] = NA_REAL; + } else { + if (ISNAN(y1)) { + out[i] = NA_REAL; + } else { + out[i] = y1 + y2; + } + } + } + } + + return out; +} +``` + +```{r} +cumsum_cpp_(c(1, NA, 2, 4), FALSE) +cumsum_cpp_(c(1, NA, 2, 4), TRUE) +``` + +This example works immediately, because the input vector is a vector of doubles. +If we create a sequence of integers, we need to cast it as doubles. + +```{r} +cumsum_cpp_(as.double(1:4), FALSE) + +# or use a wrapper function +cumsum_cpp <- function(x, na_rm = FALSE) { + if (!is.double(x)) { + x <- as.double(x) + } + cumsum_cpp_(x, na_rm) +} + +cumsum_cpp(1:4, FALSE) +``` + +The `diff_cpp_()` implementation will return an `NA` vector of length +`length(x) - lag`, if the input vector contains a missing value. In case of +`na_rm = TRUE`, the function will return an `NA` for every difference with at +least one `NA` as input. + +```{cpp} +#include + +using namespace cpp11; + +[[cpp11::register]] doubles diff_cpp_(doubles x, int lag, bool na_rm) { + int n = x.size(); + + if (lag >= n) stop("`lag` must be less than `length(x)`."); + + writable::doubles out(n - lag); + + for (int i = lag; i < n; i++) { + if (is_na(x[i]) || is_na(x[i - lag])) { + if (!na_rm) { + writable::doubles out_na(n - lag); + for (int j = 0; j < n - lag; ++j) { + out_na[j] = NA_REAL; + } + return out_na; + } + out[i - lag] = NA_REAL; + continue; + } + out[i - lag] = x[i] - x[i - lag]; + } + + return out; +} +``` + +```{r} +diff_cpp_(c(1, 3, NA, 10), 1L, FALSE) +diff_cpp_(c(1, 3, NA, 10), 1L, TRUE) +``` + +## Standard Template Library + +To practice using the STL algorithms and data structures, implement the +following using R functions in C++, using the hints provided: + +__[Q1]{.Q}__: `median.default()` using `partial_sort`. + +__[A]{.solved}__: The median is computed differently for even or odd vectors, +which we allow for in the function below. + +To be able to use `partial_sort()` we need to include the `algorithm` header. +Unlike the previous examples, the input will be `const doubles& x`, meaning that +the function takes a constant reference to an object of type `doubles` (i.e., +the function will not modify the object `x`), and the `&` symbol means that the +function takes a reference to the object instead of a copy of the object. + +This can improve performance when the object is large, because it avoids copying +the object, but in this case we did it to use the `partial_sort()` function, +which is not compatible with `doubles` but it is with `vector` types. + +`doubles` is a data type we can send from R to C++ and vice-versa, but it is not +compatible with all of C++ functions. `vector` is a C++ data type that +we cannot send to R. There are more details about this in the alternative +solutions section at the end of the chapter. + +```{cpp} +#include +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] double median_cpp_(const doubles& x) { + int n = x.size(); + + vector y(n); + for (int i = 0; i < n; ++i) { + y[i] = x[i]; + } + + if (n % 2 == 0) { + partial_sort(y.begin(), y.begin() + n / 2 + 1, y.end()); + return (y[n / 2 - 1] + y[n / 2]) / 2; + } else { + partial_sort(y.begin(), y.begin() + (n + 1) / 2, y.end()); + return y[(n + 1) / 2 - 1]; + } +} +``` + +__[Q2]{.Q}__: `%in%` using `unordered_set` and the `find()` or `count()` +methods. + +__[A]{.solved}__: We use the `find()` method and loop through the +`unordered_set` until we find a match or have scanned the entire set. + +```{cpp} +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] logicals in_cpp_(const strings& x, const strings& table) { + unordered_set seen; + seen.insert(table.begin(), table.end()); + + int n = x.size(); + writable::logicals out(n); + for (int i = 0; i < n; ++i) { + out[i] = seen.find(x[i]) != seen.end(); + } + + return out; +} +``` + +```{r} +x <- letters[1:3] +y <- letters[1:2] +in_cpp_(x, y) +x %in% y +``` + +__[Q3]{.Q}__: `unique()` using an `unordered_set` (challenge: do it in one +line!). + +__[A]{.solved}__: The `insert()`-method will return if an equivalent element +already exists. If a new element is inserted, we will add it to the (unique) +return vector of our function. + +First we will implement the function in multiple lines, and then reduce. + +```{cpp} +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] doubles unique_cpp_(const doubles& x) { + unordered_set seen; + int n = x.size(); + + writable::doubles out; + for (int i = 0; i < n; ++i) { + if (seen.insert(x[i]).second) out.push_back(x[i]); + } + + return out; +} +``` + +In one line we would need to write a wrapper function in C++ to be able to +export the result to R. + +```{cpp} +#include +#include + +using namespace cpp11; +using namespace std; + +unordered_set unique_short1_cpp_(const doubles& x) { + return unordered_set(x.begin(), x.end()); +} + +[[cpp11::register]] doubles unique_short2_cpp_(const doubles& x) { + unordered_set y = unique_short1_cpp_(x); + + int n = y.size(); + writable::doubles out(n); + copy(y.begin(), y.end(), out.begin()); + + return out; +} +``` + +```{r} +x <- c(1, 2, 2) +unique_cpp_(x) +unique_short2_cpp_(x) +``` + +__[Q4]{.Q}__: `min()` using `std::min()`, or `max()` using `std::max()`. + +__[A]{.solved}__: We will implement `min()` by iterating over the vector and +recursively comparing each element to the current minimum value. + +In this example, and unlike the previous `min_cpp_()`, we can assign `x[i]` from +a `doubles` object to the left hand side that is a `double` variable without the +need to convert data types. + +```{cpp} +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] double min_cpp_(const doubles& x) { + int n = x.size(); + double out = x[0]; + + for (int i = 0; i < n; i++) { + out = min(out, x[i]); + } + + return out; +} +``` + +```{r} +x <- c(-1, 0, 1) +min_cpp_(x) +``` + +__[Q5]{.Q}__: `which.min()` using `min_element`, or `which.max()` using +`max_element`. + +__[A]{.solved}__: To implement `which.min()`, we will first locate the +`min_element` and then compute the `distance()` to it (starting from the +beginning of the vector). + +Check the `+1` in the return statement, which was included because of zero +indexes as it was mentioned in the beginning of the chapter. + +```{cpp} +#include +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] double which_min_cpp_(const doubles& x) { + int out = distance(x.begin(), min_element(x.begin(), x.end()) + ); + + return out + 1; +} +``` + +```{r} +which_min_cpp_(c(1, -1)) +``` + +__[Q6]{.Q}__: `setdiff()`, `union()`, and `intersect()` for integers using +sorted ranges and `set_union`, `set_intersection` and `set_difference`. + +__[A]{.solved}__: The structure of the three functions will be very similar. + +We first sort both input vectors. Then we apply the respective `set_union`, +`set_intersection` or `set_difference` function. After that, the result will be +between the iterators `tmp.begin()` and `out_end`. To retrieve the result, we +loop once through the range between `tmp.begin()` and `out_end` in the last part +of each function. + +The set operations in base R will discard duplicated values in the arguments. +We achieve a similar behaviour by introducing a deduplication step, which omits +values that match their predecessor. For the C++ implementation we rely on the +properties of the set operations and the fact that the input vectors are sorted. + +We also use variables of type `vector::iterator`, which are used to point +to elements in a `vector`. + +```{cpp} +#include +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] integers union_cpp_(const integers& x, const integers& y) { + vector vx(x.begin(), x.end()); + vector vy(y.begin(), y.end()); + + sort(vx.begin(), vx.end()); + sort(vy.begin(), vy.end()); + + vector tmp(vx.size() + vy.size()); + + vector::iterator out_end = + set_union(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin()); + + int prev_value = 0; + writable::integers out; + + for (vector::iterator it = tmp.begin(); it != out_end; ++it) { + if ((it != tmp.begin()) && (prev_value == *it)) continue; + + out.push_back(*it); + + prev_value = *it; + } + + return out; +} + +[[cpp11::register]] integers intersect_cpp_(const integers& x, + const integers& y) { + vector vx(x.begin(), x.end()); + vector vy(y.begin(), y.end()); + + sort(vx.begin(), vx.end()); + sort(vy.begin(), vy.end()); + + vector tmp(min(vx.size(), vy.size())); + + vector::iterator out_end = + set_intersection(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin()); + + writable::integers out; + + for (vector::iterator it = tmp.begin(); it != out_end; ++it) { + out.push_back(*it); + } + + return out; +} + +[[cpp11::register]] integers setdiff_cpp_(const integers& x, + const integers& y) { + vector vx(x.begin(), x.end()); + vector vy(y.begin(), y.end()); + + sort(vx.begin(), vx.end()); + sort(vy.begin(), vy.end()); + + vector tmp(vx.size()); + + vector::iterator out_end = + set_difference(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin()); + + writable::integers out; + + for (vector::iterator it = tmp.begin(); it != out_end; ++it) { + out.push_back(*it); + } + + return out; +} +``` + +Let's verify, that these functions work as intended. + +```{r} +# input vectors include duplicates +x <- 1:3 +y <- 0:5 + +union(x, y) +union_cpp_(x, y) + +intersect(x, y) +intersect_cpp_(x, y) + +x <- 1:3 +y <- 0:1 + +setdiff(x, y) +setdiff_cpp_(x, y) +``` + +## Alternative solutions + +### All + +The `all_cpp_()` function can be implemented at least in three more ways. + +I can save lines by not defining n. + +```cpp +bool all_cpp_(logicals x) { + for (int i = 0; i < x.size(); ++i) { + if (x[i] == false) { + return false; + } + } + return true; +} +``` + +It is also possible to directly define a logical variable `i` inside the loop. + +```cpp +bool all_cpp_(logicals x) { + for (bool i : x) { + if (i == false) { + return false; + } + } + return true; +} +``` + +Using `std::all_of()` you can do the same thing in one line. + +```cpp +bool all_cpp_(logicals x) { + return std::all_of(x.begin(), x.end(), [](bool x) { return x; }); +} +``` + +### Pairwise minimum + +Unlike `cumprod_cpp_()`, `cummin_cpp_()` requires to declare additional `double` +values, otherwise `std::min()` will not work. + +It is possible to save some lines by using `std::vector`. + +```cpp +#include +#include + +using namespace cpp11; +using namespace std; + +[[cpp11::register]] doubles pmin_cpp_(doubles x, doubles y) { + int n = max(x.size(), y.size()); + + vector x1(n); + vector y1(n); + for (int i = 0; i < n; ++i) { + x1[i] = x[i % x.size()]; + y1[i] = y[i % y.size()]; + } + + writable::doubles out(n); + + for (int i = 0; i < n; ++i) { + out[i] = min(x1[i], y1[i]); + } + + return out; +} +``` + +We can subset `x1` and `y1` when these are of class `vector` instead of +`doubles` because `x1[i]` and `y1[i]` are of class `double`. When `x1` and `y1` +are of class `doubles`, `x1[i]` and `y1[i]` are proxy objects that represent +elements of `x1` and `y1` + +Passing proxies to `std::min()`, which returns a reference to its smallest +argument, creates an output that is a new proxy object that cannot be assigned +to `out[i]`. From 37132b37e9f9d2558a35b7145c9bc3071e7eda5d Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 24 Jan 2024 08:56:04 -0500 Subject: [PATCH 09/25] IMPORTANT ch24 now uses fixest bc speedglm fails with Golub matrices and corner cases --- 24_Improving_performance.qmd | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/24_Improving_performance.qmd b/24_Improving_performance.qmd index 8daf5424..5402c08b 100755 --- a/24_Improving_performance.qmd +++ b/24_Improving_performance.qmd @@ -1,14 +1,18 @@ +--- +bibliography: references.bib +--- + ```{r, include = FALSE} source("common.R") ``` -# Improving performance +# 24 - Improving performance {-} ## Checking for existing solutions __[Q1]{.Q}__: What are faster alternatives to `lm`? Which are specifically designed to work with larger datasets? -__[A]{.solved}__: The [CRAN task view for high-performance computing](https://cran.rstudio.com/web/views/HighPerformanceComputing.html) provides many recommendations. For this question, we are most interested in the section on "Large memory and out-of-memory data". We could for example give `biglm::biglm()` [@biglm], `speedglm::speedlm()` [@speedglm] or `RcppEigen::fastLm()` [@RcppEigen] a try. +__[A]{.solved}__: The [CRAN task view for high-performance computing](https://cran.rstudio.com/web/views/HighPerformanceComputing.html) provides many recommendations. For this question, we are most interested in the section on "Large memory and out-of-memory data". We could for example give `biglm::biglm()` [@biglm], `fixest::feols()` [@fixest] a try. For small datasets, we observe only minor performance gains (or even a small cost): @@ -24,11 +28,7 @@ bench::mark( body_mass_g ~ bill_length_mm + species, data = penguins ) %>% coef(), - "speedglm" = speedglm::speedlm( - body_mass_g ~ bill_length_mm + species, - data = penguins - ) %>% coef(), - "fastLm" = RcppEigen::fastLm( + "fixest" = fixest::feols( body_mass_g ~ bill_length_mm + species, data = penguins ) %>% coef() @@ -47,14 +47,13 @@ td <- data.frame(y = y, x1 = x1, x2 = x2, eps = eps) bench::mark( "lm" = lm(y ~ x1 + x2, data = td) %>% coef(), "biglm" = biglm::biglm(y ~ x1 + x2, data = td) %>% coef(), - "speedglm" = speedglm::speedlm(y ~ x1 + x2, data = td) %>% coef(), - "fastLm" = RcppEigen::fastLm(y ~ x1 + x2, data = td) %>% coef() + "fixest" = fixest::feols(y ~ x1 + x2, data = td) %>% coef() ) ``` -For further speed improvements, you could install a linear algebra library optimised for your system (see `?speedglm::speedlm`). +For further speed improvements, you could install a linear algebra library optimised for your system. -> The functions of class 'speedlm' may speed up the fitting of LMs to large datasets. High performances can be obtained especially if R is linked against an optimized BLAS, such as ATLAS. +> The functions of class 'feols' may speed up the fitting of LMs to large datasets. High performances can be obtained especially if R is linked against an optimized BLAS, such as ATLAS, Intel MKL, OpenBLAS, and others. Tip: In case your dataset is stored in a database, you might want to check out the [`{modeldb}` package](https://github.com/tidymodels/modeldb) [@modeldb] which executes the linear model code in the corresponding database backend. @@ -158,10 +157,6 @@ slider::slide_dbl(x, mean, .before = 1, .complete = TRUE) bench::mark( caTools = caTools::runmean(x, k = 2, endrule = "NA"), data.table = data.table::frollmean(x, 2), - RcppRoll = RcppRoll::roll_mean(x, - n = 2, fill = NA, - align = "right" - ), slider = slider::slide_dbl(x, mean, .before = 1, .complete = TRUE), TTR = TTR::SMA(x, 2), zoo_apply = zoo::rollapply(x, 2, mean, fill = NA, align = "right"), @@ -195,7 +190,6 @@ optimize(function(x) x^2 - 100 * x + 50, c(-1e20, 1e20)) For more general alternatives, the appropriate choice highly depends on the type of optimisation you intend to do. The [CRAN task view on optimisation and mathematical modelling](https://cran.r-project.org/web/views/Optimization.html) can serve as a useful reference. Here are a couple of examples: - `{optimx}` [@optimx1; @optimx2] extends the `optim()` function with the same syntax but more `method` choices. -- `{RcppNumerical}` [@RcppNumerical] wraps several open source libraries for numerical computing (written in C++) and integrates them with R via `{Rcpp}`. - `{DEoptim}` [@Deoptim] provides a global optimiser based on the Differential Evolution algorithm. ## Doing as little as possible @@ -389,3 +383,5 @@ weightedsum %>% ) + theme(legend.position = "top") ``` + +## References From 5b8957150ca4100021df7066b4ed4cabb4cc8a13 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 24 Jan 2024 10:32:22 -0500 Subject: [PATCH 10/25] chunk ch10_29 works in the HTML but not in the PDF --- 10_Function_factories.qmd | 69 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/10_Function_factories.qmd b/10_Function_factories.qmd index e96455a9..b8fa42d4 100755 --- a/10_Function_factories.qmd +++ b/10_Function_factories.qmd @@ -2,17 +2,17 @@ bibliography: references.bib --- -```{r, include = FALSE} +```{r ch10_01, include = FALSE} source("common.R") ``` -# Function factories +# 10 - Function factories {-} ## Prerequisites {-} For most of this chapter base R [@RLanguage] is sufficient. Just a few exercises require the `{rlang}` [@rlang], `{dplyr}` [@dplyr], `{purrr}` [@purrr] and `{ggplot2}` [@ggplot2] packages. -```{r, message = FALSE} +```{r ch10_02, message = FALSE} library(rlang) library(dplyr) library(purrr) @@ -23,7 +23,7 @@ library(ggplot2) __[Q1]{.Q}__: The definition of `force()` is simple: -```{r} +```{r ch10_03} force ``` @@ -39,7 +39,7 @@ __[A]{.solved}__: Let's begin with `approxfun()` as it is used within `ecdf()` a `approxfun()` takes a combination of data points (x and y values) as input and returns a stepwise linear (or constant) interpolation function. To find out what this means exactly, we first create a few random data points. -```{r} +```{r ch10_04} x <- runif(10) y <- runif(10) plot(x, y, lwd = 10) @@ -47,7 +47,7 @@ plot(x, y, lwd = 10) Next, we use `approxfun()` to construct the linear and constant interpolation functions for our `x` and `y` values. -```{r} +```{r ch10_05} f_lin <- approxfun(x, y) f_con <- approxfun(x, y, method = "constant") @@ -58,7 +58,7 @@ identical(f_con(x), y) When we apply these functions to new x values, these are mapped to the lines connecting the initial y values (linear case) or to the same y value as for the next smallest initial x value (constant case). -```{r} +```{r ch10_06} x_new <- runif(1000) plot(x, y, lwd = 10) @@ -68,7 +68,7 @@ points(x_new, f_con(x_new), col = "firebrick", pch = 16) However, both functions are only defined within `range(x)`. -```{r} +```{r ch10_07} f_lin(range(x)) f_con(range(x)) @@ -80,7 +80,7 @@ f_con(c(min(x) - eps, max(x) + eps)) To change this behaviour, one can set `rule = 2`. This leads to the result that for values outside of `range(x)` the boundary values of the function are returned. -```{r} +```{r ch10_08} f_lin <- approxfun(x, y, rule = 2) f_con <- approxfun(x, y, method = "constant", rule = 2) @@ -90,7 +90,7 @@ f_con(c(-Inf, Inf)) Another option is to customise the return values as individual constants for each side via `yleft` and/or `yright`. -```{r} +```{r ch10_09} f_lin <- approxfun(x, y, yleft = 5) f_con <- approxfun(x, y, method = "constant", yleft = 5, yright = -5) @@ -100,7 +100,7 @@ f_con(c(-Inf, Inf)) Further, `approxfun()` provides the option to shift the y values for `method = "constant"` between their left and right values. According to the documentation this indicates a compromise between left- and right-continuous steps. -```{r} +```{r ch10_10} f_con <- approxfun(x, y, method = "constant", f = .5) plot(x, y, lwd = 10) @@ -111,7 +111,7 @@ Finally, the `ties` argument allows to aggregate y values if multiple ones were Next, we focus on `ecdf()`. "ecdf" is an acronym for empirical cumulative distribution function. For a numeric vector of density values, `ecdf()` initially creates the (x, y) pairs for the nodes of the density function and then passes these pairs to `approxfun()`, which gets called with specifically adapted settings (`approxfun(vals, cumsum(tabulate(match(x, vals)))/n, method = "constant", yleft = 0, yright = 1, f = 0, ties = "ordered")`). -```{r} +```{r ch10_11} x <- runif(10) f_ecdf <- ecdf(x) class(f_ecdf) @@ -121,7 +121,7 @@ plot(x, f_ecdf(x), lwd = 10, ylim = 0:1) New values are then mapped on the y value of the next smallest x value from within the initial input. -```{r} +```{r ch10_12} x_new <- runif(1000) plot(x, f_ecdf(x), lwd = 10, ylim = 0:1) @@ -130,7 +130,7 @@ points(x_new, f_ecdf(x_new), ylim = 0:1) __[Q3]{.Q}__: Create a function `pick()` that takes an index, `i`, as an argument and returns a function with an argument `x` that subsets `x` with `i`. -```{r, eval = FALSE} +```{r ch10_13, eval = FALSE} pick(1)(x) # should be equivalent to x[[1]] @@ -142,7 +142,7 @@ lapply(mtcars, function(x) x[[5]]) __[A]{.solved}__: In this exercise `pick(i)` acts as a function factory, which returns the required subsetting function. -```{r} +```{r ch10_14} pick <- function(i) { force(i) @@ -159,7 +159,7 @@ identical( __[Q4]{.Q}__: Create a function that creates functions that compute the i^th^ [central moment](http://en.wikipedia.org/wiki/Central_moment) of a numeric vector. You can test it by running the following code: -```{r, eval = FALSE} +```{r ch10_15, eval = FALSE} m1 <- moment(1) m2 <- moment(2) @@ -170,7 +170,7 @@ stopifnot(all.equal(m2(x), var(x) * 99 / 100)) __[A]{.solved}__: The first moment is closely related to the mean and describes the average deviation from the mean, which is 0 (within numerical margin of error). The second moment describes the variance of the input data. If we want to compare it to `var()`, we need to undo [Bessel's correction](https://en.wikipedia.org/wiki/Bessel%27s_correction) by multiplying with $\frac{N-1}{N}$. -```{r} +```{r ch10_16} moment <- function(i) { force(i) @@ -187,7 +187,7 @@ all.equal(m2(x), var(x) * 99 / 100) __[Q5]{.Q}__: What happens if you don't use a closure? Make predictions, then verify with the code below. -```{r} +```{r ch10_17} i <- 0 new_counter2 <- function() { i <<- i + 1 @@ -197,7 +197,7 @@ new_counter2 <- function() { __[A]{.solved}__: Without the captured and encapsulated environment of a closure the counts will be stored in the global environment. Here they can be overwritten or deleted as well as interfere with other counters. -```{r, error = TRUE} +```{r ch10_18, error = TRUE} new_counter2() i new_counter2() @@ -210,7 +210,7 @@ i __[Q6]{.Q}__: What happens if you use `<-` instead of `<<-`? Make predictions, then verify with the code below. -```{r} +```{r ch10_19} new_counter3 <- function() { i <- 0 function() { @@ -222,7 +222,7 @@ new_counter3 <- function() { __[A]{.solved}__: Without the super assignment `<<-`, the counter will always return 1. The counter always starts in a new execution environment within the same enclosing environment, which contains an unchanged value for `i` (in this case it remains 0). -```{r} +```{r ch10_20} new_counter_3 <- new_counter3() new_counter_3() @@ -245,7 +245,7 @@ __[Q1]{.Q}__: In `boot_model()`, why don't I need to force the evaluation of `df __[A]{.solved}__: `boot_model()` ultimately returns a function, and whenever you return a function you need to make sure all the inputs are explicitly evaluated. Here that happens automatically because we use `df` and `formula` in `lm()` before returning the function. -```{r} +```{r ch10_21} boot_model <- function(df, formula) { mod <- lm(formula, data = df) fitted <- unname(fitted(mod)) @@ -260,7 +260,7 @@ boot_model <- function(df, formula) { __[Q2]{.Q}__: Why might you formulate the Box-Cox transformation like this? -```{r} +```{r ch10_22} boxcox3 <- function(x) { function(lambda) { if (lambda == 0) { @@ -274,7 +274,7 @@ boxcox3 <- function(x) { __[A]{.solved}__: `boxcox3()` returns a function where `x` is fixed (though it is not forced, so it may be manipulated later). This allows us to apply and test different transformations for different inputs and give them a descriptive name. -```{r, out.width = "49%", fig.show = "hold"} +```{r ch10_23, out.width = "49%", fig.show = "hold"} boxcox_airpassengers <- boxcox3(AirPassengers) plot(boxcox_airpassengers(0)) @@ -287,7 +287,7 @@ __[Q3]{.Q}__: Why don't you need to worry that `boot_permute()` stores a copy of __[A]{.solved}__: `boot_permute()` is defined in *Advanced R* as: -```{r} +```{r ch10_24} boot_permute <- function(df, var) { n <- nrow(df) force(var) @@ -301,7 +301,7 @@ boot_permute <- function(df, var) { We don't need to worry that it stores a copy of the data, because it actually doesn't store one; it's just a name that points to the same underlying object in memory. -```{r} +```{r ch10_25} boot_mtcars1 <- boot_permute(mtcars, "mpg") lobstr::obj_size(mtcars) @@ -313,7 +313,7 @@ __[Q4]{.Q}__: How much time does `ll_poisson2()` save compared to `ll_poisson1() __[A]{.solved}__: Let us recall the definitions of `ll_poisson1()`, `ll_poisson2()` and the test data `x1`: -```{r} +```{r ch10_26} ll_poisson1 <- function(x) { n <- length(x) @@ -337,7 +337,7 @@ x1 <- c(41, 30, 31, 38, 29, 24, 30, 29, 31, 38) A benchmark on `x1` reveals a performance improvement of factor 2 for `ll_poisson2()` over `ll_poisson1()`: -```{r} +```{r ch10_27} bench::mark( llp1 = optimise(ll_poisson1(x1), c(0, 100), maximum = TRUE), llp2 = optimise(ll_poisson2(x1), c(0, 100), maximum = TRUE) @@ -346,7 +346,7 @@ bench::mark( As the redundant calculations within `ll_poisson1()` become more expensive with growing length of `x1`, we expect even further relative performance improvements for `ll_poisson2()`. The following benchmark reveals a relative performance improvement of factor 20 for `ll_poisson2()` when `x1` is of length 100,000: -```{r, message = FALSE, warning = FALSE} +```{r ch10_28, message = FALSE, warning = FALSE} bench_poisson <- function(x_length) { x <- rpois(x_length, 100L) @@ -389,7 +389,8 @@ __[Q1]{.Q}__: Which of the following commands is equivalent to `with(x, f(z))`? __[A]{.solved}__: (e) "It depends" is the correct answer. Usually `with()` is used with a data frame, so you'd usually expect (b), but if `x` is a list, it could be any of the options. -```{r} +```{r ch10_29, eval = FALSE} +# TODO: This works in the HTML but not in the PDF f <- mean z <- 1 x <- list(f = mean, z = 1) @@ -402,7 +403,7 @@ identical(with(x, f(z)), f(z)) __[Q2]{.Q}__: Compare and contrast the effects of `env_bind()` vs. `attach()` for the following code. -```{r} +```{r ch10_30} funs <- list( mean = function(x) mean(x, na.rm = TRUE), sum = function(x) sum(x, na.rm = TRUE) @@ -419,7 +420,7 @@ env_unbind(globalenv(), names(funs)) __[A]{.solved}__: `attach()` adds `funs` to the search path. Therefore, the provided functions are found before their respective versions from the `{base}` package. Further, they cannot get accidentally overwritten by similar named functions in the global environment. One annoying downside of using `attach()` is the possibility to attach the same object multiple times, making it necessary to call `detach()` equally often. -```{r} +```{r ch10_31} attach(funs) attach(funs) @@ -430,7 +431,9 @@ detach(funs) In contrast `rlang::env_bind()` just adds the functions in `fun` to the global environment. No further side effects are introduced, and the functions are overwritten when similarly named functions are defined. -```{r} +```{r ch10_32} env_bind(globalenv(), !!!funs) head(search()) ``` + +## References From 98c9e4d9f3a895f5f44ff72f718a1cf46abc7f37 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 24 Jan 2024 10:36:44 -0500 Subject: [PATCH 11/25] chunk ch11_12 works in the HTML but not in the PDF --- 11_Function_operators.qmd | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/11_Function_operators.qmd b/11_Function_operators.qmd index 5bedcfd5..cb2c350d 100755 --- a/11_Function_operators.qmd +++ b/11_Function_operators.qmd @@ -1,18 +1,14 @@ ---- -bibliography: references.bib ---- - -```{r, include = FALSE} +```{r ch11_01, include = FALSE} source("common.R") ``` -# Function operators +# 11 - Function operators {-} ## Prerequisites {-} Also in the third chapter on functional programming, we make relatively frequent use of the {purrr} package. -```{r setup, message = FALSE} +```{r ch11_02, message = FALSE} library(purrr) ``` @@ -26,7 +22,7 @@ However, despite what the function's name implies, `Vectorize()` is not able to Let's take a look at an example from the documentation: -```{r, eval=FALSE} +```{r ch11_03, eval=FALSE} vrep <- Vectorize(rep.int) vrep #> function (x, times) @@ -45,12 +41,12 @@ vrep -```{r, include=FALSE} +```{r ch11_04, include=FALSE} vrep <- Vectorize(rep.int) vrep ``` -```{r} +```{r ch11_05} # Application vrep(1:2, 3:4) ``` @@ -63,7 +59,7 @@ __[A]{.solved}__: `possibly()` modifies functions to return a specified default While reading the source code, we notice that `possibly()` internally uses `purrr::as_mapper()`. This enables users to supply not only functions, but also formulas or atomics via the same syntax as known from other functions in the `{purrr}` package. Besides this, the new default value (`otherwise`) gets evaluated once to make it (almost) immutable. -```{r} +```{r ch11_06} possibly ``` @@ -75,7 +71,7 @@ __[A]{.solved}__: `safely()` modifies functions to return a list, containing the As the `tryCatch()` part is hidden in the internal `purrr:::capture_output()` function, we provide it here in addition to `safely()`: -```{r} +```{r ch11_07} safely purrr:::capture_error @@ -103,7 +99,7 @@ __[Q3]{.Q}__: Create a function operator that reports whenever a file is created __[A]{.solved}__: We start with a function that reports the difference between two vectors containing file names: -```{r} +```{r ch11_08} dir_compare <- function(old, new) { if (setequal(old, new)) { return() @@ -130,7 +126,7 @@ dir_compare(c("x", "y"), c("x", "a")) Then we wrap it up in a function operator -```{r} +```{r ch11_09} track_dir <- function(f) { force(f) function(...) { @@ -144,7 +140,7 @@ track_dir <- function(f) { And try it out by creating wrappers around `file.create()` and `file.remove()`: -```{r} +```{r ch11_10} file_create <- track_dir(file.create) file_remove <- track_dir(file.remove) @@ -165,7 +161,7 @@ __[Q4]{.Q}__: Write a function operator that logs a timestamp and message to a f __[A]{.solved}__: Our `logger()` function operator takes a function and a file path as input. One timestamp is written to the file under `log_path` when we call `logger()` and another timestamp is written to the same file each time the new function gets called. -```{r} +```{r ch11_11} append_line <- function(path, ...) { cat(..., "\n", sep = "", file = path, append = TRUE) } @@ -184,7 +180,8 @@ logger <- function(f, log_path) { Now, let's check if our `logger()` works as intended and apply it to the `mean()` function: -```{r} +```{r ch11_12} +# TODO: This works in the HTML but not in the PDF log_path <- tempfile() mean2 <- logger(mean, log_path) Sys.sleep(5) @@ -199,7 +196,7 @@ __[Q5]{.Q}__: Modify `delay_by()` so that instead of delaying by a fixed amount __[A]{.solved}__: `delay_by()` was defined in *Advanced R* as: -```{r} +```{r ch11_13} delay_by <- function(f, amount) { force(f) force(amount) @@ -213,7 +210,7 @@ delay_by <- function(f, amount) { To ensure that the function created by `delay_by()` waits that a certain amount of time has passed since its last execution, we incorporate three little changes into our new `delay_atleast()` as indicated in the corresponding comments below. -```{r, eval = FALSE} +```{r ch11_14, eval = FALSE} delay_atleast <- function(amount, f) { force(f) force(amount) From 4327390e91a746c31cd93147c8a0df76068bb9ed Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 24 Jan 2024 10:36:55 -0500 Subject: [PATCH 12/25] chunk ch11_12 works in the HTML but not in the PDF --- 11_Function_operators.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/11_Function_operators.qmd b/11_Function_operators.qmd index cb2c350d..008724d5 100755 --- a/11_Function_operators.qmd +++ b/11_Function_operators.qmd @@ -180,7 +180,7 @@ logger <- function(f, log_path) { Now, let's check if our `logger()` works as intended and apply it to the `mean()` function: -```{r ch11_12} +```{r ch11_12, eval = FALSE} # TODO: This works in the HTML but not in the PDF log_path <- tempfile() mean2 <- logger(mean, log_path) From d8f4e55065f0a24287ad78dc3476fab3dbd5949f Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 24 Jan 2024 11:26:36 -0500 Subject: [PATCH 13/25] chunk ch18_17 works in the HTML but not in the PDF --- 18_Expressions.qmd | 615 +++++++++++++++++++++ 18_Translating_R_code.qmd | 1079 ------------------------------------- 2 files changed, 615 insertions(+), 1079 deletions(-) create mode 100755 18_Expressions.qmd delete mode 100755 18_Translating_R_code.qmd diff --git a/18_Expressions.qmd b/18_Expressions.qmd new file mode 100755 index 00000000..f85cb5ad --- /dev/null +++ b/18_Expressions.qmd @@ -0,0 +1,615 @@ +--- +bibliography: references.bib +--- + +```{r ch18_01, include = FALSE} +source("common.R") +``` + +# 18 - Expressions {-} + +## Prerequisites {-} + +To capture and compute on expressions, and to visualise them, we will load the `{rlang}` [@rlang] and the `{lobstr}` [@lobstr] packages. + +```{r ch18_02, message = FALSE} +library(rlang) +library(lobstr) +``` + +## Abstract syntax trees + +__[Q1]{.Q}__: Reconstruct the code represented by the trees below: + +```{r ch18_03, echo = FALSE} +ast(f(g(h()))) + +ast(1 + 2 + 3) + +ast((x + y) * z) +``` + +__[A]{.solved}__: Let the source (of the code chunks above) be with you and show you how the ASTs (abstract syntax trees) were produced. + +```{r ch18_04} +ast(f(g(h()))) + +ast(1 + 2 + 3) + +ast((x + y) * z) +``` + +__[Q2]{.Q}__: Draw the following trees by hand then check your answers with `ast()`. + +```{r ch18_05, eval = FALSE} +f(g(h(i(1, 2, 3)))) +f(1, g(2, h(3, i()))) +f(g(1, 2), h(3, i(4, 5))) +``` + +__[A]{.solved}__: Let us delegate the drawing to the `{lobstr}` package. + +```{r ch18_06} +ast(f(g(h(i(1, 2, 3))))) + +ast(f(1, g(2, h(3, i())))) + +ast(f(g(1, 2), h(3, i(4, 5)))) +``` + +__[Q3]{.Q}__: What's happening with the ASTs below? (Hint: carefully read `?"^"`) + +```{r ch18_07} +ast(`x` + `y`) +ast(x**y) +ast(1 -> x) +``` + +__[A]{.solved}__: ASTs start function calls with the name of the function. This is why the call in the first expression is translated into its prefix form. In the second case, `**` is translated by R's parser into `^`. In the last AST, the expression is flipped when R parses it: + +```{r ch18_08} +str(expr(x**y)) +str(expr(a -> b)) +``` + +__[Q4]{.Q}__: What is special about the AST below? (Hint: re-read section [6.2.1](https://adv-r.hadley.nz/functions.html#fun-components)) + +```{r ch18_09} +ast(function(x = 1, y = 2) {}) +``` + +__[A]{.solved}__: The last leaf of the AST is not explicitly specified in the expression. Instead, the `srcref` attribute, which points to the functions source code, is automatically created by base R. + +__[Q5]{.Q}__: What does the call tree of an `if` statement with multiple `else if` conditions look like? Why? + +__[A]{.solved}__: The AST of nested `else if` statements might look a bit confusing because it contains multiple curly braces. However, we can see that in the `else` part of the AST just another expression is being evaluated, which happens to be an `if` statement and so forth. + +```{r ch18_10} +ast( + if (FALSE) { + 1 + } else if (FALSE) { + 2 + } else if (TRUE) { + 3 + } +) +``` + +We can see the structure more clearly if we avoid the curly braces: + +```{r ch18_11} +ast( + if (FALSE) { + 1 + } else if (FALSE) { + 2 + } else if (TRUE) 3 +) +``` + +## Expressions + +__[Q1]{.Q}__: Which two of the six types of atomic vector can't appear in an expression? Why? Similarly, why can't you create an expression that contains an atomic vector of length greater than one? + +__[A]{.solved}__: There is no way to create raws and complex atomics without using a function call (this is only possible for imaginary scalars like `i`, `5i` etc.). But expressions that include a function are *calls*. Therefore, both of these vector types cannot appear in an expression. + +Similarly, it is not possible to create an expression that evaluates to an atomic of length greater than one without using a function (e.g. `c()`). + +Let's make this observation concrete via an example: + +```{r ch18_12} +# Atomic +is_atomic(expr(1)) + +# Not an atomic (although it would evaluate to an atomic) +is_atomic(expr(c(1, 1))) +is_call(expr(c(1, 1))) +``` + +__[Q2]{.Q}__: What happens when you subset a call object to remove the first element, e.g. `expr(read.csv("foo.csv", header = TRUE))[-1]`. Why? + +__[A]{.solved}__: When the first element of a call object is removed, the second element moves to the first position, which is the function to call. Therefore, we get `"foo.csv"(header = TRUE)`. + +__[Q3]{.Q}__: Describe the differences between the following call objects. + +```{r ch18_13, results = FALSE} +x <- 1:10 + +call2(median, x, na.rm = TRUE) +call2(expr(median), x, na.rm = TRUE) +call2(median, expr(x), na.rm = TRUE) +call2(expr(median), expr(x), na.rm = TRUE) +``` + +__[A]{.solved}__: The call objects differ in their first two elements, which are in some cases evaluated before the call is constructed. In the first one, both `median()` and `x` are evaluated and inlined into the call. Therefore, we can see in the constructed call that median is a generic and the `x` argument is 1:10. + +```{r ch18_14} +call2(median, x, na.rm = TRUE) +``` + +In the following calls we remain with differing combinations. Once, only `x` and once only `median()` gets evaluated. + +```{r ch18_15} +call2(expr(median), x, na.rm = TRUE) +call2(median, expr(x), na.rm = TRUE) +``` + +In the final call neither `x` nor `median()` is evaluated. + +```{r ch18_16} +call2(expr(median), expr(x), na.rm = TRUE) +``` + +Note that all these calls will generate the same result when evaluated. The key difference is when the values bound to the `x` and `median` symbols are found. + +__[Q4]{.Q}__: `rlang::call_standardise()` doesn't work so well for the following calls. +Why? What makes `mean()` special? + +```{r ch18_17, eval = FALSE} +# TODO: This works in the HTML but not in the PDF +call_standardise(quote(mean(1:10, na.rm = TRUE))) +call_standardise(quote(mean(n = T, 1:10))) +call_standardise(quote(mean(x = 1:10, , TRUE))) +``` + +__[A]{.solved}__: The reason for this unexpected behaviour is that `mean()` uses the `...` argument and therefore cannot standardise the regarding arguments. Since `mean()` uses S3 dispatch (i.e. `UseMethod()`) and the underlying `mean.default()` method specifies some more arguments, `call_standardise()` can do much better with a specific S3 method. + +```{r ch18_18} +call_standardise(quote(mean.default(1:10, na.rm = TRUE))) +call_standardise(quote(mean.default(n = T, 1:10))) +call_standardise(quote(mean.default(x = 1:10, , TRUE))) +``` + +__[Q5]{.Q}__: Why does this code not make sense? + +```{r ch18_19, eval = FALSE} +x <- expr(foo(x = 1)) +names(x) <- c("x", "") +``` + +__[A]{.solved}__: As stated in *Advanced R* + +> The first element of a call is always the function that gets called. + +Let's see what happens when we run the code + +```{r ch18_20} +x <- expr(foo(x = 1)) +x + +names(x) <- c("x", "") +x + +names(x) <- c("", "x") +x +``` + +So, giving the first element a name just adds metadata that R ignores. + +__[Q6]{.Q}__: Construct the expression `if(x > 1) "a" else "b"` using multiple calls to `call2()`. How does the code structure reflect the structure of the AST? + +__[A]{.solved}__: Similar to the prefix version we get + +```{r ch18_21} +call2("if", call2(">", sym("x"), 1), "a", "b") +``` + +When we read the AST from left to right, we get the same structure: Function to evaluate, expression, which is another function and is evaluated first, and two constants which will be evaluated next. + +```{r ch18_22} +ast(`if`(x > 1, "a", "b")) +``` + +## Parsing and grammar + +__[Q1]{.Q}__: R uses parentheses in two slightly different ways as illustrated by these two calls: + +```{r ch18_23, eval = FALSE} +f((1)) +`(`(1 + 1) +``` + +Compare and contrast the two uses by referencing the AST. + +__[A]{.solved}__: The trick with these examples lies in the fact that `(` can be a part of R's general prefix function syntax but can also represent a call to the `(` function. + +So, in the AST of the first example, we will not see the outer `(` since it is prefix function syntax and belongs to `f()`. In contrast, the inner `(` is a function (represented as a symbol in the AST): + +```{r ch18_24} +ast(f((1))) +``` + +In the second example, we can see that the outer `(` is a function and the inner `(` belongs to its syntax: + +```{r ch18_25} +ast(`(`(1 + 1)) +``` + +For the sake of clarity, let's also create a third example, where none of the `(` is part of another function's syntax: + +```{r ch18_26} +ast(((1 + 1))) +``` + +__[Q2]{.Q}__: `=` can also be used in two ways. Construct a simple example that shows both uses. + +__[A]{.solved}__: `=` is used both for assignment, and for naming arguments in function calls: + +```{r ch18_27} +b <- c(c = 1) +``` + +So, when we play with `ast()`, we can directly see that the following is not possible: + +```{r ch18_28, error = TRUE} +ast(b = c(c = 1)) +``` + +We get an error because `b = ` makes R looking for an argument called `b`. Since `x` is the only argument of `ast()`, we get an error. + +The easiest way around this problem is to wrap this line in `{}`. + +```{r ch18_29} +ast({ + b <- c(c = 1) +}) +``` + +When we ignore the braces and compare the trees, we can see that the first `=` is used for assignment and the second `=` is part of the syntax of function calls. + +__[Q3]{.Q}__: Does `-2^2` yield 4 or -4? Why? + +__[A]{.solved}__: It yields `-4`, because `^` has a higher operator precedence than `-`, which we can verify by looking at the AST (or looking it up under `?"Syntax"`): + +```{r ch18_30} +-2^2 + +ast(-2^2) +``` + +__[Q4]{.Q}__: What does `!1 + !1` return? Why? + +__[A]{.solved}__: The answer is a little surprising: + +```{r ch18_31} +!1 + !1 +``` + +To answer the "why?", we take a look at the AST: + +```{r ch18_32} +ast(!1 + !1) +``` + +The right `!1` is evaluated first. It evaluates to `FALSE`, because R coerces every non 0 numeric to `TRUE`, when a logical operator is applied. The negation of `TRUE` then equals `FALSE`. + +Next `1 + FALSE` is evaluated to `1`, since `FALSE` is coerced to `0`. + +Finally `!1` is evaluated to `FALSE`. + +Note that if `!` had a higher precedence, the intermediate result would be `FALSE + FALSE`, which would evaluate to `0`. + +__[Q5]{.Q}__: Why does `x1 <- x2 <- x3 <- 0` work? Describe the two reasons. + +__[A]{.solved}__: One reason is that `<-` is right-associative, i.e. evaluation takes place from right to left: + +```{r ch18_33} +x1 <- (x2 <- (x3 <- 0)) +``` + +The other reason is that `<-` invisibly returns the value on the right-hand side. + +```{r ch18_34} +(x3 <- 0) +``` + +__[Q6]{.Q}__: Compare the ASTs of `x + y %+% z` and `x ^ y %+% z`. What have you learned about the precedence of custom infix functions? + +__[A]{.solved}__: Let's take a look at the syntax trees: + +```{r ch18_35} +ast(x + y %+% z) +``` + +Here `y %+% z` will be calculated first and the result will be added to `x`. + +```{r ch18_36} +ast(x^y %+% z) +``` + +Here `x ^ y` will be calculated first, and the result will be used as first argument to `%+%()`. + +We can conclude that custom infix functions have precedence between addition and exponentiation. + +The exact precedence of infix functions can be looked up under `?"Syntax"` where we see that it lies directly behind the sequence operator (`:`) and in front of the multiplication and division operators (`*` and `/`). + +__[Q7]{.Q}__: What happens if you call `parse_expr()` with a string that generates multiple expressions, e.g. `parse_expr("x + 1; y + 1")`? + +__[A]{.solved}__: In this case `parse_expr()` notices that more than one expression would have to be generated and throws an error. + +```{r ch18_37, error = TRUE} +parse_expr("x + 1; y + 1") +``` + +__[Q8]{.Q}__: What happens if you attempt to parse an invalid expression, e.g. `"a +"` or `"f())"`? + +__[A]{.solved}__: Invalid expressions will lead to an error in the underlying `parse()` function. + +```{r ch18_38, error = TRUE} +parse_expr("a +") +parse_expr("f())") + +parse(text = "a +") +parse(text = "f())") +``` + +__[Q9]{.Q}__: `deparse()` produces vectors when the input is long. For example, the following call produces a vector of length two: + +```{r ch18_39, eval = FALSE} +expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + + n + o + p + q + r + s + t + u + v + w + x + y + z)) + +deparse(expr) +``` + +What does `expr_text()` do instead? + +__[A]{.solved}__: `expr_text()` will paste the results from `deparse(expr)` together and use a linebreak (`\n`) as separator. + +```{r ch18_40, eval = FALSE} +expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m + + n + o + p + q + r + s + t + u + v + w + x + y + z)) +deparse(expr) +#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n + " +#> [2] "o + p + q + r + s + t + u + v + w + x + y + z)" +expr_text(expr) +#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n +#> + \n o + p + q + r + s + t + u + v + w + x + y + z)" +``` + +__[Q10]{.Q}__: `pairwise.t.test()` assumes that `deparse()` always returns a length one character vector. Can you construct an input that violates this expectation? What happens? + +__[A]{.solved}__: The function `pairwise.t.test()` captures its data arguments (`x` and `g`) so it can print the input expressions along the computed p-values. Prior to R 4.0.0 this used to be implemented via `deparse(substitute(x))` in combination with `paste()`. This could lead to unexpected output, if one of the inputs exceeded the default `width.cutoff` value of 60 characters within `deparse()`. In this case, the expression would be split into a character vector of length greater 1. + +```{r ch18_41, eval = FALSE} +# Output in R version 3.6.2 +d <- 1 +pairwise.t.test(2, d + d + d + d + d + d + d + d + + d + d + d + d + d + d + d + d + d) +#> Pairwise comparisons using t tests with pooled SD +#> +#> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d +#> + d + d + 2 and d +#> +#> <0 x 0 matrix> +#> +#> P value adjustment method: holm +``` + +In [R 4.0.0](https://cran.r-project.org/doc/manuals/r-release/NEWS.html) `pairwise.t.test()` was updated to use the newly introduced `deparse1()`, which serves as a wrapper around `deparse()`. + +> deparse1() is a simple utility added in R 4.0.0 to ensure a string result (character vector of length one), typically used in name construction, as deparse1(substitute(.)). + +```{r ch18_42, eval = FALSE} +# Output since R 4.0.0 +d <- 1 +pairwise.t.test(2, d + d + d + d + d + d + d + d + + d + d + d + d + d + d + d + d + d) +#> Pairwise comparisons using t tests with pooled SD +#> +#> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d +#> + d + d + d +#> +#> <0 x 0 matrix> +#> +#> P value adjustment method: holm +``` + +## Walking AST with recursive functions {#ast-funs} + +__[Q1]{.Q}__: `logical_abbr()` returns `TRUE` for `T(1, 2, 3)`. How could you modify `logical_abbr_rec()` so that it ignores function calls that use `T` or `F`? + +__[A]{.solved}__: We can apply a similar logic as in the [assignment example](https://adv-r.hadley.nz/expressions.html#finding-all-variables-created-by-assignment) from *Advanced R*. We just treat it as a special case handled within a sub function called `find_T_call()`, which finds `T()` calls and "bounces them out". Therefore, we also repeat the `expr_type()` helper which tells us if we are in the base or in the recursive case. + +```{r ch18_43} +expr_type <- function(x) { + if (rlang::is_syntactic_literal(x)) { + "constant" + } else if (is.symbol(x)) { + "symbol" + } else if (is.call(x)) { + "call" + } else if (is.pairlist(x)) { + "pairlist" + } else { + typeof(x) + } +} + +switch_expr <- function(x, ...) { + switch(expr_type(x), + ..., + stop("Don't know how to handle type ", + typeof(x), + call. = FALSE + ) + ) +} +``` + +```{r ch18_44} +find_T_call <- function(x) { + if (is_call(x, "T")) { + x <- as.list(x)[-1] + purrr::some(x, logical_abbr_rec) + } else { + purrr::some(x, logical_abbr_rec) + } +} + +logical_abbr_rec <- function(x) { + switch_expr( + x, + # Base cases + constant = FALSE, + symbol = as_string(x) %in% c("F", "T"), + + # Recursive cases + pairlist = purrr::some(x, logical_abbr_rec), + call = find_T_call(x) + ) +} + +logical_abbr <- function(x) { + logical_abbr_rec(enexpr(x)) +} +``` + +Now let's test our new `logical_abbr()` function: + +```{r ch18_45} +logical_abbr(T(1, 2, 3)) +logical_abbr(T(T, T(3, 4))) +logical_abbr(T(T)) +logical_abbr(T()) +logical_abbr() +logical_abbr(c(T, T, T)) +``` + +__[Q2]{.Q}__: `logical_abbr()` works with expressions. It currently fails when you give it a function. Why? How could you modify `logical_abbr()` to make it work? What components of a function will you need to recurse over? + +```{r ch18_46, eval = TRUE} +f <- function(x = TRUE) { + g(x + T) +} +``` + +__[A]{.solved}__: The function currently fails, because `"closure"` is not handled in `switch_expr()` within `logical_abbr_rec()`. + +```{r ch18_47, error = TRUE} +logical_abbr(!!f) +``` + +If we want to make it work, we have to write a function to also iterate over the formals and the body of the input function. + +__[Q3]{.Q}__: Modify `find_assign` to also detect assignment using replacement functions, i.e. `names(x) <- y`. + +__[A]{.solved}__: Let's see what the AST of such an assignment looks like: + +```{r ch18_48} +ast(names(x) <- x) +``` + +So, we need to catch the case where the first two elements are both calls. Further the first call is identical to `<-` and we must return only the second call to see which objects got new values assigned. + +This is why we add the following block within another `else` statement in `find_assign_call()`: + +```{r ch18_49, eval = FALSE} +if (is_call(x, "<-") && is_call(x[[2]])) { + lhs <- expr_text(x[[2]]) + children <- as.list(x)[-1] +} +``` + +Let us finish with the whole code, followed by some tests for our new function: + +```{r ch18_50} +flat_map_chr <- function(.x, .f, ...) { + purrr::flatten_chr(purrr::map(.x, .f, ...)) +} + +find_assign <- function(x) unique(find_assign_rec(enexpr(x))) + +find_assign_call <- function(x) { + if (is_call(x, "<-") && is_symbol(x[[2]])) { + lhs <- as_string(x[[2]]) + children <- as.list(x)[-1] + } else { + if (is_call(x, "<-") && is_call(x[[2]])) { + lhs <- expr_text(x[[2]]) + children <- as.list(x)[-1] + } else { + lhs <- character() + children <- as.list(x) + } + } + + c(lhs, flat_map_chr(children, find_assign_rec)) +} + +find_assign_rec <- function(x) { + switch_expr( + x, + # Base cases + constant = , symbol = character(), + # Recursive cases + pairlist = flat_map_chr(x, find_assign_rec), + call = find_assign_call(x) + ) +} + +# Tests functionality +find_assign(x <- y) +find_assign(names(x)) +find_assign(names(x) <- y) +find_assign(names(x(y)) <- y) +find_assign(names(x(y)) <- y <- z) +``` + +__[Q4]{.Q}__: Write a function that extracts all calls to a specified function. + +__[A]{.solved}__: Here we need to delete the previously added else statement and check for a call (not necessarily `<-`) within the first `if()` in `find_assign_call()`. We save a call when we found one and return it later as part of our character output. Everything else stays the same: + +```{r ch18_51} +find_assign_call <- function(x) { + if (is_call(x)) { + lhs <- expr_text(x) + children <- as.list(x)[-1] + } else { + lhs <- character() + children <- as.list(x) + } + + c(lhs, flat_map_chr(children, find_assign_rec)) +} + +find_assign_rec <- function(x) { + switch_expr( + x, + # Base cases + constant = , + symbol = character(), + + # Recursive cases + pairlist = flat_map_chr(x, find_assign_rec), + call = find_assign_call(x) + ) +} + +find_assign(x <- y) +find_assign(names(x(y)) <- y <- z) +find_assign(mean(sum(1:3))) +``` + +## References diff --git a/18_Translating_R_code.qmd b/18_Translating_R_code.qmd deleted file mode 100755 index d486b19f..00000000 --- a/18_Translating_R_code.qmd +++ /dev/null @@ -1,1079 +0,0 @@ -```{r, include = FALSE} -source("common.R") -``` - -# Translating R code - -## Prerequisites {-} - -In this chapter we combine R's metaprogramming and functional programming capabilities and therefore load both the `{rlang}` and the `{purrr}` package. - -```{r setup, message = FALSE} -library(rlang) -library(purrr) -``` - -## HTML - -__[Q1]{.Q}__: The escaping rules for `` so that the tag isn't closed too early. For example, `script("''")`, shouldn't generate this: - -```{html} -' -``` - -But - -```{html} - -``` - -Adapt the `escape()` to follow these rules when a new argument `script` is set to `TRUE`. - -__[A]{.solved}__: We are asked to implement a special case of escaping for the ` and ") %>% - as.character(), - paste("") -) -``` - -We implement the desired change and add the optional argument `script` to the `escape()` and the `tag()` functions (default: `script = FALSE`). The argument has to be added for all methods of the `escape()` generic. - -```{r} -escape <- function(x, script = FALSE) UseMethod("escape") - -escape.character <- function(x, script = FALSE) { - - if (script) { - x <- gsub("", "<\\/script>", x, fixed = TRUE) - x <- gsub("", "<\\/style>", x, fixed = TRUE) - } else { - x <- gsub("&", "&", x) - x <- gsub("<", "<", x) - x <- gsub(">", ">", x) - } - - html(x) -} - -escape.advr_html <- function(x, script = FALSE) x - - -tag <- function(tag, script = FALSE) { - - new_function( - exprs(... = ), - expr({ - dots <- dots_partition(...) - attribs <- html_attributes(dots$named) - children <- map_chr(dots$unnamed, escape, script = !!script) - html(paste0( - !!paste0("<", tag), attribs, ">", - paste(children, collapse = ""), - !!paste0("") - )) - }), - caller_env() - ) -} -``` - -Finally, we create new `

`, `` and ` and ") %>% - as.character(), - paste("") -) - -script("Don't escape &, <, > - escape and ") -``` - -__[Q2]{.Q}__: The use of `...` for all functions has some big downsides. There's no input validation and there will be little information in the documentation or autocomplete about how they are used in the function. Create a new function that, when given a named list of tags and their attribute names (like below), creates tag functions with named arguments. - -```{r, eval = FALSE} -list( - a = c("href"), - img = c("src", "width", "height") -) -``` - -All tags should get `class` and `id` attributes. - -__[A]{.solved}__: This exercise requires a function factory: The named list of attribute names will be extended (by `class` and `id`) and mapped to function arguments. These will default to `NULL`, so that the user isn't forced to provide them. - -When creating the tag functions itself we use `check_dots_unnamed()` from the `{ellipsis}` package to ensure named arguments correspond to the expected values (and are not created by some spelling mistake). After that we follow the logic from the `tag()` function factory above. - -To keep the focus on the key ideas, we ignore special cases like `` so that the tag isn't closed too early. For example, `script("''")`, shouldn't generate this: + +```{html} +' +``` + +But + +```{html} + +``` + +Adapt the `escape()` to follow these rules when a new argument `script` is set to `TRUE`. + +__[A]{.solved}__: We are asked to implement a special case of escaping for the ` and ") %>% + as.character(), + paste( + "" + ) +) +``` + +We implement the desired change and add the optional argument `script` to the `escape()` and the `tag()` functions (default: `script = FALSE`). The argument has to be added for all methods of the `escape()` generic. + +```{r} +escape <- function(x, script = FALSE) UseMethod("escape") + +escape.character <- function(x, script = FALSE) { + if (script) { + x <- gsub("", "<\\/script>", x, fixed = TRUE) + x <- gsub("", "<\\/style>", x, fixed = TRUE) + } else { + x <- gsub("&", "&", x) + x <- gsub("<", "<", x) + x <- gsub(">", ">", x) + } + + html(x) +} + +escape.advr_html <- function(x, script = FALSE) x + + +tag <- function(tag, script = FALSE) { + new_function( + exprs(... = ), + expr({ + dots <- dots_partition(...) + attribs <- html_attributes(dots$named) + children <- map_chr(dots$unnamed, escape, script = !!script) + html(paste0( + !!paste0("<", tag), attribs, ">", + paste(children, collapse = ""), + !!paste0("") + )) + }), + caller_env() + ) +} +``` + +Finally, we create new `

`, `` and ` and ") %>% + as.character(), + paste( + "" + ) +) + +script("Don't escape &, <, > - escape and ") +``` + +__[Q2]{.Q}__: The use of `...` for all functions has some big downsides. There's no input validation and there will be little information in the documentation or autocomplete about how they are used in the function. Create a new function that, when given a named list of tags and their attribute names (like below), creates tag functions with named arguments. + +```{r, eval = FALSE} +list( + a = c("href"), + img = c("src", "width", "height") +) +``` + +All tags should get `class` and `id` attributes. + +__[A]{.solved}__: This exercise requires a function factory: The named list of attribute names will be extended (by `class` and `id`) and mapped to function arguments. These will default to `NULL`, so that the user isn't forced to provide them. + +When creating the tag functions itself we use `check_dots_unnamed()` from the `{ellipsis}` package to ensure named arguments correspond to the expected values (and are not created by some spelling mistake). After that we follow the logic from the `tag()` function factory above. + +To keep the focus on the key ideas, we ignore special cases like ` + + + + + + + + + + + + + + + + + + + + + + + + +

+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Preface

+
+ + + +
+ + + + +
+ + +
+ +

Welcome to Advanced R Solutions!

+

This book provides worked-out solutions to the exercises given in Advanced R (Wickham 2019) and reflects our efforts to understand and acquire its content.

+

Advanced R covers R (R Core Team 2020) and programming. It presents the specific characteristics of the R language to programmers and helps R users to improve their understanding of general programming concepts.

+

When we came across Advanced R, it gave us a more thorough understanding of the R code we worked with daily and helped us to see the underlying principles more clearly. The content helped us to get a more complete picture of R’s programming landscape.

+

We soon re-discovered that reading about programming is not enough and that it helps greatly to open the editor and write some code along the way. The clear structure of Advanced R and the exercises given provided a great starting point for this.

+

We think of this book as a solutions manual, which intends to supplement and support your own study of the R language through Advanced R. We hope that it will help you to stay on track and allow you to check your understanding and progress along the way. The solutions may also give you another perspective on some of the presented material.

+
+

How this book came to be

+

The solutions in this book are written from our personal perspective and current level of understanding. We both came from mathematics and statistics backgrounds preparing us more carefully for data analysis than for programming. So, we were R users first and improved as programmers in our day jobs and through working on projects like this one.

+

By taking advantage of the {bookdown} package (Xie 2016) to structure our process, we created this book almost as a by-product. While the initial progress was fun and motivating, actually providing solutions to all of the 284 exercises took slightly longer than originally expected (and Hadley’s rewrite of Advanced R halfway in between didn’t really make the journey shorter).

+

As the project matured, we strived to provide solutions that were as clean, straightforward, and expressive as possible. As well-written code is often more expressive than lengthy explanations, many of the solutions are rather code heavy. The written explanations aim to provide context and motivation, discuss important implementation details, or relate to the practical work of being an R programmer.

+

Hadley Wickham wrote Advanced R and created the exercises which form the substructure of this book. We took the task to solve them as correctly and idiomatically as possible. When we finished a chapter, we asked Hadley to review it. His feedback included many comments (which we then had to resolve), corrections, and suggestions, as well as a few complete solutions. We repeated this process until each exercise was reviewed and approved. As a result, we feel pretty good about the quality of the solutions in the book. However, any remaining mistakes or inconsistencies are certainly on us.

+
+
+

How to use this book

+

Since this book builds so heavily on Advanced R, we think it should be read together with the textbook, either as a hardcopy or the online version (https://adv-r.hadley.nz). Working on an exercise first by yourself should in general give you the biggest benefit.

+

It may be a good idea to start with the parts of Advanced R that are most relevant to your work and interest. You can certainly read the book cover to cover, but we think that you don’t have to, though it’s probably a good idea to start with the foundations part.

+

Of the more difficult exercises in the book, only a few were completed in one go. Often we had to reread the question or look up the related content in Advanced R and started by writing a few lines of code first or consulting the documentation. Reading the source code (preferably with syntax highlighting) and searching the web were typically quite helpful.

+

To support your study, you may also be interested in the R4DS Advanced R book club, where groups of readers regularly discuss a different chapter of Advanced R.

+

In case you want to do more or have a special interest in the mechanics of base R, you may be interested in checking out the first edition of Advanced R (http://adv-r.had.co.nz/) (Wickham 2014). Some additional solutions related to that edition can be found at https://advanced-r-solutions-ed1.netlify.app/.

+

There is one recommendation from Advanced R that we’d like to echo: reading source code can be tremendously helpful in developing your programming skill! For example, you can just head to GitHub and start looking into the source code of packages you love and developers you admire. While reading, it’s not necessary to understand every line of code right away. Keeping this a regular practice (for a while) will expose you to many new ideas, patterns, and design choices, and also expand your R vocabulary.

+

We don’t necessarily apply many of the concepts taught in Advanced R in daily programming and that’s okay! But we hope that the code we write has become more robust, expressive, and readable, and it’s actually quite easy to see the progress when we take a look at the earlier drafts of our own code.

+
+
+

Acknowledgements

+

Many open source projects are the result of the work of a lot of people; so is this. We would like to explicitly mention and thank everybody who contributed solutions, raised questions, or helped to fix spelling and grammar to improve this work:

+

@3zhang, Leon Kim (@BetweenTwoTests), @Charles926, Corrado Lanera (@CorradoLanera), @Elucidase, @HannesOberreiter, @MajoroMask, Maya Gans (@MayaGans), Anne (@ahoffrichter), Anh N Tran (@anhtr), Arash (@arashHaratian), Jun Cai (@caijun), Safouane Chergui (@chsafouane), @davidblitz, Zhuoer Dong (@dongzhuoer), Fabian Scheipl (@fabian-s), @its-gazza, Jorge Aranda (@jorgearanda), @lotgon, Øystein Sørensen (@osorensen), Peter Hurford (@peterhurford), @philyoun, PJ (@pieterjanvc), Robert Krzyzanowski (@robertzk), Emily Robinson (@robinsones), Tanner Stauss (@tmstauss), @trannhatanh89, and Yihui Xie (@yihui).

+

Tobias Stalder (@toeb18) designed the beautiful cover, which visualizes the structure of Advanced R and its exercises.

+

Thanks to CRC Press for the interest in the project and our editor, Rob Calver, and his assistant, Vaishali Singh, for their patience and support in making this book a reality.

+

Thanks to our managers and companies for granting us some flexibility with our work schedules and generally supporting the completion of this project.

+
+
+

Conventions

+

A brief overview of conventions we followed and decisions we made.

+
    +
  • Some chapters and sections in Advanced R do not contain exercises. In our book you will see that we skipped these chapters and sections. This decision introduces some gaps in the numbering, but we feel that keeping the numbers in sync with those of Advanced R will provide the most practical value.
  • +
  • We strived to follow mostly the tidyverse style guide. The {styler} package (Müller and Walthert 2020) helped us to check many of the rules automatically.
  • +
  • Each chapter of this book was rendered in a separate R session via the {bookdown} package. We configured this process to initially: +
      +
    • set `%>%` <- magrittr::`%>%` to unlock the pipe operator without specifically loading the {magrittr} package (Bache and Wickham 2020) every time,
    • +
    • set a random seed (1014) to improve reproducibility (similar as in Advanced R), and
    • +
    • define a few {ggplot2} and {knitr} options.
    • +
    +You can check out the exact code on GitHub.
  • +
  • We chose to keep the code in this book as self-contained as possible. +
      +
    • The packages used are usually loaded in the beginning of each chapter.
    • +
    • We repeat all code from Advanced R that is necessary to work on an exercise but not explicitly part of the exercise. When some longer code passages (from Advanced R) are omitted, this is explicitly stated in the solution.
    • +
  • +
  • The printed version of the book was rendered with R version 4.0.3 (2020-10-10) and the most recent available package versions as of December 2020. (The print version of Advanced R was rendered with R version 3.5.2.)
  • +
  • Emoji images in the printed book come from the open-licensed Twitter Emoji.
  • +
  • Benchmarks are computed when the book is rendered. While this improves reproducibility, the exact results will depend on the system creating the document.
  • +
+
+
+

Closing remarks

+

We are so happy to finish this exciting project that in fact neither of us really had the time for. We probably wouldn’t have made it to the finish line if we hadn’t worked on it together.

+

Collaboration is powerful and it’s fun to build and share. The various backgrounds represented in the R community generally make this exchange much more interesting and meaningful. Much of this success is possible because R is free software. At least in theory, everyone can contribute and no one can take away your freedom to do so.

+

The automated systems we build using these tools are not neutral and the rapid adoption of data-driven processes in business and technology does clearly affect our everyday lives and societies. It’s important that everyone has a fair say in the discussions about these systems and participates in their design. Against this background, we chose to donate half of our royalties from this book to https://rladies.org/, an organization empowering minority genders in the R community.

+

Thank you for your interest in this project and we hope the solutions will be of value to you.

+

See you around!

+

Malte Grosser @malte_grosser

+

Henning Bumann @henningsway

+

Mauricio Vargas Sepulveda m.sepulveda@mail.utoronto.ca

+
+
+

References

+ + +
+
+Bache, Stefan Milton, and Hadley Wickham. 2020. Magrittr: A Forward-Pipe Operator for R. http://magrittr.tidyverse.org/. +
+
+Müller, Kirill, and Lorenz Walthert. 2020. Styler: Non-Invasive Pretty Printing of R Code. http://styler.r-lib.org. +
+
+R Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/. +
+
+Wickham, Hadley. 2014. Advanced R. First. Boca Raton, Florida: Chapman; Hall/CRC. http://adv-r.had.co.nz/. +
+
+———. 2019. Advanced R. Second. Boca Raton, Florida: Chapman; Hall/CRC. https://adv-r.hadley.nz/. +
+
+Xie, Yihui. 2016. Bookdown: Authoring Books and Technical Documents with R Markdown. Boca Raton, Florida: Chapman; Hall/CRC. https://github.com/rstudio/bookdown. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/00_03_Abstracts.html b/docs/00_03_Abstracts.html new file mode 100644 index 00000000..a1e23e91 --- /dev/null +++ b/docs/00_03_Abstracts.html @@ -0,0 +1,723 @@ + + + + + + + + + + +Advanced R Solutions - Chapter abstracts + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Chapter abstracts

+
+ + + +
+ + + + +
+ + +
+ +
+

2. Names and values

+

The second chapter explains the distinction between an object and its name. This distinction is important, as it helps:

+
    +
  • More accurately predicting the performance and memory usage of R code.
  • +
  • Writeing faster code by avoiding accidental copies, a major source of slow code.
  • +
  • Better understanding R’s functional programming tools.
  • +
+

In section “Binding basics”, we introduce the distinction between names and values, and how bindings, or references, between a name and a value are created. Then, in “Copy-on-modify”, we learn when R makes a copy and how to use tracemem to figure out when a copy actually occurs. We also learn about the implications for different R objects. In “Object size” we explore how much memory an object occupies. “Modify-in-place” describes two exceptions to copy-on-modify: environments and values with a single name are actually modified in place. Lastly, we conclude this chapter with a discussion of the garbage collector, in “Unbinding and the garbage collector”.

+
+
+

3. Vectors

+

The third chapter discusses the most important family of data types in base R: vectors. It won’t cover individual vector types in too much detail, but it will show how all the types fit together as a whole.

+

Vectors come in two flavours: atomic vectors and lists. We start with “Atomic vectors”, which are R’s simplest data structures. For atomic vectors, all elements must have the same type. Then, we take a small detour to discuss “Attributes”, R’s flexible metadata specification. “S3 atomic vectors” discusses the important vector types that are built by combining atomic vectors with special attributes. These include factors, dates, date-times, and durations. Next, we dive into “Lists”. Lists are very similar to atomic vectors. However, an element of a list can be any data type, including another list. This makes them suitable for representing hierarchical data. “Data frames and tibbles” teaches you about data frames and tibbles, which are used to represent rectangular data. They combine the behaviour of lists and matrices to make a structure ideally suited for the needs of statistical data. To finish up this chapter, we briefly talk about one final important data structure that’s closely related to vectors: “NULL”.

+
+
+

4. Subsetting

+

In chapter 4 we discuss R’s fast and powerful subsetting operators. Mastering them allows you to succinctly perform complex operations in a way that few other languages can match. Subsetting in R is easy to learn but hard to master because you need to internalise a number of interrelated concepts.

+

“Selecting multiple elements” starts by teaching you about [. You’ll learn the six ways to subset atomic vectors. You’ll then learn how those six ways act when used to subset lists, matrices, and data frames. “Selecting a single element” expands your knowledge of subsetting operators to include [[ and $ and focuses on the important principles of simplifying versus preserving. “Applications” leads you through eight important, but not obvious, applications of subsetting to solve problems that you often encounter in data analysis.

+
+
+

5. Control Flow

+

In chapter 5 you’ll learn about the two primary tools of control flow: choices and loops. Choices, like if statements and switch() calls, allow you to run different code depending on the input. Loops, like for and while, allow you to repeatedly run code, typically with changing options.

+

We’d expect that you’re already familiar with the basics of these functions so we’ll briefly cover some technical details and then introduce some useful, but lesser known, features. The condition system (messages, warnings, and errors), which you’ll learn about in Chapter 8, also provides non-local control flow.

+

In “Choices” we dive into the details of the if statement, and then discuss the close relatives ifelse() and switch(). “Loops” starts off by reminding you of the basic structure of the for loop in R, discusses some common pitfalls, and then talks about the related while and repeat statements.

+
+
+

6. Functions

+

In chapter 6, you’ll learn how to turn your informal, working knowledge about functions into more rigorous, theoretical understanding. The tricks and techniques you will learn along the way will be important for understanding the more advanced topics discussed later in the book.

+

“Function fundamentals” describes the basics of creating a function, the three main components of a function, and the exception to many function rules: primitive functions (which are implemented in C, not R). “Lexical scoping” shows you how R finds the value associated with a given name, i.e. the rules of lexical scoping. “Lazy evaluation” is devoted to an important property of function arguments: they are only evaluated when used for the first time. “… (dot-dot-dot)” discusses the special … argument, which allows you to pass on extra arguments to another function. “Exiting a function” discusses the two primary ways that a function can exit, and how to define an exit handler, code that is run on exit, regardless of what triggers it. “Function forms” shows you the various ways in which R disguises ordinary function calls, and how you can use the standard prefix form to better understand what’s going on.

+
+
+

7. Environments

+

In chapter 7 you will learn about environments, the data structure that powers scoping. This chapter dives deep into environments, describing their structure in depth, and using them to improve your understanding of the four scoping rules described in the “Lexical scoping” section of the functions chapter. Understanding environments is not necessary for day-to-day use of R. But they are important to understand because they power many important R features like lexical scoping, namespaces, and R6 classes, and interact with evaluation to give you powerful tools for making domain specific languages, like dplyr and ggplot2.

+

“Environment basics” introduces you to the basic properties of an environment and shows you how to create your own. “Recursing over environments” provides a function template for computing with environments, illustrating the idea with a useful function. “Special environments” describes environments used for special purposes: for packages, within functions, for namespaces, and for function execution. “Call stacks” explains the last important environment: the caller environment. This requires you to learn about the call stack, that describes how a function was called. You’ll have seen the call stack if you’ve ever called traceback() to aid debugging. “As data structures” briefly discusses three places where environments are useful data structures for solving other problems.

+
+
+

8. Conditions

+

In chapter 8 we will discuss R’s condition system, which provides a paired set of tools that allow the author of a function to indicate that something unusual is happening, and the user of that function to deal with it. The function author signals conditions with functions like stop(), warning(), and message(), then the function user can handle them with functions like tryCatch() and withCallingHandlers(). Understanding the condition system is important because you’ll often need to play both roles: signalling conditions from the functions you create, and handle conditions signalled by the functions you call.

+

R’s condition system is based on ideas from Common Lisp. Like R’s approach to object-oriented programming, it is rather different to currently popular programming languages so it is easy to misunderstand, and there has been relatively little written about how to use it effectively. Historically, this has meant that few people have taken full advantage of its power. The goal of this chapter is to remedy that situation. Here you will learn about the big ideas of R’s condition system, as well as learning a bunch of practical tools that will make your code stronger.

+

“Signalling conditions” introduces the basic tools for signalling conditions, and discusses when it is appropriate to use each type. “Handling conditions” introduces the condition object, and the two fundamental tools of condition handling: tryCatch() for error conditions, and withCallingHandlers() for everything else. “Custom conditions” shows you how to extend the built-in condition objects to store useful data that condition handlers can use to make more informed decisions. “Applications” closes out the chapter with a grab bag of practical applications based on the low-level tools found in earlier sections.

+
+
+

9. Functionals

+

In chapter 9 we’ll learn about functionals. A functional is a function that takes a function as an input and returns a vector as output. A common use of functionals is as an alternative to for loops. As Loops do not convey what should be done with the results, it’s better to use a functional. Each functional is tailored for a specific task, so when you recognise the functional you immediately know why it’s being used.

+

“My first functional: map()” introduces your first functional: purrr::map(). “Map variants” teaches you about 18 (!!) important variants of purrr::map(). Fortunately, their orthogonal design makes them easy to learn, remember, and master. “Predicate functionals” teaches you about predicates: functions that return a single TRUE or FALSE, and the family of functionals that use them to solve common problems. “Base functionals” reviews some functionals in base R that are not members of the map, reduce, or predicate families.

+
+
+

10. Function factories

+

In chapter 10 we’ll discuss function factories. A function factory is a function that makes functions.

+

Of the three main functional programming tools (functionals, function factories, and function operators), function factories are the least used. Generally, they don’t tend to reduce overall code complexity but instead partition complexity into more easily digested chunks. Function factories are also an important building block for the very useful function operators, which you’ll learn about in Chapter 11 (“Function operators”).

+

“Factory fundamentals” begins the chapter with an explanation of how function factories work, pulling together ideas from scoping and environments. You’ll also see how function factories can be used to implement a memory for functions, allowing data to persist across calls. “Graphical factories” illustrates the use of function factories with examples from ggplot2. You’ll see two examples of how ggplot2 works with user supplied function factories, and one example of where ggplot2 uses a function factory internally. “Statistical factories” uses function factories to tackle three challenges from statistics: understanding the Box-Cox transform, solving maximum likelihood problems, and drawing bootstrap resamples. “Function factories + functionals” shows how you can combine function factories and functionals to rapidly generate a family of functions from data.

+
+
+

11. Function operators

+

In chapter 11, you’ll learn about function operators. A function operator is a function that takes one (or more) functions as input and returns a function as output.

+

Function operators are closely related to function factories; indeed they’re just a function factory that takes a function as input. Like factories, there’s nothing you can’t do without them, but they often allow you to factor out complexity in order to make your code more readable and reusable. Function operators are typically paired with functionals. If you’re using a for-loop, there’s rarely a reason to use a function operator, as it will make your code more complex for little gain. If you’re familiar with Python, decorators is just another name for function operators.

+

“Existing function operators” introduces you to two extremely useful existing function operators, and shows you how to use them to solve real problems. “Case study: Creating your own function operators” works through a problem amenable to solution with function operators: downloading many web pages.

+
+
+

13. S3

+

In chapter 13 we’ll learn about R’s first and simplest OO system: S3. S3 is informal and ad hoc, but there is a certain elegance in its minimalism: you can’t take away any part of it and still have a useful OO system. For these reasons, you should use it, unless you have a compelling reason to do otherwise. S3 is the only OO system used in the base and stats packages, and it’s the most commonly used system in CRAN packages.

+

“Basics” gives a rapid overview of all the main components of S3: classes, generics, and methods. You’ll also learn about sloop::s3_dispatch(), which we’ll use throughout the chapter to explore how S3 works. Then, “Classes” goes into the details of creating a new S3 class, including the three functions that should accompany most classes: a constructor, a helper, and a validator. Further, “Generics and methods” describes how S3 generics and methods work, including the basics of method dispatch. “Object styles” discusses the four main styles of S3 objects: vector, record, data frame, and scalar. “Inheritance” demonstrates how inheritance works in S3, and shows you what you need to make a class “subclassable”. “Dispatch details” concludes the chapter with a discussion of the finer details of method dispatch including base types, internal generics, group generics, and double dispatch.

+
+
+

14. R6

+

Chapter 14 describes the R6 OOP system which is more like OOP in other languages. It uses the encapsulated OOP paradigm, which means that methods belong to objects, not generics, and you call them like object$method(). Also, R6 objects are mutable, which means that they are modified in place, and hence have reference semantics.

+

If you’ve learned OOP in another programming language, it’s likely that R6 will feel very natural, and you’ll be inclined to prefer it over S3. Resist the temptation to follow the path of least resistance: in most cases R6 will lead you to non-idiomatic R code.

+

“Classes and methods” introduces R6::R6Class(), the one function that you need to know to create R6 classes. You’ll learn about the constructor method, $new(), which allows you to create R6 objects, as well as other important methods like $initialize() and $print(). “Controlling access” discusses the access mechanisms of R6: private and active fields. Together, these allow you to hide data from the user, or expose private data for reading but not writing. “Reference semantics” explores the consequences of R6’s reference semantics. You’ll learn about the use of finalizers to automatically clean up any operations performed in the initializer, and a common gotcha if you use an R6 object as a field in another R6 object. “Why R6?” describes why we cover R6, rather than the base RC system.

+
+
+

15. S4

+

In chapter 15 we’ll learn about the S4 OO system, which provides a formal approach to functional OOP. The underlying ideas are similar to S3, but the implementation is much stricter and makes use of specialised functions for creating classes (setClass()), generics (setGeneric()), and methods (setMethod()). Additionally, S4 provides both multiple inheritance (i.e. a class can have multiple parents) and multiple dispatch (i.e. method dispatch can use the class of multiple arguments).

+

An important new component of S4 is the slot, a named component of the object that is accessed using the specialised subsetting operator @ (pronounced at). The set of slots, and their classes, forms an important part of the definition of an S4 class.

+

“Basics” gives a quick overview of the main components of S4: classes, generics, and methods. “Classes” dives into the details of S4 classes, including prototypes, constructors, helpers, and validators. “Generics and methods” shows you how to create new S4 generics, and how to supply those generics with methods. You’ll also learn about accessor functions which are designed to allow users to safely inspect and modify object slots. “Method dispatch” dives into the full details of method dispatch in S4. The basic idea is simple, then it rapidly gets more complex once multiple inheritance and multiple dispatch are combined. “S4 and S3” discusses the interaction between S4 and S3, showing you how to use them together.

+
+
+

18. Expressions

+

The focus of chapter 18 chapter are the data structures that underlie expressions. Mastering this knowledge will allow you to inspect and modify captured code, and to generate code with code. We’ll come back to expr() in Chapter 19 (“Quasiquotation”), and to eval() in Chapter 20 (“Evaluation”).

+

“Abstract syntax trees” introduces the idea of the abstract syntax tree (AST), and reveals the tree like structure that underlies all R code. “Expressions” dives into the details of the data structures that underpin the AST: constants, symbols, and calls, which are collectively known as expressions. “Parsing and grammar” covers parsing, the act of converting the linear sequence of character in code into the AST, and uses that idea to explore some details of R’s grammar. “Walking AST with recursive functions” shows you how you can use recursive functions to compute on the language, writing functions that compute with expressions. “Specialised data structures” circles back to three more specialised data structures: pairlists, missing arguments, and expression vectors.

+
+
+

19. Quasiquotation

+

In chapter 19 you will learn about quasiquotation. Quasiquotation is one of the three pillars of tidy evaluation. You’ll learn about the other two (quosures and the data mask) in Chapter 20 (“Evaluation”). When used alone, quasiquotation is most useful for programming, particularly for generating code. But when it’s combined with the other techniques, tidy evaluation becomes a powerful tool for data analysis.

+

“Motivation” motivates the development of quasiquotation with a function, cement(), that works like paste() but automatically quotes its arguments so that you don’t have to. “Quoting” gives you the tools to quote expressions, whether they come from you or the user, or whether you use rlang or base R tools. “Unquoting” introduces the biggest difference between rlang quoting functions and base quoting function: unquoting with !! and !!!. “… (dot-dot-dot)” explores another place that you can use !!!, functions that take …. It also introduces the special := operator, which allows you to dynamically change argument names. “Case studies” shows a few practical uses of quoting to solve problems that naturally require some code generation.

+
+
+

20. Evaluation

+

Chapter 20 discusses the topic evaluation. The user-facing inverse of quotation is unquotation: it gives the user the ability to selectively evaluate parts of an otherwise quoted argument. The developer-facing complement of quotation is evaluation: this gives the developer the ability to evaluate quoted expressions in custom environments to achieve specific goals.

+

“Evaluation basics” discusses the basics of evaluation using eval(), and shows how you can use it to implement key functions like local() and source(). “Quosures” introduces a new data structure, the quosure, which combines an expression with an environment. You’ll learn how to capture quosures from promises, and evaluate them using rlang::eval_tidy(). “Data masks” extends evaluation with the data mask, which makes it trivial to intermingle symbols bound in an environment with variables found in a data frame. “Using tidy evaluation” shows how to use tidy evaluation in practice, focussing on the common pattern of quoting and unquoting, and how to handle ambiguity with pronouns. “Base evaluation” circles back to evaluation in base R, discusses some of the downsides, and shows how to use quasiquotation and evaluation to wrap functions that use NSE.

+
+
+

21. Translating R code

+

Chapter 20 discusses the creation of domain specific languages. The combination of first-class environments, lexical scoping, and metaprogramming gives us a powerful toolkit for translating R code into other languages. One fully-fledged example of this idea is dbplyr, which powers the database backends for dplyr, allowing you to express data manipulation in R and automatically translate it into SQL. You can see the key idea in translate_sql() which takes R code and returns the equivalent SQL.

+

Translating R to SQL is complex because of the many idiosyncrasies of SQL dialects, so here I’ll develop two simple, but useful, domain specific languages (DSL): one to generate HTML, and the other to generate mathematical equations in LaTeX.

+

In “HTML” we create a DSL for generating HTML, using quasiquotation and purrr to generate a function for each HTML tag, then tidy evaluation to easily access them. In “LaTeX” we transform mathematically R code into its LaTeX equivalent using a combination of tidy evaluation and expression walking.

+
+
+

23. Measuring performance

+

In chapter 23 we learn about measuring performance.

+

Before you can make your code faster, you first need to figure out what’s making it slow. This sounds easy, but it’s not. Even experienced programmers have a hard time identifying bottlenecks in their code. So instead of relying on your intuition, you should profile your code: measure the run-time of each line of code using realistic inputs.

+

Once you’ve identified bottlenecks you’ll need to carefully experiment with alternatives to find faster code that is still equivalent. In Chapter 24 (“Improving performance”) you’ll learn a bunch of ways to speed up code, but first you need to learn how to microbenchmark so that you can precisely measure the difference in performance.

+

“Profiling” shows you how to use profiling tools to dig into exactly what is making code slow. Section “Microbenchmarking” shows how to use microbenchmarking to explore alternative implementations and figure out exactly which one is fastest.

+
+
+

24. Improving performance

+

Chapter 24 teaches how to improve performance. Once you’ve used profiling to identify a bottleneck, you need to make it faster. It’s difficult to provide general advice on improving performance, but in this chapter we’ll see four techniques that can be applied in many situations and also a general strategy for performance optimisation that helps ensure that your faster code is still correct. Also it is easy to get caught up in trying to remove all bottlenecks. Don’t! Be pragmatic: don’t spend hours of your time to save seconds of computer time.

+

“Checking for existing solutions” reminds you to look for existing solutions. “Doing as little as possible” emphasises the importance of being lazy: often the easiest way to make a function faster is to let it to do less work. “Vectorise” concisely defines vectorisation, and shows you how to make the most of built-in functions. “Avoiding copies” discusses the performance perils of copying data. “Case study: t-test” pulls all the pieces together into a case study showing how to speed up repeated t-tests by about a thousand times. “Other techniques” finishes the chapter with pointers to more resources that will help you write fast code.

+
+
+

25. Rewriting R code in C++

+

Chapter 25 shows how to improve the performance by rewriting R code in C++ via the cpp11 package.

+

cpp11 simplifies connecting R and C++. While it is possible to write C or Fortran code for use in R, it will be more challenging by comparison. cpp11 provides a clean, approachable API that lets you write high-performance code, that makes interfacing with R’s C API and C++ code safer.

+

Typical bottlenecks that C++ can address include:

+
    +
  • Loops that cannot be easily vectorised because subsequent iterations depend on previous ones.
  • +
  • Recursive functions, or problems which involve calling functions millions of times. The overhead of calling a function in C++ is much lower than in R.
  • +
  • Problems that require advanced data structures and algorithms that R does not provide. Through the standard template library (STL), C++ has efficient implementations of many important data structures, from ordered maps to double-ended queues.
  • +
+

“Getting started with C++” teaches you how to write C++ by converting simple R functions to their C++ equivalents. You’ll learn how C++ differs from R, and how strings and numbers are translated between languages. “Missing values” teaches you how to work with R’s missing values in C++. “Standard Template Library” shows you how to use some of the most important data structures and algorithms from the standard template library, or STL, built-in to C++.

+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/02_Names_and_values.html b/docs/02_Names_and_values.html new file mode 100644 index 00000000..bf743d15 --- /dev/null +++ b/docs/02_Names_and_values.html @@ -0,0 +1,1109 @@ + + + + + + + + + + +Advanced R Solutions - 2 - Names and values + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

2 - Names and values

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

In this chapter we will use the {lobstr} package (Wickham 2019) to help answer questions regarding the internal representation of R objects.

+
+
library(lobstr)
+
+
+
+

Binding basics

+

Q1: Explain the relationship between a, b, c, and d in the following code:

+
+
a <- 1:10
+b <- a
+c <- b
+d <- 1:10
+
+

A: a, b, and c point to the same object (with the same address in memory). This object has the value 1:10. d points to a different object with the same value.

+
+
list_of_names <- list(a, b, c, d)
+obj_addrs(list_of_names)
+#> [1] "0x579852a52008" "0x579852a52008" "0x579852a52008" "0x579852b9b088"
+
+

Q2: The following code accesses the mean function in multiple ways. Do they all point to the same underlying function object? Verify this with lobstr::obj_addr().

+
+
mean
+base::mean
+get("mean")
+evalq(mean)
+match.fun("mean")
+
+

A: Yes, they point to the same object. We confirm this by inspecting the address of the underlying function object.

+
+
mean_functions <- list(
+  mean,
+  base::mean,
+  get("mean"),
+  evalq(mean),
+  match.fun("mean")
+)
+
+unique(obj_addrs(mean_functions))
+#> [1] "0x5798501620b8"
+
+

Q3: By default, base R data import functions, like read.csv(), will automatically convert non-syntactic names to syntactic ones. Why might this be problematic? What option allows you to suppress this behaviour?

+

A: Column names are often data, and the underlying make.names() transformation is non-invertible, so the default behaviour corrupts data. To avoid this, set check.names = FALSE.

+

Q4: What rules does make.names() use to convert non-syntactic names into syntactic ones?

+

A: A valid name must start with a letter or a dot (not followed by a number) and may further contain numbers and underscores ("_"s are allowed since R version 1.9.0).

+

Three main mechanisms ensure syntactically valid names (see ?make.names):

+
    +
  1. Names that do not start with a letter or a dot will be prepended with an "X".

    +

    ::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-7_f6ccd6953d5a91424d54eb5b450943a0’}

    +
    make.names("") # prepending "x"
    +#> [1] "X"
    +

    :::

    +

    The same holds for names that begin with a dot followed by a number.

    +

    ::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-8_3c866f40ef56f4f8e63bf8e89559c7e8’}

    +
    make.names(".1") # prepending "X"
    +#> [1] "X.1"
    +

    :::

  2. +
  3. Additionally, non-valid characters are replaced by a dot.

    +

    ::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-9_860c452c7c7ee11fe572d39a98a28b68’}

    +
    make.names("non-valid") # "." replacement
    +#> [1] "non.valid"
    +make.names("@") # prepending "X" + "." replacement
    +#> [1] "X."
    +make.names("  R") # prepending "X" + ".." replacement
    +#> [1] "X..R"
    +

    :::

  4. +
  5. Reserved R keywords (see ?reserved) are suffixed by a dot.

    +

    ::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-10_424c337c3ffcfb23561e4b66ebfe240a’}

    +
    make.names("if") # "." suffix
    +#> [1] "if."
    +

    :::

  6. +
+

Interestingly, some of these transformations are influenced by the current locale. From ?make.names:

+
+

The definition of a letter depends on the current locale, but only ASCII digits are considered to be digits.

+
+

Q5: I slightly simplified the rules that govern syntactic names. Why is .123e1 not a syntactic name? Read ?make.names for the full details.

+

A: .123e1 is not a syntactic name, because it starts with one dot which is followed by a number. This makes it a double, 1.23.

+
+
+

Copy-on-modify

+

Q1: Why is tracemem(1:10) not useful?

+

A: When 1:10 is called an object with an address in memory is created, but it is not bound to a name. Therefore, the object cannot be called or manipulated from R. As no copies will be made, it is not useful to track the object for copying.

+
+
obj_addr(1:10) # the object exists, but has no name
+#> [1] "0x5798525d5010"
+
+

Q2: Explain why tracemem() shows two copies when you run this code. Hint: carefully look at the difference between this code and the code shown earlier in the section.

+
+
x <- c(1L, 2L, 3L)
+tracemem(x)
+
+x[[3]] <- 4
+
+

A: Initially the vector x has integer type. The replacement call assigns a double to the third element of x, which triggers copy-on-modify.

+
+
x <- c(1L, 2L, 3L)
+tracemem(x)
+#> <0x66a4a70>
+
+x[[3]] <- 4
+#> tracemem[0x55eec7b3af38 -> 0x55eec774cc18]:
+
+

We can avoid the copy by sub-assigning an integer instead of a double:

+
+
x <- c(1L, 2L, 3L)
+tracemem(x)
+#> <0x55eec6940ae0>
+
+x[[3]] <- 4L
+
+

Please be aware that running this code in RStudio will result in additional copies because of the reference from the environment pane.

+

Q3: Sketch out the relationship between the following objects:

+
+
a <- 1:10
+b <- list(a, a)
+c <- list(b, a, 1:10)
+
+

A: a contains a reference to an address with the value 1:10. b contains a list of two references to the same address as a. c contains a list of b (containing two references to a), a (containing the same reference again) and a reference pointing to a different address containing the same value (1:10).

+
+
+
+
+

+
+
+
+
+

We can confirm these relationships by inspecting the reference tree in R.

+
+
ref(c)
+#> █ [1:0x55erc93cbdd8] <list>    # c
+#> ├─█ [2:0x55efcb8246e8] <list>  # - b
+#> │ ├─[3:0x55eac7df4e98] <int>   # -- a
+#> │ └─[3:0x55eac7df4e98]         # -- a
+#> ├─[3:0x55eac7df4e98]           # - a
+#> └─[4:0x55etc7aa6968] <int>     # - 1:10
+
+

Q4: What happens when you run this code:

+
+
x <- list(1:10)
+x[[2]] <- x
+
+

Draw a picture.

+

A: The initial reference tree of x shows that the name x binds to a list object. This object contains a reference to the integer vector 1:10.

+
+
x <- list(1:10)
+
+ref(x)
+#> █ [1:0x55853b74ff40] <list>
+#> └─[2:0x534t3abffad8] <int>
+
+
+
+
+
+

+
+
+
+
+

When x is assigned to an element of itself, copy-on-modify takes place and the list is copied to a new address in memory.

+
+
tracemem(x)
+x[[2]] <- x
+#> tracemem[0x55853b74ff40 -> 0x5d553bacdcd8]:
+
+

The list object previously bound to x is now referenced in the newly created list object. It is no longer bound to a name. The integer vector is referenced twice.

+
+
ref(x)
+#> █ [1:0x5d553bacdcd8] <list>
+#> ├─[2:0x534t3abffad8] <int>
+#> └─█ [3:0x55853b74ff40] <list>
+#>   └─[2:0x534t3abffad8]
+
+
+
+
+
+

+
+
+
+
+
+
+

Object size

+ +

Q1: In the following example, why are object.size(y) and obj_size(y) so radically different? Consult the documentation of object.size().

+
+
y <- rep(list(runif(1e4)), 100)
+
+object.size(y)
+#> 8005648 bytes
+obj_size(y)
+#> 80.90 kB
+
+

A: object.size() doesn’t account for shared elements within lists. Therefore, the results differ by a factor of ~ 100.

+

Q2: Take the following list. Why is its size somewhat misleading?

+
+
funs <- list(mean, sd, var)
+obj_size(funs)
+#> 17.55 kB
+
+

A: All three functions are built-in to R as part of the {base} and {stats} packages and hence always available. So, what does it mean to measure the size of something that’s already included in R?

+

(There’s typically a more general question about what you want to know when you ask for the size of something — do you want to know how much data you’d need to send to communicate the object to someone else (e.g. serialise it), or do you want to know how much memory you’d free if you deleted it?)

+

Let us look for how many other objects this applies to as well.

+

The following packages are usually loaded by default.

+
+
base_pkgs <- c(
+  "package:stats", "package:graphics", "package:grDevices",
+  "package:utils", "package:datasets", "package:methods",
+  "package:base"
+)
+
+

To look up all functions from these packages we iterate over base_pkgs and apply ls() and mget() within each iteration.

+
+
base_objs <- base_pkgs %>%
+  lapply(as.environment) %>%
+  lapply(function(x) mget(ls(x, all.names = TRUE), x)) %>%
+  setNames(base_pkgs)
+
+

This gives us more than 2700 objects which are usually available by default.

+
+
sum(lengths(base_objs))
+#> [1] 2776
+
+# We can also show the sizes in MB per package
+vapply(base_objs, obj_size, double(1)) / 1024^2
+#>     package:stats  package:graphics package:grDevices     package:utils 
+#>            11.150             3.114             2.315             7.283 
+#>  package:datasets   package:methods      package:base 
+#>             0.558            13.962            21.310
+
+# Check if we've over-counted
+as.numeric(obj_size(!!!base_objs)) / 1024^2
+#> [1] 57.9
+
+

Q3: Predict the output of the following code:

+
+
a <- runif(1e6)
+obj_size(a)
+
+b <- list(a, a)
+obj_size(b)
+obj_size(a, b)
+
+b[[1]][[1]] <- 10
+obj_size(b)
+obj_size(a, b)
+
+b[[2]][[1]] <- 10
+obj_size(b)
+obj_size(a, b)
+
+

A: In R (on most platforms) a length-0 vector has 48 bytes of overhead.

+
+
obj_size(list())
+#> 48 B
+obj_size(double())
+#> 48 B
+obj_size(character())
+#> 48 B
+
+

A single double takes up an additional 8 bytes of memory.

+
+
obj_size(double(1))
+#> 56 B
+obj_size(double(2))
+#> 64 B
+
+

So, a 1 million double should take up 8,000,048 bytes.

+
+
a <- runif(1e6)
+obj_size(a)
+#> 8.00 MB
+
+

(If you look carefully at the amount of memory occupied by short vectors, you will notice that the pattern is actually more complicated. This has to do with how R allocates memory and is not that important. If you want to know the full details, they’re discussed in the 1st edition of Advanced R: http://adv-r.had.co.nz/memory.html#object-size).

+

For b <- list(a, a) both list elements contain references to the same memory address.

+
+
b <- list(a, a)
+ref(a, b)
+#> [1:0x579859a76fc0] <dbl> 
+#>  
+#> █ [2:0x579852b66208] <list> 
+#> ├─[1:0x579859a76fc0] 
+#> └─[1:0x579859a76fc0]
+
+

Therefore, no additional memory is required for the second list element. The list itself requires 64 bytes, 48 bytes for an empty list and 8 bytes for each element (obj_size(vector("list", 2))). This lets us predict 8,000,048 B + 64 B = 8,000,112 B.

+
+
obj_size(b)
+#> 8.00 MB
+
+

When we modify the first element of b[[1]] copy-on-modify occurs. Both elements will still have the same size (8,000,040 B), but the first one gets a new address in memory. As b’s elements don’t share references anymore, its object size adds up to the sum of the elements and the length-2 list: 8,000,048 B + 8,000,048 B + 64 B = 16,000,160 B (16 MB).

+
+
b[[1]][[1]] <- 10
+obj_size(b)
+#> 16.00 MB
+
+

The second element of b still references the same address as a, so the combined size of a and b is the same as b.

+
+
obj_size(a, b)
+#> 16.00 MB
+ref(a, b)
+#> [1:0x579859a76fc0] <dbl> 
+#>  
+#> █ [2:0x5798587d8828] <list> 
+#> ├─[3:0x57985cdf4fa0] <dbl> 
+#> └─[1:0x579859a76fc0]
+
+

When we modify the second element of b, this element will also point to a new memory address. This does not affect the size of the list.

+
+
b[[2]][[1]] <- 10
+obj_size(b)
+#> 16.00 MB
+
+

However, as b doesn’t share references with a anymore, the memory usage of the combined objects increases.

+
+
ref(a, b)
+#> [1:0x579859a76fc0] <dbl> 
+#>  
+#> █ [2:0x579858188b58] <list> 
+#> ├─[3:0x57985cdf4fa0] <dbl> 
+#> └─[4:0x57985af6c830] <dbl>
+obj_size(a, b)
+#> 24.00 MB
+
+
+
+

Modify-in-place

+ +

Q1: Explain why the following code doesn’t create a circular list.

+
+
x <- list()
+x[[1]] <- x
+
+

A: In this situation copy-on-modify prevents the creation of a circular list. Let us step through the details:

+
+
x <- list() # creates initial object
+obj_addr(x)
+#> [1] "0x55862f23ab80"
+
+tracemem(x)
+#> [1] "<0x55862f23ab80>"
+x[[1]] <- x # Copy-on-modify triggers new copy
+#> tracemem[0x55862f23ab80 -> 0x55862e8ce028]:
+
+obj_addr(x) # copied object has new memory address
+#> [1] "0x55862e8ce028"
+obj_addr(x[[1]]) # list element contains old memory address
+#> [1] "0x55862f23ab80"
+
+

Q2: Wrap the two methods for subtracting medians into two functions, then use the {bench} package to carefully compare their speeds. How does performance change as the number of columns increase?

+

A: First, we define a function to create some random data.

+
+
create_random_df <- function(nrow, ncol) {
+  random_matrix <- matrix(runif(nrow * ncol), nrow = nrow)
+  as.data.frame(random_matrix)
+}
+
+create_random_df(2, 2)
+#>      V1     V2
+#> 1 0.972 0.0116
+#> 2 0.849 0.4339
+
+

Next, we wrap the two approaches to subtract numerical values (in our case medians) from each column of a data frame in their own function. We name these functions depending on whether the approach operates on a data frame or a list. For a fairer comparison, the second function also contains the overhead code to convert between data frame and list objects.

+
+
subtract_df <- function(x, medians) {
+  for (i in seq_along(medians)) {
+    x[[i]] <- x[[i]] - medians[[i]]
+  }
+  x
+}
+
+subtract_list <- function(x, medians) {
+  x <- as.list(x)
+  x <- subtract_df(x, medians)
+  list2DF(x)
+}
+
+

This lets us profile the performance, via benchmarks on data frames with differing numbers of columns. Therefore, we create a small helper that creates our random data frame and its medians before it benchmarks the two approaches by employing the {bench} package (Hester 2020).

+
+
benchmark_medians <- function(ncol) {
+  df <- create_random_df(nrow = 1e4, ncol = ncol)
+  medians <- vapply(df, median, numeric(1), USE.NAMES = FALSE)
+
+  bench::mark(
+    "data frame" = subtract_df(df, medians),
+    "list" = subtract_list(df, medians),
+    time_unit = "ms"
+  )
+}
+
+benchmark_medians(1)
+#> # A tibble: 2 × 6
+#>   expression    min median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>  <dbl>  <dbl>     <dbl> <bch:byt>    <dbl>
+#> 1 data frame 0.0130 0.0149    60947.    99.1KB     61.0
+#> 2 list       0.0124 0.0141    65028.    78.2KB     65.1
+
+

The bench::press() function allows us to run our helper across a grid of parameters. We will use it to slowly increase the number of data frame columns in our benchmark.

+
+
results <- bench::press(
+  ncol = c(1, 10, 50, 100, 250, 300, 400, 500, 750, 1000),
+  benchmark_medians(ncol)
+)
+#> Running with:
+#>     ncol
+#>  1     1
+#>  2    10
+#>  3    50
+#>  4   100
+#>  5   250
+#>  6   300
+#>  7   400
+#>  8   500
+#>  9   750
+#> 10  1000
+
+

Finally, we can plot and interpret our results.

+
+
library(ggplot2)
+
+ggplot(
+  results,
+  aes(ncol, median, col = attr(expression, "description"))
+) +
+  geom_point(size = 2) +
+  geom_smooth() +
+  labs(
+    x = "Number of Columns",
+    y = "Execution Time (ms)",
+    colour = "Data Structure"
+  ) +
+  theme(legend.position = "top")
+#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
+
+
+
+

+
+
+
+
+

When working directly with the data frame, the execution time grows quadratically with the number of columns in the input data. This is because (e.g.) the first column must be copied n times, the second column n-1 times, and so on. When working with a list, the execution time increases only linearly.

+

Obviously in the long run, linear growth creates shorter run-times, but there is some cost to this strategy — we have to convert between data structures with as.list() and list2DF(). Even though this is fast and probably doesn’t hurt much, the improved approach doesn’t really pay off in this scenario until we get to a data frame that is about 300 columns wide (with the exact value depending on the characteristics of the system running the code).

+

Q3: What happens if you attempt to use tracemem() on an environment?

+

A: tracemem() cannot be used to mark and trace environments.

+
+
x <- new.env()
+tracemem(x)
+#> Error in tracemem(x): 'tracemem' is not useful for promise and environment objects
+
+

The error occurs because “it is not useful to trace NULL, environments, promises, weak references, or external pointer objects, as these are not duplicated” (see ?tracemem). Environments are always modified in place.

+
+
+

References

+ + +
+
+Hester, Jim. 2020. Bench: High Precision Timing of r Expressions. https://github.com/r-lib/bench. +
+
+Wickham, Hadley. 2019. Lobstr: Visualize r Data Structures with Trees. https://github.com/r-lib/lobstr. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/03_Vectors.html b/docs/03_Vectors.html new file mode 100644 index 00000000..71259499 --- /dev/null +++ b/docs/03_Vectors.html @@ -0,0 +1,1075 @@ + + + + + + + + + + +Advanced R Solutions - 3 - Vectors + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

3 - Vectors

+
+ + + +
+ + + + +
+ + +
+ +
+

Atomic vectors

+

Q1: How do you create raw and complex scalars? (See ?raw and ?complex.)

+

A: In R, scalars are represented as vectors of length one. However, there’s no built-in syntax like there is for logicals, integers, doubles, and character vectors to create individual raw and complex values. Instead, you have to create them by calling a function.

+

For raw vectors you can use either as.raw() or charToRaw() to create them from numeric or character values.

+
+
as.raw(42)
+#> [1] 2a
+charToRaw("A")
+#> [1] 41
+
+

In the case of complex numbers, real and imaginary parts may be provided directly to the complex() constructor.

+
+
complex(length.out = 1, real = 1, imaginary = 1)
+#> [1] 1+1i
+
+

You can create purely imaginary numbers (e.g.) 1i, but there is no way to create complex numbers without + (e.g. 1i + 1).

+

Q2: Test your knowledge of vector coercion rules by predicting the output of the following uses of c():

+
+
c(1, FALSE) # will be coerced to double    -> 1 0
+c("a", 1) # will be coerced to character -> "a" "1"
+c(TRUE, 1L) # will be coerced to integer   -> 1 1
+
+

Q3: Why is 1 == "1" true? Why is -1 < FALSE true? Why is "one" < 2 false?

+

A: These comparisons are carried out by operator-functions (==, <), which coerce their arguments to a common type. In the examples above, these types will be character, double and character: 1 will be coerced to "1", FALSE is represented as 0 and 2 turns into "2" (and numbers precede letters in lexicographic order (may depend on locale)).

+

Q4: Why is the default missing value, NA, a logical vector? What’s special about logical vectors? (Hint: think about c(FALSE, NA_character_).)

+

A: The presence of missing values shouldn’t affect the type of an object. Recall that there is a type-hierarchy for coercion from character → double → integer → logical. When combining NAs with other atomic types, the NAs will be coerced to integer (NA_integer_), double (NA_real_) or character (NA_character_) and not the other way round. If NA were a character and added to a set of other values all of these would be coerced to character as well.

+

Q5: Precisely what do is.atomic(), is.numeric(), and is.vector() test for?

+

A: The documentation states that:

+
    +
  • is.atomic() tests if an object is an atomic vector (as defined in Advanced R) or is NULL (!).
  • +
  • is.numeric() tests if an object has type integer or double and is not of class factor, Date, POSIXt or difftime.
  • +
  • is.vector() tests if an object is a vector (as defined in Advanced R) or an expression and has no attributes, apart from names.
  • +
+

Atomic vectors are defined in Advanced R as objects of type logical, integer, double, complex, character or raw. Vectors are defined as atomic vectors or lists.

+
+
+

Attributes

+

Q1: How is setNames() implemented? How is unname() implemented? Read the source code.

+

A: setNames() is implemented as:

+
+
setNames <- function(object = nm, nm) {
+  names(object) <- nm
+  object
+}
+
+

Because the data argument comes first, setNames() also works well with the magrittr-pipe operator. When no first argument is given, the result is a named vector (this is rather untypical as required arguments usually come first):

+
+
setNames(, c("a", "b", "c"))
+#>   a   b   c 
+#> "a" "b" "c"
+
+

unname() is implemented in the following way:

+
+
unname <- function(obj, force = FALSE) {
+  if (!is.null(names(obj))) {
+    names(obj) <- NULL
+  }
+  if (!is.null(dimnames(obj)) && (force || !is.data.frame(obj))) {
+    dimnames(obj) <- NULL
+  }
+  obj
+}
+
+

unname() removes existing names (or dimnames) by setting them to NULL.

+

Q2: What does dim() return when applied to a 1-dimensional vector? When might you use NROW() or NCOL()?

+

A: From ?nrow:

+
+

dim() will return NULL when applied to a 1d vector.

+
+

One may want to use NROW() or NCOL() to handle atomic vectors, lists and NULL values in the same way as one column matrices or data frames. For these objects nrow() and ncol() return NULL:

+
+
x <- 1:10
+
+# Return NULL
+nrow(x)
+#> NULL
+ncol(x)
+#> NULL
+
+# Pretend it's a column vector
+NROW(x)
+#> [1] 10
+NCOL(x)
+#> [1] 1
+
+

Q3: How would you describe the following three objects? What makes them different to 1:5?

+
+
x1 <- array(1:5, c(1, 1, 5)) # 1 row,  1 column,  5 in third dim.
+x2 <- array(1:5, c(1, 5, 1)) # 1 row,  5 columns, 1 in third dim.
+x3 <- array(1:5, c(5, 1, 1)) # 5 rows, 1 column,  1 in third dim.
+
+

A: These are all “one dimensional”. If you imagine a 3d cube, x1 is in the x-dimension, x2 is in the y-dimension, and x3 is in the z-dimension. In contrast to 1:5, x1, x2 and x3 have a dim attribute.

+

Q4: An early draft used this code to illustrate structure():

+
+
structure(1:5, comment = "my attribute")
+#> [1] 1 2 3 4 5
+
+

But when you print that object you don’t see the comment attribute. Why? Is the attribute missing, or is there something else special about it? (Hint: try using help.)

+

A: The documentation states (see ?comment):

+
+

Contrary to other attributes, the comment is not printed (by print or print.default).

+
+

Also, from ?attributes:

+
+

Note that some attributes (namely class, comment, dim, dimnames, names, row.names and tsp) are treated specially and have restrictions on the values which can be set.

+
+

We can retrieve comment attributes by calling them explicitly:

+
+
foo <- structure(1:5, comment = "my attribute")
+
+attributes(foo)
+#> $comment
+#> [1] "my attribute"
+attr(foo, which = "comment")
+#> [1] "my attribute"
+
+
+
+

S3 atomic vectors

+

Q1: What sort of object does table() return? What is its type? What attributes does it have? How does the dimensionality change as you tabulate more variables?

+

A: table() returns a contingency table of its input variables. It is implemented as an integer vector with class table and dimensions (which makes it act like an array). Its attributes are dim (dimensions) and dimnames (one name for each input column). The dimensions correspond to the number of unique values (factor levels) in each input variable.

+
+
x <- table(mtcars[c("vs", "cyl", "am")])
+
+typeof(x)
+#> [1] "integer"
+attributes(x)
+#> $dim
+#> [1] 2 3 2
+#> 
+#> $dimnames
+#> $dimnames$vs
+#> [1] "0" "1"
+#> 
+#> $dimnames$cyl
+#> [1] "4" "6" "8"
+#> 
+#> $dimnames$am
+#> [1] "0" "1"
+#> 
+#> 
+#> $class
+#> [1] "table"
+
+# Subset x like it's an array
+x[, , 1]
+#>    cyl
+#> vs   4  6  8
+#>   0  0  0 12
+#>   1  3  4  0
+x[, , 2]
+#>    cyl
+#> vs  4 6 8
+#>   0 1 3 2
+#>   1 7 0 0
+
+

Q2: What happens to a factor when you modify its levels?

+
+
f1 <- factor(letters)
+levels(f1) <- rev(levels(f1))
+
+

A: The underlying integer values stay the same, but the levels are changed, making it look like the data has changed.

+
+
f1 <- factor(letters)
+f1
+#>  [1] a b c d e f g h i j k l m n o p q r s t u v w x y z
+#> Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
+as.integer(f1)
+#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
+#> [26] 26
+
+levels(f1) <- rev(levels(f1))
+f1
+#>  [1] z y x w v u t s r q p o n m l k j i h g f e d c b a
+#> Levels: z y x w v u t s r q p o n m l k j i h g f e d c b a
+as.integer(f1)
+#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
+#> [26] 26
+
+

Q3: What does this code do? How do f2 and f3 differ from f1?

+
+
f2 <- rev(factor(letters))
+
+f3 <- factor(letters, levels = rev(letters))
+
+

A: For f2 and f3 either the order of the factor elements or its levels are being reversed. For f1 both transformations are occurring.

+
+
# Reverse element order
+(f2 <- rev(factor(letters)))
+#>  [1] z y x w v u t s r q p o n m l k j i h g f e d c b a
+#> Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
+as.integer(f2)
+#>  [1] 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
+#> [26]  1
+
+# Reverse factor levels (when creating factor)
+(f3 <- factor(letters, levels = rev(letters)))
+#>  [1] a b c d e f g h i j k l m n o p q r s t u v w x y z
+#> Levels: z y x w v u t s r q p o n m l k j i h g f e d c b a
+as.integer(f3)
+#>  [1] 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
+#> [26]  1
+
+
+
+

Lists

+

Q1: List all the ways that a list differs from an atomic vector.

+

A: To summarise:

+
    +
  • Atomic vectors are always homogeneous (all elements must be of the same type). Lists may be heterogeneous (the elements can be of different types) as described in the introduction of the vectors chapter.

  • +
  • Atomic vectors point to one address in memory, while lists contain a separate reference for each element. (This was described in the list sections of the vectors and the names and values chapters.)

    +

    ::: {.cell layout-align=“center” hash=‘03_Vectors_cache/html/unnamed-chunk-17_0058a5e26b51d7db0318a76d78964418’}

    +
    lobstr::ref(1:2)
    +#> [1:0x64f19ae18cf8] <int>
    +lobstr::ref(list(1:2, 2))
    +#> █ [1:0x64f19c1af298] <list> 
    +#> ├─[2:0x64f19b1df130] <int> 
    +#> └─[3:0x64f19b417d30] <dbl>
    +

    :::

  • +
  • Subsetting with out-of-bounds and NA values leads to different output. For example, [ returns NA for atomics and NULL for lists. (This is described in more detail within the subsetting chapter.)

    +

    ::: {.cell layout-align=“center” hash=‘03_Vectors_cache/html/unnamed-chunk-18_96e783346fc71ba0391dc1e6eefae75a’}

    +
    # Subsetting atomic vectors
    +(1:2)[3]
    +#> [1] NA
    +(1:2)[NA]
    +#> [1] NA NA
    +
    +# Subsetting lists
    +as.list(1:2)[3]
    +#> [[1]]
    +#> NULL
    +as.list(1:2)[NA]
    +#> [[1]]
    +#> NULL
    +#> 
    +#> [[2]]
    +#> NULL
    +

    :::

  • +
+

Q2: Why do you need to use unlist() to convert a list to an atomic vector? Why doesn’t as.vector() work?

+

A: A list is already a vector, though not an atomic one!

+

Note that as.vector() and is.vector() use different definitions of “vector”!

+
+
is.vector(as.vector(mtcars))
+#> [1] TRUE
+
+

Q3: Compare and contrast c() and unlist() when combining a date and date-time into a single vector.

+

A: Date and date-time objects are both built upon doubles. While dates store the number of days since the reference date 1970-01-01 (also known as “the Epoch”) in days, date-time-objects (POSIXct) store the time difference to this date in seconds.

+
+
date <- as.Date("1970-01-02")
+dttm_ct <- as.POSIXct("1970-01-01 01:00", tz = "UTC")
+
+# Internal representations
+unclass(date)
+#> [1] 1
+unclass(dttm_ct)
+#> [1] 3600
+#> attr(,"tzone")
+#> [1] "UTC"
+
+

As the c() generic only dispatches on its first argument, combining date and date-time objects via c() could lead to surprising results in older R versions (pre R 4.0.0):

+
+
# Output in R version 3.6.2
+c(date, dttm_ct) # equal to c.Date(date, dttm_ct)
+#> [1] "1970-01-02" "1979-11-10"
+c(dttm_ct, date) # equal to c.POSIXct(date, dttm_ct)
+#> [1] "1970-01-01 02:00:00 CET" "1970-01-01 01:00:01 CET"
+
+

In the first statement above c.Date() is executed, which incorrectly treats the underlying double of dttm_ct (3600) as days instead of seconds. Conversely, when c.POSIXct() is called on a date, one day is counted as one second only.

+

We can highlight these mechanics by the following code:

+
+
# Output in R version 3.6.2
+unclass(c(date, dttm_ct)) # internal representation
+#> [1] 1 3600
+date + 3599
+#> "1979-11-10"
+
+

As of R 4.0.0 these issues have been resolved and both methods now convert their input first into POSIXct and Date, respectively.

+
+
c(dttm_ct, date)
+#> [1] "1970-01-01 01:00:00 UTC" "1970-01-02 00:00:00 UTC"
+unclass(c(dttm_ct, date))
+#> [1]  3600 86400
+#> attr(,"tzone")
+#> [1] "UTC"
+
+c(date, dttm_ct)
+#> [1] "1970-01-02" "1970-01-01"
+unclass(c(date, dttm_ct))
+#> [1] 1 0
+
+

However, as c() strips the time zone (and other attributes) of POSIXct objects, some caution is still recommended.

+
+
(dttm_ct <- as.POSIXct("1970-01-01 01:00", tz = "HST"))
+#> [1] "1970-01-01 01:00:00 HST"
+attributes(c(dttm_ct))
+#> $class
+#> [1] "POSIXct" "POSIXt" 
+#> 
+#> $tzone
+#> [1] "HST"
+
+

A package that deals with these kinds of problems in more depth and provides a structural solution for them is the {vctrs} package (Wickham, Henry, and Vaughan 2020) which is also used throughout the tidyverse (Wickham et al. 2019).

+

Let’s look at unlist(), which operates on list input.

+
+
# Attributes are stripped
+unlist(list(date, dttm_ct))
+#> [1]     1 39600
+
+

We see again that dates and date-times are internally stored as doubles. Unfortunately, this is all we are left with, when unlist strips the attributes of the list.

+

To summarise: c() coerces types and strips time zones. Errors may have occurred in older R versions because of inappropriate method dispatch/immature methods. unlist() strips attributes.

+
+
+

Data frames and tibbles

+

Q1: Can you have a data frame with zero rows? What about zero columns?

+

A: Yes, you can create these data frames easily; either during creation or via subsetting. Even both dimensions can be zero.

+

Create a 0-row, 0-column, or an empty data frame directly:

+
+
data.frame(a = integer(), b = logical())
+#> [1] a b
+#> <0 rows> (or 0-length row.names)
+
+data.frame(row.names = 1:3) # or data.frame()[1:3, ]
+#> data frame with 0 columns and 3 rows
+
+data.frame()
+#> data frame with 0 columns and 0 rows
+
+

Create similar data frames via subsetting the respective dimension with either 0, NULL, FALSE or a valid 0-length atomic (logical(0), character(0), integer(0), double(0)). Negative integer sequences would also work. The following example uses a zero:

+
+
mtcars[0, ]
+#>  [1] mpg  cyl  disp hp   drat wt   qsec vs   am   gear carb
+#> <0 rows> (or 0-length row.names)
+
+mtcars[, 0] # or mtcars[0]
+#> data frame with 0 columns and 32 rows
+
+mtcars[0, 0]
+#> data frame with 0 columns and 0 rows
+
+

Q2: What happens if you attempt to set rownames that are not unique?

+

A: Matrices can have duplicated row names, so this does not cause problems.

+

Data frames, however, require unique rownames and you get different results depending on how you attempt to set them. If you set them directly or via row.names(), you get an error:

+
+
data.frame(row.names = c("x", "y", "y"))
+#> Error in data.frame(row.names = c("x", "y", "y")): duplicate row.names: y
+
+df <- data.frame(x = 1:3)
+row.names(df) <- c("x", "y", "y")
+#> Warning: non-unique value when setting 'row.names': 'y'
+#> Error in `.rowNamesDF<-`(x, value = value): duplicate 'row.names' are not allowed
+
+

If you use subsetting, [ automatically deduplicates:

+
+
row.names(df) <- c("x", "y", "z")
+df[c(1, 1, 1), , drop = FALSE]
+#>     x
+#> x   1
+#> x.1 1
+#> x.2 1
+
+

Q3: If df is a data frame, what can you say about t(df), and t(t(df))? Perform some experiments, making sure to try different column types.

+

A: Both of t(df) and t(t(df)) will return matrices:

+
+
df <- data.frame(x = 1:3, y = letters[1:3])
+is.matrix(df)
+#> [1] FALSE
+is.matrix(t(df))
+#> [1] TRUE
+is.matrix(t(t(df)))
+#> [1] TRUE
+
+

The dimensions will respect the typical transposition rules:

+
+
dim(df)
+#> [1] 3 2
+dim(t(df))
+#> [1] 2 3
+dim(t(t(df)))
+#> [1] 3 2
+
+

Because the output is a matrix, every column is coerced to the same type. (It is implemented within t.data.frame() via as.matrix() which is described below).

+
+
df
+#>   x y
+#> 1 1 a
+#> 2 2 b
+#> 3 3 c
+t(df)
+#>   [,1] [,2] [,3]
+#> x "1"  "2"  "3" 
+#> y "a"  "b"  "c"
+
+

Q4: What does as.matrix() do when applied to a data frame with columns of different types? How does it differ from data.matrix()?

+

A: The type of the result of as.matrix depends on the types of the input columns (see ?as.matrix):

+
+

The method for data frames will return a character matrix if there is only atomic columns and any non-(numeric/logical/complex) column, applying as.vector to factors and format to other non-character columns. Otherwise the usual coercion hierarchy (logical < integer < double < complex) will be used, e.g. all-logical data frames will be coerced to a logical matrix, mixed logical-integer will give an integer matrix, etc.

+
+

On the other hand, data.matrix will always return a numeric matrix (see ?data.matrix()).

+
+

Return the matrix obtained by converting all the variables in a data frame to numeric mode and then binding them together as the columns of a matrix. Factors and ordered factors are replaced by their internal codes. […] Character columns are first converted to factors and then to integers.

+
+

We can illustrate and compare the mechanics of these functions using a concrete example. as.matrix() makes it possible to retrieve most of the original information from the data frame but leaves us with characters. To retrieve all information from data.matrix()’s output, we would need a lookup table for each column.

+
+
df_coltypes <- data.frame(
+  a = c("a", "b"),
+  b = c(TRUE, FALSE),
+  c = c(1L, 0L),
+  d = c(1.5, 2),
+  e = factor(c("f1", "f2"))
+)
+
+as.matrix(df_coltypes)
+#>      a   b       c   d     e   
+#> [1,] "a" "TRUE"  "1" "1.5" "f1"
+#> [2,] "b" "FALSE" "0" "2.0" "f2"
+data.matrix(df_coltypes)
+#>      a b c   d e
+#> [1,] 1 1 1 1.5 1
+#> [2,] 2 0 0 2.0 2
+
+
+
+

References

+ + +
+
+Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686. +
+
+Wickham, Hadley, Lionel Henry, and Davis Vaughan. 2020. Vctrs: Vector Helpers. https://github.com/r-lib/vctrs. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/04_Subsetting.html b/docs/04_Subsetting.html new file mode 100644 index 00000000..71e80428 --- /dev/null +++ b/docs/04_Subsetting.html @@ -0,0 +1,805 @@ + + + + + + + + + + +Advanced R Solutions - 4 - Subsetting + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

4 - Subsetting

+
+ + + +
+ + + + +
+ + +
+ +
+

Selecting multiple elements

+

Q1: Fix each of the following common data frame subsetting errors:

+
+
mtcars[mtcars$cyl = 4, ]
+# use `==`              (instead of `=`)
+
+mtcars[-1:4, ]
+# use `-(1:4)`          (instead of `-1:4`)
+
+mtcars[mtcars$cyl <= 5]
+# `,` is missing
+
+mtcars[mtcars$cyl == 4 | 6, ]
+# use `mtcars$cyl == 6` (instead of `6`)
+#  or `%in% c(4, 6)`    (instead of `== 4 | 6`)
+
+

Q2: Why does the following code yield five missing values? (Hint: why is it different from x[NA_real_]?)

+
+
x <- 1:5
+x[NA]
+#> [1] NA NA NA NA NA
+
+

A: In contrast to NA_real, NA has logical type and logical vectors are recycled to the same length as the vector being subset, i.e. x[NA] is recycled to x[c(NA, NA, NA, NA, NA)].

+

Q3: What does upper.tri() return? How does subsetting a matrix with it work? Do we need any additional subsetting rules to describe its behaviour?

+
+
x <- outer(1:5, 1:5, FUN = "*")
+x[upper.tri(x)]
+
+

A: upper.tri(x) returns a logical matrix, which contains TRUE values above the diagonal and FALSE values everywhere else. In upper.tri() the positions for TRUE and FALSE values are determined by comparing x’s row and column indices via .row(dim(x)) < .col(dim(x)).

+
+
x
+#>      [,1] [,2] [,3] [,4] [,5]
+#> [1,]    1    2    3    4    5
+#> [2,]    2    4    6    8   10
+#> [3,]    3    6    9   12   15
+#> [4,]    4    8   12   16   20
+#> [5,]    5   10   15   20   25
+upper.tri(x)
+#>       [,1]  [,2]  [,3]  [,4]  [,5]
+#> [1,] FALSE  TRUE  TRUE  TRUE  TRUE
+#> [2,] FALSE FALSE  TRUE  TRUE  TRUE
+#> [3,] FALSE FALSE FALSE  TRUE  TRUE
+#> [4,] FALSE FALSE FALSE FALSE  TRUE
+#> [5,] FALSE FALSE FALSE FALSE FALSE
+
+

When subsetting with logical matrices, all elements that correspond to TRUE will be selected. Matrices extend vectors with a dimension attribute, so the vector forms of subsetting can be used (including logical subsetting). We should take care, that the dimensions of the subsetting matrix match the object of interest — otherwise unintended selections due to vector recycling may occur. Please also note, that this form of subsetting returns a vector instead of a matrix, as the subsetting alters the dimensions of the object.

+
+
x[upper.tri(x)]
+#>  [1]  2  3  6  4  8 12  5 10 15 20
+
+

Q4: Why does mtcars[1:20] return an error? How does it differ from the similar mtcars[1:20, ]?

+

A: When subsetting a data frame with a single vector, it behaves the same way as subsetting a list of columns. So, mtcars[1:20] would return a data frame containing the first 20 columns of the dataset. However, as mtcars has only 11 columns, the index will be out of bounds and an error is thrown. mtcars[1:20, ] is subsetted with two vectors, so 2d subsetting kicks in, and the first index refers to rows.

+

Q5: Implement your own function that extracts the diagonal entries from a matrix (it should behave like diag(x) where x is a matrix).

+

A: The elements in the diagonal of a matrix have the same row- and column indices. This characteristic can be used to create a suitable numeric matrix used for subsetting.

+
+
diag2 <- function(x) {
+  n <- min(nrow(x), ncol(x))
+  idx <- cbind(seq_len(n), seq_len(n))
+
+  x[idx]
+}
+
+# Let's check if it works
+(x <- matrix(1:30, 5))
+#>      [,1] [,2] [,3] [,4] [,5] [,6]
+#> [1,]    1    6   11   16   21   26
+#> [2,]    2    7   12   17   22   27
+#> [3,]    3    8   13   18   23   28
+#> [4,]    4    9   14   19   24   29
+#> [5,]    5   10   15   20   25   30
+
+diag(x)
+#> [1]  1  7 13 19 25
+diag2(x)
+#> [1]  1  7 13 19 25
+
+

Q6: What does df[is.na(df)] <- 0 do? How does it work?

+

A: This expression replaces the NAs in df with 0. Here is.na(df) returns a logical matrix that encodes the position of the missing values in df. Subsetting and assignment are then combined to replace only the missing values.

+
+
+

Selecting a single element

+

Q1: Brainstorm as many ways as possible to extract the third value from the cyl variable in the mtcars dataset.

+

A: Base R already provides an abundance of possibilities:

+
+
# Select column first
+mtcars$cyl[[3]]
+#> [1] 4
+mtcars[ , "cyl"][[3]]
+#> [1] 4
+mtcars[["cyl"]][[3]]
+#> [1] 4
+with(mtcars, cyl[[3]])
+#> [1] 4
+
+# Select row first
+mtcars[3, ]$cyl
+#> [1] 4
+mtcars[3, "cyl"]
+#> [1] 4
+mtcars[3, ][ , "cyl"]
+#> [1] 4
+mtcars[3, ][["cyl"]]
+#> [1] 4
+
+# Select simultaneously
+mtcars[3, 2]
+#> [1] 4
+mtcars[[c(2, 3)]]
+#> [1] 4
+
+

Q2: Given a linear model, e.g. mod <- lm(mpg ~ wt, data = mtcars), extract the residual degrees of freedom. Extract the R squared from the model summary (summary(mod)).

+

A: mod is of type list, which opens up several possibilities. We use $ or [[ to extract a single element:

+
+
mod <- lm(mpg ~ wt, data = mtcars)
+
+mod$df.residual
+#> [1] 30
+mod[["df.residual"]]
+#> [1] 30
+
+

The same also applies to summary(mod), so we could use, e.g.:

+
+
summary(mod)$r.squared
+#> [1] 0.753
+
+

(Tip: The {broom} package (Robinson, Hayes, and Couch 2020) provides a very useful approach to work with models in a tidy way.)

+
+
+

Applications

+

Q1: How would you randomly permute the columns of a data frame? (This is an important technique in random forests.) Can you simultaneously permute the rows and columns in one step?

+

A: This can be achieved by combining [ and sample():

+
+
# Permute columns
+mtcars[sample(ncol(mtcars))]
+
+# Permute columns and rows in one step
+mtcars[sample(nrow(mtcars)), sample(ncol(mtcars))]
+
+

Q2: How would you select a random sample of m rows from a data frame? What if the sample had to be contiguous (i.e. with an initial row, a final row, and every row in between)?

+

A: Selecting m random rows from a data frame can be achieved through subsetting.

+
+
m <- 10
+mtcars[sample(nrow(mtcars), m), ]
+
+

Holding successive lines together as a blocked sample requires only a certain amount of caution in order to obtain the correct start and end index.

+
+
start <- sample(nrow(mtcars) - m + 1, 1)
+end <- start + m - 1
+mtcars[start:end, , drop = FALSE]
+
+

Q3: How could you put the columns in a data frame in alphabetical order?

+

A: We combine [ with order() or sort():

+
+
mtcars[order(names(mtcars))]
+mtcars[sort(names(mtcars))]
+
+
+
+

References

+ + +
+
+Robinson, David, Alex Hayes, and Simon Couch. 2020. Broom: Convert Statistical Objects into Tidy Tibbles. https://github.com/tidymodels/broom. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/05_Control_flow.html b/docs/05_Control_flow.html new file mode 100644 index 00000000..91c7162d --- /dev/null +++ b/docs/05_Control_flow.html @@ -0,0 +1,696 @@ + + + + + + + + + + +Advanced R Solutions - 5 - Control flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

5 - Control flow

+
+ + + +
+ + + + +
+ + +
+ +
+

Choices

+

Q1: What type of vector does each of the following calls to ifelse() return?

+
+
ifelse(TRUE, 1, "no")
+ifelse(FALSE, 1, "no")
+ifelse(NA, 1, "no")
+
+

Read the documentation and write down the rules in your own words.

+

A: The arguments of ifelse() are named test, yes and no. In general, ifelse() returns the entry for yes when test is TRUE, the entry for no when test is FALSE and NA when test is NA. Therefore, the expressions above return vectors of type double (1), character ("no") and logical (NA).

+

To be a little more precise, we will cite the part of the documentation on the return value of ifelse():

+
+

A vector of the same length and attributes (including dimensions and “class”) as test and data values from the values of yes or no. The mode of the answer will be coerced from logical to accommodate first any values taken from yes and then any values taken from no.

+
+

This is surprising because it uses the type of test. In practice this means, that test is first converted to logical and if the result is neither TRUE nor FALSE, simply as.logical(test) is returned.

+
+
ifelse(logical(), 1, "no")
+#> logical(0)
+ifelse(NaN, 1, "no")
+#> [1] NA
+ifelse(NA_character_, 1, "no")
+#> [1] NA
+ifelse("a", 1, "no")
+#> [1] NA
+ifelse("true", 1, "no")
+#> [1] 1
+
+

Q2: Why does the following code work?

+
+
x <- 1:10
+if (length(x)) "not empty" else "empty"
+#> [1] "not empty"
+
+x <- numeric()
+if (length(x)) "not empty" else "empty"
+#> [1] "empty"
+
+

A: if() expects a logical condition, but also accepts a numeric vector where 0 is treated as FALSE and all other numbers are treated as TRUE. Numerical missing values (including NaN) lead to an error in the same way that a logical missing, NA, does.

+
+
+

Loops

+

Q1: Why does this code succeed without errors or warnings?

+
+
x <- numeric()
+out <- vector("list", length(x))
+for (i in 1:length(x)) {
+  out[i] <- x[i]^2
+}
+out
+
+

A: This loop is a delicate issue, and we have to consider a few points to explain why it is evaluated without raising any errors or warnings.

+

The beginning of this code smell is the statement 1:length(x) which creates the index of the for loop. As x has length 0 1:length(x) counts down from 1 to 0. This issue is typically avoided via usage of seq_along(x) or similar helpers which would just generate integer(0) in this case.

+

As we use [<- and [ for indexing 0-length vectors at their first and zeroth position, we need to be aware of their subsetting behaviour for out-of-bounds and zero indices.

+

During the first iteration x[1] will generate an NA (out-of-bounds indexing for atomics). The resulting NA (from squaring) will be assigned to the empty length-1 list out[1] (out-of-bounds indexing for lists).

+

In the next iteration, x[0] will return numeric(0) (zero indexing for atomics). Again, squaring doesn’t change the value and numeric(0) is assigned to out[0] (zero indexing for lists). Assigning a 0-length vector to a 0-length subset works but doesn’t change the object.

+

Overall, the code works, because each step includes valid R operations (even though the result may not be what the user intended).

+

Q2: When the following code is evaluated, what can you say about the vector being iterated?

+
+
xs <- c(1, 2, 3)
+for (x in xs) {
+  xs <- c(xs, x * 2)
+}
+xs
+#> [1] 1 2 3 2 4 6
+
+

A: In this loop x takes on the values of the initial xs (1, 2 and 3), indicating that it is evaluated just once in the beginning of the loop, not after each iteration. (Otherwise, we would run into an infinite loop.)

+

Q3: What does the following code tell you about when the index is updated?

+
+
for (i in 1:3) {
+  i <- i * 2
+  print(i)
+}
+#> [1] 2
+#> [1] 4
+#> [1] 6
+
+

A: In a for loop the index is updated in the beginning of each iteration. Therefore, reassigning the index symbol during one iteration doesn’t affect the following iterations. (Again, we would otherwise run into an infinite loop.)

+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/06_Functions.html b/docs/06_Functions.html new file mode 100644 index 00000000..3d84ef88 --- /dev/null +++ b/docs/06_Functions.html @@ -0,0 +1,1215 @@ + + + + + + + + + + +Advanced R Solutions - 6 - Functions + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

6 - Functions

+
+ + + +
+ + + + +
+ + +
+ +
+

Function fundamentals

+

Q1: Given a name, like "mean", match.fun() lets you find a function. Given a function, can you find its name? Why doesn’t that make sense in R?

+

A: In R there is no one-to-one mapping between functions and names. A name always points to a single object, but an object may have zero, one or many names.

+

Let’s look at an example:

+
+
function(x) sd(x) / mean(x)
+#> function(x) sd(x) / mean(x)
+
+f1 <- function(x) (x - min(x)) / (max(x) - min(x))
+f2 <- f1
+f3 <- f1
+
+

While the function in the first line is not bound to a name multiple names (f1, f2 and f3) point to the second function. So, the main point is that the relation between name and object is only clearly defined in one direction.

+

Besides that, there are obviously ways to search for function names. However, to be sure to find the right one(s), you should not only compare the code (body) but also the arguments (formals) and the creation environment. As formals(), body() and environment() all return NULL for primitive functions, the easiest way to check if two functions are exactly equal is just to use identical().

+

Q2: It’s possible (although typically not useful) to call an anonymous function. Which of the two approaches below is correct? Why?

+
+
function(x) 3()
+#> function(x) 3()
+(function(x) 3)()
+#> [1] 3
+
+

A: The second approach is correct.

+

The anonymous function function(x) 3 is surrounded by a pair of parentheses before it is called by (). These extra parentheses separate the function call from the anonymous function’s body. Without them a function with the invalid body 3() is returned, which throws an error when we call it. This is easier to see if we name the function:

+
+
f <- function(x) 3()
+f
+#> function(x) 3()
+f()
+#> Error in f(): attempt to apply non-function
+
+

Q3: A good rule of thumb is that an anonymous function should fit on one line and shouldn’t need to use {}. Review your code. Where could you have used an anonymous function instead of a named function? Where should you have used a named function instead of an anonymous function?

+

A: The use of anonymous functions allows concise and elegant code in certain situations. However, they miss a descriptive name and when re-reading the code, it can take a while to figure out what they do. That’s why it’s helpful to give long and complex functions a descriptive name. It may be worthwhile to take a look at your own projects or other people’s code to reflect on this part of your coding style.

+

Q4: What function allows you to tell if an object is a function? What function allows you to tell if a function is a primitive function?

+

A: Use is.function() to test if an object is a function. Consider using is.primitive() to test specifically for primitive functions.

+

Q5: This code makes a list of all functions in the {base} package.

+
+
objs <- mget(ls("package:base", all = TRUE), inherits = TRUE)
+funs <- Filter(is.function, objs)
+
+

Use it to answer the following questions:

+
    +
  1. Which base function has the most arguments?

  2. +
  3. How many base functions have no arguments? What’s special about those functions?

  4. +
  5. How could you adapt the code to find all primitive functions?

  6. +
+

A: Let’s look at each sub-question separately:

+
    +
  1. To find the function with the most arguments, we first compute the length of formals().

    +

    ::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-6_6267cff5cf01cfe02ecd151e21d5a5fa’}

    +
    library(purrr)
    +
    +n_args <- funs %>%
    +  map(formals) %>%
    +  map_int(length)
    +

    :::

    +

    Then we sort n_args in decreasing order and look at its first entries.

    +

    ::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-7_e2ebb773e25ecb466480bc13c7da9a54’}

    +
    n_args %>%
    +  sort(decreasing = TRUE) %>%
    +  head()
    +#> scan format.default source
    +#> 22 16 16
    +#> formatC library merge.data.frame
    +#> 15 13 13
    +

    :::

  2. +
  3. We can further use n_args to find the number of functions with no arguments:

    +

    ::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-8_c75252d5453caf2a84875fac9332cabc’}

    +
    sum(n_args == 0)
    +#> [1] 253
    +

    :::

    +

    However, this over counts because formals() returns NULL for primitive functions, and length(NULL) is 0. To fix this, we can first remove the primitive functions:

    +

    ::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-9_26e9cc7827d73a0a237f756700c9bf1e’}

    +
    n_args2 <- funs %>%
    +  discard(is.primitive) %>%
    +  map(formals) %>%
    +  map_int(length)
    +
    +sum(n_args2 == 0)
    +#> [1] 48
    +

    :::

    +

    Indeed, most of the functions with no arguments are actually primitive functions.

  4. +
  5. To find all primitive functions, we can change the predicate in Filter() from is.function() to is.primitive():

    +

    ::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-10_ff0eddde09f29f9d6acb9dcb81dfbef0’}

    +
    funs <- Filter(is.primitive, objs)
    +length(funs)
    +#> [1] 205
    +

    :::

  6. +
+

Q6: What are the three important components of a function?

+

A: These components are the function’s body(), formals() and environment(). However, as mentioned in Advanced R:

+
+

There is one exception to the rule that functions have three components. Primitive functions, like sum(), call C code directly with .Primitive() and contain no R code. Therefore, their formals(), body(), and environment() are all NULL.

+
+

Q7: When does printing a function not show what environment it was created in?

+

A: Primitive functions and functions created in the global environment do not print their environment.

+
+
+

Lexical scoping

+

Q1: What does the following code return? Why? Describe how each of the three c’s is interpreted.

+
+
c <- 10
+c(c = c)
+
+

A: This code returns a named numeric vector of length one — with one element of the value 10 and the name "c". The first c represents the c() function, the second c is interpreted as a (quoted) name and the third c as a value.

+

Q2: What are the four principles that govern how R looks for values?

+

A: R’s lexical scoping rules are based on these four principles:

+ +

Q3: What does the following function return? Make a prediction before running the code yourself.

+
+
f <- function(x) {
+  f <- function(x) {
+    f <- function() {
+      x^2
+    }
+    f() + 1
+  }
+  f(x) * 2
+}
+f(10)
+
+

A: Within this nested function two more functions also named f are defined and called. Because the functions are each executed in their own environment R will look up and use the functions defined last in these environments. The innermost f() is called last, though it is the first function to return a value. Therefore, the order of the calculation passes “from the inside to the outside” and the function returns ((10 ^ 2) + 1) * 2, i.e. 202.

+
+
+

Lazy evaluation

+

Q1: What important property of && makes x_ok() work?

+
+
x_ok <- function(x) {
+  !is.null(x) && length(x) == 1 && x > 0
+}
+
+x_ok(NULL)
+#> [1] FALSE
+x_ok(1)
+#> [1] TRUE
+x_ok(1:3)
+#> [1] FALSE
+
+

What is different with this code? Why is this behaviour undesirable here?

+
+
x_ok <- function(x) {
+  !is.null(x) & length(x) == 1 & x > 0
+}
+
+x_ok(NULL)
+#> logical(0)
+x_ok(1)
+#> [1] TRUE
+x_ok(1:3)
+#> [1] FALSE FALSE FALSE
+
+

A: In summary: && short-circuits which means that if the left-hand side is FALSE it doesn’t evaluate the right-hand side (because it doesn’t matter). Similarly, if the left-hand side of || is TRUE it doesn’t evaluate the right-hand side.

+

We expect x_ok() to validate its input via certain criteria: it must not be NULL, have length 1 and be greater than 0. Meaningful outcomes for this assertion will be TRUE, FALSE or NA. The desired behaviour is reached by combining the assertions through && instead of &.

+

&& does not perform elementwise comparisons; instead it uses the first element of each value only. It also uses lazy evaluation, in the sense that evaluation “proceeds only until the result is determined” (from ?Logic). This means that the RHS of && won’t be evaluated if the LHS already determines the outcome of the comparison (e.g. evaluate to FALSE). This behaviour is also known as “short-circuiting”. For some situations (x = 1) both operators will lead to the same result. But this is not always the case. For x = NULL, the &&-operator will stop after the !is.null statement and return the result. The following conditions won’t even be evaluated! (If the other conditions are also evaluated (by the use of &), the outcome would change. NULL > 0 returns logical(0), which is not helpful in this case.)

+

We can also see the difference in behaviour, when we set x = 1:3. The &&-operator returns the result from length(x) == 1, which is FALSE. Using & as the logical operator leads to the (vectorised) x > 0 condition being evaluated and also returned.

+

Q2: What does this function return? Why? Which principle does it illustrate?

+
+
f2 <- function(x = z) {
+  z <- 100
+  x
+}
+f2()
+
+

A: The function returns 100. The default argument (x = z) gets lazily evaluated within the function environment when x gets accessed. At this time z has already been bound to the value 100. The illustrated principle here is lazy evaluation.

+

Q3: What does this function return? Why? Which principle does it illustrate?

+
+
y <- 10
+f1 <- function(x = {
+                 y <- 1
+                 2
+               }, y = 0) {
+  c(x, y)
+}
+f1()
+y
+
+

A: The function returns c(2, 1) which is due to name masking. When x is accessed within c(), the promise x = {y <- 1; 2} is evaluated inside f1()’s environment. y gets bound to the value 1 and the return value of {() (2) gets assigned to x. When y gets accessed next within c(), it has already the value 1 and R doesn’t need to look it up any further. Therefore, the promise y = 0 won’t be evaluated. Also, as y is assigned within f1()’s environment, the value of the global variable y is left untouched.

+

Q4: In hist(), the default value of xlim is range(breaks), the default value for breaks is "Sturges", and

+
+
range("Sturges")
+#> [1] "Sturges" "Sturges"
+
+

Explain how hist() works to get a correct xlim value.

+

A: The xlim argument of hist() defines the range of the histogram’s x-axis. In order to provide a valid axis xlim must contain a numeric vector of exactly two unique values. Consequently, for the default xlim = range(breaks)), breaks must evaluate to a vector with at least two unique values.

+

During execution hist() overwrites the breaks argument. The breaks argument is quite flexible and allows the users to provide the breakpoints directly or compute them in several ways. Therefore, the specific behaviour depends highly on the input. But hist ensures that breaks evaluates to a numeric vector containing at least two unique elements before xlim is computed.

+

Q5: Explain why this function works. Why is it confusing?

+
+
show_time <- function(x = stop("Error!")) {
+  stop <- function(...) Sys.time()
+  print(x)
+}
+show_time()
+#> [1] "2024-01-24 11:45:19 EST"
+
+

A: Before show_time() accesses x (default stop("Error")), the stop() function is masked by function(...) Sys.time(). As default arguments are evaluated in the function environment, print(x) will be evaluated as print(Sys.time()).

+

This function is confusing because its behaviour changes when x’s value is supplied directly. Now the value from the calling environment will be used and the overwriting of stop() won’t affect x anymore.

+
+
show_time(x = stop("Error!"))
+#> Error in print(x): Error!
+
+

Q6: How many arguments are required when calling library()?

+

A: library() doesn’t require any arguments. When called without arguments library() invisibly returns a list of class libraryIQR, which contains a results matrix with one row and three columns per installed package. These columns contain entries for the name of the package (“Package”), the path to the package (“LibPath”) and the title of the package (“Title”). library() also has its own print method (print.libraryIQR()), which displays this information conveniently in its own window.

+

This behaviour is also documented under the details section of library()’s help page (?library):

+
+

If library is called with no package or help argument, it lists all available packages in the libraries specified by lib.loc, and returns the corresponding information in an object of class “libraryIQR”. (The structure of this class may change in future versions.) Use .packages(all = TRUE) to obtain just the names of all available packages, and installed.packages() for even more information.

+
+

Because the package and help argument from library() do not show a default value, it’s easy to overlook the possibility to call library() without these arguments. (Instead of providing NULLs as default values library() uses missing() to check if these arguments were provided.)

+
+
str(formals(library))
+#> Dotted pair list of 13
+#>  $ package        : symbol 
+#>  $ help           : symbol 
+#>  $ pos            : num 2
+#>  $ lib.loc        : NULL
+#>  $ character.only : logi FALSE
+#>  $ logical.return : logi FALSE
+#>  $ warn.conflicts : symbol 
+#>  $ quietly        : logi FALSE
+#>  $ verbose        : language getOption("verbose")
+#>  $ mask.ok        : symbol 
+#>  $ exclude        : symbol 
+#>  $ include.only   : symbol 
+#>  $ attach.required: language missing(include.only)
+
+
+
+

... (dot-dot-dot)

+

Q1: Explain the following results:

+
+
sum(1, 2, 3)
+#> [1] 6
+mean(1, 2, 3)
+#> [1] 1
+
+sum(1, 2, 3, na.omit = TRUE)
+#> [1] 7
+mean(1, 2, 3, na.omit = TRUE)
+#> [1] 1
+
+

A: Let’s inspect the arguments and their order for both functions. For sum() these are ... and na.rm:

+
+
str(sum)
+#> function (..., na.rm = FALSE)
+
+

For the ... argument sum() expects numeric, complex, or logical vector input (see ?sum). Unfortunately, when ... is used, misspelled arguments (!) like na.omit won’t raise an error (in case of no further input checks). So instead, na.omit is treated as a logical and becomes part of the ... argument. It will be coerced to 1 and be part of the sum. All other arguments are left unchanged. Therefore sum(1, 2, 3) returns 6 and sum(1, 2, 3, na.omit = TRUE) returns 7.

+

In contrast, the generic function mean() expects x, trim, na.rm and ... for its default method.

+
+
str(mean.default)
+#> function (x, trim = 0, na.rm = FALSE, ...)
+
+

As na.omit is not one of mean()’s named arguments (x; and no candidate for partial matching), na.omit again becomes part of the ... argument. However, in contrast to sum() the elements of ... are not “part” of the mean. The other supplied arguments are matched by their order, i.e. x = 1, trim = 2 and na.rm = 3. As x is of length 1 and not NA, the settings of trim and na.rm do not affect the calculation of the mean. Both calls (mean(1, 2, 3) and mean(1, 2, 3, na.omit = TRUE)) return 1.

+

Q2: Explain how to find the documentation for the named arguments in the following function call:

+
+
plot(1:10, col = "red", pch = 20, xlab = "x", col.lab = "blue")
+
+
+
+

+
+
+
+
+

A: First we type ?plot in the console and check the “Usage” section which contains:

+
plot(x, y, ...)
+

The arguments we want to learn more about (col, pch, xlab, col.lab) are part of the ... argument. There we can find information for the xlab argument and a recommendation to visit ?par for the other arguments. Under ?par we type “col” into the search bar, which leads us to the section “Color Specification”. We also search for the pch argument, which leads to the recommendation to check ?points. Finally, col.lab is also directly documented within ?par.

+

Q3: Why does plot(1:10, col = "red") only colour the points, not the axes or labels? Read the source code of plot.default() to find out.

+

A: To learn about the internals of plot.default() we add browser() to the first line of the code and interactively run plot(1:10, col = "red"). This way we can see how the plot is built and learn where the axes are added.

+

This leads us to the function call

+
+
localTitle(main = main, sub = sub, xlab = xlab, ylab = ylab, ...)
+
+

The localTitle() function was defined in the first lines of plot.default() as:

+
+
localTitle <- function(..., col, bg, pch, cex, lty, lwd) title(...)
+
+

The call to localTitle() passes the col parameter as part of the ... argument to title(). ?title tells us that the title() function specifies four parts of the plot: Main (title of the plot), sub (sub-title of the plot) and both axis labels. Therefore, it would introduce ambiguity inside title() to use col directly. Instead, one has the option to supply col via the ... argument, via col.lab or as part of xlab in the form xlab = list(c("index"), col = "red") (similar for ylab).

+
+
+

Exiting a function

+

Q1: What does load() return? Why don’t you normally see these values?

+

A: load() loads objects saved to disk in .Rdata files by save(). When run successfully, load() invisibly returns a character vector containing the names of the newly loaded objects. To print these names to the console, one can set the argument verbose to TRUE or surround the call in parentheses to trigger R’s auto-printing mechanism.

+

Q2: What does write.table() return? What would be more useful?

+

A: write.table() writes an object, usually a data frame or a matrix, to disk. The function invisibly returns NULL. It would be more useful if write.table() would (invisibly) return the input data, x. This would allow to save intermediate results and directly take on further processing steps without breaking the flow of the code (i.e. breaking it into different lines). One package which uses this pattern is the {readr} package (Wickham and Hester 2020), which is part of the tidyverse-ecosystem.

+

Q3: How does the chdir parameter of source() compare to with_dir()? Why might you prefer one to the other?

+

A: The with_dir() approach was given in Advanced R as:

+
+
with_dir <- function(dir, code) {
+  old <- setwd(dir)
+  on.exit(setwd(old))
+
+  force(code)
+}
+
+

with_dir() takes a path for a working directory (dir) as its first argument. This is the directory where the provided code (code) should be executed. Therefore, the current working directory is changed in with_dir() via setwd(). Then, on.exit() ensures that the modification of the working directory is reset to the initial value when the function exits. By passing the path explicitly, the user has full control over the directory to execute the code in.

+

In source() the code is passed via the file argument (a path to a file). The chdir argument specifies if the working directory should be changed to the directory containing the file. The default for chdir is FALSE, so you don’t have to provide a value. However, as you can only provide TRUE or FALSE, you are also less flexible in choosing the working directory for the code execution.

+

Q4: Write a function that opens a graphics device, runs the supplied code, and closes the graphics device (always, regardless of whether or not the plotting code works).

+

A: To control the graphics device we use pdf() and dev.off(). To ensure a clean termination on.exit() is used.

+
+
plot_pdf <- function(code) {
+  pdf("test.pdf")
+  on.exit(dev.off(), add = TRUE)
+  code
+}
+
+

Q5: We can use on.exit() to implement a simple version of capture.output().

+
+
capture.output2 <- function(code) {
+  temp <- tempfile()
+  on.exit(file.remove(temp), add = TRUE, after = TRUE)
+
+  sink(temp)
+  on.exit(sink(), add = TRUE, after = TRUE)
+
+  force(code)
+  readLines(temp)
+}
+capture.output2(cat("a", "b", "c", sep = "\n"))
+#> [1] "a" "b" "c"
+
+

Compare capture.output() to capture.output2(). How do the functions differ? What features have I removed to make the key ideas easier to see? How have I rewritten the key ideas to be easier to understand?

+

A: Using body(capture.output) we inspect the source code of the original capture.output() function: The implementation for capture.output() is quite a bit longer (39 lines vs. 7 lines).

+

In capture_output2() the code is simply forced, and the output is caught via sink() in a temporary file. An additional feature of capture_output() is that one can also capture messages by setting type = "message". As this is internally forwarded to sink(), this behaviour (and also sink()’s split argument) could be easily introduced within capture_output2() as well.

+

The main difference is that capture.output() calls print, i.e. compare the output of these two calls:

+
+
capture.output({
+  1
+})
+#> [1] "[1] 1"
+capture.output2({
+  1
+})
+#> character(0)
+
+
+
+

Function forms

+

Q1: Rewrite the following code snippets into prefix form:

+
+
1 + 2 + 3
+
+1 + (2 + 3)
+
+if (length(x) <= 5) x[[5]] else x[[n]]
+
+

A: Let’s rewrite the expressions to match the exact syntax from the code above. Because prefix functions already define the execution order, we may omit the parentheses in the second expression.

+
+
`+`(`+`(1, 2), 3)
+
+`+`(1, `(`(`+`(2, 3)))
+`+`(1, `+`(2, 3))
+
+`if`(`<=`(length(x), 5), `[[`(x, 5), `[[`(x, n))
+
+

Q2: Clarify the following list of odd function calls:

+
+
x <- sample(replace = TRUE, 20, x = c(1:10, NA))
+y <- runif(min = 0, max = 1, 20)
+cor(m = "k", y = y, u = "p", x = x)
+
+

A: None of these functions provides a ... argument. Therefore, the function arguments are first matched exactly, then via partial matching and finally by position. This leads us to the following explicit function calls:

+
+
x <- sample(c(1:10, NA), size = 20, replace = TRUE)
+y <- runif(20, min = 0, max = 1)
+cor(x, y, use = "pairwise.complete.obs", method = "kendall")
+
+

Q3: Explain why the following code fails:

+
+
modify(get("x"), 1) <- 10
+#> Error: target of assignment expands to non-language object
+
+

A: First, let’s define x and recall the definition of modify() from Advanced R:

+
+
x <- 1:3
+
+`modify<-` <- function(x, position, value) {
+  x[position] <- value
+  x
+}
+
+

R internally transforms the code, and the transformed code reproduces the error above:

+
+
get("x") <- `modify<-`(get("x"), 1, 10)
+#> Error in get("x") <- `modify<-`(get("x"), 1, 10) :
+#>   target of assignment expands to non-language object
+
+

The error occurs during the assignment because no corresponding replacement function, i.e. get<-, exists for get(). To confirm this, we reproduce the error via the following simplified example.

+
+
get("x") <- 2
+#> Error in get("x") <- 2 :
+#>   target of assignment expands to non-language object
+
+

Q4: Create a replacement function that modifies a random location in a vector.

+

A: Let’s define random<- like this:

+
+
`random<-` <- function(x, value) {
+  idx <- sample(length(x), 1)
+  x[idx] <- value
+  x
+}
+
+

Q5: Write your own version of + that pastes its inputs together if they are character vectors but behaves as usual otherwise. In other words, make this code work:

+
+
1 + 2
+#> [1] 3
+
+"a" + "b"
+#> [1] "ab"
+
+

A: To achieve this behaviour, we need to override the + operator. We need to take care to not use the + operator itself inside of the function definition, as this would lead to an undesired infinite recursion. We also add b = 0L as a default value to keep the behaviour of + as a unary operator, i.e. to keep + 1 working and not throwing an error.

+
+
`+` <- function(a, b = 0L) {
+  if (is.character(a) && is.character(b)) {
+    paste0(a, b)
+  } else {
+    base::`+`(a, b)
+  }
+}
+
+# Test
++1
+#> [1] 1
+1 + 2
+#> [1] 3
+"a" + "b"
+#> [1] "ab"
+
+# Return back to the original `+` operator
+rm(`+`)
+
+

Q6: Create a list of all the replacement functions found in the {base} package. Which ones are primitive functions? (Hint use apropos())

+

A: The hint suggests to look for functions with a specific naming pattern: Replacement functions conventionally end on “<-”. We can search for these objects by supplying the regular expression "<-$" to apropos(). apropos() also allows to return the position on the search path (search()) for each of its matches via setting where = TRUE. Finally, we can set mode = function to narrow down our search to relevant objects only. This gives us the following statement to begin with:

+
+
repls <- apropos("<-", where = TRUE, mode = "function")
+head(repls, 30)
+#>                     12                     12                     12 
+#>        ".rowNamesDF<-"                 "[[<-"      "[[<-.data.frame" 
+#>                     12                     12                     12 
+#>          "[[<-.factor" "[[<-.numeric_version"         "[[<-.POSIXlt" 
+#>                     12                     12                     12 
+#>                  "[<-"       "[<-.data.frame"             "[<-.Date" 
+#>                     12                     12                     12 
+#>         "[<-.difftime"           "[<-.factor"  "[<-.numeric_version" 
+#>                     12                     12                     12 
+#>          "[<-.POSIXct"          "[<-.POSIXlt"                  "@<-" 
+#>                     12                     12                     12 
+#>                   "<-"                  "<<-"                  "$<-" 
+#>                     12                     12                     10 
+#>       "$<-.data.frame"          "$<-.POSIXlt"                 "as<-" 
+#>                     12                     12                     10 
+#>               "attr<-"         "attributes<-"               "body<-" 
+#>                     12                     12                     10 
+#>               "body<-"              "class<-"             "coerce<-" 
+#>                     12                     12                      3 
+#>           "colnames<-"            "comment<-"          "contrasts<-"
+
+

To restrict repl to names of replacement functions from the {base} package, we select only matches containing the relevant position on the search path.

+
+
repls_base <- repls[names(repls) == length(search())]
+repls_base
+#>                        12                        12                        12 
+#>           ".rowNamesDF<-"                    "[[<-"         "[[<-.data.frame" 
+#>                        12                        12                        12 
+#>             "[[<-.factor"    "[[<-.numeric_version"            "[[<-.POSIXlt" 
+#>                        12                        12                        12 
+#>                     "[<-"          "[<-.data.frame"                "[<-.Date" 
+#>                        12                        12                        12 
+#>            "[<-.difftime"              "[<-.factor"     "[<-.numeric_version" 
+#>                        12                        12                        12 
+#>             "[<-.POSIXct"             "[<-.POSIXlt"                     "@<-" 
+#>                        12                        12                        12 
+#>                      "<-"                     "<<-"                     "$<-" 
+#>                        12                        12                        12 
+#>          "$<-.data.frame"             "$<-.POSIXlt"                  "attr<-" 
+#>                        12                        12                        12 
+#>            "attributes<-"                  "body<-"                 "class<-" 
+#>                        12                        12                        12 
+#>              "colnames<-"               "comment<-"                  "diag<-" 
+#>                        12                        12                        12 
+#>                   "dim<-"              "dimnames<-"   "dimnames<-.data.frame" 
+#>                        12                        12                        12 
+#>              "Encoding<-"           "environment<-"               "formals<-" 
+#>                        12                        12                        12 
+#>                 "is.na<-"         "is.na<-.default"          "is.na<-.factor" 
+#>                        12                        12                        12 
+#> "is.na<-.numeric_version"                "length<-"           "length<-.Date" 
+#>                        12                        12                        12 
+#>       "length<-.difftime"         "length<-.factor"        "length<-.POSIXct" 
+#>                        12                        12                        12 
+#>        "length<-.POSIXlt"                "levels<-"         "levels<-.factor" 
+#>                        12                        12                        12 
+#>                  "mode<-"        "mostattributes<-"                 "names<-" 
+#>                        12                        12                        12 
+#>         "names<-.POSIXlt"              "oldClass<-"            "parent.env<-" 
+#>                        12                        12                        12 
+#>            "regmatches<-"             "row.names<-"  "row.names<-.data.frame" 
+#>                        12                        12                        12 
+#>     "row.names<-.default"              "rownames<-"                 "split<-" 
+#>                        12                        12                        12 
+#>      "split<-.data.frame"         "split<-.default"          "storage.mode<-" 
+#>                        12                        12                        12 
+#>                "substr<-"             "substring<-"                 "units<-" 
+#>                        12 
+#>        "units<-.difftime"
+
+

To find out which of these functions are primitives, we first search for these functions via mget() and then subset the result using Filter() and is.primitive().

+
+
repls_base_prim <- mget(repls_base, envir = baseenv()) %>%
+  Filter(is.primitive, .) %>%
+  names()
+
+repls_base_prim
+#>  [1] "[[<-"           "[<-"            "@<-"            "<-"            
+#>  [5] "<<-"            "$<-"            "attr<-"         "attributes<-"  
+#>  [9] "class<-"        "dim<-"          "dimnames<-"     "environment<-" 
+#> [13] "length<-"       "levels<-"       "names<-"        "oldClass<-"    
+#> [17] "storage.mode<-"
+
+

Overall the {base} package contains 64 replacement functions of which 17 are primitive functions.

+

Q7: What are valid names for user-created infix functions?

+

A: Let’s cite from the section on function forms from Advanced R:

+
+

… names of infix functions are more flexible than regular R functions: they can contain any sequence of characters except “%”.

+
+

Q8: Create an infix xor() operator.

+

A: We could create an infix %xor% like this:

+
+
`%xor%` <- function(a, b) {
+  xor(a, b)
+}
+TRUE %xor% TRUE
+#> [1] FALSE
+FALSE %xor% TRUE
+#> [1] TRUE
+
+

Q9: Create infix versions of the set functions intersect(), union(), and setdiff(). You might call them %n%, %u%, and %/% to match conventions from mathematics.

+

A: These infix operators could be defined in the following way. (%/% is chosen instead of %\%, because \ serves as an escape character.)

+
+
`%n%` <- function(a, b) {
+  intersect(a, b)
+}
+
+`%u%` <- function(a, b) {
+  union(a, b)
+}
+
+`%/%` <- function(a, b) {
+  setdiff(a, b)
+}
+
+x <- c("a", "b", "d")
+y <- c("a", "c", "d")
+
+x %u% y
+#> [1] "a" "b" "d" "c"
+x %n% y
+#> [1] "a" "d"
+x %/% y
+#> [1] "b"
+
+
+
+

References

+ + +
+
+Wickham, Hadley, and Jim Hester. 2020. Readr: Read Rectangular Text Data. https://github.com/tidyverse/readr. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/07_Environments.html b/docs/07_Environments.html new file mode 100644 index 00000000..4c895c81 --- /dev/null +++ b/docs/07_Environments.html @@ -0,0 +1,1032 @@ + + + + + + + + + + +Advanced R Solutions - 7 Environments + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

7 Environments

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

Just like in Advanced R, we mainly use the {rlang} package (Henry and Wickham 2020) to work with environments.

+
+
library(rlang)
+
+
+
+

Environment basics

+

Q1: List three ways in which an environment differs from a list.

+

A: The most important differences between environments and lists are:

+
    +
  • environments have reference semantics (i.e. they don’t copy-on-modify)
  • +
  • environments have parents
  • +
  • the contents of an environment must have unique names
  • +
  • the contents of an environment are not ordered
  • +
  • (environments can only be compared via identical(); not with ==)
  • +
  • (environments can contain themselves)
  • +
+

Q2: Create an environment as illustrated by this picture.

+
+
+
+
+

+
+
+
+
+

A: Let’s create an environment that contains itself.

+
+
e1 <- env()
+e1$loop <- e1
+
+# Print the environment
+env_print(e1)
+#> <environment: 0x590c00c194d0>
+#> Parent: <environment: global>
+#> Bindings:
+#> • loop: <env>
+
+# Verify that it contains itself
+lobstr::ref(e1)
+#> █ [1:0x590c00c194d0] <env> 
+#> └─loop = [1:0x590c00c194d0]
+
+

Q3: Create a pair of environments as illustrated by this picture.

+
+
+
+
+

+
+
+
+
+

A: These two environments contain each other:

+
+
e1 <- env()
+e2 <- env()
+
+e1$loop <- e2
+e2$dedoop <- e1
+
+lobstr::ref(e1)
+#> █ [1:0x590c00f0d1d8] <env> 
+#> └─loop = █ [2:0x590c00f8e0a8] <env> 
+#>          └─dedoop = [1:0x590c00f0d1d8]
+lobstr::ref(e2)
+#> █ [1:0x590c00f8e0a8] <env> 
+#> └─dedoop = █ [2:0x590c00f0d1d8] <env> 
+#>            └─loop = [1:0x590c00f8e0a8]
+
+

Q4: Explain why e[[1]] and e[c("a", "b")] don’t make sense when e is an environment.

+

A: The first option doesn’t make sense, because elements of an environment are not ordered. The second option would return two objects at the same time. What data structure would they be contained inside?

+

Q5: Create a version of env_poke() that will only bind new names, never re-bind old names. Some programming languages only do this, and are known as single assignment languages.

+

A: As described in Advanced R rlang::env_poke() takes a name (as string) and a value to assign (or reassign) a binding in an environment.

+
+
e3 <- new.env()
+
+env_poke(e3, "a", 100)
+e3$a
+#> [1] 100
+env_poke(e3, "a", 200)
+e3$a
+#> [1] 200
+
+

So, we want env_poke2() to test, if the supplied name is already present in the given environment. This can be checked via env_has(). If this is the case, an (informative) error is thrown.

+
+
env_poke2 <- function(env, name, value) {
+  if (env_has(env, name)) {
+    abort(paste0("\"", name, "\" is already assigned to a value."))
+  }
+
+  env_poke(env, name, value)
+  invisible(env)
+}
+
+# Test
+env_poke2(e3, "b", 100)
+e3$b
+#> [1] 100
+env_poke2(e3, "b", 200)
+#> Error in `env_poke2()`:
+#> ! "b" is already assigned to a value.
+
+

Q6: What does this function do? How does it differ from <<- and why might you prefer it?

+
+
rebind <- function(name, value, env = caller_env()) {
+  if (identical(env, empty_env())) {
+    stop("Can't find `", name, "`", call. = FALSE)
+  } else if (env_has(env, name)) {
+    env_poke(env, name, value)
+  } else {
+    rebind(name, value, env_parent(env))
+  }
+}
+rebind("a", 10)
+#> Error: Can't find `a`
+a <- 5
+rebind("a", 10)
+a
+#> [1] 10
+
+

A: The primary difference between rebind() and <<- is that rebind() will only carry out an assignment when it finds an existing binding; unlike <<- it will never create a new one in the global environment. This behaviour of <<- is usually undesirable because global variables introduce non-obvious dependencies between functions.

+
+
+

Recursing over environments

+

Q1: Modify where() to return all environments that contain a binding for name. Carefully think through what type of object the function will need to return.

+

A: where() searches (recursively) for a given name within a given environment and its ancestors. If where() finds the name in one of these environments, it returns the environment’s name. Otherwise, it throws an error.

+

The definition of where() was given in Advanced R as:

+
+
where <- function(name, env = caller_env()) {
+  if (identical(env, empty_env())) {
+    # Base case
+    stop("Can't find `", name, "`.", call. = FALSE)
+  } else if (env_has(env, name)) {
+    # Success case
+    env
+  } else {
+    # Recursive case
+    where(name, env_parent(env))
+  }
+}
+
+

Our modified version of where() will always recurse until it reaches the empty environment. No matter if it has already found the name or not. Along the way, it will check each environment for the given name. Finally, it will return a list of environments where the binding was found; if no binding was found, the list will be empty.

+

Please also note how the list is initialised via the default argument, when the function is called for the first time. This is a bit confusing, which is why it’s common to wrap a recursive function inside another, more user friendly, function.

+
+
where2 <- function(name, env = caller_env(), results = list()) {
+  if (identical(env, empty_env())) {
+    # Base case
+    results
+  } else {
+    # Recursive case
+    if (env_has(env, name)) {
+      results <- c(results, env)
+    }
+    where2(name, env_parent(env), results)
+  }
+}
+
+# Test
+e1a <- env(empty_env(), a = 1, b = 2)
+e1b <- env(e1a, b = 10, c = 11)
+e1c <- env(e1b, a = 12, d = 13)
+
+where2("a", e1c)
+#> [[1]]
+#> <environment: 0x590bff309938>
+#> 
+#> [[2]]
+#> <environment: 0x590bff08c7a8>
+
+

Q2: Write a function called fget() that finds only function objects. It should have two arguments, name and env, and should obey the regular scoping rules for functions: if there’s an object with a matching name that’s not a function, look in the parent. For an added challenge, also add an inherits argument which controls whether the function recurses up the parents or only looks in one environment.

+

A: We follow a similar approach to the previous exercise. This time we additionally check if the found object is a function and implement an argument to turn off the recursion, if desired.

+
+
fget <- function(name, env = caller_env(), inherits = TRUE) {
+  # Base case
+  if (env_has(env, name)) {
+    obj <- env_get(env, name)
+
+    if (is.function(obj)) {
+      return(obj)
+    }
+  }
+
+  if (identical(env, emptyenv()) || !inherits) {
+    stop("Could not find a function called \"", name, "\".",
+      call. = FALSE
+    )
+  }
+
+  # Recursive Case
+  fget(name, env_parent(env))
+}
+
+# Test
+mean <- 10
+fget("mean", inherits = TRUE)
+#> function (x, ...) 
+#> UseMethod("mean")
+#> <bytecode: 0x590bfe4e2010>
+#> <environment: namespace:base>
+
+
+
+

Special environments

+

Q1: How is search_envs() different to env_parents(global_env())?

+

A: search_envs() returns all the environments on the search path, which is “a chain of environments containing exported functions of attached packages” (from ?search_envs). Every time you attach a new package, this search path will grow. The search path ends with the base-environment. The global environment is included, because functions present in the global environment will always be part of the search path.

+
+
search_envs()
+#>  [[1]] $ <env: global>
+#>  [[2]] $ <env: package:rlang>
+#>  [[3]] $ <env: package:stats>
+#>  [[4]] $ <env: package:graphics>
+#>  [[5]] $ <env: package:grDevices>
+#>  [[6]] $ <env: package:datasets>
+#>  [[7]] $ <env: package:devtools>
+#>  [[8]] $ <env: package:usethis>
+#>  [[9]] $ <env: package:utils>
+#> [[10]] $ <env: package:methods>
+#> [[11]] $ <env: Autoloads>
+#> [[12]] $ <env: package:base>
+
+

env_parents(global_env()) will list all the ancestors of the global environment, therefore the global environment itself is not included. This also includes the “ultimate ancestor”, the empty environment. This environment is not considered part of the search path because it contains no objects.

+
+
env_parents(global_env())
+#>  [[1]] $ <env: package:rlang>
+#>  [[2]] $ <env: package:stats>
+#>  [[3]] $ <env: package:graphics>
+#>  [[4]] $ <env: package:grDevices>
+#>  [[5]] $ <env: package:datasets>
+#>  [[6]] $ <env: package:devtools>
+#>  [[7]] $ <env: package:usethis>
+#>  [[8]] $ <env: package:utils>
+#>  [[9]] $ <env: package:methods>
+#> [[10]] $ <env: Autoloads>
+#> [[11]] $ <env: package:base>
+#> [[12]] $ <env: empty>
+
+

Q2: Draw a diagram that shows the enclosing environments of this function:

+
+
f1 <- function(x1) {
+  f2 <- function(x2) {
+    f3 <- function(x3) {
+      x1 + x2 + x3
+    }
+    f3(3)
+  }
+  f2(2)
+}
+f1(1)
+
+

A: This exercise urges us to think carefully about the function environment at creation time.

+

When f1 is defined it binds its parent environment, which is the global environment. But f2 will only be created at runtime of f1 and will therefore bind f1’s execution environment. The value 1 will also bind to the name x1 at execution time. The same holds true for x2, f3 and x3.

+

The following diagram visualises the relations between the function environments.

+
+
+
+
+

+
+
+
+
+

We can also inspect the binding of the environments, adding print statements to the function definition. Please note that these print statements will be evaluated at execution time. Therefore, the execution of f1(1) will print different results each time we run it.

+
+
f1 <- function(x1) {
+  f2 <- function(x2) {
+    f3 <- function(x3) {
+      x1 + x2 + x3
+      print("f3")
+      print(env_print())
+    }
+    f3(3)
+    print("f2")
+    print(env_print())
+  }
+  f2(2)
+  print("f1")
+  print(env_print())
+}
+
+f1(1)
+#> [1] "f3"
+#> <environment: 0x590bfc014578>
+#> Parent: <environment: 0x590bfc0143b8>
+#> Bindings:
+#> • x3: <dbl>
+#> <environment: 0x590bfc014578>
+#> [1] "f2"
+#> <environment: 0x590bfc0143b8>
+#> Parent: <environment: 0x590bfc013fc8>
+#> Bindings:
+#> • f3: <fn>
+#> • x2: <dbl>
+#> <environment: 0x590bfc0143b8>
+#> [1] "f1"
+#> <environment: 0x590bfc013fc8>
+#> Parent: <environment: global>
+#> Bindings:
+#> • f2: <fn>
+#> • x1: <dbl>
+#> <environment: 0x590bfc013fc8>
+
+

Q3: Write an enhanced version of str() that provides more information about functions. Show where the function was found and what environment it was defined in.

+

A: To solve this problem, we need to write a function that takes the name of a function and looks for that function returning both the function and the environment that it was found in.

+
+
fget2 <- function(name, env = caller_env()) {
+  # Base case
+  if (env_has(env, name)) {
+    obj <- env_get(env, name)
+
+    if (is.function(obj)) {
+      return(list(fun = obj, env = env))
+    }
+  }
+
+  if (identical(env, emptyenv())) {
+    stop("Could not find a function called \"", name, "\"",
+      call. = FALSE
+    )
+  }
+
+  # Recursive Case
+  fget2(name, env_parent(env))
+}
+
+fstr <- function(fun_name, env = caller_env()) {
+  if (!is.character(fun_name) && length(fun_name) == 1) {
+    stop("`fun_name` must be a string.", call. = FALSE)
+  }
+  fun_env <- fget2(fun_name, env)
+
+  list(
+    where = fun_env$env,
+    enclosing = fn_env(fun_env$fun)
+  )
+}
+
+# Test
+fstr("mean")
+#> $where
+#> <environment: base>
+#> 
+#> $enclosing
+#> <environment: namespace:base>
+
+

Once you have learned about tidy evaluation, you could rewrite fstr() to use enquo() so that you’d call it more like str(), i.e. fstr(sum).

+
+
+

Call stacks

+

Q1: Write a function that lists all the variables defined in the environment in which it was called. It should return the same results as ls().

+

A: We can implement this dynamic scoping behaviour by explicitly referencing the caller environment. Please note that this approach returns also variables starting with a dot, an option that ls() usually requires.

+
+
ls2 <- function(env = caller_env()) {
+  sort(env_names(env))
+}
+
+# Test in global environment
+ls(all.names = TRUE)
+#>  [1] ".main"           ".Random.seed"    "%>%"             "a"              
+#>  [5] "e1"              "e1a"             "e1b"             "e1c"            
+#>  [9] "e2"              "e3"              "env_poke2"       "error_wrap"     
+#> [13] "f1"              "fget"            "fget2"           "fstr"           
+#> [17] "has_annotations" "ls2"             "mean"            "rebind"         
+#> [21] "where"           "where2"
+ls2()
+#>  [1] ".main"           ".Random.seed"    "%>%"             "a"              
+#>  [5] "e1"              "e1a"             "e1b"             "e1c"            
+#>  [9] "e2"              "e3"              "env_poke2"       "error_wrap"     
+#> [13] "f1"              "fget"            "fget2"           "fstr"           
+#> [17] "has_annotations" "ls2"             "mean"            "rebind"         
+#> [21] "where"           "where2"
+
+# Test in "sandbox" environment
+e1 <- env(a = 1, b = 2)
+ls(e1)
+#> [1] "a" "b"
+ls2(e1)
+#> [1] "a" "b"
+
+
+
+

References

+ + +
+
+Henry, Lionel, and Hadley Wickham. 2020. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/08_Conditions.html b/docs/08_Conditions.html new file mode 100644 index 00000000..08e9c883 --- /dev/null +++ b/docs/08_Conditions.html @@ -0,0 +1,1054 @@ + + + + + + + + + + +Advanced R Solutions - 8 - Conditions + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

8 - Conditions

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

Similar to the environments chapter, we also use functions from the {rlang} package to work with conditions.

+
+
library(rlang)
+
+
+
+

Signalling conditions

+

Q1: Write a wrapper around file.remove() that throws an error if the file to be deleted does not exist.

+

A: We prefer the following solution for its clarity and simplicity:

+
+
file_remove_strict <- function(path) {
+  if (!file.exists(path)) {
+    stop("Can't delete the file \"", path,
+      "\" because it doesn't exist.",
+      call. = FALSE
+    )
+  }
+  file.remove(path)
+}
+
+# Test
+saveRDS(mtcars, "mtcars.rds")
+file_remove_strict("mtcars.rds")
+#> [1] TRUE
+file_remove_strict("mtcars.rds")
+#> Error: Can't delete the file "mtcars.rds" because it doesn't exist.
+
+

Q2: What does the appendLF argument to message() do? How is it related to cat()?

+

A: The appendLF argument automatically appends a new line to the message. Let’s illustrate this behaviour with a small example function:

+
+
multiline_msg <- function(appendLF = TRUE) {
+  message("first", appendLF = appendLF)
+  message("second", appendLF = appendLF)
+  cat("third")
+  cat("fourth")
+}
+
+multiline_msg(appendLF = TRUE)
+#> first
+#> second
+#> thirdfourth
+multiline_msg(appendLF = FALSE)
+#> firstsecondthirdfourth
+
+

Comparable behaviour regarding line breaks for cat() can be achieved via setting its sep argument to "\n".

+
+
+

Handling conditions

+

Q1: What extra information does the condition generated by abort() contain compared to the condition generated by stop(), i.e. what’s the difference between these two objects? Read the help for ?abort to learn more.

+
+
catch_cnd(stop("An error"))
+catch_cnd(abort("An error"))
+
+

A: In contrast to stop(), which contains the call, abort() stores the whole backtrace generated by rlang::trace_back(). This is a lot of extra data!

+
+
str(catch_cnd(stop("An error")))
+#> List of 2
+#>  $ message: chr "An error"
+#>  $ call   : language force(expr)
+#>  - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
+
+str(catch_cnd(abort("An error")))
+#> List of 5
+#>  $ message: chr "An error"
+#>  $ trace  :Classes 'rlang_trace', 'rlib_trace', 'tbl' and 'data.frame':  9 obs...
+#>   ..$ call       :List of 9
+#>   .. ..$ : language str(catch_cnd(abort("An error")))
+#>   .. ..$ : language catch_cnd(abort("An error"))
+#>   .. ..$ : language eval_bare(rlang::expr(tryCatch(!!!handlers, {     force(ex..
+#>   .. ..$ : language tryCatch(condition = `<fn>`, {     force(expr) ...
+#>   .. ..$ : language tryCatchList(expr, classes, parentenv, handlers)
+#>   .. ..$ : language tryCatchOne(expr, names, parentenv, handlers[[1L]])
+#>   .. ..$ : language doTryCatch(return(expr), name, parentenv, handler)
+#>   .. ..$ : language force(expr)
+#>   .. ..$ : language abort("An error")
+#>   ..$ parent     : int [1:9] 0 0 2 2 4 5 6 2 0
+#>   ..$ visible    : logi [1:9] FALSE FALSE FALSE FALSE FALSE FALSE ...
+#>   ..$ namespace  : chr [1:9] "utils" "rlang" "rlang" "base" ...
+#>   ..$ scope      : chr [1:9] "::" "::" "::" "::" ...
+#>   ..$ error_frame: logi [1:9] FALSE FALSE FALSE FALSE FALSE FALSE ...
+#>   ..- attr(*, "version")= int 2
+#>  $ parent : NULL
+#>  $ rlang  :List of 1
+#>   ..$ inherit: logi TRUE
+#>  $ call   : NULL
+#>  - attr(*, "class")= chr [1:3] "rlang_error" "error" "condition"
+
+

Q2: Predict the results of evaluating the following code

+
+
show_condition <- function(code) {
+  tryCatch(
+    error = function(cnd) "error",
+    warning = function(cnd) "warning",
+    message = function(cnd) "message",
+    {
+      code
+      NULL
+    }
+  )
+}
+
+
+show_condition(stop("!"))
+show_condition(10)
+show_condition(warning("?!"))
+show_condition({
+  10
+  message("?")
+  warning("?!")
+})
+
+

A: The first three examples are straightforward:

+
+
show_condition(stop("!")) # stop raises an error
+#> [1] "error"
+show_condition(10) # no condition is signalled
+#> NULL
+show_condition(warning("?!")) # warning raises a warning
+#> [1] "warning"
+
+

The last example is the most interesting and makes us aware of the exiting qualities of tryCatch(); it will terminate the evaluation of the code as soon as it is called.

+
+
show_condition({
+  10
+  message("?")
+  warning("?!")
+})
+#> [1] "message"
+
+

Q3: Explain the results of running this code:

+
+
withCallingHandlers( # (1)
+  message = function(cnd) message("b"),
+  withCallingHandlers( # (2)
+    message = function(cnd) message("a"),
+    message("c")
+  )
+)
+#> b
+#> a
+#> b
+#> c
+
+

A: It’s a little tricky to untangle the flow here:

+

First, message("c") is run, and it’s caught by (1). It then calls message("a"), which is caught by (2), which calls message("b"). message("b") isn’t caught by anything, so we see a b on the console, followed by a. But why do we get another b before we see c? That’s because we haven’t handled the message, so it bubbles up to the outer calling handler.

+

Q4: Read the source code for catch_cnd() and explain how it works. At the time Advanced R was written, the source for catch_cnd() was a little simpler:

+
+
catch_cnd <- function(expr) {
+  tryCatch(
+    condition = function(cnd) cnd,
+    {
+      force(expr)
+      return(NULL)
+    }
+  )
+}
+
+

A: catch_cnd() is a simple wrapper around tryCatch(). If a condition is signalled, it’s caught and returned. If no condition is signalled, execution proceeds sequentially and the function returns NULL.

+

The current version of catch_cnd() is a little more complex because it allows you to specify which classes of condition you want to capture. This requires some manual code generation because the interface of tryCatch() provides condition classes as argument names.

+
+
rlang::catch_cnd
+#> function (expr, classes = "condition") 
+#> {
+#>     stopifnot(is_character(classes))
+#>     handlers <- rep_named(classes, list(identity))
+#>     eval_bare(rlang::expr(tryCatch(!!!handlers, {
+#>         force(expr)
+#>         return(NULL)
+#>     })))
+#> }
+#> <bytecode: 0x59a31a9d0fd8>
+#> <environment: namespace:rlang>
+
+

Q5: How could you rewrite show_condition() to use a single handler?

+

A: show_condition() was defined in one of the previous questions. Let’s use the condition argument of tryCatch() as shown in rlang::catch_cond() above for our re-implementation:

+
+
show_condition2 <- function(code) {
+  tryCatch(
+    condition = function(cnd) {
+      if (inherits(cnd, "error")) {
+        return("error")
+      }
+      if (inherits(cnd, "warning")) {
+        return("warning")
+      }
+      if (inherits(cnd, "message")) {
+        return("message")
+      }
+    },
+    {
+      code
+      NULL
+    }
+  )
+}
+
+# Test
+show_condition2(stop("!"))
+#> [1] "error"
+show_condition2(10)
+#> NULL
+show_condition2(warning("?!"))
+#> [1] "warning"
+show_condition2({
+  10
+  message("?")
+  warning("?!")
+})
+#> [1] "message"
+
+

tryCatch() executes the code and captures any condition raised. The function provided as the condition handles this condition. In this case it dispatches on the class of the condition.

+
+
+

Custom conditions

+

Q1: Inside a package, it’s occasionally useful to check that a package is installed before using it. Write a function that checks if a package is installed (with requireNamespace("pkg", quietly = FALSE)) and if not, throws a custom condition that includes the package name in the metadata.

+

A: We use rlang::abort() to supply error metadata:

+
+
check_installed <- function(package) {
+  if (!requireNamespace(package, quietly = FALSE)) {
+    abort(
+      "error_pkg_not_found",
+      message = paste0("package '", package, "' not installed."),
+      package = package
+    )
+  }
+
+  TRUE
+}
+
+check_installed("ggplot2")
+#> [1] TRUE
+check_installed("ggplot3")
+#> Loading required namespace: ggplot3
+#> Error in `check_installed()`:
+#> ! package 'ggplot3' not installed.
+
+

Q2: Inside a package you often need to stop with an error when something is not right. Other packages that depend on your package might be tempted to check these errors in their unit tests. How could you help these packages to avoid relying on the error message which is part of the user interface rather than the API and might change without notice?

+

A: Instead of returning an error it might be preferable to throw a customised condition and place a standardised error message inside the metadata. Then the downstream package could check for the class of the condition, rather than inspecting the message.

+
+
+

Applications

+

Q1: Create suppressConditions() that works like suppressMessages() and suppressWarnings() but suppresses everything. Think carefully about how you should handle errors.

+

A: In general, we would like to catch errors, since they contain important information for debugging. To suppress the error message and hide the returned error object from the console, we handle errors within a tryCatch() and return the error object invisibly:

+
+
suppressErrors <- function(expr) {
+  tryCatch(
+    error = function(cnd) invisible(cnd),
+    interrupt = function(cnd) {
+      stop("Terminated by the user.",
+        call. = FALSE
+      )
+    },
+    expr
+  )
+}
+
+

After we defined the error handling, we can just combine it with the other handlers to create suppressConditions():

+
+
suppressConditions <- function(expr) {
+  suppressErrors(suppressWarnings(suppressMessages(expr)))
+}
+
+

To test the new function, we apply it to a set of conditions and inspect the returned error object.

+
+
# The messages/warnings/conditions are suppressed successfully
+error_obj <- suppressConditions({
+  message("message")
+  warning("warning")
+  abort("error")
+})
+
+error_obj
+#> <error/rlang_error>
+#> Error:
+#> ! error
+#> ---
+#> Backtrace:
+#> ▆
+
+

Q2: Compare the following two implementations of message2error(). What is the main advantage of withCallingHandlers() in this scenario? (Hint: look carefully at the traceback.)

+
+
message2error <- function(code) {
+  withCallingHandlers(code, message = function(e) stop(e))
+}
+message2error <- function(code) {
+  tryCatch(code, message = function(e) stop(e))
+}
+
+

A: Both functions differ in the way conditions are handled. withCallingHandlers() creates a calling handler, which is executed from within the signalling function. This makes it possible to record a detailed call stack, which helps us identify the signalling condition.

+

tryCatch() defines an exiting handler, which means that the signalling function is terminated as soon as a condition is raised. It also returns control to the context where tryCatch() was called.

+

In this example the use of withCallingHandlers() returns more information than the use of tryCatch(). This allows us to determine the exact call that raised the condition.

+
+
message2error1 <- function(code) {
+  withCallingHandlers(code, message = function(e) stop("error"))
+}
+
+message2error1({
+  1
+  message("hidden error")
+  NULL
+})
+#> Error in (function (e) : error
+traceback()
+#> 9: stop("error") at #2
+#> 8: (function (e)
+#>    stop("error"))(list(message = "hidden error\n",
+#>      call = message("hidden error")))
+#> 7: signalCondition(cond)
+#> 6: doWithOneRestart(return(expr), restart)
+#> 5: withOneRestart(expr, restarts[[1L]])
+#> 4: withRestarts({
+#>        signalCondition(cond)
+#>        defaultHandler(cond)
+#>    }, muffleMessage = function() NULL)
+#> 3: message("hidden error") at #1
+#> 2: withCallingHandlers(code,
+#>      message = function(e) stop("error")) at #2
+#> 1: message2error1({
+#>        1
+#>        message("hidden error")
+#>        NULL
+#>    })
+
+
+
message2error2 <- function(code) {
+  tryCatch(code, message = function(e) (stop("error")))
+}
+
+message2error2({
+  1
+  stop("hidden error")
+  NULL
+})
+#> Error in value[[3L]](cond) : error
+traceback()
+#> 6: stop("error") at #2
+#> 5: value[[3L]](cond)
+#> 4: tryCatchOne(expr, names, parentenv, handlers[[1L]])
+#> 3: tryCatchList(expr, classes, parentenv, handlers)
+#> 2: tryCatch(code, message = function(e) (stop("error"))) at #2
+#> 1: message2error2({
+#>        1
+#>        message("hidden error")
+#>        NULL
+#>    })
+
+

Q3: How would you modify the catch_cnds() definition if you wanted to recreate the original intermingling of warnings and messages?

+

A: It looks like Hadley wrote a part of the chapter after the exercises, as the catch_cnds() function defined in the chapter already solves this problem by storing all messages and warnings in their original order within a list.

+
+
catch_cnds <- function(expr) {
+  conds <- list()
+  add_cond <- function(cnd) {
+    conds <<- append(conds, list(cnd))
+    cnd_muffle(cnd)
+  }
+
+  tryCatch(
+    error = function(cnd) {
+      conds <<- append(conds, list(cnd))
+    },
+    withCallingHandlers(
+      message = add_cond,
+      warning = add_cond,
+      expr
+    )
+  )
+
+  conds
+}
+
+# Test
+catch_cnds({
+  inform("message a")
+  warn("warning b")
+  inform("message c")
+})
+#> [[1]]
+#> <message/rlang_message>
+#> Message:
+#> message a
+#> 
+#> [[2]]
+#> <warning/rlang_warning>
+#> Warning:
+#> warning b
+#> 
+#> [[3]]
+#> <message/rlang_message>
+#> Message:
+#> message c
+
+

Q4: Why is catching interrupts dangerous? Run this code to find out.

+
+
bottles_of_beer <- function(i = 99) {
+  message(
+    "There are ", i,
+    " bottles of beer on the wall, ", i,
+    " bottles of beer."
+  )
+  while (i > 0) {
+    tryCatch(
+      Sys.sleep(1),
+      interrupt = function(err) {
+        i <<- i - 1
+        if (i > 0) {
+          message(
+            "Take one down, pass it around, ", i,
+            " bottle", if (i > 1) "s", " of beer on the wall."
+          )
+        }
+      }
+    )
+  }
+  message(
+    "No more bottles of beer on the wall, ",
+    "no more bottles of beer."
+  )
+}
+
+

A: When running the bottles_of_beer() function in your console, the output should look somehow like the following:

+
+
bottles_of_beer()
+#> There are 99 bottles of beer on the wall, 99 bottles of beer.
+#> Take one down, pass it around, 98 bottles of beer on the wall.
+#> Take one down, pass it around, 97 bottles of beer on the wall.
+#> Take one down, pass it around, 96 bottles of beer on the wall.
+#> Take one down, pass it around, 95 bottles of beer on the wall.
+#>
+
+

At this point you’ll probably recognise how hard it is to get the number of bottles down from 99 to 0. There’s no way to break out of the function because we’re capturing the interrupt that you’d usually use!

+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/09_Functionals.html b/docs/09_Functionals.html new file mode 100644 index 00000000..27fe7662 --- /dev/null +++ b/docs/09_Functionals.html @@ -0,0 +1,1082 @@ + + + + + + + + + + +Advanced R Solutions - 9 - Functionals + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

9 - Functionals

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

For the functional programming part of the book, we will mainly use functions from the {purrr} package (Henry and Wickham 2020).

+
+
library(purrr)
+
+
+
+

My first functional: map()

+

Q1: Use as_mapper() to explore how {purrr} generates anonymous functions for the integer, character, and list helpers. What helper allows you to extract attributes? Read the documentation to find out.

+

A: map() offers multiple ways (functions, formulas, and extractor functions) to specify its function argument (.f). Initially, the various inputs have to be transformed into a valid function, which is then applied. The creation of this valid function is the job of as_mapper() and it is called every time map() is used.

+

Given character, numeric or list input as_mapper() will create an extractor function. Characters select by name, while numeric input selects by positions and a list allows a mix of these two approaches. This extractor interface can be very useful, when working with nested data.

+

The extractor function is implemented as a call to purrr::pluck(), which accepts a list of accessors (accessors “access” some part of your data object).

+
+
as_mapper(c(1, 2)) # equivalent to function(x) x[[1]][[2]]
+#> function (x, ...) 
+#> pluck_raw(x, list(1, 2), .default = NULL)
+#> <environment: 0x5d63c648c988>
+as_mapper(c("a", "b")) # equivalent to function(x) x[["a"]][["b]]
+#> function (x, ...) 
+#> pluck_raw(x, list("a", "b"), .default = NULL)
+#> <environment: 0x5d63c64eb4d0>
+as_mapper(list(1, "b")) # equivalent to function(x) x[[1]][["b]]
+#> function (x, ...) 
+#> pluck_raw(x, list(1, "b"), .default = NULL)
+#> <environment: 0x5d63c660f0b8>
+
+

Besides mixing positions and names, it is also possible to pass along an accessor function. This is basically an anonymous function that gets information about some aspect of the input data. You are free to define your own accessor functions.

+

If you need to access certain attributes, the helper attr_getter(y) is already predefined and will create the appropriate accessor function for you.

+
+
# Define custom accessor function
+get_class <- function(x) attr(x, "class")
+pluck(mtcars, get_class)
+#> [1] "data.frame"
+
+# Use attr_getter() as a helper
+pluck(mtcars, attr_getter("class"))
+#> [1] "data.frame"
+
+

Q2: map(1:3, ~ runif(2)) is a useful pattern for generating random numbers, but map(1:3, runif(2)) is not. Why not? Can you explain why it returns the result that it does?

+

A: The first pattern creates multiple random numbers, because ~ runif(2) successfully uses the formula interface. Internally map() applies as_mapper() to this formula, which converts ~ runif(2) into an anonymous function. Afterwards runif(2) is applied three times (one time during each iteration), leading to three different pairs of random numbers.

+

In the second pattern runif(2) is evaluated once, then the results are passed to map(). Consequently as_mapper() creates an extractor function based on the return values from runif(2) (via pluck()). This leads to three NULLs (pluck()’s .default return), because no values corresponding to the index can be found.

+
+
as_mapper(~ runif(2))
+#> <lambda>
+#> function (..., .x = ..1, .y = ..2, . = ..1) 
+#> runif(2)
+#> attr(,"class")
+#> [1] "rlang_lambda_function" "function"
+as_mapper(runif(2))
+#> function (x, ...) 
+#> pluck_raw(x, list(0.0807501375675201, 0.834333037259057), .default = NULL)
+#> <environment: 0x5d63c462a700>
+
+

Q3: Use the appropriate map() function to:

+
    +
  1. Compute the standard deviation of every column in a numeric data frame.

  2. +
  3. Compute the standard deviation of every numeric column in a mixed data frame. (Hint: you’ll need to do it in two steps.)

  4. +
  5. Compute the number of levels for every factor in a data frame.

  6. +
+

A: To solve this exercise we take advantage of calling the type stable variants of map(), which give us more concise output, and use map_lgl() to select the columns of the data frame (later you’ll learn about keep(), which simplifies this pattern a little).

+
+
map_dbl(mtcars, sd)
+#>     mpg     cyl    disp      hp    drat      wt    qsec      vs      am    gear 
+#>   6.027   1.786 123.939  68.563   0.535   0.978   1.787   0.504   0.499   0.738 
+#>    carb 
+#>   1.615
+
+penguins <- palmerpenguins::penguins
+
+penguins_numeric <- map_lgl(penguins, is.numeric)
+map_dbl(penguins[penguins_numeric], sd, na.rm = TRUE)
+#>    bill_length_mm     bill_depth_mm flipper_length_mm       body_mass_g 
+#>             5.460             1.975            14.062           801.955 
+#>              year 
+#>             0.818
+
+penguins_factor <- map_lgl(penguins, is.factor)
+map_int(penguins[penguins_factor], ~ length(levels(.x)))
+#> species  island     sex 
+#>       3       3       2
+
+

Q4: The following code simulates the performance of a t-test for non-normal data. Extract the p-value from each test, then visualise.

+
+
trials <- map(1:100, ~ t.test(rpois(10, 10), rpois(10, 7)))
+
+

A: There are many ways to visualise this data. However, since there are only 100 data points, we choose a dot plot to visualise the distribution. (Unfortunately, {ggplot2}s geom_dotplot() doesn’t compute proper counts as it was created to visualise distribution densities instead of frequencies, so a histogram would be a suitable alternative).

+
+
library(ggplot2)
+
+df_trials <- tibble::tibble(p_value = map_dbl(trials, "p.value"))
+
+df_trials %>%
+  ggplot(aes(x = p_value, fill = p_value < 0.05)) +
+  geom_dotplot(binwidth = .01) + # geom_histogram() as alternative
+  theme(
+    axis.text.y = element_blank(),
+    axis.ticks.y = element_blank(),
+    legend.position = "top"
+  )
+
+
+
+

+
+
+
+
+

Q5: The following code uses a map nested inside another map to apply a function to every element of a nested list. Why does it fail, and what do you need to do to make it work?

+
+
x <- list(
+  list(1, c(3, 9)),
+  list(c(3, 6), 7, c(4, 7, 6))
+)
+
+triple <- function(x) x * 3
+map(x, map, .f = triple)
+#> Error in `map()`:
+#> ℹ In index: 1.
+#> Caused by error in `.f()`:
+#> ! unused argument (function (.x, .f, ..., .progress = FALSE) 
+#> {
+#>     map_("list", .x, .f, ..., .progress = .progress)
+#> })
+
+

A: This function call fails, because triple() is specified as the .f argument and consequently belongs to the outer map(). The unnamed argument map is treated as an argument of triple(), which causes the error.

+

There are a number of ways we could resolve the problem. However, there is not much to choose between them for this simple example, although it is good to know your options for more complicated cases.

+
+
# Don't name the argument
+map(x, map, triple)
+
+# Use magrittr-style anonymous function
+map(x, . %>% map(triple))
+
+# Use purrr-style anonymous function
+map(x, ~ map(.x, triple))
+
+

Q6: Use map() to fit linear models to the mtcars dataset using the formulas stored in this list:

+
+
formulas <- list(
+  mpg ~ disp,
+  mpg ~ I(1 / disp),
+  mpg ~ disp + wt,
+  mpg ~ I(1 / disp) + wt
+)
+
+

A: The data (mtcars) is constant for all these models and so we iterate over the formulas provided. As the formula is the first argument of lm(), we don’t need to specify it explicitly.

+
+
models <- map(formulas, lm, data = mtcars)
+
+

Q7: Fit the model mpg ~ disp to each of the bootstrap replicates of mtcars in the list below, then extract the \(R^2\) of the model fit (Hint: you can compute the \(R^2\) with summary())

+
+
bootstrap <- function(df) {
+  df[sample(nrow(df), replace = TRUE), , drop = FALSE]
+}
+
+bootstraps <- map(1:10, ~ bootstrap(mtcars))
+
+

A: To accomplish this task, we take advantage of the “list in, list out”-functionality of map(). This allows us to chain multiple transformations together. We start by fitting the models. We then calculate the summaries and extract the \(R^2\) values. For the last call we use map_dbl(), which provides convenient output.

+
+
bootstraps %>%
+  map(~ lm(mpg ~ disp, data = .x)) %>%
+  map(summary) %>%
+  map_dbl("r.squared")
+#>  [1] 0.588 0.822 0.745 0.746 0.784 0.749 0.613 0.792 0.653 0.726
+
+
+
+

Map variants

+

Q1: Explain the results of modify(mtcars, 1).

+

A: modify() is based on map(), and in this case, the extractor interface will be used. It extracts the first element of each column in mtcars. modify() always returns the same structure as its input: in this case it forces the first row to be recycled 32 times. (Internally modify() uses .x[] <- map(.x, .f, ...) for assignment.)

+
+
head(modify(mtcars, 1))
+#>   mpg cyl disp  hp drat   wt qsec vs am gear carb
+#> 1  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+#> 2  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+#> 3  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+#> 4  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+#> 5  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+#> 6  21   6  160 110  3.9 2.62 16.5  0  1    4    4
+
+

Q2: Rewrite the following code to use iwalk() instead of walk2(). What are the advantages and disadvantages?

+
+
cyls <- split(mtcars, mtcars$cyl)
+paths <- file.path(temp, paste0("cyl-", names(cyls), ".csv"))
+walk2(cyls, paths, write.csv)
+
+

A: iwalk() allows us to use a single variable, storing the output path in the names.

+
+
temp <- tempfile()
+dir.create(temp)
+
+cyls <- split(mtcars, mtcars$cyl)
+names(cyls) <- file.path(temp, paste0("cyl-", names(cyls), ".csv"))
+iwalk(cyls, ~ write.csv(.x, .y))
+
+

We could do this in a single pipe by taking advantage of set_names():

+
+
mtcars %>%
+  split(mtcars$cyl) %>%
+  set_names(~ file.path(temp, paste0("cyl-", .x, ".csv"))) %>%
+  iwalk(~ write.csv(.x, .y))
+
+

Q3: Explain how the following code transforms a data frame using functions stored in a list.

+
+
trans <- list(
+  disp = function(x) x * 0.0163871,
+  am = function(x) factor(x, labels = c("auto", "manual"))
+)
+
+nm <- names(trans)
+mtcars[nm] <- map2(trans, mtcars[nm], function(f, var) f(var))
+
+

Compare and contrast the map2() approach to this map() approach:

+
+
mtcars[nm] <- map(nm, ~ trans[[.x]](mtcars[[.x]]))
+
+

A: In the first approach

+
+
mtcars[nm] <- map2(trans, mtcars[nm], function(f, var) f(var))
+
+

the list of the 2 functions (trans) and the 2 appropriately selected data frame columns (mtcars[nm]) are supplied to map2(). map2() creates an anonymous function (f(var)) which applies the functions to the variables when map2() iterates over their (similar) indices. On the left-hand side, the respective 2 elements of mtcars are being replaced by their new transformations.

+

The map() variant

+
+
mtcars[nm] <- map(nm, ~ trans[[.x]](mtcars[[.x]]))
+
+

does basically the same. However, it directly iterates over the names (nm) of the transformations. Therefore, the data frame columns are selected during the iteration.

+

Besides the iteration pattern, the approaches differ in the possibilities for appropriate argument naming in the .f argument. In the map2() approach we iterate over the elements of x and y. Therefore, it is possible to choose appropriate placeholders like f and var. This makes the anonymous function more expressive at the cost of making it longer. We think using the formula interface in this way is preferable compared to the rather cryptic mtcars[nm] <- map2(trans, mtcars[nm], ~ .x(.y)).

+

In the map() approach we map over the variable names. It is therefore not possible to introduce placeholders for the function and variable names. The formula syntax together with the .x pronoun is pretty compact. The object names and the brackets clearly indicate the application of transformations to specific columns of mtcars. In this case the iteration over the variable names comes in handy, as it highlights the importance of matching between trans and mtcars element names. Together with the replacement form on the left-hand side, this line is relatively easy to inspect.

+

To summarise, in situations where map() and map2() provide solutions for an iteration problem, several points may be considered before deciding for one or the other approach.

+

Q4: What does write.csv() return, i.e. what happens if you use it with map2() instead of walk2()?

+

A: write.csv() returns NULL. As we call the function for its side effect (creating a CSV file), walk2() would be appropriate here. Otherwise, we receive a rather uninformative list of NULLs.

+
+
cyls <- split(mtcars, mtcars$cyl)
+paths <- file.path(tempdir(), paste0("cyl-", names(cyls), ".csv"))
+
+map2(cyls, paths, write.csv)
+#> $`4`
+#> NULL
+#> 
+#> $`6`
+#> NULL
+#> 
+#> $`8`
+#> NULL
+
+
+
+

Predicate functionals

+

Q1: Why isn’t is.na() a predicate function? What base R function is closest to being a predicate version of is.na()?

+

A: is.na() is not a predicate function, because it returns a logical vector the same length as the input, not a single TRUE or FALSE.

+

anyNA() is the closest equivalent because it always returns a single TRUE or FALSE if there are any missing values present. You could also imagine an allNA() which would return TRUE if all values were missing, but that’s considerably less useful so base R does not provide it.

+

Q2: simple_reduce() has a problem when x is length 0 or length 1. Describe the source of the problem and how you might go about fixing it.

+
+
simple_reduce <- function(x, f) {
+  out <- x[[1]]
+  for (i in seq(2, length(x))) {
+    out <- f(out, x[[i]])
+  }
+  out
+}
+
+

A: The loop inside simple_reduce() always starts with the index 2, and seq() can count both up and down:

+
+
seq(2, 0)
+#> [1] 2 1 0
+seq(2, 1)
+#> [1] 2 1
+
+

Therefore, subsetting length-0 and length-1 vectors via [[ will lead to a subscript out of bounds error. To avoid this, we allow simple_reduce() to return before the for loop is started and include a default argument for 0-length vectors.

+
+
simple_reduce <- function(x, f, default) {
+  if (length(x) == 0L) {
+    return(default)
+  }
+  if (length(x) == 1L) {
+    return(x[[1L]])
+  }
+
+  out <- x[[1]]
+  for (i in seq(2, length(x))) {
+    out <- f(out, x[[i]])
+  }
+  out
+}
+
+

Our new simple_reduce() now works as intended:

+
+
simple_reduce(integer(0), `+`)
+#> Error in simple_reduce(integer(0), `+`): argument "default" is missing, with no default
+simple_reduce(integer(0), `+`, default = 0L)
+#> [1] 0
+simple_reduce(1, `+`)
+#> [1] 1
+simple_reduce(1:3, `+`)
+#> [1] 6
+
+

Q3: Implement the span() function from Haskell: given a list x and a predicate function f, span(x, f) returns the location of the longest sequential run of elements where the predicate is true. (Hint: you might find rle() helpful.)

+

A: Our span_r() function returns the indices of the (first occurring) longest sequential run of elements where the predicate is true. If the predicate is never true, the longest run has length 0, in which case we return integer(0).

+
+
span_r <- function(x, f) {
+  idx <- unname(map_lgl(x, ~ f(.x)))
+  rle <- rle(idx)
+
+  # Check if the predicate is never true
+  if (!any(rle$values)) {
+    return(integer(0))
+  }
+
+  # Find the length of the longest sequence of true values
+  longest <- max(rle$lengths[rle$values])
+  # Find the positition of the (first) longest run in rle
+  longest_idx <- which(rle$values & rle$lengths == longest)[1]
+
+  # Add up all lengths in rle before the longest run
+  ind_before_longest <- sum(rle$lengths[seq_len(longest_idx - 1)])
+
+  out_start <- ind_before_longest + 1L
+  out_end <- ind_before_longest + longest
+  out_start:out_end
+}
+
+# Check that it works
+span_r(c(0, 0, 0, 0, 0), is.na)
+#> integer(0)
+span_r(c(NA, 0, 0, 0, 0), is.na)
+#> [1] 1
+span_r(c(NA, 0, NA, NA, NA), is.na)
+#> [1] 3 4 5
+
+

Q4: Implement arg_max(). It should take a function and a vector of inputs, and return the elements of the input where the function returns the highest value. For example, arg_max(-10:5, function(x) x ^ 2) should return -10. arg_max(-5:5, function(x) x ^ 2) should return c(-5, 5). Also implement the matching arg_min() function.

+

A: Both functions take a vector of inputs and a function as an argument. The function output is then used to subset the input accordingly.

+
+
arg_max <- function(x, f) {
+  y <- map_dbl(x, f)
+  x[y == max(y)]
+}
+
+arg_min <- function(x, f) {
+  y <- map_dbl(x, f)
+  x[y == min(y)]
+}
+
+arg_max(-10:5, function(x) x^2)
+#> [1] -10
+arg_min(-10:5, function(x) x^2)
+#> [1] 0
+
+

Q5: The function below scales a vector so it falls in the range [0, 1]. How would you apply it to every column of a data frame? How would you apply it to every numeric column in a data frame?

+
+
scale01 <- function(x) {
+  rng <- range(x, na.rm = TRUE)
+  (x - rng[1]) / (rng[2] - rng[1])
+}
+
+

A: To apply a function to every column of a data frame, we can use purrr::modify() (or purrr::map_dfr()), which also conveniently returns a data frame. To limit the application to numeric columns, the scoped version modify_if() can be used.

+
+
modify_if(mtcars, is.numeric, scale01)
+
+
+
+

Base functionals

+

Q1: How does apply() arrange the output? Read the documentation and perform some experiments.

+

A: Basically apply() applies a function over the margins of an array. In the two-dimensional case, the margins are just the rows and columns of a matrix. Let’s make this concrete.

+
+
arr2 <- array(1:12, dim = c(3, 4))
+rownames(arr2) <- paste0("row", 1:3)
+colnames(arr2) <- paste0("col", 1:4)
+arr2
+#>      col1 col2 col3 col4
+#> row1    1    4    7   10
+#> row2    2    5    8   11
+#> row3    3    6    9   12
+
+

When we apply the head() function over the first margin of arr2() (i.e. the rows), the results are contained in the columns of the output, transposing the array compared to the original input.

+
+
apply(arr2, 1, function(x) x[1:2])
+#>      row1 row2 row3
+#> col1    1    2    3
+#> col2    4    5    6
+
+

And vice versa if we apply over the second margin (the columns):

+
+
apply(arr2, 2, function(x) x[1:2])
+#>      col1 col2 col3 col4
+#> row1    1    4    7   10
+#> row2    2    5    8   11
+
+

The output of apply() is organised first by the margins being operated over, then the results of the function. This can become quite confusing for higher dimensional arrays.

+

Q2: What do eapply() and rapply() do? Does {purrr} have equivalents?

+

A: eapply() is a variant of lapply(), which iterates over the (named) elements of an environment. In {purrr} there is no equivalent for eapply() as {purrr} mainly provides functions that operate on vectors and functions, but not on environments.

+

rapply() applies a function to all elements of a list recursively. This function makes it possible to limit the application of the function to specified classes (default classes = ANY). One may also specify how elements of other classes should remain: as their identity (how = replace) or another value (default = NULL). The closest equivalent in {purrr} is modify_depth(), which allows you to modify elements at a specified depth in a nested list.

+

Q3: Challenge: read about the fixed point algorithm. Complete the exercises using R.

+

A: A number \(x\) is called a fixed point of a function \(f\) if it satisfies the equation \(f(x) = x\). For some functions we may find a fixed point by beginning with a starting value and applying \(f\) repeatedly. Here fixed_point() acts as a functional because it takes a function as an argument.

+
+
fixed_point <- function(f, x_init, n_max = 10000, tol = 0.0001) {
+  n <- 0
+  x <- x_init
+  y <- f(x)
+
+  is_fixed_point <- function(x, y) {
+    abs(x - y) < tol
+  }
+
+  while (!is_fixed_point(x, y)) {
+    x <- y
+    y <- f(y)
+
+    # Make sure we eventually stop
+    n <- n + 1
+    if (n > n_max) {
+      stop("Failed to converge.", call. = FALSE)
+    }
+  }
+
+  x
+}
+
+
+# Functions with fixed points
+fixed_point(sin, x_init = 1)
+#> [1] 0.0843
+fixed_point(cos, x_init = 1)
+#> [1] 0.739
+
+# Functions without fixed points
+add_one <- function(x) x + 1
+fixed_point(add_one, x_init = 1)
+#> Error: Failed to converge.
+
+
+
+

References

+ + +
+
+Henry, Lionel, and Hadley Wickham. 2020. Purrr: Functional Programming Tools. https://github.com/tidyverse/purrr. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/10_Function_factories.html b/docs/10_Function_factories.html new file mode 100644 index 00000000..be2437e7 --- /dev/null +++ b/docs/10_Function_factories.html @@ -0,0 +1,1150 @@ + + + + + + + + + + +Advanced R Solutions - 10 - Function factories + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

10 - Function factories

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

For most of this chapter base R (R Core Team 2020) is sufficient. Just a few exercises require the {rlang} (Henry and Wickham 2020b), {dplyr} (Wickham et al. 2020), {purrr} (Henry and Wickham 2020a) and {ggplot2} (Wickham 2016) packages.

+
+
library(rlang)
+library(dplyr)
+library(purrr)
+library(ggplot2)
+
+
+
+

Factory fundamentals

+

Q1: The definition of force() is simple:

+
+
force
+#> function (x) 
+#> x
+#> <bytecode: 0x5f56c3bd90f0>
+#> <environment: namespace:base>
+
+

Why is it better to force(x) instead of just x?

+

A: As you can see force(x) is similar to x. As mentioned in Advanced R, we prefer this explicit form, because

+
+

using this function clearly indicates that you’re forcing evaluation, not that you’ve accidentally typed x.”

+
+

Q2: Base R contains two function factories, approxfun() and ecdf(). Read their documentation and experiment to figure out what the functions do and what they return.

+

A: Let’s begin with approxfun() as it is used within ecdf() as well:

+

approxfun() takes a combination of data points (x and y values) as input and returns a stepwise linear (or constant) interpolation function. To find out what this means exactly, we first create a few random data points.

+
+
x <- runif(10)
+y <- runif(10)
+plot(x, y, lwd = 10)
+
+
+
+

+
+
+
+
+

Next, we use approxfun() to construct the linear and constant interpolation functions for our x and y values.

+
+
f_lin <- approxfun(x, y)
+f_con <- approxfun(x, y, method = "constant")
+
+# Both functions exactly reproduce their input y values
+identical(f_lin(x), y)
+#> [1] TRUE
+identical(f_con(x), y)
+#> [1] TRUE
+
+

When we apply these functions to new x values, these are mapped to the lines connecting the initial y values (linear case) or to the same y value as for the next smallest initial x value (constant case).

+
+
x_new <- runif(1000)
+
+plot(x, y, lwd = 10)
+points(x_new, f_lin(x_new), col = "cornflowerblue", pch = 16)
+points(x_new, f_con(x_new), col = "firebrick", pch = 16)
+
+
+
+

+
+
+
+
+

However, both functions are only defined within range(x).

+
+
f_lin(range(x))
+#> [1] 0.402 0.175
+f_con(range(x))
+#> [1] 0.402 0.175
+
+(eps <- .Machine$double.neg.eps)
+#> [1] 1.11e-16
+
+f_lin(c(min(x) - eps, max(x) + eps))
+#> [1] NA NA
+f_con(c(min(x) - eps, max(x) + eps))
+#> [1] NA NA
+
+

To change this behaviour, one can set rule = 2. This leads to the result that for values outside of range(x) the boundary values of the function are returned.

+
+
f_lin <- approxfun(x, y, rule = 2)
+f_con <- approxfun(x, y, method = "constant", rule = 2)
+
+f_lin(c(-Inf, Inf))
+#> [1] 0.402 0.175
+f_con(c(-Inf, Inf))
+#> [1] 0.402 0.175
+
+

Another option is to customise the return values as individual constants for each side via yleft and/or yright.

+
+
f_lin <- approxfun(x, y, yleft = 5)
+f_con <- approxfun(x, y, method = "constant", yleft = 5, yright = -5)
+
+f_lin(c(-Inf, Inf))
+#> [1]  5 NA
+f_con(c(-Inf, Inf))
+#> [1]  5 -5
+
+

Further, approxfun() provides the option to shift the y values for method = "constant" between their left and right values. According to the documentation this indicates a compromise between left- and right-continuous steps.

+
+
f_con <- approxfun(x, y, method = "constant", f = .5)
+
+plot(x, y, lwd = 10)
+points(x_new, f_con(x_new), pch = 16)
+
+
+
+

+
+
+
+
+

Finally, the ties argument allows to aggregate y values if multiple ones were provided for the same x value. For example, in the following line we use mean() to aggregate these y values before they are used for the interpolation approxfun(x = c(1,1,2), y = 1:3, ties = mean).

+

Next, we focus on ecdf(). “ecdf” is an acronym for empirical cumulative distribution function. For a numeric vector of density values, ecdf() initially creates the (x, y) pairs for the nodes of the density function and then passes these pairs to approxfun(), which gets called with specifically adapted settings (approxfun(vals, cumsum(tabulate(match(x, vals)))/n, method = "constant", yleft = 0, yright = 1, f = 0, ties = "ordered")).

+
+
x <- runif(10)
+f_ecdf <- ecdf(x)
+class(f_ecdf)
+#> [1] "ecdf"     "stepfun"  "function"
+
+plot(x, f_ecdf(x), lwd = 10, ylim = 0:1)
+
+
+
+

+
+
+
+
+

New values are then mapped on the y value of the next smallest x value from within the initial input.

+
+
x_new <- runif(1000)
+
+plot(x, f_ecdf(x), lwd = 10, ylim = 0:1)
+points(x_new, f_ecdf(x_new), ylim = 0:1)
+
+
+
+

+
+
+
+
+

Q3: Create a function pick() that takes an index, i, as an argument and returns a function with an argument x that subsets x with i.

+
+
pick(1)(x)
+# should be equivalent to
+x[[1]]
+
+lapply(mtcars, pick(5))
+# should be equivalent to
+lapply(mtcars, function(x) x[[5]])
+
+

A: In this exercise pick(i) acts as a function factory, which returns the required subsetting function.

+
+
pick <- function(i) {
+  force(i)
+
+  function(x) x[[i]]
+}
+
+x <- 1:3
+identical(x[[1]], pick(1)(x))
+#> [1] TRUE
+identical(
+  lapply(mtcars, function(x) x[[5]]),
+  lapply(mtcars, pick(5))
+)
+#> [1] TRUE
+
+

Q4: Create a function that creates functions that compute the ith central moment of a numeric vector. You can test it by running the following code:

+
+
m1 <- moment(1)
+m2 <- moment(2)
+
+x <- runif(100)
+stopifnot(all.equal(m1(x), 0))
+stopifnot(all.equal(m2(x), var(x) * 99 / 100))
+
+

A: The first moment is closely related to the mean and describes the average deviation from the mean, which is 0 (within numerical margin of error). The second moment describes the variance of the input data. If we want to compare it to var(), we need to undo Bessel’s correction by multiplying with \(\frac{N-1}{N}\).

+
+
moment <- function(i) {
+  force(i)
+
+  function(x) sum((x - mean(x))^i) / length(x)
+}
+
+m1 <- moment(1)
+m2 <- moment(2)
+
+x <- runif(100)
+all.equal(m1(x), 0) # removed stopifnot() for clarity
+#> [1] TRUE
+all.equal(m2(x), var(x) * 99 / 100)
+#> [1] TRUE
+
+

Q5: What happens if you don’t use a closure? Make predictions, then verify with the code below.

+
+
i <- 0
+new_counter2 <- function() {
+  i <<- i + 1
+  i
+}
+
+

A: Without the captured and encapsulated environment of a closure the counts will be stored in the global environment. Here they can be overwritten or deleted as well as interfere with other counters.

+
+
new_counter2()
+#> [1] 1
+i
+#> [1] 1
+new_counter2()
+#> [1] 2
+i
+#> [1] 2
+
+i <- 0
+new_counter2()
+#> [1] 1
+i
+#> [1] 1
+
+

Q6: What happens if you use <- instead of <<-? Make predictions, then verify with the code below.

+
+
new_counter3 <- function() {
+  i <- 0
+  function() {
+    i <- i + 1
+    i
+  }
+}
+
+

A: Without the super assignment <<-, the counter will always return 1. The counter always starts in a new execution environment within the same enclosing environment, which contains an unchanged value for i (in this case it remains 0).

+
+
new_counter_3 <- new_counter3()
+
+new_counter_3()
+#> [1] 1
+new_counter_3()
+#> [1] 1
+
+
+
+

Graphical factories

+

Q1: Compare and contrast ggplot2::label_bquote() with scales::number_format().

+

A: Both functions will help you in styling your output, e.g. in your plots and they do this by returning the desired formatting function to you.

+

ggplot2::label_bquote() takes relatively straightforward plotmath expressions and uses them for faceting labels in {ggplot2}. Because this function is used in {ggplot2} it needs to return a function of class = "labeller".

+

scales::number_format() initially force()s the computation of all parameters. It’s essentially a parametrised wrapper around scales::number() and will help you format numbers appropriately. It will return a simple function.

+
+
+

Statistical factories

+

Q1: In boot_model(), why don’t I need to force the evaluation of df or model?

+

A: boot_model() ultimately returns a function, and whenever you return a function you need to make sure all the inputs are explicitly evaluated. Here that happens automatically because we use df and formula in lm() before returning the function.

+
+
boot_model <- function(df, formula) {
+  mod <- lm(formula, data = df)
+  fitted <- unname(fitted(mod))
+  resid <- unname(resid(mod))
+  rm(mod)
+
+  function() {
+    fitted + sample(resid)
+  }
+}
+
+

Q2: Why might you formulate the Box-Cox transformation like this?

+
+
boxcox3 <- function(x) {
+  function(lambda) {
+    if (lambda == 0) {
+      log(x)
+    } else {
+      (x^lambda - 1) / lambda
+    }
+  }
+}
+
+

A: boxcox3() returns a function where x is fixed (though it is not forced, so it may be manipulated later). This allows us to apply and test different transformations for different inputs and give them a descriptive name.

+
+
boxcox_airpassengers <- boxcox3(AirPassengers)
+
+plot(boxcox_airpassengers(0))
+plot(boxcox_airpassengers(1))
+plot(boxcox_airpassengers(2))
+plot(boxcox_airpassengers(3))
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+

Q3: Why don’t you need to worry that boot_permute() stores a copy of the data inside the function that it generates?

+

A: boot_permute() is defined in Advanced R as:

+
+
boot_permute <- function(df, var) {
+  n <- nrow(df)
+  force(var)
+
+  function() {
+    col <- df[[var]]
+    col[sample(n, replace = TRUE)]
+  }
+}
+
+

We don’t need to worry that it stores a copy of the data, because it actually doesn’t store one; it’s just a name that points to the same underlying object in memory.

+
+
boot_mtcars1 <- boot_permute(mtcars, "mpg")
+
+lobstr::obj_size(mtcars)
+#> 7.21 kB
+lobstr::obj_size(boot_mtcars1)
+#> 20.18 kB
+lobstr::obj_sizes(mtcars, boot_mtcars1)
+#> *  7.21 kB
+#> * 12.97 kB
+
+

Q4: How much time does ll_poisson2() save compared to ll_poisson1()? Use bench::mark() to see how much faster the optimisation occurs. How does changing the length of x change the results?

+

A: Let us recall the definitions of ll_poisson1(), ll_poisson2() and the test data x1:

+
+
ll_poisson1 <- function(x) {
+  n <- length(x)
+
+  function(lambda) {
+    log(lambda) * sum(x) - n * lambda - sum(lfactorial(x))
+  }
+}
+
+ll_poisson2 <- function(x) {
+  n <- length(x)
+  sum_x <- sum(x)
+  c <- sum(lfactorial(x))
+
+  function(lambda) {
+    log(lambda) * sum_x - n * lambda - c
+  }
+}
+
+x1 <- c(41, 30, 31, 38, 29, 24, 30, 29, 31, 38)
+
+

A benchmark on x1 reveals a performance improvement of factor 2 for ll_poisson2() over ll_poisson1():

+
+
bench::mark(
+  llp1 = optimise(ll_poisson1(x1), c(0, 100), maximum = TRUE),
+  llp2 = optimise(ll_poisson2(x1), c(0, 100), maximum = TRUE)
+)
+#> # A tibble: 2 × 6
+#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 llp1         19.2µs   25.1µs    37614.    12.9KB     33.9
+#> 2 llp2         10.7µs     13µs    71319.        0B     35.7
+
+

As the redundant calculations within ll_poisson1() become more expensive with growing length of x1, we expect even further relative performance improvements for ll_poisson2(). The following benchmark reveals a relative performance improvement of factor 20 for ll_poisson2() when x1 is of length 100,000:

+
+
bench_poisson <- function(x_length) {
+  x <- rpois(x_length, 100L)
+
+  bench::mark(
+    llp1 = optimise(ll_poisson1(x), c(0, 100), maximum = TRUE),
+    llp2 = optimise(ll_poisson2(x), c(0, 100), maximum = TRUE),
+    time_unit = "ms"
+  )
+}
+
+performances <- map_dfr(10^(1:5), bench_poisson)
+
+df_perf <- tibble(
+  x_length = rep(10^(1:5), each = 2),
+  method   = attr(performances$expression, "description"),
+  median   = performances$median
+)
+
+ggplot(df_perf, aes(x_length, median, col = method)) +
+  geom_point(size = 2) +
+  geom_line(linetype = 2) +
+  scale_x_log10() +
+  labs(
+    x = "Length of x",
+    y = "Execution Time (ms)",
+    color = "Method"
+  ) +
+  theme(legend.position = "top")
+
+
+
+

+
+
+
+
+
+
+

Function factories + functionals

+

Q1: Which of the following commands is equivalent to with(x, f(z))?

+
    +
  1. x$f(x$z).
  2. +
  3. f(x$z).
  4. +
  5. x$f(z).
  6. +
  7. f(z).
  8. +
  9. It depends.
  10. +
+

A: (e) “It depends” is the correct answer. Usually with() is used with a data frame, so you’d usually expect (b), but if x is a list, it could be any of the options.

+
+
f <- mean
+z <- 1
+x <- list(f = mean, z = 1)
+
+identical(with(x, f(z)), x$f(x$z))
+#> [1] TRUE
+identical(with(x, f(z)), f(x$z))
+#> [1] TRUE
+identical(with(x, f(z)), x$f(z))
+#> [1] TRUE
+identical(with(x, f(z)), f(z))
+#> [1] TRUE
+
+

Q2: Compare and contrast the effects of env_bind() vs. attach() for the following code.

+
+
funs <- list(
+  mean = function(x) mean(x, na.rm = TRUE),
+  sum = function(x) sum(x, na.rm = TRUE)
+)
+
+attach(funs)
+#> The following objects are masked from package:base:
+#> 
+#>     mean, sum
+mean <- function(x) stop("Hi!")
+detach(funs)
+
+env_bind(globalenv(), !!!funs)
+mean <- function(x) stop("Hi!")
+env_unbind(globalenv(), names(funs))
+
+

A: attach() adds funs to the search path. Therefore, the provided functions are found before their respective versions from the {base} package. Further, they cannot get accidentally overwritten by similar named functions in the global environment. One annoying downside of using attach() is the possibility to attach the same object multiple times, making it necessary to call detach() equally often.

+
+
attach(funs)
+#> The following objects are masked from package:base:
+#> 
+#>     mean, sum
+attach(funs)
+#> The following objects are masked from funs (pos = 3):
+#> 
+#>     mean, sum
+#> 
+#> The following objects are masked from package:base:
+#> 
+#>     mean, sum
+
+head(search())
+#> [1] ".GlobalEnv"      "funs"            "funs"            "package:ggplot2"
+#> [5] "package:purrr"   "package:dplyr"
+detach(funs)
+detach(funs)
+
+

In contrast rlang::env_bind() just adds the functions in fun to the global environment. No further side effects are introduced, and the functions are overwritten when similarly named functions are defined.

+
+
env_bind(globalenv(), !!!funs)
+head(search())
+#> [1] ".GlobalEnv"      "package:ggplot2" "package:purrr"   "package:dplyr"  
+#> [5] "package:rlang"   "package:stats"
+
+
+
+

References

+ + +
+
+Henry, Lionel, and Hadley Wickham. 2020a. Purrr: Functional Programming Tools. https://github.com/tidyverse/purrr. +
+
+———. 2020b. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang. +
+
+R Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/. +
+
+Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org. +
+
+Wickham, Hadley, Romain François, Lionel Henry, and Kirill Müller. 2020. Dplyr: A Grammar of Data Manipulation. https://github.com/tidyverse/dplyr. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/11_Function_operators.html b/docs/11_Function_operators.html new file mode 100644 index 00000000..f68cc57c --- /dev/null +++ b/docs/11_Function_operators.html @@ -0,0 +1,853 @@ + + + + + + + + + + +Advanced R Solutions - 11 - Function operators + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

11 - Function operators

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

Also in the third chapter on functional programming, we make relatively frequent use of the {purrr} package.

+
+
library(purrr)
+
+
+
+

Existing function operators

+

Q1: Base R provides a function operator in the form of Vectorize(). What does it do? When might you use it?

+

A: In R a lot of functions are “vectorised”. Vectorised has two meanings. First, it means (broadly) that a function inputs a vector or vectors and does something to each element. Secondly, it usually implies that these operations are implemented in a compiled language such as C or Fortran, so that the implementation is very fast.

+

However, despite what the function’s name implies, Vectorize() is not able to speed up the provided function. It rather changes the input format of the supplied arguments (vectorize.args), so that they can be iterated over.

+

Let’s take a look at an example from the documentation:

+
+
vrep <- Vectorize(rep.int)
+vrep
+#> function (x, times)
+#> {
+#>   args <- lapply(as.list(match.call())[-1L], eval, parent.frame())
+#>   names <- if (is.null(names(args)))
+#>     character(length(args))
+#>   else names(args)
+#>   dovec <- names %in% vectorize.args
+#>   do.call("mapply", c(FUN = FUN, args[dovec],
+#>                       MoreArgs = list(args[!dovec]),
+#>                       SIMPLIFY = SIMPLIFY, USE.NAMES = USE.NAMES))
+#> }
+#> <environment: 0x558902db65d0>
+
+ +
+
# Application
+vrep(1:2, 3:4)
+#> [[1]]
+#> [1] 1 1 1
+#> 
+#> [[2]]
+#> [1] 2 2 2 2
+
+

Vectorize() provides a convenient and concise notation to iterate over multiple arguments but has some major drawbacks that mean you generally shouldn’t use it. See https://www.jimhester.com/post/2018-04-12-vectorize/ for more details.

+

Q2: Read the source code for possibly(). How does it work?

+

A: possibly() modifies functions to return a specified default value (otherwise) in case of an error and to suppress any error messages (quiet = TRUE).

+

While reading the source code, we notice that possibly() internally uses purrr::as_mapper(). This enables users to supply not only functions, but also formulas or atomics via the same syntax as known from other functions in the {purrr} package. Besides this, the new default value (otherwise) gets evaluated once to make it (almost) immutable.

+
+
possibly
+#> function (.f, otherwise = NULL, quiet = TRUE) 
+#> {
+#>     .f <- as_mapper(.f)
+#>     force(otherwise)
+#>     check_bool(quiet)
+#>     function(...) {
+#>         tryCatch(.f(...), error = function(e) {
+#>             if (!quiet) 
+#>                 message("Error: ", conditionMessage(e))
+#>             otherwise
+#>         })
+#>     }
+#> }
+#> <bytecode: 0x612763fdb428>
+#> <environment: namespace:purrr>
+
+

The main functionality of possibly() is provided by base::tryCatch(). In this part the supplied function (.f) gets wrapped and the error and interrupt handling are specified.

+

Q3: Read the source code for safely(). How does it work?

+

A: safely() modifies functions to return a list, containing the elements result and error. It works in a similar fashion as possibly() and besides using as_mapper(), safely() also provides the otherwise and quiet arguments. However, in order to provide the result and the error in a consistent way, the tryCatch() part of the implementation returns a list with similar structure for both cases. In the case of successful evaluation error equals NULL and in case of an error result equals otherwise, which is NULL by default.

+

As the tryCatch() part is hidden in the internal purrr:::capture_output() function, we provide it here in addition to safely():

+
+
safely
+#> function (.f, otherwise = NULL, quiet = TRUE) 
+#> {
+#>     .f <- as_mapper(.f)
+#>     force(otherwise)
+#>     check_bool(quiet)
+#>     function(...) capture_error(.f(...), otherwise, quiet)
+#> }
+#> <bytecode: 0x6127643254f0>
+#> <environment: namespace:purrr>
+
+purrr:::capture_error
+#> function (code, otherwise = NULL, quiet = TRUE) 
+#> {
+#>     tryCatch(list(result = code, error = NULL), error = function(e) {
+#>         if (!quiet) 
+#>             message("Error: ", conditionMessage(e))
+#>         list(result = otherwise, error = e)
+#>     })
+#> }
+#> <bytecode: 0x6127643aebe8>
+#> <environment: namespace:purrr>
+
+

Take a look at Advanced R or the documentation of safely() to see how you can take advantage of this behaviour, e.g. when fitting many models.

+
+
+

Case study: Creating your own function operators

+

Q1: Weigh the pros and cons of download.file %>% dot_every(10) %>% delay_by(0.1) versus download.file %>% delay_by(0.1) %>% dot_every(10).

+

A: Both commands will print a dot every 10 downloads and will take the same amount of time to run, so the differences may seem quite subtle.

+

In the first case, first the dot functionality is added to download.file(). Then the delay is added to this already tweaked function. This implies, that the printing of the dot will also be delayed, and the first dot will be printed as soon as the download for the 10th URL starts.

+

In the latter case the delay is added first and the dot-functionality is wrapped around it. This order will print the first dot immediately after the 9th download is finished, then the short delay occurs before the 10th download actually starts.

+

Q2: Should you memoise file.download()? Why or why not?

+

A: Memoising file.download() will only work if the files are immutable, i.e. if the file at a given URL is always the same. There’s no point memoising unless this is true. Even if this is true, however, memoise has to store the results in memory, and large files will potentially take up a lot of memory.

+

This implies that it’s probably not beneficial to memoise file.download() in most cases. The only exception is if you are downloading small files many times, and the file at a given URL is guaranteed not to change.

+

Q3: Create a function operator that reports whenever a file is created or deleted in the working directory, using dir() and setdiff(). What other global function effects might you want to track?

+

A: We start with a function that reports the difference between two vectors containing file names:

+
+
dir_compare <- function(old, new) {
+  if (setequal(old, new)) {
+    return()
+  }
+
+  added <- setdiff(new, old)
+  removed <- setdiff(old, new)
+
+  changes <- c(
+    if (length(added) > 0) paste0(" * '", added, "' was added"),
+    if (length(removed) > 0) {
+      paste0(
+        " * '", removed,
+        "' was removed"
+      )
+    }
+  )
+  message(paste(changes, collapse = "\n"))
+}
+
+dir_compare(c("x", "y"), c("x", "y"))
+#> NULL
+dir_compare(c("x", "y"), c("x", "a"))
+#>  * 'a' was added
+#>  * 'y' was removed
+
+

Then we wrap it up in a function operator

+
+
track_dir <- function(f) {
+  force(f)
+  function(...) {
+    dir_old <- dir()
+    on.exit(dir_compare(dir_old, dir()), add = TRUE)
+
+    f(...)
+  }
+}
+
+

And try it out by creating wrappers around file.create() and file.remove():

+
+
file_create <- track_dir(file.create)
+file_remove <- track_dir(file.remove)
+
+file_create("delete_me")
+#>  * 'delete_me' was added
+#> [1] TRUE
+file_remove("delete_me")
+#>  * 'delete_me' was removed
+#> [1] TRUE
+
+

To create a more serious version of track_dir() one might provide optionality to set the full.names and recursive arguments of dir() to TRUE. This would enable to also track the creation/deletion of hidden files and files in folders contained in the working directory.

+

Other global effects that might be worth tracking include changes regarding:

+
    +
  • the search path and possibly introduced conflicts()
  • +
  • options() and par() which modify global settings
  • +
  • the path of the working directory
  • +
  • environment variables
  • +
+

Q4: Write a function operator that logs a timestamp and message to a file every time a function is run.

+

A: Our logger() function operator takes a function and a file path as input. One timestamp is written to the file under log_path when we call logger() and another timestamp is written to the same file each time the new function gets called.

+
+
append_line <- function(path, ...) {
+  cat(..., "\n", sep = "", file = path, append = TRUE)
+}
+
+logger <- function(f, log_path) {
+  force(f)
+  force(log_path)
+
+  append_line(log_path, "created at: ", as.character(Sys.time()))
+  function(...) {
+    append_line(log_path, "called at: ", as.character(Sys.time()))
+    f(...)
+  }
+}
+
+

Now, let’s check if our logger() works as intended and apply it to the mean() function:

+
+
log_path <- tempfile()
+mean2 <- logger(mean, log_path)
+Sys.sleep(5)
+mean2(1:4)
+#> [1] 2.5
+Sys.sleep(1)
+mean2(1:4)
+#> [1] 2.5
+
+readLines(log_path)
+#> [1] "created at: 2024-01-24 11:45:37.692096"
+#> [2] "called at: 2024-01-24 11:45:42.699738" 
+#> [3] "called at: 2024-01-24 11:45:43.703109"
+
+

Q5: Modify delay_by() so that instead of delaying by a fixed amount of time, it ensures that a certain amount of time has elapsed since the function was last called. That is, if you called g <- delay_by(1, f); g(); Sys.sleep(2); g() there shouldn’t be an extra delay.

+

A: delay_by() was defined in Advanced R as:

+
+
delay_by <- function(f, amount) {
+  force(f)
+  force(amount)
+
+  function(...) {
+    Sys.sleep(amount)
+    f(...)
+  }
+}
+
+

To ensure that the function created by delay_by() waits that a certain amount of time has passed since its last execution, we incorporate three little changes into our new delay_atleast() as indicated in the corresponding comments below.

+
+
delay_atleast <- function(amount, f) {
+  force(f)
+  force(amount)
+
+  # Store the last time the function was run
+  last_time <- NULL
+
+  # Return modified "delay-aware" function
+  function(...) {
+    if (!is.null(last_time)) {
+      wait <- (last_time - Sys.time()) + amount
+      if (wait > 0) {
+        Sys.sleep(wait)
+      }
+    }
+
+    # Update the time after the function has finished
+    on.exit(last_time <<- Sys.time())
+
+    f(...)
+  }
+}
+
+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/13_S3.html b/docs/13_S3.html new file mode 100644 index 00000000..ddf95ac9 --- /dev/null +++ b/docs/13_S3.html @@ -0,0 +1,1434 @@ + + + + + + + + + + +Advanced R Solutions - 13 - S3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

13 - S3

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

To interact with S3 objects, we will mainly use the {sloop} package (Wickham 2019).

+
+
library(sloop)
+
+
+
+

Basics

+

Q1: Describe the difference between t.test() and t.data.frame()? When is each function called?

+

A: Because of S3’s generic.class() naming scheme, both functions may initially look similar, while they are in fact unrelated.

+
    +
  • t.test() is a generic function that performs a t-test.
  • +
  • t.data.frame() is a method that gets called by the generic t() to transpose data frame input.
  • +
+

Due to R’s S3 dispatch rules, t.test() would also get called when t() is applied to an object of class test.

+

Q2: Make a list of commonly used base R functions that contain . in their name but are not S3 methods.

+

A: In recent years “snake_case”-style has become increasingly common when naming functions and variables in R. But many functions in base R will continue to be “point.separated”, which is why some inconsistency in your R code most likely cannot be avoided.(Bååth 2012)

+
+
# Some base R functions with point.separated names
+install.packages()
+read.csv()
+
+list.files()
+download.file()
+
+data.frame()
+as.character()
+Sys.Date()
+
+all.equal()
+
+do.call()
+on.exit()
+
+

Q3: What does the as.data.frame.data.frame() method do? Why is it confusing? How could you avoid this confusion in your own code?

+

A: The function as.data.frame.data.frame() implements the data.frame() method for the as.data.frame() generic, which coerces objects to data frames.

+

The name is confusing, because it does not clearly communicate the type of the function, which could be a regular function, a generic or a method. Even if we assume a method, the amount of .’s makes it difficult to separate the generic- and the class-part of the name. Is it the data.frame.data.frame() method for the as() generic? Is it the frame.data.frame() method for the as.data() generic?

+

We could avoid this confusion by applying a different naming convention (e.g. “snake_case”) for our class and function names.

+

Q4: Describe the difference in behaviour in these two calls.

+
+
some_days <- as.Date("2017-01-31") + sample(10, 5)
+
+mean(some_days)
+#> [1] "2017-02-06"
+mean(unclass(some_days))
+#> [1] 17203
+
+

A: mean() is a generic function, which will select the appropriate method based on the class of the input. some_days has the class Date and mean.Date(some_days) will be used to calculate the mean date of some_days.

+

After unclass() has removed the class attribute from some_date, the default method is chosen. mean.default(unclass(some_days)) then calculates the mean of the underlying double.

+

Q5: What class of object does the following code return? What base type is it built on? What attributes does it use?

+
+
x <- ecdf(rpois(100, 10))
+x
+#> Empirical CDF 
+#> Call: ecdf(rpois(100, 10))
+#>  x[1:18] =  2,  3,  4,  ..., 2e+01, 2e+01
+
+

A: It returns an object of the class ecdf (empirical cumulative distribution function) with the superclasses stepfun and function. The ecdf object is built on the base type closure (a function). The expression, which was used to create it (rpois(100, 10)), is stored in the call attribute.

+
+
typeof(x)
+#> [1] "closure"
+
+attributes(x)
+#> $class
+#> [1] "ecdf"     "stepfun"  "function"
+#> 
+#> $call
+#> ecdf(rpois(100, 10))
+
+

Q6: What class of object does the following code return? What base type is it built on? What attributes does it use?

+
+
x <- table(rpois(100, 5))
+x
+#> 
+#>  1  2  3  4  5  6  7  8  9 10 
+#>  7  5 18 14 15 15 14  4  5  3
+
+

A: This code returns a table object, which is built upon the integer type. The attribute dimnames is used to name the elements of the integer vector.

+
+
typeof(x)
+#> [1] "integer"
+
+attributes(x)
+#> $dim
+#> [1] 10
+#> 
+#> $dimnames
+#> $dimnames[[1]]
+#>  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10"
+#> 
+#> 
+#> $class
+#> [1] "table"
+
+
+
+

Classes

+

Q1: Write a constructor for data.frame objects. What base type is a data frame built on? What attributes does it use? What are the restrictions placed on the individual elements? What about the names?

+

A: Data frames are built on named lists of vectors, which all have the same length. Besides the class and the column names (names), the row.names are their only further attribute. This must be a character vector with the same length as the other vectors.

+

We need to provide the number of rows as an input to make it possible to create data frames with 0 columns but multiple rows.

+

This leads to the following constructor:

+
+
new_data.frame <- function(x, n, row.names = NULL) {
+  # Check if the underlying object is a list
+  stopifnot(is.list(x))
+  
+  # Check all inputs are the same length
+  # (This check also allows that x has length 0)
+  stopifnot(all(lengths(x) == n))
+  
+  if (is.null(row.names)) {
+    # Use special row names helper from base R
+    row.names <- .set_row_names(n)
+  } else {
+    # Otherwise check that they're a character vector with the 
+    # correct length
+    stopifnot(is.character(row.names), length(row.names) == n)
+  }
+  
+  structure(
+    x,
+    class = "data.frame",
+    row.names = row.names
+  )
+}
+
+# Test
+x <- list(a = 1, b = 2)
+new_data.frame(x, n = 1)
+#>   a b
+#> 1 1 2
+new_data.frame(x, n = 1, row.names = "l1")
+#>    a b
+#> l1 1 2
+
+# Create a data frame with 0 columns and 2 rows
+new_data.frame(list(), n = 2)
+#> data frame with 0 columns and 2 rows
+
+

There are two additional restrictions we could implement if we were being very strict: both the row names and column names should be unique.

+

Q2: Enhance my factor() helper to have better behaviour when one or more values is not found in levels. What does base::factor() do in this situation?

+

A: base::factor() converts these values (silently) into NAs:

+
+
factor(c("a", "b", "c"), levels = c("a", "b"))
+#> [1] a    b    <NA>
+#> Levels: a b
+
+

The factor() helper including the constructor (new_factor()) and its validator (validate_factor()) were given in Advanced R. However, as the goal of this question is to throw an early error within the helper, we only repeat the code for the helper:

+
+
# Simplified version of the factor() helper, as defined in Advanced R
+factor <- function(x = character(), levels = unique(x)) {
+  ind <- match(x, levels)
+  validate_factor(new_factor(ind, levels))
+}
+
+

To improve the factor() helper we choose to return an informative error message instead.

+
+
factor2 <- function(x, levels = unique(x)) {
+  new_levels <- match(x, levels)
+  
+  # Error if levels don't include all values
+  missing <- unique(setdiff(x, levels))
+  if (length(missing) > 0) {
+    stop(
+      "The following values do not occur in the levels of x: ",
+      paste0("'", missing, "'", collapse = ", "), ".", 
+      call. = FALSE
+    )
+  }
+  
+  validate_factor(new_factor(new_levels, levels))
+}
+
+# Test
+factor2(c("a", "b", "c"), levels = c("a", "b"))
+#> Error: The following values do not occur in the levels of x: 'c'.
+
+

Q3: Carefully read the source code of factor(). What does it do that our constructor does not?

+

A: The original implementation (base::factor()) allows more flexible input for x. It coerces x to character or replaces it with character(0) (in case of NULL). It also ensures that the levels are unique. This is achieved by setting them via base::levels<-, which fails when duplicate values are supplied.

+

Q4: Factors have an optional “contrasts” attribute. Read the help for C(), and briefly describe the purpose of the attribute. What type should it have? Rewrite the new_factor() constructor to include this attribute.

+

A: When factor variables (representing nominal or ordinal information) are used in statistical models, they are typically encoded as dummy variables and by default each level is compared with the first factor level. However, many different encodings (“contrasts”) are possible, see https://en.wikipedia.org/wiki/Contrast_(statistics).

+

Within R’s formula interface you can wrap a factor in stats::C() and specify the contrast of your choice. Alternatively, you can set the contrasts attribute of your factor variable, which accepts matrix input. (See ?contr.helmert or similar for details.)

+

The new_factor() constructor was given in Advanced R as:

+
+
# new_factor() constructor from Advanced R
+new_factor <- function(x = integer(), levels = character()) {
+  stopifnot(is.integer(x))
+  stopifnot(is.character(levels))
+
+  structure(
+    x,
+    levels = levels,
+    class = "factor"
+  )
+}
+
+

Our updated new_factor() constructor gets a contrasts argument, which accepts a numeric matrix or NULL (default).

+
+
# Updated new_factor() constructor
+new_factor <- function(
+  x = integer(),
+  levels = character(),
+  contrasts = NULL
+) {
+  stopifnot(is.integer(x))
+  stopifnot(is.character(levels))
+  
+  if (!is.null(constrasts)) {
+    stopifnot(is.matrix(contrasts) && is.numeric(contrasts))
+  }
+  
+  structure(
+    x,
+    levels = levels,
+    class = "factor",
+    contrasts = contrasts
+  )
+}
+
+

Q5: Read the documentation for utils::as.roman(). How would you write a constructor for this class? Does it need a validator? What might a helper do?

+

A: This function transforms numeric input into Roman numbers. It is built on the integer type, which results in the following constructor.

+
+
new_roman <- function(x = integer()) {
+  stopifnot(is.integer(x))
+  structure(x, class = "roman")
+}
+
+

The documentation tells us, that only values between 1 and 3899 are uniquely represented, which we then include in our validation function.

+
+
validate_roman <- function(x) {
+  values <- unclass(x)
+  
+  if (any(values < 1 | values > 3899)) {
+    stop(
+      "Roman numbers must fall between 1 and 3899.",
+      call. = FALSE
+    )
+  }
+  
+  x
+}
+
+

For convenience, we allow the user to also pass real values to a helper function.

+
+
roman <- function(x = integer()) {
+  x <- as.integer(x)
+  
+  validate_roman(new_roman(x))
+}
+
+# Test
+roman(c(1, 753, 2019))
+#> [1] I       DCCLIII MMXIX
+roman(0)
+#> Error: Roman numbers must fall between 1 and 3899.
+
+
+
+

Generics and methods

+

Q1: Read the source code for t() and t.test() and confirm that t.test() is an S3 generic and not an S3 method. What happens if you create an object with class test and call t() with it? Why?

+
+
x <- structure(1:10, class = "test")
+t(x)
+
+

A: We can see that t.test() is a generic because it calls UseMethod():

+
+
t.test
+#> function (x, ...) 
+#> UseMethod("t.test")
+#> <bytecode: 0x580b4c5c2f68>
+#> <environment: namespace:stats>
+
+# or simply call
+ftype(t.test)
+#> [1] "S3"      "generic"
+
+# The same holds for t()
+t
+#> function (x) 
+#> UseMethod("t")
+#> <bytecode: 0x580b4ce1f4f8>
+#> <environment: namespace:base>
+
+

Interestingly, R also provides helpers, which list functions that look like methods, but in fact are not:

+
+
tools::nonS3methods("stats")
+#> [1] "anova.lmlist"        "expand.model.frame"  "fitted.values"      
+#> [4] "influence.measures"  "lag.plot"            "t.test"             
+#> [7] "plot.spec.phase"     "plot.spec.coherency"
+
+

When we create an object with class test, t() dispatches to the t.default() method. This happens, because UseMethod() simply searches for functions named paste0("generic", ".", c(class(x), "default")).

+
+
x <- structure(1:10, class = "test")
+
+t(x)
+#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
+#> [1,]    1    2    3    4    5    6    7    8    9    10
+#> attr(,"class")
+#> [1] "test"
+
+

However, in older versions of R (pre R 4.0.0; when Advanced R was written) this behaviour was slightly different. Instead of dispatching to the t.default() method, the t.test() generic was erroneously treated as a method of t() which then dispatched to t.test.default() or (when defined) to t.test.test().

+
+
# Output in R version 3.6.2
+x <- structure(1:10, class = "test")
+t(x)
+#>
+#>  One Sample t-test
+#>
+#> data:  x
+#> t = 5.7446, df = 9, p-value = 0.0002782
+#> alternative hypothesis: true mean is not equal to 0
+#> 95 percent confidence interval:
+#>  3.334149 7.665851
+#> sample estimates:
+#> mean of x 
+#>       5.5 
+
+t.test.test <- function(x) "Hi!"
+t(x)
+#>[1] "Hi!"
+
+

Q2: What generics does the table class have methods for?

+

A: This is a simple application of sloop::s3_methods_class():

+
+
s3_methods_class("table")
+#> # A tibble: 10 × 4
+#>    generic       class visible source             
+#>    <chr>         <chr> <lgl>   <chr>              
+#>  1 [             table TRUE    base               
+#>  2 aperm         table TRUE    base               
+#>  3 as.data.frame table TRUE    base               
+#>  4 Axis          table FALSE   registered S3method
+#>  5 lines         table FALSE   registered S3method
+#>  6 plot          table FALSE   registered S3method
+#>  7 points        table FALSE   registered S3method
+#>  8 print         table TRUE    base               
+#>  9 summary       table TRUE    base               
+#> 10 tail          table FALSE   registered S3method
+
+

Interestingly, the table class has a number of methods designed to help plotting with base graphics.

+
+
x <- rpois(100, 5)
+plot(table(x))
+
+
+
+

+
+
+
+
+

Q3: What generics does the ecdf class have methods for?

+

A: We use the same approach as above:

+
+
s3_methods_class("ecdf")
+#> # A tibble: 4 × 4
+#>   generic  class visible source             
+#>   <chr>    <chr> <lgl>   <chr>              
+#> 1 plot     ecdf  TRUE    stats              
+#> 2 print    ecdf  FALSE   registered S3method
+#> 3 quantile ecdf  FALSE   registered S3method
+#> 4 summary  ecdf  FALSE   registered S3method
+
+

The methods are primarily designed for display (plot(), print(), summary()), but you can also extract quantiles with quantile().

+

Q4: Which base generic has the greatest number of defined methods?

+

A: A little experimentation (and thinking about the most popular functions) suggests that the print() generic has the most defined methods.

+
+
nrow(s3_methods_generic("print"))
+#> [1] 310
+nrow(s3_methods_generic("summary"))
+#> [1] 41
+nrow(s3_methods_generic("plot"))
+#> [1] 34
+
+

Let’s verify this programmatically with the tools we have learned in this and the previous chapters.

+
+
library(purrr)
+
+ls(all.names = TRUE, env = baseenv()) %>% 
+  mget(envir = baseenv()) %>% 
+  keep(is_function) %>% 
+  names() %>% 
+  keep(is_s3_generic) %>% 
+  map(~ set_names(nrow(s3_methods_generic(.x)), .x)) %>% 
+  flatten_int() %>% 
+  sort(decreasing = TRUE) %>% 
+  head()
+#>        print       format            [ as.character      summary         plot 
+#>          310          146           59           46           41           34
+
+

Q5: Carefully read the documentation for UseMethod() and explain why the following code returns the results that it does. What two usual rules of function evaluation does UseMethod() violate?

+
+
g <- function(x) {
+  x <- 10
+  y <- 10
+  UseMethod("g")
+}
+g.default <- function(x) c(x = x, y = y)
+
+x <- 1
+y <- 1
+g(x)
+#>  x  y 
+#>  1 10
+
+

A: Let’s take this step by step. If you call g.default(x) directly you get c(1, 1) as you might expect.

+

The value bound to x comes from the argument, the value from y comes from the global environment.

+
+
g.default(x)
+#> x y 
+#> 1 1
+
+

But when we call g(x) we get c(1, 10):

+
+
g(x)
+#>  x  y 
+#>  1 10
+
+

This is seemingly inconsistent: why does x come from the value defined inside of g(), and y still come from the global environment? It’s because UseMethod() calls g.default() in a special way so that variables defined inside the generic are available to methods. The exception are arguments supplied to the function: they are passed on as is and cannot be affected by code inside the generic.

+

Q6: What are the arguments to [? Why is this a hard question to answer?

+

A: The subsetting operator [ is a primitive and a generic function, which can be confirmed via ftype().

+
+
ftype(`[`)
+#> [1] "primitive" "generic"
+
+

For primitive functions formals([) returns NULL so we need to find another way to determine the functions arguments. One possible way to figure out [’s arguments would be to inspect the underlying C source code, which can be searched for via pryr::show_c_source(.Primitive("[")).

+

When we inspect the arguments of some of [’s methods, we see that the arguments vary with the class of x.

+
+
names(formals(`[.data.frame`))
+#> [1] "x"    "i"    "j"    "drop"
+names(formals(`[.table`))
+#> [1] "x"    "i"    "j"    "..."  "drop"
+names(formals(`[.Date`))
+#> [1] "x"    "..."  "drop"
+names(formals(`[.AsIs`))
+#> [1] "x"   "i"   "..."
+
+

To finally get a better overview, we have to put in a little more effort and also use s3_methods_generic() again.

+
+
library(dplyr)
+
+s3_methods_generic("[") %>%
+  filter(visible) %>%
+  mutate(
+    method = paste0("[.", class),
+    argnames = purrr::map(method, ~ names(formals(.x))),
+    args = purrr::map(method, ~ formals(.x)),
+    args = purrr::map2(
+      argnames, args,
+      ~ paste(.x, .y, sep = " = ")
+    ),
+    args = purrr::set_names(args, method)
+  ) %>%
+  pull(args) %>%
+  head()
+#> $`[.AsIs`
+#> [1] "x = "   "i = "   "... = "
+#> 
+#> $`[.data.frame`
+#> [1] "x = "                                              
+#> [2] "i = "                                              
+#> [3] "j = "                                              
+#> [4] "drop = if (missing(i)) TRUE else length(cols) == 1"
+#> 
+#> $`[.Date`
+#> [1] "x = "        "... = "      "drop = TRUE"
+#> 
+#> $`[.difftime`
+#> [1] "x = "        "... = "      "drop = TRUE"
+#> 
+#> $`[.Dlist`
+#> [1] "x = "   "i = "   "... = "
+#> 
+#> $`[.DLLInfoList`
+#> [1] "x = "   "... = "
+
+
+
+

Object styles

+

Q1: Categorise the objects returned by lm(), factor(), table(), as.Date(), as.POSIXct(), ecdf(), ordered(), I() into the styles described above.

+

A: We can categorise the return values into the various object styles by observing how the number of observations is calculated: For vector style classes, length(x) represents the number of observations. Record style objects use a list of equal length elements to represent individual components. For data frames and matrices, the observations are represented by the rows. Scalar style objects use a list to represent a single thing.

+

This leads us to:

+
    +
  • Vector object-style: factor(), table(), as.Date(), as.POSIXct(), ordered()
  • +
  • Record object-style: not observed
  • +
  • Data frame object-style: not observed
  • +
  • Scalar object-style: lm(), ecdf()
  • +
+

The object style of I() depends on the input since this function returns a “copy of the object with class AsIs prepended to the class(es)”.

+

Q2: What would a constructor function for lm objects, new_lm(), look like? Use ?lm and experimentation to figure out the required fields and their types.

+

A: The constructor needs to populate the attributes of an lm object and check their types for correctness. Let’s start by creating a simple lm object and explore its underlying base type and attributes:

+
+
mod <- lm(cyl ~ ., data = mtcars)
+
+typeof(mod)
+#> [1] "list"
+
+attributes(mod)
+#> $names
+#>  [1] "coefficients"  "residuals"     "effects"       "rank"         
+#>  [5] "fitted.values" "assign"        "qr"            "df.residual"  
+#>  [9] "xlevels"       "call"          "terms"         "model"        
+#> 
+#> $class
+#> [1] "lm"
+
+

As mod is built upon a list, we can simply use map(mod, typeof) to find out the base types of its elements. (Additionally, we inspect ?lm, to learn more about the individual attributes.)

+
+
map_chr(mod, typeof)
+#>  coefficients     residuals       effects          rank fitted.values 
+#>      "double"      "double"      "double"     "integer"      "double" 
+#>        assign            qr   df.residual       xlevels          call 
+#>     "integer"        "list"     "integer"        "list"    "language" 
+#>         terms         model 
+#>    "language"        "list"
+
+

Now we should have enough information to write a constructor for new lm objects.

+
+
new_lm <- function(
+  coefficients, residuals, effects, rank, fitted.values, assign,
+  qr, df.residual, xlevels, call, terms, model
+) {
+  
+  stopifnot(
+    is.double(coefficients), is.double(residuals), 
+    is.double(effects), is.integer(rank), is.double(fitted.values),
+    is.integer(assign), is.list(qr), is.integer(df.residual),
+    is.list(xlevels), is.language(call), is.language(terms),
+    is.list(model)
+  )
+  
+  structure(
+    list(
+      coefficients = coefficients,
+      residuals = residuals,
+      effects = effects,
+      rank = rank, 
+      fitted.values = fitted.values,
+      assign = assign,
+      qr = qr,
+      df.residual = df.residual,
+      xlevels = xlevels,
+      call = call,
+      terms = terms, 
+      model = model
+    ),
+    class = "lm"
+  )
+}
+
+
+
+

Inheritance

+

Q1: How does [.Date support subclasses? How does it fail to support subclasses?

+

A: [.Date calls .Date with the result of calling [ on the parent class, along with oldClass():

+
+
`[.Date`
+#> function (x, ..., drop = TRUE) 
+#> {
+#>     .Date(NextMethod("["), oldClass(x))
+#> }
+#> <bytecode: 0x580b4c38d620>
+#> <environment: namespace:base>
+
+

.Date is kind of like a constructor for date classes, although it doesn’t check the input is the correct type:

+
+
.Date
+#> function (xx, cl = "Date") 
+#> `class<-`(xx, cl)
+#> <bytecode: 0x580b4fb47758>
+#> <environment: namespace:base>
+
+

oldClass() is basically the same as class(), except that it doesn’t return implicit classes, i.e. it’s basically attr(x, "class") (looking at the C code that’s exactly what it does, except that it also handles S4 objects).

+

As oldClass() is “basically” class(), we can rewrite [.Date to make the implementation more clear:

+
+
`[.Date` <- function(x, ..., drop = TRUE) {
+  out <- NextMethod("[")
+  class(out) <- class(x)
+  out
+}
+
+

So, [.Date ensures that the output has the same class as in the input. But what about other attributes that a subclass might possess? They get lost:

+
+
x <- structure(1:4, test = "test", class = c("myDate", "Date"))
+attributes(x[1])
+#> $class
+#> [1] "myDate" "Date"
+
+

Q2: R has two classes for representing date time data, POSIXct and POSIXlt, which both inherit from POSIXt. Which generics have different behaviours for the two classes? Which generics share the same behaviour?

+

A: To answer this question, we have to get the respective generics

+
+
generics_t  <- s3_methods_class("POSIXt")$generic
+generics_ct <- s3_methods_class("POSIXct")$generic
+generics_lt <- s3_methods_class("POSIXlt")$generic
+
+

The generics in generics_t with a method for the superclass POSIXt potentially share the same behaviour for both subclasses. However, if a generic has a specific method for one of the subclasses, it has to be subtracted:

+
+
# These generics provide subclass-specific methods
+union(generics_ct, generics_lt)
+#>  [1] "["             "[["            "[<-"           "as.data.frame"
+#>  [5] "as.Date"       "as.list"       "as.POSIXlt"    "c"            
+#>  [9] "format"        "length<-"      "mean"          "print"        
+#> [13] "rep"           "split"         "summary"       "Summary"      
+#> [17] "weighted.mean" "xtfrm"         "[[<-"          "$<-"          
+#> [21] "anyNA"         "as.double"     "as.matrix"     "as.POSIXct"   
+#> [25] "as.vector"     "duplicated"    "is.finite"     "is.infinite"  
+#> [29] "is.na"         "is.nan"        "length"        "names"        
+#> [33] "names<-"       "sort"          "unique"
+
+# These generics share (inherited) methods for both subclasses
+setdiff(generics_t, union(generics_ct, generics_lt))
+#>  [1] "-"            "+"            "all.equal"    "as.character" "Axis"        
+#>  [6] "cut"          "diff"         "hist"         "is.numeric"   "julian"      
+#> [11] "Math"         "months"       "Ops"          "pretty"       "quantile"    
+#> [16] "quarters"     "round"        "seq"          "str"          "trunc"       
+#> [21] "weekdays"
+
+

Q3: What do you expect this code to return? What does it actually return? Why?

+
+
generic2 <- function(x) UseMethod("generic2")
+generic2.a1 <- function(x) "a1"
+generic2.a2 <- function(x) "a2"
+generic2.b <- function(x) {
+  class(x) <- "a1"
+  NextMethod()
+}
+
+generic2(structure(list(), class = c("b", "a2")))
+
+

A: When we execute the code above, this is what is happening:

+
    +
  • we pass an object of classes b and a2 to generic2(), which prompts R to look for a methodgeneric2.b()

  • +
  • the method generic2.b() then changes the class to a1 and calls NextMethod()

  • +
  • One would think that this will lead R to call generic2.a1(), but in fact, as mentioned in Advanced R, NextMethod()

    +
    +

    doesn’t actually work with the class attribute of the object, but instead uses a special global variable (.Class) to keep track of which method to call next.

    +
    +

    This is why generic2.a2() is called instead.

    +

    ::: {.cell layout-align=“center” hash=‘13_S3_cache/html/ch13_44_8c6cf6f696f18f5dcc4121e7c3e7a7f2’}

    +
    generic2(structure(list(), class = c("b", "a2")))
    +#> [1] "a2"
    +

    :::

  • +
+

Let’s just double check the statement above and evaluate .Class explicitly within the generic2.b() method.

+
+
generic2.b <- function(x) {
+  class(x) <- "a1"
+  print(.Class)
+  NextMethod()
+}
+
+generic2(structure(list(), class = c("b", "a2")))
+#> [1] "b"  "a2"
+#> [1] "a2"
+
+
+
+

Dispatch details

+

Q1: Explain the differences in dispatch below:

+
+
length.integer <- function(x) 10
+
+x1 <- 1:5
+class(x1)
+#> [1] "integer"
+s3_dispatch(length(x1))
+#>  * length.integer
+#>    length.numeric
+#>    length.default
+#> => length (internal)
+
+x2 <- structure(x1, class = "integer")
+class(x2)
+#> [1] "integer"
+s3_dispatch(length(x2))
+#> => length.integer
+#>    length.default
+#>  * length (internal)
+
+

A: class() returns integer in both cases. However, while the class of x1 is created implicitly and inherits from the numeric class, the class of x2 is set explicitly. This is important because length() is an internal generic and internal generics only dispatch to methods when the class attribute has been set, i.e. internal generics do not use implicit classes.

+

An object has no explicit class if attr(x, "class") returns NULL:

+
+
attr(x1, "class")
+#> NULL
+attr(x2, "class")
+#> [1] "integer"
+
+

To see the relevant classes for the S3 dispatch, one can use sloop::s3_class():

+
+
s3_class(x1)  # implicit
+#> [1] "integer" "numeric"
+
+s3_class(x2)  # explicit
+#> [1] "integer"
+
+

For a better understanding of s3_dipatch()’s output we quote from ?s3_dispatch:

+
    +
  • => method exists and is found by UseMethod().
  • +
  • -> method exists and is used by NextMethod().
  • +
  • * method exists but is not used.
  • +
  • Nothing (and greyed out in console): method does not exist.
  • +
+

Q2: What classes have a method for the Math() group generic in base R? Read the source code. How do the methods work?

+

A: The following functions belong to this group (see ?Math):

+
    +
  • abs, sign, sqrt, floor, ceiling, trunc, round, signif
  • +
  • exp, log, expm1, log1p, cos, sin, tan, cospi, sinpi, tanpi, acos, asin, atan, cosh, sinh, tanh, acosh, asinh, atanh
  • +
  • lgamma, gamma, digamma, trigamma
  • +
  • cumsum, cumprod, cummax, cummin
  • +
+

The following classes have a method for this group generic:

+
+
s3_methods_generic("Math")
+#> # A tibble: 8 × 4
+#>   generic class      visible source             
+#>   <chr>   <chr>      <lgl>   <chr>              
+#> 1 Math    data.frame TRUE    base               
+#> 2 Math    Date       TRUE    base               
+#> 3 Math    difftime   TRUE    base               
+#> 4 Math    factor     TRUE    base               
+#> 5 Math    POSIXt     TRUE    base               
+#> 6 Math    quosure    FALSE   registered S3method
+#> 7 Math    vctrs_sclr FALSE   registered S3method
+#> 8 Math    vctrs_vctr FALSE   registered S3method
+
+

To explain the basic idea, we just overwrite the data frame method:

+
+
Math.data.frame <- function(x) "hello"
+
+

Now all functions from the math generic group, will return "hello"

+
+
abs(mtcars)
+#> [1] "hello"
+exp(mtcars)
+#> [1] "hello"
+lgamma(mtcars)
+#> [1] "hello"
+
+

Of course, different functions should perform different calculations. Here .Generic comes into play, which provides us with the calling generic as a string

+
+
Math.data.frame <- function(x, ...) {
+  .Generic
+}
+
+abs(mtcars)
+#> [1] "abs"
+exp(mtcars)
+#> [1] "exp"
+lgamma(mtcars)
+#> [1] "lgamma"
+
+rm(Math.data.frame)
+
+

The original source code of Math.data.frame() is a good example on how to invoke the string returned by .Generic into a specific method. Math.factor() is a good example of a method, which is simply defined for better error messages.

+

Q3: Math.difftime() is more complicated than I described. Why?

+

A: Math.difftime() also excludes cases apart from abs, sign, floor, ceiling, trunc, round and signif and needs to return a fitting error message.

+

For comparison: Math.difftime() as defined in Advanced R:

+
+
Math.difftime <- function(x, ...) {
+  new_difftime(NextMethod(), units = attr(x, "units"))
+}
+rm(Math.difftime)
+
+

Math.difftime() as defined in the {base} package:

+
+
Math.difftime
+#> function (x, ...) 
+#> {
+#>     switch(.Generic, abs = , sign = , floor = , ceiling = , trunc = , 
+#>         round = , signif = {
+#>             units <- attr(x, "units")
+#>             .difftime(NextMethod(), units)
+#>         }, stop(gettextf("'%s' not defined for \"difftime\" objects", 
+#>             .Generic), domain = NA))
+#> }
+#> <bytecode: 0x580b4d8f7740>
+#> <environment: namespace:base>
+
+
+
+

References

+ + +
+
+Bååth, Rasmus. 2012. “The State of Naming Conventions in r.” The R Journal 4 (2): 74–75. https://doi.org/10.32614/RJ-2012-018. +
+
+Wickham, Hadley. 2019. Sloop: Helpers for ’OOP’ in r. https://github.com/r-lib/sloop. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/14_R6.html b/docs/14_R6.html new file mode 100644 index 00000000..bc869cf7 --- /dev/null +++ b/docs/14_R6.html @@ -0,0 +1,1034 @@ + + + + + + + + + + +Advanced R Solutions - 14 - R6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

14 - R6

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

To solve the exercises in this chapter we will have to create R6 objects, which are implemented in the {R6} package (Chang 2020).

+
+
library(R6)
+
+
+
+

Classes and methods

+

Q1: Create a bank account R6 class that stores a balance and allows you to deposit and withdraw money. Create a subclass that throws an error if you attempt to go into overdraft. Create another subclass that allows you to go into overdraft, but charges you a fee.

+

A: Let’s start with a basic bank account, similar to the Accumulator class in Advanced R.

+
+
BankAccount <- R6Class(
+  classname = "BankAccount",
+  public = list(
+    balance = 0,
+    deposit = function(dep = 0) {
+      self$balance <- self$balance + dep
+      invisible(self)
+    },
+    withdraw = function(draw) {
+      self$balance <- self$balance - draw
+      invisible(self)
+    }
+  )
+)
+
+

To test this class, we create one instance and leave it with a negative balance.

+
+
my_account <- BankAccount$new()
+my_account$balance
+#> [1] 0
+
+my_account$
+  deposit(5)$
+  withdraw(15)$
+  balance
+#> [1] -10
+
+

Now, we create the first subclass that prevents us from going into overdraft and throws an error in case we attempt to withdraw more than our current balance.

+
+
BankAccountStrict <- R6Class(
+  classname = "BankAccountStrict",
+  inherit = BankAccount,
+  public = list(
+    withdraw = function(draw = 0) {
+      if (self$balance - draw < 0) {
+        stop("Your `withdraw` must be smaller ",
+          "than your `balance`.",
+          call. = FALSE
+        )
+      }
+      super$withdraw(draw = draw)
+    }
+  )
+)
+
+

This time our test should throw an error.

+
+
my_strict_account <- BankAccountStrict$new()
+my_strict_account$balance
+#> [1] 0
+
+my_strict_account$
+  deposit(5)$
+  withdraw(15)
+#> Error: Your `withdraw` must be smaller than your `balance`.
+
+my_strict_account$balance
+#> [1] 5
+
+

Finally, we create another subclass that charges a constant fee of 1 for each withdrawal which leaves the account with a negative balance.

+
+
BankAccountCharging <- R6Class(
+  classname = "BankAccountCharging",
+  inherit = BankAccount,
+  public = list(
+    withdraw = function(draw = 0) {
+      if (self$balance - draw < 0) {
+        draw <- draw + 1
+      }
+      super$withdraw(draw = draw)
+    }
+  )
+)
+
+

Let’s take a look at the implemented functionality. We expect a final balance of -12, because we pay the fee twice.

+
+
my_charging_account <- BankAccountCharging$new()
+my_charging_account$balance
+#> [1] 0
+
+my_charging_account$
+  deposit(5)$
+  withdraw(15)$
+  withdraw(0)
+
+my_charging_account$balance
+#> [1] -12
+
+

Q2: Create an R6 class that represents a shuffled deck of cards. You should be able to draw cards from the deck with $draw(n), and return all cards to the deck and reshuffle with $reshuffle(). Use the following code to make a vector of cards.

+
+
suit <- c("SPADE", "HEARTS", "DIAMOND", "CLUB")
+value <- c("A", 2:10, "J", "Q", "K")
+cards <- paste(rep(value, 4), suit)
+
+

(This question was altered slightly to avoid the unicode characters.)

+

A: Our new ShuffledDeck class will use sample() and positive integer subsetting to implement the reshuffling and drawing functionality. We also add a check, so you cannot draw more cards than there are left in the deck.

+
+
ShuffledDeck <- R6Class(
+  classname = "ShuffledDeck",
+  public = list(
+    deck = NULL,
+    initialize = function(deck = cards) {
+      self$deck <- sample(deck)
+    },
+    reshuffle = function() {
+      self$deck <- sample(cards)
+      invisible(self)
+    },
+    n = function() {
+      length(self$deck)
+    },
+    draw = function(n = 1) {
+      if (n > self$n()) {
+        stop("Only ", self$n(), " cards remaining.", call. = FALSE)
+      }
+
+      output <- self$deck[seq_len(n)]
+      self$deck <- self$deck[-seq_len(n)]
+      output
+    }
+  )
+)
+
+

To test this class, we create a deck (initialise an instance), draw all the cards, then reshuffle, checking we get different cards each time.

+
+
my_deck <- ShuffledDeck$new()
+
+my_deck$draw(52)
+#>  [1] "6 SPADE"    "10 DIAMOND" "Q CLUB"     "J SPADE"    "Q HEARTS"  
+#>  [6] "8 DIAMOND"  "5 DIAMOND"  "4 CLUB"     "9 CLUB"     "9 SPADE"   
+#> [11] "5 SPADE"    "3 HEARTS"   "J CLUB"     "2 DIAMOND"  "K SPADE"   
+#> [16] "2 HEARTS"   "2 SPADE"    "8 SPADE"    "8 HEARTS"   "6 HEARTS"  
+#> [21] "7 HEARTS"   "6 CLUB"     "K CLUB"     "3 CLUB"     "10 SPADE"  
+#> [26] "3 DIAMOND"  "Q SPADE"    "9 HEARTS"   "J DIAMOND"  "7 DIAMOND" 
+#> [31] "9 DIAMOND"  "7 SPADE"    "4 DIAMOND"  "10 HEARTS"  "2 CLUB"    
+#> [36] "4 SPADE"    "4 HEARTS"   "8 CLUB"     "K HEARTS"   "A SPADE"   
+#> [41] "A HEARTS"   "5 HEARTS"   "A DIAMOND"  "5 CLUB"     "7 CLUB"    
+#> [46] "Q DIAMOND"  "A CLUB"     "10 CLUB"    "3 SPADE"    "K DIAMOND" 
+#> [51] "J HEARTS"   "6 DIAMOND"
+my_deck$draw(10)
+#> Error: Only 0 cards remaining.
+
+my_deck$reshuffle()$draw(5)
+#> [1] "6 DIAMOND" "2 CLUB"    "Q DIAMOND" "9 CLUB"    "J DIAMOND"
+my_deck$reshuffle()$draw(5)
+#> [1] "8 CLUB"   "9 SPADE"  "2 SPADE"  "Q HEARTS" "6 SPADE"
+
+

Q3: Why can’t you model a bank account or a deck of cards with an S3 class?

+

A: Because S3 classes obey R’s usual semantics of copy-on-modify: every time you deposit money into your bank account or draw a card from the deck, you’d get a new copy of the object.

+

It is possible to combine S3 classes with an environment (which is how R6 works), but it is ill-advised to create an object that looks like a regular R object but has reference semantics.

+

Q4: Create an R6 class that allows you to get and set the current time zone. You can access the current time zone with Sys.timezone() and set it with Sys.setenv(TZ = "newtimezone"). When setting the time zone, make sure the new time zone is in the list provided by OlsonNames().

+

A: To create an R6 class that allows us to get and set the time zone, we provide the respective functions as public methods to the R6 class.

+
+
Timezone <- R6Class(
+  classname = "Timezone",
+  public = list(
+    get = function() {
+      Sys.timezone()
+    },
+    set = function(value) {
+      stopifnot(value %in% OlsonNames())
+
+      old <- self$get()
+      Sys.setenv(TZ = value)
+      invisible(old)
+    }
+  )
+)
+
+

(When setting, we return the old value invisibly because this makes it easy to restore the previous value.)

+

Now, let us create one instance of this class and test, if we can set and get the time zone as intended.

+
+
tz <- Timezone$new()
+
+old <- tz$set("Antarctica/South_Pole")
+tz$get()
+#> [1] "America/Toronto"
+
+tz$set(old)
+tz$get()
+#> [1] "America/Toronto"
+
+

Q5: Create an R6 class that manages the current working directory. It should have $get() and $set() methods.

+

A: Take a look at the following implementation, which is quite minimalistic:

+
+
WorkingDirectory <- R6Class(
+  classname = "WorkingDirectory",
+  public = list(
+    get = function() {
+      getwd()
+    },
+    set = function(value) {
+      setwd(value)
+    }
+  )
+)
+
+ +

Q6: Why can’t you model the time zone or current working directory with an S3 class?

+

A: Because S3 classes are not suitable for modelling a state that changes over time. S3 methods should (almost) always return the same result when called with the same inputs.

+

Q7: What base type are R6 objects built on top of? What attributes do they have?

+

A: R6 objects are built on top of environments. They have a class attribute, which is a character vector containing the class name, the name of any super classes (if existent) and the string "R6" as the last element.

+
+
+

Controlling access

+

Q1: Create a bank account class that prevents you from directly setting the account balance, but that you can still withdraw from and deposit to. Throw an error if you attempt to go into overdraft.

+

A: To fulfil this requirement, we make balance a private field. The user has to use the $deposit() and $withdraw() methods which have access to the balance field.

+
+
BankAccountStrict2 <- R6Class(
+  classname = "BankAccountStrict2",
+  public = list(
+    deposit = function(dep = 0) {
+      private$balance <- private$balance + dep
+      invisible(self)
+    },
+    withdraw = function(draw = 0) {
+      if (private$balance - draw < 0) {
+        stop(
+          "Your `withdraw` must be smaller ",
+          "than your `balance`.",
+          call. = FALSE
+        )
+      }
+      private$balance <- private$balance - draw
+      invisible(self)
+    }
+  ),
+  private = list(
+    balance = 0
+  )
+)
+
+

To test our new class, we create an instance and try to go into overdraft.

+
+
my_account_strict_2 <- BankAccountStrict2$new()
+
+my_account_strict_2$deposit(5)
+my_account_strict_2$withdraw(10)
+#> Error: Your `withdraw` must be smaller than your `balance`.
+
+

Q2: Create a class with a write-only $password field. It should have $check_password(password) method that returns TRUE or FALSE, but there should be no way to view the complete password.

+

A: To protect the password from changes and direct access, the password will be a private field. Further, our Password will get its own print method which hides the password.

+
+
Password <- R6Class(
+  classname = "Password",
+  public = list(
+    print = function(...) {
+      cat("<Password>: ********\n")
+      invisible(self)
+    },
+    set = function(value) {
+      private$password <- value
+    },
+    check = function(password) {
+      identical(password, private$password)
+    }
+  ),
+  private = list(
+    password = NULL
+  )
+)
+
+

Let’s create one instance of our new class and confirm that the password is neither accessible nor visible, but still check-able.

+
+
my_pw <- Password$new()
+my_pw$set("snuffles")
+my_pw$password
+#> NULL
+my_pw
+#> <Password>: ********
+my_pw$check("snuggles")
+#> [1] FALSE
+my_pw$check("snuffles")
+#> [1] TRUE
+
+

Q3: Extend the Rando class with another active binding that allows you to access the previous random value. Ensure that active binding is the only way to access the value.

+

A: To access the previous random value from an instance, we add a private $last_random field to our class, and we modify $random() to write to this field, whenever it is called. To access the $last_random field we provide $previous().

+
+
Rando <- R6::R6Class(
+  classname = "Rando",
+  private = list(
+    last_random = NULL
+  ),
+  active = list(
+    random = function(value) {
+      if (missing(value)) {
+        private$last_random <- runif(1)
+        private$last_random
+      } else {
+        stop("Can't set `$random`.", call. = FALSE)
+      }
+    },
+    previous = function(value) {
+      if (missing(value)) {
+        private$last_random
+      }
+    }
+  )
+)
+
+

Now, we initiate a new Rando object and see if it behaves as expected.

+
+
x <- Rando$new()
+x$random
+#> [1] 0.349
+x$random
+#> [1] 0.947
+x$previous
+#> [1] 0.947
+
+

Q4: Can subclasses access private fields/methods from their parent? Perform an experiment to find out.

+

A: To find out if private fields/methods can be accessed from subclasses, we first create a class A with a private field foo and a private method bar(). Afterwards, an instance of a subclass B is created and calls the foobar() methods, which tries to access the foo field and the bar() method from its superclass A.

+
+
A <- R6Class(
+  classname = "A",
+  private = list(
+    field = "foo",
+    method = function() {
+      "bar"
+    }
+  )
+)
+
+B <- R6Class(
+  classname = "B",
+  inherit = A,
+  public = list(
+    test = function() {
+      cat("Field:  ", super$field, "\n", sep = "")
+      cat("Method: ", super$method(), "\n", sep = "")
+    }
+  )
+)
+
+B$new()$test()
+#> Field:  
+#> Method: bar
+
+

We conclude that subclasses can access private methods from their superclasses, but not private fields.

+
+
+

Reference semantics

+

Q1: Create a class that allows you to write a line to a specified file. You should open a connection to the file in $initialize(), append a line using cat() in $append_line(), and close the connection in $finalize().

+

A: Our FileWriter class will create a connection to a file at initialization. Therefore, we open a connection to a user specified file during the initialisation. Note that we need to set open = "a" in file() to open connection for appending text. Otherwise, cat() would only work when applied to files, but not with connections as explicitly asked for in the exercise. Further, we add the append_line() method and a close() statement as finalizer.

+
+
FileWriter <- R6::R6Class(
+  classname = "FileWriter",
+  public = list(
+    con = NULL,
+    initialize = function(filename) {
+      self$con <- file(filename, open = "a")
+    },
+    finalize = function() {
+      close(self$con)
+    },
+    append_line = function(x) {
+      cat(x, "\n", sep = "", file = self$con)
+    }
+  )
+)
+
+

Let’s see, if new instances of our class work as expected.

+
+
tmp_file <- tempfile()
+my_fw <- FileWriter$new(tmp_file)
+
+readLines(tmp_file)
+#> character(0)
+my_fw$append_line("First")
+my_fw$append_line("Second")
+readLines(tmp_file)
+#> [1] "First"  "Second"
+
+
+
+

References

+ + +
+
+Chang, Winston. 2020. R6: Encapsulated Classes with Reference Semantics. https://github.com/r-lib/R6. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/15_S4.html b/docs/15_S4.html new file mode 100644 index 00000000..f946fe19 --- /dev/null +++ b/docs/15_S4.html @@ -0,0 +1,1007 @@ + + + + + + + + + + +Advanced R Solutions - 15 - S4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

15 - S4

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

We load the {methods} package (R Core Team 2020) as it contains the S4 object-oriented programming system.

+
+
library(methods)
+
+
+
+

Basics

+

Q1: lubridate::period() returns an S4 class. What slots does it have? What class is each slot? What accessors does it provide?

+

A: Objects of the S4 Period class have six slots named year, month, day, hour, minute, and .Data (which contains the number of seconds). All slots are of type double. Most fields can be retrieved by an identically named accessor (e.g. lubridate::year() will return the field), use second() to get the .Data slot.

+

As a short example, we create a period of 1 second, 2 minutes, 3 hours, 4 days and 5 weeks.

+
+
example_12345 <- lubridate::period(
+  c(1, 2, 3, 4, 5),
+  c("second", "minute", "hour", "day", "week")
+)
+
+

This should add up to a period of 39 days, 3 hours, 2 minutes and 1 second.

+
+
example_12345
+#> [1] "39d 3H 2M 1S"
+
+

When we inspect example_12345, we see the fields and infer that the seconds are stored in the .Data field.

+
+
str(example_12345)
+#> Formal class 'Period' [package "lubridate"] with 6 slots
+#>   ..@ .Data : num 1
+#>   ..@ year  : num 0
+#>   ..@ month : num 0
+#>   ..@ day   : num 39
+#>   ..@ hour  : num 3
+#>   ..@ minute: num 2
+
+

Q2: What other ways can you find help for a method? Read ?"?" and summarise the details.

+

A: Besides adding ? in front of a function call (i.e. ?method()), we may find:

+
    +
  • general documentation for a generic via ?genericName
  • +
  • general documentation for the methods of a generic via methods?genericName
  • +
  • documentation for a specific method via ClassName?methodName.
  • +
+
+
+

Classes

+

Q1: Extend the Person class with fields to match utils::person(). Think about what slots you will need, what class each slot should have, and what you’ll need to check in your validity method.

+

A: The Person class from Advanced R contains the slots name and age. The person class from the {utils} package contains the slots given (vector of given names), family, role, email and comment (see ?utils::person).

+

All slots from utils::person() besides role must be of type character and length 1. The entries in the role slot must match one of the following abbreviations “aut”, “com”, “cph”, “cre”, “ctb”, “ctr”, “dtc”, “fnd”, “rev”, “ths”, “trl”. Therefore, role might be of different length than the other slots and we’ll add a corresponding constraint within the validator.

+
+
# Definition of the Person class
+setClass("Person",
+  slots = c(
+    age = "numeric",
+    given = "character",
+    family = "character",
+    role = "character",
+    email = "character",
+    comment = "character"
+  ),
+  prototype = list(
+    age = NA_real_,
+    given = NA_character_,
+    family = NA_character_,
+    role = NA_character_,
+    email = NA_character_,
+    comment = NA_character_
+  )
+)
+
+# Helper to create instances of the Person class
+Person <- function(given, family,
+                   age = NA_real_,
+                   role = NA_character_,
+                   email = NA_character_,
+                   comment = NA_character_) {
+  age <- as.double(age)
+
+  new("Person",
+    age = age,
+    given = given,
+    family = family,
+    role = role,
+    email = email,
+    comment = comment
+  )
+}
+
+# Validator to ensure that each slot is of length one
+setValidity("Person", function(object) {
+  invalids <- c()
+  if (length(object@age) != 1 ||
+    length(object@given) != 1 ||
+    length(object@family) != 1 ||
+    length(object@email) != 1 ||
+    length(object@comment) != 1) {
+    invalids <- paste0(
+      "@name, @age, @given, @family, @email, ",
+      "@comment must be of length 1"
+    )
+  }
+
+  known_roles <- c(
+    NA_character_, "aut", "com", "cph", "cre", "ctb",
+    "ctr", "dtc", "fnd", "rev", "ths", "trl"
+  )
+
+  if (!all(object@role %in% known_roles)) {
+    paste(
+      "@role(s) must be one of",
+      paste(known_roles, collapse = ", ")
+    )
+  }
+
+  if (length(invalids)) {
+    return(invalids)
+  }
+  TRUE
+})
+#> Class "Person" [in ".GlobalEnv"]
+#> 
+#> Slots:
+#>                                                                   
+#> Name:        age     given    family      role     email   comment
+#> Class:   numeric character character character character character
+
+

Q2: What happens if you define a new S4 class that doesn’t have any slots? (Hint: read about virtual classes in ?setClass.)

+

A: It depends on the other arguments. If we inherit from another class, we get the same slots. But something interesting happens if we don’t inherit from an existing class. We get a virtual class. A virtual class can’t be instantiated:

+
+
setClass("Human")
+new("Human")
+#> Error in new("Human"): trying to generate an object from a virtual class ("Human")
+
+

But can be inherited from:

+
+
setClass("Programmer", contains = "Human")
+
+

Q3: Imagine you were going to reimplement factors, dates, and data frames in S4. Sketch out the setClass() calls that you would use to define the classes. Think about appropriate slots and prototype.

+

A: For all these classes we need one slot for the data and one slot per attribute. Keep in mind, that inheritance matters for ordered factors and dates. For data frames, special checks like equal lengths of the underlying list’s elements should be done within a validator.

+

For simplicity we don’t introduce an explicit subclass for ordered factors. Instead, we introduce ordered as a slot.

+
+
setClass("Factor",
+  slots = c(
+    data = "integer",
+    levels = "character",
+    ordered = "logical"
+  ),
+  prototype = list(
+    data = integer(),
+    levels = character(),
+    ordered = FALSE
+  )
+)
+
+
+new("Factor", data = c(1L, 2L), levels = letters[1:3])
+#> An object of class "Factor"
+#> Slot "data":
+#> [1] 1 2
+#> 
+#> Slot "levels":
+#> [1] "a" "b" "c"
+#> 
+#> Slot "ordered":
+#> [1] FALSE
+
+

The Date2 class stores its dates as integers, similarly to base R which uses doubles. Dates don’t have any other attributes.

+
+
setClass("Date2",
+  slots = list(
+    data = "integer"
+  ),
+  prototype = list(
+    data = integer()
+  )
+)
+
+new("Date2", data = 1L)
+#> An object of class "Date2"
+#> Slot "data":
+#> [1] 1
+
+

Our DataFrame class consists of a list and a slot for row.names. Most of the logic (e.g. checking that all elements of the list are a vector, and that they all have the same length) would need to be part of a validator.

+
+
setClass("DataFrame",
+  slots = c(
+    data = "list",
+    row.names = "character"
+  ),
+  prototype = list(
+    data = list(),
+    row.names = character(0)
+  )
+)
+
+new("DataFrame", data = list(a = 1, b = 2))
+#> An object of class "DataFrame"
+#> Slot "data":
+#> $a
+#> [1] 1
+#> 
+#> $b
+#> [1] 2
+#> 
+#> 
+#> Slot "row.names":
+#> character(0)
+
+
+
+

Generics and methods

+

Q1: Add age() accessors for the Person class.

+

A: We implement the accessors via an age() generic, with a method for the Person class and a corresponding replacement function age<-:

+
+
setGeneric("age", function(x) standardGeneric("age"))
+#> [1] "age"
+setMethod("age", "Person", function(x) x@age)
+
+setGeneric("age<-", function(x, value) standardGeneric("age<-"))
+#> [1] "age<-"
+setMethod("age<-", "Person", function(x, value) {
+  x@age <- value
+  validObject(x)
+  x
+})
+
+

Q2: In the definition of the generic, why is it necessary to repeat the name of the generic twice?

+

A: Within setGeneric() the name (1st argument) is needed as the name of the generic. Then, the name also explicitly incorporates method dispatch via standardGeneric() within the generic’s body (def parameter of setGeneric()). This behaviour is similar to UseMethod() in S3.

+

Q3: Why does the show() method defined in section 15.4.3 use is(object)[[1]]? (Hint: try printing the employee subclass.)

+

A: is(object) returns the class of the object. is(object) also contains the superclass, for subclasses like Employee. In order to always return the most specific class (the subclass), show() returns the first element of is(object).

+

Q4: What happens if you define a method with different argument names to the generic?

+

A: It depends. We first create the object hadley of class Person:

+
+
.Person <- setClass(
+  "Person",
+  slots = c(name = "character", age = "numeric")
+)
+
+hadley <- .Person(name = "Hadley")
+hadley
+#> An object of class "Person"
+#> Slot "name":
+#> [1] "Hadley"
+#> 
+#> Slot "age":
+#> numeric(0)
+
+

Now let’s see which arguments can be supplied to the show() generic.

+
+
formals("show")
+#> $object
+
+

Usually, we would use this argument when defining a new method.

+
+
setMethod("show", "Person", function(object) {
+  cat(object@name, "creates hard exercises")
+})
+
+hadley
+#> Hadley creates hard exercises
+
+

When we supply another name as a first element of our method (e.g. x instead of object), this element will be matched to the correct object argument and we receive a warning. Our method will work, though:

+
+
setMethod("show", "Person", function(x) {
+  cat(x@name, "creates hard exercises")
+})
+#> Warning: For function 'show', signature 'Person': argument in method definition
+#> changed from (x) to (object)
+
+hadley
+#> Hadley creates hard exercises
+
+

If we add more arguments to our method than our generic can handle, we will get an error.

+
+
setMethod("show", "Person", function(x, y) {
+  cat(x@name, "is", x@age, "years old")
+})
+#> Error in conformMethod(signature, mnames, fnames, f, fdef, definition): in method for 'show' with signature 'object="Person"': formal arguments (object = "Person") omitted in the method definition cannot be in the signature
+
+

If we do this with arguments added to the correctly written object argument, we will receive an informative error message. It states that we could add other argument names for generics, which can take the ... argument.

+
+
setMethod("show", "Person", function(object, y) {
+  cat(object@name, "is", object@age, "years old")
+})
+#> Error in rematchDefinition(definition, fdef, mnames, fnames, signature): methods can add arguments to the generic 'show' only if '...' is an argument to the generic
+
+
+
+

Method dispatch

+

Q1: Draw the method graph for f(😅, 😽).

+

A: Look at the graph and repeat after me: “I will keep my class structure simple and use multiple inheritance sparingly”.

+
+
+
+
+

+
+
+
+
+

Q2: Draw the method graph for f(😃, 😉, 😙).

+

A: We see that the method graph below looks simpler than the one above. Relatively speaking, multiple dispatch seems to introduce less complexity than multiple inheritance. Use it with care, though!

+
+
+
+
+

+
+
+
+
+

Q3: Take the last example which shows multiple dispatch over two classes that use multiple inheritance. What happens if you define a method for all terminal classes? Why does method dispatch not save us much work here?

+

A: We will introduce ambiguity, since one class has distance 2 to all terminal nodes and the other four have distance 1 to two terminal nodes each. To resolve this ambiguity we have to define five more methods, one per class combination.

+
+
+

S4 and S3

+

Q1: What would a full setOldClass() definition look like for an ordered factor (i.e. add slots and prototype to the definition above)?

+

A: The purpose of setOldClass() lies in registering an S3 class as a “formally defined class”, so that it can be used within the S4 object-oriented programming system. When using it, we may provide the argument S4Class, which will inherit the slots and their default values (prototype) to the registered class.

+

Let’s build an S4 OrderedFactor on top of the S3 factor in such a way.

+
+
setOldClass("factor") # use build-in definition for brevity
+
+OrderedFactor <- setClass(
+  "OrderedFactor",
+  contains = "factor", # inherit from registered S3 class
+  slots = c(
+    levels = "character",
+    ordered = "logical" # add logical order slot
+  ),
+  prototype = structure(
+    integer(),
+    levels = character(),
+    ordered = logical() # add default value
+  )
+)
+
+

We can now register the (S3) ordered-class, while providing an “S4 template”. We can also use the S4-class to create new object directly.

+
+
setOldClass("ordered", S4Class = "OrderedFactor")
+
+x <- OrderedFactor(
+  c(1L, 2L, 2L),
+  levels = c("a", "b", "c"),
+  ordered = TRUE
+)
+str(x)
+#> Formal class 'OrderedFactor' [package ".GlobalEnv"] with 4 slots
+#>   ..@ .Data   : int [1:3] 1 2 2
+#>   ..@ levels  : chr [1:3] "a" "b" "c"
+#>   ..@ ordered : logi TRUE
+#>   ..@ .S3Class: chr "factor"
+
+

Q2: Define a length method for the Person class.

+

A: We keep things simple and will just return "180cm" when the length() method is called on a Person object. The method can be defined either as an S3 or S4 method.

+
+
length.Person <- function(x) "180cm" # S3
+setMethod("length", "Person", function(x) "180cm") # S4
+
+
+
+

References

+ + +
+
+R Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/18_Expressions.html b/docs/18_Expressions.html new file mode 100644 index 00000000..3c81cd23 --- /dev/null +++ b/docs/18_Expressions.html @@ -0,0 +1,1312 @@ + + + + + + + + + + +Advanced R Solutions - 18 - Expressions + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

18 - Expressions

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

To capture and compute on expressions, and to visualise them, we will load the {rlang} (Henry and Wickham 2020) and the {lobstr} (Wickham 2019) packages.

+
+
library(rlang)
+library(lobstr)
+
+
+
+

Abstract syntax trees

+

Q1: Reconstruct the code represented by the trees below:

+
+
#> █─f 
+#> └─█─g 
+#>   └─█─h
+#> █─`+` 
+#> ├─█─`+` 
+#> │ ├─1 
+#> │ └─2 
+#> └─3
+#> █─`*` 
+#> ├─█─`(` 
+#> │ └─█─`+` 
+#> │   ├─x 
+#> │   └─y 
+#> └─z
+
+

A: Let the source (of the code chunks above) be with you and show you how the ASTs (abstract syntax trees) were produced.

+
+
ast(f(g(h())))
+#> █─f 
+#> └─█─g 
+#>   └─█─h
+
+ast(1 + 2 + 3)
+#> █─`+` 
+#> ├─█─`+` 
+#> │ ├─1 
+#> │ └─2 
+#> └─3
+
+ast((x + y) * z)
+#> █─`*` 
+#> ├─█─`(` 
+#> │ └─█─`+` 
+#> │   ├─x 
+#> │   └─y 
+#> └─z
+
+

Q2: Draw the following trees by hand then check your answers with ast().

+
+
f(g(h(i(1, 2, 3))))
+f(1, g(2, h(3, i())))
+f(g(1, 2), h(3, i(4, 5)))
+
+

A: Let us delegate the drawing to the {lobstr} package.

+
+
ast(f(g(h(i(1, 2, 3)))))
+#> █─f 
+#> └─█─g 
+#>   └─█─h 
+#>     └─█─i 
+#>       ├─1 
+#>       ├─2 
+#>       └─3
+
+ast(f(1, g(2, h(3, i()))))
+#> █─f 
+#> ├─1 
+#> └─█─g 
+#>   ├─2 
+#>   └─█─h 
+#>     ├─3 
+#>     └─█─i
+
+ast(f(g(1, 2), h(3, i(4, 5))))
+#> █─f 
+#> ├─█─g 
+#> │ ├─1 
+#> │ └─2 
+#> └─█─h 
+#>   ├─3 
+#>   └─█─i 
+#>     ├─4 
+#>     └─5
+
+

Q3: What’s happening with the ASTs below? (Hint: carefully read ?"^")

+
+
ast(`x` + `y`)
+#> █─`+` 
+#> ├─x 
+#> └─y
+ast(x**y)
+#> █─`^` 
+#> ├─x 
+#> └─y
+ast(1 -> x)
+#> █─`<-` 
+#> ├─x 
+#> └─1
+
+

A: ASTs start function calls with the name of the function. This is why the call in the first expression is translated into its prefix form. In the second case, ** is translated by R’s parser into ^. In the last AST, the expression is flipped when R parses it:

+
+
str(expr(x**y))
+#>  language x^y
+str(expr(a -> b))
+#>  language b <- a
+
+

Q4: What is special about the AST below? (Hint: re-read section 6.2.1)

+
+
ast(function(x = 1, y = 2) {})
+#> █─`function` 
+#> ├─█─x = 1 
+#> │ └─y = 2 
+#> ├─█─`{` 
+#> └─<inline srcref>
+
+

A: The last leaf of the AST is not explicitly specified in the expression. Instead, the srcref attribute, which points to the functions source code, is automatically created by base R.

+

Q5: What does the call tree of an if statement with multiple else if conditions look like? Why?

+

A: The AST of nested else if statements might look a bit confusing because it contains multiple curly braces. However, we can see that in the else part of the AST just another expression is being evaluated, which happens to be an if statement and so forth.

+
+
ast(
+  if (FALSE) {
+    1
+  } else if (FALSE) {
+    2
+  } else if (TRUE) {
+    3
+  }
+)
+#> █─`if` 
+#> ├─FALSE 
+#> ├─█─`{` 
+#> │ └─1 
+#> └─█─`if` 
+#>   ├─FALSE 
+#>   ├─█─`{` 
+#>   │ └─2 
+#>   └─█─`if` 
+#>     ├─TRUE 
+#>     └─█─`{` 
+#>       └─3
+
+

We can see the structure more clearly if we avoid the curly braces:

+
+
ast(
+  if (FALSE) {
+    1
+  } else if (FALSE) {
+    2
+  } else if (TRUE) 3
+)
+#> █─`if` 
+#> ├─FALSE 
+#> ├─█─`{` 
+#> │ └─1 
+#> └─█─`if` 
+#>   ├─FALSE 
+#>   ├─█─`{` 
+#>   │ └─2 
+#>   └─█─`if` 
+#>     ├─TRUE 
+#>     └─3
+
+
+
+

Expressions

+

Q1: Which two of the six types of atomic vector can’t appear in an expression? Why? Similarly, why can’t you create an expression that contains an atomic vector of length greater than one?

+

A: There is no way to create raws and complex atomics without using a function call (this is only possible for imaginary scalars like i, 5i etc.). But expressions that include a function are calls. Therefore, both of these vector types cannot appear in an expression.

+

Similarly, it is not possible to create an expression that evaluates to an atomic of length greater than one without using a function (e.g. c()).

+

Let’s make this observation concrete via an example:

+
+
# Atomic
+is_atomic(expr(1))
+#> [1] TRUE
+
+# Not an atomic (although it would evaluate to an atomic)
+is_atomic(expr(c(1, 1)))
+#> [1] FALSE
+is_call(expr(c(1, 1)))
+#> [1] TRUE
+
+

Q2: What happens when you subset a call object to remove the first element, e.g. expr(read.csv("foo.csv", header = TRUE))[-1]. Why?

+

A: When the first element of a call object is removed, the second element moves to the first position, which is the function to call. Therefore, we get "foo.csv"(header = TRUE).

+

Q3: Describe the differences between the following call objects.

+
+
x <- 1:10
+
+call2(median, x, na.rm = TRUE)
+call2(expr(median), x, na.rm = TRUE)
+call2(median, expr(x), na.rm = TRUE)
+call2(expr(median), expr(x), na.rm = TRUE)
+
+

A: The call objects differ in their first two elements, which are in some cases evaluated before the call is constructed. In the first one, both median() and x are evaluated and inlined into the call. Therefore, we can see in the constructed call that median is a generic and the x argument is 1:10.

+
+
call2(median, x, na.rm = TRUE)
+#> (function (x, na.rm = FALSE, ...) 
+#> UseMethod("median"))(1:10, na.rm = TRUE)
+
+

In the following calls we remain with differing combinations. Once, only x and once only median() gets evaluated.

+
+
call2(expr(median), x, na.rm = TRUE)
+#> median(1:10, na.rm = TRUE)
+call2(median, expr(x), na.rm = TRUE)
+#> (function (x, na.rm = FALSE, ...) 
+#> UseMethod("median"))(x, na.rm = TRUE)
+
+

In the final call neither x nor median() is evaluated.

+
+
call2(expr(median), expr(x), na.rm = TRUE)
+#> median(x, na.rm = TRUE)
+
+

Note that all these calls will generate the same result when evaluated. The key difference is when the values bound to the x and median symbols are found.

+

Q4: rlang::call_standardise() doesn’t work so well for the following calls. Why? What makes mean() special?

+
+
call_standardise(quote(mean(1:10, na.rm = TRUE)))
+#> Warning: `call_standardise()` is deprecated as of rlang 0.4.11
+#> This warning is displayed once every 8 hours.
+#> mean(x = 1:10, na.rm = TRUE)
+call_standardise(quote(mean(n = T, 1:10)))
+#> mean(x = 1:10, n = T)
+call_standardise(quote(mean(x = 1:10, , TRUE)))
+#> mean(x = 1:10, , TRUE)
+
+

A: The reason for this unexpected behaviour is that mean() uses the ... argument and therefore cannot standardise the regarding arguments. Since mean() uses S3 dispatch (i.e. UseMethod()) and the underlying mean.default() method specifies some more arguments, call_standardise() can do much better with a specific S3 method.

+
+
call_standardise(quote(mean.default(1:10, na.rm = TRUE)))
+#> mean.default(x = 1:10, na.rm = TRUE)
+call_standardise(quote(mean.default(n = T, 1:10)))
+#> mean.default(x = 1:10, na.rm = T)
+call_standardise(quote(mean.default(x = 1:10, , TRUE)))
+#> mean.default(x = 1:10, na.rm = TRUE)
+
+

Q5: Why does this code not make sense?

+
+
x <- expr(foo(x = 1))
+names(x) <- c("x", "")
+
+

A: As stated in Advanced R

+
+

The first element of a call is always the function that gets called.

+
+

Let’s see what happens when we run the code

+
+
x <- expr(foo(x = 1))
+x
+#> foo(x = 1)
+
+names(x) <- c("x", "")
+x
+#> foo(1)
+
+names(x) <- c("", "x")
+x
+#> foo(x = 1)
+
+

So, giving the first element a name just adds metadata that R ignores.

+

Q6: Construct the expression if(x > 1) "a" else "b" using multiple calls to call2(). How does the code structure reflect the structure of the AST?

+

A: Similar to the prefix version we get

+
+
call2("if", call2(">", sym("x"), 1), "a", "b")
+#> if (x > 1) "a" else "b"
+
+

When we read the AST from left to right, we get the same structure: Function to evaluate, expression, which is another function and is evaluated first, and two constants which will be evaluated next.

+
+
ast(`if`(x > 1, "a", "b"))
+#> █─`if` 
+#> ├─█─`>` 
+#> │ ├─x 
+#> │ └─1 
+#> ├─"a" 
+#> └─"b"
+
+
+
+

Parsing and grammar

+

Q1: R uses parentheses in two slightly different ways as illustrated by these two calls:

+
+
f((1))
+`(`(1 + 1)
+
+

Compare and contrast the two uses by referencing the AST.

+

A: The trick with these examples lies in the fact that ( can be a part of R’s general prefix function syntax but can also represent a call to the ( function.

+

So, in the AST of the first example, we will not see the outer ( since it is prefix function syntax and belongs to f(). In contrast, the inner ( is a function (represented as a symbol in the AST):

+
+
ast(f((1)))
+#> █─f 
+#> └─█─`(` 
+#>   └─1
+
+

In the second example, we can see that the outer ( is a function and the inner ( belongs to its syntax:

+
+
ast(`(`(1 + 1))
+#> █─`(` 
+#> └─█─`+` 
+#>   ├─1 
+#>   └─1
+
+

For the sake of clarity, let’s also create a third example, where none of the ( is part of another function’s syntax:

+
+
ast(((1 + 1)))
+#> █─`(` 
+#> └─█─`(` 
+#>   └─█─`+` 
+#>     ├─1 
+#>     └─1
+
+

Q2: = can also be used in two ways. Construct a simple example that shows both uses.

+

A: = is used both for assignment, and for naming arguments in function calls:

+
+
b <- c(c = 1)
+
+

So, when we play with ast(), we can directly see that the following is not possible:

+
+
ast(b = c(c = 1))
+#> Error in ast(b = c(c = 1)): unused argument (b = c(c = 1))
+
+

We get an error because b = makes R looking for an argument called b. Since x is the only argument of ast(), we get an error.

+

The easiest way around this problem is to wrap this line in {}.

+
+
ast({
+  b <- c(c = 1)
+})
+#> █─`{` 
+#> └─█─`<-` 
+#>   ├─b 
+#>   └─█─c 
+#>     └─c = 1
+
+

When we ignore the braces and compare the trees, we can see that the first = is used for assignment and the second = is part of the syntax of function calls.

+

Q3: Does -2^2 yield 4 or -4? Why?

+

A: It yields -4, because ^ has a higher operator precedence than -, which we can verify by looking at the AST (or looking it up under ?"Syntax"):

+
+
-2^2
+#> [1] -4
+
+ast(-2^2)
+#> █─`-` 
+#> └─█─`^` 
+#>   ├─2 
+#>   └─2
+
+

Q4: What does !1 + !1 return? Why?

+

A: The answer is a little surprising:

+
+
!1 + !1
+#> [1] FALSE
+
+

To answer the “why?”, we take a look at the AST:

+
+
ast(!1 + !1)
+#> █─`!` 
+#> └─█─`+` 
+#>   ├─1 
+#>   └─█─`!` 
+#>     └─1
+
+

The right !1 is evaluated first. It evaluates to FALSE, because R coerces every non 0 numeric to TRUE, when a logical operator is applied. The negation of TRUE then equals FALSE.

+

Next 1 + FALSE is evaluated to 1, since FALSE is coerced to 0.

+

Finally !1 is evaluated to FALSE.

+

Note that if ! had a higher precedence, the intermediate result would be FALSE + FALSE, which would evaluate to 0.

+

Q5: Why does x1 <- x2 <- x3 <- 0 work? Describe the two reasons.

+

A: One reason is that <- is right-associative, i.e. evaluation takes place from right to left:

+
+
x1 <- (x2 <- (x3 <- 0))
+
+

The other reason is that <- invisibly returns the value on the right-hand side.

+
+
(x3 <- 0)
+#> [1] 0
+
+

Q6: Compare the ASTs of x + y %+% z and x ^ y %+% z. What have you learned about the precedence of custom infix functions?

+

A: Let’s take a look at the syntax trees:

+
+
ast(x + y %+% z)
+#> █─`+` 
+#> ├─x 
+#> └─█─`%+%` 
+#>   ├─y 
+#>   └─z
+
+

Here y %+% z will be calculated first and the result will be added to x.

+
+
ast(x^y %+% z)
+#> █─`%+%` 
+#> ├─█─`^` 
+#> │ ├─x 
+#> │ └─y 
+#> └─z
+
+

Here x ^ y will be calculated first, and the result will be used as first argument to %+%().

+

We can conclude that custom infix functions have precedence between addition and exponentiation.

+

The exact precedence of infix functions can be looked up under ?"Syntax" where we see that it lies directly behind the sequence operator (:) and in front of the multiplication and division operators (* and /).

+

Q7: What happens if you call parse_expr() with a string that generates multiple expressions, e.g. parse_expr("x + 1; y + 1")?

+

A: In this case parse_expr() notices that more than one expression would have to be generated and throws an error.

+
+
parse_expr("x + 1; y + 1")
+#> Error in `parse_expr()`:
+#> ! `x` must contain exactly 1 expression, not 2.
+
+

Q8: What happens if you attempt to parse an invalid expression, e.g. "a +" or "f())"?

+

A: Invalid expressions will lead to an error in the underlying parse() function.

+
+
parse_expr("a +")
+#> Error in parse(text = x, keep.source = FALSE): <text>:2:0: unexpected end of input
+#> 1: a +
+#>    ^
+parse_expr("f())")
+#> Error in parse(text = x, keep.source = FALSE): <text>:1:4: unexpected ')'
+#> 1: f())
+#>        ^
+
+parse(text = "a +")
+#> Error in parse(text = "a +"): <text>:2:0: unexpected end of input
+#> 1: a +
+#>    ^
+parse(text = "f())")
+#> Error in parse(text = "f())"): <text>:1:4: unexpected ')'
+#> 1: f())
+#>        ^
+
+

Q9: deparse() produces vectors when the input is long. For example, the following call produces a vector of length two:

+
+
expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m +
+  n + o + p + q + r + s + t + u + v + w + x + y + z))
+
+deparse(expr)
+
+

What does expr_text() do instead?

+

A: expr_text() will paste the results from deparse(expr) together and use a linebreak (\n) as separator.

+
+
expr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m +
+  n + o + p + q + r + s + t + u + v + w + x + y + z))
+deparse(expr)
+#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n + "
+#> [2] "o + p + q + r + s + t + u + v + w + x + y + z)"
+expr_text(expr)
+#> [1] "g(a + b + c + d + e + f + g + h + i + j + k + l + m + n
+#> + \n    o + p + q + r + s + t + u + v + w + x + y + z)"
+
+

Q10: pairwise.t.test() assumes that deparse() always returns a length one character vector. Can you construct an input that violates this expectation? What happens?

+

A: The function pairwise.t.test() captures its data arguments (x and g) so it can print the input expressions along the computed p-values. Prior to R 4.0.0 this used to be implemented via deparse(substitute(x)) in combination with paste(). This could lead to unexpected output, if one of the inputs exceeded the default width.cutoff value of 60 characters within deparse(). In this case, the expression would be split into a character vector of length greater 1.

+
+
# Output in R version 3.6.2
+d <- 1
+pairwise.t.test(2, d + d + d + d + d + d + d + d +
+  d + d + d + d + d + d + d + d + d)
+#>  Pairwise comparisons using t tests with pooled SD
+#>
+#> data:  2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d
+#> + d + d +  2 and     d
+#>
+#> <0 x 0 matrix>
+#>
+#> P value adjustment method: holm
+
+

In R 4.0.0 pairwise.t.test() was updated to use the newly introduced deparse1(), which serves as a wrapper around deparse().

+
+

deparse1() is a simple utility added in R 4.0.0 to ensure a string result (character vector of length one), typically used in name construction, as deparse1(substitute(.)).

+
+
+
# Output since R 4.0.0
+d <- 1
+pairwise.t.test(2, d + d + d + d + d + d + d + d +
+  d + d + d + d + d + d + d + d + d)
+#>  Pairwise comparisons using t tests with pooled SD
+#>
+#> data:  2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d
+#> + d + d + d
+#>
+#> <0 x 0 matrix>
+#>
+#> P value adjustment method: holm
+
+
+
+

Walking AST with recursive functions

+

Q1: logical_abbr() returns TRUE for T(1, 2, 3). How could you modify logical_abbr_rec() so that it ignores function calls that use T or F?

+

A: We can apply a similar logic as in the assignment example from Advanced R. We just treat it as a special case handled within a sub function called find_T_call(), which finds T() calls and “bounces them out”. Therefore, we also repeat the expr_type() helper which tells us if we are in the base or in the recursive case.

+
+
expr_type <- function(x) {
+  if (rlang::is_syntactic_literal(x)) {
+    "constant"
+  } else if (is.symbol(x)) {
+    "symbol"
+  } else if (is.call(x)) {
+    "call"
+  } else if (is.pairlist(x)) {
+    "pairlist"
+  } else {
+    typeof(x)
+  }
+}
+
+switch_expr <- function(x, ...) {
+  switch(expr_type(x),
+    ...,
+    stop("Don't know how to handle type ",
+      typeof(x),
+      call. = FALSE
+    )
+  )
+}
+
+
+
find_T_call <- function(x) {
+  if (is_call(x, "T")) {
+    x <- as.list(x)[-1]
+    purrr::some(x, logical_abbr_rec)
+  } else {
+    purrr::some(x, logical_abbr_rec)
+  }
+}
+
+logical_abbr_rec <- function(x) {
+  switch_expr(
+    x,
+    # Base cases
+    constant = FALSE,
+    symbol = as_string(x) %in% c("F", "T"),
+
+    # Recursive cases
+    pairlist = purrr::some(x, logical_abbr_rec),
+    call = find_T_call(x)
+  )
+}
+
+logical_abbr <- function(x) {
+  logical_abbr_rec(enexpr(x))
+}
+
+

Now let’s test our new logical_abbr() function:

+
+
logical_abbr(T(1, 2, 3))
+#> [1] FALSE
+logical_abbr(T(T, T(3, 4)))
+#> [1] TRUE
+logical_abbr(T(T))
+#> [1] TRUE
+logical_abbr(T())
+#> [1] FALSE
+logical_abbr()
+#> [1] FALSE
+logical_abbr(c(T, T, T))
+#> [1] TRUE
+
+

Q2: logical_abbr() works with expressions. It currently fails when you give it a function. Why? How could you modify logical_abbr() to make it work? What components of a function will you need to recurse over?

+
+
f <- function(x = TRUE) {
+  g(x + T)
+}
+
+

A: The function currently fails, because "closure" is not handled in switch_expr() within logical_abbr_rec().

+
+
logical_abbr(!!f)
+#> Error: Don't know how to handle type closure
+
+

If we want to make it work, we have to write a function to also iterate over the formals and the body of the input function.

+

Q3: Modify find_assign to also detect assignment using replacement functions, i.e. names(x) <- y.

+

A: Let’s see what the AST of such an assignment looks like:

+
+
ast(names(x) <- x)
+#> █─`<-` 
+#> ├─█─names 
+#> │ └─x 
+#> └─x
+
+

So, we need to catch the case where the first two elements are both calls. Further the first call is identical to <- and we must return only the second call to see which objects got new values assigned.

+

This is why we add the following block within another else statement in find_assign_call():

+
+
if (is_call(x, "<-") && is_call(x[[2]])) {
+  lhs <- expr_text(x[[2]])
+  children <- as.list(x)[-1]
+}
+
+

Let us finish with the whole code, followed by some tests for our new function:

+
+
flat_map_chr <- function(.x, .f, ...) {
+  purrr::flatten_chr(purrr::map(.x, .f, ...))
+}
+
+find_assign <- function(x) unique(find_assign_rec(enexpr(x)))
+
+find_assign_call <- function(x) {
+  if (is_call(x, "<-") && is_symbol(x[[2]])) {
+    lhs <- as_string(x[[2]])
+    children <- as.list(x)[-1]
+  } else {
+    if (is_call(x, "<-") && is_call(x[[2]])) {
+      lhs <- expr_text(x[[2]])
+      children <- as.list(x)[-1]
+    } else {
+      lhs <- character()
+      children <- as.list(x)
+    }
+  }
+
+  c(lhs, flat_map_chr(children, find_assign_rec))
+}
+
+find_assign_rec <- function(x) {
+  switch_expr(
+    x,
+    # Base cases
+    constant = , symbol = character(),
+    # Recursive cases
+    pairlist = flat_map_chr(x, find_assign_rec),
+    call = find_assign_call(x)
+  )
+}
+
+# Tests functionality
+find_assign(x <- y)
+#> [1] "x"
+find_assign(names(x))
+#> character(0)
+find_assign(names(x) <- y)
+#> [1] "names(x)"
+find_assign(names(x(y)) <- y)
+#> [1] "names(x(y))"
+find_assign(names(x(y)) <- y <- z)
+#> [1] "names(x(y))" "y"
+
+

Q4: Write a function that extracts all calls to a specified function.

+

A: Here we need to delete the previously added else statement and check for a call (not necessarily <-) within the first if() in find_assign_call(). We save a call when we found one and return it later as part of our character output. Everything else stays the same:

+
+
find_assign_call <- function(x) {
+  if (is_call(x)) {
+    lhs <- expr_text(x)
+    children <- as.list(x)[-1]
+  } else {
+    lhs <- character()
+    children <- as.list(x)
+  }
+
+  c(lhs, flat_map_chr(children, find_assign_rec))
+}
+
+find_assign_rec <- function(x) {
+  switch_expr(
+    x,
+    # Base cases
+    constant = ,
+    symbol = character(),
+
+    # Recursive cases
+    pairlist = flat_map_chr(x, find_assign_rec),
+    call = find_assign_call(x)
+  )
+}
+
+find_assign(x <- y)
+#> [1] "x <- y"
+find_assign(names(x(y)) <- y <- z)
+#> [1] "names(x(y)) <- y <- z" "names(x(y))"           "x(y)"                 
+#> [4] "y <- z"
+find_assign(mean(sum(1:3)))
+#> [1] "mean(sum(1:3))" "sum(1:3)"       "1:3"
+
+
+
+

References

+ + +
+
+Henry, Lionel, and Hadley Wickham. 2020. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang. +
+
+Wickham, Hadley. 2019. Lobstr: Visualize r Data Structures with Trees. https://github.com/r-lib/lobstr. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/19_Quasiquotation.html b/docs/19_Quasiquotation.html new file mode 100644 index 00000000..26b8655f --- /dev/null +++ b/docs/19_Quasiquotation.html @@ -0,0 +1,1071 @@ + + + + + + + + + + +Advanced R Solutions - 19 - Quasiquotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

19 - Quasiquotation

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

To continue computing on the language, we keep using the {rlang} package in this chapter.

+
+
library(rlang)
+
+
+
+

Motivation

+

Q1: For each function in the following base R code, identify which arguments are quoted and which are evaluated.

+
+
library(MASS)
+
+mtcars2 <- subset(mtcars, cyl == 4)
+
+with(mtcars2, sum(vs))
+sum(mtcars2$am)
+
+rm(mtcars2)
+
+

A: For each argument we first follow the advice from Advanced R and execute the argument outside of the respective function. Since MASS, cyl, vs and am are not objects contained in the global environment, their execution raises an “Object not found” error. This way we confirm that the respective function arguments are quoted. For the other arguments, we may inspect the source code (and the documentation) to check if any quoting mechanisms are applied or the arguments are evaluated.

+
+
library(MASS) # MASS -> quoted
+
+

library() also accepts character vectors and doesn’t quote when character.only is set to TRUE, so library(MASS, character.only = TRUE) would raise an error.

+
+
mtcars2 <- subset(mtcars, cyl == 4) # mtcars -> evaluated
+# cyl -> quoted
+
+with(mtcars2, sum(vs)) # mtcars2 -> evaluated
+# sum(vs) -> quoted
+
+sum(mtcars2$am) # matcars$am -> evaluated
+# am -> quoted by $()
+
+

When we inspect the source code of rm(), we notice that rm() catches its ... argument as an unevaluated call (in this case a pairlist) via match.call(). This call is then converted into a string for further evaluation.

+
+
rm(mtcars2) # mtcars2 -> quoted
+
+

Q2: For each function in the following tidyverse code, identify which arguments are quoted and which are evaluated.

+
+
library(dplyr)
+library(ggplot2)
+
+by_cyl <- mtcars %>%
+  group_by(cyl) %>%
+  summarise(mean = mean(mpg))
+
+ggplot(by_cyl, aes(cyl, mean)) +
+  geom_point()
+
+

A: From the previous exercise we’ve already learned that library() quotes its first argument.

+
+
library(dplyr) # dplyr   -> quoted
+library(ggplot2) # ggplot2 -> quoted
+
+

In similar fashion, it becomes clear that cyl is quoted by group_by().

+
+
by_cyl <- mtcars %>% # mtcars -> evaluated
+  group_by(cyl) %>% # cyl -> quoted
+  summarise(mean = mean(mpg)) # mean = mean(mpg) -> quoted
+
+

To find out what happens in summarise(), we inspect the source code. Tracing down the S3-dispatch of summarise(), we see that the ... argument is quoted in dplyr:::summarise_cols() which is called in the underlying summarise.data.frame() method.

+
+
dplyr::summarise
+#> function (.data, ..., .by = NULL, .groups = NULL) 
+#> {
+#>     by <- enquo(.by)
+#>     if (!quo_is_null(by) && !is.null(.groups)) {
+#>         abort("Can't supply both `.by` and `.groups`.")
+#>     }
+#>     UseMethod("summarise")
+#> }
+#> <bytecode: 0x632cfde74b50>
+#> <environment: namespace:dplyr>
+
+
+
dplyr:::summarise.data.frame
+#> function (.data, ..., .by = NULL, .groups = NULL) 
+#> {
+#>     by <- compute_by({
+#>         {
+#>             .by
+#>         }
+#>     }, .data, by_arg = ".by", data_arg = ".data")
+#>     cols <- summarise_cols(.data, dplyr_quosures(...), by, "summarise")
+#>     out <- summarise_build(by, cols)
+#>     if (!cols$all_one) {
+#>         summarise_deprecate_variable_size()
+#>     }
+#>     if (!is_tibble(.data)) {
+#>         out <- as.data.frame(out)
+#>     }
+#>     if (identical(.groups, "rowwise")) {
+#>         out <- rowwise_df(out, character())
+#>     }
+#>     out
+#> }
+#> <bytecode: 0x632cf8b3b358>
+#> <environment: namespace:dplyr>
+
+
+
dplyr:::summarise_cols
+#> function (.data, ...)
+#> {
+#>     mask <- DataMask$new(.data, caller_env())
+#>     dots <- enquos(...)
+#>     dots_names <- names(dots)
+#>     auto_named_dots <- names(enquos(..., .named = TRUE))
+#>     cols <- list()
+#>     sizes <- 1L
+#>     chunks <- vector("list", length(dots))
+#>     types <- vector("list", length(dots))
+#>
+#>     ## function definition abbreviated for clarity ##
+#> }
+#> <bytecode: 0x55b540c07ca0>
+#> <environment: namespace:dplyr>
+
+

In the following {ggplot2} expression the cyl- and mean-objects are quoted.

+
+
ggplot(
+  by_cyl, # by_cyl -> evaluated
+  aes(cyl, mean)
+) + # aes() -> evaluated
+  # cyl, mean -> quoted (via aes)
+  geom_point()
+
+

We can confirm this also by inspecting aes()’s source code.

+
+
ggplot2::aes
+#> function (x, y, ...) 
+#> {
+#>     xs <- arg_enquos("x")
+#>     ys <- arg_enquos("y")
+#>     dots <- enquos(...)
+#>     args <- c(xs, ys, dots)
+#>     args <- Filter(Negate(quo_is_missing), args)
+#>     local({
+#>         aes <- function(x, y, ...) NULL
+#>         inject(aes(!!!args))
+#>     })
+#>     aes <- new_aes(args, env = parent.frame())
+#>     rename_aes(aes)
+#> }
+#> <bytecode: 0x632cfc5e3ce0>
+#> <environment: namespace:ggplot2>
+
+
+
+

Quoting

+

Q1: How is expr() implemented? Look at its source code.

+

A: expr() acts as a simple wrapper, which passes its argument to enexpr().

+
+
expr
+#> function (expr) 
+#> {
+#>     enexpr(expr)
+#> }
+#> <bytecode: 0x632cfc901de8>
+#> <environment: namespace:rlang>
+
+

Q2: Compare and contrast the following two functions. Can you predict the output before running them?

+
+
f1 <- function(x, y) {
+  exprs(x = x, y = y)
+}
+f2 <- function(x, y) {
+  enexprs(x = x, y = y)
+}
+f1(a + b, c + d)
+f2(a + b, c + d)
+
+

A: Both functions are able to capture multiple arguments and will return a named list of expressions. f1() will return the arguments defined within the body of f1(). This happens because exprs() captures the expressions as specified by the developer during the definition of f1().

+
+
f1(a + b, c + d)
+#> $x
+#> x
+#> 
+#> $y
+#> y
+
+

f2() will return the arguments supplied to f2() as specified by the user when the function is called.

+
+
f2(a + b, c + d)
+#> $x
+#> a + b
+#> 
+#> $y
+#> c + d
+
+

Q3: What happens if you try to use enexpr() with an expression (i.e. enexpr(x + y))? What happens if enexpr() is passed a missing argument?

+

A: In the first case an error is thrown:

+
+
on_expr <- function(x) {
+  enexpr(expr(x))
+}
+on_expr(x + y)
+#> Error in `enexpr()`:
+#> ! `arg` must be a symbol
+
+

In the second case a missing argument is returned:

+
+
on_missing <- function(x) {
+  enexpr(x)
+}
+on_missing()
+is_missing(on_missing())
+#> [1] TRUE
+
+

Q4: How are exprs(a) and exprs(a = ) different? Think about both the input and the output.

+

A: In exprs(a) the input a is interpreted as a symbol for an unnamed argument. Consequently, the output shows an unnamed list with the first element containing the symbol a.

+
+
out1 <- exprs(a)
+str(out1)
+#> List of 1
+#>  $ : symbol a
+
+

In exprs(a = ) the first argument is named a, but then no value is provided. This leads to the output of a named list with the first element named a, which contains the missing argument.

+
+
out2 <- exprs(a = )
+str(out2)
+#> List of 1
+#>  $ a: symbol
+is_missing(out2$a)
+#> [1] TRUE
+
+

Q5: What are other differences between exprs() and alist()? Read the documentation for the named arguments of exprs() to find out.

+

A: exprs() provides the additional arguments .named (= FALSE), .ignore_empty (c("trailing", "none", "all")) and .unquote_names (TRUE). .named allows to ensure that all dots are named. ignore_empty allows to specify how empty arguments should be handled for dots ("trailing") or all arguments ("none" and "all"). Further via .unquote_names one can specify if := should be treated like =. := can be useful as it supports unquoting (!!) on the left-hand side.

+

Q6: The documentation for substitute() says:

+
+

Substitution takes place by examining each component of the parse tree as follows:

+
    +
  • If it is not a bound symbol in env, it is unchanged.
  • +
  • If it is a promise object (i.e. a formal argument to a function) the expression slot of the promise replaces the symbol.
  • +
  • If it is an ordinary variable, its value is substituted, unless env is .GlobalEnv in which case the symbol is left unchanged.
  • +
+
+

Create examples that illustrate each of the above cases.

+

A: Let’s create a new environment my_env, which contains no objects. In this case substitute() will just return its first argument (expr):

+
+
my_env <- env()
+substitute(x, my_env)
+#> x
+
+

When we create a function containing an argument, which is directly returned after substitution, this function just returns the provided expression:

+
+
foo <- function(x) substitute(x)
+
+foo(x + y * sin(0))
+#> x + y * sin(0)
+
+

In case substitute() can find (parts of) the expression in env, it will literally substitute. However, unless env is .GlobalEnv.

+
+
my_env$x <- 7
+substitute(x, my_env)
+#> [1] 7
+
+x <- 7
+substitute(x, .GlobalEnv)
+#> x
+
+
+
+

Unquoting

+

Q1: Given the following components:

+
+
xy <- expr(x + y)
+xz <- expr(x + z)
+yz <- expr(y + z)
+abc <- exprs(a, b, c)
+
+

Use quasiquotation to construct the following calls:

+
+
(x + y) / (y + z) # (1)
+-(x + z)^(y + z) # (2)
+(x + y) + (y + z) - (x + y) # (3)
+atan2(x + y, y + z) # (4)
+sum(x + y, x + y, y + z) # (5)
+sum(a, b, c) # (6)
+mean(c(a, b, c), na.rm = TRUE) # (7)
+foo(a = x + y, b = y + z) # (8)
+
+

A: We combine and unquote the given quoted expressions to construct the desired calls like this:

+
+
expr(!!xy / !!yz) # (1)
+#> (x + y)/(y + z)
+
+expr(-(!!xz)^(!!yz)) # (2)
+#> -(x + z)^(y + z)
+
+expr(((!!xy)) + !!yz - !!xy) # (3)
+#> (x + y) + (y + z) - (x + y)
+
+expr(atan2(!!xy, !!yz)) # (4)
+#> atan2(x + y, y + z)
+
+expr(sum(!!xy, !!xy, !!yz)) # (5)
+#> sum(x + y, x + y, y + z)
+
+expr(sum(!!!abc)) # (6)
+#> sum(a, b, c)
+
+expr(mean(c(!!!abc), na.rm = TRUE)) # (7)
+#> mean(c(a, b, c), na.rm = TRUE)
+
+expr(foo(a = !!xy, b = !!yz)) # (8)
+#> foo(a = x + y, b = y + z)
+
+

Q2: The following two calls print the same, but are actually different:

+
+
(a <- expr(mean(1:10)))
+#> mean(1:10)
+(b <- expr(mean(!!(1:10))))
+#> mean(1:10)
+identical(a, b)
+#> [1] FALSE
+
+

What’s the difference? Which one is more natural?

+

A: It’s easiest to see the difference with lobstr::ast():

+
+
lobstr::ast(mean(1:10))
+#> █─mean 
+#> └─█─`:` 
+#>   ├─1 
+#>   └─10
+lobstr::ast(mean(!!(1:10)))
+#> █─mean 
+#> └─<inline integer>
+
+

In the expression mean(!!(1:10)) the call 1:10 is evaluated to an integer vector, while still being a call object in mean(1:10).

+

The first version (mean(1:10)) seems more natural. It captures lazy evaluation, with a promise that is evaluated when the function is called. The second version (mean(!!(1:10))) inlines a vector directly into a call.

+
+
+

... (dot-dot-dot)

+

Q1: One way to implement exec() is shown below. Describe how it works. What are the key ideas?

+
+
exec <- function(f, ..., .env = caller_env()) {
+  args <- list2(...)
+  do.call(f, args, envir = .env)
+}
+
+

A: exec() takes a function (f), its arguments (...) and an environment (.env) as input. This allows to construct a call from f and ... and evaluate this call in the supplied environment. As the ... argument is handled via list2(), exec() supports tidy dots (quasiquotation), which means that arguments and names (on the left-hand side of :=) can be unquoted via !! and !!!.

+

Q2: Carefully read the source code for interaction(), expand.grid(), and par(). Compare and contrast the techniques they use for switching between dots and list behaviour.

+

A: All three functions capture the dots via args <- list(...).

+

interaction() computes factor interactions between the captured input factors by iterating over the args. When a list is provided this is detected via length(args) == 1 && is.list(args[[1]]) and one level of the list is stripped through args <- args[[1]]. The rest of the function’s code doesn’t differentiate further between list and dots behaviour.

+
+
# Both calls create the same output
+interaction(a = c("a", "b", "c", "d"), b = c("e", "f")) # dots
+#> [1] a.e b.f c.e d.f
+#> Levels: a.e b.e c.e d.e a.f b.f c.f d.f
+interaction(list(a = c("a", "b", "c", "d"), b = c("e", "f"))) # list
+#> [1] a.e b.f c.e d.f
+#> Levels: a.e b.e c.e d.e a.f b.f c.f d.f
+
+

expand.grid() uses the same strategy and also assigns args <- args[[1]] in case of length(args) == 1 && is.list(args[[1]]).

+

par() does the most pre-processing to ensure a valid structure of the args argument. When no dots are provided (!length(args)) it creates a list of arguments from an internal character vector (partly depending on its no.readonly argument). Further, given that all elements of args are character vectors (all(unlist(lapply(args, is.character)))), args is turned into a list via as.list(unlist(args)) (this flattens nested lists). Similar to the other functions, one level of args gets stripped via args <- args[[1L]], when args is of length one and its first element is a list.

+

Q3: Explain the problem with this definition of set_attr()

+
+
set_attr <- function(x, ...) {
+  attr <- rlang::list2(...)
+  attributes(x) <- attr
+  x
+}
+set_attr(1:10, x = 10)
+#> Error in attributes(x) <- attr: attributes must be named
+
+

A: set_attr() expects an object named x and its attributes, supplied via the dots. Unfortunately, this prohibits us to provide attributes named x as these would collide with the argument name of our object. Even omitting the object’s argument name doesn’t help in this case — as can be seen in the example where the object is consequently treated as an unnamed attribute.

+

However, we may name the first argument .x, which seems clearer and less likely to invoke errors. In this case 1:10 will get the (named) attribute x = 10 assigned:

+
+
set_attr <- function(.x, ...) {
+  attr <- rlang::list2(...)
+
+  attributes(.x) <- attr
+  .x
+}
+
+set_attr(1:10, x = 10)
+#>  [1]  1  2  3  4  5  6  7  8  9 10
+#> attr(,"x")
+#> [1] 10
+
+
+
+

Case studies

+

Q1: In the linear-model example, we could replace the expr() in reduce(summands, ~ expr(!!.x + !!.y)) with call2(): reduce(summands, call2, "+"). Compare and contrast the two approaches. Which do you think is easier to read?

+

A: We would consider the first version to be more readable. There seems to be a little more boilerplate code at first, but the unquoting syntax is very readable. Overall, the whole expression seems more explicit and less complex.

+

Q2: Re-implement the Box-Cox transform defined below using unquoting and new_function():

+
+
bc <- function(lambda) {
+  if (lambda == 0) {
+    function(x) log(x)
+  } else {
+    function(x) (x^lambda - 1) / lambda
+  }
+}
+
+

A: Here new_function() allows us to create a function factory using tidy evaluation.

+
+
bc2 <- function(lambda) {
+  lambda <- enexpr(lambda)
+
+  if (!!lambda == 0) {
+    new_function(exprs(x = ), expr(log(x)))
+  } else {
+    new_function(exprs(x = ), expr((x^(!!lambda) - 1) / !!lambda))
+  }
+}
+
+bc2(0)
+#> function (x) 
+#> log(x)
+#> <environment: 0x632cfd501268>
+bc2(2)
+#> function (x) 
+#> (x^2 - 1)/2
+#> <environment: 0x632cfd573528>
+bc2(2)(2)
+#> [1] 1.5
+
+

Q3: Re-implement the simple compose() defined below using quasiquotation and new_function():

+
+
compose <- function(f, g) {
+  function(...) f(g(...))
+}
+
+

A: The implementation is fairly straightforward, even though a lot of parentheses are required:

+
+
compose2 <- function(f, g) {
+  f <- enexpr(f)
+  g <- enexpr(g)
+
+  new_function(exprs(... = ), expr((!!f)((!!g)(...))))
+}
+
+compose(sin, cos)
+#> function(...) f(g(...))
+#> <environment: 0x632cfbc88290>
+compose(sin, cos)(pi)
+#> [1] -0.841
+
+compose2(sin, cos)
+#> function (...) 
+#> sin(cos(...))
+#> <environment: 0x632cfc1fbf80>
+compose2(sin, cos)(pi)
+#> [1] -0.841
+
+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/20_Evaluation.html b/docs/20_Evaluation.html new file mode 100644 index 00000000..320a3544 --- /dev/null +++ b/docs/20_Evaluation.html @@ -0,0 +1,1106 @@ + + + + + + + + + + +Advanced R Solutions - 20 - Evaluation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

20 - Evaluation

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

On our journey through R’s metaprogramming, we continue to use the functions from the {rlang} package.

+
+
library(rlang)
+
+
+
+

Evaluation basics

+

Q1: Carefully read the documentation for source(). What environment does it use by default? What if you supply local = TRUE? How do you provide a custom environment?

+

A: By default, source() uses the global environment (local = FALSE). A specific evaluation environment may be chosen, by passing it explicitly to the local argument. To use current environment (i.e. the calling environment of source()) set local = TRUE.

+
+
# Create a temporary, sourceable R script that prints x
+tmp_file <- tempfile()
+writeLines("print(x)", tmp_file)
+
+# Set `x` globally
+x <- "global environment"
+env2 <- env(x = "specified environment")
+
+locate_evaluation <- function(file, local) {
+  x <- "local environment"
+  source(file, local = local)
+}
+
+# Where will source() evaluate the code?
+locate_evaluation(tmp_file, local = FALSE) # default
+#> [1] "global environment"
+locate_evaluation(tmp_file, local = env2)
+#> [1] "specified environment"
+locate_evaluation(tmp_file, local = TRUE)
+#> [1] "local environment"
+
+

Q2: Predict the results of the following lines of code:

+
+
eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1)
+eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2)
+expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3)
+
+

A: Let’s look at a quote from the first edition of Advanced R:

+
+

expr() and eval() are opposites. […] each eval() peels off one layer of expr()’s”.

+
+

In general, eval(expr(x)) evaluates to x. Therefore, (1) evaluates to \(2 + 2 = 4\). Adding another eval() doesn’t have impact here. So, also (2) evaluates to 4. However, when wrapping (1) into expr() the whole expression will be quoted.

+
+
eval(expr(eval(expr(eval(expr(2 + 2)))))) # (1)
+#> [1] 4
+eval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2)
+#> [1] 4
+expr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3)
+#> eval(expr(eval(expr(eval(expr(2 + 2))))))
+
+

Q3: Fill in the function bodies below to re-implement get() using sym() and eval(), and assign() using sym(), expr(), and eval(). Don’t worry about the multiple ways of choosing an environment that get() and assign() support; assume that the user supplies it explicitly.

+
+
# name is a string
+get2 <- function(name, env) {}
+assign2 <- function(name, value, env) {}
+
+

A: We reimplement these two functions using tidy evaluation. We turn the string name into a symbol, then evaluate it:

+
+
get2 <- function(name, env = caller_env()) {
+  name_sym <- sym(name)
+  eval(name_sym, env)
+}
+
+x <- 1
+get2("x")
+#> [1] 1
+
+

To build the correct expression for the value assignment, we unquote using !!.

+
+
assign2 <- function(name, value, env = caller_env()) {
+  name_sym <- sym(name)
+  assign_expr <- expr(!!name_sym <- !!value)
+  eval(assign_expr, env)
+}
+
+assign2("x", 4)
+x
+#> [1] 4
+
+

Q4: Modify source2() so it returns the result of every expression, not just the last one. Can you eliminate the for loop?

+

A: The code for source2() was given in Advanced R as:

+
+
source2 <- function(path, env = caller_env()) {
+  file <- paste(readLines(path, warn = FALSE), collapse = "\n")
+  exprs <- parse_exprs(file)
+
+  res <- NULL
+  for (i in seq_along(exprs)) {
+    res <- eval(exprs[[i]], env)
+  }
+
+  invisible(res)
+}
+
+

In order to highlight the modifications in our new source2() function, we’ve preserved the differing code from the former source2() in a comment.

+
+
source2 <- function(path, env = caller_env()) {
+  file <- paste(readLines(path, warn = FALSE), collapse = "\n")
+  exprs <- parse_exprs(file)
+
+  # res <- NULL
+  # for (i in seq_along(exprs)) {
+  #   res[[i]] <- eval(exprs[[i]], env)
+  # }
+
+  res <- purrr::map(exprs, eval, env)
+
+  invisible(res)
+}
+
+

Let’s create a file and test source2(). Keep in mind that <- returns invisibly.

+
+
tmp_file <- tempfile()
+writeLines(
+  "x <- 1
+       x
+       y <- 2
+       y  # some comment",
+  tmp_file
+)
+
+(source2(tmp_file))
+#> [[1]]
+#> [1] 1
+#> 
+#> [[2]]
+#> [1] 1
+#> 
+#> [[3]]
+#> [1] 2
+#> 
+#> [[4]]
+#> [1] 2
+
+

Q5: We can make base::local() slightly easier to understand by spreading it over multiple lines:

+
+
local3 <- function(expr, envir = new.env()) {
+  call <- substitute(eval(quote(expr), envir))
+  eval(call, envir = parent.frame())
+}
+
+

Explain how local() works in words. (Hint: you might want to print(call) to help understand what substitute() is doing, and read the documentation to remind yourself what environment new.env() will inherit from.)

+

A: Let’s follow the advice and add print(call) inside of local3():

+
+
local3 <- function(expr, envir = new.env()) {
+  call <- substitute(eval(quote(expr), envir))
+  print(call)
+  eval(call, envir = parent.frame())
+}
+
+

The first line generates a call to eval(), because substitute() operates in the current evaluation argument. However, this doesn’t matter here, as both, expr and envir are promises and therefore “the expression slots of the promises replace the symbols”, from ?substitute.

+
+
local3({
+  x <- 10
+  x * 2
+})
+#> eval(quote({
+#>     x <- 10
+#>     x * 2
+#> }), new.env())
+#> [1] 20
+
+

Next, call will be evaluated in the caller environment (aka the parent frame). Given that call contains another call eval() why does this matter? The answer is subtle: this outer environment determines where the bindings for eval, quote, and new.env are found.

+
+
eval(quote({
+  x <- 10
+  x * 2
+}), new.env())
+#> [1] 20
+exists("x")
+#> [1] TRUE
+
+
+
+

Quosures

+

Q1: Predict what evaluating each of the following quosures will return if evaluated.

+
+
q1 <- new_quosure(expr(x), env(x = 1))
+q1
+#> <quosure>
+#> expr: ^x
+#> env:  0x5c4a1926acd8
+
+q2 <- new_quosure(expr(x + !!q1), env(x = 10))
+q2
+#> <quosure>
+#> expr: ^x + (^x)
+#> env:  0x5c4a1a129268
+
+q3 <- new_quosure(expr(x + !!q2), env(x = 100))
+q3
+#> <quosure>
+#> expr: ^x + (^x + (^x))
+#> env:  0x5c4a1a590570
+
+

A: Each quosure is evaluated in its own environment, so x is bound to a different value for each time. This leads us to:

+
+
eval_tidy(q1)
+#> [1] 1
+eval_tidy(q2)
+#> [1] 11
+eval_tidy(q3)
+#> [1] 111
+
+

Q2: Write an enenv() function that captures the environment associated with an argument. (Hint: this should only require two function calls.)

+

A: A quosure captures both the expression and the environment. From a quosure, we can access the environment with the help of get_env().

+
+
enenv <- function(x) {
+  get_env(enquo(x))
+}
+
+# Test
+enenv(x)
+#> <environment: R_GlobalEnv>
+
+# Test if it also works within functions
+capture_env <- function(x) {
+  enenv(x)
+}
+capture_env(x)
+#> <environment: 0x5c4a18b688b0>
+
+
+
+

Data masks

+

Q1: Why did I use a for loop in transform2() instead of map()? Consider transform2(df, x = x * 2, x = x * 2).

+

A: transform2() was defined in Advanced R as:

+
+
transform2 <- function(.data, ...) {
+  dots <- enquos(...)
+
+  for (i in seq_along(dots)) {
+    name <- names(dots)[[i]]
+    dot <- dots[[i]]
+
+    .data[[name]] <- eval_tidy(dot, .data)
+  }
+
+  .data
+}
+
+

A for loop applies the processing steps regarding .data iteratively. This includes updating .data and reusing the same variable names. This makes it possible to apply transformations sequentially, so that subsequent transformations can refer to columns that were just created.

+

Q2: Here’s an alternative implementation of subset2():

+
+
subset3 <- function(data, rows) {
+  rows <- enquo(rows)
+  eval_tidy(expr(data[!!rows, , drop = FALSE]), data = data)
+}
+
+df <- data.frame(x = 1:3)
+subset3(df, x == 1)
+
+

Compare and contrast subset3() to subset2(). What are its advantages and disadvantages?

+

A: Let’s take a closer look at subset2() first:

+
+
subset2 <- function(data, rows) {
+  rows <- enquo(rows)
+  rows_val <- eval_tidy(rows, data)
+  stopifnot(is.logical(rows_val))
+
+  data[rows_val, , drop = FALSE]
+}
+
+

subset2() provides an additional logical check, which is missing from subset3(). Here, rows is evaluated in the context of data, which results in a logical vector. Afterwards only [ needs to be used for subsetting.

+
+
# subset2() evaluation
+(rows_val <- eval_tidy(quo(x == 1), df))
+#> [1]  TRUE FALSE FALSE
+df[rows_val, , drop = FALSE]
+#>   x
+#> 1 1
+
+

With subset3() both of these steps occur in a single line (which is probably closer to what one would produce by hand). This means that the subsetting is also evaluated in the context of the data mask.

+
+
# subset3() evaluation
+eval_tidy(expr(df[x == 1, , drop = FALSE]), df)
+#>   x
+#> 1 1
+
+

This is shorter (but probably also less readable) because the evaluation and the subsetting take place in the same expression. However, it may introduce unwanted errors, if the data mask contains an element named “data”, as the objects from the data mask take precedence over arguments of the function.

+
+
df <- data.frame(x = 1:3, data = 1)
+subset2(df, x == 1)
+#>   x data
+#> 1 1    1
+subset3(df, x == 1)
+#> Error in data[~x == 1, , drop = FALSE]: incorrect number of dimensions
+
+

Q3: The following function implements the basics of dplyr::arrange(). Annotate each line with a comment explaining what it does. Can you explain why !!.na.last is strictly correct, but omitting the !! is unlikely to cause problems?

+
+
arrange2 <- function(.df, ..., .na.last = TRUE) {
+  args <- enquos(...)
+
+  order_call <- expr(order(!!!args, na.last = !!.na.last))
+
+  ord <- eval_tidy(order_call, .df)
+  stopifnot(length(ord) == nrow(.df))
+
+  .df[ord, , drop = FALSE]
+}
+
+

A: arrange2() basically reorders a data frame by one or more of its variables. As arrange2() allows to provide the variables as expressions (via ...), these need to be quoted first. Afterwards they are used to build up an order() call, which is then evaluated in the context of the data frame. Finally, the data frame is reordered via integer subsetting. Let’s take a closer look at the source code:

+
+
arrange2 <- function(.df, ..., .na.last = TRUE) {
+  # Capture and quote arguments, which determine the order
+  args <- enquos(...)
+
+  # `!!!`: unquote-splice arguments into order()
+  # `!!.na.last`: pass option for treatment of NAs to order()
+  # return expression-object
+  order_call <- expr(order(!!!args, na.last = !!.na.last))
+
+  # Evaluate order_call within .df
+  ord <- eval_tidy(order_call, .df)
+  # Ensure that no rows are dropped
+  stopifnot(length(ord) == nrow(.df))
+
+  # Reorder rows via integer subsetting
+  .df[ord, , drop = FALSE]
+}
+
+

By using !!.na.last the .na.last argument is unquoted when the order() call is built. This way, the na.last argument is already correctly specified (typically TRUE, FALSE or NA).

+

Without the unquoting, the expression would read na.last = .na.last and the value for .na.last would still need to be looked up and found. Because these computations take place inside of the function’s execution environment (which contains .na.last), this is unlikely to cause problems.

+
+
# The effect of unquoting .na.last
+.na.last <- FALSE
+expr(order(..., na.last = !!.na.last))
+#> order(..., na.last = FALSE)
+expr(order(..., na.last = .na.last))
+#> order(..., na.last = .na.last)
+
+
+
+

Using tidy evaluation

+

Q1: I’ve included an alternative implementation of threshold_var() below. What makes it different to the approach I used above? What makes it harder?

+
+
threshold_var2 <- function(df, var, val) {
+  var <- ensym(var)
+
+  subset2(df, `$`(.data, !!var) >= !!val)
+}
+
+

A: Let’s compare this approach to the original implementation:

+
+
threshold_var <- function(df, var, val) {
+  var <- as_string(ensym(var))
+  subset2(df, .data[[var]] >= !!val)
+}
+
+

We can see that threshold_var2() no longer coerces the symbol to a string. Therefore $ instead of [[ can be used for subsetting. Initially we suspected partial matching would be introduced by $, but .data deliberately avoids this problem.

+

The prefix call to $() is less common than infix-subsetting using [[, but ultimately both functions behave the same.

+
+
df <- data.frame(x = 1:10)
+threshold_var(df, x, 8)
+#>     x
+#> 8   8
+#> 9   9
+#> 10 10
+threshold_var2(df, x, 8)
+#>     x
+#> 8   8
+#> 9   9
+#> 10 10
+
+
+
+

Base evaluation

+

Q1: Why does this function fail?

+
+
lm3a <- function(formula, data) {
+  formula <- enexpr(formula)
+
+  lm_call <- expr(lm(!!formula, data = data))
+  eval(lm_call, caller_env())
+}
+lm3a(mpg ~ disp, mtcars)$call
+#> Error in model.frame.default(formula = mpg ~ disp, data = data, drop.unused.levels = TRUE): 'data' must be a data.frame, environment, or list
+
+

A: In this function, lm_call is evaluated in the caller environment, which happens to be the global environment. In this environment, the name data is bound to utils::data. To fix the error, we can either set the evaluation environment to the function’s execution environment or unquote the data argument when building the call to lm().

+
+
# Change evaluation environment
+lm3b <- function(formula, data) {
+  formula <- enexpr(formula)
+
+  lm_call <- expr(lm(!!formula, data = data))
+  eval(lm_call, current_env())
+}
+
+lm3b(mpg ~ disp, mtcars)$call
+#> lm(formula = mpg ~ disp, data = data)
+lm3b(mpg ~ disp, data)$call # reproduces original error
+#> Error in model.frame.default(formula = mpg ~ disp, data = data, drop.unused.levels = TRUE): 'data' must be a data.frame, environment, or list
+
+

When we want to unquote an argument within a function, we first need to capture the user-input (by enexpr()).

+
+
# Unquoting data-argument
+lm3c <- function(formula, data) {
+  formula <- enexpr(formula)
+  data_quo <- enexpr(data)
+
+  lm_call <- expr(lm(!!formula, data = !!data_quo))
+  eval(lm_call, caller_env())
+}
+lm3c(mpg ~ disp, mtcars)$call
+#> lm(formula = mpg ~ disp, data = mtcars)
+
+

Q2: When model building, typically the response and data are relatively constant while you rapidly experiment with different predictors. Write a small wrapper that allows you to reduce duplication in the code below.

+
+
lm(mpg ~ disp, data = mtcars)
+lm(mpg ~ I(1 / disp), data = mtcars)
+lm(mpg ~ disp * cyl, data = mtcars)
+
+

A: In our wrapper lm_wrap(), we provide mpg and mtcars as default response and data. This seems to give us a good mix of usability and flexibility.

+
+
lm_wrap <- function(pred, resp = mpg, data = mtcars,
+                    env = caller_env()) {
+  pred <- enexpr(pred)
+  resp <- enexpr(resp)
+  data <- enexpr(data)
+
+  formula <- expr(!!resp ~ !!pred)
+  lm_call <- expr(lm(!!formula, data = !!data))
+  eval(lm_call, envir = env)
+}
+
+# Test if the output looks ok
+lm_wrap(I(1 / disp) + disp * cyl)
+#> 
+#> Call:
+#> lm(formula = mpg ~ I(1/disp) + disp * cyl, data = mtcars)
+#> 
+#> Coefficients:
+#> (Intercept)    I(1/disp)         disp          cyl     disp:cyl  
+#>   -1.22e+00     1.85e+03     7.68e-02     1.18e+00    -9.14e-03
+
+# Test if the result is identical to calling lm() directly
+identical(
+  lm_wrap(I(1 / disp) + disp * cyl),
+  lm(mpg ~ I(1 / disp) + disp * cyl, data = mtcars)
+)
+#> [1] TRUE
+
+

Q3: Another way to write resample_lm() would be to include the resample expression (data[sample(nrow(data), replace = TRUE), , drop = FALSE]) in the data argument. Implement that approach. What are the advantages? What are the disadvantages?

+

A: Different versions of resample_lm() were given in Advanced R. However, none of them implemented the resampling within the function argument.

+

Different versions of resample_lm() (resample_lm0(), resample_lm1(), resample_lm2()) were specified in Advanced R. However, in none of these versions was the resampling step implemented in any of the arguments.

+

This approach takes advantage of R’s lazy evaluation of function arguments, by moving the resampling step into the argument definition. The user passes the data to the function, but only a permutation of this data (resample_data) will be used.

+
+
resample_lm <- function(
+    formula, data,
+    resample_data = data[sample(nrow(data), replace = TRUE), ,
+      drop = FALSE
+    ],
+    env = current_env()) {
+  formula <- enexpr(formula)
+
+  lm_call <- expr(lm(!!formula, data = resample_data))
+  expr_print(lm_call)
+  eval(lm_call, env)
+}
+
+df <- data.frame(x = 1:10, y = 5 + 3 * (1:10) + round(rnorm(10), 2))
+(lm_1 <- resample_lm(y ~ x, data = df))
+#> lm(y ~ x, data = resample_data)
+#> 
+#> Call:
+#> lm(formula = y ~ x, data = resample_data)
+#> 
+#> Coefficients:
+#> (Intercept)            x  
+#>        4.85         3.02
+lm_1$call
+#> lm(formula = y ~ x, data = resample_data)
+
+

With this approach the evaluation needs to take place within the function’s environment, because the resampled dataset (defined as a default argument) will only be available in the function environment.

+

Overall, putting an essential part of the pre-processing outside of the functions body is not common practice in R. Compared to the unquoting-implementation (resample_lm1() in Advanced R), this approach captures the model-call in a more meaningful way. This approach will also lead to a new resample every time you update() the model.

+
+
+

References

+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/21_Translating_R_code.html b/docs/21_Translating_R_code.html new file mode 100644 index 00000000..f68c94a4 --- /dev/null +++ b/docs/21_Translating_R_code.html @@ -0,0 +1,1438 @@ + + + + + + + + + + +Advanced R Solutions - 21 - Translating R code + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

21 - Translating R code

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

In this chapter we combine R’s metaprogramming and functional programming capabilities and therefore load both the {rlang} and the {purrr} package.

+
+
library(rlang)
+library(purrr)
+
+
+
+

HTML

+

Q1: The escaping rules for <script> tags are different because they contain JavaScript, not HTML. Instead of escaping angle brackets or ampersands, you need to escape </script> so that the tag isn’t closed too early. For example, script("'</script>'"), shouldn’t generate this:

+
+
<script>'</script>'</script>
+
+

But

+
+
<script>'<\/script>'</script>
+
+

Adapt the escape() to follow these rules when a new argument script is set to TRUE.

+

A: We are asked to implement a special case of escaping for the <script> tag. At first we will revisit the relevant functions provided in Advanced R and confirm that our code reliably escapes for tags like <p> and <b> but doesn’t escape correctly for the <script> tag. Then we modify the escape() and tag() functions to redefine the <script> tag and confirm that all defined tags now escape correctly.

+

Note that the <style> tag, which contains styling information in CSS, follows the same escaping rules as the <script> tag. We therefore implement the desired escaping for the <style> tag function also.

+

Let’s start by loading the relevant code from Advanced R first.

+
+
# Escaping
+html <- function(x) structure(x, class = "advr_html")
+
+print.advr_html <- function(x, ...) {
+  out <- paste0("<HTML> ", x)
+  cat(paste(strwrap(out), collapse = "\n"), "\n", sep = "")
+}
+
+escape <- function(x) UseMethod("escape")
+
+escape.character <- function(x) {
+  x <- gsub("&", "&amp;", x)
+  x <- gsub("<", "&lt;", x)
+  x <- gsub(">", "&gt;", x)
+
+  html(x)
+}
+
+escape.advr_html <- function(x) x
+
+# Basic tag functions
+dots_partition <- function(...) {
+  dots <- list2(...)
+
+  if (is.null(names(dots))) {
+    is_named <- rep(FALSE, length(dots))
+  } else {
+    is_named <- names(dots) != ""
+  }
+
+  list(
+    named = dots[is_named],
+    unnamed = dots[!is_named]
+  )
+}
+
+# html_attributes() function from the GitHub repository of Advanced R
+# https://github.com/hadley/adv-r/blob/master/dsl-html-attributes.r
+
+html_attributes <- function(list) {
+  if (length(list) == 0) {
+    return("")
+  }
+
+  attr <- map2_chr(names(list), list, html_attribute)
+  paste0(" ", unlist(attr), collapse = "")
+}
+
+html_attribute <- function(name, value = NULL) {
+  if (length(value) == 0) {
+    return(name)
+  } # for attributes with no value
+  if (length(value) != 1) stop("`value` must be NULL or length 1")
+  if (is.logical(value)) {
+    # Convert T and F to true and false
+    value <- tolower(value)
+  } else {
+    value <- escape_attr(value)
+  }
+  paste0(name, "='", value, "'")
+}
+
+escape_attr <- function(x) {
+  x <- escape.character(x)
+  x <- gsub("\'", "&#39;", x)
+  x <- gsub("\"", "&quot;", x)
+  x <- gsub("\r", "&#13;", x)
+  x <- gsub("\n", "&#10;", x)
+  x
+}
+
+# Tag functions
+tag <- function(tag) {
+  new_function(
+    exprs(... = ),
+    expr({
+      dots <- dots_partition(...)
+      attribs <- html_attributes(dots$named)
+      children <- map_chr(dots$unnamed, escape)
+
+      html(paste0(
+        !!paste0("<", tag), attribs, ">",
+        paste(children, collapse = ""),
+        !!paste0("</", tag, ">")
+      ))
+    }),
+    caller_env()
+  )
+}
+
+

This code escapes the <p> and <b> tags correctly, but doesn’t achieve the desired behaviour for the <script> tag yet:

+
+
p <- tag("p")
+b <- tag("b")
+
+identical(
+  p("&", "and <", b("& > will be escaped")) %>%
+    as.character(),
+  "<p>&amp;and &lt;<b>&amp; &gt; will be escaped</b></p>"
+)
+#> [1] TRUE
+
+script <- tag("script")
+
+identical(
+  script("Don't escape &, <, > - escape </script> and </style>") %>%
+    as.character(),
+  paste(
+    "<script>Don't escape &, <, >",
+    "- escape <\\/script> and <\\/style></script>"
+  )
+)
+#> [1] FALSE
+
+

We implement the desired change and add the optional argument script to the escape() and the tag() functions (default: script = FALSE). The argument has to be added for all methods of the escape() generic.

+
+
escape <- function(x, script = FALSE) UseMethod("escape")
+
+escape.character <- function(x, script = FALSE) {
+  if (script) {
+    x <- gsub("</script>", "<\\/script>", x, fixed = TRUE)
+    x <- gsub("</style>", "<\\/style>", x, fixed = TRUE)
+  } else {
+    x <- gsub("&", "&amp;", x)
+    x <- gsub("<", "&lt;", x)
+    x <- gsub(">", "&gt;", x)
+  }
+
+  html(x)
+}
+
+escape.advr_html <- function(x, script = FALSE) x
+
+
+tag <- function(tag, script = FALSE) {
+  new_function(
+    exprs(... = ),
+    expr({
+      dots <- dots_partition(...)
+      attribs <- html_attributes(dots$named)
+      children <- map_chr(dots$unnamed, escape, script = !!script)
+      html(paste0(
+        !!paste0("<", tag), attribs, ">",
+        paste(children, collapse = ""),
+        !!paste0("</", tag, ">")
+      ))
+    }),
+    caller_env()
+  )
+}
+
+

Finally, we create new <p>, <b> and <script> tag functions, which now pass their escaping tests.

+
+
p <- tag("p")
+b <- tag("b")
+
+identical(
+  p("&", "and <", b("& > will be escaped")) %>%
+    as.character(),
+  "<p>&amp;and &lt;<b>&amp; &gt; will be escaped</b></p>"
+)
+#> [1] TRUE
+
+script <- tag("script", script = TRUE)
+style <- tag("style", script = TRUE)
+
+identical(
+  script("Don't escape &, <, > - escape </script> and </style>") %>%
+    as.character(),
+  paste(
+    "<script>Don't escape &, <, >",
+    "- escape <\\/script> and <\\/style></script>"
+  )
+)
+#> [1] TRUE
+
+script("Don't escape &, <, > - escape </script> and </style>")
+#> <HTML> <script>Don't escape &, <, > - escape <\/script> and
+#> <\/style></script>
+
+

Q2: The use of ... for all functions has some big downsides. There’s no input validation and there will be little information in the documentation or autocomplete about how they are used in the function. Create a new function that, when given a named list of tags and their attribute names (like below), creates tag functions with named arguments.

+
+
list(
+  a = c("href"),
+  img = c("src", "width", "height")
+)
+
+

All tags should get class and id attributes.

+

A: This exercise requires a function factory: The named list of attribute names will be extended (by class and id) and mapped to function arguments. These will default to NULL, so that the user isn’t forced to provide them.

+

When creating the tag functions itself we use check_dots_unnamed() from the {ellipsis} package to ensure named arguments correspond to the expected values (and are not created by some spelling mistake). After that we follow the logic from the tag() function factory above.

+

To keep the focus on the key ideas, we ignore special cases like <script>, <style> and void tags in this solution (even if this leads to an incorrect tag function for the <img> tag).

+
+
tag_factory <- function(tag, tag_attrs) {
+  attrs <- c("class", "id", tag_attrs)
+
+  attr_args <- set_names(rep(list(NULL), length(attrs)), attrs)
+  attr_list <- call2("list", !!!syms(set_names(attrs)))
+
+  new_function(
+    exprs(... = , !!!attr_args),
+    expr({
+      ellipsis::check_dots_unnamed()
+
+      attribs <- html_attributes(compact(!!attr_list))
+      dots <- compact(list(...))
+      children <- map_chr(dots, escape)
+
+      html(paste0(
+        !!paste0("<", tag), attribs, ">",
+        paste(children, collapse = ""),
+        !!paste0("</", tag, ">")
+      ))
+    })
+  )
+}
+
+

To validate our new function factory, we modify the with_html() example from Advanced R to work with our newly created a() and img() tag functions.

+
+
tag_list <- list(
+  a = c("href"),
+  img = c("src", "width", "height")
+)
+
+tags <- map2(names(tag_list), unname(tag_list), tag_factory) %>%
+  set_names(names(tag_list))
+
+with_tags <- function(code) {
+  code <- enquo(code)
+  eval_tidy(code, tags)
+}
+
+with_tags(
+  a(
+    img("Correct me if I am wrong", id = "second"),
+    href = "https://github.com/Tazinho/Advanced-R-Solutions/issues",
+    id = "first"
+  )
+)
+#> <HTML> <a id='first'
+#> href='https://github.com/Tazinho/Advanced-R-Solutions/issues'><img
+#> id='second'>Correct me if I am wrong</img></a>
+
+

Q3: Reason about the following code that calls with_html() referencing objects from the environment. Will it work or fail? Why? Run the code to verify your predictions.

+
+
greeting <- "Hello!"
+with_html(p(greeting))
+
+p <- function() "p"
+address <- "123 anywhere street"
+with_html(p(address))
+
+

A: First, we rerun the relevant code from Advanced R to define with_html(). Note that we skip the code for void tags, as none of them appear in the code chunk from this exercise.

+
+
tags <- c(
+  "a", "abbr", "address", "article", "aside", "audio",
+  "b", "bdi", "bdo", "blockquote", "body", "button", "canvas",
+  "caption", "cite", "code", "colgroup", "data", "datalist",
+  "dd", "del", "details", "dfn", "div", "dl", "dt", "em",
+  "eventsource", "fieldset", "figcaption", "figure", "footer",
+  "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header",
+  "hgroup", "html", "i", "iframe", "ins", "kbd", "label",
+  "legend", "li", "mark", "map", "menu", "meter", "nav",
+  "noscript", "object", "ol", "optgroup", "option", "output",
+  "p", "pre", "progress", "q", "ruby", "rp", "rt", "s", "samp",
+  "script", "section", "select", "small", "span", "strong",
+  "style", "sub", "summary", "sup", "table", "tbody", "td",
+  "textarea", "tfoot", "th", "thead", "time", "title", "tr",
+  "u", "ul", "var", "video"
+)
+
+html_tags <- tags %>%
+  set_names() %>%
+  map(tag)
+
+with_html <- function(code) {
+  code <- enquo(code)
+  eval_tidy(code, html_tags)
+}
+
+

Now, let us briefly repeat, that with_html() was introduced to evaluate tag functions from within a list. Otherwise, defining some tag functions like body(), source(), summary() etc. within the global environment would collide with base R functions with the same name. To prevent this the DSL code wrapped in with_html() is evaluated within the “context” of html_tags, which was provided as a data mask to eval_tidy(). As ?rlang::as_data_mask mentions: “Objects in the mask have precedence over objects in the environment”.

+

Therefore, p() refers to the tag function from html_tags within both examples from the exercise. However, as address is not only a string within the global environment, but also a tag function within html_tags (the <address> HTML tag may be used to provide contact information on an HTML page), p() operates on address() in the second example. This correctly leads to an error as we haven’t implemented an escape.function() method.

+
+
greeting <- "Hello!"
+with_html(p(greeting))
+#> <HTML> <p>Hello!</p>
+
+p <- function() "p"
+address <- "123 anywhere street"
+with_html(p(address))
+#> Error in `map_chr()`:
+#> ℹ In index: 1.
+#> Caused by error in `UseMethod()`:
+#> ! no applicable method for 'escape' applied to an object of class "function"
+
+

Q4: Currently the HTML doesn’t look terribly pretty, and it’s hard to see the structure. How could you adapt tag() to do indenting and formatting? (You may need to do some research into block and inline tags.)

+

A: First, let us load all relevant functions from Advanced R:

+
+
tag <- function(tag) {
+  new_function(
+    exprs(... = ),
+    expr({
+      dots <- dots_partition(...)
+      attribs <- html_attributes(dots$named)
+      children <- map_chr(dots$unnamed, escape)
+      html(paste0(
+        !!paste0("<", tag), attribs, ">",
+        paste(children, collapse = ""),
+        !!paste0("</", tag, ">")
+      ))
+    }),
+    caller_env()
+  )
+}
+
+void_tag <- function(tag) {
+  new_function(
+    exprs(... = ),
+    expr({
+      dots <- dots_partition(...)
+      if (length(dots$unnamed) > 0) {
+        stop(
+          !!paste0("<", tag, "> must not have unnamed arguments"),
+          call. = FALSE
+        )
+      }
+
+      attribs <- html_attributes(dots$named)
+
+      html(paste0(!!paste0("<", tag), attribs, " />"))
+    }),
+    caller_env()
+  )
+}
+
+tags <- c(
+  "a", "abbr", "address", "article", "aside", "audio", "b",
+  "bdi", "bdo", "blockquote", "body", "button", "canvas",
+  "caption", "cite", "code", "colgroup", "data", "datalist",
+  "dd", "del", "details", "dfn", "div", "dl", "dt", "em",
+  "eventsource", "fieldset", "figcaption", "figure", "footer",
+  "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header",
+  "hgroup", "html", "i", "iframe", "ins", "kbd", "label", "legend",
+  "li", "mark", "map", "menu", "meter", "nav", "noscript", "object",
+  "ol", "optgroup", "option", "output", "p", "pre", "progress", "q",
+  "ruby", "rp", "rt", "s", "samp", "script", "section", "select",
+  "small", "span", "strong", "style", "sub", "summary", "sup",
+  "table", "tbody", "td", "textarea", "tfoot", "th", "thead",
+  "time", "title", "tr", "u", "ul", "var", "video"
+)
+
+void_tags <- c(
+  "area", "base", "br", "col", "command", "embed", "hr", "img",
+  "input", "keygen", "link", "meta", "param", "source",
+  "track", "wbr"
+)
+
+html_tags <- c(
+  tags %>% set_names() %>% map(tag),
+  void_tags %>% set_names() %>% map(void_tag)
+)
+
+with_html <- function(code) {
+  code <- enquo(code)
+  eval_tidy(code, html_tags)
+}
+
+

Now, let’s look at the example from above:

+
+
with_html(
+  body(
+    h1("A heading", id = "first"),
+    p("Some text &", b("some bold text.")),
+    img(src = "myimg.png", width = 100, height = 100)
+  )
+)
+#> <HTML> <body><h1 id='first'>A heading</h1><p>Some text &amp;<b>some
+#> bold text.</b></p><img src='myimg.png' width='100' height='100'
+#> /></body>
+
+

The formatting consists of only one long line of code. This output makes it difficult to check the content of the HTML code and its correctness.

+

What kind of formatting would we prefer instead? Google’s HTML style guide suggests indentation by 2 spaces and new lines for every block, list, or table element. There are other recommendations, but we will keep things simple and will be satisfied with the following output.

+
+
<body>
+  <h1 id='first'>A heading</h1>
+  <p>Some text &amp;<b>some bold text.</b></p>
+  <img src='myimg.png'width='100' height='100' />
+</body>
+
+

First we adjust the print.advr_html() method, removing strwrap() function, because this will re-wrap the HTML, making it harder to understand what’s happening.

+
+
html <- function(x) structure(x, class = "advr_html")
+
+print.advr_html <- function(x, ...) {
+  cat(paste("<HTML>", x, sep = "\n"))
+}
+
+

In our desired output we can see that the content of the body-function requires different formatting than the other tag-functions. We will therefore create a new format_code() function, that allows for optional indentation and line breaks.

+
+
indent <- function(x) {
+  paste0("  ", gsub("\n", "\n  ", x))
+}
+
+format_code <- function(children, indent = FALSE) {
+  if (indent) {
+    paste0("\n", paste0(indent(children), collapse = "\n"), "\n")
+  } else {
+    paste(children, collapse = "")
+  }
+}
+
+

We adjust the body function to include the format_code() helper. (This could also be approached programmatically in the tag function factory.)

+
+
html_tags$body <- function(...) {
+  dots <- dots_partition(...)
+  attribs <- html_attributes(dots$named)
+  children <- map_chr(dots$unnamed, escape)
+
+  html(paste0(
+    "<body", attribs, ">",
+    format_code(children, indent = TRUE),
+    "</body>"
+  ))
+}
+
+

The resulting output is much more satisfying.

+
+
with_html(
+  body(
+    h1("A heading", id = "first"),
+    p("Some text &", b("some bold text.")),
+    img(src = "myimg.png", width = 100, height = 100)
+  )
+)
+#> <HTML>
+#> <body>
+#>   <h1 id='first'>A heading</h1>
+#>   <p>Some text &amp;<b>some bold text.</b></p>
+#>   <img src='myimg.png' width='100' height='100' />
+#> </body>
+
+
+
+

LaTeX

+

Q1: Add escaping. The special symbols that should be escaped by adding a backslash in front of them are \, $, and %. Just as with HTML, you’ll need to make sure you don’t end up double-escaping. So, you’ll need to create a small S3 class and then use that in function operators. That will also allow you to embed arbitrary LaTeX if needed.

+

A: Currently our to_math() function generates the following output:

+
+
to_math(`$`)
+#> <LATEX> \mathrm{f}($)    # instead of <LATEX> \$
+to_math(a$b)
+#> <LATEX> \mathrm{$}(a b)  # instead of <LATEX> \mathrm{\$}(a b)
+to_math(`\\`)
+#> <LATEX> \mathrm{f}(\)    # instead of <LATEX> \\
+to_math(`%`)
+#> <LATEX> \mathrm{f}(%)    # instead of <LATEX> \%
+
+

To adjust this behaviour, we need an escape function with methods for the character and advr_latex classes.

+

(Note that we must first repeat the underlying code from Advanced R. However, since this would be a bit verbose, and not very meaningful, we will not show this step here.)

+
+
escape_latex <- function(x) UseMethod("escape_latex")
+
+escape_latex.character <- function(x) {
+  x <- gsub("^\\\\$", "\\\\\\\\", x)
+  x <- gsub("^\\$$", "\\\\$", x)
+  x <- gsub("^\\%$", "\\\\%", x)
+
+  latex(x)
+}
+
+escape_latex.advr_latex <- function(x) x
+
+

We apply escape_latex() within latex_env() when creating environments for unknown symbols and unknown functions. For the unknown function, we need to modify unknown_op() first.

+
+
unknown_op <- function(op) {
+  new_function(
+    exprs(... = ),
+    expr({
+      contents <- paste(..., collapse = ", ")
+      paste0(
+        !!paste0("\\mathrm{", escape_latex(op), "}("), contents, ")"
+      )
+    })
+  )
+}
+
+latex_env <- function(expr) {
+  calls <- all_calls(expr)
+  call_list <- map(set_names(calls), unknown_op)
+  call_env <- as_environment(call_list)
+
+  # Known functions
+  f_env <- env_clone(f_env, call_env)
+
+  # Default symbols
+  names <- all_names(expr)
+  symbol_env <- as_environment(set_names(escape_latex(names), names),
+    parent = f_env
+  )
+
+  # Known symbols
+  greek_env <- env_clone(greek_env, parent = symbol_env)
+  greek_env
+}
+
+

Now, we can validate to_math() on the test cases from above.

+
+
to_math(`$`)
+#> <LATEX> \$
+to_math(a$b)
+#> <LATEX> \mathrm{\$}(a b)
+to_math(`\\`)
+#> <LATEX> \\
+to_math(`%`)
+#> <LATEX> \%
+
+

Q2: Complete the DSL to support all the functions that plotmath supports.

+

A: You can see all supported functions in ?plotmath. There are a lot (!) so here we choose to implement a representative sample:

+
+
to_math(x %+-% y)
+to_math(x %*% y)
+to_math(x %->% y)
+to_math(bold(x))
+to_math(x != y)
+
+

Implementing the rest is just a mechanical application of the same principles with more LaTex expressions, which can be found on Wikipedia.

+

To provide these translations, we’ll follow the LaTeX section from Advanced R from the beginning. This makes it easier to keep an overview, as we just need to insert the specific changes at the relevant parts.

+

Let’s start and repeat the converter function to_math() from the textbook.

+
+
to_math <- function(x) {
+  expr <- enexpr(x)
+  out <- eval_bare(expr, latex_env(expr))
+
+  latex(out)
+}
+
+latex <- function(x) structure(x, class = "advr_latex")
+print.advr_latex <- function(x) {
+  cat("<LATEX> ", x, "\n", sep = "")
+}
+
+

One specific property in this setting is that the environment where to_math() evaluates the expression is not constant, but depends on what we already know about the expression.

+

Next, we start building up latex_env(), which contains a chain of all the necessary environments which to_math() checks to evaluate the expression in.

+

The first environment is the one for Greek letters.

+
+
greek <- c(
+  "alpha", "theta", "tau", "beta", "vartheta", "pi", "upsilon",
+  "gamma", "varpi", "phi", "delta", "kappa", "rho",
+  "varphi", "epsilon", "lambda", "varrho", "chi", "varepsilon",
+  "mu", "sigma", "psi", "zeta", "nu", "varsigma", "omega", "eta",
+  "xi", "Gamma", "Lambda", "Sigma", "Psi", "Delta", "Xi",
+  "Upsilon", "Omega", "Theta", "Pi", "Phi"
+)
+greek_list <- set_names(paste0("\\", greek), greek)
+greek_env <- as_environment(greek_list)
+
+latex_env <- function(expr) {
+  greek_env
+}
+
+

We already know from Advanced R that e.g. to_math(pi) now correctly converts to \\pi. So, let’s move on to the next one.

+

Here, it’ll become a bit more technical. Not every symbol is Greek (and not every part of an expression is a symbol). To find out which symbols are present within the expression, first, we use an approach from section 5 of the expressions chapter (walking the AST to find all symbols) where Hadley recursively walks the AST to distinguish between different expression element types.

+

Let’s briefly repeat the helpers defined in that section:

+
+
expr_type <- function(x) {
+  if (rlang::is_syntactic_literal(x)) {
+    "constant"
+  } else if (is.symbol(x)) {
+    "symbol"
+  } else if (is.call(x)) {
+    "call"
+  } else if (is.pairlist(x)) {
+    "pairlist"
+  } else {
+    typeof(x)
+  }
+}
+
+switch_expr <- function(x, ...) {
+  switch(expr_type(x),
+    ...,
+    stop("Don't know how to handle type ",
+      typeof(x),
+      call. = FALSE
+    )
+  )
+}
+
+flat_map_chr <- function(.x, .f, ...) {
+  purrr::flatten_chr(purrr::map(.x, .f, ...))
+}
+
+

This lets us define all_names(), which returns the desired symbols, already converted to characters.

+
+
all_names_rec <- function(x) {
+  switch_expr(x,
+    constant = character(),
+    symbol = as.character(x),
+    call = flat_map_chr(as.list(x[-1]), all_names)
+  )
+}
+
+all_names <- function(x) {
+  unique(all_names_rec(x))
+}
+
+all_names(expr(x + y + f(a, b, c, 10)))
+#> [1] "x" "y" "a" "b" "c"
+
+

We use all_names() now within latex_env() to create an environment of the symbols which were found within the expression. This environment will be set as the parent environment of greek_env.

+
+
latex_env <- function(expr) {
+  # Unknown symbols
+  names <- all_names(expr)
+  symbol_env <- as_environment(set_names(names))
+
+  # Known symbols
+  env_clone(greek_env, parent = symbol_env)
+}
+
+

In this way, to_math() will first convert all known Greek letters (found in greek_env) and then any other symbols, which are left as is (in this implementation).

+

We also have to add support for functions. This will give us the opportunity to insert some specific support for plotmath functions.

+

To support a whole bunch of unary and binary functions within the function environment (f_env), which will be added next to latex_env, Hadley defines the following two helpers in Advanced R.

+
+
unary_op <- function(left, right) {
+  new_function(
+    exprs(e1 = ),
+    expr(
+      paste0(!!left, e1, !!right)
+    ),
+    caller_env()
+  )
+}
+
+binary_op <- function(sep) {
+  new_function(
+    exprs(e1 = , e2 = ),
+    expr(
+      paste0(e1, !!sep, e2)
+    ),
+    caller_env()
+  )
+}
+
+

While defining the function environment, f_env, we mostly continue to copy the exact code from Advanced R. However, at the bottom we add a short section where we define some extra conversions which are part of plotmath (and selected above in our intro to this solution).

+
+
f_env <- child_env(
+  # Binary operators
+  .parent = empty_env(),
+  `+` = binary_op(" + "),
+  `-` = binary_op(" - "),
+  `*` = binary_op(" * "),
+  `/` = binary_op(" / "),
+  `^` = binary_op("^"),
+  `[` = binary_op("_"),
+
+  # Grouping
+  `{` = unary_op("\\left{ ", " \\right}"),
+  `(` = unary_op("\\left( ", " \\right)"),
+  paste = paste,
+
+  # Other math functions
+  sqrt = unary_op("\\sqrt{", "}"),
+  sin = unary_op("\\sin(", ")"),
+  log = unary_op("\\log(", ")"),
+  abs = unary_op("\\left| ", "\\right| "),
+  frac = function(a, b) {
+    paste0("\\frac{", a, "}{", b, "}")
+  },
+
+  # Labelling
+  hat = unary_op("\\hat{", "}"),
+  tilde = unary_op("\\tilde{", "}"),
+
+  # Plotmath
+  `%+-%` = binary_op(" \\pm "),
+  `%*%` = binary_op(" \\times "),
+  `%->%` = binary_op(" \\rightarrow "),
+  bold = unary_op("\\textbf{", "}"),
+  `!=` = binary_op(" \\neq ")
+)
+
+

Again we extend latex_env() to include the additional environment, f_env, which must be the parent of the symbol environment (which is the parent of the Greek symbol environment).

+
+
latex_env <- function(expr) {
+  # Known functions
+  f_env
+
+  # Default symbols
+  names <- all_names(expr)
+  symbol_env <- as_environment(set_names(names), parent = f_env)
+
+  # Known symbols
+  greek_env <- env_clone(greek_env, parent = symbol_env)
+
+  greek_env
+}
+
+

Now, we can finally check if our new functionality works:

+
+
# New plotmath functionality
+to_math(x %+-% y)
+#> <LATEX> x \pm y
+to_math(x %*% y)
+#> <LATEX> x \times y
+to_math(x %->% y)
+#> <LATEX> x \rightarrow y
+to_math(bold(x))
+#> <LATEX> \textbf{x}
+to_math(x != y)
+#> <LATEX> x \neq y
+
+# Other examples from Advanced R
+to_math(sin(x + pi))
+#> <LATEX> \sin(x + \pi)
+to_math(log(x[i]^2))
+#> <LATEX> \log(x_i^2)
+to_math(sin(sin))
+#> <LATEX> \sin(sin)
+
+

If we wanted, we could include further plotmath functions in this step. If this collides with other functions at some point, we could just create our own f_plotmath_env to support more plotmath functions. In that case we would need to add this environment also to latex_env() (as child environment of the function environment f_env).

+

To complete this answer, we will also add the support for unknown functions. Similarly as for the unknown symbols, we use the trick to recursively run the AST and just reuse the code from Advanced R.

+
+
all_calls_rec <- function(x) {
+  switch_expr(x,
+    constant = ,
+    symbol = character(),
+    call = {
+      fname <- as.character(x[[1]])
+      children <- flat_map_chr(as.list(x[-1]), all_calls)
+      c(fname, children)
+    }
+  )
+}
+
+all_calls <- function(x) {
+  unique(all_calls_rec(x))
+}
+
+all_calls(expr(f(g + b, c, d(a))))
+#> [1] "f" "+" "d"
+
+unknown_op <- function(op) {
+  new_function(
+    exprs(... = ),
+    expr({
+      contents <- paste(..., collapse = ", ")
+      paste0(!!paste0("\\mathrm{", op, "}("), contents, ")")
+    })
+  )
+}
+
+

Of course, we need to add the new call_env also to latex_env().

+
+
latex_env <- function(expr) {
+  calls <- all_calls(expr)
+  call_list <- map(set_names(calls), unknown_op)
+  call_env <- as_environment(call_list)
+
+  # Known functions
+  f_env <- env_clone(f_env, call_env)
+
+  # Default symbols
+  names <- all_names(expr)
+  symbol_env <- as_environment(set_names(names), parent = f_env)
+
+  # Known symbols
+  greek_env <- env_clone(greek_env, parent = symbol_env)
+  greek_env
+}
+
+

Finally, we rerun our tests and double check the newly supported plotmath operators.

+
+
# New plotmath functionality
+to_math(x %+-% y)
+#> <LATEX> x \pm y
+to_math(x %*% y)
+#> <LATEX> x \times y
+to_math(x %->% y)
+#> <LATEX> x \rightarrow y
+to_math(bold(x))
+#> <LATEX> \textbf{x}
+to_math(x != y)
+#> <LATEX> x \neq y
+
+# Other examples from Advanced R
+to_math(sin(x + pi))
+#> <LATEX> \sin(x + \pi)
+to_math(log(x[i]^2))
+#> <LATEX> \log(x_i^2)
+to_math(sin(sin))
+#> <LATEX> \sin(sin)
+
+# Unknown functions
+to_math(f(g(x)))
+#> <LATEX> \mathrm{f}(\mathrm{g}(x))
+
+ + +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/23_Measuring_performance.html b/docs/23_Measuring_performance.html new file mode 100644 index 00000000..d9f50667 --- /dev/null +++ b/docs/23_Measuring_performance.html @@ -0,0 +1,774 @@ + + + + + + + + + + +Advanced R Solutions - 23 - Measuring performance + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

23 - Measuring performance

+
+ + + +
+ + + + +
+ + +
+ +
+

Profiling

+

Q1: Profile the following function with torture = TRUE. What is surprising? Read the source code of rm() to figure out what’s going on.

+
+
f <- function(n = 1e5) {
+  x <- rep(1, n)
+  rm(x)
+}
+
+

A: We expect f() to create a vector (x) of length n, which is then removed so that f() just returns NULL. When we profile this function, it executes too fast for meaningful results.

+
+
profvis::profvis(f())
+#> Error in parse_rprof_lines(lines, expr_source): No parsing data available. Maybe your function was too fast?
+
+

Setting torture = TRUE triggers garbage collection after every memory allocation call, which may be useful for more exact memory profiling.

+
+
profvis::profvis(f(), torture = TRUE)
+
+

Surprisingly, profiling f() like this takes a very long time. What could be the reason?

+

We follow the hint in the question and inspect the source code of rm():

+
+
function(..., list = character(), pos = -1,
+         envir = as.environment(pos),
+         inherits = FALSE) {
+  dots <- match.call(expand.dots = FALSE)$...
+  if (
+    length(dots) && !all(
+      vapply(dots, function(x) {
+        is.symbol(x) ||
+          is.character(x)
+      }, NA, USE.NAMES = FALSE)
+    )
+  ) {
+    stop("... must contain names or character strings")
+  }
+  names <- vapply(dots, as.character, "")
+  if (length(names) == 0L) {
+    names <- character()
+  }
+  list <- .Primitive("c")(list, names)
+  .Internal(remove(list, envir, inherits))
+}
+
+

rm() does a surprising amount of work to get the name of the object to delete because it relies on non-standard evaluation.

+

We can make the job of rm() considerably simpler by using the list argument:

+
+
f2 <- function(n = 1e5) {
+  x <- rep(1, n)
+  rm(list = "x")
+}
+profvis::profvis(f2(), torture = TRUE)
+
+

Unfortunately, this still takes too long, and we are literally stuck in profiling.

+

Anecdotally, one of the authors once finished the profiling under an older R version. But the output seemed to be not very meaningful.

+

In conclusion, this question appears to be unanswerable for us, even for Hadley.

+
+
+

Microbenchmarking

+

Q1: Instead of using bench::mark(), you could use the built-in function system.time(). But system.time() is much less precise, so you’ll need to repeat each operation many times with a loop, and then divide to find the average time of each operation, as in the code below.

+
+
n <- 1e6
+system.time(for (i in 1:n) sqrt(x)) / n
+system.time(for (i in 1:n) x^0.5) / n
+
+

How do the estimates from system.time() compare to those from bench::mark()? Why are they different?

+

A: We first microbenchmark these two expressions using bench::mark() (Hester 2020) and observe that the mean is not reported (as it is generally more affected by outliers).

+
+
n <- 1e6
+x <- runif(100)
+
+bench_df <- bench::mark(
+  sqrt(x),
+  x^0.5,
+  iterations = n
+)
+
+bench_df
+#> # A tibble: 2 × 6
+#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 sqrt(x)    191.15ns    237ns  2277084.      848B     38.7
+#> 2 x^0.5        1.38µs    1.5µs   644621.      848B     23.2
+
+

We need to access the raw data, so we can compare the results of both benchmarking approaches.

+
+
t1_bench <- mean(unlist(bench_df[1, "time"]))
+t2_bench <- mean(unlist(bench_df[2, "time"]))
+
+t1_systime <- system.time(for (i in 1:n) sqrt(x)) / n
+t2_systime <- system.time(for (i in 1:n) x^0.5) / n
+
+

We see, that both approaches get the order of magnitude right. We assume, that the bench::mark()-results may be a little more accurate, because of its high precision timer. There may also be overhead introduced by the for loop in the system.time()-approach.

+
+
# Compare the results
+t1_systime["elapsed"]
+t1_bench
+
+t2_systime["elapsed"]
+t2_bench
+
+

Side Note: take a look at ?proc.time if you want to learn about the differences between “user”, “system” and “elapsed” time.

+

Q2: Here are two other ways to compute the square root of a vector. Which do you think will be fastest? Which will be slowest? Use microbenchmarking to test your answers.

+
+
x^(1 / 2)
+exp(log(x) / 2)
+
+

A: To compare these approaches, we’ll bench::mark() them and sort the result by the median execution time.

+
+
x <- runif(100)
+
+bm <- bench::mark(
+  sqrt(x),
+  x^0.5,
+  x^(1 / 2),
+  exp(log(x) / 2)
+)
+
+bm[order(bm$median), ]
+#> # A tibble: 4 × 6
+#>   expression         min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 sqrt(x)       205.01ns 223.05ns  4053946.      848B        0
+#> 2 exp(log(x)/2)   1.08µs   1.14µs   842693.      848B        0
+#> 3 x^0.5           1.45µs    1.5µs   639435.      848B        0
+#> 4 x^(1/2)         1.52µs   1.58µs   607937.      848B        0
+
+

As one might expect the idiomatic primitive function sqrt() is the fastest. The approach exp(log(x) / 2) which builds on two other primitive functions is second, even though already considerably slower. The other calculations are even slower: x^0.5 is faster than x^ (1/2), because 0.5 requires less computation than 1/2.

+
+
+

References

+ + +
+
+Hester, Jim. 2020. Bench: High Precision Timing of r Expressions. https://github.com/r-lib/bench. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/24_Improving_performance.html b/docs/24_Improving_performance.html new file mode 100644 index 00000000..74dde350 --- /dev/null +++ b/docs/24_Improving_performance.html @@ -0,0 +1,1289 @@ + + + + + + + + + + +Advanced R Solutions - 24 - Improving performance + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

24 - Improving performance

+
+ + + +
+ + + + +
+ + +
+ +
+

Checking for existing solutions

+

Q1: What are faster alternatives to lm? Which are specifically designed to work with larger datasets?

+

A: The CRAN task view for high-performance computing provides many recommendations. For this question, we are most interested in the section on “Large memory and out-of-memory data”. We could for example give biglm::biglm() (Lumley 2020), fixest::feols() (Bergé 2018) a try.

+

For small datasets, we observe only minor performance gains (or even a small cost):

+
+
penguins <- palmerpenguins::penguins
+
+bench::mark(
+  "lm" = lm(
+    body_mass_g ~ bill_length_mm + species,
+    data = penguins
+  ) %>% coef(),
+  "biglm" = biglm::biglm(
+    body_mass_g ~ bill_length_mm + species,
+    data = penguins
+  ) %>% coef(),
+  "fixest" = fixest::feols(
+    body_mass_g ~ bill_length_mm + species,
+    data = penguins
+  ) %>% coef()
+)
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).
+#> # A tibble: 3 × 6
+#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 lm         423.93µs 500.75µs     1844.  937.49KB    10.6 
+#> 2 biglm      320.17µs 367.26µs     2636.    6.14MB    10.4 
+#> 3 fixest       3.58ms   3.93ms      252.   13.79MB     6.25
+
+

For larger datasets the selection of the appropriate method is of greater relevance:

+
+
eps <- rnorm(100000)
+x1 <- rnorm(100000, 5, 3)
+x2 <- rep(c("a", "b"), 50000)
+y <- 7 * x1 + (x2 == "a") + eps
+td <- data.frame(y = y, x1 = x1, x2 = x2, eps = eps)
+
+bench::mark(
+  "lm" = lm(y ~ x1 + x2, data = td) %>% coef(),
+  "biglm" = biglm::biglm(y ~ x1 + x2, data = td) %>% coef(),
+  "fixest" = fixest::feols(y ~ x1 + x2, data = td) %>% coef()
+)
+#> # A tibble: 3 × 6
+#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 lm          16.91ms  17.08ms      58.5   27.04MB    732. 
+#> 2 biglm        15.4ms  15.57ms      64.0   22.22MB    256. 
+#> 3 fixest       8.18ms   8.68ms     110.     9.05MB     60.8
+
+

For further speed improvements, you could install a linear algebra library optimised for your system.

+
+

The functions of class ‘feols’ may speed up the fitting of LMs to large datasets. High performances can be obtained especially if R is linked against an optimized BLAS, such as ATLAS, Intel MKL, OpenBLAS, and others.

+
+

Tip: In case your dataset is stored in a database, you might want to check out the {modeldb} package (Kuhn 2020) which executes the linear model code in the corresponding database backend.

+

Q2: What package implements a version of match() that’s faster for repeated lookups? How much faster is it?

+

A: A web search points us to the {fastmatch} package (Urbanek 2017). We compare it to base::match() and observe an impressive performance gain.

+
+
table <- 1:100000
+x <- sample(table, 10000, replace = TRUE)
+
+bench::mark(
+  match = match(x, table),
+  fastmatch = fastmatch::fmatch(x, table)
+)
+#> # A tibble: 2 × 6
+#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 match        7.41ms   7.58ms      131.    1.46MB     6.33
+#> 2 fastmatch   258.9µs 270.06µs     3642.  442.91KB     4.05
+
+

Q3: List four functions (not just those in base R) that convert a string into a date time object. What are their strengths and weaknesses?

+

A: The usual base R way is to use the as.POSIXct() generic and create a date time object of class POSIXct and type integer.

+
+
date_ct <- as.POSIXct("2020-01-01 12:30:25")
+date_ct
+#> [1] "2020-01-01 12:30:25 EST"
+
+

Under the hood as.POSIXct() employs as.POSIXlt() for the character conversion. This creates a date time object of class POSIXlt and type list.

+
+
date_lt <- as.POSIXlt("2020-01-01 12:30:25")
+date_lt
+#> [1] "2020-01-01 12:30:25 EST"
+
+

The POSIXlt class has the advantage that it carries the individual time components as attributes. This allows to extract the time components via typical list operators.

+
+
attributes(date_lt)
+#> $names
+#>  [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"  
+#>  [9] "isdst"  "zone"   "gmtoff"
+#> 
+#> $class
+#> [1] "POSIXlt" "POSIXt" 
+#> 
+#> $tzone
+#> [1] ""    "EST" "EDT"
+#> 
+#> $balanced
+#> [1] TRUE
+date_lt$sec
+#> [1] 25
+
+

However, while lists may be practical, basic calculations are often faster and require less memory for objects with underlying integer type.

+
+
date_lt2 <- rep(date_lt, 10000)
+date_ct2 <- rep(date_ct, 10000)
+
+bench::mark(
+  date_lt2 - date_lt2,
+  date_ct2 - date_ct2,
+  date_ct2 - date_lt2
+)
+#> # A tibble: 3 × 6
+#>   expression               min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>          <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 date_lt2 - date_lt2  17.32ms  17.52ms      56.9    1.39MB     2.03
+#> 2 date_ct2 - date_ct2  36.06µs  40.44µs   23556.   195.45KB   111.  
+#> 3 date_ct2 - date_lt2   7.67ms   8.75ms     115.   781.95KB     2.05
+
+

as.POSIXlt() in turn uses strptime() under the hood, which creates a similar date time object.

+
+
date_str <- strptime("2020-01-01 12:30:25",
+  format = "%Y-%m-%d %H:%M:%S"
+)
+identical(date_lt, date_str)
+#> [1] TRUE
+
+

as.POSIXct() and as.POSIXlt() accept different character inputs by default (e.g. "2001-01-01 12:30" or "2001/1/1 12:30"). strptime() requires the format argument to be set explicitly, and provides a performance improvement in return.

+
+
bench::mark(
+  as.POSIXct = as.POSIXct("2020-01-01 12:30:25"),
+  as.POSIXct_format = as.POSIXct("2020-01-01 12:30:25",
+    format = "%Y-%m-%d %H:%M:%S"
+  ),
+  strptime_fomat = strptime("2020-01-01 12:30:25",
+    format = "%Y-%m-%d %H:%M:%S"
+  )
+)[1:3]
+#> # A tibble: 3 × 3
+#>   expression             min   median
+#>   <bch:expr>        <bch:tm> <bch:tm>
+#> 1 as.POSIXct         20.43µs  23.71µs
+#> 2 as.POSIXct_format   10.9µs  12.38µs
+#> 3 strptime_fomat      2.85µs   3.08µs
+
+

A fourth way is to use the converter functions from the {lubridate} package (Grolemund and Wickham 2011), which contains wrapper functions (for the POSIXct approach) with an intuitive syntax. (There is a slight decrease in performance though.)

+
+
library(lubridate)
+ymd_hms("2013-07-24 23:55:26")
+#> [1] "2013-07-24 23:55:26 UTC"
+
+bench::mark(
+  as.POSIXct = as.POSIXct("2013-07-24 23:55:26", tz = "UTC"),
+  ymd_hms = ymd_hms("2013-07-24 23:55:26")
+)[1:3]
+#> # A tibble: 2 × 3
+#>   expression      min   median
+#>   <bch:expr> <bch:tm> <bch:tm>
+#> 1 as.POSIXct  22.55µs   25.7µs
+#> 2 ymd_hms      1.54ms    1.7ms
+
+

For additional ways to convert characters into date time objects, have a look at the {chron}, the {anytime} and the {fasttime} packages. The {chron} package (James and Hornik 2020) introduces new classes and stores times as fractions of days in the underlying double type, while it doesn’t deal with time zones and daylight savings. The {anytime} package (Eddelbuettel 2020) aims to convert “Anything to POSIXct or Date”. The {fasttime} package (Urbanek 2016) contains only one function, fastPOSIXct().

+

Q4: Which packages provide the ability to compute a rolling mean?

+

A: A rolling mean is a useful statistic to smooth time-series, spatial and other types of data. The size of the rolling window usually determines the amount of smoothing and the number of missing values at the boundaries of the data.

+

The general functionality can be found in multiple packages, which vary in speed and flexibility of the computations. Here is a benchmark for several functions that all serve our purpose.

+
+
x <- 1:10
+slider::slide_dbl(x, mean, .before = 1, .complete = TRUE)
+#>  [1]  NA 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5
+
+bench::mark(
+  caTools = caTools::runmean(x, k = 2, endrule = "NA"),
+  data.table = data.table::frollmean(x, 2),
+  slider = slider::slide_dbl(x, mean, .before = 1, .complete = TRUE),
+  TTR = TTR::SMA(x, 2),
+  zoo_apply = zoo::rollapply(x, 2, mean, fill = NA, align = "right"),
+  zoo_rollmean = zoo::rollmean(x, 2, fill = NA, align = "right")
+)
+#> # A tibble: 6 × 6
+#>   expression        min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>   <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 caTools          25µs   29.2µs    33235.  168.47KB     16.6
+#> 2 data.table     13.2µs   15.6µs    60402.   32.73KB     30.2
+#> 3 slider         29.8µs   34.5µs    28092.        0B     16.9
+#> 4 TTR            53.8µs   62.7µs    15513.  608.02KB     14.6
+#> 5 zoo_apply     123.8µs  145.7µs     6673.  453.96KB     17.0
+#> 6 zoo_rollmean  115.2µs  123.7µs     7637.    6.43KB     19.0
+
+

You may also take a look at an extensive example in the first edition of Advanced R, which demonstrates how a rolling mean function can be created.

+

Q5: What are the alternatives to optim()?

+

A: According to its description (see ?optim) optim() implements:

+
+

General-purpose optimization based on Nelder–Mead, quasi-Newton and conjugate-gradient algorithms. It includes an option for box-constrained optimization and simulated annealing.

+
+

optim() allows to optimise a function (fn) on an interval with a specific method (method = c("Nelder-Mead", "BFGS", "CG", "L-BFGS-B", "SANN", "Brent")). Many detailed examples are given in the documentation. In the simplest case, we give optim() the starting value par = 0 to calculate the minimum of a quadratic polynomial:

+
+
optim(0, function(x) x^2 - 100 * x + 50,
+  method = "Brent",
+  lower = -1e20, upper = 1e20
+)
+#> $par
+#> [1] 50
+#> 
+#> $value
+#> [1] -2450
+#> 
+#> $counts
+#> function gradient 
+#>       NA       NA 
+#> 
+#> $convergence
+#> [1] 0
+#> 
+#> $message
+#> NULL
+
+

Since this solves a one-dimensional optimisation task, we could have also used stats::optimize().

+
+
optimize(function(x) x^2 - 100 * x + 50, c(-1e20, 1e20))
+#> $minimum
+#> [1] 50
+#> 
+#> $objective
+#> [1] -2450
+
+

For more general alternatives, the appropriate choice highly depends on the type of optimisation you intend to do. The CRAN task view on optimisation and mathematical modelling can serve as a useful reference. Here are a couple of examples:

+ +
+
+

Doing as little as possible

+

Q1: What’s the difference between rowSums() and .rowSums()?

+

A: When we inspect the source code of the user-facing rowSums(), we see that it is designed as a wrapper around .rowSums() with some input validation, conversions and handling of complex numbers.

+
+
rowSums
+#> function (x, na.rm = FALSE, dims = 1L) 
+#> {
+#>     if (is.data.frame(x)) 
+#>         x <- as.matrix(x)
+#>     if (!is.array(x) || length(dn <- dim(x)) < 2L) 
+#>         stop("'x' must be an array of at least two dimensions")
+#>     if (dims < 1L || dims > length(dn) - 1L) 
+#>         stop("invalid 'dims'")
+#>     p <- prod(dn[-(id <- seq_len(dims))])
+#>     dn <- dn[id]
+#>     z <- if (is.complex(x)) 
+#>         .Internal(rowSums(Re(x), prod(dn), p, na.rm)) + (0+1i) * 
+#>             .Internal(rowSums(Im(x), prod(dn), p, na.rm))
+#>     else .Internal(rowSums(x, prod(dn), p, na.rm))
+#>     if (length(dn) > 1L) {
+#>         dim(z) <- dn
+#>         dimnames(z) <- dimnames(x)[id]
+#>     }
+#>     else names(z) <- dimnames(x)[[1L]]
+#>     z
+#> }
+#> <bytecode: 0x5f225cb2bb38>
+#> <environment: namespace:base>
+
+

.rowSums() calls an internal function, which is built into the R interpreter. These compiled functions can be very fast.

+
+
.rowSums
+#> function (x, m, n, na.rm = FALSE) 
+#> .Internal(rowSums(x, m, n, na.rm))
+#> <bytecode: 0x5f225c1051e0>
+#> <environment: namespace:base>
+
+

However, as our benchmark reveals almost identical computing times, we prefer the safer variant over the internal function for this case.

+
+
m <- matrix(rnorm(1e6), nrow = 1000)
+
+bench::mark(
+  rowSums(m),
+  .rowSums(m, 1000, 1000)
+)
+#> # A tibble: 2 × 6
+#>   expression                   min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>              <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 rowSums(m)                1.96ms    2.2ms      455.    7.86KB        0
+#> 2 .rowSums(m, 1000, 1000)   1.98ms   2.19ms      458.    7.86KB        0
+
+

Q2: Make a faster version of chisq.test() that only computes the chi-square test statistic when the input is two numeric vectors with no missing values. You can try simplifying chisq.test() or by coding from the mathematical definition.

+

A: We aim to speed up our reimplementation of chisq.test() by doing less.

+
+
chisq.test2 <- function(x, y) {
+  m <- rbind(x, y)
+  margin1 <- rowSums(m)
+  margin2 <- colSums(m)
+  n <- sum(m)
+  me <- tcrossprod(margin1, margin2) / n
+
+  x_stat <- sum((m - me)^2 / me)
+  df <- (length(margin1) - 1) * (length(margin2) - 1)
+  p.value <- pchisq(x_stat, df = df, lower.tail = FALSE)
+
+  list(x_stat = x_stat, df = df, p.value = p.value)
+}
+
+

We check if our new implementation returns the same results and benchmark it afterwards.

+
+
a <- 21:25
+b <- seq(21, 29, 2)
+m <- cbind(a, b)
+
+chisq.test(m) %>% print(digits = 5)
+#> 
+#>  Pearson's Chi-squared test
+#> 
+#> data:  m
+#> X-squared = 0.162, df = 4, p-value = 1
+chisq.test2(a, b)
+#> $x_stat
+#> [1] 0.162
+#> 
+#> $df
+#> [1] 4
+#> 
+#> $p.value
+#> [1] 0.997
+
+bench::mark(
+  chisq.test(m),
+  chisq.test2(a, b),
+  check = FALSE
+)
+#> # A tibble: 2 × 6
+#>   expression             min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>        <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 chisq.test(m)      31.43µs   35.6µs    26715.        0B     16.0
+#> 2 chisq.test2(a, b)   9.16µs   10.4µs    91271.        0B     18.3
+
+

Q3: Can you make a faster version of table() for the case of an input of two integer vectors with no missing values? Can you use it to speed up your chi-square test?

+

A: When analysing the source code of table() we aim to omit everything unnecessary and extract the main building blocks. We observe that table() is powered by tabulate() which is a very fast counting function. This leaves us with the challenge to compute the pre-processing as performant as possible.

+

First, we calculate the dimensions and names of the output table. Then we use fastmatch::fmatch() to map the elements of each vector to their position within the vector itself (i.e. the smallest value is mapped to 1L, the second smallest value to 2L, etc.). Following the logic within table() we combine and shift these values to create a mapping of the integer pairs in our data to the index of the output table. After applying these lookups tabulate() counts the values and returns an integer vector with counts for each position in the table. As a last step, we reuse the code from table() to assign the correct dimension and class.

+
+
table2 <- function(a, b) {
+  a_s <- sort(unique(a))
+  b_s <- sort(unique(b))
+
+  a_l <- length(a_s)
+  b_l <- length(b_s)
+
+  dims <- c(a_l, b_l)
+  pr <- a_l * b_l
+  dn <- list(a = a_s, b = b_s)
+
+  bin <- fastmatch::fmatch(a, a_s) +
+    a_l * fastmatch::fmatch(b, b_s) - a_l
+  y <- tabulate(bin, pr)
+
+  y <- array(y, dim = dims, dimnames = dn)
+  class(y) <- "table"
+
+  y
+}
+
+a <- sample(100, 10000, TRUE)
+b <- sample(100, 10000, TRUE)
+
+bench::mark(
+  table(a, b),
+  table2(a, b)
+)
+#> # A tibble: 2 × 6
+#>   expression        min   median `itr/sec` mem_alloc `gc/sec`
+#>   <bch:expr>   <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
+#> 1 table(a, b)     609µs    670µs     1450.    1.29MB     43.3
+#> 2 table2(a, b)    221µs    236µs     4119.  563.34KB     48.5
+
+

Since we didn’t use table() in our chisq.test2()-implementation, we cannot benefit from the slight performance gain from table2().

+
+
+

Vectorise

+

Q1: The density functions, e.g. dnorm(), have a common interface. Which arguments are vectorised over? What does rnorm(10, mean = 10:1) do?

+

A: We can get an overview of the interface of these functions via ?dnorm:

+
+
dnorm(x, mean = 0, sd = 1, log = FALSE)
+pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
+qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
+rnorm(n, mean = 0, sd = 1)
+
+

These functions are vectorised over their numeric arguments, which includes the first argument (x, q, p, n) as well as mean and sd.

+

rnorm(10, mean = 10:1) generates ten random numbers from different normal distributions. These normal distributions differ in their means. The first has mean 10, the second mean 9, the third mean 8 and so on.

+

Q2: Compare the speed of apply(x, 1, sum) with rowSums(x) for varying sizes of x.

+

A: We compare the two functions for square matrices of increasing size:

+
+
rowsums <- bench::press(
+  p = seq(500, 5000, length.out = 10),
+  {
+    mat <- tcrossprod(rnorm(p), rnorm(p))
+    bench::mark(
+      rowSums = rowSums(mat),
+      apply = apply(mat, 1, sum)
+    )
+  }
+)
+#> Running with:
+#>        p
+#>  1   500
+#>  2  1000
+#>  3  1500
+#>  4  2000
+#>  5  2500
+#>  6  3000
+#>  7  3500
+#>  8  4000
+#>  9  4500
+#> 10  5000
+
+library(ggplot2)
+
+rowsums %>%
+  summary() %>%
+  dplyr::mutate(Approach = as.character(expression)) %>%
+  ggplot(
+    aes(p, median, color = Approach, group = Approach)
+  ) +
+  geom_point() +
+  geom_line() +
+  labs(
+    x = "Number of Rows and Columns",
+    y = "Median (s)"
+  ) +
+  theme(legend.position = "top")
+
+
+
+

+
+
+
+
+

We can see that the difference in performance is negligible for small matrices but becomes more and more relevant as the size of the data increases. apply() is a very versatile tool, but it’s not “vectorised for performance” and not as optimised as rowSums().

+

Q3: How can you use crossprod() to compute a weighted sum? How much faster is it than the naive sum(x * w)?

+

A: We can hand the vectors to crossprod(), which converts them to row- and column-vectors and then multiplies these. The result is the dot product, which corresponds to a weighted sum.

+
+
x <- rnorm(10)
+w <- rnorm(10)
+all.equal(sum(x * w), crossprod(x, w)[[1]])
+#> [1] TRUE
+
+

A benchmark of both approaches for different vector lengths indicates that the crossprod() variant is almost twice as fast as sum(x * w).

+
+
weightedsum <- bench::press(
+  n = 1:10,
+  {
+    x <- rnorm(n * 1e6)
+    bench::mark(
+      sum = sum(x * x),
+      crossprod = crossprod(x, x)[[1]]
+    )
+  }
+)
+#> Running with:
+#>        n
+#>  1     1
+#>  2     2
+#>  3     3
+#>  4     4
+#>  5     5
+#>  6     6
+#>  7     7
+#>  8     8
+#>  9     9
+#> 10    10
+
+weightedsum %>%
+  summary() %>%
+  dplyr::mutate(Approach = as.character(expression)) %>%
+  ggplot(aes(n, median, color = Approach, group = Approach)) +
+  geom_point() +
+  geom_line() +
+  labs(
+    x = "Vector length (millions)",
+    y = "Median (s)"
+  ) +
+  theme(legend.position = "top")
+
+
+
+

+
+
+
+
+
+
+

References

+ + +
+
+Ardia, David, Kris Boudt, Peter Carl, Katharine M. Mullen, and Brian G. Peterson. 2011. Differential Evolution with DEoptim: An Application to Non-Convex Portfolio Optimization.” R Journal 3 (1): 27–34. https://doi.org/10.32614/RJ-2011-005. +
+
+Bergé, Laurent. 2018. “Efficient Estimation of Maximum Likelihood Models with Multiple Fixed-Effects: The R Package FENmlm.” CREA Discussion Papers, no. 13. +
+
+Eddelbuettel, Dirk. 2020. Anytime: Anything to ’POSIXct’ or ’Date’ Converter. https://CRAN.R-project.org/package=anytime. +
+
+Grolemund, Garrett, and Hadley Wickham. 2011. “Dates and Times Made Easy with lubridate.” Journal of Statistical Software 40 (3): 1–25. https://www.jstatsoft.org/v40/i03/. +
+
+James, David, and Kurt Hornik. 2020. Chron: Chronological Objects Which Can Handle Dates and Times. https://CRAN.R-project.org/package=chron. +
+
+Kuhn, Max. 2020. Modeldb: Fits Models Inside the Database. https://CRAN.R-project.org/package=modeldb. +
+
+Lumley, Thomas. 2020. Biglm: Bounded Memory Linear and Generalized Linear Models. https://CRAN.R-project.org/package=biglm. +
+
+Nash, John C. 2014. “On Best Practice Optimization Methods in R.” Journal of Statistical Software 60 (2): 1–14. http://www.jstatsoft.org/v60/i02/. +
+
+Nash, John C., and Ravi Varadhan. 2011. “Unifying Optimization Algorithms to Aid Software System Users: optimx for R.” Journal of Statistical Software 43 (9): 1–14. http://www.jstatsoft.org/v43/i09/. +
+
+Urbanek, Simon. 2016. Fasttime: Fast Utility Function for Time Parsing and Conversion. https://CRAN.R-project.org/package=fasttime. +
+
+———. 2017. Fastmatch: Fast Match() Function. https://CRAN.R-project.org/package=fastmatch. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/25_Rewriting_R_code_in_Cpp.html b/docs/25_Rewriting_R_code_in_Cpp.html new file mode 100644 index 00000000..93dfbf9c --- /dev/null +++ b/docs/25_Rewriting_R_code_in_Cpp.html @@ -0,0 +1,1423 @@ + + + + + + + + + + +Advanced R Solutions - 25 - Rewriting R code in C++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

25 - Rewriting R code in C++

+
+ + + +
+ + + + +
+ + +
+ +
+

Prerequisites

+

On our journey through R’s metaprogramming, we continue to use the functions from the {cpp11} (Vaughan, Hester, and François 2023) package.

+
+
library(cpp11)
+
+
+
+

Getting started with C++

+

Q1: With the basics of C++ in hand, it’s now a great time to practice by reading and writing some simple C++ functions. For each of the following functions, read the code and figure out what the corresponding base R function is. You might not understand every part of the code yet, but you should be able to figure out the basics of what the function does.

+

Pay attention to the parts where we use writable::doubles instead of doubles, in C++ objects can be read-only, which is different from R (or Python).

+

Unlike R, C++ indexes start at 0, not 1. This is a common source of bugs when porting code from R to C++.

+
double f1_(doubles x) {
+  int n = x.size();
+  double y = 0;
+  
+  for(int i = 0; i < n; ++i) {
+    y += x[i] / n;
+  }
+  return y;
+}
+
+doubles f2_(doubles x) {
+  int n = x.size();
+  writable::doubles out(n);
+  
+  out[0] = x[0];
+  for(int i = 1; i < n; ++i) {
+    out[i] = out[i - 1] + x[i];
+  }
+  return out;
+}
+
+bool f3_(logicals x) {
+  int n = x.size();
+  
+  for(int i = 0; i < n; ++i) {
+    if (x[i]) return true;
+  }
+  return false;
+}
+
+int f4_(function pred, list x) {
+  int n = x.size();
+  
+  for(int i = 0; i < n; ++i) {
+    logicals res = pred(x[i]);
+    if (res[0]) return i + 1;
+  }
+  return 0;
+}
+
+doubles f5_(doubles x, doubles y) {
+  int n = std::max(x.size(), y.size());
+  vector<double> x1(n);
+  vector<double> y1(n);
+
+  for (int i = 0; i < n; ++i) {
+    x1[i] = x[i % x.size()];
+    y1[i] = y[i % y.size()];
+  }
+
+  writable::doubles out(n);
+
+  for (int i = 0; i < n; ++i) {
+    out[i] = std::min(x1[i], y1[i]);
+  }
+
+  return out;
+}
+

A: The code above corresponds to the following base R functions:

+
    +
  • f1_: mean()
  • +
  • f2_: cumsum()
  • +
  • f3_: any()
  • +
  • f4_: Position()
  • +
  • f5_: pmin()
  • +
+

Q2: To practice your function writing skills, convert the following functions into C++. For now, assume the inputs have no missing values.

+
    +
  1. all().

  2. +
  3. cumprod(), cummin(), cummax().

  4. +
  5. diff(). Start by assuming lag 1, and then generalise for lag n.

  6. +
  7. range().

  8. +
  9. var(). Read about the approaches you can take on Wikipedia. Whenever implementing a numerical algorithm, it’s always good to check what is already known about the problem.

  10. +
+

A: Let’s port these functions to C++.

+
    +
  1. all()

    +
    bool all_cpp_(logicals x) {
    +  int n = x.size();
    +  for(int i = 0; i < n; ++i) {
    +    if (x[i] == false) {
    +      return false;
    +    }
    +  }
    +  return true;
    +}
  2. +
  3. cumprod(), cummin(), cummax().

    +
    doubles cumprod_cpp_(doubles x) {
    +  int n = x.size();
    +  writable::doubles out(n);
    +  out[0] = x[0];
    +  for(int i = 1; i < n; ++i) {
    +    out[i] = out[i - 1] * x[i];
    +  }
    +  return out;
    +}
    +
    +doubles cummin_cpp_(doubles x) {
    +  int n = x.size();
    +  writable::doubles out(n);
    +
    +  out[0] = x[0];
    +  for (int i = 1; i < n; ++i) {
    +    double x1 = out[i - 1];
    +    double x2 = x[i];
    +    out[i] = std::min(x1, x2);
    +  }
    +
    +  return out;
    +}
    +
    +doubles cummax_cpp_(doubles x) {
    +  int n = x.size();
    +  writable::doubles out(n);
    +
    +  out[0] = x[0];
    +  for (int i = 1; i < n; ++i) {
    +    double x1 = out[i - 1];
    +    double x2 = x[i];
    +    out[i] = std::max(x1, x2);
    +  }
    +  return out;
    +}
  4. +
  5. diff() (Start by assuming lag 1, and then generalise for lag n.)

    +
    doubles diff_cpp_(doubles x) {
    +  int n = x.size();
    +  writable::doubles out(n - 1);
    +
    +  for (int i = 1; i < n; i++) {
    +    out[i - 1] = x[i] - x[i - 1];
    +  }
    +  return out ;
    +}
    +
    +doubles diff_lag_cpp_(doubles x, int lag) {
    +  int n = x.size();
    +
    +  if (lag >= n) stop("`lag` must be less than `length(x)`.");
    +
    +  writable::doubles out(n - lag);
    +
    +  for (int i = lag; i < n; i++) {
    +    out[i - lag] = x[i] - x[i - lag];
    +  }
    +  return out;
    +}
  6. +
  7. range()

    +
    doubles range_cpp_(doubles x) {
    +  double omin = x[0], omax = x[0];
    +  int n = x.size();
    +
    +  if (n == 0) stop("`length(x)` must be greater than 0.");
    +
    +  for (int i = 1; i < n; i++) {
    +    omin = std::min(x[i], omin);
    +    omax = std::max(x[i], omax);
    +  }
    +
    +  writable::doubles out(2);
    +  out[0] = omin;
    +  out[1] = omax;
    +  return out;
    +}
  8. +
  9. var()

    +
    double var_cpp_(doubles x) {
    +  int n = x.size();
    +
    +  if (n < 2) {
    +    return NA_REAL;
    +  }
    +
    +  double mx = 0;
    +  for (int i = 0; i < n; ++i) {
    +    mx += x[i] / n;
    +  }
    +
    +  double out = 0;
    +  for (int i = 0; i < n; ++i) {
    +    out += pow(x[i] - mx, 2);
    +  }
    +
    +  return out / (n - 1);
    +}
  10. +
+
+
+

Missing values

+

Q1: Rewrite any of the functions from the first exercise to deal with missing values. If na.rm is true, ignore the missing values. If na.rm is false, return a missing value if the input contains any missing values. Some good functions to practice with are min(), max(), range(), mean(), and var().

+

A: For this exercise we start with min_cpp_() and extend it so it can deal with missing values. We introduce an na_rm argument to make min_cpp_() aware of NAs. In case x contains exclusively NA values min_cpp_() should return Inf for na_rm = TRUE. For the return values vector data types are used to avoid irregular type conversions.

+

We use expressions provided by #include <cpp11.hpp> to simplify the code:

+
    +
  • R_PosInf, which is pure C++ this would be std::numeric_limits<double>::infinity(); and requires #include <limits>.
  • +
  • is_na(x[i]), which is the same as x[i] == NA_REAL.
  • +
+
#include <cpp11.hpp>
+
+using namespace cpp11;
+
+[[cpp11::register]] doubles min_cpp_(cpp11::doubles x, bool na_rm) {
+  int n = x.size();
+  writable::doubles out = {R_PosInf};
+
+  if (na_rm) {
+    for (int i = 0; i < n; ++i) {
+      if (x[i] == NA_REAL) {
+        continue;
+      }
+      if (x[i] < out[0]) {
+        out[0] = x[i];
+      }
+    }
+  } else {
+    for (int i = 0; i < n; ++i) {
+      if (is_na(x[i])) {
+        out[0] = NA_REAL;
+        return out;
+      }
+      if (x[i] < out[0]) {
+        out[0] = x[i];
+      }
+    }
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/01_min.cpp")
+
+x <- c(2:4, NA)
+min(x, na.rm = FALSE)
+#> [1] NA
+min_cpp_(as.double(x), FALSE)
+#> [1] NA
+min(x, na.rm = TRUE)
+#> [1] 2
+min_cpp_(as.double(x), TRUE)
+#> [1] 2
+
+y <- c(NA, NA)
+min(y, na.rm = FALSE)
+#> [1] NA
+min_cpp_(as.double(y), FALSE)
+#> [1] NA
+min(y, na.rm = TRUE)
+#> Warning in min(y, na.rm = TRUE): no non-missing arguments to min; returning Inf
+#> [1] Inf
+min_cpp_(as.double(y), TRUE)
+#> [1] Inf
+
+

Note that we added explicit values and types for each parameter. This is necessary because cpp11 does not automatically cast integers (i.e., 2:4) to doubles and does not allow default parameters in the function. This is because R (and Python) automatically cast 1L to 1.0 depending on the context, which is not the case for C++. Run min_cpp_(c(2:4, NA), FALSE) and read the error message carefully.

+

To simplify things for the end user, you can provide a wrapper function that calls min_cpp_() with the correct types and default values.

+
+
min_cpp <- function(x, na_rm = FALSE) {
+  if (!is.double(x)) {
+    x <- as.double(x)
+  }
+  min_cpp_(x, na_rm)
+}
+
+min_cpp(c(2:4, NA))
+#> [1] NA
+
+

We also extend any_cpp_() so it can deal with missing values. Please note that this (again) introduces some code duplication. This could be avoided by moving the check for missing values to the inner loop at the expense of a slight decrease of performance. Here we use logicals as return type. If we would use bool instead, the C++ NA_LOGICAL would be converted into R’s logical TRUE.

+
#include <cpp11.hpp>
+
+using namespace cpp11;
+
+[[cpp11::register]] logicals any_cpp_(logicals x, bool na_rm) {
+  int n = x.size();
+  writable::logicals out = {false};
+
+  if (na_rm == false) {
+    for (int i = 0; i < n; ++i) {
+      if (is_na(x[i])) {
+        out[0] = NA_LOGICAL;
+        return out;
+      } else {
+        if (x[i]) {
+          out[0] = true;
+        }
+      }
+    }
+  }
+
+  if (na_rm) {
+    for (int i = 0; i < n; ++i) {
+      if (is_na(x[i])) {
+        continue;
+      }
+      if (x[i]) {
+        out[0] = true;
+        return out;
+      }
+    }
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/02_any.cpp")
+
+x <- c(NA, TRUE)
+any(x)
+#> [1] TRUE
+any_cpp_(x, F)
+#> [1] NA
+any_cpp_(x, T)
+#> [1] TRUE
+
+

Q2: Rewrite cumsum() and diff() so they can handle missing values. Note that these functions have slightly more complicated behaviour.

+

A: Our NA-aware cumsum_cpp_() function will return a vector of the same length as x. By default (na_rm = FALSE) all values following the first NA input value will be set to NA, because they depend on the unknown missing value. In case of na_rm = FALSE the NA values are treated like zeros.

+
#include <cpp11.hpp>
+
+using namespace cpp11;
+
+[[cpp11::register]] doubles cumsum_cpp_(doubles x, bool na_rm = false) {
+  int n = x.size();
+
+  writable::doubles out(n);
+  out[0] = x[0];
+
+  if (na_rm == true) {
+    for (int i = 1; i < n; ++i) {
+      double y1 = out[i - 1], y2 = x[i];
+      if (ISNAN(y2)) {
+        out[i] = y1;
+      } else {
+        if (ISNAN(y1)) {
+          out[i] = y2;
+        } else {
+          out[i] = y1 + y2;
+        }
+      }
+    }
+  } else {
+    for (int i = 1; i < n; ++i) {
+      double y1 = out[i - 1], y2 = x[i];
+      if (ISNAN(y2)) {
+        out[i] = NA_REAL;
+      } else {
+        if (ISNAN(y1)) {
+          out[i] = NA_REAL;
+        } else {
+          out[i] = y1 + y2;
+        }
+      }
+    }
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/03_cumsum.cpp")
+
+x <- c(1, NA, 2, 4)
+cumsum(x)
+#> [1]  1 NA NA NA
+cumsum_cpp_(c(1, NA, 2, 4), FALSE)
+#> [1]  1 NA NA NA
+cumsum_cpp_(c(1, NA, 2, 4), TRUE)
+#> [1] 1 1 3 7
+
+

This example works immediately, because the input vector is a vector of doubles. If we create a sequence of integers, we need to cast it as doubles.

+
+
cumsum_cpp_(as.double(1:4), FALSE)
+#> [1]  1  3  6 10
+
+# or use a wrapper function
+cumsum_cpp <- function(x, na_rm = FALSE) {
+  if (!is.double(x)) {
+    x <- as.double(x)
+  }
+  cumsum_cpp_(x, na_rm)
+}
+
+cumsum_cpp(1:4, FALSE)
+#> [1]  1  3  6 10
+
+

The diff_cpp_() implementation will return an NA vector of length length(x) - lag, if the input vector contains a missing value. In case of na_rm = TRUE, the function will return an NA for every difference with at least one NA as input.

+
#include <cpp11.hpp>
+
+using namespace cpp11;
+
+[[cpp11::register]] doubles diff_cpp_(doubles x, int lag, bool na_rm) {
+  int n = x.size();
+
+  if (lag >= n) stop("`lag` must be less than `length(x)`.");
+
+  writable::doubles out(n - lag);
+
+  for (int i = lag; i < n; i++) {
+    if (is_na(x[i]) || is_na(x[i - lag])) {
+      if (!na_rm) {
+        writable::doubles out_na(n - lag);
+        for (int j = 0; j < n - lag; ++j) {
+          out_na[j] = NA_REAL;
+        }
+        return out_na;
+      }
+      out[i - lag] = NA_REAL;
+      continue;
+    }
+    out[i - lag] = x[i] - x[i - lag];
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/04_diff.cpp")
+
+x <- c(1, 3, NA, 10)
+diff(x, 1L)
+#> [1]  2 NA NA
+diff_cpp_(x, 1L, FALSE)
+#> [1] NA NA NA
+diff_cpp_(x, 1L, TRUE)
+#> [1]  2 NA NA
+
+
+
+

Standard Template Library

+

To practice using the STL algorithms and data structures, implement the following using R functions in C++, using the hints provided:

+

Q1: median.default() using partial_sort.

+

A: The median is computed differently for even or odd vectors, which we allow for in the function below.

+

To be able to use partial_sort() we need to include the algorithm header. Unlike the previous examples, the input will be const doubles& x, meaning that the function takes a constant reference to an object of type doubles (i.e., the function will not modify the object x), and the & symbol means that the function takes a reference to the object instead of a copy of the object.

+

This can improve performance when the object is large, because it avoids copying the object, but in this case we did it to use the partial_sort() function, which is not compatible with doubles but it is with vector<double> types.

+

doubles is a data type we can send from R to C++ and vice-versa, but it is not compatible with all of C++ functions. vector<double> is a C++ data type that we cannot send to R. There are more details about this in the alternative solutions section at the end of the chapter.

+
#include <algorithm>
+#include <cpp11.hpp>
+#include <vector>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] double median_cpp_(const doubles& x) {
+  int n = x.size();
+
+  vector<double> y(n);
+  for (int i = 0; i < n; ++i) {
+    y[i] = x[i];
+  }
+
+  if (n % 2 == 0) {
+    partial_sort(y.begin(), y.begin() + n / 2 + 1, y.end());
+    return (y[n / 2 - 1] + y[n / 2]) / 2;
+  } else {
+    partial_sort(y.begin(), y.begin() + (n + 1) / 2, y.end());
+    return y[(n + 1) / 2 - 1];
+  }
+}
+
+
cpp_source("cpp/05_median.cpp")
+
+x <- c(1, 2, 3)
+median(x)
+#> [1] 2
+median_cpp_(x)
+#> [1] 2
+
+

Q2: %in% using unordered_set and the find() or count() methods.

+

A: We use the find() method and loop through the unordered_set until we find a match or have scanned the entire set.

+
#include <cpp11.hpp>
+#include <unordered_set>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] logicals in_cpp_(const strings& x, const strings& table) {
+  unordered_set<string> seen;
+  seen.insert(table.begin(), table.end());
+
+  int n = x.size();
+  writable::logicals out(n);
+  for (int i = 0; i < n; ++i) {
+    out[i] = seen.find(x[i]) != seen.end();
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/06_in.cpp")
+
+x <- letters[1:3]
+y <- letters[1:2]
+in_cpp_(x, y)
+#> [1]  TRUE  TRUE FALSE
+x %in% y
+#> [1]  TRUE  TRUE FALSE
+
+

Q3: unique() using an unordered_set (challenge: do it in one line!).

+

A: The insert()-method will return if an equivalent element already exists. If a new element is inserted, we will add it to the (unique) return vector of our function.

+

First we will implement the function in multiple lines, and then reduce.

+
#include <cpp11.hpp>
+#include <unordered_set>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] doubles unique_cpp_(const doubles& x) {
+  unordered_set<double> seen;
+  int n = x.size();
+
+  writable::doubles out;
+  for (int i = 0; i < n; ++i) {
+    if (seen.insert(x[i]).second) out.push_back(x[i]);
+  }
+
+  return out;
+}
+

In one line we would need to write a wrapper function in C++ to be able to export the result to R.

+
#include <cpp11.hpp>
+#include <unordered_set>
+
+using namespace cpp11;
+using namespace std;
+
+unordered_set<double> unique_short1_cpp_(const doubles& x) {
+  return unordered_set<double>(x.begin(), x.end());
+}
+
+[[cpp11::register]] doubles unique_short2_cpp_(const doubles& x) {
+  unordered_set<double> y = unique_short1_cpp_(x);
+
+  int n = y.size();
+  writable::doubles out(n);
+  copy(y.begin(), y.end(), out.begin());
+
+  return out;
+}
+
+
cpp_source("cpp/07_unique.cpp")
+cpp_source("cpp/08_unique_short.cpp")
+
+x <- c(1, 2, 2)
+unique(x)
+#> [1] 1 2
+unique_cpp_(x)
+#> [1] 1 2
+unique_short2_cpp_(x)
+#> [1] 2 1
+
+

Q4: min() using std::min(), or max() using std::max().

+

A: We will implement min() by iterating over the vector and recursively comparing each element to the current minimum value.

+

In this example, and unlike the previous min_cpp_(), we can assign x[i] from a doubles object to the left hand side that is a double variable without the need to convert data types.

+
#include <cpp11.hpp>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] double min_cpp_(const doubles& x) {
+  int n = x.size();
+  double out = x[0];
+
+  for (int i = 0; i < n; i++) {
+    out = min(out, x[i]);
+  }
+
+  return out;
+}
+
+
cpp_source("cpp/09_min.cpp")
+
+x <- c(-1, 0, 1)
+min(x)
+#> [1] -1
+min_cpp_(x)
+#> [1] -1
+
+

Q5: which.min() using min_element, or which.max() using max_element.

+

A: To implement which.min(), we will first locate the min_element and then compute the distance() to it (starting from the beginning of the vector).

+

Check the +1 in the return statement, which was included because of zero indexes as it was mentioned in the beginning of the chapter.

+
#include <algorithm>
+#include <cpp11.hpp>
+#include <iterator>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] double which_min_cpp_(const doubles& x) {
+  int out = distance(x.begin(), min_element(x.begin(), x.end())
+  );
+
+  return out + 1;
+}
+
+
cpp_source("cpp/10_which_min.cpp")
+
+x <- c(1, -1)
+which.min(x)
+#> [1] 2
+which_min_cpp_(x)
+#> [1] 2
+
+

Q6: setdiff(), union(), and intersect() for integers using sorted ranges and set_union, set_intersection and set_difference.

+

A: The structure of the three functions will be very similar.

+

We first sort both input vectors. Then we apply the respective set_union, set_intersection or set_difference function. After that, the result will be between the iterators tmp.begin() and out_end. To retrieve the result, we loop once through the range between tmp.begin() and out_end in the last part of each function.

+

The set operations in base R will discard duplicated values in the arguments. We achieve a similar behaviour by introducing a deduplication step, which omits values that match their predecessor. For the C++ implementation we rely on the properties of the set operations and the fact that the input vectors are sorted.

+

We also use variables of type vector<int>::iterator, which are used to point to elements in a vector<int>.

+
#include <algorithm>
+#include <cpp11.hpp>
+#include <unordered_set>
+#include <vector>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] integers union_cpp_(const integers& x, const integers& y) {
+  vector<int> vx(x.begin(), x.end());
+  vector<int> vy(y.begin(), y.end());
+
+  sort(vx.begin(), vx.end());
+  sort(vy.begin(), vy.end());
+
+  vector<int> tmp(vx.size() + vy.size());
+
+  vector<int>::iterator out_end =
+      set_union(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());
+
+  int prev_value = 0;
+  writable::integers out;
+
+  for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {
+    if ((it != tmp.begin()) && (prev_value == *it)) continue;
+
+    out.push_back(*it);
+
+    prev_value = *it;
+  }
+
+  return out;
+}
+
+[[cpp11::register]] integers intersect_cpp_(const integers& x,
+                                            const integers& y) {
+  vector<int> vx(x.begin(), x.end());
+  vector<int> vy(y.begin(), y.end());
+
+  sort(vx.begin(), vx.end());
+  sort(vy.begin(), vy.end());
+
+  vector<int> tmp(min(vx.size(), vy.size()));
+
+  vector<int>::iterator out_end =
+      set_intersection(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());
+
+  writable::integers out;
+
+  for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {
+    out.push_back(*it);
+  }
+
+  return out;
+}
+
+[[cpp11::register]] integers setdiff_cpp_(const integers& x,
+                                          const integers& y) {
+  vector<int> vx(x.begin(), x.end());
+  vector<int> vy(y.begin(), y.end());
+
+  sort(vx.begin(), vx.end());
+  sort(vy.begin(), vy.end());
+
+  vector<int> tmp(vx.size());
+
+  vector<int>::iterator out_end =
+      set_difference(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());
+
+  writable::integers out;
+
+  for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {
+    out.push_back(*it);
+  }
+
+  return out;
+}
+

Let’s verify, that these functions work as intended.

+
+
cpp_source("cpp/11_set_operations.cpp")
+
+# input vectors include duplicates
+x <- 1:3
+y <- 0:5
+
+union(x, y)
+#> [1] 1 2 3 0 4 5
+union_cpp_(x, y)
+#> [1] 0 1 2 3 4 5
+
+intersect(x, y)
+#> [1] 1 2 3
+intersect_cpp_(x, y)
+#> [1] 1 2 3
+
+x <- 1:3
+y <- 0:1
+
+setdiff(x, y)
+#> [1] 2 3
+setdiff_cpp_(x, y)
+#> [1] 2 3
+
+
+
+

Alternative solutions

+
+

All

+

The all_cpp_() function can be implemented at least in three more ways.

+

I can save lines by not defining n.

+
bool all_cpp_(logicals x) {
+  for (int i = 0; i < x.size(); ++i) {
+    if (x[i] == false) {
+      return false;
+    }
+  }
+  return true;
+}
+

It is also possible to directly define a logical variable i inside the loop.

+
bool all_cpp_(logicals x) {
+  for (bool i : x) {
+    if (i == false) {
+      return false;
+    }
+  }
+  return true;
+}
+

Using std::all_of() you can do the same thing in one line.

+
bool all_cpp_(logicals x) {
+  return std::all_of(x.begin(), x.end(), [](bool x) { return x; });
+}
+
+
+

Pairwise minimum

+

Unlike cumprod_cpp_(), cummin_cpp_() requires to declare additional double values, otherwise std::min() will not work.

+

It is possible to save some lines by using std::vector.

+
#include <cpp11.hpp>
+#include <vector>
+
+using namespace cpp11;
+using namespace std;
+
+[[cpp11::register]] doubles pmin_cpp_(doubles x, doubles y) {
+  int n = max(x.size(), y.size());
+
+  vector<double> x1(n);
+  vector<double> y1(n);
+  for (int i = 0; i < n; ++i) {
+    x1[i] = x[i % x.size()];
+    y1[i] = y[i % y.size()];
+  }
+
+  writable::doubles out(n);
+
+  for (int i = 0; i < n; ++i) {
+    out[i] = min(x1[i], y1[i]);
+  }
+
+  return out;
+}
+

We can subset x1 and y1 when these are of class vector<double> instead of doubles because x1[i] and y1[i] are of class double. When x1 and y1 are of class doubles, x1[i] and y1[i] are proxy objects that represent elements of x1 and y1

+

Passing proxies to std::min(), which returns a reference to its smallest argument, creates an output that is a new proxy object that cannot be assigned to out[i].

+
+
+
+

References

+ + +
+
+Vaughan, Davis, Jim Hester, and Romain François. 2023. Cpp11: A c++11 Interface for r’s c Interface. https://CRAN.R-project.org/package=cpp11. +
+
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/_redirects b/docs/_redirects new file mode 100644 index 00000000..5068753f --- /dev/null +++ b/docs/_redirects @@ -0,0 +1,3 @@ +http://advanced-r-solutions.rbind.io/* https://advanced-r-solutions.rbind.io/:splat 301! +https://advanced-r-solutions.netlify.com/* https://advanced-r-solutions.rbind.io/:splat 301! +http://advanced-r-solutions.netlify.com/* https://advanced-r-solutions.rbind.io/:splat 301! \ No newline at end of file diff --git a/docs/images/cover/advrs_cover.png b/docs/images/cover/advrs_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..04cb8bc699a4ec293b62f0968b8e9a379bb76122 GIT binary patch literal 121310 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

EUi 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ⅅBqw(yc1nwxdP| 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

D{psd0T+S77CZ#f> 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 literal 0 HcmV?d00001 diff --git a/docs/images/environments/recursive-2.png b/docs/images/environments/recursive-2.png new file mode 100755 index 0000000000000000000000000000000000000000..672cc71b090efd2f44402a068fb276ebc3772345 GIT binary patch literal 19964 zcmeIaWmMGN_csjVsDPA+poBDtNDrWZFqCvi>QEv|cOxwb(jcWncY^{$H-boahe&rL z&3%STuitO|pLM@`)_R^7f7Wt2d^zzw`|Pv#XMgrS)YR01Hm?o%mBpX_=?;E-LThAaXT{IX?&#>q=E%)v zX=BLF`S|f;b`CCfE-qHkg4Nd9!cNbL)xwtUpF#ePBmTx#-^SR=&e+m|8a=MwD@%L3 zC$zNaiT?fh=RNI=4gNEeh3%hZfd#Uo|H976#=-vY*r2N*`YFHi8(T{=d-U*X7RGi$ zT!NR4|L5cX%=S+&F-vnRn>V($pqmiSpDzFX?0>dbv@w1I)`y-(i1SbT|94o#4t>R(T+P1reUr}5_e0+Su%JS#)1HW!% zZEfxSLd(H{(~PbmJUqPoa%v1rEI0;)&=UiiB9nAK$5)RO`tP%PM`)Poz?HuZs0ocB zttcr{f);Fy%Ps64jrqvd_bN%0U0@MHd`G2QpXvmM{deb)dBO*69*IQBom(UY_3~g&~4;9>L zooVvRyuhK+SMXfmU%2hLw&(+Q7+djuIULAd`zfL$;yx7UP>&(Uh~KBOSy9gg^6~latLD>^&OwNNgqD{dEX`__zEU+ z^-(03bH`(^hoys~k*0knvn|2xk126I;SIOSPj}kGO|R;jKr|%WY(ee`>R(F5uhvYi00h>RnGryaw)F=l?&S5{I4?nzp4z8&|uHs zz&c>Pj)JSH4d%3%o*nO#^J$|{sOIM8^w@%cfB=PfetWZOM43hW;GRD&@F?&(EMU$x z=YtYv zTJ1}hU2MsfkLAs#3%AgmbdtVl(ifXipZ!~5*f7y8Mzh+Zg_F&? zi=PeNC%-of({Y)ne%%DF){BA&UNBE6BrQh0iEY%d5ck+NgHLDLbyvRl$auJ5QbAxn z?d}`57iEfX?}@@CZ~ zI(oq1_nDup6^Fj!#k4}Bhz}4iT=KU2pF;4!_7`9oy}JEk8^e0kLHd0GmPIM0?e{V&Feie!Ty%<=fc`P z)26LTlKoQUODLcV6;w7ho>RS&42JEiu1qVQhPAJMZpk(5P9Sn^@*|iA8>>w&eToJy z%D3PJ=?hINSn!_$5V9rL?Pk(Mk8|fvTv-uu?%xEDetLRcxo)x3Oe{@!r9gCj1BsmG7~_&(&Sis2R+;?~!%|;E4mDCjJ@dbX&T& zIbka&rZMs}x1mhBF{alwcx;hDjJ88>9=o>lz)c485{+5=hO49xwJTLq+h5VPxg9f#C*+4M-AlP|G43iEvLdSzsls;B5!zccVB}@^|z;Kh_*p2C|WlnO?Yd@(iDDIM%VSu(UtCH}wt! zit`D>Cg1Z$OrA(mGqfa6nbKJC$$q5o;+(?qd9g8e<4u6C9e`Rx=-Yu;__;zB$|D zOPd(2sQoHd&o3!^@4K7E{fk4OGx2QC&8~477!;3|yM{)HSk=Ozh_Ou*k|g4BAM9K1 zr?XVKVhVozBZ|SA5=jhM3qzYdNMGHv6%A!G?J9?T;pXeW#@q%rIWHi#qb0_Z-{+q5 z+)Y--o*zr@IAi`|-U%N`$0UX>h!fMGC1h~1#P9c9@)in=*cn@k8SB@pZg!Y8nvuvHimNXqWM)o|Uu+_2Bh z0`;bjgxBP*i0oqPA{7=NNnq^Ka^GES0^!pyyzsC6z5eNl)TGI=62GnN%!CJHQz}Qf zq5b%yk(%G7q`po93p4gQEt}&IxTUL#7!~SU5^~pOW#Oh+^aCZj9?DQ)y6b!p7w2aY zLe0hLP;uqq?^GUndP?Raj3NfFdMbT9cyvxSsy3H;Q&Fpa{ByO(D=fFDQDQ2%?6rrl zn0fIUGw^=^tCggLKKrQGKQ!{NtAStS->~V5d+d&bOv;#LM|JfI3oa4_DavB+ZA_j7 zuoOI6%`1lO<$X3MBSPu-@GEI6+vjQ&mY&7h%Z@vzrbHr&^RO_y-qC}@(E5r&Wt)MT zhr|8!@Mw4O$0trPQF(H>>n7?)`g&DbU&&lVyapc)_N>SH zki)^KA=+mnGctAwl;diV89a!QlU3b|V_;Hx6trAnuT{X%XA;!n*Ufb?W{2Cu9OHKfSJ(j6xBep=_@ccXn*dk7(5L z2d`m9=u|nZr^o0Z?WzS{c2wg78y}5PV;as%hU*QFfDWW)j6Op)r8RT{1NzpmowaNr z;U+?{eu_e#sH6AF?YNL!oP=`5re&>X@z6rG8x8t&*MMa>214p(r+esA{~NmJRv7%a zq}ZF+`*6xJ!Zg;rv{&e+m@lqKmboZV{)K&zSC?RGfIPqSS{qAY^>z#Sb=*5)QCR*^ za9+5;d5M(0K2E*$1XD3tkWeM`^t=ISkX`;?EDP z-^A8yTGpid`;G>yNd{=!0{@`x7|;8p%cA4kH6V}x4B>BdY7}>_cu^5<`5+CLCjpvs z&(Gj)T z;ROxo^DZa}%h#`0y`<#wTI)jWlI!Z~Uib;0is+|G zQds+3Fr$q^EwFF%F4(U;L~i!%F=C@ag^pVjSroI@%ck8|6l~8XHx(%psi82lv&I|j zP=A_uM;^O^D+Dm!9PRLaY{ffZKSR-$KI;nyDh%7mN<}R3e9|Jya6L660{a?1MQgcX z!VpHhA%JqeRzbrs$^Ea!vQt(c>28Cb6u@>{J&M4ABI&~rS<89dBHq`&K9P(#q`iRO zYEJ;?gQK$=Xm;Aj(_pgO1}SM*F|i&ocxu@O#I(|c1;BBVOPfhFjY5zPhVZO(+D`=C zIxg#|!rJ2puVpU|%IXFO2I3sXjA=4uZNO&Jfz6hD=}!X5#!4eGS$QV#)AI_UNjBC( zcd_HNn`3T%X&()g|M7zonrAZ=o3$rtBV9r#Yo{Xb(}A2KfYQpR%wR&b2zzoA^H;Ts zUi%B%P`0rp^Ez$4^g&W7oFAY5BCX>9A;bcJg6ZRe`;29dcN3u(^4-IxR{i21YiFr0 z4*hgakGee)&RNiSIYk5#F;nS6F?*upIPO*6I$*@HDs^z(3k%UWc`jg??%%@P&Fno>-*#8MmRB_E|r?Qn-~C%+8tH@9=b zo}nW1v65a_8a#mmFtO!yEv0~iondYCdCgv*EI@aAZBZ;|*-Nh>*gWP=?G!x16t2JI zJbn4P(y8b-Y09=l4t-nX|f*TR3Ig{iLw`R{&7xs~sTpZX;Ecf1>sE)%ziXw=s2B3oR+Z6AJXxIe zoOPrrLX5+pg71izqYW?AT1zq*0N( zr*>UVFo!&c=GcT&2w9%f+=!e2)L@MKXRhYL!M)0qN)VxUJ(|TWLC*MIf%szJ6^eM# zQ9zc)tFdDE5?{L+)blI`dWmSy5vVml||>yW-xbY!S}rBiBmC-?0RfVQfW2K;gLitt+l z?t7_JlUBqJr?gc<@|#oCTS3tg@Vv100Ylb<@FXpglFCR zn0rd|xc$CAjhjUavR|$}5rAFG(Oh?E`GK8Q1j$1aJDkUuBm9fb1aOD>P0 zOdIBqLGXG?OfnruGyjToC=tS`rr_H2#y4YQpBcZ<_geje)?(^(T6?*7$sU8{=g;L)GIO=HK(gT=`*xMFZFj-IEvKQh|tO(D^MwjI=HJF?%mu&9VJTfC- ze34|yB?fi%^I+7Y>h#KFvXnRzXD;@E`jRaj zv%YINSugw_`$*yF7Ay-YH9b4YMK2%C6Q4p=#Z(o8>a;zAn9z|B59W!tSW_(Wwqg@~ zSRJdYS34?QHfGGbf9!?^i%V19-Lxpjf4Yq327JTHa+q>hTfU!fa3(wgkRjur#u@i#5?LV5V~wOmTAIZM!3Ke`ILXE1!Q|Hg zRq(|$&?J0Cd1XuRJqA<|9Gd~3rCY7vNovF9$Euxo?S7_eSXSREPu2DN!a)nQ)2Uhs zG7K{51vD1jt2+j8>R&)ybUN@)Opv3I%L%HTzGlbNyxr%Tu5Gz>9g3t)8cX5VPhdlo zw3b@~j)fVkXDh?ADfI*4KeHf1NO*ag&R2NAD~G-F)HYnJjQn-`9>~xf_%)vsid=() z)4tSDsOo##CN=&^G}?4^D4+WU>PCyxFHblQ#3BCcs&asa6JWbWs7Ox4pmzaO^VEL4 zEsY$Qao;LU`kxNF_U}Zf6aI8y!n2`#@lS`>cxCuGXKTpumc)6IC{@*-OD<<%?_(>7}c_NhvSQa<+ z7x>PAzuEk7p>34e>uV-jn{0baP8}U`$090vn@TP zFk71-9J}@z`<|h^e6Vy`US3BzAUyf>8htk9-r?8*c zh0MG--@Mr9N%jtrE}#1-%WuCDNtls6p7-r&IWsY5o=dv*-jDAn)8Q$*etGn)z}$Dx zbz1{}mlJ%ln|L8;x76b!IRU~p!q%XA0Qk5pCLVd*$R0@>ao^9?jkh0q!5aLcZLRiX zLq)~lfV)gzNxuppkc-nr;frNO4}@yu(4(jubj5u^<3P?V);oh?aGpbRMASnku5V$S zm^^n$b)04ZwHi?>&WK=6Bey6Qky!#!BwvF3W36w-eIH+`T#N$bDp{w#+qfh-4v_qS zCoc^4sqB&(ZS|~2@|Y@^R3lAjK*ZyM4s31Om>moii?LaCs-3`^o-D@Mel+3Pv`=^1 zs93z`^wY~^Pg!!QQHm5mqepmmYsqi}Iw)FE9p&%$hFXHj2iqp>hqcf5KmzbgEC6tn zM-A7hPQTq!JZvJTBDF@g^5}59ZVh{XgOn^WgW_VF>cSdeFy4J)540L}5`{qo7Cz|@ zm=2n?`cb(*#|xR0DyF&pv*!1d=>chxzac?!AsG+82tZtzqtfGBqIpwb7%}kMR8r~w|U%e|#@21+G zryyyhDI(;ot+%Hy&VTo&N{$N=!O7HAZ8<>v;IdKi-6gGb7GyFsx{IG|PrJ;~D(Ht& z=z5%?&U4&Uiys;FQ143Fy6>B+J=FoY2SkTe+jRh<^XQkQ`Mfm>`w0lV8 z7y8!+lQLUqVLLya?>UU<*%)Q_19Fznu#2K%(Cf9|?^t1JiSyq2? z?yB6964m&lQuSh1rQNi_YbGCqG7n`M@70FkoJVc$C4?dB8e zi}W}dpYC7`!w)O99eWAXqho;&I<$n$>+@z#fl6 zd$b~Bbl(0LGFf;Qdhdyj^L*5#<0RCn7fG}&qTJ!AaSk`-?&+E zwo0an7{hKG;EyzBqnqA`vmvcXt;Z+?`E>Ez8CiEk3Q$-YPF_4BoeFa8&FkZ77CdZ7 zVZD29BTk<+(Wm@7d)aY!0kDVAZXZp&C==Qb+vw;arwh11(-t;GU!gD+5k!%T}<$$FN$_HyiF=S1a)esK#5poxp>n&xjTVr_!%a5lQ9 zUA=X{YJuLXY;3{9pWcj~3w0*_c(&t_vpKm1CM)5K7k~%yzN#pj8m7fApW@y|^V|?vk&MAqUA!c$;IL>0qRuNBOgpZyHtx>_9lV zU+GQG4PyLk#rW?pA=JaTIA|KU7;2Xh=zxSZfd8yBt&DJxHF5n^$~Q)WGecf}U5vit zQJ3m*abB8Q*aPRm52i9Wdd+;iRJ+c-hIC3ZXtqN8 z+j5yn-Pyse%dy*DyM1Q7gRKWUC9 zvxb$dhHWoTR{aJXtEGjCz?%AR;QtRGRUH2;T$l~GCppB5x0WgMSB^#|*nR0?2A(&5 zZ}a6`^c;IDKJ;6Ptxy#@I0?KKtunaYbZMHr;G%&vH=_xYvNhk!DKRmoIsE#<*Bj6E zMrOL!t+RiRl0~Cn@4u#~YWOXTa$5_-#$A8OX~%tstXY(g%Bj12kDTuPa7YNF?3mqNS8l5$Hr_`P zTbK;>P}OCQ(MNi5=v2z#k3Dc#a^*SvTrzOIVo3Rwp3gKegX^#D9$6r5kAf9S@zK2E&h!|iKcu|TU($KWuXaFM;;`@>B+dVzPwFl+leTF&)~ z)FLRUf}};em~x_v zFyE~C&0CnsKD;-pf`_c=pm;?3w9=>rs00VubzQt`5-s?1h?XUa+ANh7vvm9JC%;wI z)OcbOd_~MFGI}wqhTG74v1Zr2cgPg-JJ4kNRWcjn^5Y`|prh>G88)ti_$T4*3iIq}p>7?_ zaN)BC8VGSRp$QT(c>l zsX_KPu4aC)p2v%E`iV&?2BPGpqk3}=|9CWiW&TEXy;TYJPy81k`^^s!%MH0yi54P)kVh-$kwqFfA-H=Hpfqh{jZlDs5gwakG_T@{}Is-1I#Q6zdu8s z+oi(g|j1Ty~>>~0)Qmy3@mK|s(hN@0`MSEk6bd9<@UBV89cQm$DD`5p~C>o z$8M43*6a^y1_lNO6Z}C8k3jm>ar6!8t>;bg$2?BWw>1Q}zulU`QCjxCIGetpAtq&n8Wr&?N+oM_cpp<0We`jy5BF2ygbBYeqf9O z#8OE3LQM*lAD{+zCl0=@CUgUj3>$h3P~pIK?qFYt)Ikxee9-PfOLm!@^oWb*+h^I@ zg9HmYHE)mf|C%{oyjn6dvdz78P{R}s%ph|gi|Kec4&Q0?E; zF&6OPs0(%1G09#A`KT3-G(EgJ^$3{=Jmui?t%T6Oa+CYV&7b}><(Yl%)Jy60*joYKG!Iw&}7hZC}xGi2dttPjy#DCy-+{mlFkLN9O%{ZYpn$jrinaX{brf7^$ zxGyn}uvouDzklbASz3jNI`q`yL}KSGB>Rv;AejE>dVGalZmD|pDbNvqH; zcqTZ=q@qER&+q_^$mDPK6pFa;xT!QC<_aC;#6DLd_S6IF{~D2|Mh&rmmGI-6-pScV zTf~2;1Wc?sP*B18{VIItFPDI($mS3xLTIY#4_ELQRMfUxV}^n3#2>Oi3a|;$NCL(G zkR>62aIn$BpeOjlp8R)(%b(iaFntK1ZA$6_lXF#Kg8;GBNAq&{ZWUYlE}I@Tq2@nS zQZotG-B3o%Dx0w=UgS_)j_4Gl#v<3<4UpUAu%LKB-vh$)y3=`f#>Ro~QOK9hGhbGN zv}1M}oq~KWc{ji=MY6a^@i9SDE(R|tsRgJ8zduQl7O3B<5!q@c)xE8Y)$8mJnh?6=5_ zF2zlnNoN#KgbS5!ffrKM4-wpvQn5^MKQ?xmDF8^s3;GWm*cZXQ5VFEK=*pjKJ1G}?f{O=r!lKZ`(akVUV_0r<>B^XJl_tp z7P8Jip#vs3640OhP>C-b*mL$bbPsLh)n~6EoD)D!SB^*G&4&({NTZZmQbqcR7nCAg1t#WtDo?NuXm}x z+GpWsF^(YQ_r*b1#!|V~N6;cspcgE6{OPg0-Wj92s*dnC?Vq1)meqOl?4STTK3()U zXR3069&yZVRy}Zxs$KDXa&5(}VXoP~?nw4t`>YrkLFf%7Dvsp&4Jx{d3}gvFB=Shu zj}85P=!ow5P7LtMt4##L9iOj1JNZ&kEcquDvyQr&Lk^0t20SsZOfblI5Pl#Bi!YCI z>e|%|V|A^bL#~98g@BlNYXRkX= z_PbY9T-c<1UbX#zoqc$?!qI+ns>XhG2sp4K3Ak{vdfxNx=8RlsR<`{N_v2C6J*@u9m#qSQjHt`zggoDa28JjTmw#oa?) z@cv9i#VpwI(~GQanXScAYHTBREj4c+{NZ;U%%9)EEwFw1w?Kw<0aTN@SlG&}^wKDC zu)3~Y6IpF3{2^hDjh2ASD*ebxO_{gT>Vniu$?|&f?%BV4Q zkRQ}zu8d~W&dH~+>x_FGL1||$bajD^jqM)Hs3$y_)Ub^7`OL?7L0X_SlJBD=Gf1p% zgle5QJ{jOEGe}xhmOKXZKT0JqqbOgqOo5vQ21}5Px~*~x%V%1;oU# zuE%H}b_$5eQvX@RZU0c~$NJJ%xCjCw^!jqs)qeEWe0+%c@a1xC-%neAB8$ z?pq+y?!--aL503-$3M#r@WlT>F6>_ID-^@384a5dxlT!+>;MXW7~KMxpufaG1wvvG zVVtB1nG&#&5FO!jem*5T|$Kc z@?Cir%WbI8=eh|hLzRukB!k!UB6b?MOF`SOtZ%tM(GZ+k5Mo((R;oG{p(q53@|G1* zAPKF~Pd@-VUcRj2^VCYk2Y>=>C<`Q4J-<&z5gYY;+C$iw3~>HOpE&guKw1|dP6j+r zCMY#EDCEe&yhH}C6YKYu`_uapoEPqzJH^5dKm`e!6Q_F`bf1+~o(uyN*4BdxnY+Z7 zhzU-8--|&uS`bu9t~@&dY-dDEdPJ&%;I??M3$Qf>(pP?BV`3cwU~ww9<%LEgUePxX zK?KDlkKAje3#|qv0rE8!K-px|LB(Q@+sT3a`vxjtw`Bl2A-;jm%mSAth>2&ng5{81 zg68GQ#?#oBO764L^{ka#!GA<;j3G#aCitj_krLtAvXuGF9t zNhLULmwF4Uq(fyk0Z@R%lg6=GTf$H-P_5QZNKuH^nh)e&z!_x2@ZN$dm15~`-QS*j ztHX*+F83TKte?0X1d-G3+`yCs+YnMu#0tgvTn|bqNZEDrq~|N`;Dp{<@3ltq5z^_) zFh#}m<&mrmuBt(G&E@+L`%L2yK*MZ-np7@2FkcY4r3f_%6vn*_w(kfOnhL%#pa7+G zyhp?CcrC%HVOU0N$Y;jrx@(mes{`5nfGEh{C;`R9Hc%Ip$SprO9OQjGF`OwO@8Lsr2LW;K7JN}A=oAWK?WY63#+#pZy=t$T;1^rij0cF zqY~0`Gd^Z(swxdCb@3F_(WTqWd42a60hRw7RPi{?wT2^8qiN|w!Eq!75@yRH zVuFe?BsohM9QMg^MX1Y8N`Ab3>&5G^+d(suMK2rPad!*uqS;xMaVsar>{ZoRYpHZf z>u)zf#oLQRhmW*q)*a}+9JE!sLd3H%%YV0&=@YaT?&t_8@dJ7X%}?Mr~}0pgV@hH zpQg_!j60??*y-;nb$kw|h&; z-epv8my&fs?Uq8-=s;pw6TZOfP77KY>6aiPUg6!{`+N?Pk%goFMmny*M-BCLiIEr9 z@#--5&(MJ3o`K;$kl-4KP-A(iC_HXnHHfggL8KVqxQvj+WICi{or@IOEqH9ZPz{Vm zhJM~CATm|bXQfLpuUsQ0C3PvZ5>+i;0)?opK&K^2jW}>2URdZ0523>6hoE-2C4@5e z*Yk~_e!zVbpy91H89U|jB=B!RslOyxv79c>e)Ih(-aNkmXaV6Pkqa$(1&=9J9|cA` zSlsj(J=7NiN-GN#WHhCL1M9U{y);ui3}nwhvS|xk-)I-LQzuR+<+!J5_Vs^B;e3A|+wZg_M$l^XXO08V=h(4S@JGwITn5)u-O&oKpt3ba|?WXLkf zNrhz#D|^_d3+EX(^*%LP;qCvK!4`iVog;{h?C~7;u@XxP!`?DxpX+0=B;YpCT7F@<_{r~yVo-3lR7`?N&jH2p2PPp*CZZZneH$}4COcFezdx`~Fh2i`AJD^K%@|cW=`fzYORERG%p>5Vnv)}c=pSGY z@RcA`bW3sy%5!S%<;6@Hl!hvkQ?in6t+g{#j#D-TY2O;#4v67D7B3#9pXB0wR=C<> zxoN-7`PFIrm13o{2Y{_vHT&Ejv|?3^cEe%6slrPmzA=M}(%RE=mImFX!jJx3Y941X zr>Ka}OkHV%Twkiw3++~iI%8)t>-r3jbFU;lr|MA-^6`Vaf(nISDnoOy8&LHD5)UQq zgXNaKH{`OWnhd0Gn)As@@8?fe+RZA=55~s8Y-RLG%uJk#K{j$Y;2Bm8LnSpaC5O-XYw{f4b)L(!BME3cJ5H3`NP4w z&#U7OECrN322C5c$z>vB1^jsV$oIDajsg6dDc>XjnB}AO4jA%In*-Sq>$8rgBuKVq zOX0p0DLm@8eVwthZze##xuUXst=@S~ohk7evgV;|oO4k}gb{*+Ji`9Av#QP~GDV2# zNGoChrvqTI*K*#wUtKUeST)U-ijT0<0}Y{LcDc0=N2P`+BP z!!ASCCFU=`!sex)XhTqDj3$d+H)mcv8$5m7?as{oxMSL&*;KRxT_Z3puq1W6pb7svS7 z*zv_hx(h}EQ z+Vi1f=O>@m&6+6$?{&JO_p`>L6c7cOAsn+)sDa*$BUK`q8m-DcTt!ehPpu9$S<&o% zKE05i!@GYMHAPMyFjZi}U6u2yI{?pnJbxHc^r5HywJQ^ChW<4u#myd!C0WyP`4_`N zfrw6Swa)J)Z3o?j=7sOmZ&rsqUbquaDFnO)aj7|)T#JgL#X!4$ths>tk1KsH>JHAS zIpzk4&QFs)Is0pP<{L+)?Tss3v!6Au+pw0MN%7@t|kQ#jb$u@L~uk;X%r zl08zAI0_1VIjnzu%V=TH4)S?gK=hIj_)bgcK#GFq@WD0@CCh3tqZur8KAVR!GtWHp zvDM?cqUhYXMd%gku-g!oVO0O#`#kX|+K&=E^DFwYH>t})Lxhfv?2CcHHFoE=5g=MA z11JFiO>%OCyjK5AXHIE87a4{;o>iAGZ)o907U$4FgO;#FK?S4S>5=%);C=JGAGqIt zIS=0Eejp~p;!TkqYkqpTjlTC(n({?A)3GzdiyS!S$C$<_NexGY*6fzy0TX%qJ)Oy~ z{FwoG716s$U(9DTU(ED>+3#PCM-Qzbp3UArC+_X5iiY5a{t|_MFX_f{yfeU|iZ2sBM8ax68!bD3kmNuM;@LQ{x)LgO=ZL3$kOIyXiT=vj4m^ZAmy%7k6g z({Dj`atr`Qq3>SyJpWcjPO(uGtuVA;d4HO41DAIW!9OqhNtAIb`vlLWui>|G@UEM8 zAE!45T7-!mjeICH1 zu%_=}P`1g3R*-y`kxBrleh*t!+?beFP9M}5Y7mK%PxLZGQ-n89LGplSy$w`NE{|hFF=;12Rw6F(=VZMEs+{H&LKk+bAJrXu!iST;1 z`N4c!;d^6WOr7nCmtWpOuk!v)qshua_1-%~y{$nlhN4wrrpd{S$sdS}GzNMyAAYAa ztC8h%co6b!v-txFkpcRAjEKMdZiMUaV|LBPT;*ujBM5tKy!1g?MRx^eMW;|UnkSM< ztPgp^(_C?nsP|Jx*9>|i`U+`$9zKWE$e5P3YhRD$KPY1j{AT0#j`bxMDA^xRDh7 zb=FdvQr+177Rrz-6(snE%KrRbYz+G+Wq2pEO!rOfc=a78vWD^3K-px9M3SlWh z#Msevc3!2V@kkYtZg`Ehp3)R@WnA4{g=_`st;0Zmy{z5qX^=fMKYC!p%JHedXLzp z)ynweTinAr$pTb$$kx*tqMpSIpRU~T%8TX<^LvVGB^g&@9f>WpX$=7xV+uKYkaH4k zX%!zpd4d0C(4`EUMaYbAK z2+|R1H?U(JKV-*JU?1Z{TDD5-Ze~k+piVExi8$L?klaVzO*_B&nwR>fp+phT6m`Y`yNuoeLBX^kTXddjF zniSOT&IHZ+a4u7xBrn2iQ)oS29dA|XMdR2z(Hw@ktAJm@z+^6s;4gHr>+oF2mBwFC z&-J&KhCb4VKvQJl*Y5=_S08&Li-w2G&Wd;=x&wWXU7z|yb{;~4Ejab>g0ry*g+0hY z9c-!&%4rU}>*ubWJ{)?calI^eqRQN2h=iV4icwb>`x&_L+sK%NC*;6Z*jvZW8(m$O ztkq|(?Pgv4!eY46{rk>}HcL*~1AC$Dlo$F~K(=sdeCUCZN{!oSi^hX-)+{!HPt!tg z27xX(gmg^YoEC3MB&FlU$CLN-N!4S}@j~-cO0p;uA63Jr zmd}){RGjzO=6TlX`cn<)#0o}X=&v%kq|B74p(VRVI_A7fx&YeGqZpWd#otB_nH*?F zvj4f|hh8~ojU@w@-Qfv-RA@+494^@-Q-5+f0Q#@>%$RdXm1=P`<@nFI??6y}m7(?j zlO|qf2__u23mqWdnaHj{ztjg$AyX?)I3WZ!EV8uC2JNFqeno|^C#ot6O^(OjmU_mR#oj;wtoB+$!oLl{a^>PHTP0oNk zk9L&sZTLItw?IJG>&(kv=HSu$*eU=u$-eFyjN zsMYA`S8ZzU?~1*u(R64PZPUxYqy7S4!$DHG!&vtB<^O*zlC6u)pGD#lwQey0~?+PO%*|Tdwk!@rTVeDIseX_J5jBRXL zhRQmYL6(VOy!WK%cYgoDd(L~_`<%|VG~aug# z$WbK-HK$*J$MMH%rXCQ;Q&;LA8bxuwqt zu;U|V58Hc>?S)<49ny$$7akXdfX$3k3 z3X+O1mn{qxPdX1?Gq?qBf-xGDlEbDW+!Knc2?5RUasF(|$ui?3EX+PMD(Bs9{-g3D ztW-!%1C1r^Q67AVF&pb~K&D`!f%2S8911Ts_TR#^K0U{#^h%!rTm1jy|GEUY;KK{F z)Lm#s85SE=gCQh}K0;KO!e4>;zqb%}F<4Cr@HII5>g~679(; zqfPY|W%dsrE`Ll+Omvxb-|11#dhCOww}K(kc}lC3l}x@sF58Yq$~xwNoUjCrAf40lpjV;^28(enf9`8BzkZfwvJvDuTv z*_|Oz9#2nCPs@L20fB_DK0kU4%r5%;&wf~032)x`kZgI~-e~L=qGFgB83S`n1QFGR zr;%@<9pOB)Y?kfXVH-PpNHdP)JjY_pf!1ATq26>s7}@Sp`)aXIhPYOen#?%9H_`Je zG=@zA-38t9_VEes#RmL32gHMYC=?}3Jx|L_Jto)DZ?48=yr=x}z?C;}zXnu(ZEfvA znSnsMIX`od?sJa{`~bAu)$?E3!kuH{KEcmWD%A=;l@o#5^1YlFF5Iwr^5l0qF{lhR zDj`!dgtxv-;Bic)6d4FK=IZkAy}#o?2NqP*%Q-<^P*i$Jm1+9evo3KO9nC&I$RUEge;A1b4MK5g_I99c5! z01VECba*QRCa$il(_OQ_%AxW;47l{`GBSSl;77LkTqCa&pdDFGP2-$iKZyQXbYJj7 zaO4KmvZ#|R?_@u^u&^KjM_#(FvIF*(ckUt=c(jOvS1Rf)h~Y>M=}^ba*sj^KOV;nB zkH5@*Q0~Z}Hg?U*xx(Z%5=w~QRM6Tl>%Icr&n_=tMP2OyN9^1DyC+>Fv|WAo=|!~l zy{weLm^7}l@%E!u{md6Qx2lal47WzIluM$~Y$l&R33fHXD62=n(ywig%YcVyH_EZ0 z853-Zd*+k@L$gin3&3lWM|t6;$WxvqK6M#G+*89#BN<(@O{3%Evt(GE5Mroh_L!i+U!xYy!jC-xIUm47%4&6rj@8Je4$kNZ#T zr!yR|H^uhO$2P)B8tUM?3$#5%kMo$Uwv~H3*NluFSvSV{OLI ztRQPBF?1I=iUF)J!^!4K3*qLH{CtN8XLe+;%LB-{e_ptXp+En;(G;9b)ldX&;yYkX zkby62Yik(h;l1B;eSLk-ykmQ@sM)ThDFfl8Odf&=&5!V?*RM<7J}7I1f2H;GX+{V* z6-xP(|2FG>Xx3!pQ_CMQ`R@fvxL}vnjg+}?=sAYan=t=URP2u927Z5{V+O2|eEhE- zD+LE1+(Rl)_I+r@_VAyNw2ki`9T@QNueS)wLPcow-~(q>SS-a|E2SM8Vvj5gR9}6c zQ|&w=9P6nT`ktOe(B$!e!Jxh~&@&wmQmorOCWPsBHrT9dk;>$aXpuOBlP6b&&qwa{ zFhL;OPJ8XA!TCfP-*nBMLyifwri}hFi*6(k2s@1^Wu=8r;T(Pi#YVmkMX^WK>Mb(1 z8DsnV`yOg759T`&EM%Qq`A(<6Zm2Hm8^`+9c&5C-4~9;DAo?|&;UtasZhid31kF zUg@lPqu-V?{J`vL4_?uH)eQU4Md@3YajBW1n{me^|BTV?MEikCaJlPoE(v!6<)8G* zlQg@IED(bptG!Lx&+W;bxS;#_W@BR`d9eNzu$Vj*IuJP_5AFk3I$E?hwW1&?xn1oy zA_g8>aMRHDfn#H1CLcbW;I6%#&7TUc5?t=W1Gvz+Ph~>qBNLjEQtu|(Z_rK?iyYVy zlFTOUL0cu@^4_KN9||EkMP7t!In1L+dcMYQ1UE1MLxudSMWlQJYvAiJaG5;iZ)i$~t_OVo`b5)=}s*7dF;!~ALs zHc0GT=xcHXD*oCRxn>-9>;3CyRS){tv)~}mgn59|_w@aKb>Y&bw_dA_B!#O`$%yQV z0EOVdg;D3>5^1@lF2h|Y#TD_1))RiNxop69Fe$~wofP4w$IK2T%=r!dAkv3!-UrU3 zy533xEGsViCCw^A(Jx^VV&>&EnW* zGjsFcw|Rt#i;ZEHV|8xR;mS*Kn?Id;dS=~$MDtwqZTMh*)I}LybyY6+$&9SOj1}7+ zcWovwnbJcbO0XOnDpC?Jv=H|3w0WSWpUvCW))vHi8j+Keqf^E_I5xKH2d_Pvr(l7j zr?V{v0fBT0evR&P`Gt!YcOOg4uL_;$15O*&nbSmRy7xIuQCmfROH@W?*B?Hs?uOWY zE0g5zq=fATmU+$@`19n#Lzkk}iB-PH#pLqs{f}NR5rl<~POmkOya~{|Ym!QdLgw2f z{)irfmb8v(hcXj1qFevg{o)G0t;JBUBeX3l!DJlLUw0j5RPj;4WjyI35vy}kXJ zXT_ZR;h3;e5{eoRdG^bIjw=Q~ek^Jna}g&le>;Iq%bj#>DUK5WhlY2DXTR#h?A<^DHHCg32z`CVIB)TRtSH9jS|Fzop|F8o|Kd?HNb_}r{ zUdV69Csq85Z8zqW{KE$i7U))1Rz!4XXBXW`?X@*E8GHoGtoc=Vp}`_@vohAir};ey zTQW~CMH*y%{7IBDFbkOkQ6EI!XbJRl?6Q)NwH*SD4~$H4@g|K=>?cyqNa~t#SwO*< zj5Bvv<+Om%T$%Wy^W(>lhufmqV%$jWcl4@saZjme!Ub7VPqsvOJ15!)1DEN$aI8Aj zokRmGz9H6)pOO_7U2E;>>2aySAZJ;#RM!(50@Gsv+< zug+UvYwRc$xX9Id-%SvXgh4H@Ia=jDf%!WZ8tmT9(yfyeZ!aq`MbGiW$eG}52eY3- zPfSV2$pNdFC;Go09V&f!zv4o5ZLMN2*6If_U&E~OmON(98a6Od@1cr>?&PLe0yx3~ zfOg))+h$)GPx}OaD<~J&V!~D~Yr@F2QEXC_Vw5Q&&vL(hf7)Lp;xZ4s@*_6rjs0j6 zqBmo|)J*c?HcFR&!bBh;$PUq4a@y}3@X}^JiXMC0gQ(5zZQ>Qe8918ulOj9t!5wo{ z_}_EkDHV{2XMOzm(G)pn905bWdTpD^3}a(B=6_ovr|8$tUN@1_*0OdUW}cbn=)ABa z%LZISLf5Q9en?m(iawj)&nuVhA|~G6)X+9-xWp8u2uCJ>kW>%H*%N~jy&nYqlgvY4 z_Bqh4w`k&lBfH|EzTR62#v(Q&9dtfZfu!z(-->~OfqV(-xjGo~3c@=JHNd<*M^O}X zBN?ZRCIOTz^+r8+gG?r~=%BWpX5H(h_#Xy$JLALyn=#?9OU6o{K7Be0yzvGyn(

>{1)^vFhLyg3(p0nBJs3r55R+(m%rWG4X=&-u2gh>dtUeLK($gR9_2ls) z>0s3~NtfLaOy-3P88Oqp6JO0S)Srv9AC+)St;uuTP2`WD2oR=;R_jM~)%@Tf3Gqcj zjiK;gFD|~V*T}u=7?&b{U*|e8$fd#rySuv^t%;l&H%+v3L6j$mV~+A%vO&0tBz4vD z!haFXRwG7DeSAn>NCnml6k=0TQ*XYbjL+rzT{4-o-etUoQ^U_q?L$iA&N8}p@&4rh$9tNuB-X&D6^WeCL zXE%044AN{>X&7T&fGW-qN9xH(klQJmP4YJkab9rb2aJi}@Se{{{s`qq4SNb&0|3W( zKS#}vG=#Z%@C4d`8y!hf&z)X+a|bVw5zgvtIXa(kJ+WCQV?3Tc=W5O zL%Nrawe^%KaDo~Mt}RverZtZqKVEwSutTig?f*b0)`d1GFDw)HY-E}oS&p;y?>dJ^tBtE*q{t(hxATBkfrgLq^gEln*AslWNOivU~3$30*pYno6|-qddx!JASdx7f?R3?TaucY zqvQJRJ$F?-Rk5bs4l#f-v56ll9Fa}GXxY^R!tT>7Ln$R_AqGPhgFDlH&a8AC$dh`J zVJVzMhRTa^ZF0l>4H*;F6ybMsrS|fRxZmf@M@2>LFX(6P4sxg(8D6m)Ov%!Dh75K3EFPQs;klGi6=xUOK|NBE@o+SgWE})sLkt6OGl)t`QO#4p=*}%j`P= zO=uIrqh5T#iESVK3kB^EM9k{fwYA4;5Bjp_@j$sp98;S{@V({C&WK)3BuXE*n|@$gVe&9; z(-giz+f!c(u!mN`cgwT~bYFNZc?prWwzg9;^KU(f513UT};AfKgBY0&d7aze{fM{oBS3hhl-mkb(gJ}VNjt;m(o%lg+f;|#p zn6ebCo{Mv32>rywXX31K&8Xx;;^r&xDIF#zCcZI+&Z0c*!+ii1PXMgK&8Q3vvGM$0 zCz4|Nl?{Ul%&E(GgjuPn07xUkjcB!!Ho$}inCHZK5vx5~m_H)d1ctHM-`$$Ju~dR4 zj;^nYm{!iP6De;(JZ*`TMQXy6`uL+Pz>8RyiMsXV<8r%(Fn`yDV`b~S->Q*R#LH>& z;mP{7?&T{C<6gg*M05tKMElc3^q93!{b)Fje!eF?P1v%*Q{yWgl{w-GRKXcjy`ZUZ z($p2g!%!WmuPLLgj;S0h?dy$a3w&cH@Hp{(DR}zl&!6+1$)}L19wfBnqlqVeg$5VD zRtkcos=krK7kHgK**iAWw4(c}-9JXRE^9ggQ?t?f!bhUjMj$I3DJQEn zV6C=m?b4inH)*c@RATa|tVjKX7I4L`0Vi3(cDCJrx8*oacH3lvv-GHCD$ux38US6K* zJVWS6%BcCd;SwY&5Fe-<`Kj0>#42$!F+gFee`v^Se=z3lsv-m z>aSDd;}{(zG&9Mw9u=E*r&>}K=S!r7L*W_YA$wq(T9JRqy}q}+4LbLV3@q-X+ncuX z@MZyRoQDQ-a}8oks+@+3YNS2p0>0omIoGh3v+ll*6((=7&sHqYof%{PJqoZ-W+1VC ze$upS56RrV9<1T#d@klK*uamW8LCdf{q8CiXe@TlZ*UgR?VSds2C=55W&pY`xfb^o z-<$Su66~iBhjXt+8S8vsCqwsJ@QNaYc!c-Ul+vV4Mi=Wx)+?mx9H?a~v}1`+7cf~Z zum8u!$!aZUHvMA0jmAebYb2ZY-4pxOK$f>8 z_}4S*{3B6}$Zc_>MFh;h|8~1lD9BVfHIOsMkur3jJdl%Igo(b5)rO_ARsb`C6Frl+ zMSpc+CjsnITBsjdTwb2|0AN20$doOvIR>>{5z$7@yaXxM#_eBG2Pu>h~78)3+B+k%W&kCjhz6Ub6!Blv1$_J+vmZpgp6HH zP@hj59l!R%_foqw>;$`;!C8>wIk~!)-=NjNje}RT+SLKr((hg-7xlY%!!TUY)3rlC zOYrq;pH9qU(`8AbFj>K_%FozkQ5Vv0B)z^XWBGkyX{7_qTbRTV4?=`#jHzJvH(2}OyA%r{b;IH zZXn>5Jj!zGK7PNodQ4Sp=#LXgLFF4pNT3y4-2!e)%(FzcCIUBD%)`$4`|B!pnaAzY z)LpF%OCZql>u6v*be}Bmsse5TXSV?|OiknE!+c$TA?=sG!cph(8W(Pj)>)!qFi!pp zaJs;IHNZL0(ts=Xb9D?-yQ`4dd>g05U4b|+rciP3m44Iu9Hu`CvZBY>ezKVD?anTbe9HNt>_!XlO(IEs%mXizU~Ru10j*;s$IUi13-jsTLn~BWb`j9qMK+> z3jHFHO>-Y{)AcomEWcH9C3<=Y*7n#MTukiOH<=`T zV`7l6%|slx8(r{buB_nmduD;1inITvr#dSIAN*q^oOHtXR?YDF z(0{6HYKE(6F2ez05JI|Vts}OZ#I@#!D^P^*BHT9-HK-o1K|??-#G)du6imo(dMSuN zzv3gG&TEbR4vNz`@`9MwHJi6`-yisbSJ{VjKo*epyLD;P#Oe`DVtT#5TF);Ed6hE& zW_vlJ^*-Pv6@(mv&c(?0;14j`JX$BRY9q0No}+=V6TYQrs*M>kh@oRGx!G8REiQ=r z6&rQV{tBV>ewu8$R_O!QNqKe{3SNMFx4zqI&V{IX!qB; zk8=Esl??r&q9>l~Ix})B(f($+L|3JJ({Nl|Ts!}F(!5|-&}kDht(4JT+E3B!moA;; zVENy9<47jm{Zr-s=a_tM=R#nZ3abt(Z-PLuz@5^*T#p2CLUEdCRNRmkH{4QJ>Q#E5 zA=y+zZDOT%ilQ6pasHnyKHX?gdC6=xbgRpkJ*UFQh)!RVE%?<|DF zB~L9jkPto-`(?3p0NB2}1L(;X&6|hl;V$qpBL~-k%`NB?s{tSUI0O~puL=l#7x`a& z@Lv}2a;9VK$EADmA^^euj7nrhz}0j?qGH~7B88Tl>?F{n4I3AM0vL8;O!_XpPdHUI zd&+&d!5O;kI)n76ESoMnjGTZmW^gtK9O79hUi1i$BdD8wiLC?tb!tqD*&p(iZmj9E zZ47o9Po&(2Yg~KL6YuF(VIr4{6ACed4|pE9*H0)o^t{E$$jVCTsPv>?I&%il8ZPm0 zB&Y(S=y+B*+t)dHJ%(@pt!r8_pEh%|j!I#q-xGAQv$OM7bE!VBqNkx2NK{xMHGq8? z99ACtPyjbMBcVQk{7$O_-p)=-kM1_EgXX%Ah;`GRD+uWlS`#=NQmv>i#1faVG2h#~ z_LQFETQDe>?i2;s&dva}C8_zXq9WhC$s{lNvNuP2xAM~KVG z?eW4{hA%rLL^Hk|MIg?pzRz{swI&9=sgaVQtV*bx%@7YR)QXFVioOqaaG0+-ZY)Ow z;swY71hnNJlOhyliA_9EhnzzxgEW&7Kdclw%#HskrOq#55YzZ3VSpnOl4z6!JwQVAN0Oe41oaJ}# zDIXH3ghUa8@=z>lGTP&5QfTj&X`SV1sFf2lAnu*^yLG8OC*j$|z8A75zRCjE#UpQt zn})8`Ip3!`F}0plG4wmdsaQP^z+AfYhp|25ZWACX9w1TW|HzG9CZLywOUHel*%KEM zTk2xR#U&&FuW-$^m6eq>4+;DLWabn%;Y~;%wOC&Qh>&n0Um}6P>Q0h+ zF$0nvB-Gcp+Kc!gAZ1tN*8T1h9CACA6;!NSu*yw3MDzDHH~Sb*!<&yC7emkIIW|Do zuyAKbN5UKC%GkXn!%J-L`ZN6?5vh-W@qw!GG}LepErISUze>f%f4zr0VmntIP+7yj zgTfmYR#&YB35wLJRlaiq8q|cLE>j|UahT@X{QP+m$Q%GJM4rKxjM(vbMHv9r+-O$K#t5JgMAFCN&M~z3pLm zSMdB5AM0yZ?LLx6+MSsI)Sjoi#hG9~I$kV|F>_4K;3BYdR{#>bE*0(X=NASI6yd7s z#v2=YY~PNWPdR&fxAjJ}>XIcWw<)2s{@?;lI^rbT>6&-I9tNr}75+&nJ7(Q8ja#%% z!ptor-vSzO3fjtDk#NU)MKH6MNp08r`zR-2X-QUQb2&Yf;+s5r#l7Cb(6!CjcKv57 zXYA%gNFNqIWxcZFcFCHX&=zX~^WU(eXp-!x0U5p<@#ztxWk0AyWEl9`APy!0sSy5|L6ybi$2m$v`-qgY421t1%c}mfC;O0I!=)+U<%43;#8xM9sX-07)vVmx(fZfty918K#6S^+TqC{?z4Oq7)3`6DmrW17Yep$=uPWo=s0Wo+}QlZP6v zGvOMiJBjq7Ep3z!v}L?iD@#8Y*~$+`GF{u#`jurN%reM7I{W$7t;{6mF*#{Fz||&g zZEq_$W$$={VD&>tNJuf!GvND`gR|}HuDq!t5!oK+-k-RA7nG6VNT_1Jg{+4UNV@=? za{!&C<*1*+F3NbH1WqbN>q#M~CqY6Alb{{;NUPIlmWY`tQm$6LxLl1|gLvDm#i0}C zW@ZXk2r5r~jX2)tfq;aaf2LBD64Zl>HhB3T8ZhUpvVJiRAq7EB3ye#fIfUH7B|i*E0CZb zBZ;0;V=z^si~v_-D+{oUaaw+J^TB)f`haxQe$kUv9KA-~e9HgrB+WlwS)Vz2voU{yg%H5f*8n z>f!{d2b{%E5J`V?;B{4GhFPmEllmeIt<&bVH_{hATxN*@IB~w+RVY-_Z-$sD!pu-! zn5_Wrl{NgZGpid|&M6rAenJdhkPwLsO75C{gspry4Z@+zK%UkK9(gzpjo&v!o+|u_ z6+&wFfSP=9WnwS@W}vdB2t&uyeyWAbxK&CYaKn+aNagcbokhl3fbjVV!RI7v9<;wD zC6D@Gm)+sb)E2e*41Z$1PY04mQc|);G$Q*m=$GlhXNnM{8JYvvnKC1%e`~@v1Tx2S zK}Bi;1j6RBmhoG%?j&pVT`S=v%;m1iagZDn%_{D<()~dTo}N{fxU<;h6e496$)P{H zJ`N)Cp-qxlqPvwf8J*ikbs_l#?c-UM7ph6D5�c6 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 literal 0 HcmV?d00001 diff --git a/docs/images/names_values/copy_on_modify_fig2.png b/docs/images/names_values/copy_on_modify_fig2.png new file mode 100644 index 0000000000000000000000000000000000000000..de659c0bf08e0b6e8b619908f9746f9ef78be499 GIT binary patch literal 93372 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%0A5wY4*?I%6r_n1Q78i|g-nZY{Sd-1rj1tw;4o z`b^HXUs6(1j02LCdkN+v@+A-rE{c{DJ^!)B@5ayEIS2KXv?0c|ri0PM&^dPOpMwlr zuaR7bwjZfIHm3xm&hqVF8WeOfrhxZ#PV`fNEERl#m;TBlxsKRvEFwjd6>Rpa`B;dN z5y*W`>Yv+_TxJbLlm4qW<1q-NhqlL>um*QV%iQVu;Jli^GdO;Gzc&bpC=D9MmEA7W*Bb)s ziRK-6!i=o-hgf3EGc(g~)j;%vV;n}Qdwa>i3AGupg3Ql71L^Y+L{dt0PHrmL9TI%e z^o=swGR3Q5o&}-J=)nqQyer39uV2_H6bJK@*@GFP|4I)BkC82gzS_y27a7wl$ z&&qmic?Wndc*2=|eAQ;QXYx4Upq|cy0iw535_)qsNeVUP=!4@{<71kOoY}g`1JdIVTlXlZA*H0}Nrrn<=QsusCx#sXr_}+);5&rH|0+Z*Sw~OKtL)5c(|hnidWG^B-tYbkNp-K%OOE5H&z5IWa+LplcKYN;lhC{$ zrQK#8oo)}mja#zKPExfuXV*ZZ_%H_|M!D$uPdD1fhF9CwlM!h46@+nI<{UyTp`s^x sEvkITy>-f<#?8^FS^8gl;cREr-0s)-%g>{2@SRe8sHRZ#!2Hes1AE`MUjP6A literal 0 HcmV?d00001 diff --git a/docs/images/names_values/copy_on_modify_fig3.png b/docs/images/names_values/copy_on_modify_fig3.png new file mode 100644 index 0000000000000000000000000000000000000000..ff5deaa31f5216a6282e8c5440c376590bc0eb51 GIT binary patch literal 135874 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

7iDx&N&o^%K~|IAci-sZMhFZ7l;>7^vmsUD z-oacbii}xjf+cgviZ$kv|NRTL#C|#d#S-y*2mgUG4k;gF#ks>!*{nElN@Ay=?3R0N zR*?D5?h?t^15sY|$`r2z+rBGZI%2m-#$HH-i#GuX7R*;bPh|i?l<5YU;<^G#X#gq< zC|!*e{UsrR4o9lo#X=UkMgHsF*?%CgBtqrxIYG6h#)>6Sq9N3KOw!0f0M-ET86;4X zqDaOrfno9P!OQRL&=w6p~SstKd7YGDlv!1HFG=-R6^xtxCP71Q$*_;ZTeqWm{f<>e;tI0Q&!B*(fZa zG~X%W5exAgbIpv^6@b19A~{e`7aH5087m9*bfJM0l10#5MJPS#zR`Mto;8M&hYTTs z=AKx}^EcstJ-3_>duEA4?a6#yUO`R5Ew`*G+y0WWrtCrK`Q;7n)w0E@4~-yS z71Ea!5DJAAPOc&RP*$lWA`s6TK|HPqS?HGRWTJ||LT9V6F>7j_pZvB4Y!F1pNg^sBH|lB{^ + + + + + + + + + + + +Advanced R Solutions + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Advanced R Solutions

+
+ +
+
+ Solutions to the Exercises in Hadley Wickham’s book ‘Advanced R’. +
+
+ + +
+ +
+
Author
+
+

Malte Grosser, Henning Bumann, Hadley Wickham & Mauricio Vargas Sepulveda

+
+
+ +
+
Published
+
+

January 22, 2024

+
+
+ + +
+ + +
+ +
+

Welcome

+

+

This is the website for “Advanced R Solutions” which provides solutions to the exercises from Hadley Wickham’s Advanced R, 2nd edition. A print version of this book will soon be released as part of Chapman & Hall’s R Series. Working through the exercises and their solutions will give you a deep understanding of a variety of programming challenges, many of which are relevant to everyday work.

+

Solutions to the first edition of Advanced R can be found at https://advanced-r-solutions-ed1.netlify.com.

+
+

About the authors

+

Malte Grosser is a business mathematician from Hamburg, who has been programming in R regularly since the beginning of his career. He is currently finishing his PhD on machine learning for stroke outcome prediction and develops solutions in business as a data scientist.

+

Henning Bumann is a psychologist and statistician who enjoys making sense of data and is motivated to build data-driven solutions that are beautiful and meaningful. He prefers free programming tools to support effective and transparent collaboration.

+

Hadley Wickham is Chief Scientist at RStudio, an Adjunct Professor at Stanford University and the University of Auckland, and a member of the R Foundation. He is the lead developer of the tidyverse, a collection of R packages, including ggplot2 and dplyr, designed to support data science.

+

Mauricio “Pacha” Vargas Sepulveda is completing a PhD in Political Science at the University of Toronto, specializing in International Relations and Public Policy. His research primarily focuses on the political dynamics of trade agreements and sanctions, which had led him to learn R, Python, and C++.

+
+
+

License

+

Creative Commons License
This work, as a whole, is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

+ + +
+
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/docs/search.json b/docs/search.json new file mode 100644 index 00000000..7fdbd949 --- /dev/null +++ b/docs/search.json @@ -0,0 +1,765 @@ +[ + { + "objectID": "index.html", + "href": "index.html", + "title": "Advanced R Solutions", + "section": "", + "text": "Welcome\nThis is the website for “Advanced R Solutions” which provides solutions to the exercises from Hadley Wickham’s Advanced R, 2nd edition. A print version of this book will soon be released as part of Chapman & Hall’s R Series. Working through the exercises and their solutions will give you a deep understanding of a variety of programming challenges, many of which are relevant to everyday work.\nSolutions to the first edition of Advanced R can be found at https://advanced-r-solutions-ed1.netlify.com." + }, + { + "objectID": "index.html#about-the-authors", + "href": "index.html#about-the-authors", + "title": "Advanced R Solutions", + "section": "About the authors", + "text": "About the authors\nMalte Grosser is a business mathematician from Hamburg, who has been programming in R regularly since the beginning of his career. He is currently finishing his PhD on machine learning for stroke outcome prediction and develops solutions in business as a data scientist.\nHenning Bumann is a psychologist and statistician who enjoys making sense of data and is motivated to build data-driven solutions that are beautiful and meaningful. He prefers free programming tools to support effective and transparent collaboration.\nHadley Wickham is Chief Scientist at RStudio, an Adjunct Professor at Stanford University and the University of Auckland, and a member of the R Foundation. He is the lead developer of the tidyverse, a collection of R packages, including ggplot2 and dplyr, designed to support data science.\nMauricio “Pacha” Vargas Sepulveda is completing a PhD in Political Science at the University of Toronto, specializing in International Relations and Public Policy. His research primarily focuses on the political dynamics of trade agreements and sanctions, which had led him to learn R, Python, and C++." + }, + { + "objectID": "index.html#license", + "href": "index.html#license", + "title": "Advanced R Solutions", + "section": "License", + "text": "License\nThis work, as a whole, is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License." + }, + { + "objectID": "02_Names_and_values.html#prerequisites", + "href": "02_Names_and_values.html#prerequisites", + "title": "2 - Names and values", + "section": "Prerequisites", + "text": "Prerequisites\nIn this chapter we will use the {lobstr} package (Wickham 2019) to help answer questions regarding the internal representation of R objects.\n\nlibrary(lobstr)" + }, + { + "objectID": "02_Names_and_values.html#binding-basics", + "href": "02_Names_and_values.html#binding-basics", + "title": "2 - Names and values", + "section": "Binding basics", + "text": "Binding basics\nQ1: Explain the relationship between a, b, c, and d in the following code:\n\na <- 1:10\nb <- a\nc <- b\nd <- 1:10\n\nA: a, b, and c point to the same object (with the same address in memory). This object has the value 1:10. d points to a different object with the same value.\n\nlist_of_names <- list(a, b, c, d)\nobj_addrs(list_of_names)\n#> [1] \"0x579852a52008\" \"0x579852a52008\" \"0x579852a52008\" \"0x579852b9b088\"\n\nQ2: The following code accesses the mean function in multiple ways. Do they all point to the same underlying function object? Verify this with lobstr::obj_addr().\n\nmean\nbase::mean\nget(\"mean\")\nevalq(mean)\nmatch.fun(\"mean\")\n\nA: Yes, they point to the same object. We confirm this by inspecting the address of the underlying function object.\n\nmean_functions <- list(\n mean,\n base::mean,\n get(\"mean\"),\n evalq(mean),\n match.fun(\"mean\")\n)\n\nunique(obj_addrs(mean_functions))\n#> [1] \"0x5798501620b8\"\n\nQ3: By default, base R data import functions, like read.csv(), will automatically convert non-syntactic names to syntactic ones. Why might this be problematic? What option allows you to suppress this behaviour?\nA: Column names are often data, and the underlying make.names() transformation is non-invertible, so the default behaviour corrupts data. To avoid this, set check.names = FALSE.\nQ4: What rules does make.names() use to convert non-syntactic names into syntactic ones?\nA: A valid name must start with a letter or a dot (not followed by a number) and may further contain numbers and underscores (\"_\"s are allowed since R version 1.9.0).\nThree main mechanisms ensure syntactically valid names (see ?make.names):\n\nNames that do not start with a letter or a dot will be prepended with an \"X\".\n::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-7_f6ccd6953d5a91424d54eb5b450943a0’}\nmake.names(\"\") # prepending \"x\"\n#> [1] \"X\"\n:::\nThe same holds for names that begin with a dot followed by a number.\n::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-8_3c866f40ef56f4f8e63bf8e89559c7e8’}\nmake.names(\".1\") # prepending \"X\"\n#> [1] \"X.1\"\n:::\nAdditionally, non-valid characters are replaced by a dot.\n::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-9_860c452c7c7ee11fe572d39a98a28b68’}\nmake.names(\"non-valid\") # \".\" replacement\n#> [1] \"non.valid\"\nmake.names(\"@\") # prepending \"X\" + \".\" replacement\n#> [1] \"X.\"\nmake.names(\" R\") # prepending \"X\" + \"..\" replacement\n#> [1] \"X..R\"\n:::\nReserved R keywords (see ?reserved) are suffixed by a dot.\n::: {.cell layout-align=“center” hash=‘02_Names_and_values_cache/html/unnamed-chunk-10_424c337c3ffcfb23561e4b66ebfe240a’}\nmake.names(\"if\") # \".\" suffix\n#> [1] \"if.\"\n:::\n\nInterestingly, some of these transformations are influenced by the current locale. From ?make.names:\n\nThe definition of a letter depends on the current locale, but only ASCII digits are considered to be digits.\n\nQ5: I slightly simplified the rules that govern syntactic names. Why is .123e1 not a syntactic name? Read ?make.names for the full details.\nA: .123e1 is not a syntactic name, because it starts with one dot which is followed by a number. This makes it a double, 1.23." + }, + { + "objectID": "02_Names_and_values.html#copy-on-modify", + "href": "02_Names_and_values.html#copy-on-modify", + "title": "2 - Names and values", + "section": "Copy-on-modify", + "text": "Copy-on-modify\nQ1: Why is tracemem(1:10) not useful?\nA: When 1:10 is called an object with an address in memory is created, but it is not bound to a name. Therefore, the object cannot be called or manipulated from R. As no copies will be made, it is not useful to track the object for copying.\n\nobj_addr(1:10) # the object exists, but has no name\n#> [1] \"0x5798525d5010\"\n\nQ2: Explain why tracemem() shows two copies when you run this code. Hint: carefully look at the difference between this code and the code shown earlier in the section.\n\nx <- c(1L, 2L, 3L)\ntracemem(x)\n\nx[[3]] <- 4\n\nA: Initially the vector x has integer type. The replacement call assigns a double to the third element of x, which triggers copy-on-modify.\n\nx <- c(1L, 2L, 3L)\ntracemem(x)\n#> <0x66a4a70>\n\nx[[3]] <- 4\n#> tracemem[0x55eec7b3af38 -> 0x55eec774cc18]:\n\nWe can avoid the copy by sub-assigning an integer instead of a double:\n\nx <- c(1L, 2L, 3L)\ntracemem(x)\n#> <0x55eec6940ae0>\n\nx[[3]] <- 4L\n\nPlease be aware that running this code in RStudio will result in additional copies because of the reference from the environment pane.\nQ3: Sketch out the relationship between the following objects:\n\na <- 1:10\nb <- list(a, a)\nc <- list(b, a, 1:10)\n\nA: a contains a reference to an address with the value 1:10. b contains a list of two references to the same address as a. c contains a list of b (containing two references to a), a (containing the same reference again) and a reference pointing to a different address containing the same value (1:10).\n\n\n\n\n\n\n\n\n\nWe can confirm these relationships by inspecting the reference tree in R.\n\nref(c)\n#> █ [1:0x55erc93cbdd8] <list> # c\n#> ├─█ [2:0x55efcb8246e8] <list> # - b\n#> │ ├─[3:0x55eac7df4e98] <int> # -- a\n#> │ └─[3:0x55eac7df4e98] # -- a\n#> ├─[3:0x55eac7df4e98] # - a\n#> └─[4:0x55etc7aa6968] <int> # - 1:10\n\nQ4: What happens when you run this code:\n\nx <- list(1:10)\nx[[2]] <- x\n\nDraw a picture.\nA: The initial reference tree of x shows that the name x binds to a list object. This object contains a reference to the integer vector 1:10.\n\nx <- list(1:10)\n\nref(x)\n#> █ [1:0x55853b74ff40] <list>\n#> └─[2:0x534t3abffad8] <int>\n\n\n\n\n\n\n\n\n\n\nWhen x is assigned to an element of itself, copy-on-modify takes place and the list is copied to a new address in memory.\n\ntracemem(x)\nx[[2]] <- x\n#> tracemem[0x55853b74ff40 -> 0x5d553bacdcd8]:\n\nThe list object previously bound to x is now referenced in the newly created list object. It is no longer bound to a name. The integer vector is referenced twice.\n\nref(x)\n#> █ [1:0x5d553bacdcd8] <list>\n#> ├─[2:0x534t3abffad8] <int>\n#> └─█ [3:0x55853b74ff40] <list>\n#> └─[2:0x534t3abffad8]" + }, + { + "objectID": "02_Names_and_values.html#object-size", + "href": "02_Names_and_values.html#object-size", + "title": "2 - Names and values", + "section": "Object size", + "text": "Object size\n\nQ1: In the following example, why are object.size(y) and obj_size(y) so radically different? Consult the documentation of object.size().\n\ny <- rep(list(runif(1e4)), 100)\n\nobject.size(y)\n#> 8005648 bytes\nobj_size(y)\n#> 80.90 kB\n\nA: object.size() doesn’t account for shared elements within lists. Therefore, the results differ by a factor of ~ 100.\nQ2: Take the following list. Why is its size somewhat misleading?\n\nfuns <- list(mean, sd, var)\nobj_size(funs)\n#> 17.55 kB\n\nA: All three functions are built-in to R as part of the {base} and {stats} packages and hence always available. So, what does it mean to measure the size of something that’s already included in R?\n(There’s typically a more general question about what you want to know when you ask for the size of something — do you want to know how much data you’d need to send to communicate the object to someone else (e.g. serialise it), or do you want to know how much memory you’d free if you deleted it?)\nLet us look for how many other objects this applies to as well.\nThe following packages are usually loaded by default.\n\nbase_pkgs <- c(\n \"package:stats\", \"package:graphics\", \"package:grDevices\",\n \"package:utils\", \"package:datasets\", \"package:methods\",\n \"package:base\"\n)\n\nTo look up all functions from these packages we iterate over base_pkgs and apply ls() and mget() within each iteration.\n\nbase_objs <- base_pkgs %>%\n lapply(as.environment) %>%\n lapply(function(x) mget(ls(x, all.names = TRUE), x)) %>%\n setNames(base_pkgs)\n\nThis gives us more than 2700 objects which are usually available by default.\n\nsum(lengths(base_objs))\n#> [1] 2776\n\n# We can also show the sizes in MB per package\nvapply(base_objs, obj_size, double(1)) / 1024^2\n#> package:stats package:graphics package:grDevices package:utils \n#> 11.150 3.114 2.315 7.283 \n#> package:datasets package:methods package:base \n#> 0.558 13.962 21.310\n\n# Check if we've over-counted\nas.numeric(obj_size(!!!base_objs)) / 1024^2\n#> [1] 57.9\n\nQ3: Predict the output of the following code:\n\na <- runif(1e6)\nobj_size(a)\n\nb <- list(a, a)\nobj_size(b)\nobj_size(a, b)\n\nb[[1]][[1]] <- 10\nobj_size(b)\nobj_size(a, b)\n\nb[[2]][[1]] <- 10\nobj_size(b)\nobj_size(a, b)\n\nA: In R (on most platforms) a length-0 vector has 48 bytes of overhead.\n\nobj_size(list())\n#> 48 B\nobj_size(double())\n#> 48 B\nobj_size(character())\n#> 48 B\n\nA single double takes up an additional 8 bytes of memory.\n\nobj_size(double(1))\n#> 56 B\nobj_size(double(2))\n#> 64 B\n\nSo, a 1 million double should take up 8,000,048 bytes.\n\na <- runif(1e6)\nobj_size(a)\n#> 8.00 MB\n\n(If you look carefully at the amount of memory occupied by short vectors, you will notice that the pattern is actually more complicated. This has to do with how R allocates memory and is not that important. If you want to know the full details, they’re discussed in the 1st edition of Advanced R: http://adv-r.had.co.nz/memory.html#object-size).\nFor b <- list(a, a) both list elements contain references to the same memory address.\n\nb <- list(a, a)\nref(a, b)\n#> [1:0x579859a76fc0] <dbl> \n#> \n#> █ [2:0x579852b66208] <list> \n#> ├─[1:0x579859a76fc0] \n#> └─[1:0x579859a76fc0]\n\nTherefore, no additional memory is required for the second list element. The list itself requires 64 bytes, 48 bytes for an empty list and 8 bytes for each element (obj_size(vector(\"list\", 2))). This lets us predict 8,000,048 B + 64 B = 8,000,112 B.\n\nobj_size(b)\n#> 8.00 MB\n\nWhen we modify the first element of b[[1]] copy-on-modify occurs. Both elements will still have the same size (8,000,040 B), but the first one gets a new address in memory. As b’s elements don’t share references anymore, its object size adds up to the sum of the elements and the length-2 list: 8,000,048 B + 8,000,048 B + 64 B = 16,000,160 B (16 MB).\n\nb[[1]][[1]] <- 10\nobj_size(b)\n#> 16.00 MB\n\nThe second element of b still references the same address as a, so the combined size of a and b is the same as b.\n\nobj_size(a, b)\n#> 16.00 MB\nref(a, b)\n#> [1:0x579859a76fc0] <dbl> \n#> \n#> █ [2:0x5798587d8828] <list> \n#> ├─[3:0x57985cdf4fa0] <dbl> \n#> └─[1:0x579859a76fc0]\n\nWhen we modify the second element of b, this element will also point to a new memory address. This does not affect the size of the list.\n\nb[[2]][[1]] <- 10\nobj_size(b)\n#> 16.00 MB\n\nHowever, as b doesn’t share references with a anymore, the memory usage of the combined objects increases.\n\nref(a, b)\n#> [1:0x579859a76fc0] <dbl> \n#> \n#> █ [2:0x579858188b58] <list> \n#> ├─[3:0x57985cdf4fa0] <dbl> \n#> └─[4:0x57985af6c830] <dbl>\nobj_size(a, b)\n#> 24.00 MB" + }, + { + "objectID": "02_Names_and_values.html#modify-in-place", + "href": "02_Names_and_values.html#modify-in-place", + "title": "2 - Names and values", + "section": "Modify-in-place", + "text": "Modify-in-place\n\nQ1: Explain why the following code doesn’t create a circular list.\n\nx <- list()\nx[[1]] <- x\n\nA: In this situation copy-on-modify prevents the creation of a circular list. Let us step through the details:\n\nx <- list() # creates initial object\nobj_addr(x)\n#> [1] \"0x55862f23ab80\"\n\ntracemem(x)\n#> [1] \"<0x55862f23ab80>\"\nx[[1]] <- x # Copy-on-modify triggers new copy\n#> tracemem[0x55862f23ab80 -> 0x55862e8ce028]:\n\nobj_addr(x) # copied object has new memory address\n#> [1] \"0x55862e8ce028\"\nobj_addr(x[[1]]) # list element contains old memory address\n#> [1] \"0x55862f23ab80\"\n\nQ2: Wrap the two methods for subtracting medians into two functions, then use the {bench} package to carefully compare their speeds. How does performance change as the number of columns increase?\nA: First, we define a function to create some random data.\n\ncreate_random_df <- function(nrow, ncol) {\n random_matrix <- matrix(runif(nrow * ncol), nrow = nrow)\n as.data.frame(random_matrix)\n}\n\ncreate_random_df(2, 2)\n#> V1 V2\n#> 1 0.972 0.0116\n#> 2 0.849 0.4339\n\nNext, we wrap the two approaches to subtract numerical values (in our case medians) from each column of a data frame in their own function. We name these functions depending on whether the approach operates on a data frame or a list. For a fairer comparison, the second function also contains the overhead code to convert between data frame and list objects.\n\nsubtract_df <- function(x, medians) {\n for (i in seq_along(medians)) {\n x[[i]] <- x[[i]] - medians[[i]]\n }\n x\n}\n\nsubtract_list <- function(x, medians) {\n x <- as.list(x)\n x <- subtract_df(x, medians)\n list2DF(x)\n}\n\nThis lets us profile the performance, via benchmarks on data frames with differing numbers of columns. Therefore, we create a small helper that creates our random data frame and its medians before it benchmarks the two approaches by employing the {bench} package (Hester 2020).\n\nbenchmark_medians <- function(ncol) {\n df <- create_random_df(nrow = 1e4, ncol = ncol)\n medians <- vapply(df, median, numeric(1), USE.NAMES = FALSE)\n\n bench::mark(\n \"data frame\" = subtract_df(df, medians),\n \"list\" = subtract_list(df, medians),\n time_unit = \"ms\"\n )\n}\n\nbenchmark_medians(1)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <dbl> <dbl> <dbl> <bch:byt> <dbl>\n#> 1 data frame 0.0130 0.0149 60947. 99.1KB 61.0\n#> 2 list 0.0124 0.0141 65028. 78.2KB 65.1\n\nThe bench::press() function allows us to run our helper across a grid of parameters. We will use it to slowly increase the number of data frame columns in our benchmark.\n\nresults <- bench::press(\n ncol = c(1, 10, 50, 100, 250, 300, 400, 500, 750, 1000),\n benchmark_medians(ncol)\n)\n#> Running with:\n#> ncol\n#> 1 1\n#> 2 10\n#> 3 50\n#> 4 100\n#> 5 250\n#> 6 300\n#> 7 400\n#> 8 500\n#> 9 750\n#> 10 1000\n\nFinally, we can plot and interpret our results.\n\nlibrary(ggplot2)\n\nggplot(\n results,\n aes(ncol, median, col = attr(expression, \"description\"))\n) +\n geom_point(size = 2) +\n geom_smooth() +\n labs(\n x = \"Number of Columns\",\n y = \"Execution Time (ms)\",\n colour = \"Data Structure\"\n ) +\n theme(legend.position = \"top\")\n#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'\n\n\n\n\n\n\n\n\nWhen working directly with the data frame, the execution time grows quadratically with the number of columns in the input data. This is because (e.g.) the first column must be copied n times, the second column n-1 times, and so on. When working with a list, the execution time increases only linearly.\nObviously in the long run, linear growth creates shorter run-times, but there is some cost to this strategy — we have to convert between data structures with as.list() and list2DF(). Even though this is fast and probably doesn’t hurt much, the improved approach doesn’t really pay off in this scenario until we get to a data frame that is about 300 columns wide (with the exact value depending on the characteristics of the system running the code).\nQ3: What happens if you attempt to use tracemem() on an environment?\nA: tracemem() cannot be used to mark and trace environments.\n\nx <- new.env()\ntracemem(x)\n#> Error in tracemem(x): 'tracemem' is not useful for promise and environment objects\n\nThe error occurs because “it is not useful to trace NULL, environments, promises, weak references, or external pointer objects, as these are not duplicated” (see ?tracemem). Environments are always modified in place." + }, + { + "objectID": "02_Names_and_values.html#references", + "href": "02_Names_and_values.html#references", + "title": "2 - Names and values", + "section": "References", + "text": "References\n\n\n\n\nHester, Jim. 2020. Bench: High Precision Timing of r Expressions. https://github.com/r-lib/bench.\n\n\nWickham, Hadley. 2019. Lobstr: Visualize r Data Structures with Trees. https://github.com/r-lib/lobstr." + }, + { + "objectID": "03_Vectors.html#atomic-vectors", + "href": "03_Vectors.html#atomic-vectors", + "title": "3 - Vectors", + "section": "Atomic vectors", + "text": "Atomic vectors\nQ1: How do you create raw and complex scalars? (See ?raw and ?complex.)\nA: In R, scalars are represented as vectors of length one. However, there’s no built-in syntax like there is for logicals, integers, doubles, and character vectors to create individual raw and complex values. Instead, you have to create them by calling a function.\nFor raw vectors you can use either as.raw() or charToRaw() to create them from numeric or character values.\n\nas.raw(42)\n#> [1] 2a\ncharToRaw(\"A\")\n#> [1] 41\n\nIn the case of complex numbers, real and imaginary parts may be provided directly to the complex() constructor.\n\ncomplex(length.out = 1, real = 1, imaginary = 1)\n#> [1] 1+1i\n\nYou can create purely imaginary numbers (e.g.) 1i, but there is no way to create complex numbers without + (e.g. 1i + 1).\nQ2: Test your knowledge of vector coercion rules by predicting the output of the following uses of c():\n\nc(1, FALSE) # will be coerced to double -> 1 0\nc(\"a\", 1) # will be coerced to character -> \"a\" \"1\"\nc(TRUE, 1L) # will be coerced to integer -> 1 1\n\nQ3: Why is 1 == \"1\" true? Why is -1 < FALSE true? Why is \"one\" < 2 false?\nA: These comparisons are carried out by operator-functions (==, <), which coerce their arguments to a common type. In the examples above, these types will be character, double and character: 1 will be coerced to \"1\", FALSE is represented as 0 and 2 turns into \"2\" (and numbers precede letters in lexicographic order (may depend on locale)).\nQ4: Why is the default missing value, NA, a logical vector? What’s special about logical vectors? (Hint: think about c(FALSE, NA_character_).)\nA: The presence of missing values shouldn’t affect the type of an object. Recall that there is a type-hierarchy for coercion from character → double → integer → logical. When combining NAs with other atomic types, the NAs will be coerced to integer (NA_integer_), double (NA_real_) or character (NA_character_) and not the other way round. If NA were a character and added to a set of other values all of these would be coerced to character as well.\nQ5: Precisely what do is.atomic(), is.numeric(), and is.vector() test for?\nA: The documentation states that:\n\nis.atomic() tests if an object is an atomic vector (as defined in Advanced R) or is NULL (!).\nis.numeric() tests if an object has type integer or double and is not of class factor, Date, POSIXt or difftime.\nis.vector() tests if an object is a vector (as defined in Advanced R) or an expression and has no attributes, apart from names.\n\nAtomic vectors are defined in Advanced R as objects of type logical, integer, double, complex, character or raw. Vectors are defined as atomic vectors or lists." + }, + { + "objectID": "03_Vectors.html#attributes", + "href": "03_Vectors.html#attributes", + "title": "3 - Vectors", + "section": "Attributes", + "text": "Attributes\nQ1: How is setNames() implemented? How is unname() implemented? Read the source code.\nA: setNames() is implemented as:\n\nsetNames <- function(object = nm, nm) {\n names(object) <- nm\n object\n}\n\nBecause the data argument comes first, setNames() also works well with the magrittr-pipe operator. When no first argument is given, the result is a named vector (this is rather untypical as required arguments usually come first):\n\nsetNames(, c(\"a\", \"b\", \"c\"))\n#> a b c \n#> \"a\" \"b\" \"c\"\n\nunname() is implemented in the following way:\n\nunname <- function(obj, force = FALSE) {\n if (!is.null(names(obj))) {\n names(obj) <- NULL\n }\n if (!is.null(dimnames(obj)) && (force || !is.data.frame(obj))) {\n dimnames(obj) <- NULL\n }\n obj\n}\n\nunname() removes existing names (or dimnames) by setting them to NULL.\nQ2: What does dim() return when applied to a 1-dimensional vector? When might you use NROW() or NCOL()?\nA: From ?nrow:\n\ndim() will return NULL when applied to a 1d vector.\n\nOne may want to use NROW() or NCOL() to handle atomic vectors, lists and NULL values in the same way as one column matrices or data frames. For these objects nrow() and ncol() return NULL:\n\nx <- 1:10\n\n# Return NULL\nnrow(x)\n#> NULL\nncol(x)\n#> NULL\n\n# Pretend it's a column vector\nNROW(x)\n#> [1] 10\nNCOL(x)\n#> [1] 1\n\nQ3: How would you describe the following three objects? What makes them different to 1:5?\n\nx1 <- array(1:5, c(1, 1, 5)) # 1 row, 1 column, 5 in third dim.\nx2 <- array(1:5, c(1, 5, 1)) # 1 row, 5 columns, 1 in third dim.\nx3 <- array(1:5, c(5, 1, 1)) # 5 rows, 1 column, 1 in third dim.\n\nA: These are all “one dimensional”. If you imagine a 3d cube, x1 is in the x-dimension, x2 is in the y-dimension, and x3 is in the z-dimension. In contrast to 1:5, x1, x2 and x3 have a dim attribute.\nQ4: An early draft used this code to illustrate structure():\n\nstructure(1:5, comment = \"my attribute\")\n#> [1] 1 2 3 4 5\n\nBut when you print that object you don’t see the comment attribute. Why? Is the attribute missing, or is there something else special about it? (Hint: try using help.)\nA: The documentation states (see ?comment):\n\nContrary to other attributes, the comment is not printed (by print or print.default).\n\nAlso, from ?attributes:\n\nNote that some attributes (namely class, comment, dim, dimnames, names, row.names and tsp) are treated specially and have restrictions on the values which can be set.\n\nWe can retrieve comment attributes by calling them explicitly:\n\nfoo <- structure(1:5, comment = \"my attribute\")\n\nattributes(foo)\n#> $comment\n#> [1] \"my attribute\"\nattr(foo, which = \"comment\")\n#> [1] \"my attribute\"" + }, + { + "objectID": "03_Vectors.html#s3-atomic-vectors", + "href": "03_Vectors.html#s3-atomic-vectors", + "title": "3 - Vectors", + "section": "S3 atomic vectors", + "text": "S3 atomic vectors\nQ1: What sort of object does table() return? What is its type? What attributes does it have? How does the dimensionality change as you tabulate more variables?\nA: table() returns a contingency table of its input variables. It is implemented as an integer vector with class table and dimensions (which makes it act like an array). Its attributes are dim (dimensions) and dimnames (one name for each input column). The dimensions correspond to the number of unique values (factor levels) in each input variable.\n\nx <- table(mtcars[c(\"vs\", \"cyl\", \"am\")])\n\ntypeof(x)\n#> [1] \"integer\"\nattributes(x)\n#> $dim\n#> [1] 2 3 2\n#> \n#> $dimnames\n#> $dimnames$vs\n#> [1] \"0\" \"1\"\n#> \n#> $dimnames$cyl\n#> [1] \"4\" \"6\" \"8\"\n#> \n#> $dimnames$am\n#> [1] \"0\" \"1\"\n#> \n#> \n#> $class\n#> [1] \"table\"\n\n# Subset x like it's an array\nx[, , 1]\n#> cyl\n#> vs 4 6 8\n#> 0 0 0 12\n#> 1 3 4 0\nx[, , 2]\n#> cyl\n#> vs 4 6 8\n#> 0 1 3 2\n#> 1 7 0 0\n\nQ2: What happens to a factor when you modify its levels?\n\nf1 <- factor(letters)\nlevels(f1) <- rev(levels(f1))\n\nA: The underlying integer values stay the same, but the levels are changed, making it look like the data has changed.\n\nf1 <- factor(letters)\nf1\n#> [1] a b c d e f g h i j k l m n o p q r s t u v w x y z\n#> Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z\nas.integer(f1)\n#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25\n#> [26] 26\n\nlevels(f1) <- rev(levels(f1))\nf1\n#> [1] z y x w v u t s r q p o n m l k j i h g f e d c b a\n#> Levels: z y x w v u t s r q p o n m l k j i h g f e d c b a\nas.integer(f1)\n#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25\n#> [26] 26\n\nQ3: What does this code do? How do f2 and f3 differ from f1?\n\nf2 <- rev(factor(letters))\n\nf3 <- factor(letters, levels = rev(letters))\n\nA: For f2 and f3 either the order of the factor elements or its levels are being reversed. For f1 both transformations are occurring.\n\n# Reverse element order\n(f2 <- rev(factor(letters)))\n#> [1] z y x w v u t s r q p o n m l k j i h g f e d c b a\n#> Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z\nas.integer(f2)\n#> [1] 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2\n#> [26] 1\n\n# Reverse factor levels (when creating factor)\n(f3 <- factor(letters, levels = rev(letters)))\n#> [1] a b c d e f g h i j k l m n o p q r s t u v w x y z\n#> Levels: z y x w v u t s r q p o n m l k j i h g f e d c b a\nas.integer(f3)\n#> [1] 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2\n#> [26] 1" + }, + { + "objectID": "03_Vectors.html#lists", + "href": "03_Vectors.html#lists", + "title": "3 - Vectors", + "section": "Lists", + "text": "Lists\nQ1: List all the ways that a list differs from an atomic vector.\nA: To summarise:\n\nAtomic vectors are always homogeneous (all elements must be of the same type). Lists may be heterogeneous (the elements can be of different types) as described in the introduction of the vectors chapter.\nAtomic vectors point to one address in memory, while lists contain a separate reference for each element. (This was described in the list sections of the vectors and the names and values chapters.)\n::: {.cell layout-align=“center” hash=‘03_Vectors_cache/html/unnamed-chunk-17_0058a5e26b51d7db0318a76d78964418’}\nlobstr::ref(1:2)\n#> [1:0x64f19ae18cf8] <int>\nlobstr::ref(list(1:2, 2))\n#> █ [1:0x64f19c1af298] <list> \n#> ├─[2:0x64f19b1df130] <int> \n#> └─[3:0x64f19b417d30] <dbl>\n:::\nSubsetting with out-of-bounds and NA values leads to different output. For example, [ returns NA for atomics and NULL for lists. (This is described in more detail within the subsetting chapter.)\n::: {.cell layout-align=“center” hash=‘03_Vectors_cache/html/unnamed-chunk-18_96e783346fc71ba0391dc1e6eefae75a’}\n# Subsetting atomic vectors\n(1:2)[3]\n#> [1] NA\n(1:2)[NA]\n#> [1] NA NA\n\n# Subsetting lists\nas.list(1:2)[3]\n#> [[1]]\n#> NULL\nas.list(1:2)[NA]\n#> [[1]]\n#> NULL\n#> \n#> [[2]]\n#> NULL\n:::\n\nQ2: Why do you need to use unlist() to convert a list to an atomic vector? Why doesn’t as.vector() work?\nA: A list is already a vector, though not an atomic one!\nNote that as.vector() and is.vector() use different definitions of “vector”!\n\nis.vector(as.vector(mtcars))\n#> [1] TRUE\n\nQ3: Compare and contrast c() and unlist() when combining a date and date-time into a single vector.\nA: Date and date-time objects are both built upon doubles. While dates store the number of days since the reference date 1970-01-01 (also known as “the Epoch”) in days, date-time-objects (POSIXct) store the time difference to this date in seconds.\n\ndate <- as.Date(\"1970-01-02\")\ndttm_ct <- as.POSIXct(\"1970-01-01 01:00\", tz = \"UTC\")\n\n# Internal representations\nunclass(date)\n#> [1] 1\nunclass(dttm_ct)\n#> [1] 3600\n#> attr(,\"tzone\")\n#> [1] \"UTC\"\n\nAs the c() generic only dispatches on its first argument, combining date and date-time objects via c() could lead to surprising results in older R versions (pre R 4.0.0):\n\n# Output in R version 3.6.2\nc(date, dttm_ct) # equal to c.Date(date, dttm_ct)\n#> [1] \"1970-01-02\" \"1979-11-10\"\nc(dttm_ct, date) # equal to c.POSIXct(date, dttm_ct)\n#> [1] \"1970-01-01 02:00:00 CET\" \"1970-01-01 01:00:01 CET\"\n\nIn the first statement above c.Date() is executed, which incorrectly treats the underlying double of dttm_ct (3600) as days instead of seconds. Conversely, when c.POSIXct() is called on a date, one day is counted as one second only.\nWe can highlight these mechanics by the following code:\n\n# Output in R version 3.6.2\nunclass(c(date, dttm_ct)) # internal representation\n#> [1] 1 3600\ndate + 3599\n#> \"1979-11-10\"\n\nAs of R 4.0.0 these issues have been resolved and both methods now convert their input first into POSIXct and Date, respectively.\n\nc(dttm_ct, date)\n#> [1] \"1970-01-01 01:00:00 UTC\" \"1970-01-02 00:00:00 UTC\"\nunclass(c(dttm_ct, date))\n#> [1] 3600 86400\n#> attr(,\"tzone\")\n#> [1] \"UTC\"\n\nc(date, dttm_ct)\n#> [1] \"1970-01-02\" \"1970-01-01\"\nunclass(c(date, dttm_ct))\n#> [1] 1 0\n\nHowever, as c() strips the time zone (and other attributes) of POSIXct objects, some caution is still recommended.\n\n(dttm_ct <- as.POSIXct(\"1970-01-01 01:00\", tz = \"HST\"))\n#> [1] \"1970-01-01 01:00:00 HST\"\nattributes(c(dttm_ct))\n#> $class\n#> [1] \"POSIXct\" \"POSIXt\" \n#> \n#> $tzone\n#> [1] \"HST\"\n\nA package that deals with these kinds of problems in more depth and provides a structural solution for them is the {vctrs} package (Wickham, Henry, and Vaughan 2020) which is also used throughout the tidyverse (Wickham et al. 2019).\nLet’s look at unlist(), which operates on list input.\n\n# Attributes are stripped\nunlist(list(date, dttm_ct))\n#> [1] 1 39600\n\nWe see again that dates and date-times are internally stored as doubles. Unfortunately, this is all we are left with, when unlist strips the attributes of the list.\nTo summarise: c() coerces types and strips time zones. Errors may have occurred in older R versions because of inappropriate method dispatch/immature methods. unlist() strips attributes." + }, + { + "objectID": "03_Vectors.html#data-frames-and-tibbles", + "href": "03_Vectors.html#data-frames-and-tibbles", + "title": "3 - Vectors", + "section": "Data frames and tibbles", + "text": "Data frames and tibbles\nQ1: Can you have a data frame with zero rows? What about zero columns?\nA: Yes, you can create these data frames easily; either during creation or via subsetting. Even both dimensions can be zero.\nCreate a 0-row, 0-column, or an empty data frame directly:\n\ndata.frame(a = integer(), b = logical())\n#> [1] a b\n#> <0 rows> (or 0-length row.names)\n\ndata.frame(row.names = 1:3) # or data.frame()[1:3, ]\n#> data frame with 0 columns and 3 rows\n\ndata.frame()\n#> data frame with 0 columns and 0 rows\n\nCreate similar data frames via subsetting the respective dimension with either 0, NULL, FALSE or a valid 0-length atomic (logical(0), character(0), integer(0), double(0)). Negative integer sequences would also work. The following example uses a zero:\n\nmtcars[0, ]\n#> [1] mpg cyl disp hp drat wt qsec vs am gear carb\n#> <0 rows> (or 0-length row.names)\n\nmtcars[, 0] # or mtcars[0]\n#> data frame with 0 columns and 32 rows\n\nmtcars[0, 0]\n#> data frame with 0 columns and 0 rows\n\nQ2: What happens if you attempt to set rownames that are not unique?\nA: Matrices can have duplicated row names, so this does not cause problems.\nData frames, however, require unique rownames and you get different results depending on how you attempt to set them. If you set them directly or via row.names(), you get an error:\n\ndata.frame(row.names = c(\"x\", \"y\", \"y\"))\n#> Error in data.frame(row.names = c(\"x\", \"y\", \"y\")): duplicate row.names: y\n\ndf <- data.frame(x = 1:3)\nrow.names(df) <- c(\"x\", \"y\", \"y\")\n#> Warning: non-unique value when setting 'row.names': 'y'\n#> Error in `.rowNamesDF<-`(x, value = value): duplicate 'row.names' are not allowed\n\nIf you use subsetting, [ automatically deduplicates:\n\nrow.names(df) <- c(\"x\", \"y\", \"z\")\ndf[c(1, 1, 1), , drop = FALSE]\n#> x\n#> x 1\n#> x.1 1\n#> x.2 1\n\nQ3: If df is a data frame, what can you say about t(df), and t(t(df))? Perform some experiments, making sure to try different column types.\nA: Both of t(df) and t(t(df)) will return matrices:\n\ndf <- data.frame(x = 1:3, y = letters[1:3])\nis.matrix(df)\n#> [1] FALSE\nis.matrix(t(df))\n#> [1] TRUE\nis.matrix(t(t(df)))\n#> [1] TRUE\n\nThe dimensions will respect the typical transposition rules:\n\ndim(df)\n#> [1] 3 2\ndim(t(df))\n#> [1] 2 3\ndim(t(t(df)))\n#> [1] 3 2\n\nBecause the output is a matrix, every column is coerced to the same type. (It is implemented within t.data.frame() via as.matrix() which is described below).\n\ndf\n#> x y\n#> 1 1 a\n#> 2 2 b\n#> 3 3 c\nt(df)\n#> [,1] [,2] [,3]\n#> x \"1\" \"2\" \"3\" \n#> y \"a\" \"b\" \"c\"\n\nQ4: What does as.matrix() do when applied to a data frame with columns of different types? How does it differ from data.matrix()?\nA: The type of the result of as.matrix depends on the types of the input columns (see ?as.matrix):\n\nThe method for data frames will return a character matrix if there is only atomic columns and any non-(numeric/logical/complex) column, applying as.vector to factors and format to other non-character columns. Otherwise the usual coercion hierarchy (logical < integer < double < complex) will be used, e.g. all-logical data frames will be coerced to a logical matrix, mixed logical-integer will give an integer matrix, etc.\n\nOn the other hand, data.matrix will always return a numeric matrix (see ?data.matrix()).\n\nReturn the matrix obtained by converting all the variables in a data frame to numeric mode and then binding them together as the columns of a matrix. Factors and ordered factors are replaced by their internal codes. […] Character columns are first converted to factors and then to integers.\n\nWe can illustrate and compare the mechanics of these functions using a concrete example. as.matrix() makes it possible to retrieve most of the original information from the data frame but leaves us with characters. To retrieve all information from data.matrix()’s output, we would need a lookup table for each column.\n\ndf_coltypes <- data.frame(\n a = c(\"a\", \"b\"),\n b = c(TRUE, FALSE),\n c = c(1L, 0L),\n d = c(1.5, 2),\n e = factor(c(\"f1\", \"f2\"))\n)\n\nas.matrix(df_coltypes)\n#> a b c d e \n#> [1,] \"a\" \"TRUE\" \"1\" \"1.5\" \"f1\"\n#> [2,] \"b\" \"FALSE\" \"0\" \"2.0\" \"f2\"\ndata.matrix(df_coltypes)\n#> a b c d e\n#> [1,] 1 1 1 1.5 1\n#> [2,] 2 0 0 2.0 2" + }, + { + "objectID": "03_Vectors.html#references", + "href": "03_Vectors.html#references", + "title": "3 - Vectors", + "section": "References", + "text": "References\n\n\n\n\nWickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.\n\n\nWickham, Hadley, Lionel Henry, and Davis Vaughan. 2020. Vctrs: Vector Helpers. https://github.com/r-lib/vctrs." + }, + { + "objectID": "04_Subsetting.html#selecting-multiple-elements", + "href": "04_Subsetting.html#selecting-multiple-elements", + "title": "4 - Subsetting", + "section": "Selecting multiple elements", + "text": "Selecting multiple elements\nQ1: Fix each of the following common data frame subsetting errors:\n\nmtcars[mtcars$cyl = 4, ]\n# use `==` (instead of `=`)\n\nmtcars[-1:4, ]\n# use `-(1:4)` (instead of `-1:4`)\n\nmtcars[mtcars$cyl <= 5]\n# `,` is missing\n\nmtcars[mtcars$cyl == 4 | 6, ]\n# use `mtcars$cyl == 6` (instead of `6`)\n# or `%in% c(4, 6)` (instead of `== 4 | 6`)\n\nQ2: Why does the following code yield five missing values? (Hint: why is it different from x[NA_real_]?)\n\nx <- 1:5\nx[NA]\n#> [1] NA NA NA NA NA\n\nA: In contrast to NA_real, NA has logical type and logical vectors are recycled to the same length as the vector being subset, i.e. x[NA] is recycled to x[c(NA, NA, NA, NA, NA)].\nQ3: What does upper.tri() return? How does subsetting a matrix with it work? Do we need any additional subsetting rules to describe its behaviour?\n\nx <- outer(1:5, 1:5, FUN = \"*\")\nx[upper.tri(x)]\n\nA: upper.tri(x) returns a logical matrix, which contains TRUE values above the diagonal and FALSE values everywhere else. In upper.tri() the positions for TRUE and FALSE values are determined by comparing x’s row and column indices via .row(dim(x)) < .col(dim(x)).\n\nx\n#> [,1] [,2] [,3] [,4] [,5]\n#> [1,] 1 2 3 4 5\n#> [2,] 2 4 6 8 10\n#> [3,] 3 6 9 12 15\n#> [4,] 4 8 12 16 20\n#> [5,] 5 10 15 20 25\nupper.tri(x)\n#> [,1] [,2] [,3] [,4] [,5]\n#> [1,] FALSE TRUE TRUE TRUE TRUE\n#> [2,] FALSE FALSE TRUE TRUE TRUE\n#> [3,] FALSE FALSE FALSE TRUE TRUE\n#> [4,] FALSE FALSE FALSE FALSE TRUE\n#> [5,] FALSE FALSE FALSE FALSE FALSE\n\nWhen subsetting with logical matrices, all elements that correspond to TRUE will be selected. Matrices extend vectors with a dimension attribute, so the vector forms of subsetting can be used (including logical subsetting). We should take care, that the dimensions of the subsetting matrix match the object of interest — otherwise unintended selections due to vector recycling may occur. Please also note, that this form of subsetting returns a vector instead of a matrix, as the subsetting alters the dimensions of the object.\n\nx[upper.tri(x)]\n#> [1] 2 3 6 4 8 12 5 10 15 20\n\nQ4: Why does mtcars[1:20] return an error? How does it differ from the similar mtcars[1:20, ]?\nA: When subsetting a data frame with a single vector, it behaves the same way as subsetting a list of columns. So, mtcars[1:20] would return a data frame containing the first 20 columns of the dataset. However, as mtcars has only 11 columns, the index will be out of bounds and an error is thrown. mtcars[1:20, ] is subsetted with two vectors, so 2d subsetting kicks in, and the first index refers to rows.\nQ5: Implement your own function that extracts the diagonal entries from a matrix (it should behave like diag(x) where x is a matrix).\nA: The elements in the diagonal of a matrix have the same row- and column indices. This characteristic can be used to create a suitable numeric matrix used for subsetting.\n\ndiag2 <- function(x) {\n n <- min(nrow(x), ncol(x))\n idx <- cbind(seq_len(n), seq_len(n))\n\n x[idx]\n}\n\n# Let's check if it works\n(x <- matrix(1:30, 5))\n#> [,1] [,2] [,3] [,4] [,5] [,6]\n#> [1,] 1 6 11 16 21 26\n#> [2,] 2 7 12 17 22 27\n#> [3,] 3 8 13 18 23 28\n#> [4,] 4 9 14 19 24 29\n#> [5,] 5 10 15 20 25 30\n\ndiag(x)\n#> [1] 1 7 13 19 25\ndiag2(x)\n#> [1] 1 7 13 19 25\n\nQ6: What does df[is.na(df)] <- 0 do? How does it work?\nA: This expression replaces the NAs in df with 0. Here is.na(df) returns a logical matrix that encodes the position of the missing values in df. Subsetting and assignment are then combined to replace only the missing values." + }, + { + "objectID": "04_Subsetting.html#selecting-a-single-element", + "href": "04_Subsetting.html#selecting-a-single-element", + "title": "4 - Subsetting", + "section": "Selecting a single element", + "text": "Selecting a single element\nQ1: Brainstorm as many ways as possible to extract the third value from the cyl variable in the mtcars dataset.\nA: Base R already provides an abundance of possibilities:\n\n# Select column first\nmtcars$cyl[[3]]\n#> [1] 4\nmtcars[ , \"cyl\"][[3]]\n#> [1] 4\nmtcars[[\"cyl\"]][[3]]\n#> [1] 4\nwith(mtcars, cyl[[3]])\n#> [1] 4\n\n# Select row first\nmtcars[3, ]$cyl\n#> [1] 4\nmtcars[3, \"cyl\"]\n#> [1] 4\nmtcars[3, ][ , \"cyl\"]\n#> [1] 4\nmtcars[3, ][[\"cyl\"]]\n#> [1] 4\n\n# Select simultaneously\nmtcars[3, 2]\n#> [1] 4\nmtcars[[c(2, 3)]]\n#> [1] 4\n\nQ2: Given a linear model, e.g. mod <- lm(mpg ~ wt, data = mtcars), extract the residual degrees of freedom. Extract the R squared from the model summary (summary(mod)).\nA: mod is of type list, which opens up several possibilities. We use $ or [[ to extract a single element:\n\nmod <- lm(mpg ~ wt, data = mtcars)\n\nmod$df.residual\n#> [1] 30\nmod[[\"df.residual\"]]\n#> [1] 30\n\nThe same also applies to summary(mod), so we could use, e.g.:\n\nsummary(mod)$r.squared\n#> [1] 0.753\n\n(Tip: The {broom} package (Robinson, Hayes, and Couch 2020) provides a very useful approach to work with models in a tidy way.)" + }, + { + "objectID": "04_Subsetting.html#applications", + "href": "04_Subsetting.html#applications", + "title": "4 - Subsetting", + "section": "Applications", + "text": "Applications\nQ1: How would you randomly permute the columns of a data frame? (This is an important technique in random forests.) Can you simultaneously permute the rows and columns in one step?\nA: This can be achieved by combining [ and sample():\n\n# Permute columns\nmtcars[sample(ncol(mtcars))]\n\n# Permute columns and rows in one step\nmtcars[sample(nrow(mtcars)), sample(ncol(mtcars))]\n\nQ2: How would you select a random sample of m rows from a data frame? What if the sample had to be contiguous (i.e. with an initial row, a final row, and every row in between)?\nA: Selecting m random rows from a data frame can be achieved through subsetting.\n\nm <- 10\nmtcars[sample(nrow(mtcars), m), ]\n\nHolding successive lines together as a blocked sample requires only a certain amount of caution in order to obtain the correct start and end index.\n\nstart <- sample(nrow(mtcars) - m + 1, 1)\nend <- start + m - 1\nmtcars[start:end, , drop = FALSE]\n\nQ3: How could you put the columns in a data frame in alphabetical order?\nA: We combine [ with order() or sort():\n\nmtcars[order(names(mtcars))]\nmtcars[sort(names(mtcars))]" + }, + { + "objectID": "04_Subsetting.html#references", + "href": "04_Subsetting.html#references", + "title": "4 - Subsetting", + "section": "References", + "text": "References\n\n\n\n\nRobinson, David, Alex Hayes, and Simon Couch. 2020. Broom: Convert Statistical Objects into Tidy Tibbles. https://github.com/tidymodels/broom." + }, + { + "objectID": "05_Control_flow.html#choices", + "href": "05_Control_flow.html#choices", + "title": "5 - Control flow", + "section": "Choices", + "text": "Choices\nQ1: What type of vector does each of the following calls to ifelse() return?\n\nifelse(TRUE, 1, \"no\")\nifelse(FALSE, 1, \"no\")\nifelse(NA, 1, \"no\")\n\nRead the documentation and write down the rules in your own words.\nA: The arguments of ifelse() are named test, yes and no. In general, ifelse() returns the entry for yes when test is TRUE, the entry for no when test is FALSE and NA when test is NA. Therefore, the expressions above return vectors of type double (1), character (\"no\") and logical (NA).\nTo be a little more precise, we will cite the part of the documentation on the return value of ifelse():\n\nA vector of the same length and attributes (including dimensions and “class”) as test and data values from the values of yes or no. The mode of the answer will be coerced from logical to accommodate first any values taken from yes and then any values taken from no.\n\nThis is surprising because it uses the type of test. In practice this means, that test is first converted to logical and if the result is neither TRUE nor FALSE, simply as.logical(test) is returned.\n\nifelse(logical(), 1, \"no\")\n#> logical(0)\nifelse(NaN, 1, \"no\")\n#> [1] NA\nifelse(NA_character_, 1, \"no\")\n#> [1] NA\nifelse(\"a\", 1, \"no\")\n#> [1] NA\nifelse(\"true\", 1, \"no\")\n#> [1] 1\n\nQ2: Why does the following code work?\n\nx <- 1:10\nif (length(x)) \"not empty\" else \"empty\"\n#> [1] \"not empty\"\n\nx <- numeric()\nif (length(x)) \"not empty\" else \"empty\"\n#> [1] \"empty\"\n\nA: if() expects a logical condition, but also accepts a numeric vector where 0 is treated as FALSE and all other numbers are treated as TRUE. Numerical missing values (including NaN) lead to an error in the same way that a logical missing, NA, does." + }, + { + "objectID": "05_Control_flow.html#loops", + "href": "05_Control_flow.html#loops", + "title": "5 - Control flow", + "section": "Loops", + "text": "Loops\nQ1: Why does this code succeed without errors or warnings?\n\nx <- numeric()\nout <- vector(\"list\", length(x))\nfor (i in 1:length(x)) {\n out[i] <- x[i]^2\n}\nout\n\nA: This loop is a delicate issue, and we have to consider a few points to explain why it is evaluated without raising any errors or warnings.\nThe beginning of this code smell is the statement 1:length(x) which creates the index of the for loop. As x has length 0 1:length(x) counts down from 1 to 0. This issue is typically avoided via usage of seq_along(x) or similar helpers which would just generate integer(0) in this case.\nAs we use [<- and [ for indexing 0-length vectors at their first and zeroth position, we need to be aware of their subsetting behaviour for out-of-bounds and zero indices.\nDuring the first iteration x[1] will generate an NA (out-of-bounds indexing for atomics). The resulting NA (from squaring) will be assigned to the empty length-1 list out[1] (out-of-bounds indexing for lists).\nIn the next iteration, x[0] will return numeric(0) (zero indexing for atomics). Again, squaring doesn’t change the value and numeric(0) is assigned to out[0] (zero indexing for lists). Assigning a 0-length vector to a 0-length subset works but doesn’t change the object.\nOverall, the code works, because each step includes valid R operations (even though the result may not be what the user intended).\nQ2: When the following code is evaluated, what can you say about the vector being iterated?\n\nxs <- c(1, 2, 3)\nfor (x in xs) {\n xs <- c(xs, x * 2)\n}\nxs\n#> [1] 1 2 3 2 4 6\n\nA: In this loop x takes on the values of the initial xs (1, 2 and 3), indicating that it is evaluated just once in the beginning of the loop, not after each iteration. (Otherwise, we would run into an infinite loop.)\nQ3: What does the following code tell you about when the index is updated?\n\nfor (i in 1:3) {\n i <- i * 2\n print(i)\n}\n#> [1] 2\n#> [1] 4\n#> [1] 6\n\nA: In a for loop the index is updated in the beginning of each iteration. Therefore, reassigning the index symbol during one iteration doesn’t affect the following iterations. (Again, we would otherwise run into an infinite loop.)" + }, + { + "objectID": "06_Functions.html#function-fundamentals", + "href": "06_Functions.html#function-fundamentals", + "title": "6 - Functions", + "section": "Function fundamentals", + "text": "Function fundamentals\nQ1: Given a name, like \"mean\", match.fun() lets you find a function. Given a function, can you find its name? Why doesn’t that make sense in R?\nA: In R there is no one-to-one mapping between functions and names. A name always points to a single object, but an object may have zero, one or many names.\nLet’s look at an example:\n\nfunction(x) sd(x) / mean(x)\n#> function(x) sd(x) / mean(x)\n\nf1 <- function(x) (x - min(x)) / (max(x) - min(x))\nf2 <- f1\nf3 <- f1\n\nWhile the function in the first line is not bound to a name multiple names (f1, f2 and f3) point to the second function. So, the main point is that the relation between name and object is only clearly defined in one direction.\nBesides that, there are obviously ways to search for function names. However, to be sure to find the right one(s), you should not only compare the code (body) but also the arguments (formals) and the creation environment. As formals(), body() and environment() all return NULL for primitive functions, the easiest way to check if two functions are exactly equal is just to use identical().\nQ2: It’s possible (although typically not useful) to call an anonymous function. Which of the two approaches below is correct? Why?\n\nfunction(x) 3()\n#> function(x) 3()\n(function(x) 3)()\n#> [1] 3\n\nA: The second approach is correct.\nThe anonymous function function(x) 3 is surrounded by a pair of parentheses before it is called by (). These extra parentheses separate the function call from the anonymous function’s body. Without them a function with the invalid body 3() is returned, which throws an error when we call it. This is easier to see if we name the function:\n\nf <- function(x) 3()\nf\n#> function(x) 3()\nf()\n#> Error in f(): attempt to apply non-function\n\nQ3: A good rule of thumb is that an anonymous function should fit on one line and shouldn’t need to use {}. Review your code. Where could you have used an anonymous function instead of a named function? Where should you have used a named function instead of an anonymous function?\nA: The use of anonymous functions allows concise and elegant code in certain situations. However, they miss a descriptive name and when re-reading the code, it can take a while to figure out what they do. That’s why it’s helpful to give long and complex functions a descriptive name. It may be worthwhile to take a look at your own projects or other people’s code to reflect on this part of your coding style.\nQ4: What function allows you to tell if an object is a function? What function allows you to tell if a function is a primitive function?\nA: Use is.function() to test if an object is a function. Consider using is.primitive() to test specifically for primitive functions.\nQ5: This code makes a list of all functions in the {base} package.\n\nobjs <- mget(ls(\"package:base\", all = TRUE), inherits = TRUE)\nfuns <- Filter(is.function, objs)\n\nUse it to answer the following questions:\n\nWhich base function has the most arguments?\nHow many base functions have no arguments? What’s special about those functions?\nHow could you adapt the code to find all primitive functions?\n\nA: Let’s look at each sub-question separately:\n\nTo find the function with the most arguments, we first compute the length of formals().\n::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-6_6267cff5cf01cfe02ecd151e21d5a5fa’}\nlibrary(purrr)\n\nn_args <- funs %>%\n map(formals) %>%\n map_int(length)\n:::\nThen we sort n_args in decreasing order and look at its first entries.\n::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-7_e2ebb773e25ecb466480bc13c7da9a54’}\nn_args %>%\n sort(decreasing = TRUE) %>%\n head()\n#> scan format.default source\n#> 22 16 16\n#> formatC library merge.data.frame\n#> 15 13 13\n:::\nWe can further use n_args to find the number of functions with no arguments:\n::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-8_c75252d5453caf2a84875fac9332cabc’}\nsum(n_args == 0)\n#> [1] 253\n:::\nHowever, this over counts because formals() returns NULL for primitive functions, and length(NULL) is 0. To fix this, we can first remove the primitive functions:\n::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-9_26e9cc7827d73a0a237f756700c9bf1e’}\nn_args2 <- funs %>%\n discard(is.primitive) %>%\n map(formals) %>%\n map_int(length)\n\nsum(n_args2 == 0)\n#> [1] 48\n:::\nIndeed, most of the functions with no arguments are actually primitive functions.\nTo find all primitive functions, we can change the predicate in Filter() from is.function() to is.primitive():\n::: {.cell layout-align=“center” hash=‘06_Functions_cache/html/unnamed-chunk-10_ff0eddde09f29f9d6acb9dcb81dfbef0’}\nfuns <- Filter(is.primitive, objs)\nlength(funs)\n#> [1] 205\n:::\n\nQ6: What are the three important components of a function?\nA: These components are the function’s body(), formals() and environment(). However, as mentioned in Advanced R:\n\nThere is one exception to the rule that functions have three components. Primitive functions, like sum(), call C code directly with .Primitive() and contain no R code. Therefore, their formals(), body(), and environment() are all NULL.\n\nQ7: When does printing a function not show what environment it was created in?\nA: Primitive functions and functions created in the global environment do not print their environment." + }, + { + "objectID": "06_Functions.html#lexical-scoping", + "href": "06_Functions.html#lexical-scoping", + "title": "6 - Functions", + "section": "Lexical scoping", + "text": "Lexical scoping\nQ1: What does the following code return? Why? Describe how each of the three c’s is interpreted.\n\nc <- 10\nc(c = c)\n\nA: This code returns a named numeric vector of length one — with one element of the value 10 and the name \"c\". The first c represents the c() function, the second c is interpreted as a (quoted) name and the third c as a value.\nQ2: What are the four principles that govern how R looks for values?\nA: R’s lexical scoping rules are based on these four principles:\n\nName masking\nFunctions vs. variables\nA fresh start\nDynamic lookup\n\nQ3: What does the following function return? Make a prediction before running the code yourself.\n\nf <- function(x) {\n f <- function(x) {\n f <- function() {\n x^2\n }\n f() + 1\n }\n f(x) * 2\n}\nf(10)\n\nA: Within this nested function two more functions also named f are defined and called. Because the functions are each executed in their own environment R will look up and use the functions defined last in these environments. The innermost f() is called last, though it is the first function to return a value. Therefore, the order of the calculation passes “from the inside to the outside” and the function returns ((10 ^ 2) + 1) * 2, i.e. 202." + }, + { + "objectID": "06_Functions.html#lazy-evaluation", + "href": "06_Functions.html#lazy-evaluation", + "title": "6 - Functions", + "section": "Lazy evaluation", + "text": "Lazy evaluation\nQ1: What important property of && makes x_ok() work?\n\nx_ok <- function(x) {\n !is.null(x) && length(x) == 1 && x > 0\n}\n\nx_ok(NULL)\n#> [1] FALSE\nx_ok(1)\n#> [1] TRUE\nx_ok(1:3)\n#> [1] FALSE\n\nWhat is different with this code? Why is this behaviour undesirable here?\n\nx_ok <- function(x) {\n !is.null(x) & length(x) == 1 & x > 0\n}\n\nx_ok(NULL)\n#> logical(0)\nx_ok(1)\n#> [1] TRUE\nx_ok(1:3)\n#> [1] FALSE FALSE FALSE\n\nA: In summary: && short-circuits which means that if the left-hand side is FALSE it doesn’t evaluate the right-hand side (because it doesn’t matter). Similarly, if the left-hand side of || is TRUE it doesn’t evaluate the right-hand side.\nWe expect x_ok() to validate its input via certain criteria: it must not be NULL, have length 1 and be greater than 0. Meaningful outcomes for this assertion will be TRUE, FALSE or NA. The desired behaviour is reached by combining the assertions through && instead of &.\n&& does not perform elementwise comparisons; instead it uses the first element of each value only. It also uses lazy evaluation, in the sense that evaluation “proceeds only until the result is determined” (from ?Logic). This means that the RHS of && won’t be evaluated if the LHS already determines the outcome of the comparison (e.g. evaluate to FALSE). This behaviour is also known as “short-circuiting”. For some situations (x = 1) both operators will lead to the same result. But this is not always the case. For x = NULL, the &&-operator will stop after the !is.null statement and return the result. The following conditions won’t even be evaluated! (If the other conditions are also evaluated (by the use of &), the outcome would change. NULL > 0 returns logical(0), which is not helpful in this case.)\nWe can also see the difference in behaviour, when we set x = 1:3. The &&-operator returns the result from length(x) == 1, which is FALSE. Using & as the logical operator leads to the (vectorised) x > 0 condition being evaluated and also returned.\nQ2: What does this function return? Why? Which principle does it illustrate?\n\nf2 <- function(x = z) {\n z <- 100\n x\n}\nf2()\n\nA: The function returns 100. The default argument (x = z) gets lazily evaluated within the function environment when x gets accessed. At this time z has already been bound to the value 100. The illustrated principle here is lazy evaluation.\nQ3: What does this function return? Why? Which principle does it illustrate?\n\ny <- 10\nf1 <- function(x = {\n y <- 1\n 2\n }, y = 0) {\n c(x, y)\n}\nf1()\ny\n\nA: The function returns c(2, 1) which is due to name masking. When x is accessed within c(), the promise x = {y <- 1; 2} is evaluated inside f1()’s environment. y gets bound to the value 1 and the return value of {() (2) gets assigned to x. When y gets accessed next within c(), it has already the value 1 and R doesn’t need to look it up any further. Therefore, the promise y = 0 won’t be evaluated. Also, as y is assigned within f1()’s environment, the value of the global variable y is left untouched.\nQ4: In hist(), the default value of xlim is range(breaks), the default value for breaks is \"Sturges\", and\n\nrange(\"Sturges\")\n#> [1] \"Sturges\" \"Sturges\"\n\nExplain how hist() works to get a correct xlim value.\nA: The xlim argument of hist() defines the range of the histogram’s x-axis. In order to provide a valid axis xlim must contain a numeric vector of exactly two unique values. Consequently, for the default xlim = range(breaks)), breaks must evaluate to a vector with at least two unique values.\nDuring execution hist() overwrites the breaks argument. The breaks argument is quite flexible and allows the users to provide the breakpoints directly or compute them in several ways. Therefore, the specific behaviour depends highly on the input. But hist ensures that breaks evaluates to a numeric vector containing at least two unique elements before xlim is computed.\nQ5: Explain why this function works. Why is it confusing?\n\nshow_time <- function(x = stop(\"Error!\")) {\n stop <- function(...) Sys.time()\n print(x)\n}\nshow_time()\n#> [1] \"2024-01-24 11:45:19 EST\"\n\nA: Before show_time() accesses x (default stop(\"Error\")), the stop() function is masked by function(...) Sys.time(). As default arguments are evaluated in the function environment, print(x) will be evaluated as print(Sys.time()).\nThis function is confusing because its behaviour changes when x’s value is supplied directly. Now the value from the calling environment will be used and the overwriting of stop() won’t affect x anymore.\n\nshow_time(x = stop(\"Error!\"))\n#> Error in print(x): Error!\n\nQ6: How many arguments are required when calling library()?\nA: library() doesn’t require any arguments. When called without arguments library() invisibly returns a list of class libraryIQR, which contains a results matrix with one row and three columns per installed package. These columns contain entries for the name of the package (“Package”), the path to the package (“LibPath”) and the title of the package (“Title”). library() also has its own print method (print.libraryIQR()), which displays this information conveniently in its own window.\nThis behaviour is also documented under the details section of library()’s help page (?library):\n\nIf library is called with no package or help argument, it lists all available packages in the libraries specified by lib.loc, and returns the corresponding information in an object of class “libraryIQR”. (The structure of this class may change in future versions.) Use .packages(all = TRUE) to obtain just the names of all available packages, and installed.packages() for even more information.\n\nBecause the package and help argument from library() do not show a default value, it’s easy to overlook the possibility to call library() without these arguments. (Instead of providing NULLs as default values library() uses missing() to check if these arguments were provided.)\n\nstr(formals(library))\n#> Dotted pair list of 13\n#> $ package : symbol \n#> $ help : symbol \n#> $ pos : num 2\n#> $ lib.loc : NULL\n#> $ character.only : logi FALSE\n#> $ logical.return : logi FALSE\n#> $ warn.conflicts : symbol \n#> $ quietly : logi FALSE\n#> $ verbose : language getOption(\"verbose\")\n#> $ mask.ok : symbol \n#> $ exclude : symbol \n#> $ include.only : symbol \n#> $ attach.required: language missing(include.only)" + }, + { + "objectID": "06_Functions.html#dot-dot-dot", + "href": "06_Functions.html#dot-dot-dot", + "title": "6 - Functions", + "section": "... (dot-dot-dot)", + "text": "... (dot-dot-dot)\nQ1: Explain the following results:\n\nsum(1, 2, 3)\n#> [1] 6\nmean(1, 2, 3)\n#> [1] 1\n\nsum(1, 2, 3, na.omit = TRUE)\n#> [1] 7\nmean(1, 2, 3, na.omit = TRUE)\n#> [1] 1\n\nA: Let’s inspect the arguments and their order for both functions. For sum() these are ... and na.rm:\n\nstr(sum)\n#> function (..., na.rm = FALSE)\n\nFor the ... argument sum() expects numeric, complex, or logical vector input (see ?sum). Unfortunately, when ... is used, misspelled arguments (!) like na.omit won’t raise an error (in case of no further input checks). So instead, na.omit is treated as a logical and becomes part of the ... argument. It will be coerced to 1 and be part of the sum. All other arguments are left unchanged. Therefore sum(1, 2, 3) returns 6 and sum(1, 2, 3, na.omit = TRUE) returns 7.\nIn contrast, the generic function mean() expects x, trim, na.rm and ... for its default method.\n\nstr(mean.default)\n#> function (x, trim = 0, na.rm = FALSE, ...)\n\nAs na.omit is not one of mean()’s named arguments (x; and no candidate for partial matching), na.omit again becomes part of the ... argument. However, in contrast to sum() the elements of ... are not “part” of the mean. The other supplied arguments are matched by their order, i.e. x = 1, trim = 2 and na.rm = 3. As x is of length 1 and not NA, the settings of trim and na.rm do not affect the calculation of the mean. Both calls (mean(1, 2, 3) and mean(1, 2, 3, na.omit = TRUE)) return 1.\nQ2: Explain how to find the documentation for the named arguments in the following function call:\n\nplot(1:10, col = \"red\", pch = 20, xlab = \"x\", col.lab = \"blue\")\n\n\n\n\n\n\n\n\nA: First we type ?plot in the console and check the “Usage” section which contains:\nplot(x, y, ...)\nThe arguments we want to learn more about (col, pch, xlab, col.lab) are part of the ... argument. There we can find information for the xlab argument and a recommendation to visit ?par for the other arguments. Under ?par we type “col” into the search bar, which leads us to the section “Color Specification”. We also search for the pch argument, which leads to the recommendation to check ?points. Finally, col.lab is also directly documented within ?par.\nQ3: Why does plot(1:10, col = \"red\") only colour the points, not the axes or labels? Read the source code of plot.default() to find out.\nA: To learn about the internals of plot.default() we add browser() to the first line of the code and interactively run plot(1:10, col = \"red\"). This way we can see how the plot is built and learn where the axes are added.\nThis leads us to the function call\n\nlocalTitle(main = main, sub = sub, xlab = xlab, ylab = ylab, ...)\n\nThe localTitle() function was defined in the first lines of plot.default() as:\n\nlocalTitle <- function(..., col, bg, pch, cex, lty, lwd) title(...)\n\nThe call to localTitle() passes the col parameter as part of the ... argument to title(). ?title tells us that the title() function specifies four parts of the plot: Main (title of the plot), sub (sub-title of the plot) and both axis labels. Therefore, it would introduce ambiguity inside title() to use col directly. Instead, one has the option to supply col via the ... argument, via col.lab or as part of xlab in the form xlab = list(c(\"index\"), col = \"red\") (similar for ylab)." + }, + { + "objectID": "06_Functions.html#exiting-a-function", + "href": "06_Functions.html#exiting-a-function", + "title": "6 - Functions", + "section": "Exiting a function", + "text": "Exiting a function\nQ1: What does load() return? Why don’t you normally see these values?\nA: load() loads objects saved to disk in .Rdata files by save(). When run successfully, load() invisibly returns a character vector containing the names of the newly loaded objects. To print these names to the console, one can set the argument verbose to TRUE or surround the call in parentheses to trigger R’s auto-printing mechanism.\nQ2: What does write.table() return? What would be more useful?\nA: write.table() writes an object, usually a data frame or a matrix, to disk. The function invisibly returns NULL. It would be more useful if write.table() would (invisibly) return the input data, x. This would allow to save intermediate results and directly take on further processing steps without breaking the flow of the code (i.e. breaking it into different lines). One package which uses this pattern is the {readr} package (Wickham and Hester 2020), which is part of the tidyverse-ecosystem.\nQ3: How does the chdir parameter of source() compare to with_dir()? Why might you prefer one to the other?\nA: The with_dir() approach was given in Advanced R as:\n\nwith_dir <- function(dir, code) {\n old <- setwd(dir)\n on.exit(setwd(old))\n\n force(code)\n}\n\nwith_dir() takes a path for a working directory (dir) as its first argument. This is the directory where the provided code (code) should be executed. Therefore, the current working directory is changed in with_dir() via setwd(). Then, on.exit() ensures that the modification of the working directory is reset to the initial value when the function exits. By passing the path explicitly, the user has full control over the directory to execute the code in.\nIn source() the code is passed via the file argument (a path to a file). The chdir argument specifies if the working directory should be changed to the directory containing the file. The default for chdir is FALSE, so you don’t have to provide a value. However, as you can only provide TRUE or FALSE, you are also less flexible in choosing the working directory for the code execution.\nQ4: Write a function that opens a graphics device, runs the supplied code, and closes the graphics device (always, regardless of whether or not the plotting code works).\nA: To control the graphics device we use pdf() and dev.off(). To ensure a clean termination on.exit() is used.\n\nplot_pdf <- function(code) {\n pdf(\"test.pdf\")\n on.exit(dev.off(), add = TRUE)\n code\n}\n\nQ5: We can use on.exit() to implement a simple version of capture.output().\n\ncapture.output2 <- function(code) {\n temp <- tempfile()\n on.exit(file.remove(temp), add = TRUE, after = TRUE)\n\n sink(temp)\n on.exit(sink(), add = TRUE, after = TRUE)\n\n force(code)\n readLines(temp)\n}\ncapture.output2(cat(\"a\", \"b\", \"c\", sep = \"\\n\"))\n#> [1] \"a\" \"b\" \"c\"\n\nCompare capture.output() to capture.output2(). How do the functions differ? What features have I removed to make the key ideas easier to see? How have I rewritten the key ideas to be easier to understand?\nA: Using body(capture.output) we inspect the source code of the original capture.output() function: The implementation for capture.output() is quite a bit longer (39 lines vs. 7 lines).\nIn capture_output2() the code is simply forced, and the output is caught via sink() in a temporary file. An additional feature of capture_output() is that one can also capture messages by setting type = \"message\". As this is internally forwarded to sink(), this behaviour (and also sink()’s split argument) could be easily introduced within capture_output2() as well.\nThe main difference is that capture.output() calls print, i.e. compare the output of these two calls:\n\ncapture.output({\n 1\n})\n#> [1] \"[1] 1\"\ncapture.output2({\n 1\n})\n#> character(0)" + }, + { + "objectID": "06_Functions.html#function-forms", + "href": "06_Functions.html#function-forms", + "title": "6 - Functions", + "section": "Function forms", + "text": "Function forms\nQ1: Rewrite the following code snippets into prefix form:\n\n1 + 2 + 3\n\n1 + (2 + 3)\n\nif (length(x) <= 5) x[[5]] else x[[n]]\n\nA: Let’s rewrite the expressions to match the exact syntax from the code above. Because prefix functions already define the execution order, we may omit the parentheses in the second expression.\n\n`+`(`+`(1, 2), 3)\n\n`+`(1, `(`(`+`(2, 3)))\n`+`(1, `+`(2, 3))\n\n`if`(`<=`(length(x), 5), `[[`(x, 5), `[[`(x, n))\n\nQ2: Clarify the following list of odd function calls:\n\nx <- sample(replace = TRUE, 20, x = c(1:10, NA))\ny <- runif(min = 0, max = 1, 20)\ncor(m = \"k\", y = y, u = \"p\", x = x)\n\nA: None of these functions provides a ... argument. Therefore, the function arguments are first matched exactly, then via partial matching and finally by position. This leads us to the following explicit function calls:\n\nx <- sample(c(1:10, NA), size = 20, replace = TRUE)\ny <- runif(20, min = 0, max = 1)\ncor(x, y, use = \"pairwise.complete.obs\", method = \"kendall\")\n\nQ3: Explain why the following code fails:\n\nmodify(get(\"x\"), 1) <- 10\n#> Error: target of assignment expands to non-language object\n\nA: First, let’s define x and recall the definition of modify() from Advanced R:\n\nx <- 1:3\n\n`modify<-` <- function(x, position, value) {\n x[position] <- value\n x\n}\n\nR internally transforms the code, and the transformed code reproduces the error above:\n\nget(\"x\") <- `modify<-`(get(\"x\"), 1, 10)\n#> Error in get(\"x\") <- `modify<-`(get(\"x\"), 1, 10) :\n#> target of assignment expands to non-language object\n\nThe error occurs during the assignment because no corresponding replacement function, i.e. get<-, exists for get(). To confirm this, we reproduce the error via the following simplified example.\n\nget(\"x\") <- 2\n#> Error in get(\"x\") <- 2 :\n#> target of assignment expands to non-language object\n\nQ4: Create a replacement function that modifies a random location in a vector.\nA: Let’s define random<- like this:\n\n`random<-` <- function(x, value) {\n idx <- sample(length(x), 1)\n x[idx] <- value\n x\n}\n\nQ5: Write your own version of + that pastes its inputs together if they are character vectors but behaves as usual otherwise. In other words, make this code work:\n\n1 + 2\n#> [1] 3\n\n\"a\" + \"b\"\n#> [1] \"ab\"\n\nA: To achieve this behaviour, we need to override the + operator. We need to take care to not use the + operator itself inside of the function definition, as this would lead to an undesired infinite recursion. We also add b = 0L as a default value to keep the behaviour of + as a unary operator, i.e. to keep + 1 working and not throwing an error.\n\n`+` <- function(a, b = 0L) {\n if (is.character(a) && is.character(b)) {\n paste0(a, b)\n } else {\n base::`+`(a, b)\n }\n}\n\n# Test\n+1\n#> [1] 1\n1 + 2\n#> [1] 3\n\"a\" + \"b\"\n#> [1] \"ab\"\n\n# Return back to the original `+` operator\nrm(`+`)\n\nQ6: Create a list of all the replacement functions found in the {base} package. Which ones are primitive functions? (Hint use apropos())\nA: The hint suggests to look for functions with a specific naming pattern: Replacement functions conventionally end on “<-”. We can search for these objects by supplying the regular expression \"<-$\" to apropos(). apropos() also allows to return the position on the search path (search()) for each of its matches via setting where = TRUE. Finally, we can set mode = function to narrow down our search to relevant objects only. This gives us the following statement to begin with:\n\nrepls <- apropos(\"<-\", where = TRUE, mode = \"function\")\nhead(repls, 30)\n#> 12 12 12 \n#> \".rowNamesDF<-\" \"[[<-\" \"[[<-.data.frame\" \n#> 12 12 12 \n#> \"[[<-.factor\" \"[[<-.numeric_version\" \"[[<-.POSIXlt\" \n#> 12 12 12 \n#> \"[<-\" \"[<-.data.frame\" \"[<-.Date\" \n#> 12 12 12 \n#> \"[<-.difftime\" \"[<-.factor\" \"[<-.numeric_version\" \n#> 12 12 12 \n#> \"[<-.POSIXct\" \"[<-.POSIXlt\" \"@<-\" \n#> 12 12 12 \n#> \"<-\" \"<<-\" \"$<-\" \n#> 12 12 10 \n#> \"$<-.data.frame\" \"$<-.POSIXlt\" \"as<-\" \n#> 12 12 10 \n#> \"attr<-\" \"attributes<-\" \"body<-\" \n#> 12 12 10 \n#> \"body<-\" \"class<-\" \"coerce<-\" \n#> 12 12 3 \n#> \"colnames<-\" \"comment<-\" \"contrasts<-\"\n\nTo restrict repl to names of replacement functions from the {base} package, we select only matches containing the relevant position on the search path.\n\nrepls_base <- repls[names(repls) == length(search())]\nrepls_base\n#> 12 12 12 \n#> \".rowNamesDF<-\" \"[[<-\" \"[[<-.data.frame\" \n#> 12 12 12 \n#> \"[[<-.factor\" \"[[<-.numeric_version\" \"[[<-.POSIXlt\" \n#> 12 12 12 \n#> \"[<-\" \"[<-.data.frame\" \"[<-.Date\" \n#> 12 12 12 \n#> \"[<-.difftime\" \"[<-.factor\" \"[<-.numeric_version\" \n#> 12 12 12 \n#> \"[<-.POSIXct\" \"[<-.POSIXlt\" \"@<-\" \n#> 12 12 12 \n#> \"<-\" \"<<-\" \"$<-\" \n#> 12 12 12 \n#> \"$<-.data.frame\" \"$<-.POSIXlt\" \"attr<-\" \n#> 12 12 12 \n#> \"attributes<-\" \"body<-\" \"class<-\" \n#> 12 12 12 \n#> \"colnames<-\" \"comment<-\" \"diag<-\" \n#> 12 12 12 \n#> \"dim<-\" \"dimnames<-\" \"dimnames<-.data.frame\" \n#> 12 12 12 \n#> \"Encoding<-\" \"environment<-\" \"formals<-\" \n#> 12 12 12 \n#> \"is.na<-\" \"is.na<-.default\" \"is.na<-.factor\" \n#> 12 12 12 \n#> \"is.na<-.numeric_version\" \"length<-\" \"length<-.Date\" \n#> 12 12 12 \n#> \"length<-.difftime\" \"length<-.factor\" \"length<-.POSIXct\" \n#> 12 12 12 \n#> \"length<-.POSIXlt\" \"levels<-\" \"levels<-.factor\" \n#> 12 12 12 \n#> \"mode<-\" \"mostattributes<-\" \"names<-\" \n#> 12 12 12 \n#> \"names<-.POSIXlt\" \"oldClass<-\" \"parent.env<-\" \n#> 12 12 12 \n#> \"regmatches<-\" \"row.names<-\" \"row.names<-.data.frame\" \n#> 12 12 12 \n#> \"row.names<-.default\" \"rownames<-\" \"split<-\" \n#> 12 12 12 \n#> \"split<-.data.frame\" \"split<-.default\" \"storage.mode<-\" \n#> 12 12 12 \n#> \"substr<-\" \"substring<-\" \"units<-\" \n#> 12 \n#> \"units<-.difftime\"\n\nTo find out which of these functions are primitives, we first search for these functions via mget() and then subset the result using Filter() and is.primitive().\n\nrepls_base_prim <- mget(repls_base, envir = baseenv()) %>%\n Filter(is.primitive, .) %>%\n names()\n\nrepls_base_prim\n#> [1] \"[[<-\" \"[<-\" \"@<-\" \"<-\" \n#> [5] \"<<-\" \"$<-\" \"attr<-\" \"attributes<-\" \n#> [9] \"class<-\" \"dim<-\" \"dimnames<-\" \"environment<-\" \n#> [13] \"length<-\" \"levels<-\" \"names<-\" \"oldClass<-\" \n#> [17] \"storage.mode<-\"\n\nOverall the {base} package contains 64 replacement functions of which 17 are primitive functions.\nQ7: What are valid names for user-created infix functions?\nA: Let’s cite from the section on function forms from Advanced R:\n\n… names of infix functions are more flexible than regular R functions: they can contain any sequence of characters except “%”.\n\nQ8: Create an infix xor() operator.\nA: We could create an infix %xor% like this:\n\n`%xor%` <- function(a, b) {\n xor(a, b)\n}\nTRUE %xor% TRUE\n#> [1] FALSE\nFALSE %xor% TRUE\n#> [1] TRUE\n\nQ9: Create infix versions of the set functions intersect(), union(), and setdiff(). You might call them %n%, %u%, and %/% to match conventions from mathematics.\nA: These infix operators could be defined in the following way. (%/% is chosen instead of %\\%, because \\ serves as an escape character.)\n\n`%n%` <- function(a, b) {\n intersect(a, b)\n}\n\n`%u%` <- function(a, b) {\n union(a, b)\n}\n\n`%/%` <- function(a, b) {\n setdiff(a, b)\n}\n\nx <- c(\"a\", \"b\", \"d\")\ny <- c(\"a\", \"c\", \"d\")\n\nx %u% y\n#> [1] \"a\" \"b\" \"d\" \"c\"\nx %n% y\n#> [1] \"a\" \"d\"\nx %/% y\n#> [1] \"b\"" + }, + { + "objectID": "06_Functions.html#references", + "href": "06_Functions.html#references", + "title": "6 - Functions", + "section": "References", + "text": "References\n\n\n\n\nWickham, Hadley, and Jim Hester. 2020. Readr: Read Rectangular Text Data. https://github.com/tidyverse/readr." + }, + { + "objectID": "07_Environments.html#prerequisites", + "href": "07_Environments.html#prerequisites", + "title": "7 Environments", + "section": "Prerequisites", + "text": "Prerequisites\nJust like in Advanced R, we mainly use the {rlang} package (Henry and Wickham 2020) to work with environments.\n\nlibrary(rlang)" + }, + { + "objectID": "07_Environments.html#environment-basics", + "href": "07_Environments.html#environment-basics", + "title": "7 Environments", + "section": "Environment basics", + "text": "Environment basics\nQ1: List three ways in which an environment differs from a list.\nA: The most important differences between environments and lists are:\n\nenvironments have reference semantics (i.e. they don’t copy-on-modify)\nenvironments have parents\nthe contents of an environment must have unique names\nthe contents of an environment are not ordered\n(environments can only be compared via identical(); not with ==)\n(environments can contain themselves)\n\nQ2: Create an environment as illustrated by this picture.\n\n\n\n\n\n\n\n\n\nA: Let’s create an environment that contains itself.\n\ne1 <- env()\ne1$loop <- e1\n\n# Print the environment\nenv_print(e1)\n#> <environment: 0x590c00c194d0>\n#> Parent: <environment: global>\n#> Bindings:\n#> • loop: <env>\n\n# Verify that it contains itself\nlobstr::ref(e1)\n#> █ [1:0x590c00c194d0] <env> \n#> └─loop = [1:0x590c00c194d0]\n\nQ3: Create a pair of environments as illustrated by this picture.\n\n\n\n\n\n\n\n\n\nA: These two environments contain each other:\n\ne1 <- env()\ne2 <- env()\n\ne1$loop <- e2\ne2$dedoop <- e1\n\nlobstr::ref(e1)\n#> █ [1:0x590c00f0d1d8] <env> \n#> └─loop = █ [2:0x590c00f8e0a8] <env> \n#> └─dedoop = [1:0x590c00f0d1d8]\nlobstr::ref(e2)\n#> █ [1:0x590c00f8e0a8] <env> \n#> └─dedoop = █ [2:0x590c00f0d1d8] <env> \n#> └─loop = [1:0x590c00f8e0a8]\n\nQ4: Explain why e[[1]] and e[c(\"a\", \"b\")] don’t make sense when e is an environment.\nA: The first option doesn’t make sense, because elements of an environment are not ordered. The second option would return two objects at the same time. What data structure would they be contained inside?\nQ5: Create a version of env_poke() that will only bind new names, never re-bind old names. Some programming languages only do this, and are known as single assignment languages.\nA: As described in Advanced R rlang::env_poke() takes a name (as string) and a value to assign (or reassign) a binding in an environment.\n\ne3 <- new.env()\n\nenv_poke(e3, \"a\", 100)\ne3$a\n#> [1] 100\nenv_poke(e3, \"a\", 200)\ne3$a\n#> [1] 200\n\nSo, we want env_poke2() to test, if the supplied name is already present in the given environment. This can be checked via env_has(). If this is the case, an (informative) error is thrown.\n\nenv_poke2 <- function(env, name, value) {\n if (env_has(env, name)) {\n abort(paste0(\"\\\"\", name, \"\\\" is already assigned to a value.\"))\n }\n\n env_poke(env, name, value)\n invisible(env)\n}\n\n# Test\nenv_poke2(e3, \"b\", 100)\ne3$b\n#> [1] 100\nenv_poke2(e3, \"b\", 200)\n#> Error in `env_poke2()`:\n#> ! \"b\" is already assigned to a value.\n\nQ6: What does this function do? How does it differ from <<- and why might you prefer it?\n\nrebind <- function(name, value, env = caller_env()) {\n if (identical(env, empty_env())) {\n stop(\"Can't find `\", name, \"`\", call. = FALSE)\n } else if (env_has(env, name)) {\n env_poke(env, name, value)\n } else {\n rebind(name, value, env_parent(env))\n }\n}\nrebind(\"a\", 10)\n#> Error: Can't find `a`\na <- 5\nrebind(\"a\", 10)\na\n#> [1] 10\n\nA: The primary difference between rebind() and <<- is that rebind() will only carry out an assignment when it finds an existing binding; unlike <<- it will never create a new one in the global environment. This behaviour of <<- is usually undesirable because global variables introduce non-obvious dependencies between functions." + }, + { + "objectID": "07_Environments.html#recursing-over-environments", + "href": "07_Environments.html#recursing-over-environments", + "title": "7 Environments", + "section": "Recursing over environments", + "text": "Recursing over environments\nQ1: Modify where() to return all environments that contain a binding for name. Carefully think through what type of object the function will need to return.\nA: where() searches (recursively) for a given name within a given environment and its ancestors. If where() finds the name in one of these environments, it returns the environment’s name. Otherwise, it throws an error.\nThe definition of where() was given in Advanced R as:\n\nwhere <- function(name, env = caller_env()) {\n if (identical(env, empty_env())) {\n # Base case\n stop(\"Can't find `\", name, \"`.\", call. = FALSE)\n } else if (env_has(env, name)) {\n # Success case\n env\n } else {\n # Recursive case\n where(name, env_parent(env))\n }\n}\n\nOur modified version of where() will always recurse until it reaches the empty environment. No matter if it has already found the name or not. Along the way, it will check each environment for the given name. Finally, it will return a list of environments where the binding was found; if no binding was found, the list will be empty.\nPlease also note how the list is initialised via the default argument, when the function is called for the first time. This is a bit confusing, which is why it’s common to wrap a recursive function inside another, more user friendly, function.\n\nwhere2 <- function(name, env = caller_env(), results = list()) {\n if (identical(env, empty_env())) {\n # Base case\n results\n } else {\n # Recursive case\n if (env_has(env, name)) {\n results <- c(results, env)\n }\n where2(name, env_parent(env), results)\n }\n}\n\n# Test\ne1a <- env(empty_env(), a = 1, b = 2)\ne1b <- env(e1a, b = 10, c = 11)\ne1c <- env(e1b, a = 12, d = 13)\n\nwhere2(\"a\", e1c)\n#> [[1]]\n#> <environment: 0x590bff309938>\n#> \n#> [[2]]\n#> <environment: 0x590bff08c7a8>\n\nQ2: Write a function called fget() that finds only function objects. It should have two arguments, name and env, and should obey the regular scoping rules for functions: if there’s an object with a matching name that’s not a function, look in the parent. For an added challenge, also add an inherits argument which controls whether the function recurses up the parents or only looks in one environment.\nA: We follow a similar approach to the previous exercise. This time we additionally check if the found object is a function and implement an argument to turn off the recursion, if desired.\n\nfget <- function(name, env = caller_env(), inherits = TRUE) {\n # Base case\n if (env_has(env, name)) {\n obj <- env_get(env, name)\n\n if (is.function(obj)) {\n return(obj)\n }\n }\n\n if (identical(env, emptyenv()) || !inherits) {\n stop(\"Could not find a function called \\\"\", name, \"\\\".\",\n call. = FALSE\n )\n }\n\n # Recursive Case\n fget(name, env_parent(env))\n}\n\n# Test\nmean <- 10\nfget(\"mean\", inherits = TRUE)\n#> function (x, ...) \n#> UseMethod(\"mean\")\n#> <bytecode: 0x590bfe4e2010>\n#> <environment: namespace:base>" + }, + { + "objectID": "07_Environments.html#special-environments", + "href": "07_Environments.html#special-environments", + "title": "7 Environments", + "section": "Special environments", + "text": "Special environments\nQ1: How is search_envs() different to env_parents(global_env())?\nA: search_envs() returns all the environments on the search path, which is “a chain of environments containing exported functions of attached packages” (from ?search_envs). Every time you attach a new package, this search path will grow. The search path ends with the base-environment. The global environment is included, because functions present in the global environment will always be part of the search path.\n\nsearch_envs()\n#> [[1]] $ <env: global>\n#> [[2]] $ <env: package:rlang>\n#> [[3]] $ <env: package:stats>\n#> [[4]] $ <env: package:graphics>\n#> [[5]] $ <env: package:grDevices>\n#> [[6]] $ <env: package:datasets>\n#> [[7]] $ <env: package:devtools>\n#> [[8]] $ <env: package:usethis>\n#> [[9]] $ <env: package:utils>\n#> [[10]] $ <env: package:methods>\n#> [[11]] $ <env: Autoloads>\n#> [[12]] $ <env: package:base>\n\nenv_parents(global_env()) will list all the ancestors of the global environment, therefore the global environment itself is not included. This also includes the “ultimate ancestor”, the empty environment. This environment is not considered part of the search path because it contains no objects.\n\nenv_parents(global_env())\n#> [[1]] $ <env: package:rlang>\n#> [[2]] $ <env: package:stats>\n#> [[3]] $ <env: package:graphics>\n#> [[4]] $ <env: package:grDevices>\n#> [[5]] $ <env: package:datasets>\n#> [[6]] $ <env: package:devtools>\n#> [[7]] $ <env: package:usethis>\n#> [[8]] $ <env: package:utils>\n#> [[9]] $ <env: package:methods>\n#> [[10]] $ <env: Autoloads>\n#> [[11]] $ <env: package:base>\n#> [[12]] $ <env: empty>\n\nQ2: Draw a diagram that shows the enclosing environments of this function:\n\nf1 <- function(x1) {\n f2 <- function(x2) {\n f3 <- function(x3) {\n x1 + x2 + x3\n }\n f3(3)\n }\n f2(2)\n}\nf1(1)\n\nA: This exercise urges us to think carefully about the function environment at creation time.\nWhen f1 is defined it binds its parent environment, which is the global environment. But f2 will only be created at runtime of f1 and will therefore bind f1’s execution environment. The value 1 will also bind to the name x1 at execution time. The same holds true for x2, f3 and x3.\nThe following diagram visualises the relations between the function environments.\n\n\n\n\n\n\n\n\n\nWe can also inspect the binding of the environments, adding print statements to the function definition. Please note that these print statements will be evaluated at execution time. Therefore, the execution of f1(1) will print different results each time we run it.\n\nf1 <- function(x1) {\n f2 <- function(x2) {\n f3 <- function(x3) {\n x1 + x2 + x3\n print(\"f3\")\n print(env_print())\n }\n f3(3)\n print(\"f2\")\n print(env_print())\n }\n f2(2)\n print(\"f1\")\n print(env_print())\n}\n\nf1(1)\n#> [1] \"f3\"\n#> <environment: 0x590bfc014578>\n#> Parent: <environment: 0x590bfc0143b8>\n#> Bindings:\n#> • x3: <dbl>\n#> <environment: 0x590bfc014578>\n#> [1] \"f2\"\n#> <environment: 0x590bfc0143b8>\n#> Parent: <environment: 0x590bfc013fc8>\n#> Bindings:\n#> • f3: <fn>\n#> • x2: <dbl>\n#> <environment: 0x590bfc0143b8>\n#> [1] \"f1\"\n#> <environment: 0x590bfc013fc8>\n#> Parent: <environment: global>\n#> Bindings:\n#> • f2: <fn>\n#> • x1: <dbl>\n#> <environment: 0x590bfc013fc8>\n\nQ3: Write an enhanced version of str() that provides more information about functions. Show where the function was found and what environment it was defined in.\nA: To solve this problem, we need to write a function that takes the name of a function and looks for that function returning both the function and the environment that it was found in.\n\nfget2 <- function(name, env = caller_env()) {\n # Base case\n if (env_has(env, name)) {\n obj <- env_get(env, name)\n\n if (is.function(obj)) {\n return(list(fun = obj, env = env))\n }\n }\n\n if (identical(env, emptyenv())) {\n stop(\"Could not find a function called \\\"\", name, \"\\\"\",\n call. = FALSE\n )\n }\n\n # Recursive Case\n fget2(name, env_parent(env))\n}\n\nfstr <- function(fun_name, env = caller_env()) {\n if (!is.character(fun_name) && length(fun_name) == 1) {\n stop(\"`fun_name` must be a string.\", call. = FALSE)\n }\n fun_env <- fget2(fun_name, env)\n\n list(\n where = fun_env$env,\n enclosing = fn_env(fun_env$fun)\n )\n}\n\n# Test\nfstr(\"mean\")\n#> $where\n#> <environment: base>\n#> \n#> $enclosing\n#> <environment: namespace:base>\n\nOnce you have learned about tidy evaluation, you could rewrite fstr() to use enquo() so that you’d call it more like str(), i.e. fstr(sum)." + }, + { + "objectID": "07_Environments.html#call-stacks", + "href": "07_Environments.html#call-stacks", + "title": "7 Environments", + "section": "Call stacks", + "text": "Call stacks\nQ1: Write a function that lists all the variables defined in the environment in which it was called. It should return the same results as ls().\nA: We can implement this dynamic scoping behaviour by explicitly referencing the caller environment. Please note that this approach returns also variables starting with a dot, an option that ls() usually requires.\n\nls2 <- function(env = caller_env()) {\n sort(env_names(env))\n}\n\n# Test in global environment\nls(all.names = TRUE)\n#> [1] \".main\" \".Random.seed\" \"%>%\" \"a\" \n#> [5] \"e1\" \"e1a\" \"e1b\" \"e1c\" \n#> [9] \"e2\" \"e3\" \"env_poke2\" \"error_wrap\" \n#> [13] \"f1\" \"fget\" \"fget2\" \"fstr\" \n#> [17] \"has_annotations\" \"ls2\" \"mean\" \"rebind\" \n#> [21] \"where\" \"where2\"\nls2()\n#> [1] \".main\" \".Random.seed\" \"%>%\" \"a\" \n#> [5] \"e1\" \"e1a\" \"e1b\" \"e1c\" \n#> [9] \"e2\" \"e3\" \"env_poke2\" \"error_wrap\" \n#> [13] \"f1\" \"fget\" \"fget2\" \"fstr\" \n#> [17] \"has_annotations\" \"ls2\" \"mean\" \"rebind\" \n#> [21] \"where\" \"where2\"\n\n# Test in \"sandbox\" environment\ne1 <- env(a = 1, b = 2)\nls(e1)\n#> [1] \"a\" \"b\"\nls2(e1)\n#> [1] \"a\" \"b\"" + }, + { + "objectID": "07_Environments.html#references", + "href": "07_Environments.html#references", + "title": "7 Environments", + "section": "References", + "text": "References\n\n\n\n\nHenry, Lionel, and Hadley Wickham. 2020. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang." + }, + { + "objectID": "08_Conditions.html#prerequisites", + "href": "08_Conditions.html#prerequisites", + "title": "8 - Conditions", + "section": "Prerequisites", + "text": "Prerequisites\nSimilar to the environments chapter, we also use functions from the {rlang} package to work with conditions.\n\nlibrary(rlang)" + }, + { + "objectID": "08_Conditions.html#signalling-conditions", + "href": "08_Conditions.html#signalling-conditions", + "title": "8 - Conditions", + "section": "Signalling conditions", + "text": "Signalling conditions\nQ1: Write a wrapper around file.remove() that throws an error if the file to be deleted does not exist.\nA: We prefer the following solution for its clarity and simplicity:\n\nfile_remove_strict <- function(path) {\n if (!file.exists(path)) {\n stop(\"Can't delete the file \\\"\", path,\n \"\\\" because it doesn't exist.\",\n call. = FALSE\n )\n }\n file.remove(path)\n}\n\n# Test\nsaveRDS(mtcars, \"mtcars.rds\")\nfile_remove_strict(\"mtcars.rds\")\n#> [1] TRUE\nfile_remove_strict(\"mtcars.rds\")\n#> Error: Can't delete the file \"mtcars.rds\" because it doesn't exist.\n\nQ2: What does the appendLF argument to message() do? How is it related to cat()?\nA: The appendLF argument automatically appends a new line to the message. Let’s illustrate this behaviour with a small example function:\n\nmultiline_msg <- function(appendLF = TRUE) {\n message(\"first\", appendLF = appendLF)\n message(\"second\", appendLF = appendLF)\n cat(\"third\")\n cat(\"fourth\")\n}\n\nmultiline_msg(appendLF = TRUE)\n#> first\n#> second\n#> thirdfourth\nmultiline_msg(appendLF = FALSE)\n#> firstsecondthirdfourth\n\nComparable behaviour regarding line breaks for cat() can be achieved via setting its sep argument to \"\\n\"." + }, + { + "objectID": "08_Conditions.html#handling-conditions", + "href": "08_Conditions.html#handling-conditions", + "title": "8 - Conditions", + "section": "Handling conditions", + "text": "Handling conditions\nQ1: What extra information does the condition generated by abort() contain compared to the condition generated by stop(), i.e. what’s the difference between these two objects? Read the help for ?abort to learn more.\n\ncatch_cnd(stop(\"An error\"))\ncatch_cnd(abort(\"An error\"))\n\nA: In contrast to stop(), which contains the call, abort() stores the whole backtrace generated by rlang::trace_back(). This is a lot of extra data!\n\nstr(catch_cnd(stop(\"An error\")))\n#> List of 2\n#> $ message: chr \"An error\"\n#> $ call : language force(expr)\n#> - attr(*, \"class\")= chr [1:3] \"simpleError\" \"error\" \"condition\"\n\nstr(catch_cnd(abort(\"An error\")))\n#> List of 5\n#> $ message: chr \"An error\"\n#> $ trace :Classes 'rlang_trace', 'rlib_trace', 'tbl' and 'data.frame': 9 obs...\n#> ..$ call :List of 9\n#> .. ..$ : language str(catch_cnd(abort(\"An error\")))\n#> .. ..$ : language catch_cnd(abort(\"An error\"))\n#> .. ..$ : language eval_bare(rlang::expr(tryCatch(!!!handlers, { force(ex..\n#> .. ..$ : language tryCatch(condition = `<fn>`, { force(expr) ...\n#> .. ..$ : language tryCatchList(expr, classes, parentenv, handlers)\n#> .. ..$ : language tryCatchOne(expr, names, parentenv, handlers[[1L]])\n#> .. ..$ : language doTryCatch(return(expr), name, parentenv, handler)\n#> .. ..$ : language force(expr)\n#> .. ..$ : language abort(\"An error\")\n#> ..$ parent : int [1:9] 0 0 2 2 4 5 6 2 0\n#> ..$ visible : logi [1:9] FALSE FALSE FALSE FALSE FALSE FALSE ...\n#> ..$ namespace : chr [1:9] \"utils\" \"rlang\" \"rlang\" \"base\" ...\n#> ..$ scope : chr [1:9] \"::\" \"::\" \"::\" \"::\" ...\n#> ..$ error_frame: logi [1:9] FALSE FALSE FALSE FALSE FALSE FALSE ...\n#> ..- attr(*, \"version\")= int 2\n#> $ parent : NULL\n#> $ rlang :List of 1\n#> ..$ inherit: logi TRUE\n#> $ call : NULL\n#> - attr(*, \"class\")= chr [1:3] \"rlang_error\" \"error\" \"condition\"\n\nQ2: Predict the results of evaluating the following code\n\nshow_condition <- function(code) {\n tryCatch(\n error = function(cnd) \"error\",\n warning = function(cnd) \"warning\",\n message = function(cnd) \"message\",\n {\n code\n NULL\n }\n )\n}\n\n\nshow_condition(stop(\"!\"))\nshow_condition(10)\nshow_condition(warning(\"?!\"))\nshow_condition({\n 10\n message(\"?\")\n warning(\"?!\")\n})\n\nA: The first three examples are straightforward:\n\nshow_condition(stop(\"!\")) # stop raises an error\n#> [1] \"error\"\nshow_condition(10) # no condition is signalled\n#> NULL\nshow_condition(warning(\"?!\")) # warning raises a warning\n#> [1] \"warning\"\n\nThe last example is the most interesting and makes us aware of the exiting qualities of tryCatch(); it will terminate the evaluation of the code as soon as it is called.\n\nshow_condition({\n 10\n message(\"?\")\n warning(\"?!\")\n})\n#> [1] \"message\"\n\nQ3: Explain the results of running this code:\n\nwithCallingHandlers( # (1)\n message = function(cnd) message(\"b\"),\n withCallingHandlers( # (2)\n message = function(cnd) message(\"a\"),\n message(\"c\")\n )\n)\n#> b\n#> a\n#> b\n#> c\n\nA: It’s a little tricky to untangle the flow here:\nFirst, message(\"c\") is run, and it’s caught by (1). It then calls message(\"a\"), which is caught by (2), which calls message(\"b\"). message(\"b\") isn’t caught by anything, so we see a b on the console, followed by a. But why do we get another b before we see c? That’s because we haven’t handled the message, so it bubbles up to the outer calling handler.\nQ4: Read the source code for catch_cnd() and explain how it works. At the time Advanced R was written, the source for catch_cnd() was a little simpler:\n\ncatch_cnd <- function(expr) {\n tryCatch(\n condition = function(cnd) cnd,\n {\n force(expr)\n return(NULL)\n }\n )\n}\n\nA: catch_cnd() is a simple wrapper around tryCatch(). If a condition is signalled, it’s caught and returned. If no condition is signalled, execution proceeds sequentially and the function returns NULL.\nThe current version of catch_cnd() is a little more complex because it allows you to specify which classes of condition you want to capture. This requires some manual code generation because the interface of tryCatch() provides condition classes as argument names.\n\nrlang::catch_cnd\n#> function (expr, classes = \"condition\") \n#> {\n#> stopifnot(is_character(classes))\n#> handlers <- rep_named(classes, list(identity))\n#> eval_bare(rlang::expr(tryCatch(!!!handlers, {\n#> force(expr)\n#> return(NULL)\n#> })))\n#> }\n#> <bytecode: 0x59a31a9d0fd8>\n#> <environment: namespace:rlang>\n\nQ5: How could you rewrite show_condition() to use a single handler?\nA: show_condition() was defined in one of the previous questions. Let’s use the condition argument of tryCatch() as shown in rlang::catch_cond() above for our re-implementation:\n\nshow_condition2 <- function(code) {\n tryCatch(\n condition = function(cnd) {\n if (inherits(cnd, \"error\")) {\n return(\"error\")\n }\n if (inherits(cnd, \"warning\")) {\n return(\"warning\")\n }\n if (inherits(cnd, \"message\")) {\n return(\"message\")\n }\n },\n {\n code\n NULL\n }\n )\n}\n\n# Test\nshow_condition2(stop(\"!\"))\n#> [1] \"error\"\nshow_condition2(10)\n#> NULL\nshow_condition2(warning(\"?!\"))\n#> [1] \"warning\"\nshow_condition2({\n 10\n message(\"?\")\n warning(\"?!\")\n})\n#> [1] \"message\"\n\ntryCatch() executes the code and captures any condition raised. The function provided as the condition handles this condition. In this case it dispatches on the class of the condition." + }, + { + "objectID": "08_Conditions.html#custom-conditions", + "href": "08_Conditions.html#custom-conditions", + "title": "8 - Conditions", + "section": "Custom conditions", + "text": "Custom conditions\nQ1: Inside a package, it’s occasionally useful to check that a package is installed before using it. Write a function that checks if a package is installed (with requireNamespace(\"pkg\", quietly = FALSE)) and if not, throws a custom condition that includes the package name in the metadata.\nA: We use rlang::abort() to supply error metadata:\n\ncheck_installed <- function(package) {\n if (!requireNamespace(package, quietly = FALSE)) {\n abort(\n \"error_pkg_not_found\",\n message = paste0(\"package '\", package, \"' not installed.\"),\n package = package\n )\n }\n\n TRUE\n}\n\ncheck_installed(\"ggplot2\")\n#> [1] TRUE\ncheck_installed(\"ggplot3\")\n#> Loading required namespace: ggplot3\n#> Error in `check_installed()`:\n#> ! package 'ggplot3' not installed.\n\nQ2: Inside a package you often need to stop with an error when something is not right. Other packages that depend on your package might be tempted to check these errors in their unit tests. How could you help these packages to avoid relying on the error message which is part of the user interface rather than the API and might change without notice?\nA: Instead of returning an error it might be preferable to throw a customised condition and place a standardised error message inside the metadata. Then the downstream package could check for the class of the condition, rather than inspecting the message." + }, + { + "objectID": "08_Conditions.html#applications", + "href": "08_Conditions.html#applications", + "title": "8 - Conditions", + "section": "Applications", + "text": "Applications\nQ1: Create suppressConditions() that works like suppressMessages() and suppressWarnings() but suppresses everything. Think carefully about how you should handle errors.\nA: In general, we would like to catch errors, since they contain important information for debugging. To suppress the error message and hide the returned error object from the console, we handle errors within a tryCatch() and return the error object invisibly:\n\nsuppressErrors <- function(expr) {\n tryCatch(\n error = function(cnd) invisible(cnd),\n interrupt = function(cnd) {\n stop(\"Terminated by the user.\",\n call. = FALSE\n )\n },\n expr\n )\n}\n\nAfter we defined the error handling, we can just combine it with the other handlers to create suppressConditions():\n\nsuppressConditions <- function(expr) {\n suppressErrors(suppressWarnings(suppressMessages(expr)))\n}\n\nTo test the new function, we apply it to a set of conditions and inspect the returned error object.\n\n# The messages/warnings/conditions are suppressed successfully\nerror_obj <- suppressConditions({\n message(\"message\")\n warning(\"warning\")\n abort(\"error\")\n})\n\nerror_obj\n#> <error/rlang_error>\n#> Error:\n#> ! error\n#> ---\n#> Backtrace:\n#> ▆\n\nQ2: Compare the following two implementations of message2error(). What is the main advantage of withCallingHandlers() in this scenario? (Hint: look carefully at the traceback.)\n\nmessage2error <- function(code) {\n withCallingHandlers(code, message = function(e) stop(e))\n}\nmessage2error <- function(code) {\n tryCatch(code, message = function(e) stop(e))\n}\n\nA: Both functions differ in the way conditions are handled. withCallingHandlers() creates a calling handler, which is executed from within the signalling function. This makes it possible to record a detailed call stack, which helps us identify the signalling condition.\ntryCatch() defines an exiting handler, which means that the signalling function is terminated as soon as a condition is raised. It also returns control to the context where tryCatch() was called.\nIn this example the use of withCallingHandlers() returns more information than the use of tryCatch(). This allows us to determine the exact call that raised the condition.\n\nmessage2error1 <- function(code) {\n withCallingHandlers(code, message = function(e) stop(\"error\"))\n}\n\nmessage2error1({\n 1\n message(\"hidden error\")\n NULL\n})\n#> Error in (function (e) : error\ntraceback()\n#> 9: stop(\"error\") at #2\n#> 8: (function (e)\n#> stop(\"error\"))(list(message = \"hidden error\\n\",\n#> call = message(\"hidden error\")))\n#> 7: signalCondition(cond)\n#> 6: doWithOneRestart(return(expr), restart)\n#> 5: withOneRestart(expr, restarts[[1L]])\n#> 4: withRestarts({\n#> signalCondition(cond)\n#> defaultHandler(cond)\n#> }, muffleMessage = function() NULL)\n#> 3: message(\"hidden error\") at #1\n#> 2: withCallingHandlers(code,\n#> message = function(e) stop(\"error\")) at #2\n#> 1: message2error1({\n#> 1\n#> message(\"hidden error\")\n#> NULL\n#> })\n\n\nmessage2error2 <- function(code) {\n tryCatch(code, message = function(e) (stop(\"error\")))\n}\n\nmessage2error2({\n 1\n stop(\"hidden error\")\n NULL\n})\n#> Error in value[[3L]](cond) : error\ntraceback()\n#> 6: stop(\"error\") at #2\n#> 5: value[[3L]](cond)\n#> 4: tryCatchOne(expr, names, parentenv, handlers[[1L]])\n#> 3: tryCatchList(expr, classes, parentenv, handlers)\n#> 2: tryCatch(code, message = function(e) (stop(\"error\"))) at #2\n#> 1: message2error2({\n#> 1\n#> message(\"hidden error\")\n#> NULL\n#> })\n\nQ3: How would you modify the catch_cnds() definition if you wanted to recreate the original intermingling of warnings and messages?\nA: It looks like Hadley wrote a part of the chapter after the exercises, as the catch_cnds() function defined in the chapter already solves this problem by storing all messages and warnings in their original order within a list.\n\ncatch_cnds <- function(expr) {\n conds <- list()\n add_cond <- function(cnd) {\n conds <<- append(conds, list(cnd))\n cnd_muffle(cnd)\n }\n\n tryCatch(\n error = function(cnd) {\n conds <<- append(conds, list(cnd))\n },\n withCallingHandlers(\n message = add_cond,\n warning = add_cond,\n expr\n )\n )\n\n conds\n}\n\n# Test\ncatch_cnds({\n inform(\"message a\")\n warn(\"warning b\")\n inform(\"message c\")\n})\n#> [[1]]\n#> <message/rlang_message>\n#> Message:\n#> message a\n#> \n#> [[2]]\n#> <warning/rlang_warning>\n#> Warning:\n#> warning b\n#> \n#> [[3]]\n#> <message/rlang_message>\n#> Message:\n#> message c\n\nQ4: Why is catching interrupts dangerous? Run this code to find out.\n\nbottles_of_beer <- function(i = 99) {\n message(\n \"There are \", i,\n \" bottles of beer on the wall, \", i,\n \" bottles of beer.\"\n )\n while (i > 0) {\n tryCatch(\n Sys.sleep(1),\n interrupt = function(err) {\n i <<- i - 1\n if (i > 0) {\n message(\n \"Take one down, pass it around, \", i,\n \" bottle\", if (i > 1) \"s\", \" of beer on the wall.\"\n )\n }\n }\n )\n }\n message(\n \"No more bottles of beer on the wall, \",\n \"no more bottles of beer.\"\n )\n}\n\nA: When running the bottles_of_beer() function in your console, the output should look somehow like the following:\n\nbottles_of_beer()\n#> There are 99 bottles of beer on the wall, 99 bottles of beer.\n#> Take one down, pass it around, 98 bottles of beer on the wall.\n#> Take one down, pass it around, 97 bottles of beer on the wall.\n#> Take one down, pass it around, 96 bottles of beer on the wall.\n#> Take one down, pass it around, 95 bottles of beer on the wall.\n#>\n\nAt this point you’ll probably recognise how hard it is to get the number of bottles down from 99 to 0. There’s no way to break out of the function because we’re capturing the interrupt that you’d usually use!" + }, + { + "objectID": "09_Functionals.html#prerequisites", + "href": "09_Functionals.html#prerequisites", + "title": "9 - Functionals", + "section": "Prerequisites", + "text": "Prerequisites\nFor the functional programming part of the book, we will mainly use functions from the {purrr} package (Henry and Wickham 2020).\n\nlibrary(purrr)" + }, + { + "objectID": "09_Functionals.html#my-first-functional-map", + "href": "09_Functionals.html#my-first-functional-map", + "title": "9 - Functionals", + "section": "My first functional: map()", + "text": "My first functional: map()\nQ1: Use as_mapper() to explore how {purrr} generates anonymous functions for the integer, character, and list helpers. What helper allows you to extract attributes? Read the documentation to find out.\nA: map() offers multiple ways (functions, formulas, and extractor functions) to specify its function argument (.f). Initially, the various inputs have to be transformed into a valid function, which is then applied. The creation of this valid function is the job of as_mapper() and it is called every time map() is used.\nGiven character, numeric or list input as_mapper() will create an extractor function. Characters select by name, while numeric input selects by positions and a list allows a mix of these two approaches. This extractor interface can be very useful, when working with nested data.\nThe extractor function is implemented as a call to purrr::pluck(), which accepts a list of accessors (accessors “access” some part of your data object).\n\nas_mapper(c(1, 2)) # equivalent to function(x) x[[1]][[2]]\n#> function (x, ...) \n#> pluck_raw(x, list(1, 2), .default = NULL)\n#> <environment: 0x5d63c648c988>\nas_mapper(c(\"a\", \"b\")) # equivalent to function(x) x[[\"a\"]][[\"b]]\n#> function (x, ...) \n#> pluck_raw(x, list(\"a\", \"b\"), .default = NULL)\n#> <environment: 0x5d63c64eb4d0>\nas_mapper(list(1, \"b\")) # equivalent to function(x) x[[1]][[\"b]]\n#> function (x, ...) \n#> pluck_raw(x, list(1, \"b\"), .default = NULL)\n#> <environment: 0x5d63c660f0b8>\n\nBesides mixing positions and names, it is also possible to pass along an accessor function. This is basically an anonymous function that gets information about some aspect of the input data. You are free to define your own accessor functions.\nIf you need to access certain attributes, the helper attr_getter(y) is already predefined and will create the appropriate accessor function for you.\n\n# Define custom accessor function\nget_class <- function(x) attr(x, \"class\")\npluck(mtcars, get_class)\n#> [1] \"data.frame\"\n\n# Use attr_getter() as a helper\npluck(mtcars, attr_getter(\"class\"))\n#> [1] \"data.frame\"\n\nQ2: map(1:3, ~ runif(2)) is a useful pattern for generating random numbers, but map(1:3, runif(2)) is not. Why not? Can you explain why it returns the result that it does?\nA: The first pattern creates multiple random numbers, because ~ runif(2) successfully uses the formula interface. Internally map() applies as_mapper() to this formula, which converts ~ runif(2) into an anonymous function. Afterwards runif(2) is applied three times (one time during each iteration), leading to three different pairs of random numbers.\nIn the second pattern runif(2) is evaluated once, then the results are passed to map(). Consequently as_mapper() creates an extractor function based on the return values from runif(2) (via pluck()). This leads to three NULLs (pluck()’s .default return), because no values corresponding to the index can be found.\n\nas_mapper(~ runif(2))\n#> <lambda>\n#> function (..., .x = ..1, .y = ..2, . = ..1) \n#> runif(2)\n#> attr(,\"class\")\n#> [1] \"rlang_lambda_function\" \"function\"\nas_mapper(runif(2))\n#> function (x, ...) \n#> pluck_raw(x, list(0.0807501375675201, 0.834333037259057), .default = NULL)\n#> <environment: 0x5d63c462a700>\n\nQ3: Use the appropriate map() function to:\n\nCompute the standard deviation of every column in a numeric data frame.\nCompute the standard deviation of every numeric column in a mixed data frame. (Hint: you’ll need to do it in two steps.)\nCompute the number of levels for every factor in a data frame.\n\nA: To solve this exercise we take advantage of calling the type stable variants of map(), which give us more concise output, and use map_lgl() to select the columns of the data frame (later you’ll learn about keep(), which simplifies this pattern a little).\n\nmap_dbl(mtcars, sd)\n#> mpg cyl disp hp drat wt qsec vs am gear \n#> 6.027 1.786 123.939 68.563 0.535 0.978 1.787 0.504 0.499 0.738 \n#> carb \n#> 1.615\n\npenguins <- palmerpenguins::penguins\n\npenguins_numeric <- map_lgl(penguins, is.numeric)\nmap_dbl(penguins[penguins_numeric], sd, na.rm = TRUE)\n#> bill_length_mm bill_depth_mm flipper_length_mm body_mass_g \n#> 5.460 1.975 14.062 801.955 \n#> year \n#> 0.818\n\npenguins_factor <- map_lgl(penguins, is.factor)\nmap_int(penguins[penguins_factor], ~ length(levels(.x)))\n#> species island sex \n#> 3 3 2\n\nQ4: The following code simulates the performance of a t-test for non-normal data. Extract the p-value from each test, then visualise.\n\ntrials <- map(1:100, ~ t.test(rpois(10, 10), rpois(10, 7)))\n\nA: There are many ways to visualise this data. However, since there are only 100 data points, we choose a dot plot to visualise the distribution. (Unfortunately, {ggplot2}s geom_dotplot() doesn’t compute proper counts as it was created to visualise distribution densities instead of frequencies, so a histogram would be a suitable alternative).\n\nlibrary(ggplot2)\n\ndf_trials <- tibble::tibble(p_value = map_dbl(trials, \"p.value\"))\n\ndf_trials %>%\n ggplot(aes(x = p_value, fill = p_value < 0.05)) +\n geom_dotplot(binwidth = .01) + # geom_histogram() as alternative\n theme(\n axis.text.y = element_blank(),\n axis.ticks.y = element_blank(),\n legend.position = \"top\"\n )\n\n\n\n\n\n\n\n\nQ5: The following code uses a map nested inside another map to apply a function to every element of a nested list. Why does it fail, and what do you need to do to make it work?\n\nx <- list(\n list(1, c(3, 9)),\n list(c(3, 6), 7, c(4, 7, 6))\n)\n\ntriple <- function(x) x * 3\nmap(x, map, .f = triple)\n#> Error in `map()`:\n#> ℹ In index: 1.\n#> Caused by error in `.f()`:\n#> ! unused argument (function (.x, .f, ..., .progress = FALSE) \n#> {\n#> map_(\"list\", .x, .f, ..., .progress = .progress)\n#> })\n\nA: This function call fails, because triple() is specified as the .f argument and consequently belongs to the outer map(). The unnamed argument map is treated as an argument of triple(), which causes the error.\nThere are a number of ways we could resolve the problem. However, there is not much to choose between them for this simple example, although it is good to know your options for more complicated cases.\n\n# Don't name the argument\nmap(x, map, triple)\n\n# Use magrittr-style anonymous function\nmap(x, . %>% map(triple))\n\n# Use purrr-style anonymous function\nmap(x, ~ map(.x, triple))\n\nQ6: Use map() to fit linear models to the mtcars dataset using the formulas stored in this list:\n\nformulas <- list(\n mpg ~ disp,\n mpg ~ I(1 / disp),\n mpg ~ disp + wt,\n mpg ~ I(1 / disp) + wt\n)\n\nA: The data (mtcars) is constant for all these models and so we iterate over the formulas provided. As the formula is the first argument of lm(), we don’t need to specify it explicitly.\n\nmodels <- map(formulas, lm, data = mtcars)\n\nQ7: Fit the model mpg ~ disp to each of the bootstrap replicates of mtcars in the list below, then extract the \\(R^2\\) of the model fit (Hint: you can compute the \\(R^2\\) with summary())\n\nbootstrap <- function(df) {\n df[sample(nrow(df), replace = TRUE), , drop = FALSE]\n}\n\nbootstraps <- map(1:10, ~ bootstrap(mtcars))\n\nA: To accomplish this task, we take advantage of the “list in, list out”-functionality of map(). This allows us to chain multiple transformations together. We start by fitting the models. We then calculate the summaries and extract the \\(R^2\\) values. For the last call we use map_dbl(), which provides convenient output.\n\nbootstraps %>%\n map(~ lm(mpg ~ disp, data = .x)) %>%\n map(summary) %>%\n map_dbl(\"r.squared\")\n#> [1] 0.588 0.822 0.745 0.746 0.784 0.749 0.613 0.792 0.653 0.726" + }, + { + "objectID": "09_Functionals.html#map-variants", + "href": "09_Functionals.html#map-variants", + "title": "9 - Functionals", + "section": "Map variants", + "text": "Map variants\nQ1: Explain the results of modify(mtcars, 1).\nA: modify() is based on map(), and in this case, the extractor interface will be used. It extracts the first element of each column in mtcars. modify() always returns the same structure as its input: in this case it forces the first row to be recycled 32 times. (Internally modify() uses .x[] <- map(.x, .f, ...) for assignment.)\n\nhead(modify(mtcars, 1))\n#> mpg cyl disp hp drat wt qsec vs am gear carb\n#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n#> 2 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n#> 3 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n#> 4 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n#> 5 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n#> 6 21 6 160 110 3.9 2.62 16.5 0 1 4 4\n\nQ2: Rewrite the following code to use iwalk() instead of walk2(). What are the advantages and disadvantages?\n\ncyls <- split(mtcars, mtcars$cyl)\npaths <- file.path(temp, paste0(\"cyl-\", names(cyls), \".csv\"))\nwalk2(cyls, paths, write.csv)\n\nA: iwalk() allows us to use a single variable, storing the output path in the names.\n\ntemp <- tempfile()\ndir.create(temp)\n\ncyls <- split(mtcars, mtcars$cyl)\nnames(cyls) <- file.path(temp, paste0(\"cyl-\", names(cyls), \".csv\"))\niwalk(cyls, ~ write.csv(.x, .y))\n\nWe could do this in a single pipe by taking advantage of set_names():\n\nmtcars %>%\n split(mtcars$cyl) %>%\n set_names(~ file.path(temp, paste0(\"cyl-\", .x, \".csv\"))) %>%\n iwalk(~ write.csv(.x, .y))\n\nQ3: Explain how the following code transforms a data frame using functions stored in a list.\n\ntrans <- list(\n disp = function(x) x * 0.0163871,\n am = function(x) factor(x, labels = c(\"auto\", \"manual\"))\n)\n\nnm <- names(trans)\nmtcars[nm] <- map2(trans, mtcars[nm], function(f, var) f(var))\n\nCompare and contrast the map2() approach to this map() approach:\n\nmtcars[nm] <- map(nm, ~ trans[[.x]](mtcars[[.x]]))\n\nA: In the first approach\n\nmtcars[nm] <- map2(trans, mtcars[nm], function(f, var) f(var))\n\nthe list of the 2 functions (trans) and the 2 appropriately selected data frame columns (mtcars[nm]) are supplied to map2(). map2() creates an anonymous function (f(var)) which applies the functions to the variables when map2() iterates over their (similar) indices. On the left-hand side, the respective 2 elements of mtcars are being replaced by their new transformations.\nThe map() variant\n\nmtcars[nm] <- map(nm, ~ trans[[.x]](mtcars[[.x]]))\n\ndoes basically the same. However, it directly iterates over the names (nm) of the transformations. Therefore, the data frame columns are selected during the iteration.\nBesides the iteration pattern, the approaches differ in the possibilities for appropriate argument naming in the .f argument. In the map2() approach we iterate over the elements of x and y. Therefore, it is possible to choose appropriate placeholders like f and var. This makes the anonymous function more expressive at the cost of making it longer. We think using the formula interface in this way is preferable compared to the rather cryptic mtcars[nm] <- map2(trans, mtcars[nm], ~ .x(.y)).\nIn the map() approach we map over the variable names. It is therefore not possible to introduce placeholders for the function and variable names. The formula syntax together with the .x pronoun is pretty compact. The object names and the brackets clearly indicate the application of transformations to specific columns of mtcars. In this case the iteration over the variable names comes in handy, as it highlights the importance of matching between trans and mtcars element names. Together with the replacement form on the left-hand side, this line is relatively easy to inspect.\nTo summarise, in situations where map() and map2() provide solutions for an iteration problem, several points may be considered before deciding for one or the other approach.\nQ4: What does write.csv() return, i.e. what happens if you use it with map2() instead of walk2()?\nA: write.csv() returns NULL. As we call the function for its side effect (creating a CSV file), walk2() would be appropriate here. Otherwise, we receive a rather uninformative list of NULLs.\n\ncyls <- split(mtcars, mtcars$cyl)\npaths <- file.path(tempdir(), paste0(\"cyl-\", names(cyls), \".csv\"))\n\nmap2(cyls, paths, write.csv)\n#> $`4`\n#> NULL\n#> \n#> $`6`\n#> NULL\n#> \n#> $`8`\n#> NULL" + }, + { + "objectID": "09_Functionals.html#predicate-functionals", + "href": "09_Functionals.html#predicate-functionals", + "title": "9 - Functionals", + "section": "Predicate functionals", + "text": "Predicate functionals\nQ1: Why isn’t is.na() a predicate function? What base R function is closest to being a predicate version of is.na()?\nA: is.na() is not a predicate function, because it returns a logical vector the same length as the input, not a single TRUE or FALSE.\nanyNA() is the closest equivalent because it always returns a single TRUE or FALSE if there are any missing values present. You could also imagine an allNA() which would return TRUE if all values were missing, but that’s considerably less useful so base R does not provide it.\nQ2: simple_reduce() has a problem when x is length 0 or length 1. Describe the source of the problem and how you might go about fixing it.\n\nsimple_reduce <- function(x, f) {\n out <- x[[1]]\n for (i in seq(2, length(x))) {\n out <- f(out, x[[i]])\n }\n out\n}\n\nA: The loop inside simple_reduce() always starts with the index 2, and seq() can count both up and down:\n\nseq(2, 0)\n#> [1] 2 1 0\nseq(2, 1)\n#> [1] 2 1\n\nTherefore, subsetting length-0 and length-1 vectors via [[ will lead to a subscript out of bounds error. To avoid this, we allow simple_reduce() to return before the for loop is started and include a default argument for 0-length vectors.\n\nsimple_reduce <- function(x, f, default) {\n if (length(x) == 0L) {\n return(default)\n }\n if (length(x) == 1L) {\n return(x[[1L]])\n }\n\n out <- x[[1]]\n for (i in seq(2, length(x))) {\n out <- f(out, x[[i]])\n }\n out\n}\n\nOur new simple_reduce() now works as intended:\n\nsimple_reduce(integer(0), `+`)\n#> Error in simple_reduce(integer(0), `+`): argument \"default\" is missing, with no default\nsimple_reduce(integer(0), `+`, default = 0L)\n#> [1] 0\nsimple_reduce(1, `+`)\n#> [1] 1\nsimple_reduce(1:3, `+`)\n#> [1] 6\n\nQ3: Implement the span() function from Haskell: given a list x and a predicate function f, span(x, f) returns the location of the longest sequential run of elements where the predicate is true. (Hint: you might find rle() helpful.)\nA: Our span_r() function returns the indices of the (first occurring) longest sequential run of elements where the predicate is true. If the predicate is never true, the longest run has length 0, in which case we return integer(0).\n\nspan_r <- function(x, f) {\n idx <- unname(map_lgl(x, ~ f(.x)))\n rle <- rle(idx)\n\n # Check if the predicate is never true\n if (!any(rle$values)) {\n return(integer(0))\n }\n\n # Find the length of the longest sequence of true values\n longest <- max(rle$lengths[rle$values])\n # Find the positition of the (first) longest run in rle\n longest_idx <- which(rle$values & rle$lengths == longest)[1]\n\n # Add up all lengths in rle before the longest run\n ind_before_longest <- sum(rle$lengths[seq_len(longest_idx - 1)])\n\n out_start <- ind_before_longest + 1L\n out_end <- ind_before_longest + longest\n out_start:out_end\n}\n\n# Check that it works\nspan_r(c(0, 0, 0, 0, 0), is.na)\n#> integer(0)\nspan_r(c(NA, 0, 0, 0, 0), is.na)\n#> [1] 1\nspan_r(c(NA, 0, NA, NA, NA), is.na)\n#> [1] 3 4 5\n\nQ4: Implement arg_max(). It should take a function and a vector of inputs, and return the elements of the input where the function returns the highest value. For example, arg_max(-10:5, function(x) x ^ 2) should return -10. arg_max(-5:5, function(x) x ^ 2) should return c(-5, 5). Also implement the matching arg_min() function.\nA: Both functions take a vector of inputs and a function as an argument. The function output is then used to subset the input accordingly.\n\narg_max <- function(x, f) {\n y <- map_dbl(x, f)\n x[y == max(y)]\n}\n\narg_min <- function(x, f) {\n y <- map_dbl(x, f)\n x[y == min(y)]\n}\n\narg_max(-10:5, function(x) x^2)\n#> [1] -10\narg_min(-10:5, function(x) x^2)\n#> [1] 0\n\nQ5: The function below scales a vector so it falls in the range [0, 1]. How would you apply it to every column of a data frame? How would you apply it to every numeric column in a data frame?\n\nscale01 <- function(x) {\n rng <- range(x, na.rm = TRUE)\n (x - rng[1]) / (rng[2] - rng[1])\n}\n\nA: To apply a function to every column of a data frame, we can use purrr::modify() (or purrr::map_dfr()), which also conveniently returns a data frame. To limit the application to numeric columns, the scoped version modify_if() can be used.\n\nmodify_if(mtcars, is.numeric, scale01)" + }, + { + "objectID": "09_Functionals.html#base-functionals", + "href": "09_Functionals.html#base-functionals", + "title": "9 - Functionals", + "section": "Base functionals", + "text": "Base functionals\nQ1: How does apply() arrange the output? Read the documentation and perform some experiments.\nA: Basically apply() applies a function over the margins of an array. In the two-dimensional case, the margins are just the rows and columns of a matrix. Let’s make this concrete.\n\narr2 <- array(1:12, dim = c(3, 4))\nrownames(arr2) <- paste0(\"row\", 1:3)\ncolnames(arr2) <- paste0(\"col\", 1:4)\narr2\n#> col1 col2 col3 col4\n#> row1 1 4 7 10\n#> row2 2 5 8 11\n#> row3 3 6 9 12\n\nWhen we apply the head() function over the first margin of arr2() (i.e. the rows), the results are contained in the columns of the output, transposing the array compared to the original input.\n\napply(arr2, 1, function(x) x[1:2])\n#> row1 row2 row3\n#> col1 1 2 3\n#> col2 4 5 6\n\nAnd vice versa if we apply over the second margin (the columns):\n\napply(arr2, 2, function(x) x[1:2])\n#> col1 col2 col3 col4\n#> row1 1 4 7 10\n#> row2 2 5 8 11\n\nThe output of apply() is organised first by the margins being operated over, then the results of the function. This can become quite confusing for higher dimensional arrays.\nQ2: What do eapply() and rapply() do? Does {purrr} have equivalents?\nA: eapply() is a variant of lapply(), which iterates over the (named) elements of an environment. In {purrr} there is no equivalent for eapply() as {purrr} mainly provides functions that operate on vectors and functions, but not on environments.\nrapply() applies a function to all elements of a list recursively. This function makes it possible to limit the application of the function to specified classes (default classes = ANY). One may also specify how elements of other classes should remain: as their identity (how = replace) or another value (default = NULL). The closest equivalent in {purrr} is modify_depth(), which allows you to modify elements at a specified depth in a nested list.\nQ3: Challenge: read about the fixed point algorithm. Complete the exercises using R.\nA: A number \\(x\\) is called a fixed point of a function \\(f\\) if it satisfies the equation \\(f(x) = x\\). For some functions we may find a fixed point by beginning with a starting value and applying \\(f\\) repeatedly. Here fixed_point() acts as a functional because it takes a function as an argument.\n\nfixed_point <- function(f, x_init, n_max = 10000, tol = 0.0001) {\n n <- 0\n x <- x_init\n y <- f(x)\n\n is_fixed_point <- function(x, y) {\n abs(x - y) < tol\n }\n\n while (!is_fixed_point(x, y)) {\n x <- y\n y <- f(y)\n\n # Make sure we eventually stop\n n <- n + 1\n if (n > n_max) {\n stop(\"Failed to converge.\", call. = FALSE)\n }\n }\n\n x\n}\n\n\n# Functions with fixed points\nfixed_point(sin, x_init = 1)\n#> [1] 0.0843\nfixed_point(cos, x_init = 1)\n#> [1] 0.739\n\n# Functions without fixed points\nadd_one <- function(x) x + 1\nfixed_point(add_one, x_init = 1)\n#> Error: Failed to converge." + }, + { + "objectID": "09_Functionals.html#references", + "href": "09_Functionals.html#references", + "title": "9 - Functionals", + "section": "References", + "text": "References\n\n\n\n\nHenry, Lionel, and Hadley Wickham. 2020. Purrr: Functional Programming Tools. https://github.com/tidyverse/purrr." + }, + { + "objectID": "10_Function_factories.html#prerequisites", + "href": "10_Function_factories.html#prerequisites", + "title": "10 - Function factories", + "section": "Prerequisites", + "text": "Prerequisites\nFor most of this chapter base R (R Core Team 2020) is sufficient. Just a few exercises require the {rlang} (Henry and Wickham 2020b), {dplyr} (Wickham et al. 2020), {purrr} (Henry and Wickham 2020a) and {ggplot2} (Wickham 2016) packages.\n\nlibrary(rlang)\nlibrary(dplyr)\nlibrary(purrr)\nlibrary(ggplot2)" + }, + { + "objectID": "10_Function_factories.html#factory-fundamentals", + "href": "10_Function_factories.html#factory-fundamentals", + "title": "10 - Function factories", + "section": "Factory fundamentals", + "text": "Factory fundamentals\nQ1: The definition of force() is simple:\n\nforce\n#> function (x) \n#> x\n#> <bytecode: 0x5f56c3bd90f0>\n#> <environment: namespace:base>\n\nWhy is it better to force(x) instead of just x?\nA: As you can see force(x) is similar to x. As mentioned in Advanced R, we prefer this explicit form, because\n\nusing this function clearly indicates that you’re forcing evaluation, not that you’ve accidentally typed x.”\n\nQ2: Base R contains two function factories, approxfun() and ecdf(). Read their documentation and experiment to figure out what the functions do and what they return.\nA: Let’s begin with approxfun() as it is used within ecdf() as well:\napproxfun() takes a combination of data points (x and y values) as input and returns a stepwise linear (or constant) interpolation function. To find out what this means exactly, we first create a few random data points.\n\nx <- runif(10)\ny <- runif(10)\nplot(x, y, lwd = 10)\n\n\n\n\n\n\n\n\nNext, we use approxfun() to construct the linear and constant interpolation functions for our x and y values.\n\nf_lin <- approxfun(x, y)\nf_con <- approxfun(x, y, method = \"constant\")\n\n# Both functions exactly reproduce their input y values\nidentical(f_lin(x), y)\n#> [1] TRUE\nidentical(f_con(x), y)\n#> [1] TRUE\n\nWhen we apply these functions to new x values, these are mapped to the lines connecting the initial y values (linear case) or to the same y value as for the next smallest initial x value (constant case).\n\nx_new <- runif(1000)\n\nplot(x, y, lwd = 10)\npoints(x_new, f_lin(x_new), col = \"cornflowerblue\", pch = 16)\npoints(x_new, f_con(x_new), col = \"firebrick\", pch = 16)\n\n\n\n\n\n\n\n\nHowever, both functions are only defined within range(x).\n\nf_lin(range(x))\n#> [1] 0.402 0.175\nf_con(range(x))\n#> [1] 0.402 0.175\n\n(eps <- .Machine$double.neg.eps)\n#> [1] 1.11e-16\n\nf_lin(c(min(x) - eps, max(x) + eps))\n#> [1] NA NA\nf_con(c(min(x) - eps, max(x) + eps))\n#> [1] NA NA\n\nTo change this behaviour, one can set rule = 2. This leads to the result that for values outside of range(x) the boundary values of the function are returned.\n\nf_lin <- approxfun(x, y, rule = 2)\nf_con <- approxfun(x, y, method = \"constant\", rule = 2)\n\nf_lin(c(-Inf, Inf))\n#> [1] 0.402 0.175\nf_con(c(-Inf, Inf))\n#> [1] 0.402 0.175\n\nAnother option is to customise the return values as individual constants for each side via yleft and/or yright.\n\nf_lin <- approxfun(x, y, yleft = 5)\nf_con <- approxfun(x, y, method = \"constant\", yleft = 5, yright = -5)\n\nf_lin(c(-Inf, Inf))\n#> [1] 5 NA\nf_con(c(-Inf, Inf))\n#> [1] 5 -5\n\nFurther, approxfun() provides the option to shift the y values for method = \"constant\" between their left and right values. According to the documentation this indicates a compromise between left- and right-continuous steps.\n\nf_con <- approxfun(x, y, method = \"constant\", f = .5)\n\nplot(x, y, lwd = 10)\npoints(x_new, f_con(x_new), pch = 16)\n\n\n\n\n\n\n\n\nFinally, the ties argument allows to aggregate y values if multiple ones were provided for the same x value. For example, in the following line we use mean() to aggregate these y values before they are used for the interpolation approxfun(x = c(1,1,2), y = 1:3, ties = mean).\nNext, we focus on ecdf(). “ecdf” is an acronym for empirical cumulative distribution function. For a numeric vector of density values, ecdf() initially creates the (x, y) pairs for the nodes of the density function and then passes these pairs to approxfun(), which gets called with specifically adapted settings (approxfun(vals, cumsum(tabulate(match(x, vals)))/n, method = \"constant\", yleft = 0, yright = 1, f = 0, ties = \"ordered\")).\n\nx <- runif(10)\nf_ecdf <- ecdf(x)\nclass(f_ecdf)\n#> [1] \"ecdf\" \"stepfun\" \"function\"\n\nplot(x, f_ecdf(x), lwd = 10, ylim = 0:1)\n\n\n\n\n\n\n\n\nNew values are then mapped on the y value of the next smallest x value from within the initial input.\n\nx_new <- runif(1000)\n\nplot(x, f_ecdf(x), lwd = 10, ylim = 0:1)\npoints(x_new, f_ecdf(x_new), ylim = 0:1)\n\n\n\n\n\n\n\n\nQ3: Create a function pick() that takes an index, i, as an argument and returns a function with an argument x that subsets x with i.\n\npick(1)(x)\n# should be equivalent to\nx[[1]]\n\nlapply(mtcars, pick(5))\n# should be equivalent to\nlapply(mtcars, function(x) x[[5]])\n\nA: In this exercise pick(i) acts as a function factory, which returns the required subsetting function.\n\npick <- function(i) {\n force(i)\n\n function(x) x[[i]]\n}\n\nx <- 1:3\nidentical(x[[1]], pick(1)(x))\n#> [1] TRUE\nidentical(\n lapply(mtcars, function(x) x[[5]]),\n lapply(mtcars, pick(5))\n)\n#> [1] TRUE\n\nQ4: Create a function that creates functions that compute the ith central moment of a numeric vector. You can test it by running the following code:\n\nm1 <- moment(1)\nm2 <- moment(2)\n\nx <- runif(100)\nstopifnot(all.equal(m1(x), 0))\nstopifnot(all.equal(m2(x), var(x) * 99 / 100))\n\nA: The first moment is closely related to the mean and describes the average deviation from the mean, which is 0 (within numerical margin of error). The second moment describes the variance of the input data. If we want to compare it to var(), we need to undo Bessel’s correction by multiplying with \\(\\frac{N-1}{N}\\).\n\nmoment <- function(i) {\n force(i)\n\n function(x) sum((x - mean(x))^i) / length(x)\n}\n\nm1 <- moment(1)\nm2 <- moment(2)\n\nx <- runif(100)\nall.equal(m1(x), 0) # removed stopifnot() for clarity\n#> [1] TRUE\nall.equal(m2(x), var(x) * 99 / 100)\n#> [1] TRUE\n\nQ5: What happens if you don’t use a closure? Make predictions, then verify with the code below.\n\ni <- 0\nnew_counter2 <- function() {\n i <<- i + 1\n i\n}\n\nA: Without the captured and encapsulated environment of a closure the counts will be stored in the global environment. Here they can be overwritten or deleted as well as interfere with other counters.\n\nnew_counter2()\n#> [1] 1\ni\n#> [1] 1\nnew_counter2()\n#> [1] 2\ni\n#> [1] 2\n\ni <- 0\nnew_counter2()\n#> [1] 1\ni\n#> [1] 1\n\nQ6: What happens if you use <- instead of <<-? Make predictions, then verify with the code below.\n\nnew_counter3 <- function() {\n i <- 0\n function() {\n i <- i + 1\n i\n }\n}\n\nA: Without the super assignment <<-, the counter will always return 1. The counter always starts in a new execution environment within the same enclosing environment, which contains an unchanged value for i (in this case it remains 0).\n\nnew_counter_3 <- new_counter3()\n\nnew_counter_3()\n#> [1] 1\nnew_counter_3()\n#> [1] 1" + }, + { + "objectID": "10_Function_factories.html#graphical-factories", + "href": "10_Function_factories.html#graphical-factories", + "title": "10 - Function factories", + "section": "Graphical factories", + "text": "Graphical factories\nQ1: Compare and contrast ggplot2::label_bquote() with scales::number_format().\nA: Both functions will help you in styling your output, e.g. in your plots and they do this by returning the desired formatting function to you.\nggplot2::label_bquote() takes relatively straightforward plotmath expressions and uses them for faceting labels in {ggplot2}. Because this function is used in {ggplot2} it needs to return a function of class = \"labeller\".\nscales::number_format() initially force()s the computation of all parameters. It’s essentially a parametrised wrapper around scales::number() and will help you format numbers appropriately. It will return a simple function." + }, + { + "objectID": "10_Function_factories.html#statistical-factories", + "href": "10_Function_factories.html#statistical-factories", + "title": "10 - Function factories", + "section": "Statistical factories", + "text": "Statistical factories\nQ1: In boot_model(), why don’t I need to force the evaluation of df or model?\nA: boot_model() ultimately returns a function, and whenever you return a function you need to make sure all the inputs are explicitly evaluated. Here that happens automatically because we use df and formula in lm() before returning the function.\n\nboot_model <- function(df, formula) {\n mod <- lm(formula, data = df)\n fitted <- unname(fitted(mod))\n resid <- unname(resid(mod))\n rm(mod)\n\n function() {\n fitted + sample(resid)\n }\n}\n\nQ2: Why might you formulate the Box-Cox transformation like this?\n\nboxcox3 <- function(x) {\n function(lambda) {\n if (lambda == 0) {\n log(x)\n } else {\n (x^lambda - 1) / lambda\n }\n }\n}\n\nA: boxcox3() returns a function where x is fixed (though it is not forced, so it may be manipulated later). This allows us to apply and test different transformations for different inputs and give them a descriptive name.\n\nboxcox_airpassengers <- boxcox3(AirPassengers)\n\nplot(boxcox_airpassengers(0))\nplot(boxcox_airpassengers(1))\nplot(boxcox_airpassengers(2))\nplot(boxcox_airpassengers(3))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nQ3: Why don’t you need to worry that boot_permute() stores a copy of the data inside the function that it generates?\nA: boot_permute() is defined in Advanced R as:\n\nboot_permute <- function(df, var) {\n n <- nrow(df)\n force(var)\n\n function() {\n col <- df[[var]]\n col[sample(n, replace = TRUE)]\n }\n}\n\nWe don’t need to worry that it stores a copy of the data, because it actually doesn’t store one; it’s just a name that points to the same underlying object in memory.\n\nboot_mtcars1 <- boot_permute(mtcars, \"mpg\")\n\nlobstr::obj_size(mtcars)\n#> 7.21 kB\nlobstr::obj_size(boot_mtcars1)\n#> 20.18 kB\nlobstr::obj_sizes(mtcars, boot_mtcars1)\n#> * 7.21 kB\n#> * 12.97 kB\n\nQ4: How much time does ll_poisson2() save compared to ll_poisson1()? Use bench::mark() to see how much faster the optimisation occurs. How does changing the length of x change the results?\nA: Let us recall the definitions of ll_poisson1(), ll_poisson2() and the test data x1:\n\nll_poisson1 <- function(x) {\n n <- length(x)\n\n function(lambda) {\n log(lambda) * sum(x) - n * lambda - sum(lfactorial(x))\n }\n}\n\nll_poisson2 <- function(x) {\n n <- length(x)\n sum_x <- sum(x)\n c <- sum(lfactorial(x))\n\n function(lambda) {\n log(lambda) * sum_x - n * lambda - c\n }\n}\n\nx1 <- c(41, 30, 31, 38, 29, 24, 30, 29, 31, 38)\n\nA benchmark on x1 reveals a performance improvement of factor 2 for ll_poisson2() over ll_poisson1():\n\nbench::mark(\n llp1 = optimise(ll_poisson1(x1), c(0, 100), maximum = TRUE),\n llp2 = optimise(ll_poisson2(x1), c(0, 100), maximum = TRUE)\n)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 llp1 19.2µs 25.1µs 37614. 12.9KB 33.9\n#> 2 llp2 10.7µs 13µs 71319. 0B 35.7\n\nAs the redundant calculations within ll_poisson1() become more expensive with growing length of x1, we expect even further relative performance improvements for ll_poisson2(). The following benchmark reveals a relative performance improvement of factor 20 for ll_poisson2() when x1 is of length 100,000:\n\nbench_poisson <- function(x_length) {\n x <- rpois(x_length, 100L)\n\n bench::mark(\n llp1 = optimise(ll_poisson1(x), c(0, 100), maximum = TRUE),\n llp2 = optimise(ll_poisson2(x), c(0, 100), maximum = TRUE),\n time_unit = \"ms\"\n )\n}\n\nperformances <- map_dfr(10^(1:5), bench_poisson)\n\ndf_perf <- tibble(\n x_length = rep(10^(1:5), each = 2),\n method = attr(performances$expression, \"description\"),\n median = performances$median\n)\n\nggplot(df_perf, aes(x_length, median, col = method)) +\n geom_point(size = 2) +\n geom_line(linetype = 2) +\n scale_x_log10() +\n labs(\n x = \"Length of x\",\n y = \"Execution Time (ms)\",\n color = \"Method\"\n ) +\n theme(legend.position = \"top\")" + }, + { + "objectID": "10_Function_factories.html#function-factories-functionals", + "href": "10_Function_factories.html#function-factories-functionals", + "title": "10 - Function factories", + "section": "Function factories + functionals", + "text": "Function factories + functionals\nQ1: Which of the following commands is equivalent to with(x, f(z))?\n\nx$f(x$z).\nf(x$z).\nx$f(z).\nf(z).\nIt depends.\n\nA: (e) “It depends” is the correct answer. Usually with() is used with a data frame, so you’d usually expect (b), but if x is a list, it could be any of the options.\n\nf <- mean\nz <- 1\nx <- list(f = mean, z = 1)\n\nidentical(with(x, f(z)), x$f(x$z))\n#> [1] TRUE\nidentical(with(x, f(z)), f(x$z))\n#> [1] TRUE\nidentical(with(x, f(z)), x$f(z))\n#> [1] TRUE\nidentical(with(x, f(z)), f(z))\n#> [1] TRUE\n\nQ2: Compare and contrast the effects of env_bind() vs. attach() for the following code.\n\nfuns <- list(\n mean = function(x) mean(x, na.rm = TRUE),\n sum = function(x) sum(x, na.rm = TRUE)\n)\n\nattach(funs)\n#> The following objects are masked from package:base:\n#> \n#> mean, sum\nmean <- function(x) stop(\"Hi!\")\ndetach(funs)\n\nenv_bind(globalenv(), !!!funs)\nmean <- function(x) stop(\"Hi!\")\nenv_unbind(globalenv(), names(funs))\n\nA: attach() adds funs to the search path. Therefore, the provided functions are found before their respective versions from the {base} package. Further, they cannot get accidentally overwritten by similar named functions in the global environment. One annoying downside of using attach() is the possibility to attach the same object multiple times, making it necessary to call detach() equally often.\n\nattach(funs)\n#> The following objects are masked from package:base:\n#> \n#> mean, sum\nattach(funs)\n#> The following objects are masked from funs (pos = 3):\n#> \n#> mean, sum\n#> \n#> The following objects are masked from package:base:\n#> \n#> mean, sum\n\nhead(search())\n#> [1] \".GlobalEnv\" \"funs\" \"funs\" \"package:ggplot2\"\n#> [5] \"package:purrr\" \"package:dplyr\"\ndetach(funs)\ndetach(funs)\n\nIn contrast rlang::env_bind() just adds the functions in fun to the global environment. No further side effects are introduced, and the functions are overwritten when similarly named functions are defined.\n\nenv_bind(globalenv(), !!!funs)\nhead(search())\n#> [1] \".GlobalEnv\" \"package:ggplot2\" \"package:purrr\" \"package:dplyr\" \n#> [5] \"package:rlang\" \"package:stats\"" + }, + { + "objectID": "10_Function_factories.html#references", + "href": "10_Function_factories.html#references", + "title": "10 - Function factories", + "section": "References", + "text": "References\n\n\n\n\nHenry, Lionel, and Hadley Wickham. 2020a. Purrr: Functional Programming Tools. https://github.com/tidyverse/purrr.\n\n\n———. 2020b. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang.\n\n\nR Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.\n\n\nWickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.\n\n\nWickham, Hadley, Romain François, Lionel Henry, and Kirill Müller. 2020. Dplyr: A Grammar of Data Manipulation. https://github.com/tidyverse/dplyr." + }, + { + "objectID": "11_Function_operators.html#prerequisites", + "href": "11_Function_operators.html#prerequisites", + "title": "11 - Function operators", + "section": "Prerequisites", + "text": "Prerequisites\nAlso in the third chapter on functional programming, we make relatively frequent use of the {purrr} package.\n\nlibrary(purrr)" + }, + { + "objectID": "11_Function_operators.html#existing-function-operators", + "href": "11_Function_operators.html#existing-function-operators", + "title": "11 - Function operators", + "section": "Existing function operators", + "text": "Existing function operators\nQ1: Base R provides a function operator in the form of Vectorize(). What does it do? When might you use it?\nA: In R a lot of functions are “vectorised”. Vectorised has two meanings. First, it means (broadly) that a function inputs a vector or vectors and does something to each element. Secondly, it usually implies that these operations are implemented in a compiled language such as C or Fortran, so that the implementation is very fast.\nHowever, despite what the function’s name implies, Vectorize() is not able to speed up the provided function. It rather changes the input format of the supplied arguments (vectorize.args), so that they can be iterated over.\nLet’s take a look at an example from the documentation:\n\nvrep <- Vectorize(rep.int)\nvrep\n#> function (x, times)\n#> {\n#> args <- lapply(as.list(match.call())[-1L], eval, parent.frame())\n#> names <- if (is.null(names(args)))\n#> character(length(args))\n#> else names(args)\n#> dovec <- names %in% vectorize.args\n#> do.call(\"mapply\", c(FUN = FUN, args[dovec],\n#> MoreArgs = list(args[!dovec]),\n#> SIMPLIFY = SIMPLIFY, USE.NAMES = USE.NAMES))\n#> }\n#> <environment: 0x558902db65d0>\n\n\n\n# Application\nvrep(1:2, 3:4)\n#> [[1]]\n#> [1] 1 1 1\n#> \n#> [[2]]\n#> [1] 2 2 2 2\n\nVectorize() provides a convenient and concise notation to iterate over multiple arguments but has some major drawbacks that mean you generally shouldn’t use it. See https://www.jimhester.com/post/2018-04-12-vectorize/ for more details.\nQ2: Read the source code for possibly(). How does it work?\nA: possibly() modifies functions to return a specified default value (otherwise) in case of an error and to suppress any error messages (quiet = TRUE).\nWhile reading the source code, we notice that possibly() internally uses purrr::as_mapper(). This enables users to supply not only functions, but also formulas or atomics via the same syntax as known from other functions in the {purrr} package. Besides this, the new default value (otherwise) gets evaluated once to make it (almost) immutable.\n\npossibly\n#> function (.f, otherwise = NULL, quiet = TRUE) \n#> {\n#> .f <- as_mapper(.f)\n#> force(otherwise)\n#> check_bool(quiet)\n#> function(...) {\n#> tryCatch(.f(...), error = function(e) {\n#> if (!quiet) \n#> message(\"Error: \", conditionMessage(e))\n#> otherwise\n#> })\n#> }\n#> }\n#> <bytecode: 0x612763fdb428>\n#> <environment: namespace:purrr>\n\nThe main functionality of possibly() is provided by base::tryCatch(). In this part the supplied function (.f) gets wrapped and the error and interrupt handling are specified.\nQ3: Read the source code for safely(). How does it work?\nA: safely() modifies functions to return a list, containing the elements result and error. It works in a similar fashion as possibly() and besides using as_mapper(), safely() also provides the otherwise and quiet arguments. However, in order to provide the result and the error in a consistent way, the tryCatch() part of the implementation returns a list with similar structure for both cases. In the case of successful evaluation error equals NULL and in case of an error result equals otherwise, which is NULL by default.\nAs the tryCatch() part is hidden in the internal purrr:::capture_output() function, we provide it here in addition to safely():\n\nsafely\n#> function (.f, otherwise = NULL, quiet = TRUE) \n#> {\n#> .f <- as_mapper(.f)\n#> force(otherwise)\n#> check_bool(quiet)\n#> function(...) capture_error(.f(...), otherwise, quiet)\n#> }\n#> <bytecode: 0x6127643254f0>\n#> <environment: namespace:purrr>\n\npurrr:::capture_error\n#> function (code, otherwise = NULL, quiet = TRUE) \n#> {\n#> tryCatch(list(result = code, error = NULL), error = function(e) {\n#> if (!quiet) \n#> message(\"Error: \", conditionMessage(e))\n#> list(result = otherwise, error = e)\n#> })\n#> }\n#> <bytecode: 0x6127643aebe8>\n#> <environment: namespace:purrr>\n\nTake a look at Advanced R or the documentation of safely() to see how you can take advantage of this behaviour, e.g. when fitting many models." + }, + { + "objectID": "11_Function_operators.html#case-study-creating-your-own-function-operators", + "href": "11_Function_operators.html#case-study-creating-your-own-function-operators", + "title": "11 - Function operators", + "section": "Case study: Creating your own function operators", + "text": "Case study: Creating your own function operators\nQ1: Weigh the pros and cons of download.file %>% dot_every(10) %>% delay_by(0.1) versus download.file %>% delay_by(0.1) %>% dot_every(10).\nA: Both commands will print a dot every 10 downloads and will take the same amount of time to run, so the differences may seem quite subtle.\nIn the first case, first the dot functionality is added to download.file(). Then the delay is added to this already tweaked function. This implies, that the printing of the dot will also be delayed, and the first dot will be printed as soon as the download for the 10th URL starts.\nIn the latter case the delay is added first and the dot-functionality is wrapped around it. This order will print the first dot immediately after the 9th download is finished, then the short delay occurs before the 10th download actually starts.\nQ2: Should you memoise file.download()? Why or why not?\nA: Memoising file.download() will only work if the files are immutable, i.e. if the file at a given URL is always the same. There’s no point memoising unless this is true. Even if this is true, however, memoise has to store the results in memory, and large files will potentially take up a lot of memory.\nThis implies that it’s probably not beneficial to memoise file.download() in most cases. The only exception is if you are downloading small files many times, and the file at a given URL is guaranteed not to change.\nQ3: Create a function operator that reports whenever a file is created or deleted in the working directory, using dir() and setdiff(). What other global function effects might you want to track?\nA: We start with a function that reports the difference between two vectors containing file names:\n\ndir_compare <- function(old, new) {\n if (setequal(old, new)) {\n return()\n }\n\n added <- setdiff(new, old)\n removed <- setdiff(old, new)\n\n changes <- c(\n if (length(added) > 0) paste0(\" * '\", added, \"' was added\"),\n if (length(removed) > 0) {\n paste0(\n \" * '\", removed,\n \"' was removed\"\n )\n }\n )\n message(paste(changes, collapse = \"\\n\"))\n}\n\ndir_compare(c(\"x\", \"y\"), c(\"x\", \"y\"))\n#> NULL\ndir_compare(c(\"x\", \"y\"), c(\"x\", \"a\"))\n#> * 'a' was added\n#> * 'y' was removed\n\nThen we wrap it up in a function operator\n\ntrack_dir <- function(f) {\n force(f)\n function(...) {\n dir_old <- dir()\n on.exit(dir_compare(dir_old, dir()), add = TRUE)\n\n f(...)\n }\n}\n\nAnd try it out by creating wrappers around file.create() and file.remove():\n\nfile_create <- track_dir(file.create)\nfile_remove <- track_dir(file.remove)\n\nfile_create(\"delete_me\")\n#> * 'delete_me' was added\n#> [1] TRUE\nfile_remove(\"delete_me\")\n#> * 'delete_me' was removed\n#> [1] TRUE\n\nTo create a more serious version of track_dir() one might provide optionality to set the full.names and recursive arguments of dir() to TRUE. This would enable to also track the creation/deletion of hidden files and files in folders contained in the working directory.\nOther global effects that might be worth tracking include changes regarding:\n\nthe search path and possibly introduced conflicts()\noptions() and par() which modify global settings\nthe path of the working directory\nenvironment variables\n\nQ4: Write a function operator that logs a timestamp and message to a file every time a function is run.\nA: Our logger() function operator takes a function and a file path as input. One timestamp is written to the file under log_path when we call logger() and another timestamp is written to the same file each time the new function gets called.\n\nappend_line <- function(path, ...) {\n cat(..., \"\\n\", sep = \"\", file = path, append = TRUE)\n}\n\nlogger <- function(f, log_path) {\n force(f)\n force(log_path)\n\n append_line(log_path, \"created at: \", as.character(Sys.time()))\n function(...) {\n append_line(log_path, \"called at: \", as.character(Sys.time()))\n f(...)\n }\n}\n\nNow, let’s check if our logger() works as intended and apply it to the mean() function:\n\nlog_path <- tempfile()\nmean2 <- logger(mean, log_path)\nSys.sleep(5)\nmean2(1:4)\n#> [1] 2.5\nSys.sleep(1)\nmean2(1:4)\n#> [1] 2.5\n\nreadLines(log_path)\n#> [1] \"created at: 2024-01-24 11:45:37.692096\"\n#> [2] \"called at: 2024-01-24 11:45:42.699738\" \n#> [3] \"called at: 2024-01-24 11:45:43.703109\"\n\nQ5: Modify delay_by() so that instead of delaying by a fixed amount of time, it ensures that a certain amount of time has elapsed since the function was last called. That is, if you called g <- delay_by(1, f); g(); Sys.sleep(2); g() there shouldn’t be an extra delay.\nA: delay_by() was defined in Advanced R as:\n\ndelay_by <- function(f, amount) {\n force(f)\n force(amount)\n\n function(...) {\n Sys.sleep(amount)\n f(...)\n }\n}\n\nTo ensure that the function created by delay_by() waits that a certain amount of time has passed since its last execution, we incorporate three little changes into our new delay_atleast() as indicated in the corresponding comments below.\n\ndelay_atleast <- function(amount, f) {\n force(f)\n force(amount)\n\n # Store the last time the function was run\n last_time <- NULL\n\n # Return modified \"delay-aware\" function\n function(...) {\n if (!is.null(last_time)) {\n wait <- (last_time - Sys.time()) + amount\n if (wait > 0) {\n Sys.sleep(wait)\n }\n }\n\n # Update the time after the function has finished\n on.exit(last_time <<- Sys.time())\n\n f(...)\n }\n}" + }, + { + "objectID": "13_S3.html#prerequisites", + "href": "13_S3.html#prerequisites", + "title": "13 - S3", + "section": "Prerequisites", + "text": "Prerequisites\nTo interact with S3 objects, we will mainly use the {sloop} package (Wickham 2019).\n\nlibrary(sloop)" + }, + { + "objectID": "13_S3.html#basics", + "href": "13_S3.html#basics", + "title": "13 - S3", + "section": "Basics", + "text": "Basics\nQ1: Describe the difference between t.test() and t.data.frame()? When is each function called?\nA: Because of S3’s generic.class() naming scheme, both functions may initially look similar, while they are in fact unrelated.\n\nt.test() is a generic function that performs a t-test.\nt.data.frame() is a method that gets called by the generic t() to transpose data frame input.\n\nDue to R’s S3 dispatch rules, t.test() would also get called when t() is applied to an object of class test.\nQ2: Make a list of commonly used base R functions that contain . in their name but are not S3 methods.\nA: In recent years “snake_case”-style has become increasingly common when naming functions and variables in R. But many functions in base R will continue to be “point.separated”, which is why some inconsistency in your R code most likely cannot be avoided.(Bååth 2012)\n\n# Some base R functions with point.separated names\ninstall.packages()\nread.csv()\n\nlist.files()\ndownload.file()\n\ndata.frame()\nas.character()\nSys.Date()\n\nall.equal()\n\ndo.call()\non.exit()\n\nQ3: What does the as.data.frame.data.frame() method do? Why is it confusing? How could you avoid this confusion in your own code?\nA: The function as.data.frame.data.frame() implements the data.frame() method for the as.data.frame() generic, which coerces objects to data frames.\nThe name is confusing, because it does not clearly communicate the type of the function, which could be a regular function, a generic or a method. Even if we assume a method, the amount of .’s makes it difficult to separate the generic- and the class-part of the name. Is it the data.frame.data.frame() method for the as() generic? Is it the frame.data.frame() method for the as.data() generic?\nWe could avoid this confusion by applying a different naming convention (e.g. “snake_case”) for our class and function names.\nQ4: Describe the difference in behaviour in these two calls.\n\nsome_days <- as.Date(\"2017-01-31\") + sample(10, 5)\n\nmean(some_days)\n#> [1] \"2017-02-06\"\nmean(unclass(some_days))\n#> [1] 17203\n\nA: mean() is a generic function, which will select the appropriate method based on the class of the input. some_days has the class Date and mean.Date(some_days) will be used to calculate the mean date of some_days.\nAfter unclass() has removed the class attribute from some_date, the default method is chosen. mean.default(unclass(some_days)) then calculates the mean of the underlying double.\nQ5: What class of object does the following code return? What base type is it built on? What attributes does it use?\n\nx <- ecdf(rpois(100, 10))\nx\n#> Empirical CDF \n#> Call: ecdf(rpois(100, 10))\n#> x[1:18] = 2, 3, 4, ..., 2e+01, 2e+01\n\nA: It returns an object of the class ecdf (empirical cumulative distribution function) with the superclasses stepfun and function. The ecdf object is built on the base type closure (a function). The expression, which was used to create it (rpois(100, 10)), is stored in the call attribute.\n\ntypeof(x)\n#> [1] \"closure\"\n\nattributes(x)\n#> $class\n#> [1] \"ecdf\" \"stepfun\" \"function\"\n#> \n#> $call\n#> ecdf(rpois(100, 10))\n\nQ6: What class of object does the following code return? What base type is it built on? What attributes does it use?\n\nx <- table(rpois(100, 5))\nx\n#> \n#> 1 2 3 4 5 6 7 8 9 10 \n#> 7 5 18 14 15 15 14 4 5 3\n\nA: This code returns a table object, which is built upon the integer type. The attribute dimnames is used to name the elements of the integer vector.\n\ntypeof(x)\n#> [1] \"integer\"\n\nattributes(x)\n#> $dim\n#> [1] 10\n#> \n#> $dimnames\n#> $dimnames[[1]]\n#> [1] \"1\" \"2\" \"3\" \"4\" \"5\" \"6\" \"7\" \"8\" \"9\" \"10\"\n#> \n#> \n#> $class\n#> [1] \"table\"" + }, + { + "objectID": "13_S3.html#classes", + "href": "13_S3.html#classes", + "title": "13 - S3", + "section": "Classes", + "text": "Classes\nQ1: Write a constructor for data.frame objects. What base type is a data frame built on? What attributes does it use? What are the restrictions placed on the individual elements? What about the names?\nA: Data frames are built on named lists of vectors, which all have the same length. Besides the class and the column names (names), the row.names are their only further attribute. This must be a character vector with the same length as the other vectors.\nWe need to provide the number of rows as an input to make it possible to create data frames with 0 columns but multiple rows.\nThis leads to the following constructor:\n\nnew_data.frame <- function(x, n, row.names = NULL) {\n # Check if the underlying object is a list\n stopifnot(is.list(x))\n \n # Check all inputs are the same length\n # (This check also allows that x has length 0)\n stopifnot(all(lengths(x) == n))\n \n if (is.null(row.names)) {\n # Use special row names helper from base R\n row.names <- .set_row_names(n)\n } else {\n # Otherwise check that they're a character vector with the \n # correct length\n stopifnot(is.character(row.names), length(row.names) == n)\n }\n \n structure(\n x,\n class = \"data.frame\",\n row.names = row.names\n )\n}\n\n# Test\nx <- list(a = 1, b = 2)\nnew_data.frame(x, n = 1)\n#> a b\n#> 1 1 2\nnew_data.frame(x, n = 1, row.names = \"l1\")\n#> a b\n#> l1 1 2\n\n# Create a data frame with 0 columns and 2 rows\nnew_data.frame(list(), n = 2)\n#> data frame with 0 columns and 2 rows\n\nThere are two additional restrictions we could implement if we were being very strict: both the row names and column names should be unique.\nQ2: Enhance my factor() helper to have better behaviour when one or more values is not found in levels. What does base::factor() do in this situation?\nA: base::factor() converts these values (silently) into NAs:\n\nfactor(c(\"a\", \"b\", \"c\"), levels = c(\"a\", \"b\"))\n#> [1] a b <NA>\n#> Levels: a b\n\nThe factor() helper including the constructor (new_factor()) and its validator (validate_factor()) were given in Advanced R. However, as the goal of this question is to throw an early error within the helper, we only repeat the code for the helper:\n\n# Simplified version of the factor() helper, as defined in Advanced R\nfactor <- function(x = character(), levels = unique(x)) {\n ind <- match(x, levels)\n validate_factor(new_factor(ind, levels))\n}\n\nTo improve the factor() helper we choose to return an informative error message instead.\n\nfactor2 <- function(x, levels = unique(x)) {\n new_levels <- match(x, levels)\n \n # Error if levels don't include all values\n missing <- unique(setdiff(x, levels))\n if (length(missing) > 0) {\n stop(\n \"The following values do not occur in the levels of x: \",\n paste0(\"'\", missing, \"'\", collapse = \", \"), \".\", \n call. = FALSE\n )\n }\n \n validate_factor(new_factor(new_levels, levels))\n}\n\n# Test\nfactor2(c(\"a\", \"b\", \"c\"), levels = c(\"a\", \"b\"))\n#> Error: The following values do not occur in the levels of x: 'c'.\n\nQ3: Carefully read the source code of factor(). What does it do that our constructor does not?\nA: The original implementation (base::factor()) allows more flexible input for x. It coerces x to character or replaces it with character(0) (in case of NULL). It also ensures that the levels are unique. This is achieved by setting them via base::levels<-, which fails when duplicate values are supplied.\nQ4: Factors have an optional “contrasts” attribute. Read the help for C(), and briefly describe the purpose of the attribute. What type should it have? Rewrite the new_factor() constructor to include this attribute.\nA: When factor variables (representing nominal or ordinal information) are used in statistical models, they are typically encoded as dummy variables and by default each level is compared with the first factor level. However, many different encodings (“contrasts”) are possible, see https://en.wikipedia.org/wiki/Contrast_(statistics).\nWithin R’s formula interface you can wrap a factor in stats::C() and specify the contrast of your choice. Alternatively, you can set the contrasts attribute of your factor variable, which accepts matrix input. (See ?contr.helmert or similar for details.)\nThe new_factor() constructor was given in Advanced R as:\n\n# new_factor() constructor from Advanced R\nnew_factor <- function(x = integer(), levels = character()) {\n stopifnot(is.integer(x))\n stopifnot(is.character(levels))\n\n structure(\n x,\n levels = levels,\n class = \"factor\"\n )\n}\n\nOur updated new_factor() constructor gets a contrasts argument, which accepts a numeric matrix or NULL (default).\n\n# Updated new_factor() constructor\nnew_factor <- function(\n x = integer(),\n levels = character(),\n contrasts = NULL\n) {\n stopifnot(is.integer(x))\n stopifnot(is.character(levels))\n \n if (!is.null(constrasts)) {\n stopifnot(is.matrix(contrasts) && is.numeric(contrasts))\n }\n \n structure(\n x,\n levels = levels,\n class = \"factor\",\n contrasts = contrasts\n )\n}\n\nQ5: Read the documentation for utils::as.roman(). How would you write a constructor for this class? Does it need a validator? What might a helper do?\nA: This function transforms numeric input into Roman numbers. It is built on the integer type, which results in the following constructor.\n\nnew_roman <- function(x = integer()) {\n stopifnot(is.integer(x))\n structure(x, class = \"roman\")\n}\n\nThe documentation tells us, that only values between 1 and 3899 are uniquely represented, which we then include in our validation function.\n\nvalidate_roman <- function(x) {\n values <- unclass(x)\n \n if (any(values < 1 | values > 3899)) {\n stop(\n \"Roman numbers must fall between 1 and 3899.\",\n call. = FALSE\n )\n }\n \n x\n}\n\nFor convenience, we allow the user to also pass real values to a helper function.\n\nroman <- function(x = integer()) {\n x <- as.integer(x)\n \n validate_roman(new_roman(x))\n}\n\n# Test\nroman(c(1, 753, 2019))\n#> [1] I DCCLIII MMXIX\nroman(0)\n#> Error: Roman numbers must fall between 1 and 3899." + }, + { + "objectID": "13_S3.html#generics-and-methods", + "href": "13_S3.html#generics-and-methods", + "title": "13 - S3", + "section": "Generics and methods", + "text": "Generics and methods\nQ1: Read the source code for t() and t.test() and confirm that t.test() is an S3 generic and not an S3 method. What happens if you create an object with class test and call t() with it? Why?\n\nx <- structure(1:10, class = \"test\")\nt(x)\n\nA: We can see that t.test() is a generic because it calls UseMethod():\n\nt.test\n#> function (x, ...) \n#> UseMethod(\"t.test\")\n#> <bytecode: 0x580b4c5c2f68>\n#> <environment: namespace:stats>\n\n# or simply call\nftype(t.test)\n#> [1] \"S3\" \"generic\"\n\n# The same holds for t()\nt\n#> function (x) \n#> UseMethod(\"t\")\n#> <bytecode: 0x580b4ce1f4f8>\n#> <environment: namespace:base>\n\nInterestingly, R also provides helpers, which list functions that look like methods, but in fact are not:\n\ntools::nonS3methods(\"stats\")\n#> [1] \"anova.lmlist\" \"expand.model.frame\" \"fitted.values\" \n#> [4] \"influence.measures\" \"lag.plot\" \"t.test\" \n#> [7] \"plot.spec.phase\" \"plot.spec.coherency\"\n\nWhen we create an object with class test, t() dispatches to the t.default() method. This happens, because UseMethod() simply searches for functions named paste0(\"generic\", \".\", c(class(x), \"default\")).\n\nx <- structure(1:10, class = \"test\")\n\nt(x)\n#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]\n#> [1,] 1 2 3 4 5 6 7 8 9 10\n#> attr(,\"class\")\n#> [1] \"test\"\n\nHowever, in older versions of R (pre R 4.0.0; when Advanced R was written) this behaviour was slightly different. Instead of dispatching to the t.default() method, the t.test() generic was erroneously treated as a method of t() which then dispatched to t.test.default() or (when defined) to t.test.test().\n\n# Output in R version 3.6.2\nx <- structure(1:10, class = \"test\")\nt(x)\n#>\n#> One Sample t-test\n#>\n#> data: x\n#> t = 5.7446, df = 9, p-value = 0.0002782\n#> alternative hypothesis: true mean is not equal to 0\n#> 95 percent confidence interval:\n#> 3.334149 7.665851\n#> sample estimates:\n#> mean of x \n#> 5.5 \n\nt.test.test <- function(x) \"Hi!\"\nt(x)\n#>[1] \"Hi!\"\n\nQ2: What generics does the table class have methods for?\nA: This is a simple application of sloop::s3_methods_class():\n\ns3_methods_class(\"table\")\n#> # A tibble: 10 × 4\n#> generic class visible source \n#> <chr> <chr> <lgl> <chr> \n#> 1 [ table TRUE base \n#> 2 aperm table TRUE base \n#> 3 as.data.frame table TRUE base \n#> 4 Axis table FALSE registered S3method\n#> 5 lines table FALSE registered S3method\n#> 6 plot table FALSE registered S3method\n#> 7 points table FALSE registered S3method\n#> 8 print table TRUE base \n#> 9 summary table TRUE base \n#> 10 tail table FALSE registered S3method\n\nInterestingly, the table class has a number of methods designed to help plotting with base graphics.\n\nx <- rpois(100, 5)\nplot(table(x))\n\n\n\n\n\n\n\n\nQ3: What generics does the ecdf class have methods for?\nA: We use the same approach as above:\n\ns3_methods_class(\"ecdf\")\n#> # A tibble: 4 × 4\n#> generic class visible source \n#> <chr> <chr> <lgl> <chr> \n#> 1 plot ecdf TRUE stats \n#> 2 print ecdf FALSE registered S3method\n#> 3 quantile ecdf FALSE registered S3method\n#> 4 summary ecdf FALSE registered S3method\n\nThe methods are primarily designed for display (plot(), print(), summary()), but you can also extract quantiles with quantile().\nQ4: Which base generic has the greatest number of defined methods?\nA: A little experimentation (and thinking about the most popular functions) suggests that the print() generic has the most defined methods.\n\nnrow(s3_methods_generic(\"print\"))\n#> [1] 310\nnrow(s3_methods_generic(\"summary\"))\n#> [1] 41\nnrow(s3_methods_generic(\"plot\"))\n#> [1] 34\n\nLet’s verify this programmatically with the tools we have learned in this and the previous chapters.\n\nlibrary(purrr)\n\nls(all.names = TRUE, env = baseenv()) %>% \n mget(envir = baseenv()) %>% \n keep(is_function) %>% \n names() %>% \n keep(is_s3_generic) %>% \n map(~ set_names(nrow(s3_methods_generic(.x)), .x)) %>% \n flatten_int() %>% \n sort(decreasing = TRUE) %>% \n head()\n#> print format [ as.character summary plot \n#> 310 146 59 46 41 34\n\nQ5: Carefully read the documentation for UseMethod() and explain why the following code returns the results that it does. What two usual rules of function evaluation does UseMethod() violate?\n\ng <- function(x) {\n x <- 10\n y <- 10\n UseMethod(\"g\")\n}\ng.default <- function(x) c(x = x, y = y)\n\nx <- 1\ny <- 1\ng(x)\n#> x y \n#> 1 10\n\nA: Let’s take this step by step. If you call g.default(x) directly you get c(1, 1) as you might expect.\nThe value bound to x comes from the argument, the value from y comes from the global environment.\n\ng.default(x)\n#> x y \n#> 1 1\n\nBut when we call g(x) we get c(1, 10):\n\ng(x)\n#> x y \n#> 1 10\n\nThis is seemingly inconsistent: why does x come from the value defined inside of g(), and y still come from the global environment? It’s because UseMethod() calls g.default() in a special way so that variables defined inside the generic are available to methods. The exception are arguments supplied to the function: they are passed on as is and cannot be affected by code inside the generic.\nQ6: What are the arguments to [? Why is this a hard question to answer?\nA: The subsetting operator [ is a primitive and a generic function, which can be confirmed via ftype().\n\nftype(`[`)\n#> [1] \"primitive\" \"generic\"\n\nFor primitive functions formals([) returns NULL so we need to find another way to determine the functions arguments. One possible way to figure out [’s arguments would be to inspect the underlying C source code, which can be searched for via pryr::show_c_source(.Primitive(\"[\")).\nWhen we inspect the arguments of some of [’s methods, we see that the arguments vary with the class of x.\n\nnames(formals(`[.data.frame`))\n#> [1] \"x\" \"i\" \"j\" \"drop\"\nnames(formals(`[.table`))\n#> [1] \"x\" \"i\" \"j\" \"...\" \"drop\"\nnames(formals(`[.Date`))\n#> [1] \"x\" \"...\" \"drop\"\nnames(formals(`[.AsIs`))\n#> [1] \"x\" \"i\" \"...\"\n\nTo finally get a better overview, we have to put in a little more effort and also use s3_methods_generic() again.\n\nlibrary(dplyr)\n\ns3_methods_generic(\"[\") %>%\n filter(visible) %>%\n mutate(\n method = paste0(\"[.\", class),\n argnames = purrr::map(method, ~ names(formals(.x))),\n args = purrr::map(method, ~ formals(.x)),\n args = purrr::map2(\n argnames, args,\n ~ paste(.x, .y, sep = \" = \")\n ),\n args = purrr::set_names(args, method)\n ) %>%\n pull(args) %>%\n head()\n#> $`[.AsIs`\n#> [1] \"x = \" \"i = \" \"... = \"\n#> \n#> $`[.data.frame`\n#> [1] \"x = \" \n#> [2] \"i = \" \n#> [3] \"j = \" \n#> [4] \"drop = if (missing(i)) TRUE else length(cols) == 1\"\n#> \n#> $`[.Date`\n#> [1] \"x = \" \"... = \" \"drop = TRUE\"\n#> \n#> $`[.difftime`\n#> [1] \"x = \" \"... = \" \"drop = TRUE\"\n#> \n#> $`[.Dlist`\n#> [1] \"x = \" \"i = \" \"... = \"\n#> \n#> $`[.DLLInfoList`\n#> [1] \"x = \" \"... = \"" + }, + { + "objectID": "13_S3.html#object-styles", + "href": "13_S3.html#object-styles", + "title": "13 - S3", + "section": "Object styles", + "text": "Object styles\nQ1: Categorise the objects returned by lm(), factor(), table(), as.Date(), as.POSIXct(), ecdf(), ordered(), I() into the styles described above.\nA: We can categorise the return values into the various object styles by observing how the number of observations is calculated: For vector style classes, length(x) represents the number of observations. Record style objects use a list of equal length elements to represent individual components. For data frames and matrices, the observations are represented by the rows. Scalar style objects use a list to represent a single thing.\nThis leads us to:\n\nVector object-style: factor(), table(), as.Date(), as.POSIXct(), ordered()\nRecord object-style: not observed\nData frame object-style: not observed\nScalar object-style: lm(), ecdf()\n\nThe object style of I() depends on the input since this function returns a “copy of the object with class AsIs prepended to the class(es)”.\nQ2: What would a constructor function for lm objects, new_lm(), look like? Use ?lm and experimentation to figure out the required fields and their types.\nA: The constructor needs to populate the attributes of an lm object and check their types for correctness. Let’s start by creating a simple lm object and explore its underlying base type and attributes:\n\nmod <- lm(cyl ~ ., data = mtcars)\n\ntypeof(mod)\n#> [1] \"list\"\n\nattributes(mod)\n#> $names\n#> [1] \"coefficients\" \"residuals\" \"effects\" \"rank\" \n#> [5] \"fitted.values\" \"assign\" \"qr\" \"df.residual\" \n#> [9] \"xlevels\" \"call\" \"terms\" \"model\" \n#> \n#> $class\n#> [1] \"lm\"\n\nAs mod is built upon a list, we can simply use map(mod, typeof) to find out the base types of its elements. (Additionally, we inspect ?lm, to learn more about the individual attributes.)\n\nmap_chr(mod, typeof)\n#> coefficients residuals effects rank fitted.values \n#> \"double\" \"double\" \"double\" \"integer\" \"double\" \n#> assign qr df.residual xlevels call \n#> \"integer\" \"list\" \"integer\" \"list\" \"language\" \n#> terms model \n#> \"language\" \"list\"\n\nNow we should have enough information to write a constructor for new lm objects.\n\nnew_lm <- function(\n coefficients, residuals, effects, rank, fitted.values, assign,\n qr, df.residual, xlevels, call, terms, model\n) {\n \n stopifnot(\n is.double(coefficients), is.double(residuals), \n is.double(effects), is.integer(rank), is.double(fitted.values),\n is.integer(assign), is.list(qr), is.integer(df.residual),\n is.list(xlevels), is.language(call), is.language(terms),\n is.list(model)\n )\n \n structure(\n list(\n coefficients = coefficients,\n residuals = residuals,\n effects = effects,\n rank = rank, \n fitted.values = fitted.values,\n assign = assign,\n qr = qr,\n df.residual = df.residual,\n xlevels = xlevels,\n call = call,\n terms = terms, \n model = model\n ),\n class = \"lm\"\n )\n}" + }, + { + "objectID": "13_S3.html#inheritance", + "href": "13_S3.html#inheritance", + "title": "13 - S3", + "section": "Inheritance", + "text": "Inheritance\nQ1: How does [.Date support subclasses? How does it fail to support subclasses?\nA: [.Date calls .Date with the result of calling [ on the parent class, along with oldClass():\n\n`[.Date`\n#> function (x, ..., drop = TRUE) \n#> {\n#> .Date(NextMethod(\"[\"), oldClass(x))\n#> }\n#> <bytecode: 0x580b4c38d620>\n#> <environment: namespace:base>\n\n.Date is kind of like a constructor for date classes, although it doesn’t check the input is the correct type:\n\n.Date\n#> function (xx, cl = \"Date\") \n#> `class<-`(xx, cl)\n#> <bytecode: 0x580b4fb47758>\n#> <environment: namespace:base>\n\noldClass() is basically the same as class(), except that it doesn’t return implicit classes, i.e. it’s basically attr(x, \"class\") (looking at the C code that’s exactly what it does, except that it also handles S4 objects).\nAs oldClass() is “basically” class(), we can rewrite [.Date to make the implementation more clear:\n\n`[.Date` <- function(x, ..., drop = TRUE) {\n out <- NextMethod(\"[\")\n class(out) <- class(x)\n out\n}\n\nSo, [.Date ensures that the output has the same class as in the input. But what about other attributes that a subclass might possess? They get lost:\n\nx <- structure(1:4, test = \"test\", class = c(\"myDate\", \"Date\"))\nattributes(x[1])\n#> $class\n#> [1] \"myDate\" \"Date\"\n\nQ2: R has two classes for representing date time data, POSIXct and POSIXlt, which both inherit from POSIXt. Which generics have different behaviours for the two classes? Which generics share the same behaviour?\nA: To answer this question, we have to get the respective generics\n\ngenerics_t <- s3_methods_class(\"POSIXt\")$generic\ngenerics_ct <- s3_methods_class(\"POSIXct\")$generic\ngenerics_lt <- s3_methods_class(\"POSIXlt\")$generic\n\nThe generics in generics_t with a method for the superclass POSIXt potentially share the same behaviour for both subclasses. However, if a generic has a specific method for one of the subclasses, it has to be subtracted:\n\n# These generics provide subclass-specific methods\nunion(generics_ct, generics_lt)\n#> [1] \"[\" \"[[\" \"[<-\" \"as.data.frame\"\n#> [5] \"as.Date\" \"as.list\" \"as.POSIXlt\" \"c\" \n#> [9] \"format\" \"length<-\" \"mean\" \"print\" \n#> [13] \"rep\" \"split\" \"summary\" \"Summary\" \n#> [17] \"weighted.mean\" \"xtfrm\" \"[[<-\" \"$<-\" \n#> [21] \"anyNA\" \"as.double\" \"as.matrix\" \"as.POSIXct\" \n#> [25] \"as.vector\" \"duplicated\" \"is.finite\" \"is.infinite\" \n#> [29] \"is.na\" \"is.nan\" \"length\" \"names\" \n#> [33] \"names<-\" \"sort\" \"unique\"\n\n# These generics share (inherited) methods for both subclasses\nsetdiff(generics_t, union(generics_ct, generics_lt))\n#> [1] \"-\" \"+\" \"all.equal\" \"as.character\" \"Axis\" \n#> [6] \"cut\" \"diff\" \"hist\" \"is.numeric\" \"julian\" \n#> [11] \"Math\" \"months\" \"Ops\" \"pretty\" \"quantile\" \n#> [16] \"quarters\" \"round\" \"seq\" \"str\" \"trunc\" \n#> [21] \"weekdays\"\n\nQ3: What do you expect this code to return? What does it actually return? Why?\n\ngeneric2 <- function(x) UseMethod(\"generic2\")\ngeneric2.a1 <- function(x) \"a1\"\ngeneric2.a2 <- function(x) \"a2\"\ngeneric2.b <- function(x) {\n class(x) <- \"a1\"\n NextMethod()\n}\n\ngeneric2(structure(list(), class = c(\"b\", \"a2\")))\n\nA: When we execute the code above, this is what is happening:\n\nwe pass an object of classes b and a2 to generic2(), which prompts R to look for a methodgeneric2.b()\nthe method generic2.b() then changes the class to a1 and calls NextMethod()\nOne would think that this will lead R to call generic2.a1(), but in fact, as mentioned in Advanced R, NextMethod()\n\ndoesn’t actually work with the class attribute of the object, but instead uses a special global variable (.Class) to keep track of which method to call next.\n\nThis is why generic2.a2() is called instead.\n::: {.cell layout-align=“center” hash=‘13_S3_cache/html/ch13_44_8c6cf6f696f18f5dcc4121e7c3e7a7f2’}\ngeneric2(structure(list(), class = c(\"b\", \"a2\")))\n#> [1] \"a2\"\n:::\n\nLet’s just double check the statement above and evaluate .Class explicitly within the generic2.b() method.\n\ngeneric2.b <- function(x) {\n class(x) <- \"a1\"\n print(.Class)\n NextMethod()\n}\n\ngeneric2(structure(list(), class = c(\"b\", \"a2\")))\n#> [1] \"b\" \"a2\"\n#> [1] \"a2\"" + }, + { + "objectID": "13_S3.html#dispatch-details", + "href": "13_S3.html#dispatch-details", + "title": "13 - S3", + "section": "Dispatch details", + "text": "Dispatch details\nQ1: Explain the differences in dispatch below:\n\nlength.integer <- function(x) 10\n\nx1 <- 1:5\nclass(x1)\n#> [1] \"integer\"\ns3_dispatch(length(x1))\n#> * length.integer\n#> length.numeric\n#> length.default\n#> => length (internal)\n\nx2 <- structure(x1, class = \"integer\")\nclass(x2)\n#> [1] \"integer\"\ns3_dispatch(length(x2))\n#> => length.integer\n#> length.default\n#> * length (internal)\n\nA: class() returns integer in both cases. However, while the class of x1 is created implicitly and inherits from the numeric class, the class of x2 is set explicitly. This is important because length() is an internal generic and internal generics only dispatch to methods when the class attribute has been set, i.e. internal generics do not use implicit classes.\nAn object has no explicit class if attr(x, \"class\") returns NULL:\n\nattr(x1, \"class\")\n#> NULL\nattr(x2, \"class\")\n#> [1] \"integer\"\n\nTo see the relevant classes for the S3 dispatch, one can use sloop::s3_class():\n\ns3_class(x1) # implicit\n#> [1] \"integer\" \"numeric\"\n\ns3_class(x2) # explicit\n#> [1] \"integer\"\n\nFor a better understanding of s3_dipatch()’s output we quote from ?s3_dispatch:\n\n=> method exists and is found by UseMethod().\n-> method exists and is used by NextMethod().\n* method exists but is not used.\nNothing (and greyed out in console): method does not exist.\n\nQ2: What classes have a method for the Math() group generic in base R? Read the source code. How do the methods work?\nA: The following functions belong to this group (see ?Math):\n\nabs, sign, sqrt, floor, ceiling, trunc, round, signif\nexp, log, expm1, log1p, cos, sin, tan, cospi, sinpi, tanpi, acos, asin, atan, cosh, sinh, tanh, acosh, asinh, atanh\nlgamma, gamma, digamma, trigamma\ncumsum, cumprod, cummax, cummin\n\nThe following classes have a method for this group generic:\n\ns3_methods_generic(\"Math\")\n#> # A tibble: 8 × 4\n#> generic class visible source \n#> <chr> <chr> <lgl> <chr> \n#> 1 Math data.frame TRUE base \n#> 2 Math Date TRUE base \n#> 3 Math difftime TRUE base \n#> 4 Math factor TRUE base \n#> 5 Math POSIXt TRUE base \n#> 6 Math quosure FALSE registered S3method\n#> 7 Math vctrs_sclr FALSE registered S3method\n#> 8 Math vctrs_vctr FALSE registered S3method\n\nTo explain the basic idea, we just overwrite the data frame method:\n\nMath.data.frame <- function(x) \"hello\"\n\nNow all functions from the math generic group, will return \"hello\"\n\nabs(mtcars)\n#> [1] \"hello\"\nexp(mtcars)\n#> [1] \"hello\"\nlgamma(mtcars)\n#> [1] \"hello\"\n\nOf course, different functions should perform different calculations. Here .Generic comes into play, which provides us with the calling generic as a string\n\nMath.data.frame <- function(x, ...) {\n .Generic\n}\n\nabs(mtcars)\n#> [1] \"abs\"\nexp(mtcars)\n#> [1] \"exp\"\nlgamma(mtcars)\n#> [1] \"lgamma\"\n\nrm(Math.data.frame)\n\nThe original source code of Math.data.frame() is a good example on how to invoke the string returned by .Generic into a specific method. Math.factor() is a good example of a method, which is simply defined for better error messages.\nQ3: Math.difftime() is more complicated than I described. Why?\nA: Math.difftime() also excludes cases apart from abs, sign, floor, ceiling, trunc, round and signif and needs to return a fitting error message.\nFor comparison: Math.difftime() as defined in Advanced R:\n\nMath.difftime <- function(x, ...) {\n new_difftime(NextMethod(), units = attr(x, \"units\"))\n}\nrm(Math.difftime)\n\nMath.difftime() as defined in the {base} package:\n\nMath.difftime\n#> function (x, ...) \n#> {\n#> switch(.Generic, abs = , sign = , floor = , ceiling = , trunc = , \n#> round = , signif = {\n#> units <- attr(x, \"units\")\n#> .difftime(NextMethod(), units)\n#> }, stop(gettextf(\"'%s' not defined for \\\"difftime\\\" objects\", \n#> .Generic), domain = NA))\n#> }\n#> <bytecode: 0x580b4d8f7740>\n#> <environment: namespace:base>" + }, + { + "objectID": "13_S3.html#references", + "href": "13_S3.html#references", + "title": "13 - S3", + "section": "References", + "text": "References\n\n\n\n\nBååth, Rasmus. 2012. “The State of Naming Conventions in r.” The R Journal 4 (2): 74–75. https://doi.org/10.32614/RJ-2012-018.\n\n\nWickham, Hadley. 2019. Sloop: Helpers for ’OOP’ in r. https://github.com/r-lib/sloop." + }, + { + "objectID": "14_R6.html#prerequisites", + "href": "14_R6.html#prerequisites", + "title": "14 - R6", + "section": "Prerequisites", + "text": "Prerequisites\nTo solve the exercises in this chapter we will have to create R6 objects, which are implemented in the {R6} package (Chang 2020).\n\nlibrary(R6)" + }, + { + "objectID": "14_R6.html#classes-and-methods", + "href": "14_R6.html#classes-and-methods", + "title": "14 - R6", + "section": "Classes and methods", + "text": "Classes and methods\nQ1: Create a bank account R6 class that stores a balance and allows you to deposit and withdraw money. Create a subclass that throws an error if you attempt to go into overdraft. Create another subclass that allows you to go into overdraft, but charges you a fee.\nA: Let’s start with a basic bank account, similar to the Accumulator class in Advanced R.\n\nBankAccount <- R6Class(\n classname = \"BankAccount\",\n public = list(\n balance = 0,\n deposit = function(dep = 0) {\n self$balance <- self$balance + dep\n invisible(self)\n },\n withdraw = function(draw) {\n self$balance <- self$balance - draw\n invisible(self)\n }\n )\n)\n\nTo test this class, we create one instance and leave it with a negative balance.\n\nmy_account <- BankAccount$new()\nmy_account$balance\n#> [1] 0\n\nmy_account$\n deposit(5)$\n withdraw(15)$\n balance\n#> [1] -10\n\nNow, we create the first subclass that prevents us from going into overdraft and throws an error in case we attempt to withdraw more than our current balance.\n\nBankAccountStrict <- R6Class(\n classname = \"BankAccountStrict\",\n inherit = BankAccount,\n public = list(\n withdraw = function(draw = 0) {\n if (self$balance - draw < 0) {\n stop(\"Your `withdraw` must be smaller \",\n \"than your `balance`.\",\n call. = FALSE\n )\n }\n super$withdraw(draw = draw)\n }\n )\n)\n\nThis time our test should throw an error.\n\nmy_strict_account <- BankAccountStrict$new()\nmy_strict_account$balance\n#> [1] 0\n\nmy_strict_account$\n deposit(5)$\n withdraw(15)\n#> Error: Your `withdraw` must be smaller than your `balance`.\n\nmy_strict_account$balance\n#> [1] 5\n\nFinally, we create another subclass that charges a constant fee of 1 for each withdrawal which leaves the account with a negative balance.\n\nBankAccountCharging <- R6Class(\n classname = \"BankAccountCharging\",\n inherit = BankAccount,\n public = list(\n withdraw = function(draw = 0) {\n if (self$balance - draw < 0) {\n draw <- draw + 1\n }\n super$withdraw(draw = draw)\n }\n )\n)\n\nLet’s take a look at the implemented functionality. We expect a final balance of -12, because we pay the fee twice.\n\nmy_charging_account <- BankAccountCharging$new()\nmy_charging_account$balance\n#> [1] 0\n\nmy_charging_account$\n deposit(5)$\n withdraw(15)$\n withdraw(0)\n\nmy_charging_account$balance\n#> [1] -12\n\nQ2: Create an R6 class that represents a shuffled deck of cards. You should be able to draw cards from the deck with $draw(n), and return all cards to the deck and reshuffle with $reshuffle(). Use the following code to make a vector of cards.\n\nsuit <- c(\"SPADE\", \"HEARTS\", \"DIAMOND\", \"CLUB\")\nvalue <- c(\"A\", 2:10, \"J\", \"Q\", \"K\")\ncards <- paste(rep(value, 4), suit)\n\n(This question was altered slightly to avoid the unicode characters.)\nA: Our new ShuffledDeck class will use sample() and positive integer subsetting to implement the reshuffling and drawing functionality. We also add a check, so you cannot draw more cards than there are left in the deck.\n\nShuffledDeck <- R6Class(\n classname = \"ShuffledDeck\",\n public = list(\n deck = NULL,\n initialize = function(deck = cards) {\n self$deck <- sample(deck)\n },\n reshuffle = function() {\n self$deck <- sample(cards)\n invisible(self)\n },\n n = function() {\n length(self$deck)\n },\n draw = function(n = 1) {\n if (n > self$n()) {\n stop(\"Only \", self$n(), \" cards remaining.\", call. = FALSE)\n }\n\n output <- self$deck[seq_len(n)]\n self$deck <- self$deck[-seq_len(n)]\n output\n }\n )\n)\n\nTo test this class, we create a deck (initialise an instance), draw all the cards, then reshuffle, checking we get different cards each time.\n\nmy_deck <- ShuffledDeck$new()\n\nmy_deck$draw(52)\n#> [1] \"6 SPADE\" \"10 DIAMOND\" \"Q CLUB\" \"J SPADE\" \"Q HEARTS\" \n#> [6] \"8 DIAMOND\" \"5 DIAMOND\" \"4 CLUB\" \"9 CLUB\" \"9 SPADE\" \n#> [11] \"5 SPADE\" \"3 HEARTS\" \"J CLUB\" \"2 DIAMOND\" \"K SPADE\" \n#> [16] \"2 HEARTS\" \"2 SPADE\" \"8 SPADE\" \"8 HEARTS\" \"6 HEARTS\" \n#> [21] \"7 HEARTS\" \"6 CLUB\" \"K CLUB\" \"3 CLUB\" \"10 SPADE\" \n#> [26] \"3 DIAMOND\" \"Q SPADE\" \"9 HEARTS\" \"J DIAMOND\" \"7 DIAMOND\" \n#> [31] \"9 DIAMOND\" \"7 SPADE\" \"4 DIAMOND\" \"10 HEARTS\" \"2 CLUB\" \n#> [36] \"4 SPADE\" \"4 HEARTS\" \"8 CLUB\" \"K HEARTS\" \"A SPADE\" \n#> [41] \"A HEARTS\" \"5 HEARTS\" \"A DIAMOND\" \"5 CLUB\" \"7 CLUB\" \n#> [46] \"Q DIAMOND\" \"A CLUB\" \"10 CLUB\" \"3 SPADE\" \"K DIAMOND\" \n#> [51] \"J HEARTS\" \"6 DIAMOND\"\nmy_deck$draw(10)\n#> Error: Only 0 cards remaining.\n\nmy_deck$reshuffle()$draw(5)\n#> [1] \"6 DIAMOND\" \"2 CLUB\" \"Q DIAMOND\" \"9 CLUB\" \"J DIAMOND\"\nmy_deck$reshuffle()$draw(5)\n#> [1] \"8 CLUB\" \"9 SPADE\" \"2 SPADE\" \"Q HEARTS\" \"6 SPADE\"\n\nQ3: Why can’t you model a bank account or a deck of cards with an S3 class?\nA: Because S3 classes obey R’s usual semantics of copy-on-modify: every time you deposit money into your bank account or draw a card from the deck, you’d get a new copy of the object.\nIt is possible to combine S3 classes with an environment (which is how R6 works), but it is ill-advised to create an object that looks like a regular R object but has reference semantics.\nQ4: Create an R6 class that allows you to get and set the current time zone. You can access the current time zone with Sys.timezone() and set it with Sys.setenv(TZ = \"newtimezone\"). When setting the time zone, make sure the new time zone is in the list provided by OlsonNames().\nA: To create an R6 class that allows us to get and set the time zone, we provide the respective functions as public methods to the R6 class.\n\nTimezone <- R6Class(\n classname = \"Timezone\",\n public = list(\n get = function() {\n Sys.timezone()\n },\n set = function(value) {\n stopifnot(value %in% OlsonNames())\n\n old <- self$get()\n Sys.setenv(TZ = value)\n invisible(old)\n }\n )\n)\n\n(When setting, we return the old value invisibly because this makes it easy to restore the previous value.)\nNow, let us create one instance of this class and test, if we can set and get the time zone as intended.\n\ntz <- Timezone$new()\n\nold <- tz$set(\"Antarctica/South_Pole\")\ntz$get()\n#> [1] \"America/Toronto\"\n\ntz$set(old)\ntz$get()\n#> [1] \"America/Toronto\"\n\nQ5: Create an R6 class that manages the current working directory. It should have $get() and $set() methods.\nA: Take a look at the following implementation, which is quite minimalistic:\n\nWorkingDirectory <- R6Class(\n classname = \"WorkingDirectory\",\n public = list(\n get = function() {\n getwd()\n },\n set = function(value) {\n setwd(value)\n }\n )\n)\n\n\nQ6: Why can’t you model the time zone or current working directory with an S3 class?\nA: Because S3 classes are not suitable for modelling a state that changes over time. S3 methods should (almost) always return the same result when called with the same inputs.\nQ7: What base type are R6 objects built on top of? What attributes do they have?\nA: R6 objects are built on top of environments. They have a class attribute, which is a character vector containing the class name, the name of any super classes (if existent) and the string \"R6\" as the last element." + }, + { + "objectID": "14_R6.html#controlling-access", + "href": "14_R6.html#controlling-access", + "title": "14 - R6", + "section": "Controlling access", + "text": "Controlling access\nQ1: Create a bank account class that prevents you from directly setting the account balance, but that you can still withdraw from and deposit to. Throw an error if you attempt to go into overdraft.\nA: To fulfil this requirement, we make balance a private field. The user has to use the $deposit() and $withdraw() methods which have access to the balance field.\n\nBankAccountStrict2 <- R6Class(\n classname = \"BankAccountStrict2\",\n public = list(\n deposit = function(dep = 0) {\n private$balance <- private$balance + dep\n invisible(self)\n },\n withdraw = function(draw = 0) {\n if (private$balance - draw < 0) {\n stop(\n \"Your `withdraw` must be smaller \",\n \"than your `balance`.\",\n call. = FALSE\n )\n }\n private$balance <- private$balance - draw\n invisible(self)\n }\n ),\n private = list(\n balance = 0\n )\n)\n\nTo test our new class, we create an instance and try to go into overdraft.\n\nmy_account_strict_2 <- BankAccountStrict2$new()\n\nmy_account_strict_2$deposit(5)\nmy_account_strict_2$withdraw(10)\n#> Error: Your `withdraw` must be smaller than your `balance`.\n\nQ2: Create a class with a write-only $password field. It should have $check_password(password) method that returns TRUE or FALSE, but there should be no way to view the complete password.\nA: To protect the password from changes and direct access, the password will be a private field. Further, our Password will get its own print method which hides the password.\n\nPassword <- R6Class(\n classname = \"Password\",\n public = list(\n print = function(...) {\n cat(\"<Password>: ********\\n\")\n invisible(self)\n },\n set = function(value) {\n private$password <- value\n },\n check = function(password) {\n identical(password, private$password)\n }\n ),\n private = list(\n password = NULL\n )\n)\n\nLet’s create one instance of our new class and confirm that the password is neither accessible nor visible, but still check-able.\n\nmy_pw <- Password$new()\nmy_pw$set(\"snuffles\")\nmy_pw$password\n#> NULL\nmy_pw\n#> <Password>: ********\nmy_pw$check(\"snuggles\")\n#> [1] FALSE\nmy_pw$check(\"snuffles\")\n#> [1] TRUE\n\nQ3: Extend the Rando class with another active binding that allows you to access the previous random value. Ensure that active binding is the only way to access the value.\nA: To access the previous random value from an instance, we add a private $last_random field to our class, and we modify $random() to write to this field, whenever it is called. To access the $last_random field we provide $previous().\n\nRando <- R6::R6Class(\n classname = \"Rando\",\n private = list(\n last_random = NULL\n ),\n active = list(\n random = function(value) {\n if (missing(value)) {\n private$last_random <- runif(1)\n private$last_random\n } else {\n stop(\"Can't set `$random`.\", call. = FALSE)\n }\n },\n previous = function(value) {\n if (missing(value)) {\n private$last_random\n }\n }\n )\n)\n\nNow, we initiate a new Rando object and see if it behaves as expected.\n\nx <- Rando$new()\nx$random\n#> [1] 0.349\nx$random\n#> [1] 0.947\nx$previous\n#> [1] 0.947\n\nQ4: Can subclasses access private fields/methods from their parent? Perform an experiment to find out.\nA: To find out if private fields/methods can be accessed from subclasses, we first create a class A with a private field foo and a private method bar(). Afterwards, an instance of a subclass B is created and calls the foobar() methods, which tries to access the foo field and the bar() method from its superclass A.\n\nA <- R6Class(\n classname = \"A\",\n private = list(\n field = \"foo\",\n method = function() {\n \"bar\"\n }\n )\n)\n\nB <- R6Class(\n classname = \"B\",\n inherit = A,\n public = list(\n test = function() {\n cat(\"Field: \", super$field, \"\\n\", sep = \"\")\n cat(\"Method: \", super$method(), \"\\n\", sep = \"\")\n }\n )\n)\n\nB$new()$test()\n#> Field: \n#> Method: bar\n\nWe conclude that subclasses can access private methods from their superclasses, but not private fields." + }, + { + "objectID": "14_R6.html#reference-semantics", + "href": "14_R6.html#reference-semantics", + "title": "14 - R6", + "section": "Reference semantics", + "text": "Reference semantics\nQ1: Create a class that allows you to write a line to a specified file. You should open a connection to the file in $initialize(), append a line using cat() in $append_line(), and close the connection in $finalize().\nA: Our FileWriter class will create a connection to a file at initialization. Therefore, we open a connection to a user specified file during the initialisation. Note that we need to set open = \"a\" in file() to open connection for appending text. Otherwise, cat() would only work when applied to files, but not with connections as explicitly asked for in the exercise. Further, we add the append_line() method and a close() statement as finalizer.\n\nFileWriter <- R6::R6Class(\n classname = \"FileWriter\",\n public = list(\n con = NULL,\n initialize = function(filename) {\n self$con <- file(filename, open = \"a\")\n },\n finalize = function() {\n close(self$con)\n },\n append_line = function(x) {\n cat(x, \"\\n\", sep = \"\", file = self$con)\n }\n )\n)\n\nLet’s see, if new instances of our class work as expected.\n\ntmp_file <- tempfile()\nmy_fw <- FileWriter$new(tmp_file)\n\nreadLines(tmp_file)\n#> character(0)\nmy_fw$append_line(\"First\")\nmy_fw$append_line(\"Second\")\nreadLines(tmp_file)\n#> [1] \"First\" \"Second\"" + }, + { + "objectID": "14_R6.html#references", + "href": "14_R6.html#references", + "title": "14 - R6", + "section": "References", + "text": "References\n\n\n\n\nChang, Winston. 2020. R6: Encapsulated Classes with Reference Semantics. https://github.com/r-lib/R6." + }, + { + "objectID": "15_S4.html#prerequisites", + "href": "15_S4.html#prerequisites", + "title": "15 - S4", + "section": "Prerequisites", + "text": "Prerequisites\nWe load the {methods} package (R Core Team 2020) as it contains the S4 object-oriented programming system.\n\nlibrary(methods)" + }, + { + "objectID": "15_S4.html#basics", + "href": "15_S4.html#basics", + "title": "15 - S4", + "section": "Basics", + "text": "Basics\nQ1: lubridate::period() returns an S4 class. What slots does it have? What class is each slot? What accessors does it provide?\nA: Objects of the S4 Period class have six slots named year, month, day, hour, minute, and .Data (which contains the number of seconds). All slots are of type double. Most fields can be retrieved by an identically named accessor (e.g. lubridate::year() will return the field), use second() to get the .Data slot.\nAs a short example, we create a period of 1 second, 2 minutes, 3 hours, 4 days and 5 weeks.\n\nexample_12345 <- lubridate::period(\n c(1, 2, 3, 4, 5),\n c(\"second\", \"minute\", \"hour\", \"day\", \"week\")\n)\n\nThis should add up to a period of 39 days, 3 hours, 2 minutes and 1 second.\n\nexample_12345\n#> [1] \"39d 3H 2M 1S\"\n\nWhen we inspect example_12345, we see the fields and infer that the seconds are stored in the .Data field.\n\nstr(example_12345)\n#> Formal class 'Period' [package \"lubridate\"] with 6 slots\n#> ..@ .Data : num 1\n#> ..@ year : num 0\n#> ..@ month : num 0\n#> ..@ day : num 39\n#> ..@ hour : num 3\n#> ..@ minute: num 2\n\nQ2: What other ways can you find help for a method? Read ?\"?\" and summarise the details.\nA: Besides adding ? in front of a function call (i.e. ?method()), we may find:\n\ngeneral documentation for a generic via ?genericName\ngeneral documentation for the methods of a generic via methods?genericName\ndocumentation for a specific method via ClassName?methodName." + }, + { + "objectID": "15_S4.html#classes", + "href": "15_S4.html#classes", + "title": "15 - S4", + "section": "Classes", + "text": "Classes\nQ1: Extend the Person class with fields to match utils::person(). Think about what slots you will need, what class each slot should have, and what you’ll need to check in your validity method.\nA: The Person class from Advanced R contains the slots name and age. The person class from the {utils} package contains the slots given (vector of given names), family, role, email and comment (see ?utils::person).\nAll slots from utils::person() besides role must be of type character and length 1. The entries in the role slot must match one of the following abbreviations “aut”, “com”, “cph”, “cre”, “ctb”, “ctr”, “dtc”, “fnd”, “rev”, “ths”, “trl”. Therefore, role might be of different length than the other slots and we’ll add a corresponding constraint within the validator.\n\n# Definition of the Person class\nsetClass(\"Person\",\n slots = c(\n age = \"numeric\",\n given = \"character\",\n family = \"character\",\n role = \"character\",\n email = \"character\",\n comment = \"character\"\n ),\n prototype = list(\n age = NA_real_,\n given = NA_character_,\n family = NA_character_,\n role = NA_character_,\n email = NA_character_,\n comment = NA_character_\n )\n)\n\n# Helper to create instances of the Person class\nPerson <- function(given, family,\n age = NA_real_,\n role = NA_character_,\n email = NA_character_,\n comment = NA_character_) {\n age <- as.double(age)\n\n new(\"Person\",\n age = age,\n given = given,\n family = family,\n role = role,\n email = email,\n comment = comment\n )\n}\n\n# Validator to ensure that each slot is of length one\nsetValidity(\"Person\", function(object) {\n invalids <- c()\n if (length(object@age) != 1 ||\n length(object@given) != 1 ||\n length(object@family) != 1 ||\n length(object@email) != 1 ||\n length(object@comment) != 1) {\n invalids <- paste0(\n \"@name, @age, @given, @family, @email, \",\n \"@comment must be of length 1\"\n )\n }\n\n known_roles <- c(\n NA_character_, \"aut\", \"com\", \"cph\", \"cre\", \"ctb\",\n \"ctr\", \"dtc\", \"fnd\", \"rev\", \"ths\", \"trl\"\n )\n\n if (!all(object@role %in% known_roles)) {\n paste(\n \"@role(s) must be one of\",\n paste(known_roles, collapse = \", \")\n )\n }\n\n if (length(invalids)) {\n return(invalids)\n }\n TRUE\n})\n#> Class \"Person\" [in \".GlobalEnv\"]\n#> \n#> Slots:\n#> \n#> Name: age given family role email comment\n#> Class: numeric character character character character character\n\nQ2: What happens if you define a new S4 class that doesn’t have any slots? (Hint: read about virtual classes in ?setClass.)\nA: It depends on the other arguments. If we inherit from another class, we get the same slots. But something interesting happens if we don’t inherit from an existing class. We get a virtual class. A virtual class can’t be instantiated:\n\nsetClass(\"Human\")\nnew(\"Human\")\n#> Error in new(\"Human\"): trying to generate an object from a virtual class (\"Human\")\n\nBut can be inherited from:\n\nsetClass(\"Programmer\", contains = \"Human\")\n\nQ3: Imagine you were going to reimplement factors, dates, and data frames in S4. Sketch out the setClass() calls that you would use to define the classes. Think about appropriate slots and prototype.\nA: For all these classes we need one slot for the data and one slot per attribute. Keep in mind, that inheritance matters for ordered factors and dates. For data frames, special checks like equal lengths of the underlying list’s elements should be done within a validator.\nFor simplicity we don’t introduce an explicit subclass for ordered factors. Instead, we introduce ordered as a slot.\n\nsetClass(\"Factor\",\n slots = c(\n data = \"integer\",\n levels = \"character\",\n ordered = \"logical\"\n ),\n prototype = list(\n data = integer(),\n levels = character(),\n ordered = FALSE\n )\n)\n\n\nnew(\"Factor\", data = c(1L, 2L), levels = letters[1:3])\n#> An object of class \"Factor\"\n#> Slot \"data\":\n#> [1] 1 2\n#> \n#> Slot \"levels\":\n#> [1] \"a\" \"b\" \"c\"\n#> \n#> Slot \"ordered\":\n#> [1] FALSE\n\nThe Date2 class stores its dates as integers, similarly to base R which uses doubles. Dates don’t have any other attributes.\n\nsetClass(\"Date2\",\n slots = list(\n data = \"integer\"\n ),\n prototype = list(\n data = integer()\n )\n)\n\nnew(\"Date2\", data = 1L)\n#> An object of class \"Date2\"\n#> Slot \"data\":\n#> [1] 1\n\nOur DataFrame class consists of a list and a slot for row.names. Most of the logic (e.g. checking that all elements of the list are a vector, and that they all have the same length) would need to be part of a validator.\n\nsetClass(\"DataFrame\",\n slots = c(\n data = \"list\",\n row.names = \"character\"\n ),\n prototype = list(\n data = list(),\n row.names = character(0)\n )\n)\n\nnew(\"DataFrame\", data = list(a = 1, b = 2))\n#> An object of class \"DataFrame\"\n#> Slot \"data\":\n#> $a\n#> [1] 1\n#> \n#> $b\n#> [1] 2\n#> \n#> \n#> Slot \"row.names\":\n#> character(0)" + }, + { + "objectID": "15_S4.html#generics-and-methods", + "href": "15_S4.html#generics-and-methods", + "title": "15 - S4", + "section": "Generics and methods", + "text": "Generics and methods\nQ1: Add age() accessors for the Person class.\nA: We implement the accessors via an age() generic, with a method for the Person class and a corresponding replacement function age<-:\n\nsetGeneric(\"age\", function(x) standardGeneric(\"age\"))\n#> [1] \"age\"\nsetMethod(\"age\", \"Person\", function(x) x@age)\n\nsetGeneric(\"age<-\", function(x, value) standardGeneric(\"age<-\"))\n#> [1] \"age<-\"\nsetMethod(\"age<-\", \"Person\", function(x, value) {\n x@age <- value\n validObject(x)\n x\n})\n\nQ2: In the definition of the generic, why is it necessary to repeat the name of the generic twice?\nA: Within setGeneric() the name (1st argument) is needed as the name of the generic. Then, the name also explicitly incorporates method dispatch via standardGeneric() within the generic’s body (def parameter of setGeneric()). This behaviour is similar to UseMethod() in S3.\nQ3: Why does the show() method defined in section 15.4.3 use is(object)[[1]]? (Hint: try printing the employee subclass.)\nA: is(object) returns the class of the object. is(object) also contains the superclass, for subclasses like Employee. In order to always return the most specific class (the subclass), show() returns the first element of is(object).\nQ4: What happens if you define a method with different argument names to the generic?\nA: It depends. We first create the object hadley of class Person:\n\n.Person <- setClass(\n \"Person\",\n slots = c(name = \"character\", age = \"numeric\")\n)\n\nhadley <- .Person(name = \"Hadley\")\nhadley\n#> An object of class \"Person\"\n#> Slot \"name\":\n#> [1] \"Hadley\"\n#> \n#> Slot \"age\":\n#> numeric(0)\n\nNow let’s see which arguments can be supplied to the show() generic.\n\nformals(\"show\")\n#> $object\n\nUsually, we would use this argument when defining a new method.\n\nsetMethod(\"show\", \"Person\", function(object) {\n cat(object@name, \"creates hard exercises\")\n})\n\nhadley\n#> Hadley creates hard exercises\n\nWhen we supply another name as a first element of our method (e.g. x instead of object), this element will be matched to the correct object argument and we receive a warning. Our method will work, though:\n\nsetMethod(\"show\", \"Person\", function(x) {\n cat(x@name, \"creates hard exercises\")\n})\n#> Warning: For function 'show', signature 'Person': argument in method definition\n#> changed from (x) to (object)\n\nhadley\n#> Hadley creates hard exercises\n\nIf we add more arguments to our method than our generic can handle, we will get an error.\n\nsetMethod(\"show\", \"Person\", function(x, y) {\n cat(x@name, \"is\", x@age, \"years old\")\n})\n#> Error in conformMethod(signature, mnames, fnames, f, fdef, definition): in method for 'show' with signature 'object=\"Person\"': formal arguments (object = \"Person\") omitted in the method definition cannot be in the signature\n\nIf we do this with arguments added to the correctly written object argument, we will receive an informative error message. It states that we could add other argument names for generics, which can take the ... argument.\n\nsetMethod(\"show\", \"Person\", function(object, y) {\n cat(object@name, \"is\", object@age, \"years old\")\n})\n#> Error in rematchDefinition(definition, fdef, mnames, fnames, signature): methods can add arguments to the generic 'show' only if '...' is an argument to the generic" + }, + { + "objectID": "15_S4.html#method-dispatch", + "href": "15_S4.html#method-dispatch", + "title": "15 - S4", + "section": "Method dispatch", + "text": "Method dispatch\nQ1: Draw the method graph for f(😅, 😽).\nA: Look at the graph and repeat after me: “I will keep my class structure simple and use multiple inheritance sparingly”.\n\n\n\n\n\n\n\n\n\nQ2: Draw the method graph for f(😃, 😉, 😙).\nA: We see that the method graph below looks simpler than the one above. Relatively speaking, multiple dispatch seems to introduce less complexity than multiple inheritance. Use it with care, though!\n\n\n\n\n\n\n\n\n\nQ3: Take the last example which shows multiple dispatch over two classes that use multiple inheritance. What happens if you define a method for all terminal classes? Why does method dispatch not save us much work here?\nA: We will introduce ambiguity, since one class has distance 2 to all terminal nodes and the other four have distance 1 to two terminal nodes each. To resolve this ambiguity we have to define five more methods, one per class combination." + }, + { + "objectID": "15_S4.html#s4-and-s3", + "href": "15_S4.html#s4-and-s3", + "title": "15 - S4", + "section": "S4 and S3", + "text": "S4 and S3\nQ1: What would a full setOldClass() definition look like for an ordered factor (i.e. add slots and prototype to the definition above)?\nA: The purpose of setOldClass() lies in registering an S3 class as a “formally defined class”, so that it can be used within the S4 object-oriented programming system. When using it, we may provide the argument S4Class, which will inherit the slots and their default values (prototype) to the registered class.\nLet’s build an S4 OrderedFactor on top of the S3 factor in such a way.\n\nsetOldClass(\"factor\") # use build-in definition for brevity\n\nOrderedFactor <- setClass(\n \"OrderedFactor\",\n contains = \"factor\", # inherit from registered S3 class\n slots = c(\n levels = \"character\",\n ordered = \"logical\" # add logical order slot\n ),\n prototype = structure(\n integer(),\n levels = character(),\n ordered = logical() # add default value\n )\n)\n\nWe can now register the (S3) ordered-class, while providing an “S4 template”. We can also use the S4-class to create new object directly.\n\nsetOldClass(\"ordered\", S4Class = \"OrderedFactor\")\n\nx <- OrderedFactor(\n c(1L, 2L, 2L),\n levels = c(\"a\", \"b\", \"c\"),\n ordered = TRUE\n)\nstr(x)\n#> Formal class 'OrderedFactor' [package \".GlobalEnv\"] with 4 slots\n#> ..@ .Data : int [1:3] 1 2 2\n#> ..@ levels : chr [1:3] \"a\" \"b\" \"c\"\n#> ..@ ordered : logi TRUE\n#> ..@ .S3Class: chr \"factor\"\n\nQ2: Define a length method for the Person class.\nA: We keep things simple and will just return \"180cm\" when the length() method is called on a Person object. The method can be defined either as an S3 or S4 method.\n\nlength.Person <- function(x) \"180cm\" # S3\nsetMethod(\"length\", \"Person\", function(x) \"180cm\") # S4" + }, + { + "objectID": "15_S4.html#references", + "href": "15_S4.html#references", + "title": "15 - S4", + "section": "References", + "text": "References\n\n\n\n\nR Core Team. 2020. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/." + }, + { + "objectID": "18_Expressions.html#prerequisites", + "href": "18_Expressions.html#prerequisites", + "title": "18 - Expressions", + "section": "Prerequisites", + "text": "Prerequisites\nTo capture and compute on expressions, and to visualise them, we will load the {rlang} (Henry and Wickham 2020) and the {lobstr} (Wickham 2019) packages.\n\nlibrary(rlang)\nlibrary(lobstr)" + }, + { + "objectID": "18_Expressions.html#abstract-syntax-trees", + "href": "18_Expressions.html#abstract-syntax-trees", + "title": "18 - Expressions", + "section": "Abstract syntax trees", + "text": "Abstract syntax trees\nQ1: Reconstruct the code represented by the trees below:\n\n#> █─f \n#> └─█─g \n#> └─█─h\n#> █─`+` \n#> ├─█─`+` \n#> │ ├─1 \n#> │ └─2 \n#> └─3\n#> █─`*` \n#> ├─█─`(` \n#> │ └─█─`+` \n#> │ ├─x \n#> │ └─y \n#> └─z\n\nA: Let the source (of the code chunks above) be with you and show you how the ASTs (abstract syntax trees) were produced.\n\nast(f(g(h())))\n#> █─f \n#> └─█─g \n#> └─█─h\n\nast(1 + 2 + 3)\n#> █─`+` \n#> ├─█─`+` \n#> │ ├─1 \n#> │ └─2 \n#> └─3\n\nast((x + y) * z)\n#> █─`*` \n#> ├─█─`(` \n#> │ └─█─`+` \n#> │ ├─x \n#> │ └─y \n#> └─z\n\nQ2: Draw the following trees by hand then check your answers with ast().\n\nf(g(h(i(1, 2, 3))))\nf(1, g(2, h(3, i())))\nf(g(1, 2), h(3, i(4, 5)))\n\nA: Let us delegate the drawing to the {lobstr} package.\n\nast(f(g(h(i(1, 2, 3)))))\n#> █─f \n#> └─█─g \n#> └─█─h \n#> └─█─i \n#> ├─1 \n#> ├─2 \n#> └─3\n\nast(f(1, g(2, h(3, i()))))\n#> █─f \n#> ├─1 \n#> └─█─g \n#> ├─2 \n#> └─█─h \n#> ├─3 \n#> └─█─i\n\nast(f(g(1, 2), h(3, i(4, 5))))\n#> █─f \n#> ├─█─g \n#> │ ├─1 \n#> │ └─2 \n#> └─█─h \n#> ├─3 \n#> └─█─i \n#> ├─4 \n#> └─5\n\nQ3: What’s happening with the ASTs below? (Hint: carefully read ?\"^\")\n\nast(`x` + `y`)\n#> █─`+` \n#> ├─x \n#> └─y\nast(x**y)\n#> █─`^` \n#> ├─x \n#> └─y\nast(1 -> x)\n#> █─`<-` \n#> ├─x \n#> └─1\n\nA: ASTs start function calls with the name of the function. This is why the call in the first expression is translated into its prefix form. In the second case, ** is translated by R’s parser into ^. In the last AST, the expression is flipped when R parses it:\n\nstr(expr(x**y))\n#> language x^y\nstr(expr(a -> b))\n#> language b <- a\n\nQ4: What is special about the AST below? (Hint: re-read section 6.2.1)\n\nast(function(x = 1, y = 2) {})\n#> █─`function` \n#> ├─█─x = 1 \n#> │ └─y = 2 \n#> ├─█─`{` \n#> └─<inline srcref>\n\nA: The last leaf of the AST is not explicitly specified in the expression. Instead, the srcref attribute, which points to the functions source code, is automatically created by base R.\nQ5: What does the call tree of an if statement with multiple else if conditions look like? Why?\nA: The AST of nested else if statements might look a bit confusing because it contains multiple curly braces. However, we can see that in the else part of the AST just another expression is being evaluated, which happens to be an if statement and so forth.\n\nast(\n if (FALSE) {\n 1\n } else if (FALSE) {\n 2\n } else if (TRUE) {\n 3\n }\n)\n#> █─`if` \n#> ├─FALSE \n#> ├─█─`{` \n#> │ └─1 \n#> └─█─`if` \n#> ├─FALSE \n#> ├─█─`{` \n#> │ └─2 \n#> └─█─`if` \n#> ├─TRUE \n#> └─█─`{` \n#> └─3\n\nWe can see the structure more clearly if we avoid the curly braces:\n\nast(\n if (FALSE) {\n 1\n } else if (FALSE) {\n 2\n } else if (TRUE) 3\n)\n#> █─`if` \n#> ├─FALSE \n#> ├─█─`{` \n#> │ └─1 \n#> └─█─`if` \n#> ├─FALSE \n#> ├─█─`{` \n#> │ └─2 \n#> └─█─`if` \n#> ├─TRUE \n#> └─3" + }, + { + "objectID": "18_Expressions.html#expressions", + "href": "18_Expressions.html#expressions", + "title": "18 - Expressions", + "section": "Expressions", + "text": "Expressions\nQ1: Which two of the six types of atomic vector can’t appear in an expression? Why? Similarly, why can’t you create an expression that contains an atomic vector of length greater than one?\nA: There is no way to create raws and complex atomics without using a function call (this is only possible for imaginary scalars like i, 5i etc.). But expressions that include a function are calls. Therefore, both of these vector types cannot appear in an expression.\nSimilarly, it is not possible to create an expression that evaluates to an atomic of length greater than one without using a function (e.g. c()).\nLet’s make this observation concrete via an example:\n\n# Atomic\nis_atomic(expr(1))\n#> [1] TRUE\n\n# Not an atomic (although it would evaluate to an atomic)\nis_atomic(expr(c(1, 1)))\n#> [1] FALSE\nis_call(expr(c(1, 1)))\n#> [1] TRUE\n\nQ2: What happens when you subset a call object to remove the first element, e.g. expr(read.csv(\"foo.csv\", header = TRUE))[-1]. Why?\nA: When the first element of a call object is removed, the second element moves to the first position, which is the function to call. Therefore, we get \"foo.csv\"(header = TRUE).\nQ3: Describe the differences between the following call objects.\n\nx <- 1:10\n\ncall2(median, x, na.rm = TRUE)\ncall2(expr(median), x, na.rm = TRUE)\ncall2(median, expr(x), na.rm = TRUE)\ncall2(expr(median), expr(x), na.rm = TRUE)\n\nA: The call objects differ in their first two elements, which are in some cases evaluated before the call is constructed. In the first one, both median() and x are evaluated and inlined into the call. Therefore, we can see in the constructed call that median is a generic and the x argument is 1:10.\n\ncall2(median, x, na.rm = TRUE)\n#> (function (x, na.rm = FALSE, ...) \n#> UseMethod(\"median\"))(1:10, na.rm = TRUE)\n\nIn the following calls we remain with differing combinations. Once, only x and once only median() gets evaluated.\n\ncall2(expr(median), x, na.rm = TRUE)\n#> median(1:10, na.rm = TRUE)\ncall2(median, expr(x), na.rm = TRUE)\n#> (function (x, na.rm = FALSE, ...) \n#> UseMethod(\"median\"))(x, na.rm = TRUE)\n\nIn the final call neither x nor median() is evaluated.\n\ncall2(expr(median), expr(x), na.rm = TRUE)\n#> median(x, na.rm = TRUE)\n\nNote that all these calls will generate the same result when evaluated. The key difference is when the values bound to the x and median symbols are found.\nQ4: rlang::call_standardise() doesn’t work so well for the following calls. Why? What makes mean() special?\n\ncall_standardise(quote(mean(1:10, na.rm = TRUE)))\n#> Warning: `call_standardise()` is deprecated as of rlang 0.4.11\n#> This warning is displayed once every 8 hours.\n#> mean(x = 1:10, na.rm = TRUE)\ncall_standardise(quote(mean(n = T, 1:10)))\n#> mean(x = 1:10, n = T)\ncall_standardise(quote(mean(x = 1:10, , TRUE)))\n#> mean(x = 1:10, , TRUE)\n\nA: The reason for this unexpected behaviour is that mean() uses the ... argument and therefore cannot standardise the regarding arguments. Since mean() uses S3 dispatch (i.e. UseMethod()) and the underlying mean.default() method specifies some more arguments, call_standardise() can do much better with a specific S3 method.\n\ncall_standardise(quote(mean.default(1:10, na.rm = TRUE)))\n#> mean.default(x = 1:10, na.rm = TRUE)\ncall_standardise(quote(mean.default(n = T, 1:10)))\n#> mean.default(x = 1:10, na.rm = T)\ncall_standardise(quote(mean.default(x = 1:10, , TRUE)))\n#> mean.default(x = 1:10, na.rm = TRUE)\n\nQ5: Why does this code not make sense?\n\nx <- expr(foo(x = 1))\nnames(x) <- c(\"x\", \"\")\n\nA: As stated in Advanced R\n\nThe first element of a call is always the function that gets called.\n\nLet’s see what happens when we run the code\n\nx <- expr(foo(x = 1))\nx\n#> foo(x = 1)\n\nnames(x) <- c(\"x\", \"\")\nx\n#> foo(1)\n\nnames(x) <- c(\"\", \"x\")\nx\n#> foo(x = 1)\n\nSo, giving the first element a name just adds metadata that R ignores.\nQ6: Construct the expression if(x > 1) \"a\" else \"b\" using multiple calls to call2(). How does the code structure reflect the structure of the AST?\nA: Similar to the prefix version we get\n\ncall2(\"if\", call2(\">\", sym(\"x\"), 1), \"a\", \"b\")\n#> if (x > 1) \"a\" else \"b\"\n\nWhen we read the AST from left to right, we get the same structure: Function to evaluate, expression, which is another function and is evaluated first, and two constants which will be evaluated next.\n\nast(`if`(x > 1, \"a\", \"b\"))\n#> █─`if` \n#> ├─█─`>` \n#> │ ├─x \n#> │ └─1 \n#> ├─\"a\" \n#> └─\"b\"" + }, + { + "objectID": "18_Expressions.html#parsing-and-grammar", + "href": "18_Expressions.html#parsing-and-grammar", + "title": "18 - Expressions", + "section": "Parsing and grammar", + "text": "Parsing and grammar\nQ1: R uses parentheses in two slightly different ways as illustrated by these two calls:\n\nf((1))\n`(`(1 + 1)\n\nCompare and contrast the two uses by referencing the AST.\nA: The trick with these examples lies in the fact that ( can be a part of R’s general prefix function syntax but can also represent a call to the ( function.\nSo, in the AST of the first example, we will not see the outer ( since it is prefix function syntax and belongs to f(). In contrast, the inner ( is a function (represented as a symbol in the AST):\n\nast(f((1)))\n#> █─f \n#> └─█─`(` \n#> └─1\n\nIn the second example, we can see that the outer ( is a function and the inner ( belongs to its syntax:\n\nast(`(`(1 + 1))\n#> █─`(` \n#> └─█─`+` \n#> ├─1 \n#> └─1\n\nFor the sake of clarity, let’s also create a third example, where none of the ( is part of another function’s syntax:\n\nast(((1 + 1)))\n#> █─`(` \n#> └─█─`(` \n#> └─█─`+` \n#> ├─1 \n#> └─1\n\nQ2: = can also be used in two ways. Construct a simple example that shows both uses.\nA: = is used both for assignment, and for naming arguments in function calls:\n\nb <- c(c = 1)\n\nSo, when we play with ast(), we can directly see that the following is not possible:\n\nast(b = c(c = 1))\n#> Error in ast(b = c(c = 1)): unused argument (b = c(c = 1))\n\nWe get an error because b = makes R looking for an argument called b. Since x is the only argument of ast(), we get an error.\nThe easiest way around this problem is to wrap this line in {}.\n\nast({\n b <- c(c = 1)\n})\n#> █─`{` \n#> └─█─`<-` \n#> ├─b \n#> └─█─c \n#> └─c = 1\n\nWhen we ignore the braces and compare the trees, we can see that the first = is used for assignment and the second = is part of the syntax of function calls.\nQ3: Does -2^2 yield 4 or -4? Why?\nA: It yields -4, because ^ has a higher operator precedence than -, which we can verify by looking at the AST (or looking it up under ?\"Syntax\"):\n\n-2^2\n#> [1] -4\n\nast(-2^2)\n#> █─`-` \n#> └─█─`^` \n#> ├─2 \n#> └─2\n\nQ4: What does !1 + !1 return? Why?\nA: The answer is a little surprising:\n\n!1 + !1\n#> [1] FALSE\n\nTo answer the “why?”, we take a look at the AST:\n\nast(!1 + !1)\n#> █─`!` \n#> └─█─`+` \n#> ├─1 \n#> └─█─`!` \n#> └─1\n\nThe right !1 is evaluated first. It evaluates to FALSE, because R coerces every non 0 numeric to TRUE, when a logical operator is applied. The negation of TRUE then equals FALSE.\nNext 1 + FALSE is evaluated to 1, since FALSE is coerced to 0.\nFinally !1 is evaluated to FALSE.\nNote that if ! had a higher precedence, the intermediate result would be FALSE + FALSE, which would evaluate to 0.\nQ5: Why does x1 <- x2 <- x3 <- 0 work? Describe the two reasons.\nA: One reason is that <- is right-associative, i.e. evaluation takes place from right to left:\n\nx1 <- (x2 <- (x3 <- 0))\n\nThe other reason is that <- invisibly returns the value on the right-hand side.\n\n(x3 <- 0)\n#> [1] 0\n\nQ6: Compare the ASTs of x + y %+% z and x ^ y %+% z. What have you learned about the precedence of custom infix functions?\nA: Let’s take a look at the syntax trees:\n\nast(x + y %+% z)\n#> █─`+` \n#> ├─x \n#> └─█─`%+%` \n#> ├─y \n#> └─z\n\nHere y %+% z will be calculated first and the result will be added to x.\n\nast(x^y %+% z)\n#> █─`%+%` \n#> ├─█─`^` \n#> │ ├─x \n#> │ └─y \n#> └─z\n\nHere x ^ y will be calculated first, and the result will be used as first argument to %+%().\nWe can conclude that custom infix functions have precedence between addition and exponentiation.\nThe exact precedence of infix functions can be looked up under ?\"Syntax\" where we see that it lies directly behind the sequence operator (:) and in front of the multiplication and division operators (* and /).\nQ7: What happens if you call parse_expr() with a string that generates multiple expressions, e.g. parse_expr(\"x + 1; y + 1\")?\nA: In this case parse_expr() notices that more than one expression would have to be generated and throws an error.\n\nparse_expr(\"x + 1; y + 1\")\n#> Error in `parse_expr()`:\n#> ! `x` must contain exactly 1 expression, not 2.\n\nQ8: What happens if you attempt to parse an invalid expression, e.g. \"a +\" or \"f())\"?\nA: Invalid expressions will lead to an error in the underlying parse() function.\n\nparse_expr(\"a +\")\n#> Error in parse(text = x, keep.source = FALSE): <text>:2:0: unexpected end of input\n#> 1: a +\n#> ^\nparse_expr(\"f())\")\n#> Error in parse(text = x, keep.source = FALSE): <text>:1:4: unexpected ')'\n#> 1: f())\n#> ^\n\nparse(text = \"a +\")\n#> Error in parse(text = \"a +\"): <text>:2:0: unexpected end of input\n#> 1: a +\n#> ^\nparse(text = \"f())\")\n#> Error in parse(text = \"f())\"): <text>:1:4: unexpected ')'\n#> 1: f())\n#> ^\n\nQ9: deparse() produces vectors when the input is long. For example, the following call produces a vector of length two:\n\nexpr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m +\n n + o + p + q + r + s + t + u + v + w + x + y + z))\n\ndeparse(expr)\n\nWhat does expr_text() do instead?\nA: expr_text() will paste the results from deparse(expr) together and use a linebreak (\\n) as separator.\n\nexpr <- expr(g(a + b + c + d + e + f + g + h + i + j + k + l + m +\n n + o + p + q + r + s + t + u + v + w + x + y + z))\ndeparse(expr)\n#> [1] \"g(a + b + c + d + e + f + g + h + i + j + k + l + m + n + \"\n#> [2] \"o + p + q + r + s + t + u + v + w + x + y + z)\"\nexpr_text(expr)\n#> [1] \"g(a + b + c + d + e + f + g + h + i + j + k + l + m + n\n#> + \\n o + p + q + r + s + t + u + v + w + x + y + z)\"\n\nQ10: pairwise.t.test() assumes that deparse() always returns a length one character vector. Can you construct an input that violates this expectation? What happens?\nA: The function pairwise.t.test() captures its data arguments (x and g) so it can print the input expressions along the computed p-values. Prior to R 4.0.0 this used to be implemented via deparse(substitute(x)) in combination with paste(). This could lead to unexpected output, if one of the inputs exceeded the default width.cutoff value of 60 characters within deparse(). In this case, the expression would be split into a character vector of length greater 1.\n\n# Output in R version 3.6.2\nd <- 1\npairwise.t.test(2, d + d + d + d + d + d + d + d +\n d + d + d + d + d + d + d + d + d)\n#> Pairwise comparisons using t tests with pooled SD\n#>\n#> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d\n#> + d + d + 2 and d\n#>\n#> <0 x 0 matrix>\n#>\n#> P value adjustment method: holm\n\nIn R 4.0.0 pairwise.t.test() was updated to use the newly introduced deparse1(), which serves as a wrapper around deparse().\n\ndeparse1() is a simple utility added in R 4.0.0 to ensure a string result (character vector of length one), typically used in name construction, as deparse1(substitute(.)).\n\n\n# Output since R 4.0.0\nd <- 1\npairwise.t.test(2, d + d + d + d + d + d + d + d +\n d + d + d + d + d + d + d + d + d)\n#> Pairwise comparisons using t tests with pooled SD\n#>\n#> data: 2 and d + d + d + d + d + d + d + d + d + d + d + d + d + d\n#> + d + d + d\n#>\n#> <0 x 0 matrix>\n#>\n#> P value adjustment method: holm" + }, + { + "objectID": "18_Expressions.html#ast-funs", + "href": "18_Expressions.html#ast-funs", + "title": "18 - Expressions", + "section": "Walking AST with recursive functions", + "text": "Walking AST with recursive functions\nQ1: logical_abbr() returns TRUE for T(1, 2, 3). How could you modify logical_abbr_rec() so that it ignores function calls that use T or F?\nA: We can apply a similar logic as in the assignment example from Advanced R. We just treat it as a special case handled within a sub function called find_T_call(), which finds T() calls and “bounces them out”. Therefore, we also repeat the expr_type() helper which tells us if we are in the base or in the recursive case.\n\nexpr_type <- function(x) {\n if (rlang::is_syntactic_literal(x)) {\n \"constant\"\n } else if (is.symbol(x)) {\n \"symbol\"\n } else if (is.call(x)) {\n \"call\"\n } else if (is.pairlist(x)) {\n \"pairlist\"\n } else {\n typeof(x)\n }\n}\n\nswitch_expr <- function(x, ...) {\n switch(expr_type(x),\n ...,\n stop(\"Don't know how to handle type \",\n typeof(x),\n call. = FALSE\n )\n )\n}\n\n\nfind_T_call <- function(x) {\n if (is_call(x, \"T\")) {\n x <- as.list(x)[-1]\n purrr::some(x, logical_abbr_rec)\n } else {\n purrr::some(x, logical_abbr_rec)\n }\n}\n\nlogical_abbr_rec <- function(x) {\n switch_expr(\n x,\n # Base cases\n constant = FALSE,\n symbol = as_string(x) %in% c(\"F\", \"T\"),\n\n # Recursive cases\n pairlist = purrr::some(x, logical_abbr_rec),\n call = find_T_call(x)\n )\n}\n\nlogical_abbr <- function(x) {\n logical_abbr_rec(enexpr(x))\n}\n\nNow let’s test our new logical_abbr() function:\n\nlogical_abbr(T(1, 2, 3))\n#> [1] FALSE\nlogical_abbr(T(T, T(3, 4)))\n#> [1] TRUE\nlogical_abbr(T(T))\n#> [1] TRUE\nlogical_abbr(T())\n#> [1] FALSE\nlogical_abbr()\n#> [1] FALSE\nlogical_abbr(c(T, T, T))\n#> [1] TRUE\n\nQ2: logical_abbr() works with expressions. It currently fails when you give it a function. Why? How could you modify logical_abbr() to make it work? What components of a function will you need to recurse over?\n\nf <- function(x = TRUE) {\n g(x + T)\n}\n\nA: The function currently fails, because \"closure\" is not handled in switch_expr() within logical_abbr_rec().\n\nlogical_abbr(!!f)\n#> Error: Don't know how to handle type closure\n\nIf we want to make it work, we have to write a function to also iterate over the formals and the body of the input function.\nQ3: Modify find_assign to also detect assignment using replacement functions, i.e. names(x) <- y.\nA: Let’s see what the AST of such an assignment looks like:\n\nast(names(x) <- x)\n#> █─`<-` \n#> ├─█─names \n#> │ └─x \n#> └─x\n\nSo, we need to catch the case where the first two elements are both calls. Further the first call is identical to <- and we must return only the second call to see which objects got new values assigned.\nThis is why we add the following block within another else statement in find_assign_call():\n\nif (is_call(x, \"<-\") && is_call(x[[2]])) {\n lhs <- expr_text(x[[2]])\n children <- as.list(x)[-1]\n}\n\nLet us finish with the whole code, followed by some tests for our new function:\n\nflat_map_chr <- function(.x, .f, ...) {\n purrr::flatten_chr(purrr::map(.x, .f, ...))\n}\n\nfind_assign <- function(x) unique(find_assign_rec(enexpr(x)))\n\nfind_assign_call <- function(x) {\n if (is_call(x, \"<-\") && is_symbol(x[[2]])) {\n lhs <- as_string(x[[2]])\n children <- as.list(x)[-1]\n } else {\n if (is_call(x, \"<-\") && is_call(x[[2]])) {\n lhs <- expr_text(x[[2]])\n children <- as.list(x)[-1]\n } else {\n lhs <- character()\n children <- as.list(x)\n }\n }\n\n c(lhs, flat_map_chr(children, find_assign_rec))\n}\n\nfind_assign_rec <- function(x) {\n switch_expr(\n x,\n # Base cases\n constant = , symbol = character(),\n # Recursive cases\n pairlist = flat_map_chr(x, find_assign_rec),\n call = find_assign_call(x)\n )\n}\n\n# Tests functionality\nfind_assign(x <- y)\n#> [1] \"x\"\nfind_assign(names(x))\n#> character(0)\nfind_assign(names(x) <- y)\n#> [1] \"names(x)\"\nfind_assign(names(x(y)) <- y)\n#> [1] \"names(x(y))\"\nfind_assign(names(x(y)) <- y <- z)\n#> [1] \"names(x(y))\" \"y\"\n\nQ4: Write a function that extracts all calls to a specified function.\nA: Here we need to delete the previously added else statement and check for a call (not necessarily <-) within the first if() in find_assign_call(). We save a call when we found one and return it later as part of our character output. Everything else stays the same:\n\nfind_assign_call <- function(x) {\n if (is_call(x)) {\n lhs <- expr_text(x)\n children <- as.list(x)[-1]\n } else {\n lhs <- character()\n children <- as.list(x)\n }\n\n c(lhs, flat_map_chr(children, find_assign_rec))\n}\n\nfind_assign_rec <- function(x) {\n switch_expr(\n x,\n # Base cases\n constant = ,\n symbol = character(),\n\n # Recursive cases\n pairlist = flat_map_chr(x, find_assign_rec),\n call = find_assign_call(x)\n )\n}\n\nfind_assign(x <- y)\n#> [1] \"x <- y\"\nfind_assign(names(x(y)) <- y <- z)\n#> [1] \"names(x(y)) <- y <- z\" \"names(x(y))\" \"x(y)\" \n#> [4] \"y <- z\"\nfind_assign(mean(sum(1:3)))\n#> [1] \"mean(sum(1:3))\" \"sum(1:3)\" \"1:3\"" + }, + { + "objectID": "18_Expressions.html#references", + "href": "18_Expressions.html#references", + "title": "18 - Expressions", + "section": "References", + "text": "References\n\n\n\n\nHenry, Lionel, and Hadley Wickham. 2020. Rlang: Functions for Base Types and Core r and ’Tidyverse’ Features. https://github.com/r-lib/rlang.\n\n\nWickham, Hadley. 2019. Lobstr: Visualize r Data Structures with Trees. https://github.com/r-lib/lobstr." + }, + { + "objectID": "19_Quasiquotation.html#prerequisites", + "href": "19_Quasiquotation.html#prerequisites", + "title": "19 - Quasiquotation", + "section": "Prerequisites", + "text": "Prerequisites\nTo continue computing on the language, we keep using the {rlang} package in this chapter.\n\nlibrary(rlang)" + }, + { + "objectID": "19_Quasiquotation.html#motivation", + "href": "19_Quasiquotation.html#motivation", + "title": "19 - Quasiquotation", + "section": "Motivation", + "text": "Motivation\nQ1: For each function in the following base R code, identify which arguments are quoted and which are evaluated.\n\nlibrary(MASS)\n\nmtcars2 <- subset(mtcars, cyl == 4)\n\nwith(mtcars2, sum(vs))\nsum(mtcars2$am)\n\nrm(mtcars2)\n\nA: For each argument we first follow the advice from Advanced R and execute the argument outside of the respective function. Since MASS, cyl, vs and am are not objects contained in the global environment, their execution raises an “Object not found” error. This way we confirm that the respective function arguments are quoted. For the other arguments, we may inspect the source code (and the documentation) to check if any quoting mechanisms are applied or the arguments are evaluated.\n\nlibrary(MASS) # MASS -> quoted\n\nlibrary() also accepts character vectors and doesn’t quote when character.only is set to TRUE, so library(MASS, character.only = TRUE) would raise an error.\n\nmtcars2 <- subset(mtcars, cyl == 4) # mtcars -> evaluated\n# cyl -> quoted\n\nwith(mtcars2, sum(vs)) # mtcars2 -> evaluated\n# sum(vs) -> quoted\n\nsum(mtcars2$am) # matcars$am -> evaluated\n# am -> quoted by $()\n\nWhen we inspect the source code of rm(), we notice that rm() catches its ... argument as an unevaluated call (in this case a pairlist) via match.call(). This call is then converted into a string for further evaluation.\n\nrm(mtcars2) # mtcars2 -> quoted\n\nQ2: For each function in the following tidyverse code, identify which arguments are quoted and which are evaluated.\n\nlibrary(dplyr)\nlibrary(ggplot2)\n\nby_cyl <- mtcars %>%\n group_by(cyl) %>%\n summarise(mean = mean(mpg))\n\nggplot(by_cyl, aes(cyl, mean)) +\n geom_point()\n\nA: From the previous exercise we’ve already learned that library() quotes its first argument.\n\nlibrary(dplyr) # dplyr -> quoted\nlibrary(ggplot2) # ggplot2 -> quoted\n\nIn similar fashion, it becomes clear that cyl is quoted by group_by().\n\nby_cyl <- mtcars %>% # mtcars -> evaluated\n group_by(cyl) %>% # cyl -> quoted\n summarise(mean = mean(mpg)) # mean = mean(mpg) -> quoted\n\nTo find out what happens in summarise(), we inspect the source code. Tracing down the S3-dispatch of summarise(), we see that the ... argument is quoted in dplyr:::summarise_cols() which is called in the underlying summarise.data.frame() method.\n\ndplyr::summarise\n#> function (.data, ..., .by = NULL, .groups = NULL) \n#> {\n#> by <- enquo(.by)\n#> if (!quo_is_null(by) && !is.null(.groups)) {\n#> abort(\"Can't supply both `.by` and `.groups`.\")\n#> }\n#> UseMethod(\"summarise\")\n#> }\n#> <bytecode: 0x632cfde74b50>\n#> <environment: namespace:dplyr>\n\n\ndplyr:::summarise.data.frame\n#> function (.data, ..., .by = NULL, .groups = NULL) \n#> {\n#> by <- compute_by({\n#> {\n#> .by\n#> }\n#> }, .data, by_arg = \".by\", data_arg = \".data\")\n#> cols <- summarise_cols(.data, dplyr_quosures(...), by, \"summarise\")\n#> out <- summarise_build(by, cols)\n#> if (!cols$all_one) {\n#> summarise_deprecate_variable_size()\n#> }\n#> if (!is_tibble(.data)) {\n#> out <- as.data.frame(out)\n#> }\n#> if (identical(.groups, \"rowwise\")) {\n#> out <- rowwise_df(out, character())\n#> }\n#> out\n#> }\n#> <bytecode: 0x632cf8b3b358>\n#> <environment: namespace:dplyr>\n\n\ndplyr:::summarise_cols\n#> function (.data, ...)\n#> {\n#> mask <- DataMask$new(.data, caller_env())\n#> dots <- enquos(...)\n#> dots_names <- names(dots)\n#> auto_named_dots <- names(enquos(..., .named = TRUE))\n#> cols <- list()\n#> sizes <- 1L\n#> chunks <- vector(\"list\", length(dots))\n#> types <- vector(\"list\", length(dots))\n#>\n#> ## function definition abbreviated for clarity ##\n#> }\n#> <bytecode: 0x55b540c07ca0>\n#> <environment: namespace:dplyr>\n\nIn the following {ggplot2} expression the cyl- and mean-objects are quoted.\n\nggplot(\n by_cyl, # by_cyl -> evaluated\n aes(cyl, mean)\n) + # aes() -> evaluated\n # cyl, mean -> quoted (via aes)\n geom_point()\n\nWe can confirm this also by inspecting aes()’s source code.\n\nggplot2::aes\n#> function (x, y, ...) \n#> {\n#> xs <- arg_enquos(\"x\")\n#> ys <- arg_enquos(\"y\")\n#> dots <- enquos(...)\n#> args <- c(xs, ys, dots)\n#> args <- Filter(Negate(quo_is_missing), args)\n#> local({\n#> aes <- function(x, y, ...) NULL\n#> inject(aes(!!!args))\n#> })\n#> aes <- new_aes(args, env = parent.frame())\n#> rename_aes(aes)\n#> }\n#> <bytecode: 0x632cfc5e3ce0>\n#> <environment: namespace:ggplot2>" + }, + { + "objectID": "19_Quasiquotation.html#quoting", + "href": "19_Quasiquotation.html#quoting", + "title": "19 - Quasiquotation", + "section": "Quoting", + "text": "Quoting\nQ1: How is expr() implemented? Look at its source code.\nA: expr() acts as a simple wrapper, which passes its argument to enexpr().\n\nexpr\n#> function (expr) \n#> {\n#> enexpr(expr)\n#> }\n#> <bytecode: 0x632cfc901de8>\n#> <environment: namespace:rlang>\n\nQ2: Compare and contrast the following two functions. Can you predict the output before running them?\n\nf1 <- function(x, y) {\n exprs(x = x, y = y)\n}\nf2 <- function(x, y) {\n enexprs(x = x, y = y)\n}\nf1(a + b, c + d)\nf2(a + b, c + d)\n\nA: Both functions are able to capture multiple arguments and will return a named list of expressions. f1() will return the arguments defined within the body of f1(). This happens because exprs() captures the expressions as specified by the developer during the definition of f1().\n\nf1(a + b, c + d)\n#> $x\n#> x\n#> \n#> $y\n#> y\n\nf2() will return the arguments supplied to f2() as specified by the user when the function is called.\n\nf2(a + b, c + d)\n#> $x\n#> a + b\n#> \n#> $y\n#> c + d\n\nQ3: What happens if you try to use enexpr() with an expression (i.e. enexpr(x + y))? What happens if enexpr() is passed a missing argument?\nA: In the first case an error is thrown:\n\non_expr <- function(x) {\n enexpr(expr(x))\n}\non_expr(x + y)\n#> Error in `enexpr()`:\n#> ! `arg` must be a symbol\n\nIn the second case a missing argument is returned:\n\non_missing <- function(x) {\n enexpr(x)\n}\non_missing()\nis_missing(on_missing())\n#> [1] TRUE\n\nQ4: How are exprs(a) and exprs(a = ) different? Think about both the input and the output.\nA: In exprs(a) the input a is interpreted as a symbol for an unnamed argument. Consequently, the output shows an unnamed list with the first element containing the symbol a.\n\nout1 <- exprs(a)\nstr(out1)\n#> List of 1\n#> $ : symbol a\n\nIn exprs(a = ) the first argument is named a, but then no value is provided. This leads to the output of a named list with the first element named a, which contains the missing argument.\n\nout2 <- exprs(a = )\nstr(out2)\n#> List of 1\n#> $ a: symbol\nis_missing(out2$a)\n#> [1] TRUE\n\nQ5: What are other differences between exprs() and alist()? Read the documentation for the named arguments of exprs() to find out.\nA: exprs() provides the additional arguments .named (= FALSE), .ignore_empty (c(\"trailing\", \"none\", \"all\")) and .unquote_names (TRUE). .named allows to ensure that all dots are named. ignore_empty allows to specify how empty arguments should be handled for dots (\"trailing\") or all arguments (\"none\" and \"all\"). Further via .unquote_names one can specify if := should be treated like =. := can be useful as it supports unquoting (!!) on the left-hand side.\nQ6: The documentation for substitute() says:\n\nSubstitution takes place by examining each component of the parse tree as follows:\n\nIf it is not a bound symbol in env, it is unchanged.\nIf it is a promise object (i.e. a formal argument to a function) the expression slot of the promise replaces the symbol.\nIf it is an ordinary variable, its value is substituted, unless env is .GlobalEnv in which case the symbol is left unchanged.\n\n\nCreate examples that illustrate each of the above cases.\nA: Let’s create a new environment my_env, which contains no objects. In this case substitute() will just return its first argument (expr):\n\nmy_env <- env()\nsubstitute(x, my_env)\n#> x\n\nWhen we create a function containing an argument, which is directly returned after substitution, this function just returns the provided expression:\n\nfoo <- function(x) substitute(x)\n\nfoo(x + y * sin(0))\n#> x + y * sin(0)\n\nIn case substitute() can find (parts of) the expression in env, it will literally substitute. However, unless env is .GlobalEnv.\n\nmy_env$x <- 7\nsubstitute(x, my_env)\n#> [1] 7\n\nx <- 7\nsubstitute(x, .GlobalEnv)\n#> x" + }, + { + "objectID": "19_Quasiquotation.html#unquoting", + "href": "19_Quasiquotation.html#unquoting", + "title": "19 - Quasiquotation", + "section": "Unquoting", + "text": "Unquoting\nQ1: Given the following components:\n\nxy <- expr(x + y)\nxz <- expr(x + z)\nyz <- expr(y + z)\nabc <- exprs(a, b, c)\n\nUse quasiquotation to construct the following calls:\n\n(x + y) / (y + z) # (1)\n-(x + z)^(y + z) # (2)\n(x + y) + (y + z) - (x + y) # (3)\natan2(x + y, y + z) # (4)\nsum(x + y, x + y, y + z) # (5)\nsum(a, b, c) # (6)\nmean(c(a, b, c), na.rm = TRUE) # (7)\nfoo(a = x + y, b = y + z) # (8)\n\nA: We combine and unquote the given quoted expressions to construct the desired calls like this:\n\nexpr(!!xy / !!yz) # (1)\n#> (x + y)/(y + z)\n\nexpr(-(!!xz)^(!!yz)) # (2)\n#> -(x + z)^(y + z)\n\nexpr(((!!xy)) + !!yz - !!xy) # (3)\n#> (x + y) + (y + z) - (x + y)\n\nexpr(atan2(!!xy, !!yz)) # (4)\n#> atan2(x + y, y + z)\n\nexpr(sum(!!xy, !!xy, !!yz)) # (5)\n#> sum(x + y, x + y, y + z)\n\nexpr(sum(!!!abc)) # (6)\n#> sum(a, b, c)\n\nexpr(mean(c(!!!abc), na.rm = TRUE)) # (7)\n#> mean(c(a, b, c), na.rm = TRUE)\n\nexpr(foo(a = !!xy, b = !!yz)) # (8)\n#> foo(a = x + y, b = y + z)\n\nQ2: The following two calls print the same, but are actually different:\n\n(a <- expr(mean(1:10)))\n#> mean(1:10)\n(b <- expr(mean(!!(1:10))))\n#> mean(1:10)\nidentical(a, b)\n#> [1] FALSE\n\nWhat’s the difference? Which one is more natural?\nA: It’s easiest to see the difference with lobstr::ast():\n\nlobstr::ast(mean(1:10))\n#> █─mean \n#> └─█─`:` \n#> ├─1 \n#> └─10\nlobstr::ast(mean(!!(1:10)))\n#> █─mean \n#> └─<inline integer>\n\nIn the expression mean(!!(1:10)) the call 1:10 is evaluated to an integer vector, while still being a call object in mean(1:10).\nThe first version (mean(1:10)) seems more natural. It captures lazy evaluation, with a promise that is evaluated when the function is called. The second version (mean(!!(1:10))) inlines a vector directly into a call." + }, + { + "objectID": "19_Quasiquotation.html#dot-dot-dot", + "href": "19_Quasiquotation.html#dot-dot-dot", + "title": "19 - Quasiquotation", + "section": "... (dot-dot-dot)", + "text": "... (dot-dot-dot)\nQ1: One way to implement exec() is shown below. Describe how it works. What are the key ideas?\n\nexec <- function(f, ..., .env = caller_env()) {\n args <- list2(...)\n do.call(f, args, envir = .env)\n}\n\nA: exec() takes a function (f), its arguments (...) and an environment (.env) as input. This allows to construct a call from f and ... and evaluate this call in the supplied environment. As the ... argument is handled via list2(), exec() supports tidy dots (quasiquotation), which means that arguments and names (on the left-hand side of :=) can be unquoted via !! and !!!.\nQ2: Carefully read the source code for interaction(), expand.grid(), and par(). Compare and contrast the techniques they use for switching between dots and list behaviour.\nA: All three functions capture the dots via args <- list(...).\ninteraction() computes factor interactions between the captured input factors by iterating over the args. When a list is provided this is detected via length(args) == 1 && is.list(args[[1]]) and one level of the list is stripped through args <- args[[1]]. The rest of the function’s code doesn’t differentiate further between list and dots behaviour.\n\n# Both calls create the same output\ninteraction(a = c(\"a\", \"b\", \"c\", \"d\"), b = c(\"e\", \"f\")) # dots\n#> [1] a.e b.f c.e d.f\n#> Levels: a.e b.e c.e d.e a.f b.f c.f d.f\ninteraction(list(a = c(\"a\", \"b\", \"c\", \"d\"), b = c(\"e\", \"f\"))) # list\n#> [1] a.e b.f c.e d.f\n#> Levels: a.e b.e c.e d.e a.f b.f c.f d.f\n\nexpand.grid() uses the same strategy and also assigns args <- args[[1]] in case of length(args) == 1 && is.list(args[[1]]).\npar() does the most pre-processing to ensure a valid structure of the args argument. When no dots are provided (!length(args)) it creates a list of arguments from an internal character vector (partly depending on its no.readonly argument). Further, given that all elements of args are character vectors (all(unlist(lapply(args, is.character)))), args is turned into a list via as.list(unlist(args)) (this flattens nested lists). Similar to the other functions, one level of args gets stripped via args <- args[[1L]], when args is of length one and its first element is a list.\nQ3: Explain the problem with this definition of set_attr()\n\nset_attr <- function(x, ...) {\n attr <- rlang::list2(...)\n attributes(x) <- attr\n x\n}\nset_attr(1:10, x = 10)\n#> Error in attributes(x) <- attr: attributes must be named\n\nA: set_attr() expects an object named x and its attributes, supplied via the dots. Unfortunately, this prohibits us to provide attributes named x as these would collide with the argument name of our object. Even omitting the object’s argument name doesn’t help in this case — as can be seen in the example where the object is consequently treated as an unnamed attribute.\nHowever, we may name the first argument .x, which seems clearer and less likely to invoke errors. In this case 1:10 will get the (named) attribute x = 10 assigned:\n\nset_attr <- function(.x, ...) {\n attr <- rlang::list2(...)\n\n attributes(.x) <- attr\n .x\n}\n\nset_attr(1:10, x = 10)\n#> [1] 1 2 3 4 5 6 7 8 9 10\n#> attr(,\"x\")\n#> [1] 10" + }, + { + "objectID": "19_Quasiquotation.html#expr-case-studies", + "href": "19_Quasiquotation.html#expr-case-studies", + "title": "19 - Quasiquotation", + "section": "Case studies", + "text": "Case studies\nQ1: In the linear-model example, we could replace the expr() in reduce(summands, ~ expr(!!.x + !!.y)) with call2(): reduce(summands, call2, \"+\"). Compare and contrast the two approaches. Which do you think is easier to read?\nA: We would consider the first version to be more readable. There seems to be a little more boilerplate code at first, but the unquoting syntax is very readable. Overall, the whole expression seems more explicit and less complex.\nQ2: Re-implement the Box-Cox transform defined below using unquoting and new_function():\n\nbc <- function(lambda) {\n if (lambda == 0) {\n function(x) log(x)\n } else {\n function(x) (x^lambda - 1) / lambda\n }\n}\n\nA: Here new_function() allows us to create a function factory using tidy evaluation.\n\nbc2 <- function(lambda) {\n lambda <- enexpr(lambda)\n\n if (!!lambda == 0) {\n new_function(exprs(x = ), expr(log(x)))\n } else {\n new_function(exprs(x = ), expr((x^(!!lambda) - 1) / !!lambda))\n }\n}\n\nbc2(0)\n#> function (x) \n#> log(x)\n#> <environment: 0x632cfd501268>\nbc2(2)\n#> function (x) \n#> (x^2 - 1)/2\n#> <environment: 0x632cfd573528>\nbc2(2)(2)\n#> [1] 1.5\n\nQ3: Re-implement the simple compose() defined below using quasiquotation and new_function():\n\ncompose <- function(f, g) {\n function(...) f(g(...))\n}\n\nA: The implementation is fairly straightforward, even though a lot of parentheses are required:\n\ncompose2 <- function(f, g) {\n f <- enexpr(f)\n g <- enexpr(g)\n\n new_function(exprs(... = ), expr((!!f)((!!g)(...))))\n}\n\ncompose(sin, cos)\n#> function(...) f(g(...))\n#> <environment: 0x632cfbc88290>\ncompose(sin, cos)(pi)\n#> [1] -0.841\n\ncompose2(sin, cos)\n#> function (...) \n#> sin(cos(...))\n#> <environment: 0x632cfc1fbf80>\ncompose2(sin, cos)(pi)\n#> [1] -0.841" + }, + { + "objectID": "20_Evaluation.html#prerequisites", + "href": "20_Evaluation.html#prerequisites", + "title": "20 - Evaluation", + "section": "Prerequisites", + "text": "Prerequisites\nOn our journey through R’s metaprogramming, we continue to use the functions from the {rlang} package.\n\nlibrary(rlang)" + }, + { + "objectID": "20_Evaluation.html#evaluation-basics", + "href": "20_Evaluation.html#evaluation-basics", + "title": "20 - Evaluation", + "section": "Evaluation basics", + "text": "Evaluation basics\nQ1: Carefully read the documentation for source(). What environment does it use by default? What if you supply local = TRUE? How do you provide a custom environment?\nA: By default, source() uses the global environment (local = FALSE). A specific evaluation environment may be chosen, by passing it explicitly to the local argument. To use current environment (i.e. the calling environment of source()) set local = TRUE.\n\n# Create a temporary, sourceable R script that prints x\ntmp_file <- tempfile()\nwriteLines(\"print(x)\", tmp_file)\n\n# Set `x` globally\nx <- \"global environment\"\nenv2 <- env(x = \"specified environment\")\n\nlocate_evaluation <- function(file, local) {\n x <- \"local environment\"\n source(file, local = local)\n}\n\n# Where will source() evaluate the code?\nlocate_evaluation(tmp_file, local = FALSE) # default\n#> [1] \"global environment\"\nlocate_evaluation(tmp_file, local = env2)\n#> [1] \"specified environment\"\nlocate_evaluation(tmp_file, local = TRUE)\n#> [1] \"local environment\"\n\nQ2: Predict the results of the following lines of code:\n\neval(expr(eval(expr(eval(expr(2 + 2)))))) # (1)\neval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2)\nexpr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3)\n\nA: Let’s look at a quote from the first edition of Advanced R:\n\n“expr() and eval() are opposites. […] each eval() peels off one layer of expr()’s”.\n\nIn general, eval(expr(x)) evaluates to x. Therefore, (1) evaluates to \\(2 + 2 = 4\\). Adding another eval() doesn’t have impact here. So, also (2) evaluates to 4. However, when wrapping (1) into expr() the whole expression will be quoted.\n\neval(expr(eval(expr(eval(expr(2 + 2)))))) # (1)\n#> [1] 4\neval(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (2)\n#> [1] 4\nexpr(eval(expr(eval(expr(eval(expr(2 + 2))))))) # (3)\n#> eval(expr(eval(expr(eval(expr(2 + 2))))))\n\nQ3: Fill in the function bodies below to re-implement get() using sym() and eval(), and assign() using sym(), expr(), and eval(). Don’t worry about the multiple ways of choosing an environment that get() and assign() support; assume that the user supplies it explicitly.\n\n# name is a string\nget2 <- function(name, env) {}\nassign2 <- function(name, value, env) {}\n\nA: We reimplement these two functions using tidy evaluation. We turn the string name into a symbol, then evaluate it:\n\nget2 <- function(name, env = caller_env()) {\n name_sym <- sym(name)\n eval(name_sym, env)\n}\n\nx <- 1\nget2(\"x\")\n#> [1] 1\n\nTo build the correct expression for the value assignment, we unquote using !!.\n\nassign2 <- function(name, value, env = caller_env()) {\n name_sym <- sym(name)\n assign_expr <- expr(!!name_sym <- !!value)\n eval(assign_expr, env)\n}\n\nassign2(\"x\", 4)\nx\n#> [1] 4\n\nQ4: Modify source2() so it returns the result of every expression, not just the last one. Can you eliminate the for loop?\nA: The code for source2() was given in Advanced R as:\n\nsource2 <- function(path, env = caller_env()) {\n file <- paste(readLines(path, warn = FALSE), collapse = \"\\n\")\n exprs <- parse_exprs(file)\n\n res <- NULL\n for (i in seq_along(exprs)) {\n res <- eval(exprs[[i]], env)\n }\n\n invisible(res)\n}\n\nIn order to highlight the modifications in our new source2() function, we’ve preserved the differing code from the former source2() in a comment.\n\nsource2 <- function(path, env = caller_env()) {\n file <- paste(readLines(path, warn = FALSE), collapse = \"\\n\")\n exprs <- parse_exprs(file)\n\n # res <- NULL\n # for (i in seq_along(exprs)) {\n # res[[i]] <- eval(exprs[[i]], env)\n # }\n\n res <- purrr::map(exprs, eval, env)\n\n invisible(res)\n}\n\nLet’s create a file and test source2(). Keep in mind that <- returns invisibly.\n\ntmp_file <- tempfile()\nwriteLines(\n \"x <- 1\n x\n y <- 2\n y # some comment\",\n tmp_file\n)\n\n(source2(tmp_file))\n#> [[1]]\n#> [1] 1\n#> \n#> [[2]]\n#> [1] 1\n#> \n#> [[3]]\n#> [1] 2\n#> \n#> [[4]]\n#> [1] 2\n\nQ5: We can make base::local() slightly easier to understand by spreading it over multiple lines:\n\nlocal3 <- function(expr, envir = new.env()) {\n call <- substitute(eval(quote(expr), envir))\n eval(call, envir = parent.frame())\n}\n\nExplain how local() works in words. (Hint: you might want to print(call) to help understand what substitute() is doing, and read the documentation to remind yourself what environment new.env() will inherit from.)\nA: Let’s follow the advice and add print(call) inside of local3():\n\nlocal3 <- function(expr, envir = new.env()) {\n call <- substitute(eval(quote(expr), envir))\n print(call)\n eval(call, envir = parent.frame())\n}\n\nThe first line generates a call to eval(), because substitute() operates in the current evaluation argument. However, this doesn’t matter here, as both, expr and envir are promises and therefore “the expression slots of the promises replace the symbols”, from ?substitute.\n\nlocal3({\n x <- 10\n x * 2\n})\n#> eval(quote({\n#> x <- 10\n#> x * 2\n#> }), new.env())\n#> [1] 20\n\nNext, call will be evaluated in the caller environment (aka the parent frame). Given that call contains another call eval() why does this matter? The answer is subtle: this outer environment determines where the bindings for eval, quote, and new.env are found. \n\neval(quote({\n x <- 10\n x * 2\n}), new.env())\n#> [1] 20\nexists(\"x\")\n#> [1] TRUE" + }, + { + "objectID": "20_Evaluation.html#quosures", + "href": "20_Evaluation.html#quosures", + "title": "20 - Evaluation", + "section": "Quosures", + "text": "Quosures\nQ1: Predict what evaluating each of the following quosures will return if evaluated.\n\nq1 <- new_quosure(expr(x), env(x = 1))\nq1\n#> <quosure>\n#> expr: ^x\n#> env: 0x5c4a1926acd8\n\nq2 <- new_quosure(expr(x + !!q1), env(x = 10))\nq2\n#> <quosure>\n#> expr: ^x + (^x)\n#> env: 0x5c4a1a129268\n\nq3 <- new_quosure(expr(x + !!q2), env(x = 100))\nq3\n#> <quosure>\n#> expr: ^x + (^x + (^x))\n#> env: 0x5c4a1a590570\n\nA: Each quosure is evaluated in its own environment, so x is bound to a different value for each time. This leads us to:\n\neval_tidy(q1)\n#> [1] 1\neval_tidy(q2)\n#> [1] 11\neval_tidy(q3)\n#> [1] 111\n\nQ2: Write an enenv() function that captures the environment associated with an argument. (Hint: this should only require two function calls.)\nA: A quosure captures both the expression and the environment. From a quosure, we can access the environment with the help of get_env().\n\nenenv <- function(x) {\n get_env(enquo(x))\n}\n\n# Test\nenenv(x)\n#> <environment: R_GlobalEnv>\n\n# Test if it also works within functions\ncapture_env <- function(x) {\n enenv(x)\n}\ncapture_env(x)\n#> <environment: 0x5c4a18b688b0>" + }, + { + "objectID": "20_Evaluation.html#data-masks", + "href": "20_Evaluation.html#data-masks", + "title": "20 - Evaluation", + "section": "Data masks", + "text": "Data masks\nQ1: Why did I use a for loop in transform2() instead of map()? Consider transform2(df, x = x * 2, x = x * 2).\nA: transform2() was defined in Advanced R as:\n\ntransform2 <- function(.data, ...) {\n dots <- enquos(...)\n\n for (i in seq_along(dots)) {\n name <- names(dots)[[i]]\n dot <- dots[[i]]\n\n .data[[name]] <- eval_tidy(dot, .data)\n }\n\n .data\n}\n\nA for loop applies the processing steps regarding .data iteratively. This includes updating .data and reusing the same variable names. This makes it possible to apply transformations sequentially, so that subsequent transformations can refer to columns that were just created.\nQ2: Here’s an alternative implementation of subset2():\n\nsubset3 <- function(data, rows) {\n rows <- enquo(rows)\n eval_tidy(expr(data[!!rows, , drop = FALSE]), data = data)\n}\n\ndf <- data.frame(x = 1:3)\nsubset3(df, x == 1)\n\nCompare and contrast subset3() to subset2(). What are its advantages and disadvantages?\nA: Let’s take a closer look at subset2() first:\n\nsubset2 <- function(data, rows) {\n rows <- enquo(rows)\n rows_val <- eval_tidy(rows, data)\n stopifnot(is.logical(rows_val))\n\n data[rows_val, , drop = FALSE]\n}\n\nsubset2() provides an additional logical check, which is missing from subset3(). Here, rows is evaluated in the context of data, which results in a logical vector. Afterwards only [ needs to be used for subsetting.\n\n# subset2() evaluation\n(rows_val <- eval_tidy(quo(x == 1), df))\n#> [1] TRUE FALSE FALSE\ndf[rows_val, , drop = FALSE]\n#> x\n#> 1 1\n\nWith subset3() both of these steps occur in a single line (which is probably closer to what one would produce by hand). This means that the subsetting is also evaluated in the context of the data mask.\n\n# subset3() evaluation\neval_tidy(expr(df[x == 1, , drop = FALSE]), df)\n#> x\n#> 1 1\n\nThis is shorter (but probably also less readable) because the evaluation and the subsetting take place in the same expression. However, it may introduce unwanted errors, if the data mask contains an element named “data”, as the objects from the data mask take precedence over arguments of the function.\n\ndf <- data.frame(x = 1:3, data = 1)\nsubset2(df, x == 1)\n#> x data\n#> 1 1 1\nsubset3(df, x == 1)\n#> Error in data[~x == 1, , drop = FALSE]: incorrect number of dimensions\n\nQ3: The following function implements the basics of dplyr::arrange(). Annotate each line with a comment explaining what it does. Can you explain why !!.na.last is strictly correct, but omitting the !! is unlikely to cause problems?\n\narrange2 <- function(.df, ..., .na.last = TRUE) {\n args <- enquos(...)\n\n order_call <- expr(order(!!!args, na.last = !!.na.last))\n\n ord <- eval_tidy(order_call, .df)\n stopifnot(length(ord) == nrow(.df))\n\n .df[ord, , drop = FALSE]\n}\n\nA: arrange2() basically reorders a data frame by one or more of its variables. As arrange2() allows to provide the variables as expressions (via ...), these need to be quoted first. Afterwards they are used to build up an order() call, which is then evaluated in the context of the data frame. Finally, the data frame is reordered via integer subsetting. Let’s take a closer look at the source code:\n\narrange2 <- function(.df, ..., .na.last = TRUE) {\n # Capture and quote arguments, which determine the order\n args <- enquos(...)\n\n # `!!!`: unquote-splice arguments into order()\n # `!!.na.last`: pass option for treatment of NAs to order()\n # return expression-object\n order_call <- expr(order(!!!args, na.last = !!.na.last))\n\n # Evaluate order_call within .df\n ord <- eval_tidy(order_call, .df)\n # Ensure that no rows are dropped\n stopifnot(length(ord) == nrow(.df))\n\n # Reorder rows via integer subsetting\n .df[ord, , drop = FALSE]\n}\n\nBy using !!.na.last the .na.last argument is unquoted when the order() call is built. This way, the na.last argument is already correctly specified (typically TRUE, FALSE or NA).\nWithout the unquoting, the expression would read na.last = .na.last and the value for .na.last would still need to be looked up and found. Because these computations take place inside of the function’s execution environment (which contains .na.last), this is unlikely to cause problems.\n\n# The effect of unquoting .na.last\n.na.last <- FALSE\nexpr(order(..., na.last = !!.na.last))\n#> order(..., na.last = FALSE)\nexpr(order(..., na.last = .na.last))\n#> order(..., na.last = .na.last)" + }, + { + "objectID": "20_Evaluation.html#using-tidy-evaluation", + "href": "20_Evaluation.html#using-tidy-evaluation", + "title": "20 - Evaluation", + "section": "Using tidy evaluation", + "text": "Using tidy evaluation\nQ1: I’ve included an alternative implementation of threshold_var() below. What makes it different to the approach I used above? What makes it harder?\n\nthreshold_var2 <- function(df, var, val) {\n var <- ensym(var)\n\n subset2(df, `$`(.data, !!var) >= !!val)\n}\n\nA: Let’s compare this approach to the original implementation:\n\nthreshold_var <- function(df, var, val) {\n var <- as_string(ensym(var))\n subset2(df, .data[[var]] >= !!val)\n}\n\nWe can see that threshold_var2() no longer coerces the symbol to a string. Therefore $ instead of [[ can be used for subsetting. Initially we suspected partial matching would be introduced by $, but .data deliberately avoids this problem.\nThe prefix call to $() is less common than infix-subsetting using [[, but ultimately both functions behave the same.\n\ndf <- data.frame(x = 1:10)\nthreshold_var(df, x, 8)\n#> x\n#> 8 8\n#> 9 9\n#> 10 10\nthreshold_var2(df, x, 8)\n#> x\n#> 8 8\n#> 9 9\n#> 10 10" + }, + { + "objectID": "20_Evaluation.html#base-evaluation", + "href": "20_Evaluation.html#base-evaluation", + "title": "20 - Evaluation", + "section": "Base evaluation", + "text": "Base evaluation\nQ1: Why does this function fail?\n\nlm3a <- function(formula, data) {\n formula <- enexpr(formula)\n\n lm_call <- expr(lm(!!formula, data = data))\n eval(lm_call, caller_env())\n}\nlm3a(mpg ~ disp, mtcars)$call\n#> Error in model.frame.default(formula = mpg ~ disp, data = data, drop.unused.levels = TRUE): 'data' must be a data.frame, environment, or list\n\nA: In this function, lm_call is evaluated in the caller environment, which happens to be the global environment. In this environment, the name data is bound to utils::data. To fix the error, we can either set the evaluation environment to the function’s execution environment or unquote the data argument when building the call to lm().\n\n# Change evaluation environment\nlm3b <- function(formula, data) {\n formula <- enexpr(formula)\n\n lm_call <- expr(lm(!!formula, data = data))\n eval(lm_call, current_env())\n}\n\nlm3b(mpg ~ disp, mtcars)$call\n#> lm(formula = mpg ~ disp, data = data)\nlm3b(mpg ~ disp, data)$call # reproduces original error\n#> Error in model.frame.default(formula = mpg ~ disp, data = data, drop.unused.levels = TRUE): 'data' must be a data.frame, environment, or list\n\nWhen we want to unquote an argument within a function, we first need to capture the user-input (by enexpr()).\n\n# Unquoting data-argument\nlm3c <- function(formula, data) {\n formula <- enexpr(formula)\n data_quo <- enexpr(data)\n\n lm_call <- expr(lm(!!formula, data = !!data_quo))\n eval(lm_call, caller_env())\n}\nlm3c(mpg ~ disp, mtcars)$call\n#> lm(formula = mpg ~ disp, data = mtcars)\n\nQ2: When model building, typically the response and data are relatively constant while you rapidly experiment with different predictors. Write a small wrapper that allows you to reduce duplication in the code below.\n\nlm(mpg ~ disp, data = mtcars)\nlm(mpg ~ I(1 / disp), data = mtcars)\nlm(mpg ~ disp * cyl, data = mtcars)\n\nA: In our wrapper lm_wrap(), we provide mpg and mtcars as default response and data. This seems to give us a good mix of usability and flexibility.\n\nlm_wrap <- function(pred, resp = mpg, data = mtcars,\n env = caller_env()) {\n pred <- enexpr(pred)\n resp <- enexpr(resp)\n data <- enexpr(data)\n\n formula <- expr(!!resp ~ !!pred)\n lm_call <- expr(lm(!!formula, data = !!data))\n eval(lm_call, envir = env)\n}\n\n# Test if the output looks ok\nlm_wrap(I(1 / disp) + disp * cyl)\n#> \n#> Call:\n#> lm(formula = mpg ~ I(1/disp) + disp * cyl, data = mtcars)\n#> \n#> Coefficients:\n#> (Intercept) I(1/disp) disp cyl disp:cyl \n#> -1.22e+00 1.85e+03 7.68e-02 1.18e+00 -9.14e-03\n\n# Test if the result is identical to calling lm() directly\nidentical(\n lm_wrap(I(1 / disp) + disp * cyl),\n lm(mpg ~ I(1 / disp) + disp * cyl, data = mtcars)\n)\n#> [1] TRUE\n\nQ3: Another way to write resample_lm() would be to include the resample expression (data[sample(nrow(data), replace = TRUE), , drop = FALSE]) in the data argument. Implement that approach. What are the advantages? What are the disadvantages?\nA: Different versions of resample_lm() were given in Advanced R. However, none of them implemented the resampling within the function argument.\nDifferent versions of resample_lm() (resample_lm0(), resample_lm1(), resample_lm2()) were specified in Advanced R. However, in none of these versions was the resampling step implemented in any of the arguments.\nThis approach takes advantage of R’s lazy evaluation of function arguments, by moving the resampling step into the argument definition. The user passes the data to the function, but only a permutation of this data (resample_data) will be used.\n\nresample_lm <- function(\n formula, data,\n resample_data = data[sample(nrow(data), replace = TRUE), ,\n drop = FALSE\n ],\n env = current_env()) {\n formula <- enexpr(formula)\n\n lm_call <- expr(lm(!!formula, data = resample_data))\n expr_print(lm_call)\n eval(lm_call, env)\n}\n\ndf <- data.frame(x = 1:10, y = 5 + 3 * (1:10) + round(rnorm(10), 2))\n(lm_1 <- resample_lm(y ~ x, data = df))\n#> lm(y ~ x, data = resample_data)\n#> \n#> Call:\n#> lm(formula = y ~ x, data = resample_data)\n#> \n#> Coefficients:\n#> (Intercept) x \n#> 4.85 3.02\nlm_1$call\n#> lm(formula = y ~ x, data = resample_data)\n\nWith this approach the evaluation needs to take place within the function’s environment, because the resampled dataset (defined as a default argument) will only be available in the function environment.\nOverall, putting an essential part of the pre-processing outside of the functions body is not common practice in R. Compared to the unquoting-implementation (resample_lm1() in Advanced R), this approach captures the model-call in a more meaningful way. This approach will also lead to a new resample every time you update() the model." + }, + { + "objectID": "20_Evaluation.html#references", + "href": "20_Evaluation.html#references", + "title": "20 - Evaluation", + "section": "References", + "text": "References" + }, + { + "objectID": "21_Translating_R_code.html#prerequisites", + "href": "21_Translating_R_code.html#prerequisites", + "title": "21 - Translating R code", + "section": "Prerequisites", + "text": "Prerequisites\nIn this chapter we combine R’s metaprogramming and functional programming capabilities and therefore load both the {rlang} and the {purrr} package.\n\nlibrary(rlang)\nlibrary(purrr)" + }, + { + "objectID": "21_Translating_R_code.html#html", + "href": "21_Translating_R_code.html#html", + "title": "21 - Translating R code", + "section": "HTML", + "text": "HTML\nQ1: The escaping rules for <script> tags are different because they contain JavaScript, not HTML. Instead of escaping angle brackets or ampersands, you need to escape </script> so that the tag isn’t closed too early. For example, script(\"'</script>'\"), shouldn’t generate this:\n\n<script>'</script>'</script>\n\nBut\n\n<script>'<\\/script>'</script>\n\nAdapt the escape() to follow these rules when a new argument script is set to TRUE.\nA: We are asked to implement a special case of escaping for the <script> tag. At first we will revisit the relevant functions provided in Advanced R and confirm that our code reliably escapes for tags like <p> and <b> but doesn’t escape correctly for the <script> tag. Then we modify the escape() and tag() functions to redefine the <script> tag and confirm that all defined tags now escape correctly.\nNote that the <style> tag, which contains styling information in CSS, follows the same escaping rules as the <script> tag. We therefore implement the desired escaping for the <style> tag function also.\nLet’s start by loading the relevant code from Advanced R first.\n\n# Escaping\nhtml <- function(x) structure(x, class = \"advr_html\")\n\nprint.advr_html <- function(x, ...) {\n out <- paste0(\"<HTML> \", x)\n cat(paste(strwrap(out), collapse = \"\\n\"), \"\\n\", sep = \"\")\n}\n\nescape <- function(x) UseMethod(\"escape\")\n\nescape.character <- function(x) {\n x <- gsub(\"&\", \"&\", x)\n x <- gsub(\"<\", \"<\", x)\n x <- gsub(\">\", \">\", x)\n\n html(x)\n}\n\nescape.advr_html <- function(x) x\n\n# Basic tag functions\ndots_partition <- function(...) {\n dots <- list2(...)\n\n if (is.null(names(dots))) {\n is_named <- rep(FALSE, length(dots))\n } else {\n is_named <- names(dots) != \"\"\n }\n\n list(\n named = dots[is_named],\n unnamed = dots[!is_named]\n )\n}\n\n# html_attributes() function from the GitHub repository of Advanced R\n# https://github.com/hadley/adv-r/blob/master/dsl-html-attributes.r\n\nhtml_attributes <- function(list) {\n if (length(list) == 0) {\n return(\"\")\n }\n\n attr <- map2_chr(names(list), list, html_attribute)\n paste0(\" \", unlist(attr), collapse = \"\")\n}\n\nhtml_attribute <- function(name, value = NULL) {\n if (length(value) == 0) {\n return(name)\n } # for attributes with no value\n if (length(value) != 1) stop(\"`value` must be NULL or length 1\")\n if (is.logical(value)) {\n # Convert T and F to true and false\n value <- tolower(value)\n } else {\n value <- escape_attr(value)\n }\n paste0(name, \"='\", value, \"'\")\n}\n\nescape_attr <- function(x) {\n x <- escape.character(x)\n x <- gsub(\"\\'\", \"'\", x)\n x <- gsub(\"\\\"\", \""\", x)\n x <- gsub(\"\\r\", \" \", x)\n x <- gsub(\"\\n\", \" \", x)\n x\n}\n\n# Tag functions\ntag <- function(tag) {\n new_function(\n exprs(... = ),\n expr({\n dots <- dots_partition(...)\n attribs <- html_attributes(dots$named)\n children <- map_chr(dots$unnamed, escape)\n\n html(paste0(\n !!paste0(\"<\", tag), attribs, \">\",\n paste(children, collapse = \"\"),\n !!paste0(\"</\", tag, \">\")\n ))\n }),\n caller_env()\n )\n}\n\nThis code escapes the <p> and <b> tags correctly, but doesn’t achieve the desired behaviour for the <script> tag yet:\n\np <- tag(\"p\")\nb <- tag(\"b\")\n\nidentical(\n p(\"&\", \"and <\", b(\"& > will be escaped\")) %>%\n as.character(),\n \"<p>&and <<b>& > will be escaped</b></p>\"\n)\n#> [1] TRUE\n\nscript <- tag(\"script\")\n\nidentical(\n script(\"Don't escape &, <, > - escape </script> and </style>\") %>%\n as.character(),\n paste(\n \"<script>Don't escape &, <, >\",\n \"- escape <\\\\/script> and <\\\\/style></script>\"\n )\n)\n#> [1] FALSE\n\nWe implement the desired change and add the optional argument script to the escape() and the tag() functions (default: script = FALSE). The argument has to be added for all methods of the escape() generic.\n\nescape <- function(x, script = FALSE) UseMethod(\"escape\")\n\nescape.character <- function(x, script = FALSE) {\n if (script) {\n x <- gsub(\"</script>\", \"<\\\\/script>\", x, fixed = TRUE)\n x <- gsub(\"</style>\", \"<\\\\/style>\", x, fixed = TRUE)\n } else {\n x <- gsub(\"&\", \"&\", x)\n x <- gsub(\"<\", \"<\", x)\n x <- gsub(\">\", \">\", x)\n }\n\n html(x)\n}\n\nescape.advr_html <- function(x, script = FALSE) x\n\n\ntag <- function(tag, script = FALSE) {\n new_function(\n exprs(... = ),\n expr({\n dots <- dots_partition(...)\n attribs <- html_attributes(dots$named)\n children <- map_chr(dots$unnamed, escape, script = !!script)\n html(paste0(\n !!paste0(\"<\", tag), attribs, \">\",\n paste(children, collapse = \"\"),\n !!paste0(\"</\", tag, \">\")\n ))\n }),\n caller_env()\n )\n}\n\nFinally, we create new <p>, <b> and <script> tag functions, which now pass their escaping tests.\n\np <- tag(\"p\")\nb <- tag(\"b\")\n\nidentical(\n p(\"&\", \"and <\", b(\"& > will be escaped\")) %>%\n as.character(),\n \"<p>&and <<b>& > will be escaped</b></p>\"\n)\n#> [1] TRUE\n\nscript <- tag(\"script\", script = TRUE)\nstyle <- tag(\"style\", script = TRUE)\n\nidentical(\n script(\"Don't escape &, <, > - escape </script> and </style>\") %>%\n as.character(),\n paste(\n \"<script>Don't escape &, <, >\",\n \"- escape <\\\\/script> and <\\\\/style></script>\"\n )\n)\n#> [1] TRUE\n\nscript(\"Don't escape &, <, > - escape </script> and </style>\")\n#> <HTML> <script>Don't escape &, <, > - escape <\\/script> and\n#> <\\/style></script>\n\nQ2: The use of ... for all functions has some big downsides. There’s no input validation and there will be little information in the documentation or autocomplete about how they are used in the function. Create a new function that, when given a named list of tags and their attribute names (like below), creates tag functions with named arguments.\n\nlist(\n a = c(\"href\"),\n img = c(\"src\", \"width\", \"height\")\n)\n\nAll tags should get class and id attributes.\nA: This exercise requires a function factory: The named list of attribute names will be extended (by class and id) and mapped to function arguments. These will default to NULL, so that the user isn’t forced to provide them.\nWhen creating the tag functions itself we use check_dots_unnamed() from the {ellipsis} package to ensure named arguments correspond to the expected values (and are not created by some spelling mistake). After that we follow the logic from the tag() function factory above.\nTo keep the focus on the key ideas, we ignore special cases like <script>, <style> and void tags in this solution (even if this leads to an incorrect tag function for the <img> tag).\n\ntag_factory <- function(tag, tag_attrs) {\n attrs <- c(\"class\", \"id\", tag_attrs)\n\n attr_args <- set_names(rep(list(NULL), length(attrs)), attrs)\n attr_list <- call2(\"list\", !!!syms(set_names(attrs)))\n\n new_function(\n exprs(... = , !!!attr_args),\n expr({\n ellipsis::check_dots_unnamed()\n\n attribs <- html_attributes(compact(!!attr_list))\n dots <- compact(list(...))\n children <- map_chr(dots, escape)\n\n html(paste0(\n !!paste0(\"<\", tag), attribs, \">\",\n paste(children, collapse = \"\"),\n !!paste0(\"</\", tag, \">\")\n ))\n })\n )\n}\n\nTo validate our new function factory, we modify the with_html() example from Advanced R to work with our newly created a() and img() tag functions.\n\ntag_list <- list(\n a = c(\"href\"),\n img = c(\"src\", \"width\", \"height\")\n)\n\ntags <- map2(names(tag_list), unname(tag_list), tag_factory) %>%\n set_names(names(tag_list))\n\nwith_tags <- function(code) {\n code <- enquo(code)\n eval_tidy(code, tags)\n}\n\nwith_tags(\n a(\n img(\"Correct me if I am wrong\", id = \"second\"),\n href = \"https://github.com/Tazinho/Advanced-R-Solutions/issues\",\n id = \"first\"\n )\n)\n#> <HTML> <a id='first'\n#> href='https://github.com/Tazinho/Advanced-R-Solutions/issues'><img\n#> id='second'>Correct me if I am wrong</img></a>\n\nQ3: Reason about the following code that calls with_html() referencing objects from the environment. Will it work or fail? Why? Run the code to verify your predictions.\n\ngreeting <- \"Hello!\"\nwith_html(p(greeting))\n\np <- function() \"p\"\naddress <- \"123 anywhere street\"\nwith_html(p(address))\n\nA: First, we rerun the relevant code from Advanced R to define with_html(). Note that we skip the code for void tags, as none of them appear in the code chunk from this exercise.\n\ntags <- c(\n \"a\", \"abbr\", \"address\", \"article\", \"aside\", \"audio\",\n \"b\", \"bdi\", \"bdo\", \"blockquote\", \"body\", \"button\", \"canvas\",\n \"caption\", \"cite\", \"code\", \"colgroup\", \"data\", \"datalist\",\n \"dd\", \"del\", \"details\", \"dfn\", \"div\", \"dl\", \"dt\", \"em\",\n \"eventsource\", \"fieldset\", \"figcaption\", \"figure\", \"footer\",\n \"form\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"head\", \"header\",\n \"hgroup\", \"html\", \"i\", \"iframe\", \"ins\", \"kbd\", \"label\",\n \"legend\", \"li\", \"mark\", \"map\", \"menu\", \"meter\", \"nav\",\n \"noscript\", \"object\", \"ol\", \"optgroup\", \"option\", \"output\",\n \"p\", \"pre\", \"progress\", \"q\", \"ruby\", \"rp\", \"rt\", \"s\", \"samp\",\n \"script\", \"section\", \"select\", \"small\", \"span\", \"strong\",\n \"style\", \"sub\", \"summary\", \"sup\", \"table\", \"tbody\", \"td\",\n \"textarea\", \"tfoot\", \"th\", \"thead\", \"time\", \"title\", \"tr\",\n \"u\", \"ul\", \"var\", \"video\"\n)\n\nhtml_tags <- tags %>%\n set_names() %>%\n map(tag)\n\nwith_html <- function(code) {\n code <- enquo(code)\n eval_tidy(code, html_tags)\n}\n\nNow, let us briefly repeat, that with_html() was introduced to evaluate tag functions from within a list. Otherwise, defining some tag functions like body(), source(), summary() etc. within the global environment would collide with base R functions with the same name. To prevent this the DSL code wrapped in with_html() is evaluated within the “context” of html_tags, which was provided as a data mask to eval_tidy(). As ?rlang::as_data_mask mentions: “Objects in the mask have precedence over objects in the environment”.\nTherefore, p() refers to the tag function from html_tags within both examples from the exercise. However, as address is not only a string within the global environment, but also a tag function within html_tags (the <address> HTML tag may be used to provide contact information on an HTML page), p() operates on address() in the second example. This correctly leads to an error as we haven’t implemented an escape.function() method.\n\ngreeting <- \"Hello!\"\nwith_html(p(greeting))\n#> <HTML> <p>Hello!</p>\n\np <- function() \"p\"\naddress <- \"123 anywhere street\"\nwith_html(p(address))\n#> Error in `map_chr()`:\n#> ℹ In index: 1.\n#> Caused by error in `UseMethod()`:\n#> ! no applicable method for 'escape' applied to an object of class \"function\"\n\nQ4: Currently the HTML doesn’t look terribly pretty, and it’s hard to see the structure. How could you adapt tag() to do indenting and formatting? (You may need to do some research into block and inline tags.)\nA: First, let us load all relevant functions from Advanced R:\n\ntag <- function(tag) {\n new_function(\n exprs(... = ),\n expr({\n dots <- dots_partition(...)\n attribs <- html_attributes(dots$named)\n children <- map_chr(dots$unnamed, escape)\n html(paste0(\n !!paste0(\"<\", tag), attribs, \">\",\n paste(children, collapse = \"\"),\n !!paste0(\"</\", tag, \">\")\n ))\n }),\n caller_env()\n )\n}\n\nvoid_tag <- function(tag) {\n new_function(\n exprs(... = ),\n expr({\n dots <- dots_partition(...)\n if (length(dots$unnamed) > 0) {\n stop(\n !!paste0(\"<\", tag, \"> must not have unnamed arguments\"),\n call. = FALSE\n )\n }\n\n attribs <- html_attributes(dots$named)\n\n html(paste0(!!paste0(\"<\", tag), attribs, \" />\"))\n }),\n caller_env()\n )\n}\n\ntags <- c(\n \"a\", \"abbr\", \"address\", \"article\", \"aside\", \"audio\", \"b\",\n \"bdi\", \"bdo\", \"blockquote\", \"body\", \"button\", \"canvas\",\n \"caption\", \"cite\", \"code\", \"colgroup\", \"data\", \"datalist\",\n \"dd\", \"del\", \"details\", \"dfn\", \"div\", \"dl\", \"dt\", \"em\",\n \"eventsource\", \"fieldset\", \"figcaption\", \"figure\", \"footer\",\n \"form\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"head\", \"header\",\n \"hgroup\", \"html\", \"i\", \"iframe\", \"ins\", \"kbd\", \"label\", \"legend\",\n \"li\", \"mark\", \"map\", \"menu\", \"meter\", \"nav\", \"noscript\", \"object\",\n \"ol\", \"optgroup\", \"option\", \"output\", \"p\", \"pre\", \"progress\", \"q\",\n \"ruby\", \"rp\", \"rt\", \"s\", \"samp\", \"script\", \"section\", \"select\",\n \"small\", \"span\", \"strong\", \"style\", \"sub\", \"summary\", \"sup\",\n \"table\", \"tbody\", \"td\", \"textarea\", \"tfoot\", \"th\", \"thead\",\n \"time\", \"title\", \"tr\", \"u\", \"ul\", \"var\", \"video\"\n)\n\nvoid_tags <- c(\n \"area\", \"base\", \"br\", \"col\", \"command\", \"embed\", \"hr\", \"img\",\n \"input\", \"keygen\", \"link\", \"meta\", \"param\", \"source\",\n \"track\", \"wbr\"\n)\n\nhtml_tags <- c(\n tags %>% set_names() %>% map(tag),\n void_tags %>% set_names() %>% map(void_tag)\n)\n\nwith_html <- function(code) {\n code <- enquo(code)\n eval_tidy(code, html_tags)\n}\n\nNow, let’s look at the example from above:\n\nwith_html(\n body(\n h1(\"A heading\", id = \"first\"),\n p(\"Some text &\", b(\"some bold text.\")),\n img(src = \"myimg.png\", width = 100, height = 100)\n )\n)\n#> <HTML> <body><h1 id='first'>A heading</h1><p>Some text &<b>some\n#> bold text.</b></p><img src='myimg.png' width='100' height='100'\n#> /></body>\n\nThe formatting consists of only one long line of code. This output makes it difficult to check the content of the HTML code and its correctness.\nWhat kind of formatting would we prefer instead? Google’s HTML style guide suggests indentation by 2 spaces and new lines for every block, list, or table element. There are other recommendations, but we will keep things simple and will be satisfied with the following output.\n\n<body>\n <h1 id='first'>A heading</h1>\n <p>Some text &<b>some bold text.</b></p>\n <img src='myimg.png'width='100' height='100' />\n</body>\n\nFirst we adjust the print.advr_html() method, removing strwrap() function, because this will re-wrap the HTML, making it harder to understand what’s happening.\n\nhtml <- function(x) structure(x, class = \"advr_html\")\n\nprint.advr_html <- function(x, ...) {\n cat(paste(\"<HTML>\", x, sep = \"\\n\"))\n}\n\nIn our desired output we can see that the content of the body-function requires different formatting than the other tag-functions. We will therefore create a new format_code() function, that allows for optional indentation and line breaks.\n\nindent <- function(x) {\n paste0(\" \", gsub(\"\\n\", \"\\n \", x))\n}\n\nformat_code <- function(children, indent = FALSE) {\n if (indent) {\n paste0(\"\\n\", paste0(indent(children), collapse = \"\\n\"), \"\\n\")\n } else {\n paste(children, collapse = \"\")\n }\n}\n\nWe adjust the body function to include the format_code() helper. (This could also be approached programmatically in the tag function factory.)\n\nhtml_tags$body <- function(...) {\n dots <- dots_partition(...)\n attribs <- html_attributes(dots$named)\n children <- map_chr(dots$unnamed, escape)\n\n html(paste0(\n \"<body\", attribs, \">\",\n format_code(children, indent = TRUE),\n \"</body>\"\n ))\n}\n\nThe resulting output is much more satisfying.\n\nwith_html(\n body(\n h1(\"A heading\", id = \"first\"),\n p(\"Some text &\", b(\"some bold text.\")),\n img(src = \"myimg.png\", width = 100, height = 100)\n )\n)\n#> <HTML>\n#> <body>\n#> <h1 id='first'>A heading</h1>\n#> <p>Some text &<b>some bold text.</b></p>\n#> <img src='myimg.png' width='100' height='100' />\n#> </body>" + }, + { + "objectID": "21_Translating_R_code.html#latex", + "href": "21_Translating_R_code.html#latex", + "title": "21 - Translating R code", + "section": "LaTeX", + "text": "LaTeX\nQ1: Add escaping. The special symbols that should be escaped by adding a backslash in front of them are \\, $, and %. Just as with HTML, you’ll need to make sure you don’t end up double-escaping. So, you’ll need to create a small S3 class and then use that in function operators. That will also allow you to embed arbitrary LaTeX if needed.\nA: Currently our to_math() function generates the following output:\n\nto_math(`$`)\n#> <LATEX> \\mathrm{f}($) # instead of <LATEX> \\$\nto_math(a$b)\n#> <LATEX> \\mathrm{$}(a b) # instead of <LATEX> \\mathrm{\\$}(a b)\nto_math(`\\\\`)\n#> <LATEX> \\mathrm{f}(\\) # instead of <LATEX> \\\\\nto_math(`%`)\n#> <LATEX> \\mathrm{f}(%) # instead of <LATEX> \\%\n\nTo adjust this behaviour, we need an escape function with methods for the character and advr_latex classes.\n(Note that we must first repeat the underlying code from Advanced R. However, since this would be a bit verbose, and not very meaningful, we will not show this step here.)\n\nescape_latex <- function(x) UseMethod(\"escape_latex\")\n\nescape_latex.character <- function(x) {\n x <- gsub(\"^\\\\\\\\$\", \"\\\\\\\\\\\\\\\\\", x)\n x <- gsub(\"^\\\\$$\", \"\\\\\\\\$\", x)\n x <- gsub(\"^\\\\%$\", \"\\\\\\\\%\", x)\n\n latex(x)\n}\n\nescape_latex.advr_latex <- function(x) x\n\nWe apply escape_latex() within latex_env() when creating environments for unknown symbols and unknown functions. For the unknown function, we need to modify unknown_op() first.\n\nunknown_op <- function(op) {\n new_function(\n exprs(... = ),\n expr({\n contents <- paste(..., collapse = \", \")\n paste0(\n !!paste0(\"\\\\mathrm{\", escape_latex(op), \"}(\"), contents, \")\"\n )\n })\n )\n}\n\nlatex_env <- function(expr) {\n calls <- all_calls(expr)\n call_list <- map(set_names(calls), unknown_op)\n call_env <- as_environment(call_list)\n\n # Known functions\n f_env <- env_clone(f_env, call_env)\n\n # Default symbols\n names <- all_names(expr)\n symbol_env <- as_environment(set_names(escape_latex(names), names),\n parent = f_env\n )\n\n # Known symbols\n greek_env <- env_clone(greek_env, parent = symbol_env)\n greek_env\n}\n\nNow, we can validate to_math() on the test cases from above.\n\nto_math(`$`)\n#> <LATEX> \\$\nto_math(a$b)\n#> <LATEX> \\mathrm{\\$}(a b)\nto_math(`\\\\`)\n#> <LATEX> \\\\\nto_math(`%`)\n#> <LATEX> \\%\n\nQ2: Complete the DSL to support all the functions that plotmath supports.\nA: You can see all supported functions in ?plotmath. There are a lot (!) so here we choose to implement a representative sample:\n\nto_math(x %+-% y)\nto_math(x %*% y)\nto_math(x %->% y)\nto_math(bold(x))\nto_math(x != y)\n\nImplementing the rest is just a mechanical application of the same principles with more LaTex expressions, which can be found on Wikipedia.\nTo provide these translations, we’ll follow the LaTeX section from Advanced R from the beginning. This makes it easier to keep an overview, as we just need to insert the specific changes at the relevant parts.\nLet’s start and repeat the converter function to_math() from the textbook.\n\nto_math <- function(x) {\n expr <- enexpr(x)\n out <- eval_bare(expr, latex_env(expr))\n\n latex(out)\n}\n\nlatex <- function(x) structure(x, class = \"advr_latex\")\nprint.advr_latex <- function(x) {\n cat(\"<LATEX> \", x, \"\\n\", sep = \"\")\n}\n\nOne specific property in this setting is that the environment where to_math() evaluates the expression is not constant, but depends on what we already know about the expression.\nNext, we start building up latex_env(), which contains a chain of all the necessary environments which to_math() checks to evaluate the expression in.\nThe first environment is the one for Greek letters.\n\ngreek <- c(\n \"alpha\", \"theta\", \"tau\", \"beta\", \"vartheta\", \"pi\", \"upsilon\",\n \"gamma\", \"varpi\", \"phi\", \"delta\", \"kappa\", \"rho\",\n \"varphi\", \"epsilon\", \"lambda\", \"varrho\", \"chi\", \"varepsilon\",\n \"mu\", \"sigma\", \"psi\", \"zeta\", \"nu\", \"varsigma\", \"omega\", \"eta\",\n \"xi\", \"Gamma\", \"Lambda\", \"Sigma\", \"Psi\", \"Delta\", \"Xi\",\n \"Upsilon\", \"Omega\", \"Theta\", \"Pi\", \"Phi\"\n)\ngreek_list <- set_names(paste0(\"\\\\\", greek), greek)\ngreek_env <- as_environment(greek_list)\n\nlatex_env <- function(expr) {\n greek_env\n}\n\nWe already know from Advanced R that e.g. to_math(pi) now correctly converts to \\\\pi. So, let’s move on to the next one.\nHere, it’ll become a bit more technical. Not every symbol is Greek (and not every part of an expression is a symbol). To find out which symbols are present within the expression, first, we use an approach from section 5 of the expressions chapter (walking the AST to find all symbols) where Hadley recursively walks the AST to distinguish between different expression element types.\nLet’s briefly repeat the helpers defined in that section:\n\nexpr_type <- function(x) {\n if (rlang::is_syntactic_literal(x)) {\n \"constant\"\n } else if (is.symbol(x)) {\n \"symbol\"\n } else if (is.call(x)) {\n \"call\"\n } else if (is.pairlist(x)) {\n \"pairlist\"\n } else {\n typeof(x)\n }\n}\n\nswitch_expr <- function(x, ...) {\n switch(expr_type(x),\n ...,\n stop(\"Don't know how to handle type \",\n typeof(x),\n call. = FALSE\n )\n )\n}\n\nflat_map_chr <- function(.x, .f, ...) {\n purrr::flatten_chr(purrr::map(.x, .f, ...))\n}\n\nThis lets us define all_names(), which returns the desired symbols, already converted to characters.\n\nall_names_rec <- function(x) {\n switch_expr(x,\n constant = character(),\n symbol = as.character(x),\n call = flat_map_chr(as.list(x[-1]), all_names)\n )\n}\n\nall_names <- function(x) {\n unique(all_names_rec(x))\n}\n\nall_names(expr(x + y + f(a, b, c, 10)))\n#> [1] \"x\" \"y\" \"a\" \"b\" \"c\"\n\nWe use all_names() now within latex_env() to create an environment of the symbols which were found within the expression. This environment will be set as the parent environment of greek_env.\n\nlatex_env <- function(expr) {\n # Unknown symbols\n names <- all_names(expr)\n symbol_env <- as_environment(set_names(names))\n\n # Known symbols\n env_clone(greek_env, parent = symbol_env)\n}\n\nIn this way, to_math() will first convert all known Greek letters (found in greek_env) and then any other symbols, which are left as is (in this implementation).\nWe also have to add support for functions. This will give us the opportunity to insert some specific support for plotmath functions.\nTo support a whole bunch of unary and binary functions within the function environment (f_env), which will be added next to latex_env, Hadley defines the following two helpers in Advanced R.\n\nunary_op <- function(left, right) {\n new_function(\n exprs(e1 = ),\n expr(\n paste0(!!left, e1, !!right)\n ),\n caller_env()\n )\n}\n\nbinary_op <- function(sep) {\n new_function(\n exprs(e1 = , e2 = ),\n expr(\n paste0(e1, !!sep, e2)\n ),\n caller_env()\n )\n}\n\nWhile defining the function environment, f_env, we mostly continue to copy the exact code from Advanced R. However, at the bottom we add a short section where we define some extra conversions which are part of plotmath (and selected above in our intro to this solution).\n\nf_env <- child_env(\n # Binary operators\n .parent = empty_env(),\n `+` = binary_op(\" + \"),\n `-` = binary_op(\" - \"),\n `*` = binary_op(\" * \"),\n `/` = binary_op(\" / \"),\n `^` = binary_op(\"^\"),\n `[` = binary_op(\"_\"),\n\n # Grouping\n `{` = unary_op(\"\\\\left{ \", \" \\\\right}\"),\n `(` = unary_op(\"\\\\left( \", \" \\\\right)\"),\n paste = paste,\n\n # Other math functions\n sqrt = unary_op(\"\\\\sqrt{\", \"}\"),\n sin = unary_op(\"\\\\sin(\", \")\"),\n log = unary_op(\"\\\\log(\", \")\"),\n abs = unary_op(\"\\\\left| \", \"\\\\right| \"),\n frac = function(a, b) {\n paste0(\"\\\\frac{\", a, \"}{\", b, \"}\")\n },\n\n # Labelling\n hat = unary_op(\"\\\\hat{\", \"}\"),\n tilde = unary_op(\"\\\\tilde{\", \"}\"),\n\n # Plotmath\n `%+-%` = binary_op(\" \\\\pm \"),\n `%*%` = binary_op(\" \\\\times \"),\n `%->%` = binary_op(\" \\\\rightarrow \"),\n bold = unary_op(\"\\\\textbf{\", \"}\"),\n `!=` = binary_op(\" \\\\neq \")\n)\n\nAgain we extend latex_env() to include the additional environment, f_env, which must be the parent of the symbol environment (which is the parent of the Greek symbol environment).\n\nlatex_env <- function(expr) {\n # Known functions\n f_env\n\n # Default symbols\n names <- all_names(expr)\n symbol_env <- as_environment(set_names(names), parent = f_env)\n\n # Known symbols\n greek_env <- env_clone(greek_env, parent = symbol_env)\n\n greek_env\n}\n\nNow, we can finally check if our new functionality works:\n\n# New plotmath functionality\nto_math(x %+-% y)\n#> <LATEX> x \\pm y\nto_math(x %*% y)\n#> <LATEX> x \\times y\nto_math(x %->% y)\n#> <LATEX> x \\rightarrow y\nto_math(bold(x))\n#> <LATEX> \\textbf{x}\nto_math(x != y)\n#> <LATEX> x \\neq y\n\n# Other examples from Advanced R\nto_math(sin(x + pi))\n#> <LATEX> \\sin(x + \\pi)\nto_math(log(x[i]^2))\n#> <LATEX> \\log(x_i^2)\nto_math(sin(sin))\n#> <LATEX> \\sin(sin)\n\nIf we wanted, we could include further plotmath functions in this step. If this collides with other functions at some point, we could just create our own f_plotmath_env to support more plotmath functions. In that case we would need to add this environment also to latex_env() (as child environment of the function environment f_env).\nTo complete this answer, we will also add the support for unknown functions. Similarly as for the unknown symbols, we use the trick to recursively run the AST and just reuse the code from Advanced R.\n\nall_calls_rec <- function(x) {\n switch_expr(x,\n constant = ,\n symbol = character(),\n call = {\n fname <- as.character(x[[1]])\n children <- flat_map_chr(as.list(x[-1]), all_calls)\n c(fname, children)\n }\n )\n}\n\nall_calls <- function(x) {\n unique(all_calls_rec(x))\n}\n\nall_calls(expr(f(g + b, c, d(a))))\n#> [1] \"f\" \"+\" \"d\"\n\nunknown_op <- function(op) {\n new_function(\n exprs(... = ),\n expr({\n contents <- paste(..., collapse = \", \")\n paste0(!!paste0(\"\\\\mathrm{\", op, \"}(\"), contents, \")\")\n })\n )\n}\n\nOf course, we need to add the new call_env also to latex_env().\n\nlatex_env <- function(expr) {\n calls <- all_calls(expr)\n call_list <- map(set_names(calls), unknown_op)\n call_env <- as_environment(call_list)\n\n # Known functions\n f_env <- env_clone(f_env, call_env)\n\n # Default symbols\n names <- all_names(expr)\n symbol_env <- as_environment(set_names(names), parent = f_env)\n\n # Known symbols\n greek_env <- env_clone(greek_env, parent = symbol_env)\n greek_env\n}\n\nFinally, we rerun our tests and double check the newly supported plotmath operators.\n\n# New plotmath functionality\nto_math(x %+-% y)\n#> <LATEX> x \\pm y\nto_math(x %*% y)\n#> <LATEX> x \\times y\nto_math(x %->% y)\n#> <LATEX> x \\rightarrow y\nto_math(bold(x))\n#> <LATEX> \\textbf{x}\nto_math(x != y)\n#> <LATEX> x \\neq y\n\n# Other examples from Advanced R\nto_math(sin(x + pi))\n#> <LATEX> \\sin(x + \\pi)\nto_math(log(x[i]^2))\n#> <LATEX> \\log(x_i^2)\nto_math(sin(sin))\n#> <LATEX> \\sin(sin)\n\n# Unknown functions\nto_math(f(g(x)))\n#> <LATEX> \\mathrm{f}(\\mathrm{g}(x))" + }, + { + "objectID": "23_Measuring_performance.html#profiling", + "href": "23_Measuring_performance.html#profiling", + "title": "23 - Measuring performance", + "section": "Profiling", + "text": "Profiling\nQ1: Profile the following function with torture = TRUE. What is surprising? Read the source code of rm() to figure out what’s going on.\n\nf <- function(n = 1e5) {\n x <- rep(1, n)\n rm(x)\n}\n\nA: We expect f() to create a vector (x) of length n, which is then removed so that f() just returns NULL. When we profile this function, it executes too fast for meaningful results.\n\nprofvis::profvis(f())\n#> Error in parse_rprof_lines(lines, expr_source): No parsing data available. Maybe your function was too fast?\n\nSetting torture = TRUE triggers garbage collection after every memory allocation call, which may be useful for more exact memory profiling.\n\nprofvis::profvis(f(), torture = TRUE)\n\nSurprisingly, profiling f() like this takes a very long time. What could be the reason?\nWe follow the hint in the question and inspect the source code of rm():\n\nfunction(..., list = character(), pos = -1,\n envir = as.environment(pos),\n inherits = FALSE) {\n dots <- match.call(expand.dots = FALSE)$...\n if (\n length(dots) && !all(\n vapply(dots, function(x) {\n is.symbol(x) ||\n is.character(x)\n }, NA, USE.NAMES = FALSE)\n )\n ) {\n stop(\"... must contain names or character strings\")\n }\n names <- vapply(dots, as.character, \"\")\n if (length(names) == 0L) {\n names <- character()\n }\n list <- .Primitive(\"c\")(list, names)\n .Internal(remove(list, envir, inherits))\n}\n\nrm() does a surprising amount of work to get the name of the object to delete because it relies on non-standard evaluation.\nWe can make the job of rm() considerably simpler by using the list argument:\n\nf2 <- function(n = 1e5) {\n x <- rep(1, n)\n rm(list = \"x\")\n}\nprofvis::profvis(f2(), torture = TRUE)\n\nUnfortunately, this still takes too long, and we are literally stuck in profiling.\nAnecdotally, one of the authors once finished the profiling under an older R version. But the output seemed to be not very meaningful.\nIn conclusion, this question appears to be unanswerable for us, even for Hadley." + }, + { + "objectID": "23_Measuring_performance.html#microbenchmarking", + "href": "23_Measuring_performance.html#microbenchmarking", + "title": "23 - Measuring performance", + "section": "Microbenchmarking", + "text": "Microbenchmarking\nQ1: Instead of using bench::mark(), you could use the built-in function system.time(). But system.time() is much less precise, so you’ll need to repeat each operation many times with a loop, and then divide to find the average time of each operation, as in the code below.\n\nn <- 1e6\nsystem.time(for (i in 1:n) sqrt(x)) / n\nsystem.time(for (i in 1:n) x^0.5) / n\n\nHow do the estimates from system.time() compare to those from bench::mark()? Why are they different?\nA: We first microbenchmark these two expressions using bench::mark() (Hester 2020) and observe that the mean is not reported (as it is generally more affected by outliers).\n\nn <- 1e6\nx <- runif(100)\n\nbench_df <- bench::mark(\n sqrt(x),\n x^0.5,\n iterations = n\n)\n\nbench_df\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 sqrt(x) 191.15ns 237ns 2277084. 848B 38.7\n#> 2 x^0.5 1.38µs 1.5µs 644621. 848B 23.2\n\nWe need to access the raw data, so we can compare the results of both benchmarking approaches.\n\nt1_bench <- mean(unlist(bench_df[1, \"time\"]))\nt2_bench <- mean(unlist(bench_df[2, \"time\"]))\n\nt1_systime <- system.time(for (i in 1:n) sqrt(x)) / n\nt2_systime <- system.time(for (i in 1:n) x^0.5) / n\n\nWe see, that both approaches get the order of magnitude right. We assume, that the bench::mark()-results may be a little more accurate, because of its high precision timer. There may also be overhead introduced by the for loop in the system.time()-approach.\n\n# Compare the results\nt1_systime[\"elapsed\"]\nt1_bench\n\nt2_systime[\"elapsed\"]\nt2_bench\n\nSide Note: take a look at ?proc.time if you want to learn about the differences between “user”, “system” and “elapsed” time.\nQ2: Here are two other ways to compute the square root of a vector. Which do you think will be fastest? Which will be slowest? Use microbenchmarking to test your answers.\n\nx^(1 / 2)\nexp(log(x) / 2)\n\nA: To compare these approaches, we’ll bench::mark() them and sort the result by the median execution time.\n\nx <- runif(100)\n\nbm <- bench::mark(\n sqrt(x),\n x^0.5,\n x^(1 / 2),\n exp(log(x) / 2)\n)\n\nbm[order(bm$median), ]\n#> # A tibble: 4 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 sqrt(x) 205.01ns 223.05ns 4053946. 848B 0\n#> 2 exp(log(x)/2) 1.08µs 1.14µs 842693. 848B 0\n#> 3 x^0.5 1.45µs 1.5µs 639435. 848B 0\n#> 4 x^(1/2) 1.52µs 1.58µs 607937. 848B 0\n\nAs one might expect the idiomatic primitive function sqrt() is the fastest. The approach exp(log(x) / 2) which builds on two other primitive functions is second, even though already considerably slower. The other calculations are even slower: x^0.5 is faster than x^ (1/2), because 0.5 requires less computation than 1/2." + }, + { + "objectID": "23_Measuring_performance.html#references", + "href": "23_Measuring_performance.html#references", + "title": "23 - Measuring performance", + "section": "References", + "text": "References\n\n\n\n\nHester, Jim. 2020. Bench: High Precision Timing of r Expressions. https://github.com/r-lib/bench." + }, + { + "objectID": "24_Improving_performance.html#checking-for-existing-solutions", + "href": "24_Improving_performance.html#checking-for-existing-solutions", + "title": "24 - Improving performance", + "section": "Checking for existing solutions", + "text": "Checking for existing solutions\nQ1: What are faster alternatives to lm? Which are specifically designed to work with larger datasets?\nA: The CRAN task view for high-performance computing provides many recommendations. For this question, we are most interested in the section on “Large memory and out-of-memory data”. We could for example give biglm::biglm() (Lumley 2020), fixest::feols() (Bergé 2018) a try.\nFor small datasets, we observe only minor performance gains (or even a small cost):\n\npenguins <- palmerpenguins::penguins\n\nbench::mark(\n \"lm\" = lm(\n body_mass_g ~ bill_length_mm + species,\n data = penguins\n ) %>% coef(),\n \"biglm\" = biglm::biglm(\n body_mass_g ~ bill_length_mm + species,\n data = penguins\n ) %>% coef(),\n \"fixest\" = fixest::feols(\n body_mass_g ~ bill_length_mm + species,\n data = penguins\n ) %>% coef()\n)\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> NOTE: 2 observations removed because of NA values (LHS: 2, RHS: 2).\n#> # A tibble: 3 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 lm 423.93µs 500.75µs 1844. 937.49KB 10.6 \n#> 2 biglm 320.17µs 367.26µs 2636. 6.14MB 10.4 \n#> 3 fixest 3.58ms 3.93ms 252. 13.79MB 6.25\n\nFor larger datasets the selection of the appropriate method is of greater relevance:\n\neps <- rnorm(100000)\nx1 <- rnorm(100000, 5, 3)\nx2 <- rep(c(\"a\", \"b\"), 50000)\ny <- 7 * x1 + (x2 == \"a\") + eps\ntd <- data.frame(y = y, x1 = x1, x2 = x2, eps = eps)\n\nbench::mark(\n \"lm\" = lm(y ~ x1 + x2, data = td) %>% coef(),\n \"biglm\" = biglm::biglm(y ~ x1 + x2, data = td) %>% coef(),\n \"fixest\" = fixest::feols(y ~ x1 + x2, data = td) %>% coef()\n)\n#> # A tibble: 3 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 lm 16.91ms 17.08ms 58.5 27.04MB 732. \n#> 2 biglm 15.4ms 15.57ms 64.0 22.22MB 256. \n#> 3 fixest 8.18ms 8.68ms 110. 9.05MB 60.8\n\nFor further speed improvements, you could install a linear algebra library optimised for your system.\n\nThe functions of class ‘feols’ may speed up the fitting of LMs to large datasets. High performances can be obtained especially if R is linked against an optimized BLAS, such as ATLAS, Intel MKL, OpenBLAS, and others.\n\nTip: In case your dataset is stored in a database, you might want to check out the {modeldb} package (Kuhn 2020) which executes the linear model code in the corresponding database backend.\nQ2: What package implements a version of match() that’s faster for repeated lookups? How much faster is it?\nA: A web search points us to the {fastmatch} package (Urbanek 2017). We compare it to base::match() and observe an impressive performance gain.\n\ntable <- 1:100000\nx <- sample(table, 10000, replace = TRUE)\n\nbench::mark(\n match = match(x, table),\n fastmatch = fastmatch::fmatch(x, table)\n)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 match 7.41ms 7.58ms 131. 1.46MB 6.33\n#> 2 fastmatch 258.9µs 270.06µs 3642. 442.91KB 4.05\n\nQ3: List four functions (not just those in base R) that convert a string into a date time object. What are their strengths and weaknesses?\nA: The usual base R way is to use the as.POSIXct() generic and create a date time object of class POSIXct and type integer.\n\ndate_ct <- as.POSIXct(\"2020-01-01 12:30:25\")\ndate_ct\n#> [1] \"2020-01-01 12:30:25 EST\"\n\nUnder the hood as.POSIXct() employs as.POSIXlt() for the character conversion. This creates a date time object of class POSIXlt and type list.\n\ndate_lt <- as.POSIXlt(\"2020-01-01 12:30:25\")\ndate_lt\n#> [1] \"2020-01-01 12:30:25 EST\"\n\nThe POSIXlt class has the advantage that it carries the individual time components as attributes. This allows to extract the time components via typical list operators.\n\nattributes(date_lt)\n#> $names\n#> [1] \"sec\" \"min\" \"hour\" \"mday\" \"mon\" \"year\" \"wday\" \"yday\" \n#> [9] \"isdst\" \"zone\" \"gmtoff\"\n#> \n#> $class\n#> [1] \"POSIXlt\" \"POSIXt\" \n#> \n#> $tzone\n#> [1] \"\" \"EST\" \"EDT\"\n#> \n#> $balanced\n#> [1] TRUE\ndate_lt$sec\n#> [1] 25\n\nHowever, while lists may be practical, basic calculations are often faster and require less memory for objects with underlying integer type.\n\ndate_lt2 <- rep(date_lt, 10000)\ndate_ct2 <- rep(date_ct, 10000)\n\nbench::mark(\n date_lt2 - date_lt2,\n date_ct2 - date_ct2,\n date_ct2 - date_lt2\n)\n#> # A tibble: 3 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 date_lt2 - date_lt2 17.32ms 17.52ms 56.9 1.39MB 2.03\n#> 2 date_ct2 - date_ct2 36.06µs 40.44µs 23556. 195.45KB 111. \n#> 3 date_ct2 - date_lt2 7.67ms 8.75ms 115. 781.95KB 2.05\n\nas.POSIXlt() in turn uses strptime() under the hood, which creates a similar date time object.\n\ndate_str <- strptime(\"2020-01-01 12:30:25\",\n format = \"%Y-%m-%d %H:%M:%S\"\n)\nidentical(date_lt, date_str)\n#> [1] TRUE\n\nas.POSIXct() and as.POSIXlt() accept different character inputs by default (e.g. \"2001-01-01 12:30\" or \"2001/1/1 12:30\"). strptime() requires the format argument to be set explicitly, and provides a performance improvement in return.\n\nbench::mark(\n as.POSIXct = as.POSIXct(\"2020-01-01 12:30:25\"),\n as.POSIXct_format = as.POSIXct(\"2020-01-01 12:30:25\",\n format = \"%Y-%m-%d %H:%M:%S\"\n ),\n strptime_fomat = strptime(\"2020-01-01 12:30:25\",\n format = \"%Y-%m-%d %H:%M:%S\"\n )\n)[1:3]\n#> # A tibble: 3 × 3\n#> expression min median\n#> <bch:expr> <bch:tm> <bch:tm>\n#> 1 as.POSIXct 20.43µs 23.71µs\n#> 2 as.POSIXct_format 10.9µs 12.38µs\n#> 3 strptime_fomat 2.85µs 3.08µs\n\nA fourth way is to use the converter functions from the {lubridate} package (Grolemund and Wickham 2011), which contains wrapper functions (for the POSIXct approach) with an intuitive syntax. (There is a slight decrease in performance though.)\n\nlibrary(lubridate)\nymd_hms(\"2013-07-24 23:55:26\")\n#> [1] \"2013-07-24 23:55:26 UTC\"\n\nbench::mark(\n as.POSIXct = as.POSIXct(\"2013-07-24 23:55:26\", tz = \"UTC\"),\n ymd_hms = ymd_hms(\"2013-07-24 23:55:26\")\n)[1:3]\n#> # A tibble: 2 × 3\n#> expression min median\n#> <bch:expr> <bch:tm> <bch:tm>\n#> 1 as.POSIXct 22.55µs 25.7µs\n#> 2 ymd_hms 1.54ms 1.7ms\n\nFor additional ways to convert characters into date time objects, have a look at the {chron}, the {anytime} and the {fasttime} packages. The {chron} package (James and Hornik 2020) introduces new classes and stores times as fractions of days in the underlying double type, while it doesn’t deal with time zones and daylight savings. The {anytime} package (Eddelbuettel 2020) aims to convert “Anything to POSIXct or Date”. The {fasttime} package (Urbanek 2016) contains only one function, fastPOSIXct().\nQ4: Which packages provide the ability to compute a rolling mean?\nA: A rolling mean is a useful statistic to smooth time-series, spatial and other types of data. The size of the rolling window usually determines the amount of smoothing and the number of missing values at the boundaries of the data.\nThe general functionality can be found in multiple packages, which vary in speed and flexibility of the computations. Here is a benchmark for several functions that all serve our purpose.\n\nx <- 1:10\nslider::slide_dbl(x, mean, .before = 1, .complete = TRUE)\n#> [1] NA 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5\n\nbench::mark(\n caTools = caTools::runmean(x, k = 2, endrule = \"NA\"),\n data.table = data.table::frollmean(x, 2),\n slider = slider::slide_dbl(x, mean, .before = 1, .complete = TRUE),\n TTR = TTR::SMA(x, 2),\n zoo_apply = zoo::rollapply(x, 2, mean, fill = NA, align = \"right\"),\n zoo_rollmean = zoo::rollmean(x, 2, fill = NA, align = \"right\")\n)\n#> # A tibble: 6 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 caTools 25µs 29.2µs 33235. 168.47KB 16.6\n#> 2 data.table 13.2µs 15.6µs 60402. 32.73KB 30.2\n#> 3 slider 29.8µs 34.5µs 28092. 0B 16.9\n#> 4 TTR 53.8µs 62.7µs 15513. 608.02KB 14.6\n#> 5 zoo_apply 123.8µs 145.7µs 6673. 453.96KB 17.0\n#> 6 zoo_rollmean 115.2µs 123.7µs 7637. 6.43KB 19.0\n\nYou may also take a look at an extensive example in the first edition of Advanced R, which demonstrates how a rolling mean function can be created.\nQ5: What are the alternatives to optim()?\nA: According to its description (see ?optim) optim() implements:\n\nGeneral-purpose optimization based on Nelder–Mead, quasi-Newton and conjugate-gradient algorithms. It includes an option for box-constrained optimization and simulated annealing.\n\noptim() allows to optimise a function (fn) on an interval with a specific method (method = c(\"Nelder-Mead\", \"BFGS\", \"CG\", \"L-BFGS-B\", \"SANN\", \"Brent\")). Many detailed examples are given in the documentation. In the simplest case, we give optim() the starting value par = 0 to calculate the minimum of a quadratic polynomial:\n\noptim(0, function(x) x^2 - 100 * x + 50,\n method = \"Brent\",\n lower = -1e20, upper = 1e20\n)\n#> $par\n#> [1] 50\n#> \n#> $value\n#> [1] -2450\n#> \n#> $counts\n#> function gradient \n#> NA NA \n#> \n#> $convergence\n#> [1] 0\n#> \n#> $message\n#> NULL\n\nSince this solves a one-dimensional optimisation task, we could have also used stats::optimize().\n\noptimize(function(x) x^2 - 100 * x + 50, c(-1e20, 1e20))\n#> $minimum\n#> [1] 50\n#> \n#> $objective\n#> [1] -2450\n\nFor more general alternatives, the appropriate choice highly depends on the type of optimisation you intend to do. The CRAN task view on optimisation and mathematical modelling can serve as a useful reference. Here are a couple of examples:\n\n{optimx} (Nash and Varadhan 2011; Nash 2014) extends the optim() function with the same syntax but more method choices.\n{DEoptim} (Ardia et al. 2011) provides a global optimiser based on the Differential Evolution algorithm." + }, + { + "objectID": "24_Improving_performance.html#doing-as-little-as-possible", + "href": "24_Improving_performance.html#doing-as-little-as-possible", + "title": "24 - Improving performance", + "section": "Doing as little as possible", + "text": "Doing as little as possible\nQ1: What’s the difference between rowSums() and .rowSums()?\nA: When we inspect the source code of the user-facing rowSums(), we see that it is designed as a wrapper around .rowSums() with some input validation, conversions and handling of complex numbers.\n\nrowSums\n#> function (x, na.rm = FALSE, dims = 1L) \n#> {\n#> if (is.data.frame(x)) \n#> x <- as.matrix(x)\n#> if (!is.array(x) || length(dn <- dim(x)) < 2L) \n#> stop(\"'x' must be an array of at least two dimensions\")\n#> if (dims < 1L || dims > length(dn) - 1L) \n#> stop(\"invalid 'dims'\")\n#> p <- prod(dn[-(id <- seq_len(dims))])\n#> dn <- dn[id]\n#> z <- if (is.complex(x)) \n#> .Internal(rowSums(Re(x), prod(dn), p, na.rm)) + (0+1i) * \n#> .Internal(rowSums(Im(x), prod(dn), p, na.rm))\n#> else .Internal(rowSums(x, prod(dn), p, na.rm))\n#> if (length(dn) > 1L) {\n#> dim(z) <- dn\n#> dimnames(z) <- dimnames(x)[id]\n#> }\n#> else names(z) <- dimnames(x)[[1L]]\n#> z\n#> }\n#> <bytecode: 0x5f225cb2bb38>\n#> <environment: namespace:base>\n\n.rowSums() calls an internal function, which is built into the R interpreter. These compiled functions can be very fast.\n\n.rowSums\n#> function (x, m, n, na.rm = FALSE) \n#> .Internal(rowSums(x, m, n, na.rm))\n#> <bytecode: 0x5f225c1051e0>\n#> <environment: namespace:base>\n\nHowever, as our benchmark reveals almost identical computing times, we prefer the safer variant over the internal function for this case.\n\nm <- matrix(rnorm(1e6), nrow = 1000)\n\nbench::mark(\n rowSums(m),\n .rowSums(m, 1000, 1000)\n)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 rowSums(m) 1.96ms 2.2ms 455. 7.86KB 0\n#> 2 .rowSums(m, 1000, 1000) 1.98ms 2.19ms 458. 7.86KB 0\n\nQ2: Make a faster version of chisq.test() that only computes the chi-square test statistic when the input is two numeric vectors with no missing values. You can try simplifying chisq.test() or by coding from the mathematical definition.\nA: We aim to speed up our reimplementation of chisq.test() by doing less.\n\nchisq.test2 <- function(x, y) {\n m <- rbind(x, y)\n margin1 <- rowSums(m)\n margin2 <- colSums(m)\n n <- sum(m)\n me <- tcrossprod(margin1, margin2) / n\n\n x_stat <- sum((m - me)^2 / me)\n df <- (length(margin1) - 1) * (length(margin2) - 1)\n p.value <- pchisq(x_stat, df = df, lower.tail = FALSE)\n\n list(x_stat = x_stat, df = df, p.value = p.value)\n}\n\nWe check if our new implementation returns the same results and benchmark it afterwards.\n\na <- 21:25\nb <- seq(21, 29, 2)\nm <- cbind(a, b)\n\nchisq.test(m) %>% print(digits = 5)\n#> \n#> Pearson's Chi-squared test\n#> \n#> data: m\n#> X-squared = 0.162, df = 4, p-value = 1\nchisq.test2(a, b)\n#> $x_stat\n#> [1] 0.162\n#> \n#> $df\n#> [1] 4\n#> \n#> $p.value\n#> [1] 0.997\n\nbench::mark(\n chisq.test(m),\n chisq.test2(a, b),\n check = FALSE\n)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 chisq.test(m) 31.43µs 35.6µs 26715. 0B 16.0\n#> 2 chisq.test2(a, b) 9.16µs 10.4µs 91271. 0B 18.3\n\nQ3: Can you make a faster version of table() for the case of an input of two integer vectors with no missing values? Can you use it to speed up your chi-square test?\nA: When analysing the source code of table() we aim to omit everything unnecessary and extract the main building blocks. We observe that table() is powered by tabulate() which is a very fast counting function. This leaves us with the challenge to compute the pre-processing as performant as possible.\nFirst, we calculate the dimensions and names of the output table. Then we use fastmatch::fmatch() to map the elements of each vector to their position within the vector itself (i.e. the smallest value is mapped to 1L, the second smallest value to 2L, etc.). Following the logic within table() we combine and shift these values to create a mapping of the integer pairs in our data to the index of the output table. After applying these lookups tabulate() counts the values and returns an integer vector with counts for each position in the table. As a last step, we reuse the code from table() to assign the correct dimension and class.\n\ntable2 <- function(a, b) {\n a_s <- sort(unique(a))\n b_s <- sort(unique(b))\n\n a_l <- length(a_s)\n b_l <- length(b_s)\n\n dims <- c(a_l, b_l)\n pr <- a_l * b_l\n dn <- list(a = a_s, b = b_s)\n\n bin <- fastmatch::fmatch(a, a_s) +\n a_l * fastmatch::fmatch(b, b_s) - a_l\n y <- tabulate(bin, pr)\n\n y <- array(y, dim = dims, dimnames = dn)\n class(y) <- \"table\"\n\n y\n}\n\na <- sample(100, 10000, TRUE)\nb <- sample(100, 10000, TRUE)\n\nbench::mark(\n table(a, b),\n table2(a, b)\n)\n#> # A tibble: 2 × 6\n#> expression min median `itr/sec` mem_alloc `gc/sec`\n#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>\n#> 1 table(a, b) 609µs 670µs 1450. 1.29MB 43.3\n#> 2 table2(a, b) 221µs 236µs 4119. 563.34KB 48.5\n\nSince we didn’t use table() in our chisq.test2()-implementation, we cannot benefit from the slight performance gain from table2()." + }, + { + "objectID": "24_Improving_performance.html#vectorise", + "href": "24_Improving_performance.html#vectorise", + "title": "24 - Improving performance", + "section": "Vectorise", + "text": "Vectorise\nQ1: The density functions, e.g. dnorm(), have a common interface. Which arguments are vectorised over? What does rnorm(10, mean = 10:1) do?\nA: We can get an overview of the interface of these functions via ?dnorm:\n\ndnorm(x, mean = 0, sd = 1, log = FALSE)\npnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)\nqnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)\nrnorm(n, mean = 0, sd = 1)\n\nThese functions are vectorised over their numeric arguments, which includes the first argument (x, q, p, n) as well as mean and sd.\nrnorm(10, mean = 10:1) generates ten random numbers from different normal distributions. These normal distributions differ in their means. The first has mean 10, the second mean 9, the third mean 8 and so on.\nQ2: Compare the speed of apply(x, 1, sum) with rowSums(x) for varying sizes of x.\nA: We compare the two functions for square matrices of increasing size:\n\nrowsums <- bench::press(\n p = seq(500, 5000, length.out = 10),\n {\n mat <- tcrossprod(rnorm(p), rnorm(p))\n bench::mark(\n rowSums = rowSums(mat),\n apply = apply(mat, 1, sum)\n )\n }\n)\n#> Running with:\n#> p\n#> 1 500\n#> 2 1000\n#> 3 1500\n#> 4 2000\n#> 5 2500\n#> 6 3000\n#> 7 3500\n#> 8 4000\n#> 9 4500\n#> 10 5000\n\nlibrary(ggplot2)\n\nrowsums %>%\n summary() %>%\n dplyr::mutate(Approach = as.character(expression)) %>%\n ggplot(\n aes(p, median, color = Approach, group = Approach)\n ) +\n geom_point() +\n geom_line() +\n labs(\n x = \"Number of Rows and Columns\",\n y = \"Median (s)\"\n ) +\n theme(legend.position = \"top\")\n\n\n\n\n\n\n\n\nWe can see that the difference in performance is negligible for small matrices but becomes more and more relevant as the size of the data increases. apply() is a very versatile tool, but it’s not “vectorised for performance” and not as optimised as rowSums().\nQ3: How can you use crossprod() to compute a weighted sum? How much faster is it than the naive sum(x * w)?\nA: We can hand the vectors to crossprod(), which converts them to row- and column-vectors and then multiplies these. The result is the dot product, which corresponds to a weighted sum.\n\nx <- rnorm(10)\nw <- rnorm(10)\nall.equal(sum(x * w), crossprod(x, w)[[1]])\n#> [1] TRUE\n\nA benchmark of both approaches for different vector lengths indicates that the crossprod() variant is almost twice as fast as sum(x * w).\n\nweightedsum <- bench::press(\n n = 1:10,\n {\n x <- rnorm(n * 1e6)\n bench::mark(\n sum = sum(x * x),\n crossprod = crossprod(x, x)[[1]]\n )\n }\n)\n#> Running with:\n#> n\n#> 1 1\n#> 2 2\n#> 3 3\n#> 4 4\n#> 5 5\n#> 6 6\n#> 7 7\n#> 8 8\n#> 9 9\n#> 10 10\n\nweightedsum %>%\n summary() %>%\n dplyr::mutate(Approach = as.character(expression)) %>%\n ggplot(aes(n, median, color = Approach, group = Approach)) +\n geom_point() +\n geom_line() +\n labs(\n x = \"Vector length (millions)\",\n y = \"Median (s)\"\n ) +\n theme(legend.position = \"top\")" + }, + { + "objectID": "24_Improving_performance.html#references", + "href": "24_Improving_performance.html#references", + "title": "24 - Improving performance", + "section": "References", + "text": "References\n\n\n\n\nArdia, David, Kris Boudt, Peter Carl, Katharine M. Mullen, and Brian G. Peterson. 2011. “Differential Evolution with DEoptim: An Application to Non-Convex Portfolio Optimization.” R Journal 3 (1): 27–34. https://doi.org/10.32614/RJ-2011-005.\n\n\nBergé, Laurent. 2018. “Efficient Estimation of Maximum Likelihood Models with Multiple Fixed-Effects: The R Package FENmlm.” CREA Discussion Papers, no. 13.\n\n\nEddelbuettel, Dirk. 2020. Anytime: Anything to ’POSIXct’ or ’Date’ Converter. https://CRAN.R-project.org/package=anytime.\n\n\nGrolemund, Garrett, and Hadley Wickham. 2011. “Dates and Times Made Easy with lubridate.” Journal of Statistical Software 40 (3): 1–25. https://www.jstatsoft.org/v40/i03/.\n\n\nJames, David, and Kurt Hornik. 2020. Chron: Chronological Objects Which Can Handle Dates and Times. https://CRAN.R-project.org/package=chron.\n\n\nKuhn, Max. 2020. Modeldb: Fits Models Inside the Database. https://CRAN.R-project.org/package=modeldb.\n\n\nLumley, Thomas. 2020. Biglm: Bounded Memory Linear and Generalized Linear Models. https://CRAN.R-project.org/package=biglm.\n\n\nNash, John C. 2014. “On Best Practice Optimization Methods in R.” Journal of Statistical Software 60 (2): 1–14. http://www.jstatsoft.org/v60/i02/.\n\n\nNash, John C., and Ravi Varadhan. 2011. “Unifying Optimization Algorithms to Aid Software System Users: optimx for R.” Journal of Statistical Software 43 (9): 1–14. http://www.jstatsoft.org/v43/i09/.\n\n\nUrbanek, Simon. 2016. Fasttime: Fast Utility Function for Time Parsing and Conversion. https://CRAN.R-project.org/package=fasttime.\n\n\n———. 2017. Fastmatch: Fast Match() Function. https://CRAN.R-project.org/package=fastmatch." + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#prerequisites", + "href": "25_Rewriting_R_code_in_Cpp.html#prerequisites", + "title": "25 - Rewriting R code in C++", + "section": "Prerequisites", + "text": "Prerequisites\nOn our journey through R’s metaprogramming, we continue to use the functions from the {cpp11} (Vaughan, Hester, and François 2023) package.\n\nlibrary(cpp11)" + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#getting-started-with-c", + "href": "25_Rewriting_R_code_in_Cpp.html#getting-started-with-c", + "title": "25 - Rewriting R code in C++", + "section": "Getting started with C++", + "text": "Getting started with C++\nQ1: With the basics of C++ in hand, it’s now a great time to practice by reading and writing some simple C++ functions. For each of the following functions, read the code and figure out what the corresponding base R function is. You might not understand every part of the code yet, but you should be able to figure out the basics of what the function does.\nPay attention to the parts where we use writable::doubles instead of doubles, in C++ objects can be read-only, which is different from R (or Python).\nUnlike R, C++ indexes start at 0, not 1. This is a common source of bugs when porting code from R to C++.\ndouble f1_(doubles x) {\n int n = x.size();\n double y = 0;\n \n for(int i = 0; i < n; ++i) {\n y += x[i] / n;\n }\n return y;\n}\n\ndoubles f2_(doubles x) {\n int n = x.size();\n writable::doubles out(n);\n \n out[0] = x[0];\n for(int i = 1; i < n; ++i) {\n out[i] = out[i - 1] + x[i];\n }\n return out;\n}\n\nbool f3_(logicals x) {\n int n = x.size();\n \n for(int i = 0; i < n; ++i) {\n if (x[i]) return true;\n }\n return false;\n}\n\nint f4_(function pred, list x) {\n int n = x.size();\n \n for(int i = 0; i < n; ++i) {\n logicals res = pred(x[i]);\n if (res[0]) return i + 1;\n }\n return 0;\n}\n\ndoubles f5_(doubles x, doubles y) {\n int n = std::max(x.size(), y.size());\n vector<double> x1(n);\n vector<double> y1(n);\n\n for (int i = 0; i < n; ++i) {\n x1[i] = x[i % x.size()];\n y1[i] = y[i % y.size()];\n }\n\n writable::doubles out(n);\n\n for (int i = 0; i < n; ++i) {\n out[i] = std::min(x1[i], y1[i]);\n }\n\n return out;\n}\nA: The code above corresponds to the following base R functions:\n\nf1_: mean()\nf2_: cumsum()\nf3_: any()\nf4_: Position()\nf5_: pmin()\n\nQ2: To practice your function writing skills, convert the following functions into C++. For now, assume the inputs have no missing values.\n\nall().\ncumprod(), cummin(), cummax().\ndiff(). Start by assuming lag 1, and then generalise for lag n.\nrange().\nvar(). Read about the approaches you can take on Wikipedia. Whenever implementing a numerical algorithm, it’s always good to check what is already known about the problem.\n\nA: Let’s port these functions to C++.\n\nall()\nbool all_cpp_(logicals x) {\n int n = x.size();\n for(int i = 0; i < n; ++i) {\n if (x[i] == false) {\n return false;\n }\n }\n return true;\n}\ncumprod(), cummin(), cummax().\ndoubles cumprod_cpp_(doubles x) {\n int n = x.size();\n writable::doubles out(n);\n out[0] = x[0];\n for(int i = 1; i < n; ++i) {\n out[i] = out[i - 1] * x[i];\n }\n return out;\n}\n\ndoubles cummin_cpp_(doubles x) {\n int n = x.size();\n writable::doubles out(n);\n\n out[0] = x[0];\n for (int i = 1; i < n; ++i) {\n double x1 = out[i - 1];\n double x2 = x[i];\n out[i] = std::min(x1, x2);\n }\n\n return out;\n}\n\ndoubles cummax_cpp_(doubles x) {\n int n = x.size();\n writable::doubles out(n);\n\n out[0] = x[0];\n for (int i = 1; i < n; ++i) {\n double x1 = out[i - 1];\n double x2 = x[i];\n out[i] = std::max(x1, x2);\n }\n return out;\n}\ndiff() (Start by assuming lag 1, and then generalise for lag n.)\ndoubles diff_cpp_(doubles x) {\n int n = x.size();\n writable::doubles out(n - 1);\n\n for (int i = 1; i < n; i++) {\n out[i - 1] = x[i] - x[i - 1];\n }\n return out ;\n}\n\ndoubles diff_lag_cpp_(doubles x, int lag) {\n int n = x.size();\n\n if (lag >= n) stop(\"`lag` must be less than `length(x)`.\");\n\n writable::doubles out(n - lag);\n\n for (int i = lag; i < n; i++) {\n out[i - lag] = x[i] - x[i - lag];\n }\n return out;\n}\nrange()\ndoubles range_cpp_(doubles x) {\n double omin = x[0], omax = x[0];\n int n = x.size();\n\n if (n == 0) stop(\"`length(x)` must be greater than 0.\");\n\n for (int i = 1; i < n; i++) {\n omin = std::min(x[i], omin);\n omax = std::max(x[i], omax);\n }\n\n writable::doubles out(2);\n out[0] = omin;\n out[1] = omax;\n return out;\n}\nvar()\ndouble var_cpp_(doubles x) {\n int n = x.size();\n\n if (n < 2) {\n return NA_REAL;\n }\n\n double mx = 0;\n for (int i = 0; i < n; ++i) {\n mx += x[i] / n;\n }\n\n double out = 0;\n for (int i = 0; i < n; ++i) {\n out += pow(x[i] - mx, 2);\n }\n\n return out / (n - 1);\n}" + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#missing-values", + "href": "25_Rewriting_R_code_in_Cpp.html#missing-values", + "title": "25 - Rewriting R code in C++", + "section": "Missing values", + "text": "Missing values\nQ1: Rewrite any of the functions from the first exercise to deal with missing values. If na.rm is true, ignore the missing values. If na.rm is false, return a missing value if the input contains any missing values. Some good functions to practice with are min(), max(), range(), mean(), and var().\nA: For this exercise we start with min_cpp_() and extend it so it can deal with missing values. We introduce an na_rm argument to make min_cpp_() aware of NAs. In case x contains exclusively NA values min_cpp_() should return Inf for na_rm = TRUE. For the return values vector data types are used to avoid irregular type conversions.\nWe use expressions provided by #include <cpp11.hpp> to simplify the code:\n\nR_PosInf, which is pure C++ this would be std::numeric_limits<double>::infinity(); and requires #include <limits>.\nis_na(x[i]), which is the same as x[i] == NA_REAL.\n\n#include <cpp11.hpp>\n\nusing namespace cpp11;\n\n[[cpp11::register]] doubles min_cpp_(cpp11::doubles x, bool na_rm) {\n int n = x.size();\n writable::doubles out = {R_PosInf};\n\n if (na_rm) {\n for (int i = 0; i < n; ++i) {\n if (x[i] == NA_REAL) {\n continue;\n }\n if (x[i] < out[0]) {\n out[0] = x[i];\n }\n }\n } else {\n for (int i = 0; i < n; ++i) {\n if (is_na(x[i])) {\n out[0] = NA_REAL;\n return out;\n }\n if (x[i] < out[0]) {\n out[0] = x[i];\n }\n }\n }\n\n return out;\n}\n\ncpp_source(\"cpp/01_min.cpp\")\n\nx <- c(2:4, NA)\nmin(x, na.rm = FALSE)\n#> [1] NA\nmin_cpp_(as.double(x), FALSE)\n#> [1] NA\nmin(x, na.rm = TRUE)\n#> [1] 2\nmin_cpp_(as.double(x), TRUE)\n#> [1] 2\n\ny <- c(NA, NA)\nmin(y, na.rm = FALSE)\n#> [1] NA\nmin_cpp_(as.double(y), FALSE)\n#> [1] NA\nmin(y, na.rm = TRUE)\n#> Warning in min(y, na.rm = TRUE): no non-missing arguments to min; returning Inf\n#> [1] Inf\nmin_cpp_(as.double(y), TRUE)\n#> [1] Inf\n\nNote that we added explicit values and types for each parameter. This is necessary because cpp11 does not automatically cast integers (i.e., 2:4) to doubles and does not allow default parameters in the function. This is because R (and Python) automatically cast 1L to 1.0 depending on the context, which is not the case for C++. Run min_cpp_(c(2:4, NA), FALSE) and read the error message carefully.\nTo simplify things for the end user, you can provide a wrapper function that calls min_cpp_() with the correct types and default values.\n\nmin_cpp <- function(x, na_rm = FALSE) {\n if (!is.double(x)) {\n x <- as.double(x)\n }\n min_cpp_(x, na_rm)\n}\n\nmin_cpp(c(2:4, NA))\n#> [1] NA\n\nWe also extend any_cpp_() so it can deal with missing values. Please note that this (again) introduces some code duplication. This could be avoided by moving the check for missing values to the inner loop at the expense of a slight decrease of performance. Here we use logicals as return type. If we would use bool instead, the C++ NA_LOGICAL would be converted into R’s logical TRUE.\n#include <cpp11.hpp>\n\nusing namespace cpp11;\n\n[[cpp11::register]] logicals any_cpp_(logicals x, bool na_rm) {\n int n = x.size();\n writable::logicals out = {false};\n\n if (na_rm == false) {\n for (int i = 0; i < n; ++i) {\n if (is_na(x[i])) {\n out[0] = NA_LOGICAL;\n return out;\n } else {\n if (x[i]) {\n out[0] = true;\n }\n }\n }\n }\n\n if (na_rm) {\n for (int i = 0; i < n; ++i) {\n if (is_na(x[i])) {\n continue;\n }\n if (x[i]) {\n out[0] = true;\n return out;\n }\n }\n }\n\n return out;\n}\n\ncpp_source(\"cpp/02_any.cpp\")\n\nx <- c(NA, TRUE)\nany(x)\n#> [1] TRUE\nany_cpp_(x, F)\n#> [1] NA\nany_cpp_(x, T)\n#> [1] TRUE\n\nQ2: Rewrite cumsum() and diff() so they can handle missing values. Note that these functions have slightly more complicated behaviour.\nA: Our NA-aware cumsum_cpp_() function will return a vector of the same length as x. By default (na_rm = FALSE) all values following the first NA input value will be set to NA, because they depend on the unknown missing value. In case of na_rm = FALSE the NA values are treated like zeros.\n#include <cpp11.hpp>\n\nusing namespace cpp11;\n\n[[cpp11::register]] doubles cumsum_cpp_(doubles x, bool na_rm = false) {\n int n = x.size();\n\n writable::doubles out(n);\n out[0] = x[0];\n\n if (na_rm == true) {\n for (int i = 1; i < n; ++i) {\n double y1 = out[i - 1], y2 = x[i];\n if (ISNAN(y2)) {\n out[i] = y1;\n } else {\n if (ISNAN(y1)) {\n out[i] = y2;\n } else {\n out[i] = y1 + y2;\n }\n }\n }\n } else {\n for (int i = 1; i < n; ++i) {\n double y1 = out[i - 1], y2 = x[i];\n if (ISNAN(y2)) {\n out[i] = NA_REAL;\n } else {\n if (ISNAN(y1)) {\n out[i] = NA_REAL;\n } else {\n out[i] = y1 + y2;\n }\n }\n }\n }\n\n return out;\n}\n\ncpp_source(\"cpp/03_cumsum.cpp\")\n\nx <- c(1, NA, 2, 4)\ncumsum(x)\n#> [1] 1 NA NA NA\ncumsum_cpp_(c(1, NA, 2, 4), FALSE)\n#> [1] 1 NA NA NA\ncumsum_cpp_(c(1, NA, 2, 4), TRUE)\n#> [1] 1 1 3 7\n\nThis example works immediately, because the input vector is a vector of doubles. If we create a sequence of integers, we need to cast it as doubles.\n\ncumsum_cpp_(as.double(1:4), FALSE)\n#> [1] 1 3 6 10\n\n# or use a wrapper function\ncumsum_cpp <- function(x, na_rm = FALSE) {\n if (!is.double(x)) {\n x <- as.double(x)\n }\n cumsum_cpp_(x, na_rm)\n}\n\ncumsum_cpp(1:4, FALSE)\n#> [1] 1 3 6 10\n\nThe diff_cpp_() implementation will return an NA vector of length length(x) - lag, if the input vector contains a missing value. In case of na_rm = TRUE, the function will return an NA for every difference with at least one NA as input.\n#include <cpp11.hpp>\n\nusing namespace cpp11;\n\n[[cpp11::register]] doubles diff_cpp_(doubles x, int lag, bool na_rm) {\n int n = x.size();\n\n if (lag >= n) stop(\"`lag` must be less than `length(x)`.\");\n\n writable::doubles out(n - lag);\n\n for (int i = lag; i < n; i++) {\n if (is_na(x[i]) || is_na(x[i - lag])) {\n if (!na_rm) {\n writable::doubles out_na(n - lag);\n for (int j = 0; j < n - lag; ++j) {\n out_na[j] = NA_REAL;\n }\n return out_na;\n }\n out[i - lag] = NA_REAL;\n continue;\n }\n out[i - lag] = x[i] - x[i - lag];\n }\n\n return out;\n}\n\ncpp_source(\"cpp/04_diff.cpp\")\n\nx <- c(1, 3, NA, 10)\ndiff(x, 1L)\n#> [1] 2 NA NA\ndiff_cpp_(x, 1L, FALSE)\n#> [1] NA NA NA\ndiff_cpp_(x, 1L, TRUE)\n#> [1] 2 NA NA" + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#standard-template-library", + "href": "25_Rewriting_R_code_in_Cpp.html#standard-template-library", + "title": "25 - Rewriting R code in C++", + "section": "Standard Template Library", + "text": "Standard Template Library\nTo practice using the STL algorithms and data structures, implement the following using R functions in C++, using the hints provided:\nQ1: median.default() using partial_sort.\nA: The median is computed differently for even or odd vectors, which we allow for in the function below.\nTo be able to use partial_sort() we need to include the algorithm header. Unlike the previous examples, the input will be const doubles& x, meaning that the function takes a constant reference to an object of type doubles (i.e., the function will not modify the object x), and the & symbol means that the function takes a reference to the object instead of a copy of the object.\nThis can improve performance when the object is large, because it avoids copying the object, but in this case we did it to use the partial_sort() function, which is not compatible with doubles but it is with vector<double> types.\ndoubles is a data type we can send from R to C++ and vice-versa, but it is not compatible with all of C++ functions. vector<double> is a C++ data type that we cannot send to R. There are more details about this in the alternative solutions section at the end of the chapter.\n#include <algorithm>\n#include <cpp11.hpp>\n#include <vector>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] double median_cpp_(const doubles& x) {\n int n = x.size();\n\n vector<double> y(n);\n for (int i = 0; i < n; ++i) {\n y[i] = x[i];\n }\n\n if (n % 2 == 0) {\n partial_sort(y.begin(), y.begin() + n / 2 + 1, y.end());\n return (y[n / 2 - 1] + y[n / 2]) / 2;\n } else {\n partial_sort(y.begin(), y.begin() + (n + 1) / 2, y.end());\n return y[(n + 1) / 2 - 1];\n }\n}\n\ncpp_source(\"cpp/05_median.cpp\")\n\nx <- c(1, 2, 3)\nmedian(x)\n#> [1] 2\nmedian_cpp_(x)\n#> [1] 2\n\nQ2: %in% using unordered_set and the find() or count() methods.\nA: We use the find() method and loop through the unordered_set until we find a match or have scanned the entire set.\n#include <cpp11.hpp>\n#include <unordered_set>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] logicals in_cpp_(const strings& x, const strings& table) {\n unordered_set<string> seen;\n seen.insert(table.begin(), table.end());\n\n int n = x.size();\n writable::logicals out(n);\n for (int i = 0; i < n; ++i) {\n out[i] = seen.find(x[i]) != seen.end();\n }\n\n return out;\n}\n\ncpp_source(\"cpp/06_in.cpp\")\n\nx <- letters[1:3]\ny <- letters[1:2]\nin_cpp_(x, y)\n#> [1] TRUE TRUE FALSE\nx %in% y\n#> [1] TRUE TRUE FALSE\n\nQ3: unique() using an unordered_set (challenge: do it in one line!).\nA: The insert()-method will return if an equivalent element already exists. If a new element is inserted, we will add it to the (unique) return vector of our function.\nFirst we will implement the function in multiple lines, and then reduce.\n#include <cpp11.hpp>\n#include <unordered_set>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] doubles unique_cpp_(const doubles& x) {\n unordered_set<double> seen;\n int n = x.size();\n\n writable::doubles out;\n for (int i = 0; i < n; ++i) {\n if (seen.insert(x[i]).second) out.push_back(x[i]);\n }\n\n return out;\n}\nIn one line we would need to write a wrapper function in C++ to be able to export the result to R.\n#include <cpp11.hpp>\n#include <unordered_set>\n\nusing namespace cpp11;\nusing namespace std;\n\nunordered_set<double> unique_short1_cpp_(const doubles& x) {\n return unordered_set<double>(x.begin(), x.end());\n}\n\n[[cpp11::register]] doubles unique_short2_cpp_(const doubles& x) {\n unordered_set<double> y = unique_short1_cpp_(x);\n\n int n = y.size();\n writable::doubles out(n);\n copy(y.begin(), y.end(), out.begin());\n\n return out;\n}\n\ncpp_source(\"cpp/07_unique.cpp\")\ncpp_source(\"cpp/08_unique_short.cpp\")\n\nx <- c(1, 2, 2)\nunique(x)\n#> [1] 1 2\nunique_cpp_(x)\n#> [1] 1 2\nunique_short2_cpp_(x)\n#> [1] 2 1\n\nQ4: min() using std::min(), or max() using std::max().\nA: We will implement min() by iterating over the vector and recursively comparing each element to the current minimum value.\nIn this example, and unlike the previous min_cpp_(), we can assign x[i] from a doubles object to the left hand side that is a double variable without the need to convert data types.\n#include <cpp11.hpp>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] double min_cpp_(const doubles& x) {\n int n = x.size();\n double out = x[0];\n\n for (int i = 0; i < n; i++) {\n out = min(out, x[i]);\n }\n\n return out;\n}\n\ncpp_source(\"cpp/09_min.cpp\")\n\nx <- c(-1, 0, 1)\nmin(x)\n#> [1] -1\nmin_cpp_(x)\n#> [1] -1\n\nQ5: which.min() using min_element, or which.max() using max_element.\nA: To implement which.min(), we will first locate the min_element and then compute the distance() to it (starting from the beginning of the vector).\nCheck the +1 in the return statement, which was included because of zero indexes as it was mentioned in the beginning of the chapter.\n#include <algorithm>\n#include <cpp11.hpp>\n#include <iterator>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] double which_min_cpp_(const doubles& x) {\n int out = distance(x.begin(), min_element(x.begin(), x.end())\n );\n\n return out + 1;\n}\n\ncpp_source(\"cpp/10_which_min.cpp\")\n\nx <- c(1, -1)\nwhich.min(x)\n#> [1] 2\nwhich_min_cpp_(x)\n#> [1] 2\n\nQ6: setdiff(), union(), and intersect() for integers using sorted ranges and set_union, set_intersection and set_difference.\nA: The structure of the three functions will be very similar.\nWe first sort both input vectors. Then we apply the respective set_union, set_intersection or set_difference function. After that, the result will be between the iterators tmp.begin() and out_end. To retrieve the result, we loop once through the range between tmp.begin() and out_end in the last part of each function.\nThe set operations in base R will discard duplicated values in the arguments. We achieve a similar behaviour by introducing a deduplication step, which omits values that match their predecessor. For the C++ implementation we rely on the properties of the set operations and the fact that the input vectors are sorted.\nWe also use variables of type vector<int>::iterator, which are used to point to elements in a vector<int>.\n#include <algorithm>\n#include <cpp11.hpp>\n#include <unordered_set>\n#include <vector>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] integers union_cpp_(const integers& x, const integers& y) {\n vector<int> vx(x.begin(), x.end());\n vector<int> vy(y.begin(), y.end());\n\n sort(vx.begin(), vx.end());\n sort(vy.begin(), vy.end());\n\n vector<int> tmp(vx.size() + vy.size());\n\n vector<int>::iterator out_end =\n set_union(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());\n\n int prev_value = 0;\n writable::integers out;\n\n for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {\n if ((it != tmp.begin()) && (prev_value == *it)) continue;\n\n out.push_back(*it);\n\n prev_value = *it;\n }\n\n return out;\n}\n\n[[cpp11::register]] integers intersect_cpp_(const integers& x,\n const integers& y) {\n vector<int> vx(x.begin(), x.end());\n vector<int> vy(y.begin(), y.end());\n\n sort(vx.begin(), vx.end());\n sort(vy.begin(), vy.end());\n\n vector<int> tmp(min(vx.size(), vy.size()));\n\n vector<int>::iterator out_end =\n set_intersection(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());\n\n writable::integers out;\n\n for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {\n out.push_back(*it);\n }\n\n return out;\n}\n\n[[cpp11::register]] integers setdiff_cpp_(const integers& x,\n const integers& y) {\n vector<int> vx(x.begin(), x.end());\n vector<int> vy(y.begin(), y.end());\n\n sort(vx.begin(), vx.end());\n sort(vy.begin(), vy.end());\n\n vector<int> tmp(vx.size());\n\n vector<int>::iterator out_end =\n set_difference(vx.begin(), vx.end(), vy.begin(), vy.end(), tmp.begin());\n\n writable::integers out;\n\n for (vector<int>::iterator it = tmp.begin(); it != out_end; ++it) {\n out.push_back(*it);\n }\n\n return out;\n}\nLet’s verify, that these functions work as intended.\n\ncpp_source(\"cpp/11_set_operations.cpp\")\n\n# input vectors include duplicates\nx <- 1:3\ny <- 0:5\n\nunion(x, y)\n#> [1] 1 2 3 0 4 5\nunion_cpp_(x, y)\n#> [1] 0 1 2 3 4 5\n\nintersect(x, y)\n#> [1] 1 2 3\nintersect_cpp_(x, y)\n#> [1] 1 2 3\n\nx <- 1:3\ny <- 0:1\n\nsetdiff(x, y)\n#> [1] 2 3\nsetdiff_cpp_(x, y)\n#> [1] 2 3" + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#alternative-solutions", + "href": "25_Rewriting_R_code_in_Cpp.html#alternative-solutions", + "title": "25 - Rewriting R code in C++", + "section": "Alternative solutions", + "text": "Alternative solutions\n\nAll\nThe all_cpp_() function can be implemented at least in three more ways.\nI can save lines by not defining n.\nbool all_cpp_(logicals x) {\n for (int i = 0; i < x.size(); ++i) {\n if (x[i] == false) {\n return false;\n }\n }\n return true;\n}\nIt is also possible to directly define a logical variable i inside the loop.\nbool all_cpp_(logicals x) {\n for (bool i : x) {\n if (i == false) {\n return false;\n }\n }\n return true;\n}\nUsing std::all_of() you can do the same thing in one line.\nbool all_cpp_(logicals x) {\n return std::all_of(x.begin(), x.end(), [](bool x) { return x; });\n}\n\n\nPairwise minimum\nUnlike cumprod_cpp_(), cummin_cpp_() requires to declare additional double values, otherwise std::min() will not work.\nIt is possible to save some lines by using std::vector.\n#include <cpp11.hpp>\n#include <vector>\n\nusing namespace cpp11;\nusing namespace std;\n\n[[cpp11::register]] doubles pmin_cpp_(doubles x, doubles y) {\n int n = max(x.size(), y.size());\n\n vector<double> x1(n);\n vector<double> y1(n);\n for (int i = 0; i < n; ++i) {\n x1[i] = x[i % x.size()];\n y1[i] = y[i % y.size()];\n }\n\n writable::doubles out(n);\n\n for (int i = 0; i < n; ++i) {\n out[i] = min(x1[i], y1[i]);\n }\n\n return out;\n}\nWe can subset x1 and y1 when these are of class vector<double> instead of doubles because x1[i] and y1[i] are of class double. When x1 and y1 are of class doubles, x1[i] and y1[i] are proxy objects that represent elements of x1 and y1\nPassing proxies to std::min(), which returns a reference to its smallest argument, creates an output that is a new proxy object that cannot be assigned to out[i]." + }, + { + "objectID": "25_Rewriting_R_code_in_Cpp.html#references", + "href": "25_Rewriting_R_code_in_Cpp.html#references", + "title": "25 - Rewriting R code in C++", + "section": "References", + "text": "References\n\n\n\n\nVaughan, Davis, Jim Hester, and Romain François. 2023. Cpp11: A c++11 Interface for r’s c Interface. https://CRAN.R-project.org/package=cpp11." + } +] \ No newline at end of file diff --git a/docs/site_libs/bootstrap/bootstrap-icons.css b/docs/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 00000000..94f19404 --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,2018 @@ +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?2ab2cbbe07fcebb53bdaa7313bb290f2") format("woff"); +} + +.bi::before, +[class^="bi-"]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: bootstrap-icons !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { content: "\f67f"; } +.bi-alarm-fill::before { content: "\f101"; } +.bi-alarm::before { content: "\f102"; } +.bi-align-bottom::before { content: "\f103"; } +.bi-align-center::before { content: "\f104"; } +.bi-align-end::before { content: "\f105"; } +.bi-align-middle::before { content: "\f106"; } +.bi-align-start::before { content: "\f107"; } +.bi-align-top::before { content: "\f108"; } +.bi-alt::before { content: "\f109"; } +.bi-app-indicator::before { content: "\f10a"; } +.bi-app::before { content: "\f10b"; } +.bi-archive-fill::before { content: "\f10c"; } +.bi-archive::before { content: "\f10d"; } +.bi-arrow-90deg-down::before { content: "\f10e"; } +.bi-arrow-90deg-left::before { content: "\f10f"; } +.bi-arrow-90deg-right::before { content: "\f110"; } +.bi-arrow-90deg-up::before { content: "\f111"; } +.bi-arrow-bar-down::before { content: "\f112"; } +.bi-arrow-bar-left::before { content: "\f113"; } +.bi-arrow-bar-right::before { content: "\f114"; } +.bi-arrow-bar-up::before { content: "\f115"; } +.bi-arrow-clockwise::before { content: "\f116"; } +.bi-arrow-counterclockwise::before { content: "\f117"; } +.bi-arrow-down-circle-fill::before { content: "\f118"; } +.bi-arrow-down-circle::before { content: "\f119"; } +.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } +.bi-arrow-down-left-circle::before { content: "\f11b"; } +.bi-arrow-down-left-square-fill::before { content: "\f11c"; } +.bi-arrow-down-left-square::before { content: "\f11d"; } +.bi-arrow-down-left::before { content: "\f11e"; } +.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } +.bi-arrow-down-right-circle::before { content: "\f120"; } +.bi-arrow-down-right-square-fill::before { content: "\f121"; } +.bi-arrow-down-right-square::before { content: "\f122"; } +.bi-arrow-down-right::before { content: "\f123"; } +.bi-arrow-down-short::before { content: "\f124"; } +.bi-arrow-down-square-fill::before { content: "\f125"; } +.bi-arrow-down-square::before { content: "\f126"; } +.bi-arrow-down-up::before { content: "\f127"; } +.bi-arrow-down::before { content: "\f128"; } +.bi-arrow-left-circle-fill::before { content: "\f129"; } +.bi-arrow-left-circle::before { content: "\f12a"; } +.bi-arrow-left-right::before { content: "\f12b"; } +.bi-arrow-left-short::before { content: "\f12c"; } +.bi-arrow-left-square-fill::before { content: "\f12d"; } +.bi-arrow-left-square::before { content: "\f12e"; } +.bi-arrow-left::before { content: "\f12f"; } +.bi-arrow-repeat::before { content: "\f130"; } +.bi-arrow-return-left::before { content: "\f131"; } +.bi-arrow-return-right::before { content: "\f132"; } +.bi-arrow-right-circle-fill::before { content: "\f133"; } +.bi-arrow-right-circle::before { content: "\f134"; } +.bi-arrow-right-short::before { content: "\f135"; } +.bi-arrow-right-square-fill::before { content: "\f136"; } +.bi-arrow-right-square::before { content: "\f137"; } +.bi-arrow-right::before { content: "\f138"; } +.bi-arrow-up-circle-fill::before { content: "\f139"; } +.bi-arrow-up-circle::before { content: "\f13a"; } +.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } +.bi-arrow-up-left-circle::before { content: "\f13c"; } +.bi-arrow-up-left-square-fill::before { content: "\f13d"; } +.bi-arrow-up-left-square::before { content: "\f13e"; } +.bi-arrow-up-left::before { content: "\f13f"; } +.bi-arrow-up-right-circle-fill::before { content: "\f140"; } +.bi-arrow-up-right-circle::before { content: "\f141"; } +.bi-arrow-up-right-square-fill::before { content: "\f142"; } +.bi-arrow-up-right-square::before { content: "\f143"; } +.bi-arrow-up-right::before { content: "\f144"; } +.bi-arrow-up-short::before { content: "\f145"; } +.bi-arrow-up-square-fill::before { content: "\f146"; } +.bi-arrow-up-square::before { content: "\f147"; } +.bi-arrow-up::before { content: "\f148"; } +.bi-arrows-angle-contract::before { content: "\f149"; } +.bi-arrows-angle-expand::before { content: "\f14a"; } +.bi-arrows-collapse::before { content: "\f14b"; } +.bi-arrows-expand::before { content: "\f14c"; } +.bi-arrows-fullscreen::before { content: "\f14d"; } +.bi-arrows-move::before { content: "\f14e"; } +.bi-aspect-ratio-fill::before { content: "\f14f"; } +.bi-aspect-ratio::before { content: "\f150"; } +.bi-asterisk::before { content: "\f151"; } +.bi-at::before { content: "\f152"; } +.bi-award-fill::before { content: "\f153"; } +.bi-award::before { content: "\f154"; } +.bi-back::before { content: "\f155"; } +.bi-backspace-fill::before { content: "\f156"; } +.bi-backspace-reverse-fill::before { content: "\f157"; } +.bi-backspace-reverse::before { content: "\f158"; } +.bi-backspace::before { content: "\f159"; } +.bi-badge-3d-fill::before { content: "\f15a"; } +.bi-badge-3d::before { content: "\f15b"; } +.bi-badge-4k-fill::before { content: "\f15c"; } +.bi-badge-4k::before { content: "\f15d"; } +.bi-badge-8k-fill::before { content: "\f15e"; } +.bi-badge-8k::before { content: "\f15f"; } +.bi-badge-ad-fill::before { content: "\f160"; } +.bi-badge-ad::before { content: "\f161"; } +.bi-badge-ar-fill::before { content: "\f162"; } +.bi-badge-ar::before { content: "\f163"; } +.bi-badge-cc-fill::before { content: "\f164"; } +.bi-badge-cc::before { content: "\f165"; } +.bi-badge-hd-fill::before { content: "\f166"; } +.bi-badge-hd::before { content: "\f167"; } +.bi-badge-tm-fill::before { content: "\f168"; } +.bi-badge-tm::before { content: "\f169"; } +.bi-badge-vo-fill::before { content: "\f16a"; } +.bi-badge-vo::before { content: "\f16b"; } +.bi-badge-vr-fill::before { content: "\f16c"; } +.bi-badge-vr::before { content: "\f16d"; } +.bi-badge-wc-fill::before { content: "\f16e"; } +.bi-badge-wc::before { content: "\f16f"; } +.bi-bag-check-fill::before { content: "\f170"; } +.bi-bag-check::before { content: "\f171"; } +.bi-bag-dash-fill::before { content: "\f172"; } +.bi-bag-dash::before { content: "\f173"; } +.bi-bag-fill::before { content: "\f174"; } +.bi-bag-plus-fill::before { content: "\f175"; } +.bi-bag-plus::before { content: "\f176"; } +.bi-bag-x-fill::before { content: "\f177"; } +.bi-bag-x::before { content: "\f178"; } +.bi-bag::before { content: "\f179"; } +.bi-bar-chart-fill::before { content: "\f17a"; } +.bi-bar-chart-line-fill::before { content: "\f17b"; } +.bi-bar-chart-line::before { content: "\f17c"; } +.bi-bar-chart-steps::before { content: "\f17d"; } +.bi-bar-chart::before { content: "\f17e"; } +.bi-basket-fill::before { content: "\f17f"; } +.bi-basket::before { content: "\f180"; } +.bi-basket2-fill::before { content: "\f181"; } +.bi-basket2::before { content: "\f182"; } +.bi-basket3-fill::before { content: "\f183"; } +.bi-basket3::before { content: "\f184"; } +.bi-battery-charging::before { content: "\f185"; } +.bi-battery-full::before { content: "\f186"; } +.bi-battery-half::before { content: "\f187"; } +.bi-battery::before { content: "\f188"; } +.bi-bell-fill::before { content: "\f189"; } +.bi-bell::before { content: "\f18a"; } +.bi-bezier::before { content: "\f18b"; } +.bi-bezier2::before { content: "\f18c"; } +.bi-bicycle::before { content: "\f18d"; } +.bi-binoculars-fill::before { content: "\f18e"; } +.bi-binoculars::before { content: "\f18f"; } +.bi-blockquote-left::before { content: "\f190"; } +.bi-blockquote-right::before { content: "\f191"; } +.bi-book-fill::before { content: "\f192"; } +.bi-book-half::before { content: "\f193"; } +.bi-book::before { content: "\f194"; } +.bi-bookmark-check-fill::before { content: "\f195"; } +.bi-bookmark-check::before { content: "\f196"; } +.bi-bookmark-dash-fill::before { content: "\f197"; } +.bi-bookmark-dash::before { content: "\f198"; } +.bi-bookmark-fill::before { content: "\f199"; } +.bi-bookmark-heart-fill::before { content: "\f19a"; } +.bi-bookmark-heart::before { content: "\f19b"; } +.bi-bookmark-plus-fill::before { content: "\f19c"; } +.bi-bookmark-plus::before { content: "\f19d"; } +.bi-bookmark-star-fill::before { content: "\f19e"; } +.bi-bookmark-star::before { content: "\f19f"; } +.bi-bookmark-x-fill::before { content: "\f1a0"; } +.bi-bookmark-x::before { content: "\f1a1"; } +.bi-bookmark::before { content: "\f1a2"; } +.bi-bookmarks-fill::before { content: "\f1a3"; } +.bi-bookmarks::before { content: "\f1a4"; } +.bi-bookshelf::before { content: "\f1a5"; } +.bi-bootstrap-fill::before { content: "\f1a6"; } +.bi-bootstrap-reboot::before { content: "\f1a7"; } +.bi-bootstrap::before { content: "\f1a8"; } +.bi-border-all::before { content: "\f1a9"; } +.bi-border-bottom::before { content: "\f1aa"; } +.bi-border-center::before { content: "\f1ab"; } +.bi-border-inner::before { content: "\f1ac"; } +.bi-border-left::before { content: "\f1ad"; } +.bi-border-middle::before { content: "\f1ae"; } +.bi-border-outer::before { content: "\f1af"; } +.bi-border-right::before { content: "\f1b0"; } +.bi-border-style::before { content: "\f1b1"; } +.bi-border-top::before { content: "\f1b2"; } +.bi-border-width::before { content: "\f1b3"; } +.bi-border::before { content: "\f1b4"; } +.bi-bounding-box-circles::before { content: "\f1b5"; } +.bi-bounding-box::before { content: "\f1b6"; } +.bi-box-arrow-down-left::before { content: "\f1b7"; } +.bi-box-arrow-down-right::before { content: "\f1b8"; } +.bi-box-arrow-down::before { content: "\f1b9"; } +.bi-box-arrow-in-down-left::before { content: "\f1ba"; } +.bi-box-arrow-in-down-right::before { content: "\f1bb"; } +.bi-box-arrow-in-down::before { content: "\f1bc"; } +.bi-box-arrow-in-left::before { content: "\f1bd"; } +.bi-box-arrow-in-right::before { content: "\f1be"; } +.bi-box-arrow-in-up-left::before { content: "\f1bf"; } +.bi-box-arrow-in-up-right::before { content: "\f1c0"; } +.bi-box-arrow-in-up::before { content: "\f1c1"; } +.bi-box-arrow-left::before { content: "\f1c2"; } +.bi-box-arrow-right::before { content: "\f1c3"; } +.bi-box-arrow-up-left::before { content: "\f1c4"; } +.bi-box-arrow-up-right::before { content: "\f1c5"; } +.bi-box-arrow-up::before { content: "\f1c6"; } +.bi-box-seam::before { content: "\f1c7"; } +.bi-box::before { content: "\f1c8"; } +.bi-braces::before { content: "\f1c9"; } +.bi-bricks::before { content: "\f1ca"; } +.bi-briefcase-fill::before { content: "\f1cb"; } +.bi-briefcase::before { content: "\f1cc"; } +.bi-brightness-alt-high-fill::before { content: "\f1cd"; } +.bi-brightness-alt-high::before { content: "\f1ce"; } +.bi-brightness-alt-low-fill::before { content: "\f1cf"; } +.bi-brightness-alt-low::before { content: "\f1d0"; } +.bi-brightness-high-fill::before { content: "\f1d1"; } +.bi-brightness-high::before { content: "\f1d2"; } +.bi-brightness-low-fill::before { content: "\f1d3"; } +.bi-brightness-low::before { content: "\f1d4"; } +.bi-broadcast-pin::before { content: "\f1d5"; } +.bi-broadcast::before { content: "\f1d6"; } +.bi-brush-fill::before { content: "\f1d7"; } +.bi-brush::before { content: "\f1d8"; } +.bi-bucket-fill::before { content: "\f1d9"; } +.bi-bucket::before { content: "\f1da"; } +.bi-bug-fill::before { content: "\f1db"; } +.bi-bug::before { content: "\f1dc"; } +.bi-building::before { content: "\f1dd"; } +.bi-bullseye::before { content: "\f1de"; } +.bi-calculator-fill::before { content: "\f1df"; } +.bi-calculator::before { content: "\f1e0"; } +.bi-calendar-check-fill::before { content: "\f1e1"; } +.bi-calendar-check::before { content: "\f1e2"; } +.bi-calendar-date-fill::before { content: "\f1e3"; } +.bi-calendar-date::before { content: "\f1e4"; } +.bi-calendar-day-fill::before { content: "\f1e5"; } +.bi-calendar-day::before { content: "\f1e6"; } +.bi-calendar-event-fill::before { content: "\f1e7"; } +.bi-calendar-event::before { content: "\f1e8"; } +.bi-calendar-fill::before { content: "\f1e9"; } +.bi-calendar-minus-fill::before { content: "\f1ea"; } +.bi-calendar-minus::before { content: "\f1eb"; } +.bi-calendar-month-fill::before { content: "\f1ec"; } +.bi-calendar-month::before { content: "\f1ed"; } +.bi-calendar-plus-fill::before { content: "\f1ee"; } +.bi-calendar-plus::before { content: "\f1ef"; } +.bi-calendar-range-fill::before { content: "\f1f0"; } +.bi-calendar-range::before { content: "\f1f1"; } +.bi-calendar-week-fill::before { content: "\f1f2"; } +.bi-calendar-week::before { content: "\f1f3"; } +.bi-calendar-x-fill::before { content: "\f1f4"; } +.bi-calendar-x::before { content: "\f1f5"; } +.bi-calendar::before { content: "\f1f6"; } +.bi-calendar2-check-fill::before { content: "\f1f7"; } +.bi-calendar2-check::before { content: "\f1f8"; } +.bi-calendar2-date-fill::before { content: "\f1f9"; } +.bi-calendar2-date::before { content: "\f1fa"; } +.bi-calendar2-day-fill::before { content: "\f1fb"; } +.bi-calendar2-day::before { content: "\f1fc"; } +.bi-calendar2-event-fill::before { content: "\f1fd"; } +.bi-calendar2-event::before { content: "\f1fe"; } +.bi-calendar2-fill::before { content: "\f1ff"; } +.bi-calendar2-minus-fill::before { content: "\f200"; } +.bi-calendar2-minus::before { content: "\f201"; } +.bi-calendar2-month-fill::before { content: "\f202"; } +.bi-calendar2-month::before { content: "\f203"; } +.bi-calendar2-plus-fill::before { content: "\f204"; } +.bi-calendar2-plus::before { content: "\f205"; } +.bi-calendar2-range-fill::before { content: "\f206"; } +.bi-calendar2-range::before { content: "\f207"; } +.bi-calendar2-week-fill::before { content: "\f208"; } +.bi-calendar2-week::before { content: "\f209"; } +.bi-calendar2-x-fill::before { content: "\f20a"; } +.bi-calendar2-x::before { content: "\f20b"; } +.bi-calendar2::before { content: "\f20c"; } +.bi-calendar3-event-fill::before { content: "\f20d"; } +.bi-calendar3-event::before { content: "\f20e"; } +.bi-calendar3-fill::before { content: "\f20f"; } +.bi-calendar3-range-fill::before { content: "\f210"; } +.bi-calendar3-range::before { content: "\f211"; } +.bi-calendar3-week-fill::before { content: "\f212"; } +.bi-calendar3-week::before { content: "\f213"; } +.bi-calendar3::before { content: "\f214"; } +.bi-calendar4-event::before { content: "\f215"; } +.bi-calendar4-range::before { content: "\f216"; } +.bi-calendar4-week::before { content: "\f217"; } +.bi-calendar4::before { content: "\f218"; } +.bi-camera-fill::before { content: "\f219"; } +.bi-camera-reels-fill::before { content: "\f21a"; } +.bi-camera-reels::before { content: "\f21b"; } +.bi-camera-video-fill::before { content: "\f21c"; } +.bi-camera-video-off-fill::before { content: "\f21d"; } +.bi-camera-video-off::before { content: "\f21e"; } +.bi-camera-video::before { content: "\f21f"; } +.bi-camera::before { content: "\f220"; } +.bi-camera2::before { content: "\f221"; } +.bi-capslock-fill::before { content: "\f222"; } +.bi-capslock::before { content: "\f223"; } +.bi-card-checklist::before { content: "\f224"; } +.bi-card-heading::before { content: "\f225"; } +.bi-card-image::before { content: "\f226"; } +.bi-card-list::before { content: "\f227"; } +.bi-card-text::before { content: "\f228"; } +.bi-caret-down-fill::before { content: "\f229"; } +.bi-caret-down-square-fill::before { content: "\f22a"; } +.bi-caret-down-square::before { content: "\f22b"; } +.bi-caret-down::before { content: "\f22c"; } +.bi-caret-left-fill::before { content: "\f22d"; } +.bi-caret-left-square-fill::before { content: "\f22e"; } +.bi-caret-left-square::before { content: "\f22f"; } +.bi-caret-left::before { content: "\f230"; } +.bi-caret-right-fill::before { content: "\f231"; } +.bi-caret-right-square-fill::before { content: "\f232"; } +.bi-caret-right-square::before { content: "\f233"; } +.bi-caret-right::before { content: "\f234"; } +.bi-caret-up-fill::before { content: "\f235"; } +.bi-caret-up-square-fill::before { content: "\f236"; } +.bi-caret-up-square::before { content: "\f237"; } +.bi-caret-up::before { content: "\f238"; } +.bi-cart-check-fill::before { content: "\f239"; } +.bi-cart-check::before { content: "\f23a"; } +.bi-cart-dash-fill::before { content: "\f23b"; } +.bi-cart-dash::before { content: "\f23c"; } +.bi-cart-fill::before { content: "\f23d"; } +.bi-cart-plus-fill::before { content: "\f23e"; } +.bi-cart-plus::before { content: "\f23f"; } +.bi-cart-x-fill::before { content: "\f240"; } +.bi-cart-x::before { content: "\f241"; } +.bi-cart::before { content: "\f242"; } +.bi-cart2::before { content: "\f243"; } +.bi-cart3::before { content: "\f244"; } +.bi-cart4::before { content: "\f245"; } +.bi-cash-stack::before { content: "\f246"; } +.bi-cash::before { content: "\f247"; } +.bi-cast::before { content: "\f248"; } +.bi-chat-dots-fill::before { content: "\f249"; } +.bi-chat-dots::before { content: "\f24a"; } +.bi-chat-fill::before { content: "\f24b"; } +.bi-chat-left-dots-fill::before { content: "\f24c"; } +.bi-chat-left-dots::before { content: "\f24d"; } +.bi-chat-left-fill::before { content: "\f24e"; } +.bi-chat-left-quote-fill::before { content: "\f24f"; } +.bi-chat-left-quote::before { content: "\f250"; } +.bi-chat-left-text-fill::before { content: "\f251"; } +.bi-chat-left-text::before { content: "\f252"; } +.bi-chat-left::before { content: "\f253"; } +.bi-chat-quote-fill::before { content: "\f254"; } +.bi-chat-quote::before { content: "\f255"; } +.bi-chat-right-dots-fill::before { content: "\f256"; } +.bi-chat-right-dots::before { content: "\f257"; } +.bi-chat-right-fill::before { content: "\f258"; } +.bi-chat-right-quote-fill::before { content: "\f259"; } +.bi-chat-right-quote::before { content: "\f25a"; } +.bi-chat-right-text-fill::before { content: "\f25b"; } +.bi-chat-right-text::before { content: "\f25c"; } +.bi-chat-right::before { content: "\f25d"; } +.bi-chat-square-dots-fill::before { content: "\f25e"; } +.bi-chat-square-dots::before { content: "\f25f"; } +.bi-chat-square-fill::before { content: "\f260"; } +.bi-chat-square-quote-fill::before { content: "\f261"; } +.bi-chat-square-quote::before { content: "\f262"; } +.bi-chat-square-text-fill::before { content: "\f263"; } +.bi-chat-square-text::before { content: "\f264"; } +.bi-chat-square::before { content: "\f265"; } +.bi-chat-text-fill::before { content: "\f266"; } +.bi-chat-text::before { content: "\f267"; } +.bi-chat::before { content: "\f268"; } +.bi-check-all::before { content: "\f269"; } +.bi-check-circle-fill::before { content: "\f26a"; } +.bi-check-circle::before { content: "\f26b"; } +.bi-check-square-fill::before { content: "\f26c"; } +.bi-check-square::before { content: "\f26d"; } +.bi-check::before { content: "\f26e"; } +.bi-check2-all::before { content: "\f26f"; } +.bi-check2-circle::before { content: "\f270"; } +.bi-check2-square::before { content: "\f271"; } +.bi-check2::before { content: "\f272"; } +.bi-chevron-bar-contract::before { content: "\f273"; } +.bi-chevron-bar-down::before { content: "\f274"; } +.bi-chevron-bar-expand::before { content: "\f275"; } +.bi-chevron-bar-left::before { content: "\f276"; } +.bi-chevron-bar-right::before { content: "\f277"; } +.bi-chevron-bar-up::before { content: "\f278"; } +.bi-chevron-compact-down::before { content: "\f279"; } +.bi-chevron-compact-left::before { content: "\f27a"; } +.bi-chevron-compact-right::before { content: "\f27b"; } +.bi-chevron-compact-up::before { content: "\f27c"; } +.bi-chevron-contract::before { content: "\f27d"; } +.bi-chevron-double-down::before { content: "\f27e"; } +.bi-chevron-double-left::before { content: "\f27f"; } +.bi-chevron-double-right::before { content: "\f280"; } +.bi-chevron-double-up::before { content: "\f281"; } +.bi-chevron-down::before { content: "\f282"; } +.bi-chevron-expand::before { content: "\f283"; } +.bi-chevron-left::before { content: "\f284"; } +.bi-chevron-right::before { content: "\f285"; } +.bi-chevron-up::before { content: "\f286"; } +.bi-circle-fill::before { content: "\f287"; } +.bi-circle-half::before { content: "\f288"; } +.bi-circle-square::before { content: "\f289"; } +.bi-circle::before { content: "\f28a"; } +.bi-clipboard-check::before { content: "\f28b"; } +.bi-clipboard-data::before { content: "\f28c"; } +.bi-clipboard-minus::before { content: "\f28d"; } +.bi-clipboard-plus::before { content: "\f28e"; } +.bi-clipboard-x::before { content: "\f28f"; } +.bi-clipboard::before { content: "\f290"; } +.bi-clock-fill::before { content: "\f291"; } +.bi-clock-history::before { content: "\f292"; } +.bi-clock::before { content: "\f293"; } +.bi-cloud-arrow-down-fill::before { content: "\f294"; } +.bi-cloud-arrow-down::before { content: "\f295"; } +.bi-cloud-arrow-up-fill::before { content: "\f296"; } +.bi-cloud-arrow-up::before { content: "\f297"; } +.bi-cloud-check-fill::before { content: "\f298"; } +.bi-cloud-check::before { content: "\f299"; } +.bi-cloud-download-fill::before { content: "\f29a"; } +.bi-cloud-download::before { content: "\f29b"; } +.bi-cloud-drizzle-fill::before { content: "\f29c"; } +.bi-cloud-drizzle::before { content: "\f29d"; } +.bi-cloud-fill::before { content: "\f29e"; } +.bi-cloud-fog-fill::before { content: "\f29f"; } +.bi-cloud-fog::before { content: "\f2a0"; } +.bi-cloud-fog2-fill::before { content: "\f2a1"; } +.bi-cloud-fog2::before { content: "\f2a2"; } +.bi-cloud-hail-fill::before { content: "\f2a3"; } +.bi-cloud-hail::before { content: "\f2a4"; } +.bi-cloud-haze-1::before { content: "\f2a5"; } +.bi-cloud-haze-fill::before { content: "\f2a6"; } +.bi-cloud-haze::before { content: "\f2a7"; } +.bi-cloud-haze2-fill::before { content: "\f2a8"; } +.bi-cloud-lightning-fill::before { content: "\f2a9"; } +.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } +.bi-cloud-lightning-rain::before { content: "\f2ab"; } +.bi-cloud-lightning::before { content: "\f2ac"; } +.bi-cloud-minus-fill::before { content: "\f2ad"; } +.bi-cloud-minus::before { content: "\f2ae"; } +.bi-cloud-moon-fill::before { content: "\f2af"; } +.bi-cloud-moon::before { content: "\f2b0"; } +.bi-cloud-plus-fill::before { content: "\f2b1"; } +.bi-cloud-plus::before { content: "\f2b2"; } +.bi-cloud-rain-fill::before { content: "\f2b3"; } +.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } +.bi-cloud-rain-heavy::before { content: "\f2b5"; } +.bi-cloud-rain::before { content: "\f2b6"; } +.bi-cloud-slash-fill::before { content: "\f2b7"; } +.bi-cloud-slash::before { content: "\f2b8"; } +.bi-cloud-sleet-fill::before { content: "\f2b9"; } +.bi-cloud-sleet::before { content: "\f2ba"; } +.bi-cloud-snow-fill::before { content: "\f2bb"; } +.bi-cloud-snow::before { content: "\f2bc"; } +.bi-cloud-sun-fill::before { content: "\f2bd"; } +.bi-cloud-sun::before { content: "\f2be"; } +.bi-cloud-upload-fill::before { content: "\f2bf"; } +.bi-cloud-upload::before { content: "\f2c0"; } +.bi-cloud::before { content: "\f2c1"; } +.bi-clouds-fill::before { content: "\f2c2"; } +.bi-clouds::before { content: "\f2c3"; } +.bi-cloudy-fill::before { content: "\f2c4"; } +.bi-cloudy::before { content: "\f2c5"; } +.bi-code-slash::before { content: "\f2c6"; } +.bi-code-square::before { content: "\f2c7"; } +.bi-code::before { content: "\f2c8"; } +.bi-collection-fill::before { content: "\f2c9"; } +.bi-collection-play-fill::before { content: "\f2ca"; } +.bi-collection-play::before { content: "\f2cb"; } +.bi-collection::before { content: "\f2cc"; } +.bi-columns-gap::before { content: "\f2cd"; } +.bi-columns::before { content: "\f2ce"; } +.bi-command::before { content: "\f2cf"; } +.bi-compass-fill::before { content: "\f2d0"; } +.bi-compass::before { content: "\f2d1"; } +.bi-cone-striped::before { content: "\f2d2"; } +.bi-cone::before { content: "\f2d3"; } +.bi-controller::before { content: "\f2d4"; } +.bi-cpu-fill::before { content: "\f2d5"; } +.bi-cpu::before { content: "\f2d6"; } +.bi-credit-card-2-back-fill::before { content: "\f2d7"; } +.bi-credit-card-2-back::before { content: "\f2d8"; } +.bi-credit-card-2-front-fill::before { content: "\f2d9"; } +.bi-credit-card-2-front::before { content: "\f2da"; } +.bi-credit-card-fill::before { content: "\f2db"; } +.bi-credit-card::before { content: "\f2dc"; } +.bi-crop::before { content: "\f2dd"; } +.bi-cup-fill::before { content: "\f2de"; } +.bi-cup-straw::before { content: "\f2df"; } +.bi-cup::before { content: "\f2e0"; } +.bi-cursor-fill::before { content: "\f2e1"; } +.bi-cursor-text::before { content: "\f2e2"; } +.bi-cursor::before { content: "\f2e3"; } +.bi-dash-circle-dotted::before { content: "\f2e4"; } +.bi-dash-circle-fill::before { content: "\f2e5"; } +.bi-dash-circle::before { content: "\f2e6"; } +.bi-dash-square-dotted::before { content: "\f2e7"; } +.bi-dash-square-fill::before { content: "\f2e8"; } +.bi-dash-square::before { content: "\f2e9"; } +.bi-dash::before { content: "\f2ea"; } +.bi-diagram-2-fill::before { content: "\f2eb"; } +.bi-diagram-2::before { content: "\f2ec"; } +.bi-diagram-3-fill::before { content: "\f2ed"; } +.bi-diagram-3::before { content: "\f2ee"; } +.bi-diamond-fill::before { content: "\f2ef"; } +.bi-diamond-half::before { content: "\f2f0"; } +.bi-diamond::before { content: "\f2f1"; } +.bi-dice-1-fill::before { content: "\f2f2"; } +.bi-dice-1::before { content: "\f2f3"; } +.bi-dice-2-fill::before { content: "\f2f4"; } +.bi-dice-2::before { content: "\f2f5"; } +.bi-dice-3-fill::before { content: "\f2f6"; } +.bi-dice-3::before { content: "\f2f7"; } +.bi-dice-4-fill::before { content: "\f2f8"; } +.bi-dice-4::before { content: "\f2f9"; } +.bi-dice-5-fill::before { content: "\f2fa"; } +.bi-dice-5::before { content: "\f2fb"; } +.bi-dice-6-fill::before { content: "\f2fc"; } +.bi-dice-6::before { content: "\f2fd"; } +.bi-disc-fill::before { content: "\f2fe"; } +.bi-disc::before { content: "\f2ff"; } +.bi-discord::before { content: "\f300"; } +.bi-display-fill::before { content: "\f301"; } +.bi-display::before { content: "\f302"; } +.bi-distribute-horizontal::before { content: "\f303"; } +.bi-distribute-vertical::before { content: "\f304"; } +.bi-door-closed-fill::before { content: "\f305"; } +.bi-door-closed::before { content: "\f306"; } +.bi-door-open-fill::before { content: "\f307"; } +.bi-door-open::before { content: "\f308"; } +.bi-dot::before { content: "\f309"; } +.bi-download::before { content: "\f30a"; } +.bi-droplet-fill::before { content: "\f30b"; } +.bi-droplet-half::before { content: "\f30c"; } +.bi-droplet::before { content: "\f30d"; } +.bi-earbuds::before { content: "\f30e"; } +.bi-easel-fill::before { content: "\f30f"; } +.bi-easel::before { content: "\f310"; } +.bi-egg-fill::before { content: "\f311"; } +.bi-egg-fried::before { content: "\f312"; } +.bi-egg::before { content: "\f313"; } +.bi-eject-fill::before { content: "\f314"; } +.bi-eject::before { content: "\f315"; } +.bi-emoji-angry-fill::before { content: "\f316"; } +.bi-emoji-angry::before { content: "\f317"; } +.bi-emoji-dizzy-fill::before { content: "\f318"; } +.bi-emoji-dizzy::before { content: "\f319"; } +.bi-emoji-expressionless-fill::before { content: "\f31a"; } +.bi-emoji-expressionless::before { content: "\f31b"; } +.bi-emoji-frown-fill::before { content: "\f31c"; } +.bi-emoji-frown::before { content: "\f31d"; } +.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } +.bi-emoji-heart-eyes::before { content: "\f31f"; } +.bi-emoji-laughing-fill::before { content: "\f320"; } +.bi-emoji-laughing::before { content: "\f321"; } +.bi-emoji-neutral-fill::before { content: "\f322"; } +.bi-emoji-neutral::before { content: "\f323"; } +.bi-emoji-smile-fill::before { content: "\f324"; } +.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } +.bi-emoji-smile-upside-down::before { content: "\f326"; } +.bi-emoji-smile::before { content: "\f327"; } +.bi-emoji-sunglasses-fill::before { content: "\f328"; } +.bi-emoji-sunglasses::before { content: "\f329"; } +.bi-emoji-wink-fill::before { content: "\f32a"; } +.bi-emoji-wink::before { content: "\f32b"; } +.bi-envelope-fill::before { content: "\f32c"; } +.bi-envelope-open-fill::before { content: "\f32d"; } +.bi-envelope-open::before { content: "\f32e"; } +.bi-envelope::before { content: "\f32f"; } +.bi-eraser-fill::before { content: "\f330"; } +.bi-eraser::before { content: "\f331"; } +.bi-exclamation-circle-fill::before { content: "\f332"; } +.bi-exclamation-circle::before { content: "\f333"; } +.bi-exclamation-diamond-fill::before { content: "\f334"; } +.bi-exclamation-diamond::before { content: "\f335"; } +.bi-exclamation-octagon-fill::before { content: "\f336"; } +.bi-exclamation-octagon::before { content: "\f337"; } +.bi-exclamation-square-fill::before { content: "\f338"; } +.bi-exclamation-square::before { content: "\f339"; } +.bi-exclamation-triangle-fill::before { content: "\f33a"; } +.bi-exclamation-triangle::before { content: "\f33b"; } +.bi-exclamation::before { content: "\f33c"; } +.bi-exclude::before { content: "\f33d"; } +.bi-eye-fill::before { content: "\f33e"; } +.bi-eye-slash-fill::before { content: "\f33f"; } +.bi-eye-slash::before { content: "\f340"; } +.bi-eye::before { content: "\f341"; } +.bi-eyedropper::before { content: "\f342"; } +.bi-eyeglasses::before { content: "\f343"; } +.bi-facebook::before { content: "\f344"; } +.bi-file-arrow-down-fill::before { content: "\f345"; } +.bi-file-arrow-down::before { content: "\f346"; } +.bi-file-arrow-up-fill::before { content: "\f347"; } +.bi-file-arrow-up::before { content: "\f348"; } +.bi-file-bar-graph-fill::before { content: "\f349"; } +.bi-file-bar-graph::before { content: "\f34a"; } +.bi-file-binary-fill::before { content: "\f34b"; } +.bi-file-binary::before { content: "\f34c"; } +.bi-file-break-fill::before { content: "\f34d"; } +.bi-file-break::before { content: "\f34e"; } +.bi-file-check-fill::before { content: "\f34f"; } +.bi-file-check::before { content: "\f350"; } +.bi-file-code-fill::before { content: "\f351"; } +.bi-file-code::before { content: "\f352"; } +.bi-file-diff-fill::before { content: "\f353"; } +.bi-file-diff::before { content: "\f354"; } +.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } +.bi-file-earmark-arrow-down::before { content: "\f356"; } +.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } +.bi-file-earmark-arrow-up::before { content: "\f358"; } +.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } +.bi-file-earmark-bar-graph::before { content: "\f35a"; } +.bi-file-earmark-binary-fill::before { content: "\f35b"; } +.bi-file-earmark-binary::before { content: "\f35c"; } +.bi-file-earmark-break-fill::before { content: "\f35d"; } +.bi-file-earmark-break::before { content: "\f35e"; } +.bi-file-earmark-check-fill::before { content: "\f35f"; } +.bi-file-earmark-check::before { content: "\f360"; } +.bi-file-earmark-code-fill::before { content: "\f361"; } +.bi-file-earmark-code::before { content: "\f362"; } +.bi-file-earmark-diff-fill::before { content: "\f363"; } +.bi-file-earmark-diff::before { content: "\f364"; } +.bi-file-earmark-easel-fill::before { content: "\f365"; } +.bi-file-earmark-easel::before { content: "\f366"; } +.bi-file-earmark-excel-fill::before { content: "\f367"; } +.bi-file-earmark-excel::before { content: "\f368"; } +.bi-file-earmark-fill::before { content: "\f369"; } +.bi-file-earmark-font-fill::before { content: "\f36a"; } +.bi-file-earmark-font::before { content: "\f36b"; } +.bi-file-earmark-image-fill::before { content: "\f36c"; } +.bi-file-earmark-image::before { content: "\f36d"; } +.bi-file-earmark-lock-fill::before { content: "\f36e"; } +.bi-file-earmark-lock::before { content: "\f36f"; } +.bi-file-earmark-lock2-fill::before { content: "\f370"; } +.bi-file-earmark-lock2::before { content: "\f371"; } +.bi-file-earmark-medical-fill::before { content: "\f372"; } +.bi-file-earmark-medical::before { content: "\f373"; } +.bi-file-earmark-minus-fill::before { content: "\f374"; } +.bi-file-earmark-minus::before { content: "\f375"; } +.bi-file-earmark-music-fill::before { content: "\f376"; } +.bi-file-earmark-music::before { content: "\f377"; } +.bi-file-earmark-person-fill::before { content: "\f378"; } +.bi-file-earmark-person::before { content: "\f379"; } +.bi-file-earmark-play-fill::before { content: "\f37a"; } +.bi-file-earmark-play::before { content: "\f37b"; } +.bi-file-earmark-plus-fill::before { content: "\f37c"; } +.bi-file-earmark-plus::before { content: "\f37d"; } +.bi-file-earmark-post-fill::before { content: "\f37e"; } +.bi-file-earmark-post::before { content: "\f37f"; } +.bi-file-earmark-ppt-fill::before { content: "\f380"; } +.bi-file-earmark-ppt::before { content: "\f381"; } +.bi-file-earmark-richtext-fill::before { content: "\f382"; } +.bi-file-earmark-richtext::before { content: "\f383"; } +.bi-file-earmark-ruled-fill::before { content: "\f384"; } +.bi-file-earmark-ruled::before { content: "\f385"; } +.bi-file-earmark-slides-fill::before { content: "\f386"; } +.bi-file-earmark-slides::before { content: "\f387"; } +.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } +.bi-file-earmark-spreadsheet::before { content: "\f389"; } +.bi-file-earmark-text-fill::before { content: "\f38a"; } +.bi-file-earmark-text::before { content: "\f38b"; } +.bi-file-earmark-word-fill::before { content: "\f38c"; } +.bi-file-earmark-word::before { content: "\f38d"; } +.bi-file-earmark-x-fill::before { content: "\f38e"; } +.bi-file-earmark-x::before { content: "\f38f"; } +.bi-file-earmark-zip-fill::before { content: "\f390"; } +.bi-file-earmark-zip::before { content: "\f391"; } +.bi-file-earmark::before { content: "\f392"; } +.bi-file-easel-fill::before { content: "\f393"; } +.bi-file-easel::before { content: "\f394"; } +.bi-file-excel-fill::before { content: "\f395"; } +.bi-file-excel::before { content: "\f396"; } +.bi-file-fill::before { content: "\f397"; } +.bi-file-font-fill::before { content: "\f398"; } +.bi-file-font::before { content: "\f399"; } +.bi-file-image-fill::before { content: "\f39a"; } +.bi-file-image::before { content: "\f39b"; } +.bi-file-lock-fill::before { content: "\f39c"; } +.bi-file-lock::before { content: "\f39d"; } +.bi-file-lock2-fill::before { content: "\f39e"; } +.bi-file-lock2::before { content: "\f39f"; } +.bi-file-medical-fill::before { content: "\f3a0"; } +.bi-file-medical::before { content: "\f3a1"; } +.bi-file-minus-fill::before { content: "\f3a2"; } +.bi-file-minus::before { content: "\f3a3"; } +.bi-file-music-fill::before { content: "\f3a4"; } +.bi-file-music::before { content: "\f3a5"; } +.bi-file-person-fill::before { content: "\f3a6"; } +.bi-file-person::before { content: "\f3a7"; } +.bi-file-play-fill::before { content: "\f3a8"; } +.bi-file-play::before { content: "\f3a9"; } +.bi-file-plus-fill::before { content: "\f3aa"; } +.bi-file-plus::before { content: "\f3ab"; } +.bi-file-post-fill::before { content: "\f3ac"; } +.bi-file-post::before { content: "\f3ad"; } +.bi-file-ppt-fill::before { content: "\f3ae"; } +.bi-file-ppt::before { content: "\f3af"; } +.bi-file-richtext-fill::before { content: "\f3b0"; } +.bi-file-richtext::before { content: "\f3b1"; } +.bi-file-ruled-fill::before { content: "\f3b2"; } +.bi-file-ruled::before { content: "\f3b3"; } +.bi-file-slides-fill::before { content: "\f3b4"; } +.bi-file-slides::before { content: "\f3b5"; } +.bi-file-spreadsheet-fill::before { content: "\f3b6"; } +.bi-file-spreadsheet::before { content: "\f3b7"; } +.bi-file-text-fill::before { content: "\f3b8"; } +.bi-file-text::before { content: "\f3b9"; } +.bi-file-word-fill::before { content: "\f3ba"; } +.bi-file-word::before { content: "\f3bb"; } +.bi-file-x-fill::before { content: "\f3bc"; } +.bi-file-x::before { content: "\f3bd"; } +.bi-file-zip-fill::before { content: "\f3be"; } +.bi-file-zip::before { content: "\f3bf"; } +.bi-file::before { content: "\f3c0"; } +.bi-files-alt::before { content: "\f3c1"; } +.bi-files::before { content: "\f3c2"; } +.bi-film::before { content: "\f3c3"; } +.bi-filter-circle-fill::before { content: "\f3c4"; } +.bi-filter-circle::before { content: "\f3c5"; } +.bi-filter-left::before { content: "\f3c6"; } +.bi-filter-right::before { content: "\f3c7"; } +.bi-filter-square-fill::before { content: "\f3c8"; } +.bi-filter-square::before { content: "\f3c9"; } +.bi-filter::before { content: "\f3ca"; } +.bi-flag-fill::before { content: "\f3cb"; } +.bi-flag::before { content: "\f3cc"; } +.bi-flower1::before { content: "\f3cd"; } +.bi-flower2::before { content: "\f3ce"; } +.bi-flower3::before { content: "\f3cf"; } +.bi-folder-check::before { content: "\f3d0"; } +.bi-folder-fill::before { content: "\f3d1"; } +.bi-folder-minus::before { content: "\f3d2"; } +.bi-folder-plus::before { content: "\f3d3"; } +.bi-folder-symlink-fill::before { content: "\f3d4"; } +.bi-folder-symlink::before { content: "\f3d5"; } +.bi-folder-x::before { content: "\f3d6"; } +.bi-folder::before { content: "\f3d7"; } +.bi-folder2-open::before { content: "\f3d8"; } +.bi-folder2::before { content: "\f3d9"; } +.bi-fonts::before { content: "\f3da"; } +.bi-forward-fill::before { content: "\f3db"; } +.bi-forward::before { content: "\f3dc"; } +.bi-front::before { content: "\f3dd"; } +.bi-fullscreen-exit::before { content: "\f3de"; } +.bi-fullscreen::before { content: "\f3df"; } +.bi-funnel-fill::before { content: "\f3e0"; } +.bi-funnel::before { content: "\f3e1"; } +.bi-gear-fill::before { content: "\f3e2"; } +.bi-gear-wide-connected::before { content: "\f3e3"; } +.bi-gear-wide::before { content: "\f3e4"; } +.bi-gear::before { content: "\f3e5"; } +.bi-gem::before { content: "\f3e6"; } +.bi-geo-alt-fill::before { content: "\f3e7"; } +.bi-geo-alt::before { content: "\f3e8"; } +.bi-geo-fill::before { content: "\f3e9"; } +.bi-geo::before { content: "\f3ea"; } +.bi-gift-fill::before { content: "\f3eb"; } +.bi-gift::before { content: "\f3ec"; } +.bi-github::before { content: "\f3ed"; } +.bi-globe::before { content: "\f3ee"; } +.bi-globe2::before { content: "\f3ef"; } +.bi-google::before { content: "\f3f0"; } +.bi-graph-down::before { content: "\f3f1"; } +.bi-graph-up::before { content: "\f3f2"; } +.bi-grid-1x2-fill::before { content: "\f3f3"; } +.bi-grid-1x2::before { content: "\f3f4"; } +.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } +.bi-grid-3x2-gap::before { content: "\f3f6"; } +.bi-grid-3x2::before { content: "\f3f7"; } +.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } +.bi-grid-3x3-gap::before { content: "\f3f9"; } +.bi-grid-3x3::before { content: "\f3fa"; } +.bi-grid-fill::before { content: "\f3fb"; } +.bi-grid::before { content: "\f3fc"; } +.bi-grip-horizontal::before { content: "\f3fd"; } +.bi-grip-vertical::before { content: "\f3fe"; } +.bi-hammer::before { content: "\f3ff"; } +.bi-hand-index-fill::before { content: "\f400"; } +.bi-hand-index-thumb-fill::before { content: "\f401"; } +.bi-hand-index-thumb::before { content: "\f402"; } +.bi-hand-index::before { content: "\f403"; } +.bi-hand-thumbs-down-fill::before { content: "\f404"; } +.bi-hand-thumbs-down::before { content: "\f405"; } +.bi-hand-thumbs-up-fill::before { content: "\f406"; } +.bi-hand-thumbs-up::before { content: "\f407"; } +.bi-handbag-fill::before { content: "\f408"; } +.bi-handbag::before { content: "\f409"; } +.bi-hash::before { content: "\f40a"; } +.bi-hdd-fill::before { content: "\f40b"; } +.bi-hdd-network-fill::before { content: "\f40c"; } +.bi-hdd-network::before { content: "\f40d"; } +.bi-hdd-rack-fill::before { content: "\f40e"; } +.bi-hdd-rack::before { content: "\f40f"; } +.bi-hdd-stack-fill::before { content: "\f410"; } +.bi-hdd-stack::before { content: "\f411"; } +.bi-hdd::before { content: "\f412"; } +.bi-headphones::before { content: "\f413"; } +.bi-headset::before { content: "\f414"; } +.bi-heart-fill::before { content: "\f415"; } +.bi-heart-half::before { content: "\f416"; } +.bi-heart::before { content: "\f417"; } +.bi-heptagon-fill::before { content: "\f418"; } +.bi-heptagon-half::before { content: "\f419"; } +.bi-heptagon::before { content: "\f41a"; } +.bi-hexagon-fill::before { content: "\f41b"; } +.bi-hexagon-half::before { content: "\f41c"; } +.bi-hexagon::before { content: "\f41d"; } +.bi-hourglass-bottom::before { content: "\f41e"; } +.bi-hourglass-split::before { content: "\f41f"; } +.bi-hourglass-top::before { content: "\f420"; } +.bi-hourglass::before { content: "\f421"; } +.bi-house-door-fill::before { content: "\f422"; } +.bi-house-door::before { content: "\f423"; } +.bi-house-fill::before { content: "\f424"; } +.bi-house::before { content: "\f425"; } +.bi-hr::before { content: "\f426"; } +.bi-hurricane::before { content: "\f427"; } +.bi-image-alt::before { content: "\f428"; } +.bi-image-fill::before { content: "\f429"; } +.bi-image::before { content: "\f42a"; } +.bi-images::before { content: "\f42b"; } +.bi-inbox-fill::before { content: "\f42c"; } +.bi-inbox::before { content: "\f42d"; } +.bi-inboxes-fill::before { content: "\f42e"; } +.bi-inboxes::before { content: "\f42f"; } +.bi-info-circle-fill::before { content: "\f430"; } +.bi-info-circle::before { content: "\f431"; } +.bi-info-square-fill::before { content: "\f432"; } +.bi-info-square::before { content: "\f433"; } +.bi-info::before { content: "\f434"; } +.bi-input-cursor-text::before { content: "\f435"; } +.bi-input-cursor::before { content: "\f436"; } +.bi-instagram::before { content: "\f437"; } +.bi-intersect::before { content: "\f438"; } +.bi-journal-album::before { content: "\f439"; } +.bi-journal-arrow-down::before { content: "\f43a"; } +.bi-journal-arrow-up::before { content: "\f43b"; } +.bi-journal-bookmark-fill::before { content: "\f43c"; } +.bi-journal-bookmark::before { content: "\f43d"; } +.bi-journal-check::before { content: "\f43e"; } +.bi-journal-code::before { content: "\f43f"; } +.bi-journal-medical::before { content: "\f440"; } +.bi-journal-minus::before { content: "\f441"; } +.bi-journal-plus::before { content: "\f442"; } +.bi-journal-richtext::before { content: "\f443"; } +.bi-journal-text::before { content: "\f444"; } +.bi-journal-x::before { content: "\f445"; } +.bi-journal::before { content: "\f446"; } +.bi-journals::before { content: "\f447"; } +.bi-joystick::before { content: "\f448"; } +.bi-justify-left::before { content: "\f449"; } +.bi-justify-right::before { content: "\f44a"; } +.bi-justify::before { content: "\f44b"; } +.bi-kanban-fill::before { content: "\f44c"; } +.bi-kanban::before { content: "\f44d"; } +.bi-key-fill::before { content: "\f44e"; } +.bi-key::before { content: "\f44f"; } +.bi-keyboard-fill::before { content: "\f450"; } +.bi-keyboard::before { content: "\f451"; } +.bi-ladder::before { content: "\f452"; } +.bi-lamp-fill::before { content: "\f453"; } +.bi-lamp::before { content: "\f454"; } +.bi-laptop-fill::before { content: "\f455"; } +.bi-laptop::before { content: "\f456"; } +.bi-layer-backward::before { content: "\f457"; } +.bi-layer-forward::before { content: "\f458"; } +.bi-layers-fill::before { content: "\f459"; } +.bi-layers-half::before { content: "\f45a"; } +.bi-layers::before { content: "\f45b"; } +.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } +.bi-layout-sidebar-inset::before { content: "\f45d"; } +.bi-layout-sidebar-reverse::before { content: "\f45e"; } +.bi-layout-sidebar::before { content: "\f45f"; } +.bi-layout-split::before { content: "\f460"; } +.bi-layout-text-sidebar-reverse::before { content: "\f461"; } +.bi-layout-text-sidebar::before { content: "\f462"; } +.bi-layout-text-window-reverse::before { content: "\f463"; } +.bi-layout-text-window::before { content: "\f464"; } +.bi-layout-three-columns::before { content: "\f465"; } +.bi-layout-wtf::before { content: "\f466"; } +.bi-life-preserver::before { content: "\f467"; } +.bi-lightbulb-fill::before { content: "\f468"; } +.bi-lightbulb-off-fill::before { content: "\f469"; } +.bi-lightbulb-off::before { content: "\f46a"; } +.bi-lightbulb::before { content: "\f46b"; } +.bi-lightning-charge-fill::before { content: "\f46c"; } +.bi-lightning-charge::before { content: "\f46d"; } +.bi-lightning-fill::before { content: "\f46e"; } +.bi-lightning::before { content: "\f46f"; } +.bi-link-45deg::before { content: "\f470"; } +.bi-link::before { content: "\f471"; } +.bi-linkedin::before { content: "\f472"; } +.bi-list-check::before { content: "\f473"; } +.bi-list-nested::before { content: "\f474"; } +.bi-list-ol::before { content: "\f475"; } +.bi-list-stars::before { content: "\f476"; } +.bi-list-task::before { content: "\f477"; } +.bi-list-ul::before { content: "\f478"; } +.bi-list::before { content: "\f479"; } +.bi-lock-fill::before { content: "\f47a"; } +.bi-lock::before { content: "\f47b"; } +.bi-mailbox::before { content: "\f47c"; } +.bi-mailbox2::before { content: "\f47d"; } +.bi-map-fill::before { content: "\f47e"; } +.bi-map::before { content: "\f47f"; } +.bi-markdown-fill::before { content: "\f480"; } +.bi-markdown::before { content: "\f481"; } +.bi-mask::before { content: "\f482"; } +.bi-megaphone-fill::before { content: "\f483"; } +.bi-megaphone::before { content: "\f484"; } +.bi-menu-app-fill::before { content: "\f485"; } +.bi-menu-app::before { content: "\f486"; } +.bi-menu-button-fill::before { content: "\f487"; } +.bi-menu-button-wide-fill::before { content: "\f488"; } +.bi-menu-button-wide::before { content: "\f489"; } +.bi-menu-button::before { content: "\f48a"; } +.bi-menu-down::before { content: "\f48b"; } +.bi-menu-up::before { content: "\f48c"; } +.bi-mic-fill::before { content: "\f48d"; } +.bi-mic-mute-fill::before { content: "\f48e"; } +.bi-mic-mute::before { content: "\f48f"; } +.bi-mic::before { content: "\f490"; } +.bi-minecart-loaded::before { content: "\f491"; } +.bi-minecart::before { content: "\f492"; } +.bi-moisture::before { content: "\f493"; } +.bi-moon-fill::before { content: "\f494"; } +.bi-moon-stars-fill::before { content: "\f495"; } +.bi-moon-stars::before { content: "\f496"; } +.bi-moon::before { content: "\f497"; } +.bi-mouse-fill::before { content: "\f498"; } +.bi-mouse::before { content: "\f499"; } +.bi-mouse2-fill::before { content: "\f49a"; } +.bi-mouse2::before { content: "\f49b"; } +.bi-mouse3-fill::before { content: "\f49c"; } +.bi-mouse3::before { content: "\f49d"; } +.bi-music-note-beamed::before { content: "\f49e"; } +.bi-music-note-list::before { content: "\f49f"; } +.bi-music-note::before { content: "\f4a0"; } +.bi-music-player-fill::before { content: "\f4a1"; } +.bi-music-player::before { content: "\f4a2"; } +.bi-newspaper::before { content: "\f4a3"; } +.bi-node-minus-fill::before { content: "\f4a4"; } +.bi-node-minus::before { content: "\f4a5"; } +.bi-node-plus-fill::before { content: "\f4a6"; } +.bi-node-plus::before { content: "\f4a7"; } +.bi-nut-fill::before { content: "\f4a8"; } +.bi-nut::before { content: "\f4a9"; } +.bi-octagon-fill::before { content: "\f4aa"; } +.bi-octagon-half::before { content: "\f4ab"; } +.bi-octagon::before { content: "\f4ac"; } +.bi-option::before { content: "\f4ad"; } +.bi-outlet::before { content: "\f4ae"; } +.bi-paint-bucket::before { content: "\f4af"; } +.bi-palette-fill::before { content: "\f4b0"; } +.bi-palette::before { content: "\f4b1"; } +.bi-palette2::before { content: "\f4b2"; } +.bi-paperclip::before { content: "\f4b3"; } +.bi-paragraph::before { content: "\f4b4"; } +.bi-patch-check-fill::before { content: "\f4b5"; } +.bi-patch-check::before { content: "\f4b6"; } +.bi-patch-exclamation-fill::before { content: "\f4b7"; } +.bi-patch-exclamation::before { content: "\f4b8"; } +.bi-patch-minus-fill::before { content: "\f4b9"; } +.bi-patch-minus::before { content: "\f4ba"; } +.bi-patch-plus-fill::before { content: "\f4bb"; } +.bi-patch-plus::before { content: "\f4bc"; } +.bi-patch-question-fill::before { content: "\f4bd"; } +.bi-patch-question::before { content: "\f4be"; } +.bi-pause-btn-fill::before { content: "\f4bf"; } +.bi-pause-btn::before { content: "\f4c0"; } +.bi-pause-circle-fill::before { content: "\f4c1"; } +.bi-pause-circle::before { content: "\f4c2"; } +.bi-pause-fill::before { content: "\f4c3"; } +.bi-pause::before { content: "\f4c4"; } +.bi-peace-fill::before { content: "\f4c5"; } +.bi-peace::before { content: "\f4c6"; } +.bi-pen-fill::before { content: "\f4c7"; } +.bi-pen::before { content: "\f4c8"; } +.bi-pencil-fill::before { content: "\f4c9"; } +.bi-pencil-square::before { content: "\f4ca"; } +.bi-pencil::before { content: "\f4cb"; } +.bi-pentagon-fill::before { content: "\f4cc"; } +.bi-pentagon-half::before { content: "\f4cd"; } +.bi-pentagon::before { content: "\f4ce"; } +.bi-people-fill::before { content: "\f4cf"; } +.bi-people::before { content: "\f4d0"; } +.bi-percent::before { content: "\f4d1"; } +.bi-person-badge-fill::before { content: "\f4d2"; } +.bi-person-badge::before { content: "\f4d3"; } +.bi-person-bounding-box::before { content: "\f4d4"; } +.bi-person-check-fill::before { content: "\f4d5"; } +.bi-person-check::before { content: "\f4d6"; } +.bi-person-circle::before { content: "\f4d7"; } +.bi-person-dash-fill::before { content: "\f4d8"; } +.bi-person-dash::before { content: "\f4d9"; } +.bi-person-fill::before { content: "\f4da"; } +.bi-person-lines-fill::before { content: "\f4db"; } +.bi-person-plus-fill::before { content: "\f4dc"; } +.bi-person-plus::before { content: "\f4dd"; } +.bi-person-square::before { content: "\f4de"; } +.bi-person-x-fill::before { content: "\f4df"; } +.bi-person-x::before { content: "\f4e0"; } +.bi-person::before { content: "\f4e1"; } +.bi-phone-fill::before { content: "\f4e2"; } +.bi-phone-landscape-fill::before { content: "\f4e3"; } +.bi-phone-landscape::before { content: "\f4e4"; } +.bi-phone-vibrate-fill::before { content: "\f4e5"; } +.bi-phone-vibrate::before { content: "\f4e6"; } +.bi-phone::before { content: "\f4e7"; } +.bi-pie-chart-fill::before { content: "\f4e8"; } +.bi-pie-chart::before { content: "\f4e9"; } +.bi-pin-angle-fill::before { content: "\f4ea"; } +.bi-pin-angle::before { content: "\f4eb"; } +.bi-pin-fill::before { content: "\f4ec"; } +.bi-pin::before { content: "\f4ed"; } +.bi-pip-fill::before { content: "\f4ee"; } +.bi-pip::before { content: "\f4ef"; } +.bi-play-btn-fill::before { content: "\f4f0"; } +.bi-play-btn::before { content: "\f4f1"; } +.bi-play-circle-fill::before { content: "\f4f2"; } +.bi-play-circle::before { content: "\f4f3"; } +.bi-play-fill::before { content: "\f4f4"; } +.bi-play::before { content: "\f4f5"; } +.bi-plug-fill::before { content: "\f4f6"; } +.bi-plug::before { content: "\f4f7"; } +.bi-plus-circle-dotted::before { content: "\f4f8"; } +.bi-plus-circle-fill::before { content: "\f4f9"; } +.bi-plus-circle::before { content: "\f4fa"; } +.bi-plus-square-dotted::before { content: "\f4fb"; } +.bi-plus-square-fill::before { content: "\f4fc"; } +.bi-plus-square::before { content: "\f4fd"; } +.bi-plus::before { content: "\f4fe"; } +.bi-power::before { content: "\f4ff"; } +.bi-printer-fill::before { content: "\f500"; } +.bi-printer::before { content: "\f501"; } +.bi-puzzle-fill::before { content: "\f502"; } +.bi-puzzle::before { content: "\f503"; } +.bi-question-circle-fill::before { content: "\f504"; } +.bi-question-circle::before { content: "\f505"; } +.bi-question-diamond-fill::before { content: "\f506"; } +.bi-question-diamond::before { content: "\f507"; } +.bi-question-octagon-fill::before { content: "\f508"; } +.bi-question-octagon::before { content: "\f509"; } +.bi-question-square-fill::before { content: "\f50a"; } +.bi-question-square::before { content: "\f50b"; } +.bi-question::before { content: "\f50c"; } +.bi-rainbow::before { content: "\f50d"; } +.bi-receipt-cutoff::before { content: "\f50e"; } +.bi-receipt::before { content: "\f50f"; } +.bi-reception-0::before { content: "\f510"; } +.bi-reception-1::before { content: "\f511"; } +.bi-reception-2::before { content: "\f512"; } +.bi-reception-3::before { content: "\f513"; } +.bi-reception-4::before { content: "\f514"; } +.bi-record-btn-fill::before { content: "\f515"; } +.bi-record-btn::before { content: "\f516"; } +.bi-record-circle-fill::before { content: "\f517"; } +.bi-record-circle::before { content: "\f518"; } +.bi-record-fill::before { content: "\f519"; } +.bi-record::before { content: "\f51a"; } +.bi-record2-fill::before { content: "\f51b"; } +.bi-record2::before { content: "\f51c"; } +.bi-reply-all-fill::before { content: "\f51d"; } +.bi-reply-all::before { content: "\f51e"; } +.bi-reply-fill::before { content: "\f51f"; } +.bi-reply::before { content: "\f520"; } +.bi-rss-fill::before { content: "\f521"; } +.bi-rss::before { content: "\f522"; } +.bi-rulers::before { content: "\f523"; } +.bi-save-fill::before { content: "\f524"; } +.bi-save::before { content: "\f525"; } +.bi-save2-fill::before { content: "\f526"; } +.bi-save2::before { content: "\f527"; } +.bi-scissors::before { content: "\f528"; } +.bi-screwdriver::before { content: "\f529"; } +.bi-search::before { content: "\f52a"; } +.bi-segmented-nav::before { content: "\f52b"; } +.bi-server::before { content: "\f52c"; } +.bi-share-fill::before { content: "\f52d"; } +.bi-share::before { content: "\f52e"; } +.bi-shield-check::before { content: "\f52f"; } +.bi-shield-exclamation::before { content: "\f530"; } +.bi-shield-fill-check::before { content: "\f531"; } +.bi-shield-fill-exclamation::before { content: "\f532"; } +.bi-shield-fill-minus::before { content: "\f533"; } +.bi-shield-fill-plus::before { content: "\f534"; } +.bi-shield-fill-x::before { content: "\f535"; } +.bi-shield-fill::before { content: "\f536"; } +.bi-shield-lock-fill::before { content: "\f537"; } +.bi-shield-lock::before { content: "\f538"; } +.bi-shield-minus::before { content: "\f539"; } +.bi-shield-plus::before { content: "\f53a"; } +.bi-shield-shaded::before { content: "\f53b"; } +.bi-shield-slash-fill::before { content: "\f53c"; } +.bi-shield-slash::before { content: "\f53d"; } +.bi-shield-x::before { content: "\f53e"; } +.bi-shield::before { content: "\f53f"; } +.bi-shift-fill::before { content: "\f540"; } +.bi-shift::before { content: "\f541"; } +.bi-shop-window::before { content: "\f542"; } +.bi-shop::before { content: "\f543"; } +.bi-shuffle::before { content: "\f544"; } +.bi-signpost-2-fill::before { content: "\f545"; } +.bi-signpost-2::before { content: "\f546"; } +.bi-signpost-fill::before { content: "\f547"; } +.bi-signpost-split-fill::before { content: "\f548"; } +.bi-signpost-split::before { content: "\f549"; } +.bi-signpost::before { content: "\f54a"; } +.bi-sim-fill::before { content: "\f54b"; } +.bi-sim::before { content: "\f54c"; } +.bi-skip-backward-btn-fill::before { content: "\f54d"; } +.bi-skip-backward-btn::before { content: "\f54e"; } +.bi-skip-backward-circle-fill::before { content: "\f54f"; } +.bi-skip-backward-circle::before { content: "\f550"; } +.bi-skip-backward-fill::before { content: "\f551"; } +.bi-skip-backward::before { content: "\f552"; } +.bi-skip-end-btn-fill::before { content: "\f553"; } +.bi-skip-end-btn::before { content: "\f554"; } +.bi-skip-end-circle-fill::before { content: "\f555"; } +.bi-skip-end-circle::before { content: "\f556"; } +.bi-skip-end-fill::before { content: "\f557"; } +.bi-skip-end::before { content: "\f558"; } +.bi-skip-forward-btn-fill::before { content: "\f559"; } +.bi-skip-forward-btn::before { content: "\f55a"; } +.bi-skip-forward-circle-fill::before { content: "\f55b"; } +.bi-skip-forward-circle::before { content: "\f55c"; } +.bi-skip-forward-fill::before { content: "\f55d"; } +.bi-skip-forward::before { content: "\f55e"; } +.bi-skip-start-btn-fill::before { content: "\f55f"; } +.bi-skip-start-btn::before { content: "\f560"; } +.bi-skip-start-circle-fill::before { content: "\f561"; } +.bi-skip-start-circle::before { content: "\f562"; } +.bi-skip-start-fill::before { content: "\f563"; } +.bi-skip-start::before { content: "\f564"; } +.bi-slack::before { content: "\f565"; } +.bi-slash-circle-fill::before { content: "\f566"; } +.bi-slash-circle::before { content: "\f567"; } +.bi-slash-square-fill::before { content: "\f568"; } +.bi-slash-square::before { content: "\f569"; } +.bi-slash::before { content: "\f56a"; } +.bi-sliders::before { content: "\f56b"; } +.bi-smartwatch::before { content: "\f56c"; } +.bi-snow::before { content: "\f56d"; } +.bi-snow2::before { content: "\f56e"; } +.bi-snow3::before { content: "\f56f"; } +.bi-sort-alpha-down-alt::before { content: "\f570"; } +.bi-sort-alpha-down::before { content: "\f571"; } +.bi-sort-alpha-up-alt::before { content: "\f572"; } +.bi-sort-alpha-up::before { content: "\f573"; } +.bi-sort-down-alt::before { content: "\f574"; } +.bi-sort-down::before { content: "\f575"; } +.bi-sort-numeric-down-alt::before { content: "\f576"; } +.bi-sort-numeric-down::before { content: "\f577"; } +.bi-sort-numeric-up-alt::before { content: "\f578"; } +.bi-sort-numeric-up::before { content: "\f579"; } +.bi-sort-up-alt::before { content: "\f57a"; } +.bi-sort-up::before { content: "\f57b"; } +.bi-soundwave::before { content: "\f57c"; } +.bi-speaker-fill::before { content: "\f57d"; } +.bi-speaker::before { content: "\f57e"; } +.bi-speedometer::before { content: "\f57f"; } +.bi-speedometer2::before { content: "\f580"; } +.bi-spellcheck::before { content: "\f581"; } +.bi-square-fill::before { content: "\f582"; } +.bi-square-half::before { content: "\f583"; } +.bi-square::before { content: "\f584"; } +.bi-stack::before { content: "\f585"; } +.bi-star-fill::before { content: "\f586"; } +.bi-star-half::before { content: "\f587"; } +.bi-star::before { content: "\f588"; } +.bi-stars::before { content: "\f589"; } +.bi-stickies-fill::before { content: "\f58a"; } +.bi-stickies::before { content: "\f58b"; } +.bi-sticky-fill::before { content: "\f58c"; } +.bi-sticky::before { content: "\f58d"; } +.bi-stop-btn-fill::before { content: "\f58e"; } +.bi-stop-btn::before { content: "\f58f"; } +.bi-stop-circle-fill::before { content: "\f590"; } +.bi-stop-circle::before { content: "\f591"; } +.bi-stop-fill::before { content: "\f592"; } +.bi-stop::before { content: "\f593"; } +.bi-stoplights-fill::before { content: "\f594"; } +.bi-stoplights::before { content: "\f595"; } +.bi-stopwatch-fill::before { content: "\f596"; } +.bi-stopwatch::before { content: "\f597"; } +.bi-subtract::before { content: "\f598"; } +.bi-suit-club-fill::before { content: "\f599"; } +.bi-suit-club::before { content: "\f59a"; } +.bi-suit-diamond-fill::before { content: "\f59b"; } +.bi-suit-diamond::before { content: "\f59c"; } +.bi-suit-heart-fill::before { content: "\f59d"; } +.bi-suit-heart::before { content: "\f59e"; } +.bi-suit-spade-fill::before { content: "\f59f"; } +.bi-suit-spade::before { content: "\f5a0"; } +.bi-sun-fill::before { content: "\f5a1"; } +.bi-sun::before { content: "\f5a2"; } +.bi-sunglasses::before { content: "\f5a3"; } +.bi-sunrise-fill::before { content: "\f5a4"; } +.bi-sunrise::before { content: "\f5a5"; } +.bi-sunset-fill::before { content: "\f5a6"; } +.bi-sunset::before { content: "\f5a7"; } +.bi-symmetry-horizontal::before { content: "\f5a8"; } +.bi-symmetry-vertical::before { content: "\f5a9"; } +.bi-table::before { content: "\f5aa"; } +.bi-tablet-fill::before { content: "\f5ab"; } +.bi-tablet-landscape-fill::before { content: "\f5ac"; } +.bi-tablet-landscape::before { content: "\f5ad"; } +.bi-tablet::before { content: "\f5ae"; } +.bi-tag-fill::before { content: "\f5af"; } +.bi-tag::before { content: "\f5b0"; } +.bi-tags-fill::before { content: "\f5b1"; } +.bi-tags::before { content: "\f5b2"; } +.bi-telegram::before { content: "\f5b3"; } +.bi-telephone-fill::before { content: "\f5b4"; } +.bi-telephone-forward-fill::before { content: "\f5b5"; } +.bi-telephone-forward::before { content: "\f5b6"; } +.bi-telephone-inbound-fill::before { content: "\f5b7"; } +.bi-telephone-inbound::before { content: "\f5b8"; } +.bi-telephone-minus-fill::before { content: "\f5b9"; } +.bi-telephone-minus::before { content: "\f5ba"; } +.bi-telephone-outbound-fill::before { content: "\f5bb"; } +.bi-telephone-outbound::before { content: "\f5bc"; } +.bi-telephone-plus-fill::before { content: "\f5bd"; } +.bi-telephone-plus::before { content: "\f5be"; } +.bi-telephone-x-fill::before { content: "\f5bf"; } +.bi-telephone-x::before { content: "\f5c0"; } +.bi-telephone::before { content: "\f5c1"; } +.bi-terminal-fill::before { content: "\f5c2"; } +.bi-terminal::before { content: "\f5c3"; } +.bi-text-center::before { content: "\f5c4"; } +.bi-text-indent-left::before { content: "\f5c5"; } +.bi-text-indent-right::before { content: "\f5c6"; } +.bi-text-left::before { content: "\f5c7"; } +.bi-text-paragraph::before { content: "\f5c8"; } +.bi-text-right::before { content: "\f5c9"; } +.bi-textarea-resize::before { content: "\f5ca"; } +.bi-textarea-t::before { content: "\f5cb"; } +.bi-textarea::before { content: "\f5cc"; } +.bi-thermometer-half::before { content: "\f5cd"; } +.bi-thermometer-high::before { content: "\f5ce"; } +.bi-thermometer-low::before { content: "\f5cf"; } +.bi-thermometer-snow::before { content: "\f5d0"; } +.bi-thermometer-sun::before { content: "\f5d1"; } +.bi-thermometer::before { content: "\f5d2"; } +.bi-three-dots-vertical::before { content: "\f5d3"; } +.bi-three-dots::before { content: "\f5d4"; } +.bi-toggle-off::before { content: "\f5d5"; } +.bi-toggle-on::before { content: "\f5d6"; } +.bi-toggle2-off::before { content: "\f5d7"; } +.bi-toggle2-on::before { content: "\f5d8"; } +.bi-toggles::before { content: "\f5d9"; } +.bi-toggles2::before { content: "\f5da"; } +.bi-tools::before { content: "\f5db"; } +.bi-tornado::before { content: "\f5dc"; } +.bi-trash-fill::before { content: "\f5dd"; } +.bi-trash::before { content: "\f5de"; } +.bi-trash2-fill::before { content: "\f5df"; } +.bi-trash2::before { content: "\f5e0"; } +.bi-tree-fill::before { content: "\f5e1"; } +.bi-tree::before { content: "\f5e2"; } +.bi-triangle-fill::before { content: "\f5e3"; } +.bi-triangle-half::before { content: "\f5e4"; } +.bi-triangle::before { content: "\f5e5"; } +.bi-trophy-fill::before { content: "\f5e6"; } +.bi-trophy::before { content: "\f5e7"; } +.bi-tropical-storm::before { content: "\f5e8"; } +.bi-truck-flatbed::before { content: "\f5e9"; } +.bi-truck::before { content: "\f5ea"; } +.bi-tsunami::before { content: "\f5eb"; } +.bi-tv-fill::before { content: "\f5ec"; } +.bi-tv::before { content: "\f5ed"; } +.bi-twitch::before { content: "\f5ee"; } +.bi-twitter::before { content: "\f5ef"; } +.bi-type-bold::before { content: "\f5f0"; } +.bi-type-h1::before { content: "\f5f1"; } +.bi-type-h2::before { content: "\f5f2"; } +.bi-type-h3::before { content: "\f5f3"; } +.bi-type-italic::before { content: "\f5f4"; } +.bi-type-strikethrough::before { content: "\f5f5"; } +.bi-type-underline::before { content: "\f5f6"; } +.bi-type::before { content: "\f5f7"; } +.bi-ui-checks-grid::before { content: "\f5f8"; } +.bi-ui-checks::before { content: "\f5f9"; } +.bi-ui-radios-grid::before { content: "\f5fa"; } +.bi-ui-radios::before { content: "\f5fb"; } +.bi-umbrella-fill::before { content: "\f5fc"; } +.bi-umbrella::before { content: "\f5fd"; } +.bi-union::before { content: "\f5fe"; } +.bi-unlock-fill::before { content: "\f5ff"; } +.bi-unlock::before { content: "\f600"; } +.bi-upc-scan::before { content: "\f601"; } +.bi-upc::before { content: "\f602"; } +.bi-upload::before { content: "\f603"; } +.bi-vector-pen::before { content: "\f604"; } +.bi-view-list::before { content: "\f605"; } +.bi-view-stacked::before { content: "\f606"; } +.bi-vinyl-fill::before { content: "\f607"; } +.bi-vinyl::before { content: "\f608"; } +.bi-voicemail::before { content: "\f609"; } +.bi-volume-down-fill::before { content: "\f60a"; } +.bi-volume-down::before { content: "\f60b"; } +.bi-volume-mute-fill::before { content: "\f60c"; } +.bi-volume-mute::before { content: "\f60d"; } +.bi-volume-off-fill::before { content: "\f60e"; } +.bi-volume-off::before { content: "\f60f"; } +.bi-volume-up-fill::before { content: "\f610"; } +.bi-volume-up::before { content: "\f611"; } +.bi-vr::before { content: "\f612"; } +.bi-wallet-fill::before { content: "\f613"; } +.bi-wallet::before { content: "\f614"; } +.bi-wallet2::before { content: "\f615"; } +.bi-watch::before { content: "\f616"; } +.bi-water::before { content: "\f617"; } +.bi-whatsapp::before { content: "\f618"; } +.bi-wifi-1::before { content: "\f619"; } +.bi-wifi-2::before { content: "\f61a"; } +.bi-wifi-off::before { content: "\f61b"; } +.bi-wifi::before { content: "\f61c"; } +.bi-wind::before { content: "\f61d"; } +.bi-window-dock::before { content: "\f61e"; } +.bi-window-sidebar::before { content: "\f61f"; } +.bi-window::before { content: "\f620"; } +.bi-wrench::before { content: "\f621"; } +.bi-x-circle-fill::before { content: "\f622"; } +.bi-x-circle::before { content: "\f623"; } +.bi-x-diamond-fill::before { content: "\f624"; } +.bi-x-diamond::before { content: "\f625"; } +.bi-x-octagon-fill::before { content: "\f626"; } +.bi-x-octagon::before { content: "\f627"; } +.bi-x-square-fill::before { content: "\f628"; } +.bi-x-square::before { content: "\f629"; } +.bi-x::before { content: "\f62a"; } +.bi-youtube::before { content: "\f62b"; } +.bi-zoom-in::before { content: "\f62c"; } +.bi-zoom-out::before { content: "\f62d"; } +.bi-bank::before { content: "\f62e"; } +.bi-bank2::before { content: "\f62f"; } +.bi-bell-slash-fill::before { content: "\f630"; } +.bi-bell-slash::before { content: "\f631"; } +.bi-cash-coin::before { content: "\f632"; } +.bi-check-lg::before { content: "\f633"; } +.bi-coin::before { content: "\f634"; } +.bi-currency-bitcoin::before { content: "\f635"; } +.bi-currency-dollar::before { content: "\f636"; } +.bi-currency-euro::before { content: "\f637"; } +.bi-currency-exchange::before { content: "\f638"; } +.bi-currency-pound::before { content: "\f639"; } +.bi-currency-yen::before { content: "\f63a"; } +.bi-dash-lg::before { content: "\f63b"; } +.bi-exclamation-lg::before { content: "\f63c"; } +.bi-file-earmark-pdf-fill::before { content: "\f63d"; } +.bi-file-earmark-pdf::before { content: "\f63e"; } +.bi-file-pdf-fill::before { content: "\f63f"; } +.bi-file-pdf::before { content: "\f640"; } +.bi-gender-ambiguous::before { content: "\f641"; } +.bi-gender-female::before { content: "\f642"; } +.bi-gender-male::before { content: "\f643"; } +.bi-gender-trans::before { content: "\f644"; } +.bi-headset-vr::before { content: "\f645"; } +.bi-info-lg::before { content: "\f646"; } +.bi-mastodon::before { content: "\f647"; } +.bi-messenger::before { content: "\f648"; } +.bi-piggy-bank-fill::before { content: "\f649"; } +.bi-piggy-bank::before { content: "\f64a"; } +.bi-pin-map-fill::before { content: "\f64b"; } +.bi-pin-map::before { content: "\f64c"; } +.bi-plus-lg::before { content: "\f64d"; } +.bi-question-lg::before { content: "\f64e"; } +.bi-recycle::before { content: "\f64f"; } +.bi-reddit::before { content: "\f650"; } +.bi-safe-fill::before { content: "\f651"; } +.bi-safe2-fill::before { content: "\f652"; } +.bi-safe2::before { content: "\f653"; } +.bi-sd-card-fill::before { content: "\f654"; } +.bi-sd-card::before { content: "\f655"; } +.bi-skype::before { content: "\f656"; } +.bi-slash-lg::before { content: "\f657"; } +.bi-translate::before { content: "\f658"; } +.bi-x-lg::before { content: "\f659"; } +.bi-safe::before { content: "\f65a"; } +.bi-apple::before { content: "\f65b"; } +.bi-microsoft::before { content: "\f65d"; } +.bi-windows::before { content: "\f65e"; } +.bi-behance::before { content: "\f65c"; } +.bi-dribbble::before { content: "\f65f"; } +.bi-line::before { content: "\f660"; } +.bi-medium::before { content: "\f661"; } +.bi-paypal::before { content: "\f662"; } +.bi-pinterest::before { content: "\f663"; } +.bi-signal::before { content: "\f664"; } +.bi-snapchat::before { content: "\f665"; } +.bi-spotify::before { content: "\f666"; } +.bi-stack-overflow::before { content: "\f667"; } +.bi-strava::before { content: "\f668"; } +.bi-wordpress::before { content: "\f669"; } +.bi-vimeo::before { content: "\f66a"; } +.bi-activity::before { content: "\f66b"; } +.bi-easel2-fill::before { content: "\f66c"; } +.bi-easel2::before { content: "\f66d"; } +.bi-easel3-fill::before { content: "\f66e"; } +.bi-easel3::before { content: "\f66f"; } +.bi-fan::before { content: "\f670"; } +.bi-fingerprint::before { content: "\f671"; } +.bi-graph-down-arrow::before { content: "\f672"; } +.bi-graph-up-arrow::before { content: "\f673"; } +.bi-hypnotize::before { content: "\f674"; } +.bi-magic::before { content: "\f675"; } +.bi-person-rolodex::before { content: "\f676"; } +.bi-person-video::before { content: "\f677"; } +.bi-person-video2::before { content: "\f678"; } +.bi-person-video3::before { content: "\f679"; } +.bi-person-workspace::before { content: "\f67a"; } +.bi-radioactive::before { content: "\f67b"; } +.bi-webcam-fill::before { content: "\f67c"; } +.bi-webcam::before { content: "\f67d"; } +.bi-yin-yang::before { content: "\f67e"; } +.bi-bandaid-fill::before { content: "\f680"; } +.bi-bandaid::before { content: "\f681"; } +.bi-bluetooth::before { content: "\f682"; } +.bi-body-text::before { content: "\f683"; } +.bi-boombox::before { content: "\f684"; } +.bi-boxes::before { content: "\f685"; } +.bi-dpad-fill::before { content: "\f686"; } +.bi-dpad::before { content: "\f687"; } +.bi-ear-fill::before { content: "\f688"; } +.bi-ear::before { content: "\f689"; } +.bi-envelope-check-1::before { content: "\f68a"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-1::before { content: "\f68d"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-1::before { content: "\f690"; } +.bi-envelope-exclamation-fill::before { content: "\f691"; } +.bi-envelope-exclamation::before { content: "\f692"; } +.bi-envelope-plus-fill::before { content: "\f693"; } +.bi-envelope-plus::before { content: "\f694"; } +.bi-envelope-slash-1::before { content: "\f695"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-1::before { content: "\f698"; } +.bi-envelope-x-fill::before { content: "\f699"; } +.bi-envelope-x::before { content: "\f69a"; } +.bi-explicit-fill::before { content: "\f69b"; } +.bi-explicit::before { content: "\f69c"; } +.bi-git::before { content: "\f69d"; } +.bi-infinity::before { content: "\f69e"; } +.bi-list-columns-reverse::before { content: "\f69f"; } +.bi-list-columns::before { content: "\f6a0"; } +.bi-meta::before { content: "\f6a1"; } +.bi-mortorboard-fill::before { content: "\f6a2"; } +.bi-mortorboard::before { content: "\f6a3"; } +.bi-nintendo-switch::before { content: "\f6a4"; } +.bi-pc-display-horizontal::before { content: "\f6a5"; } +.bi-pc-display::before { content: "\f6a6"; } +.bi-pc-horizontal::before { content: "\f6a7"; } +.bi-pc::before { content: "\f6a8"; } +.bi-playstation::before { content: "\f6a9"; } +.bi-plus-slash-minus::before { content: "\f6aa"; } +.bi-projector-fill::before { content: "\f6ab"; } +.bi-projector::before { content: "\f6ac"; } +.bi-qr-code-scan::before { content: "\f6ad"; } +.bi-qr-code::before { content: "\f6ae"; } +.bi-quora::before { content: "\f6af"; } +.bi-quote::before { content: "\f6b0"; } +.bi-robot::before { content: "\f6b1"; } +.bi-send-check-fill::before { content: "\f6b2"; } +.bi-send-check::before { content: "\f6b3"; } +.bi-send-dash-fill::before { content: "\f6b4"; } +.bi-send-dash::before { content: "\f6b5"; } +.bi-send-exclamation-1::before { content: "\f6b6"; } +.bi-send-exclamation-fill::before { content: "\f6b7"; } +.bi-send-exclamation::before { content: "\f6b8"; } +.bi-send-fill::before { content: "\f6b9"; } +.bi-send-plus-fill::before { content: "\f6ba"; } +.bi-send-plus::before { content: "\f6bb"; } +.bi-send-slash-fill::before { content: "\f6bc"; } +.bi-send-slash::before { content: "\f6bd"; } +.bi-send-x-fill::before { content: "\f6be"; } +.bi-send-x::before { content: "\f6bf"; } +.bi-send::before { content: "\f6c0"; } +.bi-steam::before { content: "\f6c1"; } +.bi-terminal-dash-1::before { content: "\f6c2"; } +.bi-terminal-dash::before { content: "\f6c3"; } +.bi-terminal-plus::before { content: "\f6c4"; } +.bi-terminal-split::before { content: "\f6c5"; } +.bi-ticket-detailed-fill::before { content: "\f6c6"; } +.bi-ticket-detailed::before { content: "\f6c7"; } +.bi-ticket-fill::before { content: "\f6c8"; } +.bi-ticket-perforated-fill::before { content: "\f6c9"; } +.bi-ticket-perforated::before { content: "\f6ca"; } +.bi-ticket::before { content: "\f6cb"; } +.bi-tiktok::before { content: "\f6cc"; } +.bi-window-dash::before { content: "\f6cd"; } +.bi-window-desktop::before { content: "\f6ce"; } +.bi-window-fullscreen::before { content: "\f6cf"; } +.bi-window-plus::before { content: "\f6d0"; } +.bi-window-split::before { content: "\f6d1"; } +.bi-window-stack::before { content: "\f6d2"; } +.bi-window-x::before { content: "\f6d3"; } +.bi-xbox::before { content: "\f6d4"; } +.bi-ethernet::before { content: "\f6d5"; } +.bi-hdmi-fill::before { content: "\f6d6"; } +.bi-hdmi::before { content: "\f6d7"; } +.bi-usb-c-fill::before { content: "\f6d8"; } +.bi-usb-c::before { content: "\f6d9"; } +.bi-usb-fill::before { content: "\f6da"; } +.bi-usb-plug-fill::before { content: "\f6db"; } +.bi-usb-plug::before { content: "\f6dc"; } +.bi-usb-symbol::before { content: "\f6dd"; } +.bi-usb::before { content: "\f6de"; } +.bi-boombox-fill::before { content: "\f6df"; } +.bi-displayport-1::before { content: "\f6e0"; } +.bi-displayport::before { content: "\f6e1"; } +.bi-gpu-card::before { content: "\f6e2"; } +.bi-memory::before { content: "\f6e3"; } +.bi-modem-fill::before { content: "\f6e4"; } +.bi-modem::before { content: "\f6e5"; } +.bi-motherboard-fill::before { content: "\f6e6"; } +.bi-motherboard::before { content: "\f6e7"; } +.bi-optical-audio-fill::before { content: "\f6e8"; } +.bi-optical-audio::before { content: "\f6e9"; } +.bi-pci-card::before { content: "\f6ea"; } +.bi-router-fill::before { content: "\f6eb"; } +.bi-router::before { content: "\f6ec"; } +.bi-ssd-fill::before { content: "\f6ed"; } +.bi-ssd::before { content: "\f6ee"; } +.bi-thunderbolt-fill::before { content: "\f6ef"; } +.bi-thunderbolt::before { content: "\f6f0"; } +.bi-usb-drive-fill::before { content: "\f6f1"; } +.bi-usb-drive::before { content: "\f6f2"; } +.bi-usb-micro-fill::before { content: "\f6f3"; } +.bi-usb-micro::before { content: "\f6f4"; } +.bi-usb-mini-fill::before { content: "\f6f5"; } +.bi-usb-mini::before { content: "\f6f6"; } +.bi-cloud-haze2::before { content: "\f6f7"; } +.bi-device-hdd-fill::before { content: "\f6f8"; } +.bi-device-hdd::before { content: "\f6f9"; } +.bi-device-ssd-fill::before { content: "\f6fa"; } +.bi-device-ssd::before { content: "\f6fb"; } +.bi-displayport-fill::before { content: "\f6fc"; } +.bi-mortarboard-fill::before { content: "\f6fd"; } +.bi-mortarboard::before { content: "\f6fe"; } +.bi-terminal-x::before { content: "\f6ff"; } +.bi-arrow-through-heart-fill::before { content: "\f700"; } +.bi-arrow-through-heart::before { content: "\f701"; } +.bi-badge-sd-fill::before { content: "\f702"; } +.bi-badge-sd::before { content: "\f703"; } +.bi-bag-heart-fill::before { content: "\f704"; } +.bi-bag-heart::before { content: "\f705"; } +.bi-balloon-fill::before { content: "\f706"; } +.bi-balloon-heart-fill::before { content: "\f707"; } +.bi-balloon-heart::before { content: "\f708"; } +.bi-balloon::before { content: "\f709"; } +.bi-box2-fill::before { content: "\f70a"; } +.bi-box2-heart-fill::before { content: "\f70b"; } +.bi-box2-heart::before { content: "\f70c"; } +.bi-box2::before { content: "\f70d"; } +.bi-braces-asterisk::before { content: "\f70e"; } +.bi-calendar-heart-fill::before { content: "\f70f"; } +.bi-calendar-heart::before { content: "\f710"; } +.bi-calendar2-heart-fill::before { content: "\f711"; } +.bi-calendar2-heart::before { content: "\f712"; } +.bi-chat-heart-fill::before { content: "\f713"; } +.bi-chat-heart::before { content: "\f714"; } +.bi-chat-left-heart-fill::before { content: "\f715"; } +.bi-chat-left-heart::before { content: "\f716"; } +.bi-chat-right-heart-fill::before { content: "\f717"; } +.bi-chat-right-heart::before { content: "\f718"; } +.bi-chat-square-heart-fill::before { content: "\f719"; } +.bi-chat-square-heart::before { content: "\f71a"; } +.bi-clipboard-check-fill::before { content: "\f71b"; } +.bi-clipboard-data-fill::before { content: "\f71c"; } +.bi-clipboard-fill::before { content: "\f71d"; } +.bi-clipboard-heart-fill::before { content: "\f71e"; } +.bi-clipboard-heart::before { content: "\f71f"; } +.bi-clipboard-minus-fill::before { content: "\f720"; } +.bi-clipboard-plus-fill::before { content: "\f721"; } +.bi-clipboard-pulse::before { content: "\f722"; } +.bi-clipboard-x-fill::before { content: "\f723"; } +.bi-clipboard2-check-fill::before { content: "\f724"; } +.bi-clipboard2-check::before { content: "\f725"; } +.bi-clipboard2-data-fill::before { content: "\f726"; } +.bi-clipboard2-data::before { content: "\f727"; } +.bi-clipboard2-fill::before { content: "\f728"; } +.bi-clipboard2-heart-fill::before { content: "\f729"; } +.bi-clipboard2-heart::before { content: "\f72a"; } +.bi-clipboard2-minus-fill::before { content: "\f72b"; } +.bi-clipboard2-minus::before { content: "\f72c"; } +.bi-clipboard2-plus-fill::before { content: "\f72d"; } +.bi-clipboard2-plus::before { content: "\f72e"; } +.bi-clipboard2-pulse-fill::before { content: "\f72f"; } +.bi-clipboard2-pulse::before { content: "\f730"; } +.bi-clipboard2-x-fill::before { content: "\f731"; } +.bi-clipboard2-x::before { content: "\f732"; } +.bi-clipboard2::before { content: "\f733"; } +.bi-emoji-kiss-fill::before { content: "\f734"; } +.bi-emoji-kiss::before { content: "\f735"; } +.bi-envelope-heart-fill::before { content: "\f736"; } +.bi-envelope-heart::before { content: "\f737"; } +.bi-envelope-open-heart-fill::before { content: "\f738"; } +.bi-envelope-open-heart::before { content: "\f739"; } +.bi-envelope-paper-fill::before { content: "\f73a"; } +.bi-envelope-paper-heart-fill::before { content: "\f73b"; } +.bi-envelope-paper-heart::before { content: "\f73c"; } +.bi-envelope-paper::before { content: "\f73d"; } +.bi-filetype-aac::before { content: "\f73e"; } +.bi-filetype-ai::before { content: "\f73f"; } +.bi-filetype-bmp::before { content: "\f740"; } +.bi-filetype-cs::before { content: "\f741"; } +.bi-filetype-css::before { content: "\f742"; } +.bi-filetype-csv::before { content: "\f743"; } +.bi-filetype-doc::before { content: "\f744"; } +.bi-filetype-docx::before { content: "\f745"; } +.bi-filetype-exe::before { content: "\f746"; } +.bi-filetype-gif::before { content: "\f747"; } +.bi-filetype-heic::before { content: "\f748"; } +.bi-filetype-html::before { content: "\f749"; } +.bi-filetype-java::before { content: "\f74a"; } +.bi-filetype-jpg::before { content: "\f74b"; } +.bi-filetype-js::before { content: "\f74c"; } +.bi-filetype-jsx::before { content: "\f74d"; } +.bi-filetype-key::before { content: "\f74e"; } +.bi-filetype-m4p::before { content: "\f74f"; } +.bi-filetype-md::before { content: "\f750"; } +.bi-filetype-mdx::before { content: "\f751"; } +.bi-filetype-mov::before { content: "\f752"; } +.bi-filetype-mp3::before { content: "\f753"; } +.bi-filetype-mp4::before { content: "\f754"; } +.bi-filetype-otf::before { content: "\f755"; } +.bi-filetype-pdf::before { content: "\f756"; } +.bi-filetype-php::before { content: "\f757"; } +.bi-filetype-png::before { content: "\f758"; } +.bi-filetype-ppt-1::before { content: "\f759"; } +.bi-filetype-ppt::before { content: "\f75a"; } +.bi-filetype-psd::before { content: "\f75b"; } +.bi-filetype-py::before { content: "\f75c"; } +.bi-filetype-raw::before { content: "\f75d"; } +.bi-filetype-rb::before { content: "\f75e"; } +.bi-filetype-sass::before { content: "\f75f"; } +.bi-filetype-scss::before { content: "\f760"; } +.bi-filetype-sh::before { content: "\f761"; } +.bi-filetype-svg::before { content: "\f762"; } +.bi-filetype-tiff::before { content: "\f763"; } +.bi-filetype-tsx::before { content: "\f764"; } +.bi-filetype-ttf::before { content: "\f765"; } +.bi-filetype-txt::before { content: "\f766"; } +.bi-filetype-wav::before { content: "\f767"; } +.bi-filetype-woff::before { content: "\f768"; } +.bi-filetype-xls-1::before { content: "\f769"; } +.bi-filetype-xls::before { content: "\f76a"; } +.bi-filetype-xml::before { content: "\f76b"; } +.bi-filetype-yml::before { content: "\f76c"; } +.bi-heart-arrow::before { content: "\f76d"; } +.bi-heart-pulse-fill::before { content: "\f76e"; } +.bi-heart-pulse::before { content: "\f76f"; } +.bi-heartbreak-fill::before { content: "\f770"; } +.bi-heartbreak::before { content: "\f771"; } +.bi-hearts::before { content: "\f772"; } +.bi-hospital-fill::before { content: "\f773"; } +.bi-hospital::before { content: "\f774"; } +.bi-house-heart-fill::before { content: "\f775"; } +.bi-house-heart::before { content: "\f776"; } +.bi-incognito::before { content: "\f777"; } +.bi-magnet-fill::before { content: "\f778"; } +.bi-magnet::before { content: "\f779"; } +.bi-person-heart::before { content: "\f77a"; } +.bi-person-hearts::before { content: "\f77b"; } +.bi-phone-flip::before { content: "\f77c"; } +.bi-plugin::before { content: "\f77d"; } +.bi-postage-fill::before { content: "\f77e"; } +.bi-postage-heart-fill::before { content: "\f77f"; } +.bi-postage-heart::before { content: "\f780"; } +.bi-postage::before { content: "\f781"; } +.bi-postcard-fill::before { content: "\f782"; } +.bi-postcard-heart-fill::before { content: "\f783"; } +.bi-postcard-heart::before { content: "\f784"; } +.bi-postcard::before { content: "\f785"; } +.bi-search-heart-fill::before { content: "\f786"; } +.bi-search-heart::before { content: "\f787"; } +.bi-sliders2-vertical::before { content: "\f788"; } +.bi-sliders2::before { content: "\f789"; } +.bi-trash3-fill::before { content: "\f78a"; } +.bi-trash3::before { content: "\f78b"; } +.bi-valentine::before { content: "\f78c"; } +.bi-valentine2::before { content: "\f78d"; } +.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } +.bi-wrench-adjustable-circle::before { content: "\f78f"; } +.bi-wrench-adjustable::before { content: "\f790"; } +.bi-filetype-json::before { content: "\f791"; } +.bi-filetype-pptx::before { content: "\f792"; } +.bi-filetype-xlsx::before { content: "\f793"; } +.bi-1-circle-1::before { content: "\f794"; } +.bi-1-circle-fill-1::before { content: "\f795"; } +.bi-1-circle-fill::before { content: "\f796"; } +.bi-1-circle::before { content: "\f797"; } +.bi-1-square-fill::before { content: "\f798"; } +.bi-1-square::before { content: "\f799"; } +.bi-2-circle-1::before { content: "\f79a"; } +.bi-2-circle-fill-1::before { content: "\f79b"; } +.bi-2-circle-fill::before { content: "\f79c"; } +.bi-2-circle::before { content: "\f79d"; } +.bi-2-square-fill::before { content: "\f79e"; } +.bi-2-square::before { content: "\f79f"; } +.bi-3-circle-1::before { content: "\f7a0"; } +.bi-3-circle-fill-1::before { content: "\f7a1"; } +.bi-3-circle-fill::before { content: "\f7a2"; } +.bi-3-circle::before { content: "\f7a3"; } +.bi-3-square-fill::before { content: "\f7a4"; } +.bi-3-square::before { content: "\f7a5"; } +.bi-4-circle-1::before { content: "\f7a6"; } +.bi-4-circle-fill-1::before { content: "\f7a7"; } +.bi-4-circle-fill::before { content: "\f7a8"; } +.bi-4-circle::before { content: "\f7a9"; } +.bi-4-square-fill::before { content: "\f7aa"; } +.bi-4-square::before { content: "\f7ab"; } +.bi-5-circle-1::before { content: "\f7ac"; } +.bi-5-circle-fill-1::before { content: "\f7ad"; } +.bi-5-circle-fill::before { content: "\f7ae"; } +.bi-5-circle::before { content: "\f7af"; } +.bi-5-square-fill::before { content: "\f7b0"; } +.bi-5-square::before { content: "\f7b1"; } +.bi-6-circle-1::before { content: "\f7b2"; } +.bi-6-circle-fill-1::before { content: "\f7b3"; } +.bi-6-circle-fill::before { content: "\f7b4"; } +.bi-6-circle::before { content: "\f7b5"; } +.bi-6-square-fill::before { content: "\f7b6"; } +.bi-6-square::before { content: "\f7b7"; } +.bi-7-circle-1::before { content: "\f7b8"; } +.bi-7-circle-fill-1::before { content: "\f7b9"; } +.bi-7-circle-fill::before { content: "\f7ba"; } +.bi-7-circle::before { content: "\f7bb"; } +.bi-7-square-fill::before { content: "\f7bc"; } +.bi-7-square::before { content: "\f7bd"; } +.bi-8-circle-1::before { content: "\f7be"; } +.bi-8-circle-fill-1::before { content: "\f7bf"; } +.bi-8-circle-fill::before { content: "\f7c0"; } +.bi-8-circle::before { content: "\f7c1"; } +.bi-8-square-fill::before { content: "\f7c2"; } +.bi-8-square::before { content: "\f7c3"; } +.bi-9-circle-1::before { content: "\f7c4"; } +.bi-9-circle-fill-1::before { content: "\f7c5"; } +.bi-9-circle-fill::before { content: "\f7c6"; } +.bi-9-circle::before { content: "\f7c7"; } +.bi-9-square-fill::before { content: "\f7c8"; } +.bi-9-square::before { content: "\f7c9"; } +.bi-airplane-engines-fill::before { content: "\f7ca"; } +.bi-airplane-engines::before { content: "\f7cb"; } +.bi-airplane-fill::before { content: "\f7cc"; } +.bi-airplane::before { content: "\f7cd"; } +.bi-alexa::before { content: "\f7ce"; } +.bi-alipay::before { content: "\f7cf"; } +.bi-android::before { content: "\f7d0"; } +.bi-android2::before { content: "\f7d1"; } +.bi-box-fill::before { content: "\f7d2"; } +.bi-box-seam-fill::before { content: "\f7d3"; } +.bi-browser-chrome::before { content: "\f7d4"; } +.bi-browser-edge::before { content: "\f7d5"; } +.bi-browser-firefox::before { content: "\f7d6"; } +.bi-browser-safari::before { content: "\f7d7"; } +.bi-c-circle-1::before { content: "\f7d8"; } +.bi-c-circle-fill-1::before { content: "\f7d9"; } +.bi-c-circle-fill::before { content: "\f7da"; } +.bi-c-circle::before { content: "\f7db"; } +.bi-c-square-fill::before { content: "\f7dc"; } +.bi-c-square::before { content: "\f7dd"; } +.bi-capsule-pill::before { content: "\f7de"; } +.bi-capsule::before { content: "\f7df"; } +.bi-car-front-fill::before { content: "\f7e0"; } +.bi-car-front::before { content: "\f7e1"; } +.bi-cassette-fill::before { content: "\f7e2"; } +.bi-cassette::before { content: "\f7e3"; } +.bi-cc-circle-1::before { content: "\f7e4"; } +.bi-cc-circle-fill-1::before { content: "\f7e5"; } +.bi-cc-circle-fill::before { content: "\f7e6"; } +.bi-cc-circle::before { content: "\f7e7"; } +.bi-cc-square-fill::before { content: "\f7e8"; } +.bi-cc-square::before { content: "\f7e9"; } +.bi-cup-hot-fill::before { content: "\f7ea"; } +.bi-cup-hot::before { content: "\f7eb"; } +.bi-currency-rupee::before { content: "\f7ec"; } +.bi-dropbox::before { content: "\f7ed"; } +.bi-escape::before { content: "\f7ee"; } +.bi-fast-forward-btn-fill::before { content: "\f7ef"; } +.bi-fast-forward-btn::before { content: "\f7f0"; } +.bi-fast-forward-circle-fill::before { content: "\f7f1"; } +.bi-fast-forward-circle::before { content: "\f7f2"; } +.bi-fast-forward-fill::before { content: "\f7f3"; } +.bi-fast-forward::before { content: "\f7f4"; } +.bi-filetype-sql::before { content: "\f7f5"; } +.bi-fire::before { content: "\f7f6"; } +.bi-google-play::before { content: "\f7f7"; } +.bi-h-circle-1::before { content: "\f7f8"; } +.bi-h-circle-fill-1::before { content: "\f7f9"; } +.bi-h-circle-fill::before { content: "\f7fa"; } +.bi-h-circle::before { content: "\f7fb"; } +.bi-h-square-fill::before { content: "\f7fc"; } +.bi-h-square::before { content: "\f7fd"; } +.bi-indent::before { content: "\f7fe"; } +.bi-lungs-fill::before { content: "\f7ff"; } +.bi-lungs::before { content: "\f800"; } +.bi-microsoft-teams::before { content: "\f801"; } +.bi-p-circle-1::before { content: "\f802"; } +.bi-p-circle-fill-1::before { content: "\f803"; } +.bi-p-circle-fill::before { content: "\f804"; } +.bi-p-circle::before { content: "\f805"; } +.bi-p-square-fill::before { content: "\f806"; } +.bi-p-square::before { content: "\f807"; } +.bi-pass-fill::before { content: "\f808"; } +.bi-pass::before { content: "\f809"; } +.bi-prescription::before { content: "\f80a"; } +.bi-prescription2::before { content: "\f80b"; } +.bi-r-circle-1::before { content: "\f80c"; } +.bi-r-circle-fill-1::before { content: "\f80d"; } +.bi-r-circle-fill::before { content: "\f80e"; } +.bi-r-circle::before { content: "\f80f"; } +.bi-r-square-fill::before { content: "\f810"; } +.bi-r-square::before { content: "\f811"; } +.bi-repeat-1::before { content: "\f812"; } +.bi-repeat::before { content: "\f813"; } +.bi-rewind-btn-fill::before { content: "\f814"; } +.bi-rewind-btn::before { content: "\f815"; } +.bi-rewind-circle-fill::before { content: "\f816"; } +.bi-rewind-circle::before { content: "\f817"; } +.bi-rewind-fill::before { content: "\f818"; } +.bi-rewind::before { content: "\f819"; } +.bi-train-freight-front-fill::before { content: "\f81a"; } +.bi-train-freight-front::before { content: "\f81b"; } +.bi-train-front-fill::before { content: "\f81c"; } +.bi-train-front::before { content: "\f81d"; } +.bi-train-lightrail-front-fill::before { content: "\f81e"; } +.bi-train-lightrail-front::before { content: "\f81f"; } +.bi-truck-front-fill::before { content: "\f820"; } +.bi-truck-front::before { content: "\f821"; } +.bi-ubuntu::before { content: "\f822"; } +.bi-unindent::before { content: "\f823"; } +.bi-unity::before { content: "\f824"; } +.bi-universal-access-circle::before { content: "\f825"; } +.bi-universal-access::before { content: "\f826"; } +.bi-virus::before { content: "\f827"; } +.bi-virus2::before { content: "\f828"; } +.bi-wechat::before { content: "\f829"; } +.bi-yelp::before { content: "\f82a"; } +.bi-sign-stop-fill::before { content: "\f82b"; } +.bi-sign-stop-lights-fill::before { content: "\f82c"; } +.bi-sign-stop-lights::before { content: "\f82d"; } +.bi-sign-stop::before { content: "\f82e"; } +.bi-sign-turn-left-fill::before { content: "\f82f"; } +.bi-sign-turn-left::before { content: "\f830"; } +.bi-sign-turn-right-fill::before { content: "\f831"; } +.bi-sign-turn-right::before { content: "\f832"; } +.bi-sign-turn-slight-left-fill::before { content: "\f833"; } +.bi-sign-turn-slight-left::before { content: "\f834"; } +.bi-sign-turn-slight-right-fill::before { content: "\f835"; } +.bi-sign-turn-slight-right::before { content: "\f836"; } +.bi-sign-yield-fill::before { content: "\f837"; } +.bi-sign-yield::before { content: "\f838"; } +.bi-ev-station-fill::before { content: "\f839"; } +.bi-ev-station::before { content: "\f83a"; } +.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } +.bi-fuel-pump-diesel::before { content: "\f83c"; } +.bi-fuel-pump-fill::before { content: "\f83d"; } +.bi-fuel-pump::before { content: "\f83e"; } +.bi-0-circle-fill::before { content: "\f83f"; } +.bi-0-circle::before { content: "\f840"; } +.bi-0-square-fill::before { content: "\f841"; } +.bi-0-square::before { content: "\f842"; } +.bi-rocket-fill::before { content: "\f843"; } +.bi-rocket-takeoff-fill::before { content: "\f844"; } +.bi-rocket-takeoff::before { content: "\f845"; } +.bi-rocket::before { content: "\f846"; } +.bi-stripe::before { content: "\f847"; } +.bi-subscript::before { content: "\f848"; } +.bi-superscript::before { content: "\f849"; } +.bi-trello::before { content: "\f84a"; } +.bi-envelope-at-fill::before { content: "\f84b"; } +.bi-envelope-at::before { content: "\f84c"; } +.bi-regex::before { content: "\f84d"; } +.bi-text-wrap::before { content: "\f84e"; } +.bi-sign-dead-end-fill::before { content: "\f84f"; } +.bi-sign-dead-end::before { content: "\f850"; } +.bi-sign-do-not-enter-fill::before { content: "\f851"; } +.bi-sign-do-not-enter::before { content: "\f852"; } +.bi-sign-intersection-fill::before { content: "\f853"; } +.bi-sign-intersection-side-fill::before { content: "\f854"; } +.bi-sign-intersection-side::before { content: "\f855"; } +.bi-sign-intersection-t-fill::before { content: "\f856"; } +.bi-sign-intersection-t::before { content: "\f857"; } +.bi-sign-intersection-y-fill::before { content: "\f858"; } +.bi-sign-intersection-y::before { content: "\f859"; } +.bi-sign-intersection::before { content: "\f85a"; } +.bi-sign-merge-left-fill::before { content: "\f85b"; } +.bi-sign-merge-left::before { content: "\f85c"; } +.bi-sign-merge-right-fill::before { content: "\f85d"; } +.bi-sign-merge-right::before { content: "\f85e"; } +.bi-sign-no-left-turn-fill::before { content: "\f85f"; } +.bi-sign-no-left-turn::before { content: "\f860"; } +.bi-sign-no-parking-fill::before { content: "\f861"; } +.bi-sign-no-parking::before { content: "\f862"; } +.bi-sign-no-right-turn-fill::before { content: "\f863"; } +.bi-sign-no-right-turn::before { content: "\f864"; } +.bi-sign-railroad-fill::before { content: "\f865"; } +.bi-sign-railroad::before { content: "\f866"; } +.bi-building-add::before { content: "\f867"; } +.bi-building-check::before { content: "\f868"; } +.bi-building-dash::before { content: "\f869"; } +.bi-building-down::before { content: "\f86a"; } +.bi-building-exclamation::before { content: "\f86b"; } +.bi-building-fill-add::before { content: "\f86c"; } +.bi-building-fill-check::before { content: "\f86d"; } +.bi-building-fill-dash::before { content: "\f86e"; } +.bi-building-fill-down::before { content: "\f86f"; } +.bi-building-fill-exclamation::before { content: "\f870"; } +.bi-building-fill-gear::before { content: "\f871"; } +.bi-building-fill-lock::before { content: "\f872"; } +.bi-building-fill-slash::before { content: "\f873"; } +.bi-building-fill-up::before { content: "\f874"; } +.bi-building-fill-x::before { content: "\f875"; } +.bi-building-fill::before { content: "\f876"; } +.bi-building-gear::before { content: "\f877"; } +.bi-building-lock::before { content: "\f878"; } +.bi-building-slash::before { content: "\f879"; } +.bi-building-up::before { content: "\f87a"; } +.bi-building-x::before { content: "\f87b"; } +.bi-buildings-fill::before { content: "\f87c"; } +.bi-buildings::before { content: "\f87d"; } +.bi-bus-front-fill::before { content: "\f87e"; } +.bi-bus-front::before { content: "\f87f"; } +.bi-ev-front-fill::before { content: "\f880"; } +.bi-ev-front::before { content: "\f881"; } +.bi-globe-americas::before { content: "\f882"; } +.bi-globe-asia-australia::before { content: "\f883"; } +.bi-globe-central-south-asia::before { content: "\f884"; } +.bi-globe-europe-africa::before { content: "\f885"; } +.bi-house-add-fill::before { content: "\f886"; } +.bi-house-add::before { content: "\f887"; } +.bi-house-check-fill::before { content: "\f888"; } +.bi-house-check::before { content: "\f889"; } +.bi-house-dash-fill::before { content: "\f88a"; } +.bi-house-dash::before { content: "\f88b"; } +.bi-house-down-fill::before { content: "\f88c"; } +.bi-house-down::before { content: "\f88d"; } +.bi-house-exclamation-fill::before { content: "\f88e"; } +.bi-house-exclamation::before { content: "\f88f"; } +.bi-house-gear-fill::before { content: "\f890"; } +.bi-house-gear::before { content: "\f891"; } +.bi-house-lock-fill::before { content: "\f892"; } +.bi-house-lock::before { content: "\f893"; } +.bi-house-slash-fill::before { content: "\f894"; } +.bi-house-slash::before { content: "\f895"; } +.bi-house-up-fill::before { content: "\f896"; } +.bi-house-up::before { content: "\f897"; } +.bi-house-x-fill::before { content: "\f898"; } +.bi-house-x::before { content: "\f899"; } +.bi-person-add::before { content: "\f89a"; } +.bi-person-down::before { content: "\f89b"; } +.bi-person-exclamation::before { content: "\f89c"; } +.bi-person-fill-add::before { content: "\f89d"; } +.bi-person-fill-check::before { content: "\f89e"; } +.bi-person-fill-dash::before { content: "\f89f"; } +.bi-person-fill-down::before { content: "\f8a0"; } +.bi-person-fill-exclamation::before { content: "\f8a1"; } +.bi-person-fill-gear::before { content: "\f8a2"; } +.bi-person-fill-lock::before { content: "\f8a3"; } +.bi-person-fill-slash::before { content: "\f8a4"; } +.bi-person-fill-up::before { content: "\f8a5"; } +.bi-person-fill-x::before { content: "\f8a6"; } +.bi-person-gear::before { content: "\f8a7"; } +.bi-person-lock::before { content: "\f8a8"; } +.bi-person-slash::before { content: "\f8a9"; } +.bi-person-up::before { content: "\f8aa"; } +.bi-scooter::before { content: "\f8ab"; } +.bi-taxi-front-fill::before { content: "\f8ac"; } +.bi-taxi-front::before { content: "\f8ad"; } +.bi-amd::before { content: "\f8ae"; } +.bi-database-add::before { content: "\f8af"; } +.bi-database-check::before { content: "\f8b0"; } +.bi-database-dash::before { content: "\f8b1"; } +.bi-database-down::before { content: "\f8b2"; } +.bi-database-exclamation::before { content: "\f8b3"; } +.bi-database-fill-add::before { content: "\f8b4"; } +.bi-database-fill-check::before { content: "\f8b5"; } +.bi-database-fill-dash::before { content: "\f8b6"; } +.bi-database-fill-down::before { content: "\f8b7"; } +.bi-database-fill-exclamation::before { content: "\f8b8"; } +.bi-database-fill-gear::before { content: "\f8b9"; } +.bi-database-fill-lock::before { content: "\f8ba"; } +.bi-database-fill-slash::before { content: "\f8bb"; } +.bi-database-fill-up::before { content: "\f8bc"; } +.bi-database-fill-x::before { content: "\f8bd"; } +.bi-database-fill::before { content: "\f8be"; } +.bi-database-gear::before { content: "\f8bf"; } +.bi-database-lock::before { content: "\f8c0"; } +.bi-database-slash::before { content: "\f8c1"; } +.bi-database-up::before { content: "\f8c2"; } +.bi-database-x::before { content: "\f8c3"; } +.bi-database::before { content: "\f8c4"; } +.bi-houses-fill::before { content: "\f8c5"; } +.bi-houses::before { content: "\f8c6"; } +.bi-nvidia::before { content: "\f8c7"; } +.bi-person-vcard-fill::before { content: "\f8c8"; } +.bi-person-vcard::before { content: "\f8c9"; } +.bi-sina-weibo::before { content: "\f8ca"; } +.bi-tencent-qq::before { content: "\f8cb"; } +.bi-wikipedia::before { content: "\f8cc"; } diff --git a/docs/site_libs/bootstrap/bootstrap-icons.woff b/docs/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..18d21d457558d4dc2e231a8f6ee585fada9c6bab GIT binary patch literal 164168 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%0D{F7My?sp4b~Pd<-wWT`E3Pn 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%0Aub6*Q4?Lh?RzF3+=+IGMyc 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

    V5sL;~RGzKe44( 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࿣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

    E0Q>dwTHGr5Eml?v4A4cqksyc*{&0*B}<_UWD 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 N7Xi?h+IjWj{{hmn!3F>T literal 0 HcmV?d00001 diff --git a/docs/site_libs/bootstrap/bootstrap.min.css b/docs/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 00000000..600dbd9e --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,10 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #373a3c;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #373a3c;--bs-gray-900: #212529;--bs-default: #373a3c;--bs-primary: #2780e3;--bs-secondary: #373a3c;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #373a3c;--bs-default-rgb: 55, 58, 60;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 55, 58, 60;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 55, 58, 60;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 55, 58, 60;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #373a3c;--bs-body-bg: #fff}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-bs-original-title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#1f66b6}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr /* rtl:ignore */;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f7f7f7;padding:.5rem;border:1px solid #dee2e6}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:#9753b8;background-color:#f7f7f7;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #373a3c;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #373a3c;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #373a3c;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#373a3c;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid #b6babc}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #d4e6f9;--bs-table-striped-bg: #c9dbed;--bs-table-striped-color: #000;--bs-table-active-bg: #bfcfe0;--bs-table-active-color: #000;--bs-table-hover-bg: #c4d5e6;--bs-table-hover-color: #000;color:#000;border-color:#bfcfe0}.table-secondary{--bs-table-bg: #d7d8d8;--bs-table-striped-bg: #cccdcd;--bs-table-striped-color: #000;--bs-table-active-bg: #c2c2c2;--bs-table-active-color: #000;--bs-table-hover-bg: #c7c8c8;--bs-table-hover-color: #000;color:#000;border-color:#c2c2c2}.table-success{--bs-table-bg: #d9f0d1;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:#000;border-color:#c3d8bc}.table-info{--bs-table-bg: #ebddf1;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:#000;border-color:#d4c7d9}.table-warning{--bs-table-bg: #ffe3d1;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:#000;border-color:#e6ccbc}.table-danger{--bs-table-bg: #ffccd7;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:#000;border-color:#e6b8c2}.table-light{--bs-table-bg: #f8f9fa;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #373a3c;--bs-table-striped-bg: #414446;--bs-table-striped-color: #fff;--bs-table-active-bg: #4b4e50;--bs-table-active-color: #fff;--bs-table-hover-bg: #46494b;--bs-table-hover-color: #fff;color:#fff;border-color:#4b4e50}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#373a3c;background-color:#fff;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#373a3c;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px);padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em}.form-control-color::-webkit-color-swatch{height:1.5em}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #373a3c}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2393c0f1'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:rgba(0,0,0,0);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bed9f7}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#bed9f7}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(63,182,24,.9)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group .form-control:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(255,0,57,.9)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group .form-control:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);padding:.375rem .75rem;font-size:1rem;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#373a3c}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-default:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-default,.btn-default:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-default:disabled,.btn-default.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-primary{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-primary:hover{color:#fff;background-color:#216dc1;border-color:#1f66b6}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#216dc1;border-color:#1f66b6;box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#1f66b6;border-color:#1d60aa}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-secondary{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-secondary:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-success{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-success:hover{color:#fff;background-color:#369b14;border-color:#329213}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#369b14;border-color:#329213;box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#329213;border-color:#2f8912}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-info{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-info:hover{color:#fff;background-color:#82479f;border-color:#7a4396}.btn-check:focus+.btn-info,.btn-info:focus{color:#fff;background-color:#82479f;border-color:#7a4396;box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#7a4396;border-color:#733f8c}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-info:disabled,.btn-info.disabled{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-warning{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-warning:hover{color:#fff;background-color:#d96314;border-color:#cc5e13}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#fff;background-color:#d96314;border-color:#cc5e13;box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#cc5e13;border-color:#bf5812}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-danger{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-danger:hover{color:#fff;background-color:#d90030;border-color:#cc002e}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#d90030;border-color:#cc002e;box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#cc002e;border-color:#bf002b}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-dark:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-outline-default{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-default:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-primary{color:#2780e3;border-color:#2780e3;background-color:rgba(0,0,0,0)}.btn-outline-primary:hover{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#2780e3;background-color:rgba(0,0,0,0)}.btn-outline-secondary{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-secondary:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-success{color:#3fb618;border-color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-success:hover{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-info{color:#9954bb;border-color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-info:hover{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-warning{color:#ff7518;border-color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-warning:hover{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-danger{color:#ff0039;border-color:#ff0039;background-color:rgba(0,0,0,0)}.btn-outline-danger:hover{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#ff0039;background-color:rgba(0,0,0,0)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-dark{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-dark:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-link{font-weight:400;color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#1f66b6}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:0}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#2780e3}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#373a3c;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#2780e3}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.nav{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:#1f66b6}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px}.nav-pills .nav-link{background:none;border:0}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#2780e3}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:.25 0;font-size:1.25rem;line-height:1;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);transition:box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#f8f9fa}.navbar-light .navbar-brand{color:#545555}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#1a5698}.navbar-light .navbar-nav .nav-link{color:#545555}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(26,86,152,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(84,85,85,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#1a5698}.navbar-light .navbar-toggler{color:#545555;border-color:rgba(84,85,85,0)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23545555' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#545555}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#1a5698}.navbar-dark{background-color:#f8f9fa}.navbar-dark .navbar-brand{color:#545555}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#1a5698}.navbar-dark .navbar-nav .nav-link{color:#545555}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(26,86,152,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(84,85,85,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#1a5698}.navbar-dark .navbar-toggler{color:#545555;border-color:rgba(84,85,85,0)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23545555' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#545555}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#1a5698}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:#adb5bd;border-bottom:1px solid rgba(0,0,0,.125)}.card-footer{padding:.5rem 1rem;background-color:#adb5bd;border-top:1px solid rgba(0,0,0,.125)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:.75rem}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#373a3c;text-align:left;background-color:#fff;border:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#2373cc;background-color:#e9f2fc;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%232373cc'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23373a3c'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#1f66b6;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#1f66b6;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#2780e3;border-color:#2780e3}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:0 solid rgba(0,0,0,0)}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-default .alert-link{color:#1a1c1d}.alert-primary{color:#174d88;background-color:#d4e6f9;border-color:#bed9f7}.alert-primary .alert-link{color:#123e6d}.alert-secondary{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-secondary .alert-link{color:#1a1c1d}.alert-success{color:#266d0e;background-color:#d9f0d1;border-color:#c5e9ba}.alert-success .alert-link{color:#1e570b}.alert-info{color:#5c3270;background-color:#ebddf1;border-color:#e0cceb}.alert-info .alert-link{color:#4a285a}.alert-warning{color:#99460e;background-color:#ffe3d1;border-color:#ffd6ba}.alert-warning .alert-link{color:#7a380b}.alert-danger{color:#902;background-color:#ffccd7;border-color:#ffb3c4}.alert-danger .alert-link{color:#7a001b}.alert-light{color:#959596;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#777778}.alert-dark{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-dark .alert-link{color:#1a1c1d}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress{display:flex;display:-webkit-flex;height:.5rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#2780e3;transition:width .6s ease}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:.5rem .5rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#373a3c;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#2780e3;border-color:#2780e3}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#212324;background-color:#d7d8d8}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-primary{color:#174d88;background-color:#d4e6f9}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#174d88;background-color:#bfcfe0}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#174d88;border-color:#174d88}.list-group-item-secondary{color:#212324;background-color:#d7d8d8}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-success{color:#266d0e;background-color:#d9f0d1}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#266d0e;background-color:#c3d8bc}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#266d0e;border-color:#266d0e}.list-group-item-info{color:#5c3270;background-color:#ebddf1}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#5c3270;background-color:#d4c7d9}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#5c3270;border-color:#5c3270}.list-group-item-warning{color:#99460e;background-color:#ffe3d1}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#99460e;background-color:#e6ccbc}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#99460e;border-color:#99460e}.list-group-item-danger{color:#902;background-color:#ffccd7}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#902;background-color:#e6b8c2}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#902;border-color:#902}.list-group-item-light{color:#959596;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#959596;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#959596;border-color:#959596}.list-group-item-dark{color:#212324;background-color:#d7d8d8}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:rgba(0,0,0,0) url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25);opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2)}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#373a3c}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:rgba(0,0,0,0);border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-default{color:#373a3c}.link-default:hover,.link-default:focus{color:#2c2e30}.link-primary{color:#2780e3}.link-primary:hover,.link-primary:focus{color:#1f66b6}.link-secondary{color:#373a3c}.link-secondary:hover,.link-secondary:focus{color:#2c2e30}.link-success{color:#3fb618}.link-success:hover,.link-success:focus{color:#329213}.link-info{color:#9954bb}.link-info:hover,.link-info:focus{color:#7a4396}.link-warning{color:#ff7518}.link-warning:hover,.link-warning:focus{color:#cc5e13}.link-danger{color:#ff0039}.link-danger:hover,.link-danger:focus{color:#cc002e}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#373a3c}.link-dark:hover,.link-dark:focus{color:#2c2e30}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#373a3c !important}.border-primary{border-color:#2780e3 !important}.border-secondary{border-color:#373a3c !important}.border-success{border-color:#3fb618 !important}.border-info{border-color:#9954bb !important}.border-warning{border-color:#ff7518 !important}.border-danger{border-color:#ff0039 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#373a3c !important}.border-white{border-color:#fff !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:#6c757d !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2em !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.sidebar-item .chapter-number{color:#373a3c}.quarto-container{min-height:calc(100vh - 132px)}footer.footer .nav-footer,#quarto-header>nav{padding-left:1em;padding-right:1em}nav[role=doc-toc]{padding-left:.5em}#quarto-content>*{padding-top:14px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:position 200ms linear;transition:all 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 115px);min-width:0;display:flex;align-items:center}@media(min-width: 992px){.navbar-brand-container{margin-right:1em}}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar .navbar-toggler{order:-1;margin-right:.5em}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar .quarto-navbar-tools div.dropdown{display:inline-block}.navbar .quarto-navbar-tools .quarto-navigation-tool{color:#545555}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:#1a5698}@media(max-width: 991.98px){.navbar .quarto-navbar-tools{margin-top:.25em;padding-top:.75em;display:block;color:solid #d4d4d4 1px;text-align:center;vertical-align:middle;margin-right:auto}}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}@media(max-width: 991.98px){#quarto-sidebar div.sidebar-header{padding-top:.2em}}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .quarto-navigation-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{display:inline-flex;margin-left:0px;order:2}.sidebar-tools-main:not(.tools-wide){vertical-align:middle}.sidebar-navigation .quarto-navigation-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em}.sidebar-section{margin-top:.2em;padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between}.sidebar-item-toggle:hover{cursor:pointer}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-item .sidebar-item-toggle .bi-chevron-right::before{transition:transform 200ms ease}.sidebar-item .sidebar-item-toggle[aria-expanded=false] .bi-chevron-right::before{transform:none}.sidebar-item .sidebar-item-toggle[aria-expanded=true] .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 991.98px){.quarto-secondary-nav{display:block}.quarto-secondary-nav button.quarto-search-button{padding-right:0em;padding-left:2em}.quarto-secondary-nav button.quarto-btn-toggle{margin-left:-0.75rem;margin-right:.15rem}.quarto-secondary-nav nav.quarto-page-breadcrumbs{display:flex;align-items:center;padding-right:1em;margin-left:-0.25em}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{text-decoration:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs ol.breadcrumb{margin-bottom:0}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-secondary-nav .quarto-btn-toggle{color:#595959}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.quarto-secondary-nav-title{margin-top:.3em;color:#595959;padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(27,88,157,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:#8c8c8c}div.sidebar-item-container{color:#595959}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(27,88,157,.8)}div.sidebar-item-container.disabled{color:rgba(89,89,89,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#1b589d}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{min-height:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}#quarto-sidebar{transition:width .15s ease-in}#quarto-sidebar>*{padding-right:1em}@media(max-width: 991.98px){#quarto-sidebar .sidebar-menu-container{white-space:nowrap;min-width:225px}#quarto-sidebar.show{transition:width .15s ease-out}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}@media(max-width: 991.98px){#quarto-sidebar-glass{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(255,255,255,0);transition:background-color .15s ease-in;z-index:-1}#quarto-sidebar-glass.collapsing{z-index:1000}#quarto-sidebar-glass.show{transition:background-color .15s ease-out;background-color:rgba(102,102,102,.4);z-index:1000}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}.quarto-page-breadcrumbs .breadcrumb-item+.breadcrumb-item,.quarto-page-breadcrumbs .breadcrumb-item{padding-right:.33em;padding-left:0}.quarto-page-breadcrumbs .breadcrumb-item::before{padding-right:.33em}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section .bi-chevron-right::before{font-size:.9em}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:#1f66b6}.toc-actions{display:flex}.toc-actions p{margin-block-start:0;margin-block-end:0}.toc-actions a{text-decoration:none;color:inherit;font-weight:400}.toc-actions a:hover{color:#1f66b6}.toc-actions .action-links{margin-left:4px}.sidebar nav[role=doc-toc] .toc-actions .bi{margin-left:-4px;font-size:.7rem;color:#6c757d}.sidebar nav[role=doc-toc] .toc-actions .bi:before{padding-top:3px}#quarto-margin-sidebar .toc-actions .bi:before{margin-top:.3rem;font-size:.7rem;color:#6c757d;vertical-align:top}.sidebar nav[role=doc-toc] .toc-actions>div:first-of-type{margin-top:-3px}#quarto-margin-sidebar .toc-actions p,.sidebar nav[role=doc-toc] .toc-actions p{font-size:.875rem}.nav-footer .toc-actions{padding-bottom:.5em;padding-top:.5em}.nav-footer .toc-actions :first-child{margin-left:auto}.nav-footer .toc-actions :last-child{margin-right:auto}.nav-footer .toc-actions .action-links{display:flex}.nav-footer .toc-actions .action-links p{padding-right:1.5em}.nav-footer .toc-actions .action-links p:last-of-type{padding-right:0}.nav-footer{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:64px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:#757575}.nav-footer a{color:#757575}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:inline-flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}.nav-footer-left{flex:1 1 0px;text-align:left}.nav-footer-right{flex:1 1 0px;text-align:right}.nav-footer-center{flex:1 1 0px;min-height:3em;text-align:center}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em}}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:#545555;border-radius:3px}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:#595959;border-radius:3px}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.2em;padding-right:.2em;margin-left:-0.2em;margin-right:-0.2em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}#quarto-back-to-top{display:none;position:fixed;bottom:50px;background-color:#fff;border-radius:.25rem;box-shadow:0 .2rem .5rem #6c757d,0 0 .05rem #6c757d;color:#6c757d;text-decoration:none;font-size:.9em;text-align:center;left:50%;padding:.4rem .8rem;transform:translate(-50%, 0)}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:.25rem;order:999}}@media(max-width: 991.98px){#quarto-sidebar .sidebar-search{display:none}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:#545555;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#545555;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#373a3c;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#373a3c;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#373a3c;font:inherit;height:calc(1.5em + .1rem + 2px);padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#373a3c;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#373a3c;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}.aa-PanelLayout:empty{display:none}.quarto-search-no-results.no-query{display:none}.aa-Source:has(.no-query){display:none}#quarto-search-results .aa-Panel{border:solid #ced4da 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:#f2f2f2;padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#fff;background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#fff;background-color:#4b95e8}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#373a3c}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:#e5effc}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#ced4da;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:44px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #ced4da}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#545555}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#595959}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:rgba(255,255,255,.65);width:90%;bottom:0;box-shadow:rgba(206,212,218,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #ced4da;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#373a3c;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{bottom:inherit;height:auto;margin:0 auto;position:absolute;top:100px;border-radius:6px;max-width:850px}@media(max-width: 575.98px){.aa-DetachedContainer--modal{width:100%;top:0px;border-radius:0px;border:none}}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(55,58,60,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#373a3c;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item p.card-img-top>img{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item .listing-item-img-placeholder{background-color:#adb5bd;flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post a{color:#373a3c;display:flex;flex-direction:column;text-decoration:none}div.quarto-post a div.description{flex-shrink:0}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:var(--bs-font-sans-serif);flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#2780e3}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#2780e3}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#2780e3}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#2780e3}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#2780e3}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.25rem;color:#373a3c;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#373a3c}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:inline-block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,.table{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #fff;--quarto-body-color: #373a3c;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:absolute;right:.5em;left:inherit;background-color:rgba(0,0,0,0)}:root{--mermaid-bg-color: #fff;--mermaid-edge-color: #373a3c;--mermaid-node-fg-color: #373a3c;--mermaid-fg-color: #373a3c;--mermaid-fg-color--lighter: #4f5457;--mermaid-fg-color--lightest: #686d71;--mermaid-font-family: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;--mermaid-label-bg-color: #fff;--mermaid-label-fg-color: #2780e3;--mermaid-node-bg-color: rgba(39, 128, 227, 0.1);--mermaid-node-fg-color: #373a3c}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 1250px - 3em )) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{opacity:.9;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#747a7f}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:.9rem}.panel-caption,.figure-caption,figcaption{color:#747a7f}.table-caption,caption{color:#373a3c}.quarto-layout-cell[data-ref-parent] caption{color:#747a7f}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#747a7f;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#747a7f}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f7f7f7;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:#6c757d;margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#2780e3}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.sidebar .quarto-alternate-formats a,.sidebar .quarto-alternate-notebooks a{text-decoration:none}.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#2780e3}.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2{margin-top:1rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul,.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #2780e3;color:#2780e3 !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#2780e3 !important}kbd,.kbd{color:#373a3c;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.table a{word-break:break-word}.table>thead{border-top-width:1px;border-top-color:#dee2e6;border-bottom:1px solid #b6babc}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout.callout-titled .callout-body{margin-top:.2em}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){margin-bottom:.5rem}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2fc}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:#ecf8e8}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:#fff1e8}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:#fef7ed}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:#ffe6eb}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#373a3c}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{color:#cbcccc;background-color:#373a3c;border-color:#373a3c}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#cbcccc;background-color:#555859;border-color:#4b4e50}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#cbcccc;background-color:#555859;border-color:#4b4e50;box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#fff;background-color:#5f6163;border-color:#4b4e50}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}nav.quarto-secondary-nav.color-navbar{background-color:#f8f9fa;color:#545555}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#545555}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:0}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:var(--bs-font-monospace);color:#4f5457;border:solid #4f5457 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:var(--bs-font-monospace);color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table>thead{border-top-width:0}.table>:not(caption)>*:not(:last-child)>*{border-bottom-color:#ebeced;border-bottom-style:solid;border-bottom-width:1px}.table>:not(:first-child){border-top:1px solid #b6babc;border-bottom:1px solid inherit}.table tbody{border-bottom-color:#b6babc}a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file,.code-with-filename .code-with-filename-file pre{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file,.quarto-dark .code-with-filename .code-with-filename-file pre{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#545555;background:#f8f9fa}.quarto-title-banner .code-tools-button{color:#878888}.quarto-title-banner .code-tools-button:hover{color:#545555}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-5px}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents a{color:#373a3c}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:1fr 1fr}.quarto-title-tools-only{display:flex;justify-content:right}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#373a3c}.progress .progress-bar{font-size:8px;line-height:8px}/*# sourceMappingURL=038018dfc50d695214e8253e62c2ede5.css.map */ diff --git a/docs/site_libs/bootstrap/bootstrap.min.js b/docs/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 00000000..cc0a2556 --- /dev/null +++ b/docs/site_libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'

    ',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/docs/site_libs/clipboard/clipboard.min.js b/docs/site_libs/clipboard/clipboard.min.js new file mode 100644 index 00000000..1103f811 --- /dev/null +++ b/docs/site_libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); +// @license-end \ No newline at end of file diff --git a/docs/site_libs/quarto-html/popper.min.js b/docs/site_libs/quarto-html/popper.min.js new file mode 100644 index 00000000..2269d669 --- /dev/null +++ b/docs/site_libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.4 - MIT License + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(e,t){void 0===t&&(t=!1);var n=e.getBoundingClientRect(),o=1,i=1;if(r(e)&&t){var a=e.offsetHeight,f=e.offsetWidth;f>0&&(o=s(n.width)/f||1),a>0&&(i=s(n.height)/a||1)}return{width:n.width/o,height:n.height/i,top:n.top/i,right:n.right/o,bottom:n.bottom/i,left:n.left/o,x:n.left/o,y:n.top/i}}function c(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function p(e){return e?(e.nodeName||"").toLowerCase():null}function u(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function l(e){return f(u(e)).left+c(e).scrollLeft}function d(e){return t(e).getComputedStyle(e)}function h(e){var t=d(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function m(e,n,o){void 0===o&&(o=!1);var i,a,d=r(n),m=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),v=u(n),g=f(e,m),y={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(d||!d&&!o)&&(("body"!==p(n)||h(v))&&(y=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:c(i)),r(n)?((b=f(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):v&&(b.x=l(v))),{x:g.left+y.scrollLeft-b.x,y:g.top+y.scrollTop-b.y,width:g.width,height:g.height}}function v(e){var t=f(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function g(e){return"html"===p(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||u(e)}function y(e){return["html","body","#document"].indexOf(p(e))>=0?e.ownerDocument.body:r(e)&&h(e)?e:y(g(e))}function b(e,n){var r;void 0===n&&(n=[]);var o=y(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],h(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(b(g(s)))}function x(e){return["table","td","th"].indexOf(p(e))>=0}function w(e){return r(e)&&"fixed"!==d(e).position?e.offsetParent:null}function O(e){for(var n=t(e),i=w(e);i&&x(i)&&"static"===d(i).position;)i=w(i);return i&&("html"===p(i)||"body"===p(i)&&"static"===d(i).position)?n:i||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&r(e)&&"fixed"===d(e).position)return null;var n=g(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(p(n))<0;){var i=d(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var j="top",E="bottom",D="right",A="left",L="auto",P=[j,E,D,A],M="start",k="end",W="viewport",B="popper",H=P.reduce((function(e,t){return e.concat([t+"-"+M,t+"-"+k])}),[]),T=[].concat(P,[L]).reduce((function(e,t){return e.concat([t,t+"-"+M,t+"-"+k])}),[]),R=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function S(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function q(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function V(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function N(e,r){return r===W?V(function(e){var n=t(e),r=u(e),o=n.visualViewport,i=r.clientWidth,a=r.clientHeight,s=0,f=0;return o&&(i=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(s=o.offsetLeft,f=o.offsetTop)),{width:i,height:a,x:s+l(e),y:f}}(e)):n(r)?function(e){var t=f(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(r):V(function(e){var t,n=u(e),r=c(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+l(e),p=-r.scrollTop;return"rtl"===d(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:p}}(u(e)))}function I(e,t,o){var s="clippingParents"===t?function(e){var t=b(g(e)),o=["absolute","fixed"].indexOf(d(e).position)>=0&&r(e)?O(e):e;return n(o)?t.filter((function(e){return n(e)&&q(e,o)&&"body"!==p(e)})):[]}(e):[].concat(t),f=[].concat(s,[o]),c=f[0],u=f.reduce((function(t,n){var r=N(e,n);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),N(e,c));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function _(e){return e.split("-")[1]}function F(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function U(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?_(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case j:t={x:s,y:n.y-r.height};break;case E:t={x:s,y:n.y+n.height};break;case D:t={x:n.x+n.width,y:f};break;case A:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?F(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case M:t[c]=t[c]-(n[p]/2-r[p]/2);break;case k:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function z(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function X(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function Y(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.boundary,s=void 0===a?"clippingParents":a,c=r.rootBoundary,p=void 0===c?W:c,l=r.elementContext,d=void 0===l?B:l,h=r.altBoundary,m=void 0!==h&&h,v=r.padding,g=void 0===v?0:v,y=z("number"!=typeof g?g:X(g,P)),b=d===B?"reference":B,x=e.rects.popper,w=e.elements[m?b:d],O=I(n(w)?w:w.contextElement||u(e.elements.popper),s,p),A=f(e.elements.reference),L=U({reference:A,element:x,strategy:"absolute",placement:i}),M=V(Object.assign({},x,L)),k=d===B?M:A,H={top:O.top-k.top+y.top,bottom:k.bottom-O.bottom+y.bottom,left:O.left-k.left+y.left,right:k.right-O.right+y.right},T=e.modifiersData.offset;if(d===B&&T){var R=T[i];Object.keys(H).forEach((function(e){var t=[D,E].indexOf(e)>=0?1:-1,n=[j,E].indexOf(e)>=0?"y":"x";H[e]+=R[n]*t}))}return H}var G={placement:"bottom",modifiers:[],strategy:"absolute"};function J(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[A,D].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},ie={left:"right",right:"left",bottom:"top",top:"bottom"};function ae(e){return e.replace(/left|right|bottom|top/g,(function(e){return ie[e]}))}var se={start:"end",end:"start"};function fe(e){return e.replace(/start|end/g,(function(e){return se[e]}))}function ce(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?T:f,p=_(r),u=p?s?H:H.filter((function(e){return _(e)===p})):P,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=Y(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var pe={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,g=C(v),y=f||(g===v||!h?[ae(v)]:function(e){if(C(e)===L)return[];var t=ae(e);return[fe(e),t,fe(t)]}(v)),b=[v].concat(y).reduce((function(e,n){return e.concat(C(n)===L?ce(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,P=!0,k=b[0],W=0;W=0,S=R?"width":"height",q=Y(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),V=R?T?D:A:T?E:j;x[S]>w[S]&&(V=ae(V));var N=ae(V),I=[];if(i&&I.push(q[H]<=0),s&&I.push(q[V]<=0,q[N]<=0),I.every((function(e){return e}))){k=B,P=!1;break}O.set(B,I)}if(P)for(var F=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return k=t,"break"},U=h?3:1;U>0;U--){if("break"===F(U))break}t.placement!==k&&(t.modifiersData[r]._skip=!0,t.placement=k,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ue(e,t,n){return i(e,a(t,n))}var le={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,g=n.tetherOffset,y=void 0===g?0:g,b=Y(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=_(t.placement),L=!w,P=F(x),k="x"===P?"y":"x",W=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,q={x:0,y:0};if(W){if(s){var V,N="y"===P?j:A,I="y"===P?E:D,U="y"===P?"height":"width",z=W[P],X=z+b[N],G=z-b[I],J=m?-H[U]/2:0,K=w===M?B[U]:H[U],Q=w===M?-H[U]:-B[U],Z=t.elements.arrow,$=m&&Z?v(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=ue(0,B[U],$[U]),oe=L?B[U]/2-J-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=L?-B[U]/2+J+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&O(t.elements.arrow),se=ae?"y"===P?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(V=null==S?void 0:S[P])?V:0,ce=z+ie-fe,pe=ue(m?a(X,z+oe-fe-se):X,z,m?i(G,ce):G);W[P]=pe,q[P]=pe-z}if(c){var le,de="x"===P?j:A,he="x"===P?E:D,me=W[k],ve="y"===k?"height":"width",ge=me+b[de],ye=me-b[he],be=-1!==[j,A].indexOf(x),xe=null!=(le=null==S?void 0:S[k])?le:0,we=be?ge:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ye,je=m&&be?function(e,t,n){var r=ue(e,t,n);return r>n?n:r}(we,me,Oe):ue(m?we:ge,me,m?Oe:ye);W[k]=je,q[k]=je-me}t.modifiersData[r]=q}},requiresIfExists:["offset"]};var de={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=F(s),c=[A,D].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return z("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:X(e,P))}(o.padding,n),u=v(i),l="y"===f?j:A,d="y"===f?E:D,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],g=O(i),y=g?"y"===f?g.clientHeight||0:g.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],L=y/2-u[c]/2+b,M=ue(x,L,w),k=f;n.modifiersData[r]=((t={})[k]=M,t.centerOffset=M-L,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&q(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function he(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function me(e){return[j,D,E,A].some((function(t){return e[t]>=0}))}var ve={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=Y(t,{elementContext:"reference"}),s=Y(t,{altBoundary:!0}),f=he(a,r),c=he(s,o,i),p=me(f),u=me(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},ge=K({defaultModifiers:[Z,$,ne,re]}),ye=[Z,$,ne,re,oe,pe,le,de,ve],be=K({defaultModifiers:ye});e.applyStyles=re,e.arrow=de,e.computeStyles=ne,e.createPopper=be,e.createPopperLite=ge,e.defaultModifiers=ye,e.detectOverflow=Y,e.eventListeners=Z,e.flip=pe,e.hide=ve,e.offset=oe,e.popperGenerator=K,e.popperOffsets=$,e.preventOverflow=le,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/site_libs/quarto-html/quarto-syntax-highlighting.css b/docs/site_libs/quarto-html/quarto-syntax-highlighting.css new file mode 100644 index 00000000..d9fd98f0 --- /dev/null +++ b/docs/site_libs/quarto-html/quarto-syntax-highlighting.css @@ -0,0 +1,203 @@ +/* quarto syntax highlight colors */ +:root { + --quarto-hl-ot-color: #003B4F; + --quarto-hl-at-color: #657422; + --quarto-hl-ss-color: #20794D; + --quarto-hl-an-color: #5E5E5E; + --quarto-hl-fu-color: #4758AB; + --quarto-hl-st-color: #20794D; + --quarto-hl-cf-color: #003B4F; + --quarto-hl-op-color: #5E5E5E; + --quarto-hl-er-color: #AD0000; + --quarto-hl-bn-color: #AD0000; + --quarto-hl-al-color: #AD0000; + --quarto-hl-va-color: #111111; + --quarto-hl-bu-color: inherit; + --quarto-hl-ex-color: inherit; + --quarto-hl-pp-color: #AD0000; + --quarto-hl-in-color: #5E5E5E; + --quarto-hl-vs-color: #20794D; + --quarto-hl-wa-color: #5E5E5E; + --quarto-hl-do-color: #5E5E5E; + --quarto-hl-im-color: #00769E; + --quarto-hl-ch-color: #20794D; + --quarto-hl-dt-color: #AD0000; + --quarto-hl-fl-color: #AD0000; + --quarto-hl-co-color: #5E5E5E; + --quarto-hl-cv-color: #5E5E5E; + --quarto-hl-cn-color: #8f5902; + --quarto-hl-sc-color: #5E5E5E; + --quarto-hl-dv-color: #AD0000; + --quarto-hl-kw-color: #003B4F; +} + +/* other quarto variables */ +:root { + --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +pre > code.sourceCode > span { + color: #003B4F; +} + +code span { + color: #003B4F; +} + +code.sourceCode > span { + color: #003B4F; +} + +div.sourceCode, +div.sourceCode pre.sourceCode { + color: #003B4F; +} + +code span.ot { + color: #003B4F; + font-style: inherit; +} + +code span.at { + color: #657422; + font-style: inherit; +} + +code span.ss { + color: #20794D; + font-style: inherit; +} + +code span.an { + color: #5E5E5E; + font-style: inherit; +} + +code span.fu { + color: #4758AB; + font-style: inherit; +} + +code span.st { + color: #20794D; + font-style: inherit; +} + +code span.cf { + color: #003B4F; + font-style: inherit; +} + +code span.op { + color: #5E5E5E; + font-style: inherit; +} + +code span.er { + color: #AD0000; + font-style: inherit; +} + +code span.bn { + color: #AD0000; + font-style: inherit; +} + +code span.al { + color: #AD0000; + font-style: inherit; +} + +code span.va { + color: #111111; + font-style: inherit; +} + +code span.bu { + font-style: inherit; +} + +code span.ex { + font-style: inherit; +} + +code span.pp { + color: #AD0000; + font-style: inherit; +} + +code span.in { + color: #5E5E5E; + font-style: inherit; +} + +code span.vs { + color: #20794D; + font-style: inherit; +} + +code span.wa { + color: #5E5E5E; + font-style: italic; +} + +code span.do { + color: #5E5E5E; + font-style: italic; +} + +code span.im { + color: #00769E; + font-style: inherit; +} + +code span.ch { + color: #20794D; + font-style: inherit; +} + +code span.dt { + color: #AD0000; + font-style: inherit; +} + +code span.fl { + color: #AD0000; + font-style: inherit; +} + +code span.co { + color: #5E5E5E; + font-style: inherit; +} + +code span.cv { + color: #5E5E5E; + font-style: italic; +} + +code span.cn { + color: #8f5902; + font-style: inherit; +} + +code span.sc { + color: #5E5E5E; + font-style: inherit; +} + +code span.dv { + color: #AD0000; + font-style: inherit; +} + +code span.kw { + color: #003B4F; + font-style: inherit; +} + +.prevent-inlining { + content: " { + // Find any conflicting margin elements and add margins to the + // top to prevent overlap + const marginChildren = window.document.querySelectorAll( + ".column-margin.column-container > * " + ); + + let lastBottom = 0; + for (const marginChild of marginChildren) { + if (marginChild.offsetParent !== null) { + // clear the top margin so we recompute it + marginChild.style.marginTop = null; + const top = marginChild.getBoundingClientRect().top + window.scrollY; + console.log({ + childtop: marginChild.getBoundingClientRect().top, + scroll: window.scrollY, + top, + lastBottom, + }); + if (top < lastBottom) { + const margin = lastBottom - top; + marginChild.style.marginTop = `${margin}px`; + } + const styles = window.getComputedStyle(marginChild); + const marginTop = parseFloat(styles["marginTop"]); + + console.log({ + top, + height: marginChild.getBoundingClientRect().height, + marginTop, + total: top + marginChild.getBoundingClientRect().height + marginTop, + }); + lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Recompute the position of margin elements anytime the body size changes + if (window.ResizeObserver) { + const resizeObserver = new window.ResizeObserver( + throttle(layoutMarginEls, 50) + ); + resizeObserver.observe(window.document.body); + } + + const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); + const sidebarEl = window.document.getElementById("quarto-sidebar"); + const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); + const marginSidebarEl = window.document.getElementById( + "quarto-margin-sidebar" + ); + // function to determine whether the element has a previous sibling that is active + const prevSiblingIsActiveLink = (el) => { + const sibling = el.previousElementSibling; + if (sibling && sibling.tagName === "A") { + return sibling.classList.contains("active"); + } else { + return false; + } + }; + + // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) + function fireSlideEnter(e) { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + } + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); + tabs.forEach((tab) => { + tab.addEventListener("shown.bs.tab", fireSlideEnter); + }); + + // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) + document.addEventListener("tabby", fireSlideEnter, false); + + // Track scrolling and mark TOC links as active + // get table of contents and sidebar (bail if we don't have at least one) + const tocLinks = tocEl + ? [...tocEl.querySelectorAll("a[data-scroll-target]")] + : []; + const makeActive = (link) => tocLinks[link].classList.add("active"); + const removeActive = (link) => tocLinks[link].classList.remove("active"); + const removeAllActive = () => + [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); + + // activate the anchor for a section associated with this TOC entry + tocLinks.forEach((link) => { + link.addEventListener("click", () => { + if (link.href.indexOf("#") !== -1) { + const anchor = link.href.split("#")[1]; + const heading = window.document.querySelector( + `[data-anchor-id=${anchor}]` + ); + if (heading) { + // Add the class + heading.classList.add("reveal-anchorjs-link"); + + // function to show the anchor + const handleMouseout = () => { + heading.classList.remove("reveal-anchorjs-link"); + heading.removeEventListener("mouseout", handleMouseout); + }; + + // add a function to clear the anchor when the user mouses out of it + heading.addEventListener("mouseout", handleMouseout); + } + } + }); + }); + + const sections = tocLinks.map((link) => { + const target = link.getAttribute("data-scroll-target"); + if (target.startsWith("#")) { + return window.document.getElementById(decodeURI(`${target.slice(1)}`)); + } else { + return window.document.querySelector(decodeURI(`${target}`)); + } + }); + + const sectionMargin = 200; + let currentActive = 0; + // track whether we've initialized state the first time + let init = false; + + const updateActiveLink = () => { + // The index from bottom to top (e.g. reversed list) + let sectionIndex = -1; + if ( + window.innerHeight + window.pageYOffset >= + window.document.body.offsetHeight + ) { + sectionIndex = 0; + } else { + sectionIndex = [...sections].reverse().findIndex((section) => { + if (section) { + return window.pageYOffset >= section.offsetTop - sectionMargin; + } else { + return false; + } + }); + } + if (sectionIndex > -1) { + const current = sections.length - sectionIndex - 1; + if (current !== currentActive) { + removeAllActive(); + currentActive = current; + makeActive(current); + if (init) { + window.dispatchEvent(sectionChanged); + } + init = true; + } + } + }; + + const inHiddenRegion = (top, bottom, hiddenRegions) => { + for (const region of hiddenRegions) { + if (top <= region.bottom && bottom >= region.top) { + return true; + } + } + return false; + }; + + const categorySelector = "header.quarto-title-block .quarto-category"; + const activateCategories = (href) => { + // Find any categories + // Surround them with a link pointing back to: + // #category=Authoring + try { + const categoryEls = window.document.querySelectorAll(categorySelector); + for (const categoryEl of categoryEls) { + const categoryText = categoryEl.textContent; + if (categoryText) { + const link = `${href}#category=${encodeURIComponent(categoryText)}`; + const linkEl = window.document.createElement("a"); + linkEl.setAttribute("href", link); + for (const child of categoryEl.childNodes) { + linkEl.append(child); + } + categoryEl.appendChild(linkEl); + } + } + } catch { + // Ignore errors + } + }; + function hasTitleCategories() { + return window.document.querySelector(categorySelector) !== null; + } + + function offsetRelativeUrl(url) { + const offset = getMeta("quarto:offset"); + return offset ? offset + url : url; + } + + function offsetAbsoluteUrl(url) { + const offset = getMeta("quarto:offset"); + const baseUrl = new URL(offset, window.location); + + const projRelativeUrl = url.replace(baseUrl, ""); + if (projRelativeUrl.startsWith("/")) { + return projRelativeUrl; + } else { + return "/" + projRelativeUrl; + } + } + + // read a meta tag value + function getMeta(metaName) { + const metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; + } + + async function findAndActivateCategories() { + const currentPagePath = offsetAbsoluteUrl(window.location.href); + const response = await fetch(offsetRelativeUrl("listings.json")); + if (response.status == 200) { + return response.json().then(function (listingPaths) { + const listingHrefs = []; + for (const listingPath of listingPaths) { + const pathWithoutLeadingSlash = listingPath.listing.substring(1); + for (const item of listingPath.items) { + if ( + item === currentPagePath || + item === currentPagePath + "index.html" + ) { + // Resolve this path against the offset to be sure + // we already are using the correct path to the listing + // (this adjusts the listing urls to be rooted against + // whatever root the page is actually running against) + const relative = offsetRelativeUrl(pathWithoutLeadingSlash); + const baseUrl = window.location; + const resolvedPath = new URL(relative, baseUrl); + listingHrefs.push(resolvedPath.pathname); + break; + } + } + } + + // Look up the tree for a nearby linting and use that if we find one + const nearestListing = findNearestParentListing( + offsetAbsoluteUrl(window.location.pathname), + listingHrefs + ); + if (nearestListing) { + activateCategories(nearestListing); + } else { + // See if the referrer is a listing page for this item + const referredRelativePath = offsetAbsoluteUrl(document.referrer); + const referrerListing = listingHrefs.find((listingHref) => { + const isListingReferrer = + listingHref === referredRelativePath || + listingHref === referredRelativePath + "index.html"; + return isListingReferrer; + }); + + if (referrerListing) { + // Try to use the referrer if possible + activateCategories(referrerListing); + } else if (listingHrefs.length > 0) { + // Otherwise, just fall back to the first listing + activateCategories(listingHrefs[0]); + } + } + }); + } + } + if (hasTitleCategories()) { + findAndActivateCategories(); + } + + const findNearestParentListing = (href, listingHrefs) => { + if (!href || !listingHrefs) { + return undefined; + } + // Look up the tree for a nearby linting and use that if we find one + const relativeParts = href.substring(1).split("/"); + while (relativeParts.length > 0) { + const path = relativeParts.join("/"); + for (const listingHref of listingHrefs) { + if (listingHref.startsWith(path)) { + return listingHref; + } + } + relativeParts.pop(); + } + + return undefined; + }; + + const manageSidebarVisiblity = (el, placeholderDescriptor) => { + let isVisible = true; + let elRect; + + return (hiddenRegions) => { + if (el === null) { + return; + } + + // Find the last element of the TOC + const lastChildEl = el.lastElementChild; + + if (lastChildEl) { + // Converts the sidebar to a menu + const convertToMenu = () => { + for (const child of el.children) { + child.style.opacity = 0; + child.style.overflow = "hidden"; + } + + nexttick(() => { + const toggleContainer = window.document.createElement("div"); + toggleContainer.style.width = "100%"; + toggleContainer.classList.add("zindex-over-content"); + toggleContainer.classList.add("quarto-sidebar-toggle"); + toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom + toggleContainer.id = placeholderDescriptor.id; + toggleContainer.style.position = "fixed"; + + const toggleIcon = window.document.createElement("i"); + toggleIcon.classList.add("quarto-sidebar-toggle-icon"); + toggleIcon.classList.add("bi"); + toggleIcon.classList.add("bi-caret-down-fill"); + + const toggleTitle = window.document.createElement("div"); + const titleEl = window.document.body.querySelector( + placeholderDescriptor.titleSelector + ); + if (titleEl) { + toggleTitle.append( + titleEl.textContent || titleEl.innerText, + toggleIcon + ); + } + toggleTitle.classList.add("zindex-over-content"); + toggleTitle.classList.add("quarto-sidebar-toggle-title"); + toggleContainer.append(toggleTitle); + + const toggleContents = window.document.createElement("div"); + toggleContents.classList = el.classList; + toggleContents.classList.add("zindex-over-content"); + toggleContents.classList.add("quarto-sidebar-toggle-contents"); + for (const child of el.children) { + if (child.id === "toc-title") { + continue; + } + + const clone = child.cloneNode(true); + clone.style.opacity = 1; + clone.style.display = null; + toggleContents.append(clone); + } + toggleContents.style.height = "0px"; + const positionToggle = () => { + // position the element (top left of parent, same width as parent) + if (!elRect) { + elRect = el.getBoundingClientRect(); + } + toggleContainer.style.left = `${elRect.left}px`; + toggleContainer.style.top = `${elRect.top}px`; + toggleContainer.style.width = `${elRect.width}px`; + }; + positionToggle(); + + toggleContainer.append(toggleContents); + el.parentElement.prepend(toggleContainer); + + // Process clicks + let tocShowing = false; + // Allow the caller to control whether this is dismissed + // when it is clicked (e.g. sidebar navigation supports + // opening and closing the nav tree, so don't dismiss on click) + const clickEl = placeholderDescriptor.dismissOnClick + ? toggleContainer + : toggleTitle; + + const closeToggle = () => { + if (tocShowing) { + toggleContainer.classList.remove("expanded"); + toggleContents.style.height = "0px"; + tocShowing = false; + } + }; + + // Get rid of any expanded toggle if the user scrolls + window.document.addEventListener( + "scroll", + throttle(() => { + closeToggle(); + }, 50) + ); + + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + positionToggle(); + }, 50) + ); + + window.addEventListener("quarto-hrChanged", () => { + elRect = undefined; + }); + + // Process the click + clickEl.onclick = () => { + if (!tocShowing) { + toggleContainer.classList.add("expanded"); + toggleContents.style.height = null; + tocShowing = true; + } else { + closeToggle(); + } + }; + }); + }; + + // Converts a sidebar from a menu back to a sidebar + const convertToSidebar = () => { + for (const child of el.children) { + child.style.opacity = 1; + child.style.overflow = null; + } + + const placeholderEl = window.document.getElementById( + placeholderDescriptor.id + ); + if (placeholderEl) { + placeholderEl.remove(); + } + + el.classList.remove("rollup"); + }; + + if (isReaderMode()) { + convertToMenu(); + isVisible = false; + } else { + // Find the top and bottom o the element that is being managed + const elTop = el.offsetTop; + const elBottom = + elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; + + if (!isVisible) { + // If the element is current not visible reveal if there are + // no conflicts with overlay regions + if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToSidebar(); + isVisible = true; + } + } else { + // If the element is visible, hide it if it conflicts with overlay regions + // and insert a placeholder toggle (or if we're in reader mode) + if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToMenu(); + isVisible = false; + } + } + } + } + }; + }; + + const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); + for (const tabEl of tabEls) { + const id = tabEl.getAttribute("data-bs-target"); + if (id) { + const columnEl = document.querySelector( + `${id} .column-margin, .tabset-margin-content` + ); + if (columnEl) + tabEl.addEventListener("shown.bs.tab", function (event) { + const el = event.srcElement; + if (el) { + const visibleCls = `${el.id}-margin-content`; + // walk up until we find a parent tabset + let panelTabsetEl = el.parentElement; + while (panelTabsetEl) { + if (panelTabsetEl.classList.contains("panel-tabset")) { + break; + } + panelTabsetEl = panelTabsetEl.parentElement; + } + + if (panelTabsetEl) { + const prevSib = panelTabsetEl.previousElementSibling; + if ( + prevSib && + prevSib.classList.contains("tabset-margin-container") + ) { + const childNodes = prevSib.querySelectorAll( + ".tabset-margin-content" + ); + for (const childEl of childNodes) { + if (childEl.classList.contains(visibleCls)) { + childEl.classList.remove("collapse"); + } else { + childEl.classList.add("collapse"); + } + } + } + } + } + + layoutMarginEls(); + }); + } + } + + // Manage the visibility of the toc and the sidebar + const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { + id: "quarto-toc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { + id: "quarto-sidebarnav-toggle", + titleSelector: ".title", + dismissOnClick: false, + }); + let tocLeftScrollVisibility; + if (leftTocEl) { + tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { + id: "quarto-lefttoc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + } + + // Find the first element that uses formatting in special columns + const conflictingEls = window.document.body.querySelectorAll( + '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' + ); + + // Filter all the possibly conflicting elements into ones + // the do conflict on the left or ride side + const arrConflictingEls = Array.from(conflictingEls); + const leftSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return false; + } + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + className.startsWith("column-") && + !className.endsWith("right") && + !className.endsWith("container") && + className !== "column-margin" + ); + }); + }); + const rightSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return true; + } + + const hasMarginCaption = Array.from(el.classList).find((className) => { + return className == "margin-caption"; + }); + if (hasMarginCaption) { + return true; + } + + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + !className.endsWith("container") && + className.startsWith("column-") && + !className.endsWith("left") + ); + }); + }); + + const kOverlapPaddingSize = 10; + function toRegions(els) { + return els.map((el) => { + const boundRect = el.getBoundingClientRect(); + const top = + boundRect.top + + document.documentElement.scrollTop - + kOverlapPaddingSize; + return { + top, + bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, + }; + }); + } + + let hasObserved = false; + const visibleItemObserver = (els) => { + let visibleElements = [...els]; + const intersectionObserver = new IntersectionObserver( + (entries, _observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if (visibleElements.indexOf(entry.target) === -1) { + visibleElements.push(entry.target); + } + } else { + visibleElements = visibleElements.filter((visibleEntry) => { + return visibleEntry !== entry; + }); + } + }); + + if (!hasObserved) { + hideOverlappedSidebars(); + } + hasObserved = true; + }, + {} + ); + els.forEach((el) => { + intersectionObserver.observe(el); + }); + + return { + getVisibleEntries: () => { + return visibleElements; + }, + }; + }; + + const rightElementObserver = visibleItemObserver(rightSideConflictEls); + const leftElementObserver = visibleItemObserver(leftSideConflictEls); + + const hideOverlappedSidebars = () => { + marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); + sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); + if (tocLeftScrollVisibility) { + tocLeftScrollVisibility( + toRegions(leftElementObserver.getVisibleEntries()) + ); + } + }; + + window.quartoToggleReader = () => { + // Applies a slow class (or removes it) + // to update the transition speed + const slowTransition = (slow) => { + const manageTransition = (id, slow) => { + const el = document.getElementById(id); + if (el) { + if (slow) { + el.classList.add("slow"); + } else { + el.classList.remove("slow"); + } + } + }; + + manageTransition("TOC", slow); + manageTransition("quarto-sidebar", slow); + }; + const readerMode = !isReaderMode(); + setReaderModeValue(readerMode); + + // If we're entering reader mode, slow the transition + if (readerMode) { + slowTransition(readerMode); + } + highlightReaderToggle(readerMode); + hideOverlappedSidebars(); + + // If we're exiting reader mode, restore the non-slow transition + if (!readerMode) { + slowTransition(!readerMode); + } + }; + + const highlightReaderToggle = (readerMode) => { + const els = document.querySelectorAll(".quarto-reader-toggle"); + if (els) { + els.forEach((el) => { + if (readerMode) { + el.classList.add("reader"); + } else { + el.classList.remove("reader"); + } + }); + } + }; + + const setReaderModeValue = (val) => { + if (window.location.protocol !== "file:") { + window.localStorage.setItem("quarto-reader-mode", val); + } else { + localReaderMode = val; + } + }; + + const isReaderMode = () => { + if (window.location.protocol !== "file:") { + return window.localStorage.getItem("quarto-reader-mode") === "true"; + } else { + return localReaderMode; + } + }; + let localReaderMode = null; + + const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); + const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; + + // Walk the TOC and collapse/expand nodes + // Nodes are expanded if: + // - they are top level + // - they have children that are 'active' links + // - they are directly below an link that is 'active' + const walk = (el, depth) => { + // Tick depth when we enter a UL + if (el.tagName === "UL") { + depth = depth + 1; + } + + // It this is active link + let isActiveNode = false; + if (el.tagName === "A" && el.classList.contains("active")) { + isActiveNode = true; + } + + // See if there is an active child to this element + let hasActiveChild = false; + for (child of el.children) { + hasActiveChild = walk(child, depth) || hasActiveChild; + } + + // Process the collapse state if this is an UL + if (el.tagName === "UL") { + if (tocOpenDepth === -1 && depth > 1) { + el.classList.add("collapse"); + } else if ( + depth <= tocOpenDepth || + hasActiveChild || + prevSiblingIsActiveLink(el) + ) { + el.classList.remove("collapse"); + } else { + el.classList.add("collapse"); + } + + // untick depth when we leave a UL + depth = depth - 1; + } + return hasActiveChild || isActiveNode; + }; + + // walk the TOC and expand / collapse any items that should be shown + + if (tocEl) { + walk(tocEl, 0); + updateActiveLink(); + } + + // Throttle the scroll event and walk peridiocally + window.document.addEventListener( + "scroll", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 5) + ); + window.addEventListener( + "resize", + throttle(() => { + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 10) + ); + hideOverlappedSidebars(); + highlightReaderToggle(isReaderMode()); +}); + +// grouped tabsets +window.addEventListener("pageshow", (_event) => { + function getTabSettings() { + const data = localStorage.getItem("quarto-persistent-tabsets-data"); + if (!data) { + localStorage.setItem("quarto-persistent-tabsets-data", "{}"); + return {}; + } + if (data) { + return JSON.parse(data); + } + } + + function setTabSettings(data) { + localStorage.setItem( + "quarto-persistent-tabsets-data", + JSON.stringify(data) + ); + } + + function setTabState(groupName, groupValue) { + const data = getTabSettings(); + data[groupName] = groupValue; + setTabSettings(data); + } + + function toggleTab(tab, active) { + const tabPanelId = tab.getAttribute("aria-controls"); + const tabPanel = document.getElementById(tabPanelId); + if (active) { + tab.classList.add("active"); + tabPanel.classList.add("active"); + } else { + tab.classList.remove("active"); + tabPanel.classList.remove("active"); + } + } + + function toggleAll(selectedGroup, selectorsToSync) { + for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { + const active = selectedGroup === thisGroup; + for (const tab of tabs) { + toggleTab(tab, active); + } + } + } + + function findSelectorsToSyncByLanguage() { + const result = {}; + const tabs = Array.from( + document.querySelectorAll(`div[data-group] a[id^='tabset-']`) + ); + for (const item of tabs) { + const div = item.parentElement.parentElement.parentElement; + const group = div.getAttribute("data-group"); + if (!result[group]) { + result[group] = {}; + } + const selectorsToSync = result[group]; + const value = item.innerHTML; + if (!selectorsToSync[value]) { + selectorsToSync[value] = []; + } + selectorsToSync[value].push(item); + } + return result; + } + + function setupSelectorSync() { + const selectorsToSync = findSelectorsToSyncByLanguage(); + Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { + Object.entries(tabSetsByValue).forEach(([value, items]) => { + items.forEach((item) => { + item.addEventListener("click", (_event) => { + setTabState(group, value); + toggleAll(value, selectorsToSync[group]); + }); + }); + }); + }); + return selectorsToSync; + } + + const selectorsToSync = setupSelectorSync(); + for (const [group, selectedName] of Object.entries(getTabSettings())) { + const selectors = selectorsToSync[group]; + // it's possible that stale state gives us empty selections, so we explicitly check here. + if (selectors) { + toggleAll(selectedName, selectors); + } + } +}); + +function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; +} + +function nexttick(func) { + return setTimeout(func, 0); +} diff --git a/docs/site_libs/quarto-html/tippy.css b/docs/site_libs/quarto-html/tippy.css new file mode 100644 index 00000000..e6ae635c --- /dev/null +++ b/docs/site_libs/quarto-html/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/docs/site_libs/quarto-html/tippy.umd.min.js b/docs/site_libs/quarto-html/tippy.umd.min.js new file mode 100644 index 00000000..ca292be3 --- /dev/null +++ b/docs/site_libs/quarto-html/tippy.umd.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); + diff --git a/docs/site_libs/quarto-nav/headroom.min.js b/docs/site_libs/quarto-nav/headroom.min.js new file mode 100644 index 00000000..b08f1dff --- /dev/null +++ b/docs/site_libs/quarto-nav/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/docs/site_libs/quarto-nav/quarto-nav.js b/docs/site_libs/quarto-nav/quarto-nav.js new file mode 100644 index 00000000..3b21201f --- /dev/null +++ b/docs/site_libs/quarto-nav/quarto-nav.js @@ -0,0 +1,277 @@ +const headroomChanged = new CustomEvent("quarto-hrChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +window.document.addEventListener("DOMContentLoaded", function () { + let init = false; + + // Manage the back to top button, if one is present. + let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollDownBuffer = 5; + const scrollUpBuffer = 35; + const btn = document.getElementById("quarto-back-to-top"); + const hideBackToTop = () => { + btn.style.display = "none"; + }; + const showBackToTop = () => { + btn.style.display = "inline-block"; + }; + if (btn) { + window.document.addEventListener( + "scroll", + function () { + const currentScrollTop = + window.pageYOffset || document.documentElement.scrollTop; + + // Shows and hides the button 'intelligently' as the user scrolls + if (currentScrollTop - scrollDownBuffer > lastScrollTop) { + hideBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { + showBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } + + // Show the button at the bottom, hides it at the top + if (currentScrollTop <= 0) { + hideBackToTop(); + } else if ( + window.innerHeight + currentScrollTop >= + document.body.offsetHeight + ) { + showBackToTop(); + } + }, + false + ); + } + + function throttle(func, wait) { + var timeout; + return function () { + const context = this; + const args = arguments; + const later = function () { + clearTimeout(timeout); + timeout = null; + func.apply(context, args); + }; + + if (!timeout) { + timeout = setTimeout(later, wait); + } + }; + } + + function headerOffset() { + // Set an offset if there is are fixed top navbar + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl) { + return headerEl.clientHeight; + } else { + return 0; + } + } + + function footerOffset() { + const footerEl = window.document.querySelector("footer.footer"); + if (footerEl) { + return footerEl.clientHeight; + } else { + return 0; + } + } + + function updateDocumentOffsetWithoutAnimation() { + updateDocumentOffset(false); + } + + function updateDocumentOffset(animated) { + // set body offset + const topOffset = headerOffset(); + const bodyOffset = topOffset + footerOffset(); + const bodyEl = window.document.body; + bodyEl.setAttribute("data-bs-offset", topOffset); + bodyEl.style.paddingTop = topOffset + "px"; + + // deal with sidebar offsets + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + if (!animated) { + sidebar.classList.add("notransition"); + // Remove the no transition class after the animation has time to complete + setTimeout(function () { + sidebar.classList.remove("notransition"); + }, 201); + } + + if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { + sidebar.style.top = "0"; + sidebar.style.maxHeight = "100vh"; + } else { + sidebar.style.top = topOffset + "px"; + sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; + } + }); + + // allow space for footer + const mainContainer = window.document.querySelector(".quarto-container"); + if (mainContainer) { + mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; + } + + // link offset + let linkStyle = window.document.querySelector("#quarto-target-style"); + if (!linkStyle) { + linkStyle = window.document.createElement("style"); + linkStyle.setAttribute("id", "quarto-target-style"); + window.document.head.appendChild(linkStyle); + } + while (linkStyle.firstChild) { + linkStyle.removeChild(linkStyle.firstChild); + } + if (topOffset > 0) { + linkStyle.appendChild( + window.document.createTextNode(` + section:target::before { + content: ""; + display: block; + height: ${topOffset}px; + margin: -${topOffset}px 0 0; + }`) + ); + } + if (init) { + window.dispatchEvent(headroomChanged); + } + init = true; + } + + // initialize headroom + var header = window.document.querySelector("#quarto-header"); + if (header && window.Headroom) { + const headroom = new window.Headroom(header, { + tolerance: 5, + onPin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.remove("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + onUnpin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.add("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + }); + headroom.init(); + + let frozen = false; + window.quartoToggleHeadroom = function () { + if (frozen) { + headroom.unfreeze(); + frozen = false; + } else { + headroom.freeze(); + frozen = true; + } + }; + } + + window.addEventListener( + "hashchange", + function (e) { + if ( + getComputedStyle(document.documentElement).scrollBehavior !== "smooth" + ) { + window.scrollTo(0, window.pageYOffset - headerOffset()); + } + }, + false + ); + + // Observe size changed for the header + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl && window.ResizeObserver) { + const observer = new window.ResizeObserver( + updateDocumentOffsetWithoutAnimation + ); + observer.observe(headerEl, { + attributes: true, + childList: true, + characterData: true, + }); + } else { + window.addEventListener( + "resize", + throttle(updateDocumentOffsetWithoutAnimation, 50) + ); + } + setTimeout(updateDocumentOffsetWithoutAnimation, 250); + + // fixup index.html links if we aren't on the filesystem + if (window.location.protocol !== "file:") { + const links = window.document.querySelectorAll("a"); + for (let i = 0; i < links.length; i++) { + if (links[i].href) { + links[i].href = links[i].href.replace(/\/index\.html/, "/"); + } + } + + // Fixup any sharing links that require urls + // Append url to any sharing urls + const sharingLinks = window.document.querySelectorAll( + "a.sidebar-tools-main-item" + ); + for (let i = 0; i < sharingLinks.length; i++) { + const sharingLink = sharingLinks[i]; + const href = sharingLink.getAttribute("href"); + if (href) { + sharingLink.setAttribute( + "href", + href.replace("|url|", window.location.href) + ); + } + } + + // Scroll the active navigation item into view, if necessary + const navSidebar = window.document.querySelector("nav#quarto-sidebar"); + if (navSidebar) { + // Find the active item + const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); + if (activeItem) { + // Wait for the scroll height and height to resolve by observing size changes on the + // nav element that is scrollable + const resizeObserver = new ResizeObserver((_entries) => { + // The bottom of the element + const elBottom = activeItem.offsetTop; + const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; + + // The element height and scroll height are the same, then we are still loading + if (viewBottom !== navSidebar.scrollHeight) { + // Determine if the item isn't visible and scroll to it + if (elBottom >= viewBottom) { + navSidebar.scrollTop = elBottom; + } + + // stop observing now since we've completed the scroll + resizeObserver.unobserve(navSidebar); + } + }); + resizeObserver.observe(navSidebar); + } + } + } +}); diff --git a/docs/site_libs/quarto-search/autocomplete.umd.js b/docs/site_libs/quarto-search/autocomplete.umd.js new file mode 100644 index 00000000..619c57cc --- /dev/null +++ b/docs/site_libs/quarto-search/autocomplete.umd.js @@ -0,0 +1,3 @@ +/*! @algolia/autocomplete-js 1.7.3 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,o,i=[],u=!0,a=!1;try{for(n=n.call(e);!(u=(r=n.next()).done)&&(i.push(r.value),!t||i.length!==t);u=!0);}catch(e){a=!0,o=e}finally{try{u||null==n.return||n.return()}finally{if(a)throw o}}return i}(e,t)||l(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=n?null===r?null:0:o}function S(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function E(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ae,ce,le,se=null,pe=(ae=-1,ce=-1,le=void 0,function(e){var t=++ae;return Promise.resolve(e).then((function(e){return le&&t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ye=["props","refresh","store"],be=["inputElement","formElement","panelElement"],Oe=["inputElement"],_e=["inputElement","maxLength"],Pe=["item","source"];function je(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function we(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function Ee(e){var t=e.props,n=e.refresh,r=e.store,o=Ie(e,ye);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;function u(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return we({onTouchStart:u,onMouseDown:u,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},Ie(e,be))},getRootProps:function(e){return we({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-owns":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){return e.inputElement,we({action:"",noValidate:!0,role:"search",onSubmit:function(i){var u;i.preventDefault(),t.onSubmit(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()},onReset:function(i){var u;i.preventDefault(),t.onReset(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},Ie(e,Oe))},getLabelProps:function(e){return we({htmlFor:"".concat(t.id,"-input"),id:"".concat(t.id,"-label")},e)},getInputProps:function(e){var i;function u(e){(t.openOnFocus||Boolean(r.getState().query))&&fe(we({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var a=e||{};a.inputElement;var c=a.maxLength,l=void 0===c?512:c,s=Ie(a,_e),p=A(r.getState()),f=function(e){return Boolean(e&&e.match(C))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),d=null!=p&&p.itemUrl&&!f?"go":"search";return we({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?"".concat(t.id,"-item-").concat(r.getState().activeItemId):void 0,"aria-controls":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:r.getState().completion||r.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:d,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:l,type:"search",onChange:function(e){fe(we({event:e,props:t,query:e.currentTarget.value.slice(0,l),refresh:n,store:r},o))},onKeyDown:function(e){!function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=ge(e,de);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=n.environment.document.getElementById("".concat(n.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},a=function(){var e=A(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,c=e.source;c.onActive(ve({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:c,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?fe(ve({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(n.debug||o.pendingRequests.cancelAll());t.preventDefault();var c=A(o.getState()),l=c.item,s=c.itemInputValue,p=c.itemUrl,f=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:p,item:l,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:p,item:l,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),void n.navigator.navigate({itemUrl:p,item:l,state:o.getState()});fe(ve({event:t,nextState:{isOpen:!1},props:n,query:s,refresh:r,store:o},i)).then((function(){f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i))}))}}}(we({event:e,props:t,refresh:n,store:r},o))},onFocus:u,onBlur:y,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||u(n)}},s)},getPanelProps:function(e){return we({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){return we({role:"listbox","aria-labelledby":"".concat(t.id,"-label"),id:"".concat(t.id,"-list")},e)},getItemProps:function(e){var i=e.item,u=e.source,a=Ie(e,Pe);return we({id:"".concat(t.id,"-item-").concat(i.__autocomplete_id),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=A(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,c=t.itemUrl,l=t.source;l.onActive(we({event:e,item:u,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),c=u.getItemUrl({item:i,state:r.getState()});(c?Promise.resolve():fe(we({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(we({event:e,item:i,itemInputValue:a,itemUrl:c,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function Ae(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ce(e){for(var t=1;t0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:v(),plugins:o,initialState:H({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(F(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return E(e,n)}))).then((function(e){return d(e)})).then((function(e){return e.map((function(e){return H(H({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:H({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}(e,t),r=R(Te,n,(function(e){var t=e.prevState,r=e.state;n.onStateChange(Be({prevState:t,state:r,refresh:u},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var n=0,r=e.map((function(e){return L(L({},e),{},{items:d(e.items).map((function(e){return L(L({},e),{},{__autocomplete_id:n++})}))})}));t.dispatch("setCollections",r)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:r}),i=Ee(Be({props:n,refresh:u,store:r},o));function u(){return fe(Be({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,query:r.getState().query,refresh:u,store:r},o))}return n.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,Be(Be({},o),{},{refresh:u,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})}}))})),function(e){var t,n,r=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(n=t.userAgent)||void 0===n?void 0:n.includes("Algolia Crawler")){var i=o.document.createElement("meta"),u=o.document.querySelector("head");i.name="algolia:metadata",setTimeout((function(){i.content=JSON.stringify(r),u.appendChild(i)}),0)}}({metadata:ke({plugins:n.plugins,options:e}),environment:n.environment}),Be(Be({refresh:u},i),o)}var Ue=function(e,t,n,r){var o;t[0]=0;for(var i=1;i=5&&((o||!e&&5===r)&&(u.push(r,0,o,n),r=6),e&&(u.push(r,e,0,n),r=6)),o=""},c=0;c"===t?(r=1,o=""):o=t+o[0]:i?t===i?i="":o+=t:'"'===t||"'"===t?i=t:">"===t?(a(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[c][l+1])?(a(),3===r&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(a(),r=2):o+=t),3===r&&"!--"===o&&(r=4,u=u[0])}return a(),u}(e)),t),arguments,[])).length>1?t:t[0]}var We=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function Qe(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function $e(){for(var e=arguments.length,t=new Array(e),n=0;n2&&(u.children=arguments.length>3?lt.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return _t(e,u,r,o,null)}function _t(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++pt:o};return null==o&&null!=st.vnode&&st.vnode(i),i}function Pt(e){return e.children}function jt(e,t){this.props=e,this.context=t}function wt(e,t){if(null==t)return e.__?wt(e.__,e.__.__k.indexOf(e)+1):null;for(var n;t0?_t(d.type,d.props,d.key,null,d.__v):d)){if(d.__=n,d.__b=n.__b+1,null===(f=g[s])||f&&d.key==f.key&&d.type===f.type)g[s]=void 0;else for(p=0;p0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(Ht);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Wt(e){return function(e){if(Array.isArray(e))return Qt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Qt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Qt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Qt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n",""":'"',"'":"'"},Gt=new RegExp(/\w/i),Kt=/&(amp|quot|lt|gt|#39);/g,Jt=RegExp(Kt.source);function Yt(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Gt.test((o=i.value)&&Jt.test(o)?o.replace(Kt,(function(e){return zt[e]})):o)||a!==u?i.isHighlighted:a}function Xt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Zt(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function mn(e){return function(e){if(Array.isArray(e))return vn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return vn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return vn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function vn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;if(!O.value.core.openOnFocus&&!t.query)return n;var r=Boolean(h.current||O.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:Sn,options:e}}))})),j=p(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},O.value.core.initialState)),w={getEnvironmentProps:O.value.renderer.getEnvironmentProps,getFormProps:O.value.renderer.getFormProps,getInputProps:O.value.renderer.getInputProps,getItemProps:O.value.renderer.getItemProps,getLabelProps:O.value.renderer.getLabelProps,getListProps:O.value.renderer.getListProps,getPanelProps:O.value.renderer.getPanelProps,getRootProps:O.value.renderer.getRootProps},S={setActiveItemId:P.value.setActiveItemId,setQuery:P.value.setQuery,setCollections:P.value.setCollections,setIsOpen:P.value.setIsOpen,setStatus:P.value.setStatus,setContext:P.value.setContext,refresh:P.value.refresh},I=d((function(){return Ve.bind(O.value.renderer.renderer.createElement)})),E=d((function(){return ct({autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,environment:O.value.core.environment,isDetached:_.value,placeholder:O.value.core.placeholder,propGetters:w,setIsModalOpen:k,state:j.current,translations:O.value.renderer.translations})}));function A(){tt(E.value.panel,{style:_.value?{}:wn({panelPlacement:O.value.renderer.panelPlacement,container:E.value.root,form:E.value.form,environment:O.value.core.environment})})}function C(e){j.current=e;var t={autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,components:O.value.renderer.components,container:O.value.renderer.container,html:I.value,dom:E.value,panelContainer:_.value?E.value.detachedContainer:O.value.renderer.panelContainer,propGetters:w,state:j.current,renderer:O.value.renderer.renderer},r=!g(e)&&!h.current&&O.value.renderer.renderNoResults||O.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;nt(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),nt(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),tt(o.label,{hidden:"stalled"===u.status}),tt(o.loadingIndicator,{hidden:"stalled"!==u.status}),tt(o.clearButton,{hidden:!u.query})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.html,c=t.dom,l=t.panelContainer,s=t.propGetters,p=t.state,f=t.components,d=t.renderer;if(p.isOpen){l.contains(c.panel)||"loading"===p.status||l.appendChild(c.panel),c.panel.classList.toggle("aa-Panel--stalled","stalled"===p.status);var m=p.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var c=e.source,l=e.items;return d.createElement("section",{key:t,className:u.source,"data-autocomplete-source-id":c.sourceId},c.templates.header&&d.createElement("div",{className:u.sourceHeader},c.templates.header({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})),c.templates.noResults&&0===l.length?d.createElement("div",{className:u.sourceNoResults},c.templates.noResults({components:f,createElement:d.createElement,Fragment:d.Fragment,source:c,state:p,html:a})):d.createElement("ul",i({className:u.list},s.getListProps(n({state:p,props:r.getListProps({})},o))),l.map((function(e){var t=r.getItemProps({item:e,source:c});return d.createElement("li",i({key:t.id,className:u.item},s.getItemProps(n({state:p,props:t},o))),c.templates.item({components:f,createElement:d.createElement,Fragment:d.Fragment,item:e,state:p,html:a}))}))),c.templates.footer&&d.createElement("div",{className:u.sourceFooter},c.templates.footer({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})))})),v=d.createElement(d.Fragment,null,d.createElement("div",{className:u.panelLayout},m),d.createElement("div",{className:"aa-GradientBottom"})),h=m.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n(n({children:v,state:p,sections:m,elements:h},d),{},{components:f,html:a},o),c.panel)}else l.contains(c.panel)&&l.removeChild(c.panel)}(r,t)}function D(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c();var t=O.value.renderer,n=t.components,r=u(t,In);y.current=Ge(r,O.value.core,{components:Ke(n,(function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")})),initialState:j.current},e),m(),l(),P.value.refresh().then((function(){C(j.current)}))}function k(e){requestAnimationFrame((function(){var t=O.value.core.environment.document.body.contains(E.value.detachedOverlay);e!==t&&(e?(O.value.core.environment.document.body.appendChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.add("aa-Detached"),E.value.input.focus()):(O.value.core.environment.document.body.removeChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.remove("aa-Detached"),P.value.setQuery(""),P.value.refresh()))}))}return a((function(){var e=P.value.getEnvironmentProps({formElement:E.value.form,panelElement:E.value.panel,inputElement:E.value.input});return tt(O.value.core.environment,e),function(){tt(O.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=_.value?O.value.core.environment.document.body:O.value.renderer.panelContainer,t=_.value?E.value.detachedOverlay:E.value.panel;return _.value&&j.current.isOpen&&k(!0),C(j.current),function(){e.contains(t)&&e.removeChild(t)}})),a((function(){var e=O.value.renderer.container;return e.appendChild(E.value.root),function(){e.removeChild(E.value.root)}})),a((function(){var e=f((function(e){C(e.state)}),0);return b.current=function(t){var n=t.state,r=t.prevState;(_.value&&r.isOpen!==n.isOpen&&k(n.isOpen),_.value||!n.isOpen||r.isOpen||A(),n.query!==r.query)&&O.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){b.current=void 0}})),a((function(){var e=f((function(){var e=_.value;_.value=O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches,e!==_.value?D({}):requestAnimationFrame(A)}),20);return O.value.core.environment.addEventListener("resize",e),function(){O.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!_.value)return function(){};function e(e){E.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=O.value.core.environment.matchMedia(getComputedStyle(O.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(A),function(){}})),n(n({},S),{},{update:D,destroy:function(){c()}})},e.getAlgoliaFacets=function(e){var t=En({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=An,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/docs/site_libs/quarto-search/fuse.min.js b/docs/site_libs/quarto-search/fuse.min.js new file mode 100644 index 00000000..adc28356 --- /dev/null +++ b/docs/site_libs/quarto-search/fuse.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2022 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,l=i.includeMatches,f=void 0===l?I.includeMatches:l,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,l=void 0===h?I.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?I.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=R(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,F&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=R(t,{errors:F,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(R(t,{errors:F+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:l}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(f(d),f(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=l(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,l=void 0===h?I.distance:h,f=o.includeMatches,d=void 0===f?I.includeMatches:f,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?I.findAllMatches:f,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||F(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return fe(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(le(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=le(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/site_libs/quarto-search/quarto-search.js b/docs/site_libs/quarto-search/quarto-search.js new file mode 100644 index 00000000..f5d852d1 --- /dev/null +++ b/docs/site_libs/quarto-search/quarto-search.js @@ -0,0 +1,1140 @@ +const kQueryArg = "q"; +const kResultsArg = "show-results"; + +// If items don't provide a URL, then both the navigator and the onSelect +// function aren't called (and therefore, the default implementation is used) +// +// We're using this sentinel URL to signal to those handlers that this +// item is a more item (along with the type) and can be handled appropriately +const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Ensure that search is available on this page. If it isn't, + // should return early and not do anything + var searchEl = window.document.getElementById("quarto-search"); + if (!searchEl) return; + + const { autocomplete } = window["@algolia/autocomplete-js"]; + + let quartoSearchOptions = {}; + let language = {}; + const searchOptionEl = window.document.getElementById( + "quarto-search-options" + ); + if (searchOptionEl) { + const jsonStr = searchOptionEl.textContent; + quartoSearchOptions = JSON.parse(jsonStr); + language = quartoSearchOptions.language; + } + + // note the search mode + if (quartoSearchOptions.type === "overlay") { + searchEl.classList.add("type-overlay"); + } else { + searchEl.classList.add("type-textbox"); + } + + // Used to determine highlighting behavior for this page + // A `q` query param is expected when the user follows a search + // to this page + const currentUrl = new URL(window.location); + const query = currentUrl.searchParams.get(kQueryArg); + const showSearchResults = currentUrl.searchParams.get(kResultsArg); + const mainEl = window.document.querySelector("main"); + + // highlight matches on the page + if (query !== null && mainEl) { + // perform any highlighting + highlight(escapeRegExp(query), mainEl); + + // fix up the URL to remove the q query param + const replacementUrl = new URL(window.location); + replacementUrl.searchParams.delete(kQueryArg); + window.history.replaceState({}, "", replacementUrl); + } + + // function to clear highlighting on the page when the search query changes + // (e.g. if the user edits the query or clears it) + let highlighting = true; + const resetHighlighting = (searchTerm) => { + if (mainEl && highlighting && query !== null && searchTerm !== query) { + clearHighlight(query, mainEl); + highlighting = false; + } + }; + + // Clear search highlighting when the user scrolls sufficiently + const resetFn = () => { + resetHighlighting(""); + window.removeEventListener("quarto-hrChanged", resetFn); + window.removeEventListener("quarto-sectionChanged", resetFn); + }; + + // Register this event after the initial scrolling and settling of events + // on the page + window.addEventListener("quarto-hrChanged", resetFn); + window.addEventListener("quarto-sectionChanged", resetFn); + + // Responsively switch to overlay mode if the search is present on the navbar + // Note that switching the sidebar to overlay mode requires more coordinate (not just + // the media query since we generate different HTML for sidebar overlays than we do + // for sidebar input UI) + const detachedMediaQuery = + quartoSearchOptions.type === "overlay" ? "all" : "(max-width: 991px)"; + + // If configured, include the analytics client to send insights + const plugins = configurePlugins(quartoSearchOptions); + + let lastState = null; + const { setIsOpen, setQuery, setCollections } = autocomplete({ + container: searchEl, + detachedMediaQuery: detachedMediaQuery, + defaultActiveItemId: 0, + panelContainer: "#quarto-search-results", + panelPlacement: quartoSearchOptions["panel-placement"], + debug: false, + openOnFocus: true, + plugins, + classNames: { + form: "d-flex", + }, + translations: { + clearButtonTitle: language["search-clear-button-title"], + detachedCancelButtonText: language["search-detached-cancel-button-title"], + submitButtonTitle: language["search-submit-button-title"], + }, + initialState: { + query, + }, + getItemUrl({ item }) { + return item.href; + }, + onStateChange({ state }) { + // Perhaps reset highlighting + resetHighlighting(state.query); + + // If the panel just opened, ensure the panel is positioned properly + if (state.isOpen) { + if (lastState && !lastState.isOpen) { + setTimeout(() => { + positionPanel(quartoSearchOptions["panel-placement"]); + }, 150); + } + } + + // Perhaps show the copy link + showCopyLink(state.query, quartoSearchOptions); + + lastState = state; + }, + reshape({ sources, state }) { + return sources.map((source) => { + try { + const items = source.getItems(); + + // Validate the items + validateItems(items); + + // group the items by document + const groupedItems = new Map(); + items.forEach((item) => { + const hrefParts = item.href.split("#"); + const baseHref = hrefParts[0]; + const isDocumentItem = hrefParts.length === 1; + + const items = groupedItems.get(baseHref); + if (!items) { + groupedItems.set(baseHref, [item]); + } else { + // If the href for this item matches the document + // exactly, place this item first as it is the item that represents + // the document itself + if (isDocumentItem) { + items.unshift(item); + } else { + items.push(item); + } + groupedItems.set(baseHref, items); + } + }); + + const reshapedItems = []; + let count = 1; + for (const [_key, value] of groupedItems) { + const firstItem = value[0]; + reshapedItems.push({ + ...firstItem, + type: kItemTypeDoc, + }); + + const collapseMatches = quartoSearchOptions["collapse-after"]; + const collapseCount = + typeof collapseMatches === "number" ? collapseMatches : 1; + + if (value.length > 1) { + const target = `search-more-${count}`; + const isExpanded = + state.context.expanded && + state.context.expanded.includes(target); + + const remainingCount = value.length - collapseCount; + + for (let i = 1; i < value.length; i++) { + if (collapseMatches && i === collapseCount) { + reshapedItems.push({ + target, + title: isExpanded + ? language["search-hide-matches-text"] + : remainingCount === 1 + ? `${remainingCount} ${language["search-more-match-text"]}` + : `${remainingCount} ${language["search-more-matches-text"]}`, + type: kItemTypeMore, + href: kItemTypeMoreHref, + }); + } + + if (isExpanded || !collapseMatches || i < collapseCount) { + reshapedItems.push({ + ...value[i], + type: kItemTypeItem, + target, + }); + } + } + } + count += 1; + } + + return { + ...source, + getItems() { + return reshapedItems; + }, + }; + } catch (error) { + // Some form of error occurred + return { + ...source, + getItems() { + return [ + { + title: error.name || "An Error Occurred While Searching", + text: + error.message || + "An unknown error occurred while attempting to perform the requested search.", + type: kItemTypeError, + }, + ]; + }, + }; + } + }); + }, + navigator: { + navigate({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.location.assign(itemUrl); + } + }, + navigateNewTab({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + const windowReference = window.open(itemUrl, "_blank", "noopener"); + if (windowReference) { + windowReference.focus(); + } + } + }, + navigateNewWindow({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.open(itemUrl, "_blank", "noopener"); + } + }, + }, + getSources({ state, setContext, setActiveItemId, refresh }) { + return [ + { + sourceId: "documents", + getItemUrl({ item }) { + if (item.href) { + return offsetURL(item.href); + } else { + return undefined; + } + }, + onSelect({ + item, + state, + setContext, + setIsOpen, + setActiveItemId, + refresh, + }) { + if (item.type === kItemTypeMore) { + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + + // Toggle more + setIsOpen(true); + } + }, + getItems({ query }) { + if (query === null || query === "") { + return []; + } + + const limit = quartoSearchOptions.limit; + if (quartoSearchOptions.algolia) { + return algoliaSearch(query, limit, quartoSearchOptions.algolia); + } else { + // Fuse search options + const fuseSearchOptions = { + isCaseSensitive: false, + shouldSort: true, + minMatchCharLength: 2, + limit: limit, + }; + + return readSearchData().then(function (fuse) { + return fuseSearch(query, fuse, fuseSearchOptions); + }); + } + }, + templates: { + noResults({ createElement }) { + const hasQuery = lastState.query; + + return createElement( + "div", + { + class: `quarto-search-no-results${ + hasQuery ? "" : " no-query" + }`, + }, + language["search-no-results-text"] + ); + }, + header({ items, createElement }) { + // count the documents + const count = items.filter((item) => { + return item.type === kItemTypeDoc; + }).length; + + if (count > 0) { + return createElement( + "div", + { class: "search-result-header" }, + `${count} ${language["search-matching-documents-text"]}` + ); + } else { + return createElement( + "div", + { class: "search-result-header-no-results" }, + `` + ); + } + }, + footer({ _items, createElement }) { + if ( + quartoSearchOptions.algolia && + quartoSearchOptions.algolia["show-logo"] + ) { + const libDir = quartoSearchOptions.algolia["libDir"]; + const logo = createElement("img", { + src: offsetURL( + `${libDir}/quarto-search/search-by-algolia.svg` + ), + class: "algolia-search-logo", + }); + return createElement( + "a", + { href: "http://www.algolia.com/" }, + logo + ); + } + }, + + item({ item, createElement }) { + return renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh + ); + }, + }, + }, + ]; + }, + }); + + window.quartoOpenSearch = () => { + setIsOpen(false); + setIsOpen(true); + focusSearchInput(); + }; + + // Remove the labeleledby attribute since it is pointing + // to a non-existent label + if (quartoSearchOptions.type === "overlay") { + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + if (inputEl) { + inputEl.removeAttribute("aria-labelledby"); + } + } + + // If the main document scrolls dismiss the search results + // (otherwise, since they're floating in the document they can scroll with the document) + window.document.body.onscroll = () => { + setIsOpen(false); + }; + + if (showSearchResults) { + setIsOpen(true); + focusSearchInput(); + } +}); + +function configurePlugins(quartoSearchOptions) { + const autocompletePlugins = []; + const algoliaOptions = quartoSearchOptions.algolia; + if ( + algoliaOptions && + algoliaOptions["analytics-events"] && + algoliaOptions["search-only-api-key"] && + algoliaOptions["application-id"] + ) { + const apiKey = algoliaOptions["search-only-api-key"]; + const appId = algoliaOptions["application-id"]; + + // Aloglia insights may not be loaded because they require cookie consent + // Use deferred loading so events will start being recorded when/if consent + // is granted. + const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { + if ( + window.aa && + window["@algolia/autocomplete-plugin-algolia-insights"] + ) { + window.aa("init", { + appId, + apiKey, + useCookie: true, + }); + + const { createAlgoliaInsightsPlugin } = + window["@algolia/autocomplete-plugin-algolia-insights"]; + // Register the insights client + const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ + insightsClient: window.aa, + onItemsChange({ insights, insightsEvents }) { + const events = insightsEvents.map((event) => { + const maxEvents = event.objectIDs.slice(0, 20); + return { + ...event, + objectIDs: maxEvents, + }; + }); + + insights.viewedObjectIDs(...events); + }, + }); + return algoliaInsightsPlugin; + } + }); + + // Add the plugin + autocompletePlugins.push(algoliaInsightsDeferredPlugin); + return autocompletePlugins; + } +} + +// For plugins that may not load immediately, create a wrapper +// plugin and forward events and plugin data once the plugin +// is initialized. This is useful for cases like cookie consent +// which may prevent the analytics insights event plugin from initializing +// immediately. +function deferredLoadPlugin(createPlugin) { + let plugin = undefined; + let subscribeObj = undefined; + const wrappedPlugin = () => { + if (!plugin && subscribeObj) { + plugin = createPlugin(); + if (plugin && plugin.subscribe) { + plugin.subscribe(subscribeObj); + } + } + return plugin; + }; + + return { + subscribe: (obj) => { + subscribeObj = obj; + }, + onStateChange: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onStateChange) { + plugin.onStateChange(obj); + } + }, + onSubmit: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onSubmit) { + plugin.onSubmit(obj); + } + }, + onReset: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onReset) { + plugin.onReset(obj); + } + }, + getSources: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.getSources) { + return plugin.getSources(obj); + } else { + return Promise.resolve([]); + } + }, + data: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.data) { + plugin.data(obj); + } + }, + }; +} + +function validateItems(items) { + // Validate the first item + if (items.length > 0) { + const item = items[0]; + const missingFields = []; + if (item.href == undefined) { + missingFields.push("href"); + } + if (!item.title == undefined) { + missingFields.push("title"); + } + if (!item.text == undefined) { + missingFields.push("text"); + } + + if (missingFields.length === 1) { + throw { + name: `Error: Search index is missing the ${missingFields[0]} field.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } else if (missingFields.length > 1) { + const missingFieldList = missingFields + .map((field) => { + return `${field}`; + }) + .join(", "); + + throw { + name: `Error: Search index is missing the following fields: ${missingFieldList}.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } + } +} + +let lastQuery = null; +function showCopyLink(query, options) { + const language = options.language; + lastQuery = query; + // Insert share icon + const inputSuffixEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix" + ); + + if (inputSuffixEl) { + let copyButtonEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" + ); + + if (copyButtonEl === null) { + copyButtonEl = window.document.createElement("button"); + copyButtonEl.setAttribute("class", "aa-CopyButton"); + copyButtonEl.setAttribute("type", "button"); + copyButtonEl.setAttribute("title", language["search-copy-link-title"]); + copyButtonEl.onmousedown = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const linkIcon = "bi-clipboard"; + const checkIcon = "bi-check2"; + + const shareIconEl = window.document.createElement("i"); + shareIconEl.setAttribute("class", `bi ${linkIcon}`); + copyButtonEl.appendChild(shareIconEl); + inputSuffixEl.prepend(copyButtonEl); + + const clipboard = new window.ClipboardJS(".aa-CopyButton", { + text: function (_trigger) { + const copyUrl = new URL(window.location); + copyUrl.searchParams.set(kQueryArg, lastQuery); + copyUrl.searchParams.set(kResultsArg, "1"); + return copyUrl.toString(); + }, + }); + clipboard.on("success", function (e) { + // Focus the input + + // button target + const button = e.trigger; + const icon = button.querySelector("i.bi"); + + // flash "checked" + icon.classList.add(checkIcon); + icon.classList.remove(linkIcon); + setTimeout(function () { + icon.classList.remove(checkIcon); + icon.classList.add(linkIcon); + }, 1000); + }); + } + + // If there is a query, show the link icon + if (copyButtonEl) { + if (lastQuery && options["copy-button"]) { + copyButtonEl.style.display = "flex"; + } else { + copyButtonEl.style.display = "none"; + } + } + } +} + +/* Search Index Handling */ +// create the index +var fuseIndex = undefined; +async function readSearchData() { + // Initialize the search index on demand + if (fuseIndex === undefined) { + // create fuse index + const options = { + keys: [ + { name: "title", weight: 20 }, + { name: "section", weight: 20 }, + { name: "text", weight: 10 }, + ], + ignoreLocation: true, + threshold: 0.1, + }; + const fuse = new window.Fuse([], options); + + // fetch the main search.json + const response = await fetch(offsetURL("search.json")); + if (response.status == 200) { + return response.json().then(function (searchDocs) { + searchDocs.forEach(function (searchDoc) { + fuse.add(searchDoc); + }); + fuseIndex = fuse; + return fuseIndex; + }); + } else { + return Promise.reject( + new Error( + "Unexpected status from search index request: " + response.status + ) + ); + } + } + return fuseIndex; +} + +function inputElement() { + return window.document.body.querySelector(".aa-Form .aa-Input"); +} + +function focusSearchInput() { + setTimeout(() => { + const inputEl = inputElement(); + if (inputEl) { + inputEl.focus(); + } + }, 50); +} + +/* Panels */ +const kItemTypeDoc = "document"; +const kItemTypeMore = "document-more"; +const kItemTypeItem = "document-item"; +const kItemTypeError = "error"; + +function renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh +) { + switch (item.type) { + case kItemTypeDoc: + return createDocumentCard( + createElement, + "file-richtext", + item.title, + item.section, + item.text, + item.href + ); + case kItemTypeMore: + return createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh + ); + case kItemTypeItem: + return createSectionCard( + createElement, + item.section, + item.text, + item.href + ); + case kItemTypeError: + return createErrorCard(createElement, item.title, item.text); + default: + return undefined; + } +} + +function createDocumentCard(createElement, icon, title, section, text, href) { + const iconEl = createElement("i", { + class: `bi bi-${icon} search-result-icon`, + }); + const titleEl = createElement("p", { class: "search-result-title" }, title); + const titleContainerEl = createElement( + "div", + { class: "search-result-title-container" }, + [iconEl, titleEl] + ); + + const textEls = []; + if (section) { + const sectionEl = createElement( + "p", + { class: "search-result-section" }, + section + ); + textEls.push(sectionEl); + } + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + textEls.push(descEl); + + const textContainerEl = createElement( + "div", + { class: "search-result-text-container" }, + textEls + ); + + const containerEl = createElement( + "div", + { + class: "search-result-container", + }, + [titleContainerEl, textContainerEl] + ); + + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + containerEl + ); + + const classes = ["search-result-doc", "search-item"]; + if (!section) { + classes.push("document-selectable"); + } + + return createElement( + "div", + { + class: classes.join(" "), + }, + linkEl + ); +} + +function createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh +) { + const moreCardEl = createElement( + "div", + { + class: "search-result-more search-item", + onClick: (e) => { + // Handle expanding the sections by adding the expanded + // section to the list of expanded sections + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + e.stopPropagation(); + }, + }, + item.title + ); + + return moreCardEl; +} + +function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { + const expanded = state.context.expanded || []; + if (expanded.includes(item.target)) { + setContext({ + expanded: expanded.filter((target) => target !== item.target), + }); + } else { + setContext({ expanded: [...expanded, item.target] }); + } + + refresh(); + setActiveItemId(item.__autocomplete_id); +} + +function createSectionCard(createElement, section, text, href) { + const sectionEl = createSection(createElement, section, text, href); + return createElement( + "div", + { + class: "search-result-doc-section search-item", + }, + sectionEl + ); +} + +function createSection(createElement, title, text, href) { + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { class: "search-result-section" }, title); + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + [titleEl, descEl] + ); + return linkEl; +} + +function createErrorCard(createElement, title, text) { + const descEl = createElement("p", { + class: "search-error-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { + class: "search-error-title", + dangerouslySetInnerHTML: { + __html: ` ${title}`, + }, + }); + const errorEl = createElement("div", { class: "search-error" }, [ + titleEl, + descEl, + ]); + return errorEl; +} + +function positionPanel(pos) { + const panelEl = window.document.querySelector( + "#quarto-search-results .aa-Panel" + ); + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + + if (panelEl && inputEl) { + panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; + if (pos === "start") { + panelEl.style.left = `${Math.round(inputEl.left)}px`; + } else { + panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; + } + } +} + +/* Highlighting */ +// highlighting functions +function highlightMatch(query, text) { + if (text) { + const start = text.toLowerCase().indexOf(query.toLowerCase()); + if (start !== -1) { + const startMark = ""; + const endMark = ""; + + const end = start + query.length; + text = + text.slice(0, start) + + startMark + + text.slice(start, end) + + endMark + + text.slice(end); + const startInfo = clipStart(text, start); + const endInfo = clipEnd( + text, + startInfo.position + startMark.length + endMark.length + ); + text = + startInfo.prefix + + text.slice(startInfo.position, endInfo.position) + + endInfo.suffix; + + return text; + } else { + return text; + } + } else { + return text; + } +} + +function clipStart(text, pos) { + const clipStart = pos - 50; + if (clipStart < 0) { + // This will just return the start of the string + return { + position: 0, + prefix: "", + }; + } else { + // We're clipping before the start of the string, walk backwards to the first space. + const spacePos = findSpace(text, pos, -1); + return { + position: spacePos.position, + prefix: "", + }; + } +} + +function clipEnd(text, pos) { + const clipEnd = pos + 200; + if (clipEnd > text.length) { + return { + position: text.length, + suffix: "", + }; + } else { + const spacePos = findSpace(text, clipEnd, 1); + return { + position: spacePos.position, + suffix: spacePos.clipped ? "…" : "", + }; + } +} + +function findSpace(text, start, step) { + let stepPos = start; + while (stepPos > -1 && stepPos < text.length) { + const char = text[stepPos]; + if (char === " " || char === "," || char === ":") { + return { + position: step === 1 ? stepPos : stepPos - step, + clipped: stepPos > 1 && stepPos < text.length, + }; + } + stepPos = stepPos + step; + } + + return { + position: stepPos - step, + clipped: false, + }; +} + +// removes highlighting as implemented by the mark tag +function clearHighlight(searchterm, el) { + const childNodes = el.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + if (node.nodeType === Node.ELEMENT_NODE) { + if ( + node.tagName === "MARK" && + node.innerText.toLowerCase() === searchterm.toLowerCase() + ) { + el.replaceChild(document.createTextNode(node.innerText), node); + } else { + clearHighlight(searchterm, node); + } + } + } +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +// highlight matches +function highlight(term, el) { + const termRegex = new RegExp(term, "ig"); + const childNodes = el.childNodes; + + // walk back to front avoid mutating elements in front of us + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + // Search text nodes for text to highlight + const text = node.nodeValue; + + let startIndex = 0; + let matchIndex = text.search(termRegex); + if (matchIndex > -1) { + const markFragment = document.createDocumentFragment(); + while (matchIndex > -1) { + const prefix = text.slice(startIndex, matchIndex); + markFragment.appendChild(document.createTextNode(prefix)); + + const mark = document.createElement("mark"); + mark.appendChild( + document.createTextNode( + text.slice(matchIndex, matchIndex + term.length) + ) + ); + markFragment.appendChild(mark); + + startIndex = matchIndex + term.length; + matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); + if (matchIndex > -1) { + matchIndex = startIndex + matchIndex; + } + } + if (startIndex < text.length) { + markFragment.appendChild( + document.createTextNode(text.slice(startIndex, text.length)) + ); + } + + el.replaceChild(markFragment, node); + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + // recurse through elements + highlight(term, node); + } + } +} + +/* Link Handling */ +// get the offset from this page for a given site root relative url +function offsetURL(url) { + var offset = getMeta("quarto:offset"); + return offset ? offset + url : url; +} + +// read a meta tag value +function getMeta(metaName) { + var metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; +} + +function algoliaSearch(query, limit, algoliaOptions) { + const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; + + const applicationId = algoliaOptions["application-id"]; + const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; + const indexName = algoliaOptions["index-name"]; + const indexFields = algoliaOptions["index-fields"]; + const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); + const searchParams = algoliaOptions["params"]; + const searchAnalytics = !!algoliaOptions["analytics-events"]; + + return getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: indexName, + query, + params: { + hitsPerPage: limit, + clickAnalytics: searchAnalytics, + ...searchParams, + }, + }, + ], + transformResponse: (response) => { + if (!indexFields) { + return response.hits.map((hit) => { + return hit.map((item) => { + return { + ...item, + text: highlightMatch(query, item.text), + }; + }); + }); + } else { + const remappedHits = response.hits.map((hit) => { + return hit.map((item) => { + const newItem = { ...item }; + ["href", "section", "title", "text"].forEach((keyName) => { + const mappedName = indexFields[keyName]; + if ( + mappedName && + item[mappedName] !== undefined && + mappedName !== keyName + ) { + newItem[keyName] = item[mappedName]; + delete newItem[mappedName]; + } + }); + newItem.text = highlightMatch(query, newItem.text); + return newItem; + }); + }); + return remappedHits; + } + }, + }); +} + +function fuseSearch(query, fuse, fuseOptions) { + return fuse.search(query, fuseOptions).map((result) => { + const addParam = (url, name, value) => { + const anchorParts = url.split("#"); + const baseUrl = anchorParts[0]; + const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; + anchorParts[0] = baseUrl + sep + name + "=" + value; + return anchorParts.join("#"); + }; + + return { + title: result.item.title, + section: result.item.section, + href: addParam(result.item.href, kQueryArg, query), + text: highlightMatch(query, result.item.text), + }; + }); +} From 51a78dcdf48c32a8dc181e38d56b130e247cbdc2 Mon Sep 17 00:00:00 2001 From: Mauricio 'Pacha' Vargas Sepulveda Date: Wed, 6 Mar 2024 13:35:11 -0500 Subject: [PATCH 25/25] quarto render to netlify --- .github/workflows/bookdown.yaml | 86 +++++++++++++++------------------ 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/.github/workflows/bookdown.yaml b/.github/workflows/bookdown.yaml index ac832f85..402a0782 100644 --- a/.github/workflows/bookdown.yaml +++ b/.github/workflows/bookdown.yaml @@ -1,61 +1,53 @@ on: push: - branches: - - main + branches: main -name: bookdown +name: Render and Publish jobs: - build: - runs-on: macOS-latest - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + build-deploy: + runs-on: ubuntu-latest steps: - - name: Checkout repo - uses: actions/checkout@v2 - + - name: Check out repository + uses: actions/checkout@v3 + - name: Setup R - uses: r-lib/actions/setup-r@v1 + uses: r-lib/actions/setup-r@v2 - - name: Install pandoc and pandoc citeproc - run: | - brew install pandoc + - name: Setup pandoc + uses: r-lib/actions/setup-pandoc@v2 - - name: Cache Renv packages - uses: actions/cache@v2 - with: - path: $HOME/.local/share/renv - key: r-${{ hashFiles('renv.lock') }} - restore-keys: r- + - name: Get R version + id: get-r-version + run: echo "version=$(Rscript -e 'cat(as.character(getRversion()))')" >> $GITHUB_OUTPUT + shell: bash - - name: Cache bookdown results - uses: actions/cache@v2 + - name: Cache R packages + uses: actions/cache@v3 with: - path: _bookdown_files - key: bookdown-${{ hashFiles('**/*Rmd') }} - restore-keys: bookdown- + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-${{ steps.get-r-version.outputs.version }}-3- - - name: Install packages + - name: Install dependencies run: | - R -e 'install.packages("renv")' - R -e 'renv::restore()' - R -e 'install.packages("remotes")' - R -e 'remotes::install_github("hadley/emo")' - R -e 'remotes::install_github("rstudio/bslib")' - R -e 'remotes::install_deps(dependencies = TRUE)' - - - name: Build site - run: Rscript -e 'bookdown::render_book("index.Rmd", quiet = TRUE)' - - - name: Install npm - uses: actions/setup-node@v1 - - - name: Deploy to Netlify - if: github.ref == 'refs/heads/main' - # NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID added in the repo's secrets - env: + install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") + pak::local_install_dev_deps() + shell: Rscript {0} + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + with: + tinytex: false + + # - name: Publish to GitHub Pages (and render) + # uses: quarto-dev/quarto-actions/publish@v2 + # with: + # target: gh-pages + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # this secret is always available for github actions + + - name: Publish to Netlify (and render) + uses: quarto-dev/quarto-actions/publish@v2 + with: + target: netlify NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - run: | - npm install netlify-cli -g - netlify deploy --prod --dir=_book

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%0Do(Ypwhtj1# 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