diff --git a/_posts/2023-12-13-class-11-programming-pt-1/programming-pt1.html b/_posts/2023-12-13-class-11-programming-pt-1/programming-pt1.html new file mode 100644 index 0000000..392b482 --- /dev/null +++ b/_posts/2023-12-13-class-11-programming-pt-1/programming-pt1.html @@ -0,0 +1,2253 @@ + + + + +
+ + + + + + + + + + + + + + + +The Rmarkdown for this class is on github
+# Conditionally download files from github
+source("https://raw.githubusercontent.com/rnabioco/bmsc-7810-pbda/main/_posts/2023-12-13-class-11-programming-pt-1/download-files.R")
+As an analyst you will eventually find yourself in the position of wanting to reuse a block of code. There are two general ways to do this:
+A function is essentially a block of code that you’ve given a name and saved for later. Functions have several advantages:
+Further reading
+# An example: you want to rescale a numeric vector so all values are between 0 and 1
+a <- rnorm(n = 10)
+
+a
+#> [1] -1.5705683 0.4351164 1.3195600 -0.6617301 -0.4725234 0.6865979
+#> [7] -0.3130226 -0.0628920 0.1060156 0.4955234
+rng <- range(a)
+
+(a - rng[1]) / (rng[2] - rng[1])
+#> [1] 0.0000000 0.6939777 1.0000000 0.3144629 0.3799295 0.7809917
+#> [7] 0.4351176 0.5216641 0.5801071 0.7148789
+
+There are three general steps for writing functions:
+# Lets write a function to rescale a numeric vector
+rescale_vec <- function(x) {
+
+ rng <- range(x)
+
+ (x - rng[1]) / (rng[2] - rng[1])
+}
+
+rescale_vec(b)
+rescale_vec(c)
+Write functions for the following bits of code
+Can objects present in the global environment be referenced from within a function?
+# Earlier we saved a numeric vector "a"
+a
+#> [1] -1.5705683 0.4351164 1.3195600 -0.6617301 -0.4725234 0.6865979
+#> [7] -0.3130226 -0.0628920 0.1060156 0.4955234
+sum_nums <- function(x) {
+ x + a
+}
+# Yes!
+sum_nums(10)
+#> [1] 8.429432 10.435116 11.319560 9.338270 9.527477 10.686598
+#> [7] 9.686977 9.937108 10.106016 10.495523
+Can code executed within a function modify an object present in the global environment?
+sum_nums <- function(x) {
+ a <- x + a
+}
+
+# When we run sum_nums(), will this overwrite our original vector?
+sum_nums(10)
+
+# No! (not when using the '<-' assignment operator)
+a
+#> [1] -1.5705683 0.4351164 1.3195600 -0.6617301 -0.4725234 0.6865979
+#> [7] -0.3130226 -0.0628920 0.1060156 0.4955234
+The brauer_gene_exp
data contains a data set from a manuscript describing how gene expression changes in yeast under several nutrient limitation conditions. We’ll use this data to illustrate the utility and the power of functions.
Using the Brauer data lets create a scatter plot comparing growth rate vs expression for the gene YDL104C. Use facet_wrap()
to create a separate plot for each nutrient.
brauer_gene_exp <- read_csv("data/brauer_gene_exp.csv.gz")
+What if you want to create this plot for other genes? Write a function the takes a data.frame and systematic_name as inputs and creates scatter plots for each nutrient
+# Fill in the function body
+# You can include default values for your arguments
+<- function(input, sys_name = "YNL049C") {
+ plot_expr
+
+ ????
+ }
plot_expr <- function(input, sys_name = "YNL049C") {
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+p <- plot_expr(
+ input = brauer_gene_exp,
+ sys_name = "YDL104C"
+)
+
+# You can also use the %>% pipe with your custom functions
+p <- brauer_gene_exp %>%
+ plot_expr(sys_name = "YDL104C")
+
+p
+Modify our plotting function to add the gene name as the plot title and the molecular function (MF) as a subtitle
+plot_expr <- function(input, sys_name) {
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ plot_title <- gg_data$name[1]
+ plot_sub <- gg_data$MF[1]
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ ggtitle(plot_title) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+brauer_gene_exp %>%
+ plot_expr("YDL104C")
+As you’ve seen objects that are passed to a function are not modified within the function by default. Intuitively you can think of each object being copied within the function environment to avoid modification of the original. However this would be memory inefficient and slow approach, as copying multiple large objects takes time and space.
+Instead R adopts a “copy-on-modify” approach with objects. Objects are only copied when it is necessary. The same is true of objects outside of functions.
+change_to_char <- function(large_object) {
+
+ # large object is not a copy, but a reference
+ large_object
+
+ # now a new copy of large_object is made
+ large_object <- as.character(large_object)
+ large_object
+}
+
+mat <- matrix(1:100, nrow = 10)
+
+# not copied
+a <- mat
+
+# mat not copied yet
+mat[1:5, 1:5]
+
+# now a copy is made
+mat2 <- as.character(mat)
+mat2 <- as.data.frame(mat)
+if
statements allow you to execute code depending on defined conditions.
if (condition) {
+TRUE
+ code executed when condition is
+ else {
+ } FALSE
+ code executed when condition is }
R has a set of operators that can be used to write conditional statements
+Operator | +Description | +
---|---|
< | +less than | +
<= | +less or equal | +
> | +greater than | +
>= | +greater or equal | +
== | +equal | +
!= | +not equal | +
!x | +not x | +
x | y | +x or y (returns a vector of logicals) | +
x || y | +x or y (returns single TRUE or FALSE) | +
x & y | +x and y (returns a vector of logicals) | +
x && y | +x and y (returns single TRUE or FALSE) | +
x %in% y | +x is present in y | +
Add an if
statement to our plotting function to account for a missing gene name
plot_expr <- function(input, sys_name) {
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ plot_title <- gg_data$name[1]
+ plot_sub <- gg_data$MF[1]
+
+ ????
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+plot_expr <- function(input, sys_name) {
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ plot_title <- gg_data$name[1]
+ plot_sub <- gg_data$MF[1]
+
+ if (is.na(plot_title)) {
+ plot_title <- sys_name
+ }
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+brauer_gene_exp %>%
+ plot_expr("YNL095C")
+Conditional statements can be linked together
+# Using 'else if'
+if (condition_1) {
+TRUE
+ executed when condition_1 is
+ else if (condition_2) {
+ } FALSE and condition_2 is TRUE
+ executed when condition_1 is
+ else {
+ } FALSE
+ executed when condition_1 and condition_2 are
+ }
+# The 'and' operator
+if (condition_1 && condition_2) {
+TRUE
+ executed when condition_1 and condition_2 are
+ else {
+ } FALSE
+ executed when condition_1 or condition_2 are
+ }
+# The 'or' operator
+if (condition_1 || condition_2) {
+TRUE
+ executed when condition_1 or condition_2 are
+ else {
+ } FALSE
+ executed when condition_1 and condition_2 are }
stop()
, warning()
, message()
, and stopifnot()
are commonly used functions in R for reporting information and/or stopping execution based on a condition.
See also tryCatch()
for “catching” errors and performing alternative actions.
When writing functions it can be useful to check input values to make sure they are valid. Lets modify our plotting function to check that sys_name
is a string.
is.character()
is.numeric()
is.logical()
is.factor()
plot_expr <- function(input, sys_name) {
+
+ if (!is.character(sys_name)) {
+ stop("sys_name must be a string!")
+ }
+
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ plot_title <- gg_data$name[1]
+ plot_sub <- gg_data$MF[1]
+
+ if (is.na(plot_title)) {
+ plot_title <- sys_name
+ }
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+
+brauer_gene_exp %>%
+ plot_expr("YDL104C")
+Modify our plotting function to check that sys_name
is present in the input. Hint: try the %in%
operator
<- function(input, sys_name) {
+ plot_expr
+ if (!is.character(sys_name)) {
+ stop("sys_name must be a string!")
+
+ }
+ if ( ???? ) {
+ stop( ???? )
+
+ }
+ <- input %>%
+ gg_data filter(systematic_name == sys_name)
+
+ <- gg_data$name[1]
+ plot_title <- gg_data$MF[1]
+ plot_sub
+ if (is.na(plot_title) ){
+ <- sys_name
+ plot_title
+ }
+ %>%
+ gg_data ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+ }
plot_expr <- function(input, sys_name) {
+
+ if (!is.character(sys_name)) {
+ stop("sys_name must be a string!")
+ }
+
+ if (!sys_name %in% input$systematic_name) {
+ stop("sys_name not found in input data!")
+ }
+
+ gg_data <- input %>%
+ filter(systematic_name == sys_name)
+
+ plot_title <- gg_data$name[1]
+ plot_sub <- gg_data$MF[1]
+
+ if (plot_title == "") {
+ plot_title <- sys_name
+ }
+
+ gg_data %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = 2) +
+ labs(title = plot_title, subtitle = plot_sub) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+The ellipsis allows a function to take an arbitrary number of arguments, which can then be passed to an inner function. This is nice when you have an inner function that has a lot of useful arguments. Lets first try this with our simple rescale_vec()
function.
rescale_vec <- function(x, ...) {
+ rng <- range(x, ...)
+ (x - rng[1]) / (rng[2] - rng[1])
+}
+
+rescale_vec(a)
+#> [1] 0.0000000 0.6939777 1.0000000 0.3144629 0.3799295 0.7809917
+#> [7] 0.4351176 0.5216641 0.5801071 0.7148789
+
+a[1] <- NA
+
+rescale_vec(a, na.rm = T)
+#> [1] NA 0.55360218 1.00000000 0.00000000 0.09549672 0.68053034
+#> [7] 0.17600023 0.30224655 0.38749789 0.58409089
+Modify our plotting function so the user can change the point size, shape, and alpha
+# A cumbersome way
+plot_expr <- function(input, sys_name, pt_size = 2, pt_shape = 1, pt_alpha = 1) {
+ input %>%
+ filter(systematic_name == sys_name) %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(size = pt_size, shape = pt_shape, alpha = pt_alpha) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+
+# With the ellipsis
+plot_expr <- function(input, sys_name, ...) {
+ input %>%
+ filter(systematic_name == sys_name) %>%
+ ggplot(aes(rate, expression, color = nutrient)) +
+ geom_point(...) +
+ facet_wrap(~ nutrient) +
+ theme(legend.position = "none")
+}
+
+# Now we can easily change the point size and shape
+plot_expr(
+ input = brauer_gene_exp,
+ sys_name = "YDL104C",
+ size = 5,
+ shape = 2,
+ alpha = 0.75
+)
+A good way to save commonly used functions is to keep them in a separate R script. You can load your functions using the source()
command.
source("path/to/my_functions.R")
+sessionInfo()
+#> R version 4.3.1 (2023-06-16)
+#> Platform: x86_64-pc-linux-gnu (64-bit)
+#> Running under: Ubuntu 22.04.3 LTS
+#>
+#> Matrix products: default
+#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
+#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0
+#>
+#> locale:
+#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
+#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
+#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
+#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
+#> [9] LC_ADDRESS=C LC_TELEPHONE=C
+#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
+#>
+#> time zone: America/Denver
+#> tzcode source: system (glibc)
+#>
+#> attached base packages:
+#> [1] stats graphics grDevices utils datasets methods
+#> [7] base
+#>
+#> other attached packages:
+#> [1] lubridate_1.9.3 forcats_1.0.0 stringr_1.5.0 dplyr_1.1.3
+#> [5] purrr_1.0.2 readr_2.1.4 tidyr_1.3.0 tibble_3.2.1
+#> [9] ggplot2_3.4.3 tidyverse_2.0.0
+#>
+#> loaded via a namespace (and not attached):
+#> [1] sass_0.4.7 utf8_1.2.3 generics_0.1.3
+#> [4] stringi_1.7.12 distill_1.6 hms_1.1.3
+#> [7] digest_0.6.33 magrittr_2.0.3 evaluate_0.22
+#> [10] grid_4.3.1 timechange_0.2.0 fastmap_1.1.1
+#> [13] jsonlite_1.8.7 fansi_1.0.4 scales_1.2.1
+#> [16] jquerylib_0.1.4 cli_3.6.1 rlang_1.1.1
+#> [19] crayon_1.5.2 bit64_4.0.5 munsell_0.5.0
+#> [22] withr_2.5.1 cachem_1.0.8 yaml_2.3.7
+#> [25] parallel_4.3.1 tools_4.3.1 tzdb_0.4.0
+#> [28] memoise_2.0.1 colorspace_2.1-0 vctrs_0.6.3
+#> [31] R6_2.5.1 lifecycle_1.0.3 bit_4.0.5
+#> [34] vroom_1.6.3 pkgconfig_2.0.3 pillar_1.9.0
+#> [37] bslib_0.5.1 gtable_0.3.4 glue_1.6.2
+#> [40] xfun_0.40 tidyselect_1.2.0 rstudioapi_0.15.0
+#> [43] knitr_1.44 farver_2.1.1 htmltools_0.5.6
+#> [46] labeling_0.4.3 rmarkdown_2.25 compiler_4.3.1
+#> [49] downlit_0.4.3
+
`,e.githubCompareUpdatesUrl&&(t+=`View all changes to this article since it was first published.`),t+=` + If you see mistakes or want to suggest changes, please create an issue on GitHub.
+ `);const n=e.journal;return'undefined'!=typeof n&&'Distill'===n.title&&(t+=` +Diagrams and text are licensed under Creative Commons Attribution CC-BY 4.0 with the source available on GitHub, unless noted otherwise. The figures that have been reused from other sources don’t fall under this license and can be recognized by a note in their caption: “Figure from …”.
+ `),'undefined'!=typeof e.publishedDate&&(t+=` +For attribution in academic contexts, please cite this work as
+${e.concatenatedAuthors}, "${e.title}", Distill, ${e.publishedYear}.+
BibTeX citation
+${m(e)}+ `),t}var An=Math.sqrt,En=Math.atan2,Dn=Math.sin,Mn=Math.cos,On=Math.PI,Un=Math.abs,In=Math.pow,Nn=Math.LN10,jn=Math.log,Rn=Math.max,qn=Math.ceil,Fn=Math.floor,Pn=Math.round,Hn=Math.min;const zn=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],Bn=['Jan.','Feb.','March','April','May','June','July','Aug.','Sept.','Oct.','Nov.','Dec.'],Wn=(e)=>10>e?'0'+e:e,Vn=function(e){const t=zn[e.getDay()].substring(0,3),n=Wn(e.getDate()),i=Bn[e.getMonth()].substring(0,3),a=e.getFullYear().toString(),d=e.getUTCHours().toString(),r=e.getUTCMinutes().toString(),o=e.getUTCSeconds().toString();return`${t}, ${n} ${i} ${a} ${d}:${r}:${o} Z`},$n=function(e){const t=Array.from(e).reduce((e,[t,n])=>Object.assign(e,{[t]:n}),{});return t},Jn=function(e){const t=new Map;for(var n in e)e.hasOwnProperty(n)&&t.set(n,e[n]);return t};class Qn{constructor(e){this.name=e.author,this.personalURL=e.authorURL,this.affiliation=e.affiliation,this.affiliationURL=e.affiliationURL,this.affiliations=e.affiliations||[]}get firstName(){const e=this.name.split(' ');return e.slice(0,e.length-1).join(' ')}get lastName(){const e=this.name.split(' ');return e[e.length-1]}}class Gn{constructor(){this.title='unnamed article',this.description='',this.authors=[],this.bibliography=new Map,this.bibliographyParsed=!1,this.citations=[],this.citationsCollected=!1,this.journal={},this.katex={},this.publishedDate=void 0}set url(e){this._url=e}get url(){if(this._url)return this._url;return this.distillPath&&this.journal.url?this.journal.url+'/'+this.distillPath:this.journal.url?this.journal.url:void 0}get githubUrl(){return this.githubPath?'https://github.com/'+this.githubPath:void 0}set previewURL(e){this._previewURL=e}get previewURL(){return this._previewURL?this._previewURL:this.url+'/thumbnail.jpg'}get publishedDateRFC(){return Vn(this.publishedDate)}get updatedDateRFC(){return Vn(this.updatedDate)}get publishedYear(){return this.publishedDate.getFullYear()}get publishedMonth(){return Bn[this.publishedDate.getMonth()]}get publishedDay(){return this.publishedDate.getDate()}get publishedMonthPadded(){return Wn(this.publishedDate.getMonth()+1)}get publishedDayPadded(){return Wn(this.publishedDate.getDate())}get publishedISODateOnly(){return this.publishedDate.toISOString().split('T')[0]}get volume(){const e=this.publishedYear-2015;if(1>e)throw new Error('Invalid publish date detected during computing volume');return e}get issue(){return this.publishedDate.getMonth()+1}get concatenatedAuthors(){if(2
tag. We found the following text: '+t);const n=document.createElement('span');n.innerHTML=e.nodeValue,e.parentNode.insertBefore(n,e),e.parentNode.removeChild(e)}}}}).observe(this,{childList:!0})}}var Ti='undefined'==typeof window?'undefined'==typeof global?'undefined'==typeof self?{}:self:global:window,_i=f(function(e,t){(function(e){function t(){this.months=['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'],this.notKey=[',','{','}',' ','='],this.pos=0,this.input='',this.entries=[],this.currentEntry='',this.setInput=function(e){this.input=e},this.getEntries=function(){return this.entries},this.isWhitespace=function(e){return' '==e||'\r'==e||'\t'==e||'\n'==e},this.match=function(e,t){if((void 0==t||null==t)&&(t=!0),this.skipWhitespace(t),this.input.substring(this.pos,this.pos+e.length)==e)this.pos+=e.length;else throw'Token mismatch, expected '+e+', found '+this.input.substring(this.pos);this.skipWhitespace(t)},this.tryMatch=function(e,t){return(void 0==t||null==t)&&(t=!0),this.skipWhitespace(t),this.input.substring(this.pos,this.pos+e.length)==e},this.matchAt=function(){for(;this.input.length>this.pos&&'@'!=this.input[this.pos];)this.pos++;return!('@'!=this.input[this.pos])},this.skipWhitespace=function(e){for(;this.isWhitespace(this.input[this.pos]);)this.pos++;if('%'==this.input[this.pos]&&!0==e){for(;'\n'!=this.input[this.pos];)this.pos++;this.skipWhitespace(e)}},this.value_braces=function(){var e=0;this.match('{',!1);for(var t=this.pos,n=!1;;){if(!n)if('}'==this.input[this.pos]){if(0 =k&&(++x,i=k);if(d[x]instanceof n||d[T-1].greedy)continue;w=T-x,y=e.slice(i,k),v.index-=i}if(v){g&&(h=v[1].length);var S=v.index+h,v=v[0].slice(h),C=S+v.length,_=y.slice(0,S),L=y.slice(C),A=[x,w];_&&A.push(_);var E=new n(o,u?a.tokenize(v,u):v,b,v,f);A.push(E),L&&A.push(L),Array.prototype.splice.apply(d,A)}}}}}return d},hooks:{all:{},add:function(e,t){var n=a.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=a.hooks.all[e];if(n&&n.length)for(var d,r=0;d=n[r++];)d(t)}}},i=a.Token=function(e,t,n,i,a){this.type=e,this.content=t,this.alias=n,this.length=0|(i||'').length,this.greedy=!!a};if(i.stringify=function(e,t,n){if('string'==typeof e)return e;if('Array'===a.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join('');var d={type:e.type,content:i.stringify(e.content,t,n),tag:'span',classes:['token',e.type],attributes:{},language:t,parent:n};if('comment'==d.type&&(d.attributes.spellcheck='true'),e.alias){var r='Array'===a.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(d.classes,r)}a.hooks.run('wrap',d);var l=Object.keys(d.attributes).map(function(e){return e+'="'+(d.attributes[e]||'').replace(/"/g,'"')+'"'}).join(' ');return'<'+d.tag+' class="'+d.classes.join(' ')+'"'+(l?' '+l:'')+'>'+d.content+''+d.tag+'>'},!t.document)return t.addEventListener?(t.addEventListener('message',function(e){var n=JSON.parse(e.data),i=n.language,d=n.code,r=n.immediateClose;t.postMessage(a.highlight(d,a.languages[i],i)),r&&t.close()},!1),t.Prism):t.Prism;var d=document.currentScript||[].slice.call(document.getElementsByTagName('script')).pop();return d&&(a.filename=d.src,document.addEventListener&&!d.hasAttribute('data-manual')&&('loading'===document.readyState?document.addEventListener('DOMContentLoaded',a.highlightAll):window.requestAnimationFrame?window.requestAnimationFrame(a.highlightAll):window.setTimeout(a.highlightAll,16))),t.Prism}();e.exports&&(e.exports=n),'undefined'!=typeof Ti&&(Ti.Prism=n),n.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},n.hooks.add('wrap',function(e){'entity'===e.type&&(e.attributes.title=e.content.replace(/&/,'&'))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore('markup','tag',{style:{pattern:/(
+
+
+ ${e.map(l).map((e)=>`
`)}}const Mi=`
+d-citation-list {
+ contain: layout style;
+}
+
+d-citation-list .references {
+ grid-column: text;
+}
+
+d-citation-list .references .title {
+ font-weight: 500;
+}
+`;class Oi extends HTMLElement{static get is(){return'd-citation-list'}connectedCallback(){this.hasAttribute('distill-prerendered')||(this.style.display='none')}set citations(e){x(this,e)}}var Ui=f(function(e){var t='undefined'==typeof window?'undefined'!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{}:window,n=function(){var e=/\blang(?:uage)?-(\w+)\b/i,n=0,a=t.Prism={util:{encode:function(e){return e instanceof i?new i(e.type,a.util.encode(e.content),e.alias):'Array'===a.util.type(e)?e.map(a.util.encode):e.replace(/&/g,'&').replace(/e.length)break tokenloop;if(!(y instanceof n)){c.lastIndex=0;var v=c.exec(y),w=1;if(!v&&f&&x!=d.length-1){if(c.lastIndex=i,v=c.exec(e),!v)break;for(var S=v.index+(g?v[1].length:0),C=v.index+v[0].length,T=x,k=i,p=d.length;T
+
+`);class Ni extends ei(Ii(HTMLElement)){renderContent(){if(this.languageName=this.getAttribute('language'),!this.languageName)return void console.warn('You need to provide a language attribute to your
Footnotes
+
+`,!1);class Fi extends qi(HTMLElement){connectedCallback(){super.connectedCallback(),this.list=this.root.querySelector('ol'),this.root.style.display='none'}set footnotes(e){if(this.list.innerHTML='',e.length){this.root.style.display='';for(const t of e){const e=document.createElement('li');e.id=t.id+'-listing',e.innerHTML=t.innerHTML;const n=document.createElement('a');n.setAttribute('class','footnote-backlink'),n.textContent='[\u21A9]',n.href='#'+t.id,e.appendChild(n),this.list.appendChild(e)}}else this.root.style.display='none'}}const Pi=ti('d-hover-box',`
+
+
+