diff --git a/classroom_data/frieda.json b/classroom_data/frieda.json new file mode 100644 index 0000000..52432c0 --- /dev/null +++ b/classroom_data/frieda.json @@ -0,0 +1,20 @@ +{ + "name": "Frieda", + "isDog": true, + "hobbies": ["eating", "sleeping", "barking"], + "age": 8, + "address": { + "work": null, + "home": ["Berlin", "Germany"] + }, + "friends": [ + { + "name": "Philipp", + "hobbies": ["eating", "sleeping", "reading"] + }, + { + "name": "Mitch", + "hobbies": ["running", "snacking"] + } + ] +} \ No newline at end of file diff --git a/images/references.png b/images/references.png new file mode 100644 index 0000000..2891af4 Binary files /dev/null and b/images/references.png differ diff --git a/images/references2.png b/images/references2.png new file mode 100644 index 0000000..d724e4b Binary files /dev/null and b/images/references2.png differ diff --git a/slides/images/function_machine.png b/slides/images/function_machine.png new file mode 100644 index 0000000..2bb7d9f Binary files /dev/null and b/slides/images/function_machine.png differ diff --git a/slides/images/horst_community.png b/slides/images/horst_community.png new file mode 100644 index 0000000..ebc6540 Binary files /dev/null and b/slides/images/horst_community.png differ diff --git a/slides/images/list_subset_0.png b/slides/images/list_subset_0.png new file mode 100644 index 0000000..542e616 Binary files /dev/null and b/slides/images/list_subset_0.png differ diff --git a/slides/images/student_stickers.jpg b/slides/images/student_stickers.jpg new file mode 100644 index 0000000..a05acbb Binary files /dev/null and b/slides/images/student_stickers.jpg differ diff --git a/slides/lesson1_slides.html b/slides/lesson1_slides.html new file mode 100644 index 0000000..6d1b63d --- /dev/null +++ b/slides/lesson1_slides.html @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + W1: Fundamentals + + + + + + + + + + + + + + + + + + +
+
+ +
+

W1: Fundamentals

+ +
+
+ +
+
+

Welcome!

+

Please sign up for Google Classroom (link) if you haven’t already.

+
+
+

Introductions

+
    +
  • Who am I?
  • +
+
+
    +
  • What is DaSL?
  • +
+
+
+
    +
  • Who are you?

    +
      +
    • Name, pronouns, group you work in

    • +
    • What you want to get out of the class

    • +
    • Something that keeps you going in the winter!

    • +
  • +
+
+
+
+

Goals of the course

+
+
    +
  • Continue building programming fundamentals: How to use complex data structures, write your own functions, and how to iterate repeated tasks.
  • +
+
+
+
    +
  • Continue exploration of data science fundamentals: how to clean messy data using the programming fundamentals above to a Tidy form for analysis.
  • +
+
+
+
+

A Motivating Example

+

https://colab.research.google.com/drive/1g2ylY3-s_jX2Yf2CGkIdApvgTP4vb0Dw?usp=sharing

+
+
+

Content of the course

+
    +
  1. Fundamentals and Dictionaries
  2. +
  3. Iteration
  4. +
  5. Functions
  6. +
  7. Iteration styles
  8. +
  9. Assignment and References
  10. +
  11. Mid-winter break! (for Seattle Public Schools)
  12. +
  13. Modules, Wrap-up
  14. +
  15. Optional: Data-a-thon Friday March 14, Learning Communities
  16. +
+

Full course page here: https://hutchdatascience.org/Intermediate_Python/

+
+
+

Format of the course

+
+
    +
  • Hybrid, and recordings will be available.
  • +
+
+
+
    +
  • 1-2 hour exercises after each session are encouraged for practice; time at beginning of class provided to work on exercises.
  • +
+
+
+
    +
  • Office Hours Fridays 10am - 11am PT.
  • +
+
+
+
+

Culture of the course

+
+
    +
  • Challenge: We are learning a new language, but you already have a full-time job
  • +
+
+
+
    +
  • Teach not for mastery, but teach for empowerment to learn effectively.
  • +
+
+
+
+

Culture of the course

+
    +
  • Challenge: We sometimes struggle with our data science in isolation, unaware that someone two doors down from us has gone through the same struggle.
  • +
+
+
    +
  • We learn and work better with our peers.
  • +
+
+
+
    +
  • Know that if you have a question, other people will have it.
  • +
+
+
+

We ask you to follow Participation Guidelines and Code of Conduct.

+
+
+
+

Ready?

+ +
+
+

Data types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Data type nameData type shorthandExamples
Integerint2, 4
Floatfloat3.5, -34.1009
Stringstr“hello”, “234-234-8594”
BooleanboolTrue, False
+
+

There is a special None data type that shows up when nothing is returned from an expression.

+
+
+
+

Data structures

+
    +
  • List

  • +
  • Dataframe

  • +
  • Dictionary

  • +
  • Tuple
    +

  • +
+
+
+

Objects in Python

+

What does it contain?

+
+
    +
  • Value that holds the essential data for the object.
  • +
+
+
+
    +
  • Attributes that hold subset of the data or additional data for the object.
  • +
+
+
+

What can it do?

+
    +
  • Functions called Methods specific to the data type and automatically takes the object as input.
  • +
+
+
+

This organizing structure on an object applies to pretty much all Python data types and data structures.

+
+
+
+

Lists as an Object

+

What does it contain?

+
    +
  • Value: the contents of the list, such as [2, 3, 4].
  • +
+
+
    +
  • Attributes: subsetting via [ ].
  • +
+
+
+

What can it do (methods)?

+
    +
  • my_list.append(4) appends 4 to the last element of my_list, but does not return anything.
  • +
+
+
+

What’s the difference between a method and a function?

+
+
+
+

Dataframe as an Object

+

What does it contain?

+
    +
  • Value: the spreadsheet of data.
  • +
+
+
    +
  • Attributes:

    +
  • +
+
+
+

What can it do (methods)?

+
    +
  • .head()

  • +
  • .tail()

  • +
+
+
+
+

Break!

+

A quick survey to get us started: https://forms.gle/U6atGeMHdjQuvTK67

+
+
+

Dictionary

+

A dictionary is designed as a lookup table, organized in key-value pairs. You associate the key with a particular value, and use the key to find the value.

+
+
+
sentiment = {'happy': 8, 'sad': 2, 'joy': 7.5, 'embarrassed': 3.6, 'restless': 4.1, 'apathetic': 3.8, 'calm': 7}
+sentiment
+
+
+
+
{'happy': 8,
+ 'sad': 2,
+ 'joy': 7.5,
+ 'embarrassed': 3.6,
+ 'restless': 4.1,
+ 'apathetic': 3.8,
+ 'calm': 7}
+
+
+
+
+

You use a key to find its corresponding value:

+
+
sentiment['joy']
+
+
+
+
7.5
+
+
+
+
+

You cannot use a numerical index to find values, like you did for Lists!

+
+
#sentiment[0]
+
+
+ +
+
+
+
+

Rules of Dictionaries

+
    +
  • Only one value per key. No duplicate keys allowed.
  • +
+
+
    +
  • Keys must be of string, integer, float, boolean, or tuple.
  • +
+
+
+
    +
  • Values can be of any type, including data structures such as lists and dictionaries.
  • +
+
+
+
+
duplicated_keys = {'Student' : 97, 'Student': 88, 'Student' : 91}
+duplicated_keys
+
+
+
+
{'Student': 91}
+
+
+
+
+
+
child = {"name" : "Emil", "year" : 2004, "likes": ["jumping", "skating", "laughing"]}
+
+
+ +
+
+
+
+
child["likes"][1]
+
+
+
+
'skating'
+
+
+
+
+

Data stored in nested dictionaries are often represented as JSON files. Here’s a guide on using JSON files in Python.

+
+
+
+

Using key to find values

+
+
sentiment['joy'] 
+
+
+
+
7.5
+
+
+
+
+
sentiment['joy'] = sentiment['joy'] + 1
+
+
+ +
+
+
+

If a key doesn’t exist, you will get an error:

+
+
#sentiment["dog"]
+
+
+ +
+
+
+

If you don’t want to run the risk of getting an error, you can specify a default value using the .get() method.

+
+
sentiment.get("dog", "not found")
+
+
+
+
'not found'
+
+
+
+
+
+
print(sentiment.get("dog"))
+
+
+
+
None
+
+
+
+
+
+

Adding new key-value pairs

+

You can add more key-value pairs by defining it directly. If the key already exists, the mapping for that key will simply be updated.

+
+
sentiment['dog'] = 5
+
+
+ +
+
+
+

Application: Creating a Dataframe

+

You can create a Dataframe using a Dictionary. The key represent column names, and the value is a List containing the column’s values:

+
+
import pandas as pd
+
+simple_df = pd.DataFrame(data={'id': ["AAA", "BBB", "CCC", "DDD", "EEE"],
+                               'case_control': ["case", "case", "control", "control", "control"],
+                               'measurement1': [2.5, 3.5, 9, .1, 2.2],
+                               'measurement2': [0, 0, .5, .24, .003],
+                               'measurement3': [80, 2, 1, 1, 2]})
+                               
+simple_df
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idcase_controlmeasurement1measurement2measurement3
0AAAcase2.50.00080
1BBBcase3.50.0002
2CCCcontrol9.00.5001
3DDDcontrol0.10.2401
4EEEcontrol2.20.0032
+ +
+
+
+
+
+

Application: Data Recoding

+

You want to take “case_control” column of simple_df and change “case” to “experiment” and “control” to “baseline”.

+

This correspondence relationship can be stored in a dictionary via .replace() method for Series:

+
+
simple_df.case_control.replace({"case": "experiment", "control": "baseline"})
+
+
+
+
0    experiment
+1    experiment
+2      baseline
+3      baseline
+4      baseline
+Name: case_control, dtype: object
+
+
+
+

You can do something similar to recode the column names of a Dataframe via the .rename() method.

+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/slides/lesson1_slides.qmd b/slides/lesson1_slides.qmd new file mode 100644 index 0000000..5d76845 --- /dev/null +++ b/slides/lesson1_slides.qmd @@ -0,0 +1,334 @@ +--- +title: "W1: Fundamentals" +format: + revealjs: + smaller: false + scrollable: true + echo: true +output-location: fragment +--- + +## Welcome! + +Please sign up for Google Classroom ([link](https://classroom.google.com/c/NzQ0NjM1Njg1NTQ4?cjc=cbdp7dy)) if you haven't already. + +## Introductions + +- Who am I? + +. . . + +- What is DaSL? + +. . . + +- Who are you? + + - Name, pronouns, group you work in + + - What you want to get out of the class + + - Something that keeps you going in the winter! + +## Goals of the course + +. . . + +- Continue building *programming fundamentals*: How to use complex data structures, write your own functions, and how to iterate repeated tasks. + +. . . + +- Continue exploration of *data science fundamentals*: how to clean messy data using the programming fundamentals above to a Tidy form for analysis. + +## [A Motivating Example](https://colab.research.google.com/drive/1g2ylY3-s_jX2Yf2CGkIdApvgTP4vb0Dw?usp=sharing) + +[https://colab.research.google.com/drive/1g2ylY3-s_jX2Yf2CGkIdApvgTP4vb0Dw?usp=sharing](https://colab.research.google.com/drive/1g2ylY3-s_jX2Yf2CGkIdApvgTP4vb0Dw?usp=sharinghttps://colab.research.google.com/drive/1g2ylY3-s_jX2Yf2CGkIdApvgTP4vb0Dw?usp=sharing) + +## Content of the course + +1. Fundamentals and Dictionaries +2. Iteration +3. Functions +4. Iteration styles +5. Assignment and References +6. Mid-winter break! (for Seattle Public Schools) +7. Modules, Wrap-up +8. Optional: Data-a-thon Friday March 14, Learning Communities + +Full course page here: + +## Format of the course + +. . . + +- Hybrid, and recordings will be available. + +. . . + +- 1-2 hour exercises after each session are encouraged for practice; time at beginning of class provided to work on exercises. + +. . . + +- Office Hours Fridays 10am - 11am PT. + +## Culture of the course + +. . . + +- Challenge: We are learning a new language, but you already have a full-time job + +. . . + +- *Teach not for mastery, but teach for empowerment to learn effectively.* + +## Culture of the course + +- Challenge: We sometimes struggle with our data science in isolation, unaware that someone two doors down from us has gone through the same struggle. + +. . . + +- *We learn and work better with our peers.* + +. . . + +- *Know that if you have a question, other people will have it.* + +. . . + +We ask you to follow [Participation Guidelines](https://hutchdatascience.org/communitystudios/guidelines/) and [Code of Conduct](https://github.com/fhdsl/coc). + +## Ready? + +![](images/horst_community.png) + +## Data types + +| Data type name | **Data type shorthand** | **Examples** | +|----------------|:-----------------------:|:-----------------------:| +| Integer | int | 2, 4 | +| Float | float | 3.5, -34.1009 | +| String | str | "hello", "234-234-8594" | +| Boolean | bool | True, False | + +. . . + +There is a special `None` data type that shows up when nothing is returned from an expression. + +## Data structures + +- List + +- Dataframe + +- **Dictionary** + +- **Tuple\ + ** + +## Objects in Python + +*What does it contain?* + +. . . + +- **Value** that holds the essential data for the object. + +. . . + +- **Attributes** that hold subset of the data or additional data for the object. + +. . . + +*What can it do?* + +- Functions called **Methods** specific to the data type and automatically takes the object as input. + +. . . + +This organizing structure on an object applies to pretty much all Python data types and data structures. + +## Lists as an Object + +*What does it contain?* + +- **Value**: the contents of the list, such as `[2, 3, 4]`. + +. . . + +- **Attributes**: subsetting via `[ ]`. + +. . . + +*What can it do (methods)?* + +- `my_list.append(4)` appends 4 to the last element of `my_list`, but does not return anything. + +. . . + +What's the difference between a method and a function? + +## Dataframe as an Object + +*What does it contain?* + +- **Value**: the spreadsheet of data. + +. . . + +- **Attributes**: + + - Columns of the data + + - `.columns` + + - `.shape` + + - `.iloc[ , ]` , `.loc[ , ]` for subsetting + + - [a technical syntax guide](https://colab.research.google.com/drive/1NmFx2tK0coi2O44eldz8RHDH6POOmAFE?usp=sharing) + +. . . + +*What can it do (methods)?* + +- `.head()` + +- `.tail()` + +## Break! + +A quick survey to get us started: + +## Dictionary + +A **dictionary** is designed as a lookup table, organized in **key-value** pairs. You associate the key with a particular value, and use the key to find the value. + +. . . + +```{python} +sentiment = {'happy': 8, 'sad': 2, 'joy': 7.5, 'embarrassed': 3.6, 'restless': 4.1, 'apathetic': 3.8, 'calm': 7} +sentiment +``` + +. . . + +You use a key to find its corresponding value: + +```{python} +sentiment['joy'] +``` + +. . . + +You cannot use a numerical index to find values, like you did for Lists! + +```{python} +#sentiment[0] +``` + +## Rules of Dictionaries + +- Only one value per key. No duplicate keys allowed. + +. . . + +- **Keys** must be of string, integer, float, boolean, or tuple. + +. . . + +- **Values** can be of any type, including data structures such as lists and dictionaries. + +. . . + +```{python} +duplicated_keys = {'Student' : 97, 'Student': 88, 'Student' : 91} +duplicated_keys +``` + +. . . + +```{python} +child = {"name" : "Emil", "year" : 2004, "likes": ["jumping", "skating", "laughing"]} +``` + +. . . + +```{python} +child["likes"][1] +``` + +. . . + +Data stored in nested dictionaries are often represented as JSON files. Here's a [guide on using JSON files in Python](https://realpython.com/python-json/). + +## Using key to find values + +```{python} +sentiment['joy'] +``` + +. . . + +```{python} +sentiment['joy'] = sentiment['joy'] + 1 +``` + +. . . + +If a key doesn't exist, you will get an error: + +```{python} +#sentiment["dog"] +``` + +. . . + +If you don't want to run the risk of getting an error, you can specify a default value using the `.get()` method. + +```{python} +sentiment.get("dog", "not found") +``` + +. . . + +```{python} +print(sentiment.get("dog")) +``` + +## Adding new key-value pairs + +You can add more key-value pairs by defining it directly. If the key already exists, the mapping for that key will simply be updated. + +```{python} +sentiment['dog'] = 5 +``` + +## Application: Creating a Dataframe + +You can create a Dataframe using a Dictionary. The key represent column names, and the value is a List containing the column's values: + +```{python} +import pandas as pd + +simple_df = pd.DataFrame(data={'id': ["AAA", "BBB", "CCC", "DDD", "EEE"], + 'case_control': ["case", "case", "control", "control", "control"], + 'measurement1': [2.5, 3.5, 9, .1, 2.2], + 'measurement2': [0, 0, .5, .24, .003], + 'measurement3': [80, 2, 1, 1, 2]}) + +simple_df +``` + +## Application: Data Recoding + +You want to take "case_control" column of `simple_df` and change "case" to "experiment" and "control" to "baseline". + +This correspondence relationship can be stored in a dictionary via `.replace()` method for Series: + +```{python} +simple_df.case_control.replace({"case": "experiment", "control": "baseline"}) +``` + +. . . + +You can do something similar to recode the column names of a Dataframe via the [.rename()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rename.html) method. diff --git a/slides/lesson1_slides_files/libs/clipboard/clipboard.min.js b/slides/lesson1_slides_files/libs/clipboard/clipboard.min.js new file mode 100644 index 0000000..1103f81 --- /dev/null +++ b/slides/lesson1_slides_files/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.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light-border]>.tippy-arrow:after,.tippy-box[data-theme~=light-border]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=light-border]>.tippy-arrow:after{border-color:transparent;border-style:solid}.tippy-box[data-theme~=light-border][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light-border][data-placement^=top]>.tippy-arrow:after{border-top-color:rgba(0,8,16,.2);border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=light-border][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=light-border][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=light-border][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=light-border][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:rgba(0,8,16,.2);border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=light-border][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:16px}.tippy-box[data-theme~=light-border][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=light-border][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light-border][data-placement^=left]>.tippy-arrow:after{border-left-color:rgba(0,8,16,.2);border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=light-border][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=light-border][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=light-border][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=light-border][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:rgba(0,8,16,.2)}.tippy-box[data-theme~=light-border][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=light-border][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=light-border]>.tippy-svg-arrow{fill:#fff}.tippy-box[data-theme~=light-border]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px} \ No newline at end of file diff --git a/slides/lesson1_slides_files/libs/quarto-html/popper.min.js b/slides/lesson1_slides_files/libs/quarto-html/popper.min.js new file mode 100644 index 0000000..e3726d7 --- /dev/null +++ b/slides/lesson1_slides_files/libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.7 - 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(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=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),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(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 b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(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 D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(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 N(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 I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(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+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);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}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){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,[P,L].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}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(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?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,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]=J(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 le={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,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(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,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=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 E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={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,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=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,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(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=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={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=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,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)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(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 ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={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=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(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})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/slides/lesson1_slides_files/libs/quarto-html/quarto-html.min.css b/slides/lesson1_slides_files/libs/quarto-html/quarto-html.min.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/slides/lesson1_slides_files/libs/quarto-html/quarto-html.min.css @@ -0,0 +1 @@ + diff --git a/slides/lesson1_slides_files/libs/quarto-html/quarto-syntax-highlighting.css b/slides/lesson1_slides_files/libs/quarto-html/quarto-syntax-highlighting.css new file mode 100644 index 0000000..b30ce57 --- /dev/null +++ b/slides/lesson1_slides_files/libs/quarto-html/quarto-syntax-highlighting.css @@ -0,0 +1,205 @@ +/* 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-weight: bold; + 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-weight: bold; + font-style: inherit; +} + +.prevent-inlining { + content: " !el.hasAttribute("disabled") && !el.getAttribute("aria-hidden") + ); + }; + + /** + * Remove roles and attributes from a tab and its content + * @param {Node} tab The tab + * @param {Node} content The tab content + * @param {Object} settings User settings and options + */ + var destroyTab = function (tab, content, settings) { + // Remove the generated ID + if (tab.id.slice(0, settings.idPrefix.length) === settings.idPrefix) { + tab.id = ""; + } + + // remove event listener + tab.removeEventListener("focus", focusHandler, true); + + // Remove roles + tab.removeAttribute("role"); + tab.removeAttribute("aria-controls"); + tab.removeAttribute("aria-selected"); + tab.removeAttribute("tabindex"); + tab.closest("li").removeAttribute("role"); + content.removeAttribute("role"); + content.removeAttribute("aria-labelledby"); + content.removeAttribute("hidden"); + }; + + /** + * Add the required roles and attributes to a tab and its content + * @param {Node} tab The tab + * @param {Node} content The tab content + * @param {Object} settings User settings and options + */ + var setupTab = function (tab, content, settings) { + // Give tab an ID if it doesn't already have one + if (!tab.id) { + tab.id = settings.idPrefix + content.id; + } + + // Add roles + tab.setAttribute("role", "tab"); + tab.setAttribute("aria-controls", content.id); + tab.closest("li").setAttribute("role", "presentation"); + content.setAttribute("role", "tabpanel"); + content.setAttribute("aria-labelledby", tab.id); + + // Add selected state + if (tab.matches(settings.default)) { + tab.setAttribute("aria-selected", "true"); + } else { + tab.setAttribute("aria-selected", "false"); + content.setAttribute("hidden", "hidden"); + } + + // add focus event listender + tab.addEventListener("focus", focusHandler); + }; + + /** + * Hide a tab and its content + * @param {Node} newTab The new tab that's replacing it + */ + var hide = function (newTab) { + // Variables + var tabGroup = newTab.closest('[role="tablist"]'); + if (!tabGroup) return {}; + var tab = tabGroup.querySelector('[role="tab"][aria-selected="true"]'); + if (!tab) return {}; + var content = document.querySelector(tab.hash); + + // Hide the tab + tab.setAttribute("aria-selected", "false"); + + // Hide the content + if (!content) return { previousTab: tab }; + content.setAttribute("hidden", "hidden"); + + // Return the hidden tab and content + return { + previousTab: tab, + previousContent: content, + }; + }; + + /** + * Show a tab and its content + * @param {Node} tab The tab + * @param {Node} content The tab content + */ + var show = function (tab, content) { + tab.setAttribute("aria-selected", "true"); + content.removeAttribute("hidden"); + tab.focus(); + }; + + /** + * Toggle a new tab + * @param {Node} tab The tab to show + */ + var toggle = function (tab) { + // Make sure there's a tab to toggle and it's not already active + if (!tab || tab.getAttribute("aria-selected") == "true") return; + + // Variables + var content = document.querySelector(tab.hash); + if (!content) return; + + // Hide active tab and content + var details = hide(tab); + + // Show new tab and content + show(tab, content); + + // Add event details + details.tab = tab; + details.content = content; + + // Emit a custom event + emitEvent(tab, details); + }; + + /** + * Get all of the tabs in a tablist + * @param {Node} tab A tab from the list + * @return {Object} The tabs and the index of the currently active one + */ + var getTabsMap = function (tab) { + var tabGroup = tab.closest('[role="tablist"]'); + var tabs = tabGroup ? tabGroup.querySelectorAll('[role="tab"]') : null; + if (!tabs) return; + return { + tabs: tabs, + index: Array.prototype.indexOf.call(tabs, tab), + }; + }; + + /** + * Switch the active tab based on keyboard activity + * @param {Node} tab The currently active tab + * @param {Key} key The key that was pressed + */ + var switchTabs = function (tab, key) { + // Get a map of tabs + var map = getTabsMap(tab); + if (!map) return; + var length = map.tabs.length - 1; + var index; + + // Go to previous tab + if (["ArrowUp", "ArrowLeft", "Up", "Left"].indexOf(key) > -1) { + index = map.index < 1 ? length : map.index - 1; + } + + // Go to next tab + else if (["ArrowDown", "ArrowRight", "Down", "Right"].indexOf(key) > -1) { + index = map.index === length ? 0 : map.index + 1; + } + + // Go to home + else if (key === "Home") { + index = 0; + } + + // Go to end + else if (key === "End") { + index = length; + } + + // Toggle the tab + toggle(map.tabs[index]); + }; + + /** + * Create the Constructor object + */ + var Constructor = function (selector, options) { + // + // Variables + // + + var publicAPIs = {}; + var settings, tabWrapper; + + // + // Methods + // + + publicAPIs.destroy = function () { + // Get all tabs + var tabs = tabWrapper.querySelectorAll("a"); + + // Add roles to tabs + Array.prototype.forEach.call(tabs, function (tab) { + // Get the tab content + var content = document.querySelector(tab.hash); + if (!content) return; + + // Setup the tab + destroyTab(tab, content, settings); + }); + + // Remove role from wrapper + tabWrapper.removeAttribute("role"); + + // Remove event listeners + document.documentElement.removeEventListener( + "click", + clickHandler, + true + ); + tabWrapper.removeEventListener("keydown", keyHandler, true); + + // Reset variables + settings = null; + tabWrapper = null; + }; + + /** + * Setup the DOM with the proper attributes + */ + publicAPIs.setup = function () { + // Variables + tabWrapper = document.querySelector(selector); + if (!tabWrapper) return; + var tabs = tabWrapper.querySelectorAll("a"); + + // Add role to wrapper + tabWrapper.setAttribute("role", "tablist"); + + // Add roles to tabs. provide dynanmic tab indexes if we are within reveal + var contentTabindexes = + window.document.body.classList.contains("reveal-viewport"); + var nextTabindex = 1; + Array.prototype.forEach.call(tabs, function (tab) { + if (contentTabindexes) { + tab.setAttribute("tabindex", "" + nextTabindex++); + } else { + tab.setAttribute("tabindex", "0"); + } + + // Get the tab content + var content = document.querySelector(tab.hash); + if (!content) return; + + // set tab indexes for content + if (contentTabindexes) { + getKeyboardFocusableElements(content).forEach(function (el) { + el.setAttribute("tabindex", "" + nextTabindex++); + }); + } + + // Setup the tab + setupTab(tab, content, settings); + }); + }; + + /** + * Toggle a tab based on an ID + * @param {String|Node} id The tab to toggle + */ + publicAPIs.toggle = function (id) { + // Get the tab + var tab = id; + if (typeof id === "string") { + tab = document.querySelector( + selector + ' [role="tab"][href*="' + id + '"]' + ); + } + + // Toggle the tab + toggle(tab); + }; + + /** + * Handle click events + */ + var clickHandler = function (event) { + // Only run on toggles + var tab = event.target.closest(selector + ' [role="tab"]'); + if (!tab) return; + + // Prevent link behavior + event.preventDefault(); + + // Toggle the tab + toggle(tab); + }; + + /** + * Handle keydown events + */ + var keyHandler = function (event) { + // Only run if a tab is in focus + var tab = document.activeElement; + if (!tab.matches(selector + ' [role="tab"]')) return; + + // Only run for specific keys + if (["Home", "End"].indexOf(event.key) < 0) return; + + // Switch tabs + switchTabs(tab, event.key); + }; + + /** + * Initialize the instance + */ + var init = function () { + // Merge user options with defaults + settings = extend(defaults, options || {}); + + // Setup the DOM + publicAPIs.setup(); + + // Add event listeners + document.documentElement.addEventListener("click", clickHandler, true); + tabWrapper.addEventListener("keydown", keyHandler, true); + }; + + // + // Initialize and return the Public APIs + // + + init(); + return publicAPIs; + }; + + // + // Return the Constructor + // + + return Constructor; + } +); diff --git a/slides/lesson1_slides_files/libs/quarto-html/tippy.css b/slides/lesson1_slides_files/libs/quarto-html/tippy.css new file mode 100644 index 0000000..e6ae635 --- /dev/null +++ b/slides/lesson1_slides_files/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/slides/lesson1_slides_files/libs/quarto-html/tippy.umd.min.js b/slides/lesson1_slides_files/libs/quarto-html/tippy.umd.min.js new file mode 100644 index 0000000..ca292be --- /dev/null +++ b/slides/lesson1_slides_files/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/slides/lesson1_slides_files/libs/quarto-ojs/quarto-ojs-runtime.js b/slides/lesson1_slides_files/libs/quarto-ojs/quarto-ojs-runtime.js new file mode 100644 index 0000000..8e75107 --- /dev/null +++ b/slides/lesson1_slides_files/libs/quarto-ojs/quarto-ojs-runtime.js @@ -0,0 +1,20204 @@ +// quarto-ojs-runtime v0.0.15 Copyright 2023 undefined +var EOL = {}, + EOF = {}, + QUOTE = 34, + NEWLINE = 10, + RETURN = 13; + +function objectConverter(columns) { + return new Function("d", "return {" + columns.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "] || \"\""; + }).join(",") + "}"); +} + +function customConverter(columns, f) { + var object = objectConverter(columns); + return function(row, i) { + return f(object(row), i, columns); + }; +} + +// Compute unique columns in order of discovery. +function inferColumns(rows) { + var columnSet = Object.create(null), + columns = []; + + rows.forEach(function(row) { + for (var column in row) { + if (!(column in columnSet)) { + columns.push(columnSet[column] = column); + } + } + }); + + return columns; +} + +function pad$1(value, width) { + var s = value + "", length = s.length; + return length < width ? new Array(width - length + 1).join(0) + s : s; +} + +function formatYear$1(year) { + return year < 0 ? "-" + pad$1(-year, 6) + : year > 9999 ? "+" + pad$1(year, 6) + : pad$1(year, 4); +} + +function formatDate$2(date) { + var hours = date.getUTCHours(), + minutes = date.getUTCMinutes(), + seconds = date.getUTCSeconds(), + milliseconds = date.getUTCMilliseconds(); + return isNaN(date) ? "Invalid Date" + : formatYear$1(date.getUTCFullYear()) + "-" + pad$1(date.getUTCMonth() + 1, 2) + "-" + pad$1(date.getUTCDate(), 2) + + (milliseconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "." + pad$1(milliseconds, 3) + "Z" + : seconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "Z" + : minutes || hours ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + "Z" + : ""); +} + +function dsv$1(delimiter) { + var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), + DELIMITER = delimiter.charCodeAt(0); + + function parse(text, f) { + var convert, columns, rows = parseRows(text, function(row, i) { + if (convert) return convert(row, i - 1); + columns = row, convert = f ? customConverter(row, f) : objectConverter(row); + }); + rows.columns = columns || []; + return rows; + } + + function parseRows(text, f) { + var rows = [], // output rows + N = text.length, + I = 0, // current character index + n = 0, // current line number + t, // current token + eof = N <= 0, // current token followed by EOF? + eol = false; // current token followed by EOL? + + // Strip the trailing newline. + if (text.charCodeAt(N - 1) === NEWLINE) --N; + if (text.charCodeAt(N - 1) === RETURN) --N; + + function token() { + if (eof) return EOF; + if (eol) return eol = false, EOL; + + // Unescape quotes. + var i, j = I, c; + if (text.charCodeAt(j) === QUOTE) { + while (I++ < N && text.charCodeAt(I) !== QUOTE || text.charCodeAt(++I) === QUOTE); + if ((i = I) >= N) eof = true; + else if ((c = text.charCodeAt(I++)) === NEWLINE) eol = true; + else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } + return text.slice(j + 1, i - 1).replace(/""/g, "\""); + } + + // Find next delimiter or newline. + while (I < N) { + if ((c = text.charCodeAt(i = I++)) === NEWLINE) eol = true; + else if (c === RETURN) { eol = true; if (text.charCodeAt(I) === NEWLINE) ++I; } + else if (c !== DELIMITER) continue; + return text.slice(j, i); + } + + // Return last token before EOF. + return eof = true, text.slice(j, N); + } + + while ((t = token()) !== EOF) { + var row = []; + while (t !== EOL && t !== EOF) row.push(t), t = token(); + if (f && (row = f(row, n++)) == null) continue; + rows.push(row); + } + + return rows; + } + + function preformatBody(rows, columns) { + return rows.map(function(row) { + return columns.map(function(column) { + return formatValue(row[column]); + }).join(delimiter); + }); + } + + function format(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return [columns.map(formatValue).join(delimiter)].concat(preformatBody(rows, columns)).join("\n"); + } + + function formatBody(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return preformatBody(rows, columns).join("\n"); + } + + function formatRows(rows) { + return rows.map(formatRow).join("\n"); + } + + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + + function formatValue(value) { + return value == null ? "" + : value instanceof Date ? formatDate$2(value) + : reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\"" + : value; + } + + return { + parse: parse, + parseRows: parseRows, + format: format, + formatBody: formatBody, + formatRows: formatRows, + formatRow: formatRow, + formatValue: formatValue + }; +} + +var csv = dsv$1(","); + +var csvParse = csv.parse; +var csvParseRows = csv.parseRows; + +var tsv = dsv$1("\t"); + +var tsvParse = tsv.parse; +var tsvParseRows = tsv.parseRows; + +function autoType(object) { + for (var key in object) { + var value = object[key].trim(), number, m; + if (!value) value = null; + else if (value === "true") value = true; + else if (value === "false") value = false; + else if (value === "NaN") value = NaN; + else if (!isNaN(number = +value)) value = number; + else if (m = value.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)) { + if (fixtz && !!m[4] && !m[7]) value = value.replace(/-/g, "/").replace(/T/, " "); + value = new Date(value); + } + else continue; + object[key] = value; + } + return object; +} + +// https://github.com/d3/d3-dsv/issues/45 +const fixtz = new Date("2019-01-01T00:00").getHours() || new Date("2019-07-01T00:00").getHours(); + +function dependency(name, version, main) { + return { + resolve(path = main) { + return `${name}@${version}/${path}`; + } + }; +} + +const d3 = dependency("d3", "7.6.1", "dist/d3.min.js"); +const inputs = dependency("@observablehq/inputs", "0.10.4", "dist/inputs.min.js"); +const plot = dependency("@observablehq/plot", "0.6.0", "dist/plot.umd.min.js"); +const graphviz = dependency("@observablehq/graphviz", "0.2.1", "dist/graphviz.min.js"); +const highlight = dependency("@observablehq/highlight.js", "2.0.0", "highlight.min.js"); +const katex = dependency("@observablehq/katex", "0.11.1", "dist/katex.min.js"); +const lodash = dependency("lodash", "4.17.21", "lodash.min.js"); +const htl = dependency("htl", "0.3.1", "dist/htl.min.js"); +const jszip = dependency("jszip", "3.10.0", "dist/jszip.min.js"); +const marked = dependency("marked", "0.3.12", "marked.min.js"); +const sql = dependency("sql.js", "1.7.0", "dist/sql-wasm.js"); +const vega = dependency("vega", "5.22.1", "build/vega.min.js"); +const vegalite = dependency("vega-lite", "5.5.0", "build/vega-lite.min.js"); +const vegaliteApi = dependency("vega-lite-api", "5.0.0", "build/vega-lite-api.min.js"); +const arrow4 = dependency("apache-arrow", "4.0.1", "Arrow.es2015.min.js"); +const arrow9 = dependency("apache-arrow", "9.0.0", "+esm"); +const arquero = dependency("arquero", "4.8.8", "dist/arquero.min.js"); +const topojson = dependency("topojson-client", "3.1.0", "dist/topojson-client.min.js"); +const exceljs = dependency("exceljs", "4.3.0", "dist/exceljs.min.js"); +const mermaid$1 = dependency("mermaid", "9.1.6", "dist/mermaid.min.js"); +const leaflet$1 = dependency("leaflet", "1.8.0", "dist/leaflet.js"); +const duckdb = dependency("@duckdb/duckdb-wasm", "1.17.0", "+esm"); + +const metas = new Map; +const queue$1 = []; +const map$2 = queue$1.map; +const some = queue$1.some; +const hasOwnProperty$2 = queue$1.hasOwnProperty; +const identifierRe = /^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(?:\/(.*))?$/; +const versionRe = /^\d+\.\d+\.\d+(-[\w-.+]+)?$/; +const extensionRe = /(?:\.[^/]*|\/)$/; + +class RequireError extends Error { + constructor(message) { + super(message); + } +} + +RequireError.prototype.name = RequireError.name; + +function parseIdentifier(identifier) { + const match = identifierRe.exec(identifier); + return match && { + name: match[1], + version: match[2], + path: match[3] + }; +} + +function resolveFrom(origin = "https://cdn.jsdelivr.net/npm/", mains = ["unpkg", "jsdelivr", "browser", "main"]) { + if (!/\/$/.test(origin)) throw new Error("origin lacks trailing slash"); + + function main(meta) { + for (const key of mains) { + let value = meta[key]; + if (typeof value === "string") { + if (value.startsWith("./")) value = value.slice(2); + return extensionRe.test(value) ? value : `${value}.js`; + } + } + } + + function resolveMeta(target) { + const url = `${origin}${target.name}${target.version ? `@${target.version}` : ""}/package.json`; + let meta = metas.get(url); + if (!meta) metas.set(url, meta = fetch(url).then(response => { + if (!response.ok) throw new RequireError("unable to load package.json"); + if (response.redirected && !metas.has(response.url)) metas.set(response.url, meta); + return response.json(); + })); + return meta; + } + + return async function resolve(name, base) { + if (name.startsWith(origin)) name = name.substring(origin.length); + if (/^(\w+:)|\/\//i.test(name)) return name; + if (/^[.]{0,2}\//i.test(name)) return new URL(name, base == null ? location : base).href; + if (!name.length || /^[\s._]/.test(name) || /\s$/.test(name)) throw new RequireError("illegal name"); + const target = parseIdentifier(name); + if (!target) return `${origin}${name}`; + if (!target.version && base != null && base.startsWith(origin)) { + const meta = await resolveMeta(parseIdentifier(base.substring(origin.length))); + target.version = meta.dependencies && meta.dependencies[target.name] || meta.peerDependencies && meta.peerDependencies[target.name]; + } + if (target.path && !extensionRe.test(target.path)) target.path += ".js"; + if (target.path && target.version && versionRe.test(target.version)) return `${origin}${target.name}@${target.version}/${target.path}`; + const meta = await resolveMeta(target); + return `${origin}${meta.name}@${meta.version}/${target.path || main(meta) || "index.js"}`; + }; +} + +var require = requireFrom(resolveFrom()); +let requestsInFlight = 0; +let prevDefine = undefined; + +function requireFrom(resolver) { + const cache = new Map; + const requireBase = requireRelative(null); + + function requireAbsolute(url) { + if (typeof url !== "string") return url; + let module = cache.get(url); + if (!module) cache.set(url, module = new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.onload = () => { + try { resolve(queue$1.pop()(requireRelative(url))); } + catch (error) { reject(new RequireError("invalid module")); } + script.remove(); + requestsInFlight--; + if (requestsInFlight === 0) { + window.define = prevDefine; + } + }; + script.onerror = () => { + reject(new RequireError("unable to load module")); + script.remove(); + requestsInFlight--; + if (requestsInFlight === 0) { + window.define = prevDefine; + } + }; + script.async = true; + script.src = url; + if (requestsInFlight === 0) { + prevDefine = window.define; + window.define = define; + } + requestsInFlight++; + + document.head.appendChild(script); + })); + return module; + } + + function requireRelative(base) { + return name => Promise.resolve(resolver(name, base)).then(requireAbsolute); + } + + function requireAlias(aliases) { + return requireFrom((name, base) => { + if (name in aliases) { + name = aliases[name], base = null; + if (typeof name !== "string") return name; + } + return resolver(name, base); + }); + } + + function require(name) { + return arguments.length > 1 + ? Promise.all(map$2.call(arguments, requireBase)).then(merge) + : requireBase(name); + } + + require.alias = requireAlias; + require.resolve = resolver; + + return require; +} + +function merge(modules) { + const o = {}; + for (const m of modules) { + for (const k in m) { + if (hasOwnProperty$2.call(m, k)) { + if (m[k] == null) Object.defineProperty(o, k, {get: getter(m, k)}); + else o[k] = m[k]; + } + } + } + return o; +} + +function getter(object, name) { + return () => object[name]; +} + +function isbuiltin(name) { + name = name + ""; + return name === "exports" || name === "module"; +} + +function define(name, dependencies, factory) { + const n = arguments.length; + if (n < 2) factory = name, dependencies = []; + else if (n < 3) factory = dependencies, dependencies = typeof name === "string" ? [] : name; + queue$1.push(some.call(dependencies, isbuiltin) ? require => { + const exports = {}; + const module = {exports}; + return Promise.all(map$2.call(dependencies, name => { + name = name + ""; + return name === "exports" ? exports : name === "module" ? module : require(name); + })).then(dependencies => { + factory.apply(null, dependencies); + return module.exports; + }); + } : require => { + return Promise.all(map$2.call(dependencies, require)).then(dependencies => { + return typeof factory === "function" ? factory.apply(null, dependencies) : factory; + }); + }); +} + +define.amd = {}; + +// TODO Allow this to be overridden using the Library’s resolver. +const cdn = "https://cdn.observableusercontent.com/npm/"; + +let requireDefault = require; + +function setDefaultRequire(require) { + requireDefault = require; +} + +function requirer(resolver) { + return resolver == null ? requireDefault : requireFrom(resolver); +} + +function fromEntries(obj) { + const result = {}; + for (const [key, value] of obj) { + result[key] = value; + } + return result; +} + +async function SQLite(require) { + const [init, dist] = await Promise.all([require(sql.resolve()), require.resolve(sql.resolve("dist/"))]); + return init({locateFile: file => `${dist}${file}`}); +} + +class SQLiteDatabaseClient { + constructor(db) { + Object.defineProperties(this, { + _db: {value: db} + }); + } + static async open(source) { + const [SQL, buffer] = await Promise.all([SQLite(requireDefault), Promise.resolve(source).then(load$1)]); + return new SQLiteDatabaseClient(new SQL.Database(buffer)); + } + async query(query, params) { + return await exec(this._db, query, params); + } + async queryRow(query, params) { + return (await this.query(query, params))[0] || null; + } + async explain(query, params) { + const rows = await this.query(`EXPLAIN QUERY PLAN ${query}`, params); + return element$1("pre", {className: "observablehq--inspect"}, [ + text$2(rows.map(row => row.detail).join("\n")) + ]); + } + async describeTables({schema} = {}) { + return this.query(`SELECT NULLIF(schema, 'main') AS schema, name FROM pragma_table_list() WHERE type = 'table'${schema == null ? "" : ` AND schema = ?`} AND name NOT LIKE 'sqlite_%'`, schema == null ? [] : [schema]); + } + async describeColumns({schema, table} = {}) { + if (table == null) throw new Error(`missing table`); + const rows = await this.query(`SELECT name, type, "notnull" FROM pragma_table_info(?${schema == null ? "" : `, ?`}) ORDER BY cid`, schema == null ? [table] : [table, schema]); + if (!rows.length) throw new Error(`table not found: ${table}`); + return rows.map(({name, type, notnull}) => ({name, type: sqliteType(type), databaseType: type, nullable: !notnull})); + } + async describe(object) { + const rows = await (object === undefined + ? this.query(`SELECT name FROM sqlite_master WHERE type = 'table'`) + : this.query(`SELECT * FROM pragma_table_info(?)`, [object])); + if (!rows.length) throw new Error("Not found"); + const {columns} = rows; + return element$1("table", {value: rows}, [ + element$1("thead", [element$1("tr", columns.map(c => element$1("th", [text$2(c)])))]), + element$1("tbody", rows.map(r => element$1("tr", columns.map(c => element$1("td", [text$2(r[c])]))))) + ]); + } + async sql() { + return this.query(...this.queryTag.apply(this, arguments)); + } + queryTag(strings, ...params) { + return [strings.join("?"), params]; + } +} + +Object.defineProperty(SQLiteDatabaseClient.prototype, "dialect", { + value: "sqlite" +}); + +// https://www.sqlite.org/datatype3.html +function sqliteType(type) { + switch (type) { + case "NULL": + return "null"; + case "INT": + case "INTEGER": + case "TINYINT": + case "SMALLINT": + case "MEDIUMINT": + case "BIGINT": + case "UNSIGNED BIG INT": + case "INT2": + case "INT8": + return "integer"; + case "TEXT": + case "CLOB": + return "string"; + case "REAL": + case "DOUBLE": + case "DOUBLE PRECISION": + case "FLOAT": + case "NUMERIC": + return "number"; + case "BLOB": + return "buffer"; + case "DATE": + case "DATETIME": + return "string"; // TODO convert strings to Date instances in sql.js + default: + return /^(?:(?:(?:VARYING|NATIVE) )?CHARACTER|(?:N|VAR|NVAR)CHAR)\(/.test(type) ? "string" + : /^(?:DECIMAL|NUMERIC)\(/.test(type) ? "number" + : "other"; + } +} + +function load$1(source) { + return typeof source === "string" ? fetch(source).then(load$1) + : source instanceof Response || source instanceof Blob ? source.arrayBuffer().then(load$1) + : source instanceof ArrayBuffer ? new Uint8Array(source) + : source; +} + +async function exec(db, query, params) { + const [result] = await db.exec(query, params); + if (!result) return []; + const {columns, values} = result; + const rows = values.map(row => fromEntries(row.map((value, i) => [columns[i], value]))); + rows.columns = columns; + return rows; +} + +function element$1(name, props, children) { + if (arguments.length === 2) children = props, props = undefined; + const element = document.createElement(name); + if (props !== undefined) for (const p in props) element[p] = props[p]; + if (children !== undefined) for (const c of children) element.appendChild(c); + return element; +} + +function text$2(value) { + return document.createTextNode(value); +} + +class Workbook { + constructor(workbook) { + Object.defineProperties(this, { + _: {value: workbook}, + sheetNames: { + value: workbook.worksheets.map((s) => s.name), + enumerable: true + } + }); + } + sheet(name, options) { + const sname = + typeof name === "number" + ? this.sheetNames[name] + : this.sheetNames.includes((name += "")) + ? name + : null; + if (sname == null) throw new Error(`Sheet not found: ${name}`); + const sheet = this._.getWorksheet(sname); + return extract(sheet, options); + } +} + +function extract(sheet, {range, headers} = {}) { + let [[c0, r0], [c1, r1]] = parseRange(range, sheet); + const headerRow = headers ? sheet._rows[r0++] : null; + let names = new Set(["#"]); + for (let n = c0; n <= c1; n++) { + const value = headerRow ? valueOf(headerRow.findCell(n + 1)) : null; + let name = (value && value + "") || toColumn(n); + while (names.has(name)) name += "_"; + names.add(name); + } + names = new Array(c0).concat(Array.from(names)); + + const output = new Array(r1 - r0 + 1); + for (let r = r0; r <= r1; r++) { + const row = (output[r - r0] = Object.create(null, {"#": {value: r + 1}})); + const _row = sheet.getRow(r + 1); + if (_row.hasValues) + for (let c = c0; c <= c1; c++) { + const value = valueOf(_row.findCell(c + 1)); + if (value != null) row[names[c + 1]] = value; + } + } + + output.columns = names.filter(() => true); // Filter sparse columns + return output; +} + +function valueOf(cell) { + if (!cell) return; + const {value} = cell; + if (value && typeof value === "object" && !(value instanceof Date)) { + if (value.formula || value.sharedFormula) { + return value.result && value.result.error ? NaN : value.result; + } + if (value.richText) { + return richText(value); + } + if (value.text) { + let {text} = value; + if (text.richText) text = richText(text); + return value.hyperlink && value.hyperlink !== text + ? `${value.hyperlink} ${text}` + : text; + } + return value; + } + return value; +} + +function richText(value) { + return value.richText.map((d) => d.text).join(""); +} + +function parseRange(specifier = ":", {columnCount, rowCount}) { + specifier += ""; + if (!specifier.match(/^[A-Z]*\d*:[A-Z]*\d*$/)) + throw new Error("Malformed range specifier"); + const [[c0 = 0, r0 = 0], [c1 = columnCount - 1, r1 = rowCount - 1]] = + specifier.split(":").map(fromCellReference); + return [ + [c0, r0], + [c1, r1] + ]; +} + +// Returns the default column name for a zero-based column index. +// For example: 0 -> "A", 1 -> "B", 25 -> "Z", 26 -> "AA", 27 -> "AB". +function toColumn(c) { + let sc = ""; + c++; + do { + sc = String.fromCharCode(64 + (c % 26 || 26)) + sc; + } while ((c = Math.floor((c - 1) / 26))); + return sc; +} + +// Returns the zero-based indexes from a cell reference. +// For example: "A1" -> [0, 0], "B2" -> [1, 1], "AA10" -> [26, 9]. +function fromCellReference(s) { + const [, sc, sr] = s.match(/^([A-Z]*)(\d*)$/); + let c = 0; + if (sc) + for (let i = 0; i < sc.length; i++) + c += Math.pow(26, sc.length - i - 1) * (sc.charCodeAt(i) - 64); + return [c ? c - 1 : undefined, sr ? +sr - 1 : undefined]; +} + +async function remote_fetch(file) { + const response = await fetch(await file.url()); + if (!response.ok) throw new Error(`Unable to load file: ${file.name}`); + return response; +} + +async function dsv(file, delimiter, {array = false, typed = false} = {}) { + const text = await file.text(); + return (delimiter === "\t" + ? (array ? tsvParseRows : tsvParse) + : (array ? csvParseRows : csvParse))(text, typed && autoType); +} + +class AbstractFile { + constructor(name, mimeType) { + Object.defineProperty(this, "name", {value: name, enumerable: true}); + if (mimeType !== undefined) Object.defineProperty(this, "mimeType", {value: mimeType + "", enumerable: true}); + } + async blob() { + return (await remote_fetch(this)).blob(); + } + async arrayBuffer() { + return (await remote_fetch(this)).arrayBuffer(); + } + async text() { + return (await remote_fetch(this)).text(); + } + async json() { + return (await remote_fetch(this)).json(); + } + async stream() { + return (await remote_fetch(this)).body; + } + async csv(options) { + return dsv(this, ",", options); + } + async tsv(options) { + return dsv(this, "\t", options); + } + async image(props) { + const url = await this.url(); + return new Promise((resolve, reject) => { + const i = new Image(); + if (new URL(url, document.baseURI).origin !== new URL(location).origin) { + i.crossOrigin = "anonymous"; + } + Object.assign(i, props); + i.onload = () => resolve(i); + i.onerror = () => reject(new Error(`Unable to load file: ${this.name}`)); + i.src = url; + }); + } + async arrow({version = 4} = {}) { + switch (version) { + case 4: { + const [Arrow, response] = await Promise.all([requireDefault(arrow4.resolve()), remote_fetch(this)]); + return Arrow.Table.from(response); + } + case 9: { + const [Arrow, response] = await Promise.all([import(`${cdn}${arrow9.resolve()}`), remote_fetch(this)]); + return Arrow.tableFromIPC(response); + } + default: throw new Error(`unsupported arrow version: ${version}`); + } + } + async sqlite() { + return SQLiteDatabaseClient.open(remote_fetch(this)); + } + async zip() { + const [JSZip, buffer] = await Promise.all([requireDefault(jszip.resolve()), this.arrayBuffer()]); + return new ZipArchive(await JSZip.loadAsync(buffer)); + } + async xml(mimeType = "application/xml") { + return (new DOMParser).parseFromString(await this.text(), mimeType); + } + async html() { + return this.xml("text/html"); + } + async xlsx() { + const [ExcelJS, buffer] = await Promise.all([requireDefault(exceljs.resolve()), this.arrayBuffer()]); + return new Workbook(await new ExcelJS.Workbook().xlsx.load(buffer)); + } +} + +class FileAttachment extends AbstractFile { + constructor(url, name, mimeType) { + super(name, mimeType); + Object.defineProperty(this, "_url", {value: url}); + } + async url() { + return (await this._url) + ""; + } +} + +function NoFileAttachments(name) { + throw new Error(`File not found: ${name}`); +} + +function FileAttachments(resolve) { + return Object.assign( + name => { + const result = resolve(name += ""); + if (result == null) throw new Error(`File not found: ${name}`); + if (typeof result === "object" && "url" in result) { + const {url, mimeType} = result; + return new FileAttachment(url, name, mimeType); + } + return new FileAttachment(result, name); + }, + {prototype: FileAttachment.prototype} // instanceof + ); +} + +class ZipArchive { + constructor(archive) { + Object.defineProperty(this, "_", {value: archive}); + this.filenames = Object.keys(archive.files).filter(name => !archive.files[name].dir); + } + file(path) { + const object = this._.file(path += ""); + if (!object || object.dir) throw new Error(`file not found: ${path}`); + return new ZipArchiveEntry(object); + } +} + +class ZipArchiveEntry extends AbstractFile { + constructor(object) { + super(object.name); + Object.defineProperty(this, "_", {value: object}); + Object.defineProperty(this, "_url", {writable: true}); + } + async url() { + return this._url || (this._url = this.blob().then(URL.createObjectURL)); + } + async blob() { + return this._.async("blob"); + } + async arrayBuffer() { + return this._.async("arraybuffer"); + } + async text() { + return this._.async("text"); + } + async json() { + return JSON.parse(await this.text()); + } +} + +function canvas(width, height) { + var canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + return canvas; +} + +function context2d(width, height, dpi) { + if (dpi == null) dpi = devicePixelRatio; + var canvas = document.createElement("canvas"); + canvas.width = width * dpi; + canvas.height = height * dpi; + canvas.style.width = width + "px"; + var context = canvas.getContext("2d"); + context.scale(dpi, dpi); + return context; +} + +function download(value, name = "untitled", label = "Save") { + const a = document.createElement("a"); + const b = a.appendChild(document.createElement("button")); + b.textContent = label; + a.download = name; + + async function reset() { + await new Promise(requestAnimationFrame); + URL.revokeObjectURL(a.href); + a.removeAttribute("href"); + b.textContent = label; + b.disabled = false; + } + + a.onclick = async event => { + b.disabled = true; + if (a.href) return reset(); // Already saved. + b.textContent = "Saving…"; + try { + const object = await (typeof value === "function" ? value() : value); + b.textContent = "Download"; + a.href = URL.createObjectURL(object); // eslint-disable-line require-atomic-updates + } catch (ignore) { + b.textContent = label; + } + if (event.eventPhase) return reset(); // Already downloaded. + b.disabled = false; + }; + + return a; +} + +var namespaces = { + math: "http://www.w3.org/1998/Math/MathML", + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" +}; + +function element(name, attributes) { + var prefix = name += "", i = prefix.indexOf(":"), value; + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); + var element = namespaces.hasOwnProperty(prefix) // eslint-disable-line no-prototype-builtins + ? document.createElementNS(namespaces[prefix], name) + : document.createElement(name); + if (attributes) for (var key in attributes) { + prefix = key, i = prefix.indexOf(":"), value = attributes[key]; + if (i >= 0 && (prefix = key.slice(0, i)) !== "xmlns") key = key.slice(i + 1); + if (namespaces.hasOwnProperty(prefix)) element.setAttributeNS(namespaces[prefix], key, value); // eslint-disable-line no-prototype-builtins + else element.setAttribute(key, value); + } + return element; +} + +function input$1(type) { + var input = document.createElement("input"); + if (type != null) input.type = type; + return input; +} + +function range$1(min, max, step) { + if (arguments.length === 1) max = min, min = null; + var input = document.createElement("input"); + input.min = min = min == null ? 0 : +min; + input.max = max = max == null ? 1 : +max; + input.step = step == null ? "any" : step = +step; + input.type = "range"; + return input; +} + +function select(values) { + var select = document.createElement("select"); + Array.prototype.forEach.call(values, function(value) { + var option = document.createElement("option"); + option.value = option.textContent = value; + select.appendChild(option); + }); + return select; +} + +function svg$1(width, height) { + var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("viewBox", [0, 0, width, height]); + svg.setAttribute("width", width); + svg.setAttribute("height", height); + return svg; +} + +function text$1(value) { + return document.createTextNode(value); +} + +var count$1 = 0; + +function uid(name) { + return new Id("O-" + (name == null ? "" : name + "-") + ++count$1); +} + +function Id(id) { + this.id = id; + this.href = new URL(`#${id}`, location) + ""; +} + +Id.prototype.toString = function() { + return "url(" + this.href + ")"; +}; + +var DOM = /*#__PURE__*/Object.freeze({ +__proto__: null, +canvas: canvas, +context2d: context2d, +download: download, +element: element, +input: input$1, +range: range$1, +select: select, +svg: svg$1, +text: text$1, +uid: uid +}); + +function buffer(file) { + return new Promise(function(resolve, reject) { + var reader = new FileReader; + reader.onload = function() { resolve(reader.result); }; + reader.onerror = reject; + reader.readAsArrayBuffer(file); + }); +} + +function text(file) { + return new Promise(function(resolve, reject) { + var reader = new FileReader; + reader.onload = function() { resolve(reader.result); }; + reader.onerror = reject; + reader.readAsText(file); + }); +} + +function url(file) { + return new Promise(function(resolve, reject) { + var reader = new FileReader; + reader.onload = function() { resolve(reader.result); }; + reader.onerror = reject; + reader.readAsDataURL(file); + }); +} + +var Files = /*#__PURE__*/Object.freeze({ +__proto__: null, +buffer: buffer, +text: text, +url: url +}); + +function that() { + return this; +} + +function disposable(value, dispose) { + let done = false; + if (typeof dispose !== "function") { + throw new Error("dispose is not a function"); + } + return { + [Symbol.iterator]: that, + next: () => done ? {done: true} : (done = true, {done: false, value}), + return: () => (done = true, dispose(value), {done: true}), + throw: () => ({done: done = true}) + }; +} + +function* filter(iterator, test) { + var result, index = -1; + while (!(result = iterator.next()).done) { + if (test(result.value, ++index)) { + yield result.value; + } + } +} + +function observe(initialize) { + let stale = false; + let value; + let resolve; + const dispose = initialize(change); + + if (dispose != null && typeof dispose !== "function") { + throw new Error(typeof dispose.then === "function" + ? "async initializers are not supported" + : "initializer returned something, but not a dispose function"); + } + + function change(x) { + if (resolve) resolve(x), resolve = null; + else stale = true; + return value = x; + } + + function next() { + return {done: false, value: stale + ? (stale = false, Promise.resolve(value)) + : new Promise(_ => (resolve = _))}; + } + + return { + [Symbol.iterator]: that, + throw: () => ({done: true}), + return: () => (dispose != null && dispose(), {done: true}), + next + }; +} + +function input(input) { + return observe(function(change) { + var event = eventof(input), value = valueof$1(input); + function inputted() { change(valueof$1(input)); } + input.addEventListener(event, inputted); + if (value !== undefined) change(value); + return function() { input.removeEventListener(event, inputted); }; + }); +} + +function valueof$1(input) { + switch (input.type) { + case "range": + case "number": return input.valueAsNumber; + case "date": return input.valueAsDate; + case "checkbox": return input.checked; + case "file": return input.multiple ? input.files : input.files[0]; + case "select-multiple": return Array.from(input.selectedOptions, o => o.value); + default: return input.value; + } +} + +function eventof(input) { + switch (input.type) { + case "button": + case "submit": + case "checkbox": return "click"; + case "file": return "change"; + default: return "input"; + } +} + +function* map$1(iterator, transform) { + var result, index = -1; + while (!(result = iterator.next()).done) { + yield transform(result.value, ++index); + } +} + +function queue(initialize) { + let resolve; + const queue = []; + const dispose = initialize(push); + + if (dispose != null && typeof dispose !== "function") { + throw new Error(typeof dispose.then === "function" + ? "async initializers are not supported" + : "initializer returned something, but not a dispose function"); + } + + function push(x) { + queue.push(x); + if (resolve) resolve(queue.shift()), resolve = null; + return x; + } + + function next() { + return {done: false, value: queue.length + ? Promise.resolve(queue.shift()) + : new Promise(_ => (resolve = _))}; + } + + return { + [Symbol.iterator]: that, + throw: () => ({done: true}), + return: () => (dispose != null && dispose(), {done: true}), + next + }; +} + +function* range(start, stop, step) { + start = +start; + stop = +stop; + step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; + var i = -1, n = Math.max(0, Math.ceil((stop - start) / step)) | 0; + while (++i < n) { + yield start + i * step; + } +} + +function valueAt(iterator, i) { + if (!isFinite(i = +i) || i < 0 || i !== i | 0) return; + var result, index = -1; + while (!(result = iterator.next()).done) { + if (++index === i) { + return result.value; + } + } +} + +function worker(source) { + const url = URL.createObjectURL(new Blob([source], {type: "text/javascript"})); + const worker = new Worker(url); + return disposable(worker, () => { + worker.terminate(); + URL.revokeObjectURL(url); + }); +} + +var Generators$1 = /*#__PURE__*/Object.freeze({ +__proto__: null, +disposable: disposable, +filter: filter, +input: input, +map: map$1, +observe: observe, +queue: queue, +range: range, +valueAt: valueAt, +worker: worker +}); + +// Returns true if the vaue is an Apache Arrow table. This uses a “duck” test +// (instead of strict instanceof) because we want it to work with a range of +// Apache Arrow versions at least 7.0.0 or above. +// https://arrow.apache.org/docs/7.0/js/classes/Arrow_dom.Table.html +function isArrowTable(value) { + return ( + value && + typeof value.getChild === "function" && + typeof value.toArray === "function" && + value.schema && + Array.isArray(value.schema.fields) + ); +} + +function getArrowTableSchema(table) { + return table.schema.fields.map(getArrowFieldSchema); +} + +function getArrowFieldSchema(field) { + return { + name: field.name, + type: getArrowType(field.type), + nullable: field.nullable, + databaseType: String(field.type) + }; +} + +// https://github.com/apache/arrow/blob/89f9a0948961f6e94f1ef5e4f310b707d22a3c11/js/src/enum.ts#L140-L141 +function getArrowType(type) { + switch (type.typeId) { + case 2: // Int + return "integer"; + case 3: // Float + case 7: // Decimal + return "number"; + case 4: // Binary + case 15: // FixedSizeBinary + return "buffer"; + case 5: // Utf8 + return "string"; + case 6: // Bool + return "boolean"; + case 8: // Date + case 9: // Time + case 10: // Timestamp + return "date"; + case 12: // List + case 16: // FixedSizeList + return "array"; + case 13: // Struct + case 14: // Union + return "object"; + case 11: // Interval + case 17: // Map + default: + return "other"; + } +} + +// Adapted from https://observablehq.com/@cmudig/duckdb-client +// Copyright 2021 CMU Data Interaction Group +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +class DuckDBClient { + constructor(db) { + Object.defineProperties(this, { + _db: {value: db} + }); + } + + async queryStream(query, params) { + const connection = await this._db.connect(); + let reader, batch; + try { + if (params?.length > 0) { + const statement = await connection.prepare(query); + reader = await statement.send(...params); + } else { + reader = await connection.send(query); + } + batch = await reader.next(); + if (batch.done) throw new Error("missing first batch"); + } catch (error) { + await connection.close(); + throw error; + } + return { + schema: getArrowTableSchema(batch.value), + async *readRows() { + try { + while (!batch.done) { + yield batch.value.toArray(); + batch = await reader.next(); + } + } finally { + await connection.close(); + } + } + }; + } + + async query(query, params) { + const result = await this.queryStream(query, params); + const results = []; + for await (const rows of result.readRows()) { + for (const row of rows) { + results.push(row); + } + } + results.schema = result.schema; + return results; + } + + async queryRow(query, params) { + const result = await this.queryStream(query, params); + const reader = result.readRows(); + try { + const {done, value} = await reader.next(); + return done || !value.length ? null : value[0]; + } finally { + await reader.return(); + } + } + + async sql(strings, ...args) { + return await this.query(strings.join("?"), args); + } + + queryTag(strings, ...params) { + return [strings.join("?"), params]; + } + + escape(name) { + return `"${name}"`; + } + + async describeTables() { + const tables = await this.query(`SHOW TABLES`); + return tables.map(({name}) => ({name})); + } + + async describeColumns({table} = {}) { + const columns = await this.query(`DESCRIBE ${table}`); + return columns.map(({column_name, column_type, null: nullable}) => ({ + name: column_name, + type: getDuckDBType(column_type), + nullable: nullable !== "NO", + databaseType: column_type + })); + } + + static async of(sources = {}, config = {}) { + const db = await createDuckDB(); + if (config.query?.castTimestampToDate === undefined) { + config = {...config, query: {...config.query, castTimestampToDate: true}}; + } + await db.open(config); + await Promise.all( + Object.entries(sources).map(async ([name, source]) => { + if (source instanceof FileAttachment) { // bare file + await insertFile(db, name, source); + } else if (isArrowTable(source)) { // bare arrow table + await insertArrowTable(db, name, source); + } else if (Array.isArray(source)) { // bare array of objects + await insertArray(db, name, source); + } else if ("data" in source) { // data + options + const {data, ...options} = source; + if (isArrowTable(data)) { + await insertArrowTable(db, name, data, options); + } else { + await insertArray(db, name, data, options); + } + } else if ("file" in source) { // file + options + const {file, ...options} = source; + await insertFile(db, name, file, options); + } else { + throw new Error(`invalid source: ${source}`); + } + }) + ); + return new DuckDBClient(db); + } +} + +Object.defineProperty(DuckDBClient.prototype, "dialect", { + value: "duckdb" +}); + +async function insertFile(database, name, file, options) { + const url = await file.url(); + if (url.startsWith("blob:")) { + const buffer = await file.arrayBuffer(); + await database.registerFileBuffer(file.name, new Uint8Array(buffer)); + } else { + await database.registerFileURL(file.name, url); + } + const connection = await database.connect(); + try { + switch (file.mimeType) { + case "text/csv": + return await connection.insertCSVFromPath(file.name, { + name, + schema: "main", + ...options + }); + case "application/json": + return await connection.insertJSONFromPath(file.name, { + name, + schema: "main", + ...options + }); + default: + if (/\.arrow$/i.test(file.name)) { + const buffer = new Uint8Array(await file.arrayBuffer()); + return await connection.insertArrowFromIPCStream(buffer, { + name, + schema: "main", + ...options + }); + } + if (/\.parquet$/i.test(file.name)) { + return await connection.query( + `CREATE VIEW '${name}' AS SELECT * FROM parquet_scan('${file.name}')` + ); + } + throw new Error(`unknown file type: ${file.mimeType}`); + } + } finally { + await connection.close(); + } +} + +async function insertArrowTable(database, name, table, options) { + const arrow = await loadArrow(); + const buffer = arrow.tableToIPC(table); + const connection = await database.connect(); + try { + await connection.insertArrowFromIPCStream(buffer, { + name, + schema: "main", + ...options + }); + } finally { + await connection.close(); + } +} + +async function insertArray(database, name, array, options) { + const arrow = await loadArrow(); + const table = arrow.tableFromJSON(array); + return await insertArrowTable(database, name, table, options); +} + +async function createDuckDB() { + const duck = await import(`${cdn}${duckdb.resolve()}`); + const bundle = await duck.selectBundle({ + mvp: { + mainModule: `${cdn}${duckdb.resolve("dist/duckdb-mvp.wasm")}`, + mainWorker: `${cdn}${duckdb.resolve("dist/duckdb-browser-mvp.worker.js")}` + }, + eh: { + mainModule: `${cdn}${duckdb.resolve("dist/duckdb-eh.wasm")}`, + mainWorker: `${cdn}${duckdb.resolve("dist/duckdb-browser-eh.worker.js")}` + } + }); + const logger = new duck.ConsoleLogger(); + const worker = await duck.createWorker(bundle.mainWorker); + const db = new duck.AsyncDuckDB(logger, worker); + await db.instantiate(bundle.mainModule); + return db; +} + +async function loadArrow() { + return await import(`${cdn}${arrow9.resolve()}`); +} + +// https://duckdb.org/docs/sql/data_types/overview +function getDuckDBType(type) { + switch (type) { + case "BIGINT": + case "HUGEINT": + case "UBIGINT": + return "bigint"; + case "DOUBLE": + case "REAL": + return "number"; + case "INTEGER": + case "SMALLINT": + case "TINYINT": + case "USMALLINT": + case "UINTEGER": + case "UTINYINT": + return "integer"; + case "BOOLEAN": + return "boolean"; + case "DATE": + case "TIMESTAMP": + case "TIMESTAMP WITH TIME ZONE": + return "date"; + case "VARCHAR": + case "UUID": + return "string"; + // case "BLOB": + // case "INTERVAL": + // case "TIME": + default: + if (/^DECIMAL\(/.test(type)) return "integer"; + return "other"; + } +} + +function template(render, wrapper) { + return function(strings) { + var string = strings[0], + parts = [], part, + root = null, + node, nodes, + walker, + i, n, j, m, k = -1; + + // Concatenate the text using comments as placeholders. + for (i = 1, n = arguments.length; i < n; ++i) { + part = arguments[i]; + if (part instanceof Node) { + parts[++k] = part; + string += ""; + } else if (Array.isArray(part)) { + for (j = 0, m = part.length; j < m; ++j) { + node = part[j]; + if (node instanceof Node) { + if (root === null) { + parts[++k] = root = document.createDocumentFragment(); + string += ""; + } + root.appendChild(node); + } else { + root = null; + string += node; + } + } + root = null; + } else { + string += part; + } + string += strings[i]; + } + + // Render the text. + root = render(string); + + // Walk the rendered content to replace comment placeholders. + if (++k > 0) { + nodes = new Array(k); + walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT, null, false); + while (walker.nextNode()) { + node = walker.currentNode; + if (/^o:/.test(node.nodeValue)) { + nodes[+node.nodeValue.slice(2)] = node; + } + } + for (i = 0; i < k; ++i) { + if (node = nodes[i]) { + node.parentNode.replaceChild(parts[i], node); + } + } + } + + // Is the rendered content + // … a parent of a single child? Detach and return the child. + // … a document fragment? Replace the fragment with an element. + // … some other node? Return it. + return root.childNodes.length === 1 ? root.removeChild(root.firstChild) + : root.nodeType === 11 ? ((node = wrapper()).appendChild(root), node) + : root; + }; +} + +const html$1 = template(function(string) { + var template = document.createElement("template"); + template.innerHTML = string.trim(); + return document.importNode(template.content, true); +}, function() { + return document.createElement("span"); +}); + +async function leaflet(require) { + const L = await require(leaflet$1.resolve()); + if (!L._style) { + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = await require.resolve(leaflet$1.resolve("dist/leaflet.css")); + L._style = document.head.appendChild(link); + } + return L; +} + +function md(require) { + return require(marked.resolve()).then(function(marked) { + return template( + function(string) { + var root = document.createElement("div"); + root.innerHTML = marked(string, {langPrefix: ""}).trim(); + var code = root.querySelectorAll("pre code[class]"); + if (code.length > 0) { + require(highlight.resolve()).then(function(hl) { + code.forEach(function(block) { + function done() { + hl.highlightBlock(block); + block.parentNode.classList.add("observablehq--md-pre"); + } + if (hl.getLanguage(block.className)) { + done(); + } else { + require(highlight.resolve("async-languages/index.js")) + .then(index => { + if (index.has(block.className)) { + return require(highlight.resolve("async-languages/" + index.get(block.className))).then(language => { + hl.registerLanguage(block.className, language); + }); + } + }) + .then(done, done); + } + }); + }); + } + return root; + }, + function() { + return document.createElement("div"); + } + ); + }); +} + +async function mermaid(require) { + const mer = await require(mermaid$1.resolve()); + mer.initialize({securityLevel: "loose", theme: "neutral"}); + return function mermaid() { + const root = document.createElement("div"); + root.innerHTML = mer.render(uid().id, String.raw.apply(String, arguments)); + return root.removeChild(root.firstChild); + }; +} + +function Mutable(value) { + let change; + Object.defineProperties(this, { + generator: {value: observe(_ => void (change = _))}, + value: {get: () => value, set: x => change(value = x)} // eslint-disable-line no-setter-return + }); + if (value !== undefined) change(value); +} + +function* now() { + while (true) { + yield Date.now(); + } +} + +function delay(duration, value) { + return new Promise(function(resolve) { + setTimeout(function() { + resolve(value); + }, duration); + }); +} + +var timeouts = new Map; + +function timeout(now, time) { + var t = new Promise(function(resolve) { + timeouts.delete(time); + var delay = time - now; + if (!(delay > 0)) throw new Error("invalid time"); + if (delay > 0x7fffffff) throw new Error("too long to wait"); + setTimeout(resolve, delay); + }); + timeouts.set(time, t); + return t; +} + +function when(time, value) { + var now; + return (now = timeouts.get(time = +time)) ? now.then(() => value) + : (now = Date.now()) >= time ? Promise.resolve(value) + : timeout(now, time).then(() => value); +} + +function tick(duration, value) { + return when(Math.ceil((Date.now() + 1) / duration) * duration, value); +} + +var Promises = /*#__PURE__*/Object.freeze({ +__proto__: null, +delay: delay, +tick: tick, +when: when +}); + +function resolve(name, base) { + if (/^(\w+:)|\/\//i.test(name)) return name; + if (/^[.]{0,2}\//i.test(name)) return new URL(name, base == null ? location : base).href; + if (!name.length || /^[\s._]/.test(name) || /\s$/.test(name)) throw new Error("illegal name"); + return "https://unpkg.com/" + name; +} + +const svg = template(function(string) { + var root = document.createElementNS("http://www.w3.org/2000/svg", "g"); + root.innerHTML = string.trim(); + return root; +}, function() { + return document.createElementNS("http://www.w3.org/2000/svg", "g"); +}); + +var raw = String.raw; + +function style(href) { + return new Promise(function(resolve, reject) { + var link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = href; + link.onerror = reject; + link.onload = resolve; + document.head.appendChild(link); + }); +} + +function tex(require) { + return Promise.all([ + require(katex.resolve()), + require.resolve(katex.resolve("dist/katex.min.css")).then(style) + ]).then(function(values) { + var katex = values[0], tex = renderer(); + + function renderer(options) { + return function() { + var root = document.createElement("div"); + katex.render(raw.apply(String, arguments), root, options); + return root.removeChild(root.firstChild); + }; + } + + tex.options = renderer; + tex.block = renderer({displayMode: true}); + return tex; + }); +} + +async function vl(require) { + const [v, vl, api] = await Promise.all([vega, vegalite, vegaliteApi].map(d => require(d.resolve()))); + return api.register(v, vl); +} + +function width() { + return observe(function(change) { + var width = change(document.body.clientWidth); + function resized() { + var w = document.body.clientWidth; + if (w !== width) change(width = w); + } + window.addEventListener("resize", resized); + return function() { + window.removeEventListener("resize", resized); + }; + }); +} + +function ascending(a, b) { + return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; +} + +function descending(a, b) { + return a == null || b == null ? NaN + : b < a ? -1 + : b > a ? 1 + : b >= a ? 0 + : NaN; +} + +function bisector(f) { + let compare1, compare2, delta; + + // If an accessor is specified, promote it to a comparator. In this case we + // can test whether the search value is (self-) comparable. We can’t do this + // for a comparator (except for specific, known comparators) because we can’t + // tell if the comparator is symmetric, and an asymmetric comparator can’t be + // used to test whether a single value is comparable. + if (f.length !== 2) { + compare1 = ascending; + compare2 = (d, x) => ascending(f(d), x); + delta = (d, x) => f(d) - x; + } else { + compare1 = f === ascending || f === descending ? f : zero; + compare2 = f; + delta = f; + } + + function left(a, x, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x, x) !== 0) return hi; + do { + const mid = (lo + hi) >>> 1; + if (compare2(a[mid], x) < 0) lo = mid + 1; + else hi = mid; + } while (lo < hi); + } + return lo; + } + + function right(a, x, lo = 0, hi = a.length) { + if (lo < hi) { + if (compare1(x, x) !== 0) return hi; + do { + const mid = (lo + hi) >>> 1; + if (compare2(a[mid], x) <= 0) lo = mid + 1; + else hi = mid; + } while (lo < hi); + } + return lo; + } + + function center(a, x, lo = 0, hi = a.length) { + const i = left(a, x, lo, hi - 1); + return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i; + } + + return {left, center, right}; +} + +function zero() { + return 0; +} + +function number(x) { + return x === null ? NaN : +x; +} + +bisector(ascending); +bisector(number).center; + +function reverse(values) { + if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); + return Array.from(values).reverse(); +} + +const nChecks = 20; // number of values to check in each array + +// We support two levels of DatabaseClient. The simplest DatabaseClient +// implements only the client.sql tagged template literal. More advanced +// DatabaseClients implement client.query and client.queryStream, which support +// streaming and abort, and the client.queryTag tagged template literal is used +// to translate the contents of a SQL cell or Table cell into the appropriate +// arguments for calling client.query or client.queryStream. For table cells, we +// additionally require client.describeColumns. The client.describeTables method +// is optional. +function isDatabaseClient(value, mode) { + return ( + value && + (typeof value.sql === "function" || + (typeof value.queryTag === "function" && + (typeof value.query === "function" || + typeof value.queryStream === "function"))) && + (mode !== "table" || typeof value.describeColumns === "function") && + value !== __query // don’t match our internal helper + ); +} + +// Returns true if the value is a typed array (for a single-column table), or if +// it’s an array. In the latter case, the elements of the array must be +// consistently typed: either plain objects or primitives or dates. +function isDataArray(value) { + return ( + (Array.isArray(value) && + (isQueryResultSetSchema(value.schema) || + isQueryResultSetColumns(value.columns) || + arrayContainsObjects(value) || + arrayContainsPrimitives(value) || + arrayContainsDates(value))) || + isTypedArray(value) + ); +} + +// Given an array, checks that the given value is an array that does not contain +// any primitive values (at least for the first few values that we check), and +// that the first object contains enumerable keys (see computeSchema for how we +// infer the columns). We assume that the contents of the table are homogenous, +// but we don’t currently enforce this. +// https://observablehq.com/@observablehq/database-client-specification#§1 +function arrayContainsObjects(value) { + const n = Math.min(nChecks, value.length); + for (let i = 0; i < n; ++i) { + const v = value[i]; + if (v === null || typeof v !== "object") return false; + } + return n > 0 && objectHasEnumerableKeys(value[0]); +} + +// Using a for-in loop here means that we can abort after finding at least one +// enumerable key (whereas Object.keys would require materializing the array of +// all keys, which would be considerably slower if the value has many keys!). +// This function assumes that value is an object; see arrayContainsObjects. +function objectHasEnumerableKeys(value) { + for (const _ in value) return true; + return false; +} + +function isQueryResultSetSchema(schemas) { + return (Array.isArray(schemas) && schemas.every((s) => s && typeof s.name === "string")); +} + +function isQueryResultSetColumns(columns) { + return (Array.isArray(columns) && columns.every((name) => typeof name === "string")); +} + +// Returns true if the value represents an array of primitives (i.e., a +// single-column table). This should only be passed values for which +// isDataArray returns true. +function arrayIsPrimitive(value) { + return ( + isTypedArray(value) || + arrayContainsPrimitives(value) || + arrayContainsDates(value) + ); +} + +// Given an array, checks that the first n elements are primitives (number, +// string, boolean, bigint) of a consistent type. +function arrayContainsPrimitives(value) { + const n = Math.min(nChecks, value.length); + if (!(n > 0)) return false; + let type; + let hasPrimitive = false; // ensure we encounter 1+ primitives + for (let i = 0; i < n; ++i) { + const v = value[i]; + if (v == null) continue; // ignore null and undefined + const t = typeof v; + if (type === undefined) { + switch (t) { + case "number": + case "boolean": + case "string": + case "bigint": + type = t; + break; + default: + return false; + } + } else if (t !== type) { + return false; + } + hasPrimitive = true; + } + return hasPrimitive; +} + +// Given an array, checks that the first n elements are dates. +function arrayContainsDates(value) { + const n = Math.min(nChecks, value.length); + if (!(n > 0)) return false; + let hasDate = false; // ensure we encounter 1+ dates + for (let i = 0; i < n; ++i) { + const v = value[i]; + if (v == null) continue; // ignore null and undefined + if (!(v instanceof Date)) return false; + hasDate = true; + } + return hasDate; +} + +function isTypedArray(value) { + return ( + value instanceof Int8Array || + value instanceof Int16Array || + value instanceof Int32Array || + value instanceof Uint8Array || + value instanceof Uint8ClampedArray || + value instanceof Uint16Array || + value instanceof Uint32Array || + value instanceof Float32Array || + value instanceof Float64Array + ); +} + +// __query is used by table cells; __query.sql is used by SQL cells. +const __query = Object.assign( + async (source, operations, invalidation) => { + source = await loadDataSource(await source, "table"); + if (isDatabaseClient(source)) return evaluateQuery(source, makeQueryTemplate(operations, source), invalidation); + if (isDataArray(source)) return __table(source, operations); + if (!source) throw new Error("missing data source"); + throw new Error("invalid data source"); + }, + { + sql(source, invalidation) { + return async function () { + return evaluateQuery(await loadDataSource(await source, "sql"), arguments, invalidation); + }; + } + } +); + +async function loadDataSource(source, mode) { + if (source instanceof FileAttachment) { + if (mode === "table") { + switch (source.mimeType) { + case "text/csv": return source.csv({typed: true}); + case "text/tab-separated-values": return source.tsv({typed: true}); + case "application/json": return source.json(); + } + } + if (mode === "table" || mode === "sql") { + switch (source.mimeType) { + case "application/x-sqlite3": return source.sqlite(); + } + if (/\.arrow$/i.test(source.name)) return DuckDBClient.of({__table: await source.arrow({version: 9})}); + } + throw new Error(`unsupported file type: ${source.mimeType}`); + } + if ((mode === "table" || mode === "sql") && isArrowTable(source)) { + return DuckDBClient.of({__table: source}); + } + return source; +} + +async function evaluateQuery(source, args, invalidation) { + if (!source) throw new Error("missing data source"); + + // If this DatabaseClient supports abort and streaming, use that. + if (typeof source.queryTag === "function") { + const abortController = new AbortController(); + const options = {signal: abortController.signal}; + invalidation.then(() => abortController.abort("invalidated")); + if (typeof source.queryStream === "function") { + return accumulateQuery( + source.queryStream(...source.queryTag.apply(source, args), options) + ); + } + if (typeof source.query === "function") { + return source.query(...source.queryTag.apply(source, args), options); + } + } + + // Otherwise, fallback to the basic sql tagged template literal. + if (typeof source.sql === "function") { + return source.sql.apply(source, args); + } + + // TODO: test if source is a file attachment, and support CSV etc. + throw new Error("source does not implement query, queryStream, or sql"); +} + +// Generator function that yields accumulated query results client.queryStream +async function* accumulateQuery(queryRequest) { + let then = performance.now(); + const queryResponse = await queryRequest; + const values = []; + values.done = false; + values.error = null; + values.schema = queryResponse.schema; + try { + for await (const rows of queryResponse.readRows()) { + if (performance.now() - then > 10 && values.length > 0) { + yield values; + then = performance.now(); + } + for (const value of rows) { + values.push(value); + } + } + values.done = true; + yield values; + } catch (error) { + values.error = error; + yield values; + } +} + +/** + * Returns a SQL query in the form [[parts], ...params] where parts is an array + * of sub-strings and params are the parameter values to be inserted between each + * sub-string. + */ +function makeQueryTemplate(operations, source) { + const escaper = + typeof source.escape === "function" ? source.escape : (i) => i; + const {select, from, filter, sort, slice} = operations; + if (!from.table) + throw new Error("missing from table"); + if (select.columns && select.columns.length === 0) + throw new Error("at least one column must be selected"); + const columns = select.columns ? select.columns.map((c) => `t.${escaper(c)}`) : "*"; + const args = [ + [`SELECT ${columns} FROM ${formatTable(from.table, escaper)} t`] + ]; + for (let i = 0; i < filter.length; ++i) { + appendSql(i ? `\nAND ` : `\nWHERE `, args); + appendWhereEntry(filter[i], args, escaper); + } + for (let i = 0; i < sort.length; ++i) { + appendSql(i ? `, ` : `\nORDER BY `, args); + appendOrderBy(sort[i], args, escaper); + } + if (source.dialect === "mssql") { + if (slice.to !== null || slice.from !== null) { + if (!sort.length) { + if (!select.columns) + throw new Error( + "at least one column must be explicitly specified. Received '*'." + ); + appendSql(`\nORDER BY `, args); + appendOrderBy( + {column: select.columns[0], direction: "ASC"}, + args, + escaper + ); + } + appendSql(`\nOFFSET ${slice.from || 0} ROWS`, args); + appendSql( + `\nFETCH NEXT ${ + slice.to !== null ? slice.to - (slice.from || 0) : 1e9 + } ROWS ONLY`, + args + ); + } + } else { + if (slice.to !== null || slice.from !== null) { + appendSql( + `\nLIMIT ${slice.to !== null ? slice.to - (slice.from || 0) : 1e9}`, + args + ); + } + if (slice.from !== null) { + appendSql(` OFFSET ${slice.from}`, args); + } + } + return args; +} + +function formatTable(table, escaper) { + if (typeof table === "object") { // i.e., not a bare string specifier + let from = ""; + if (table.database != null) from += escaper(table.database) + "."; + if (table.schema != null) from += escaper(table.schema) + "."; + from += escaper(table.table); + return from; + } + return table; +} + +function appendSql(sql, args) { + const strings = args[0]; + strings[strings.length - 1] += sql; +} + +function appendOrderBy({column, direction}, args, escaper) { + appendSql(`t.${escaper(column)} ${direction.toUpperCase()}`, args); +} + +function appendWhereEntry({type, operands}, args, escaper) { + if (operands.length < 1) throw new Error("Invalid operand length"); + + // Unary operations + if (operands.length === 1) { + appendOperand(operands[0], args, escaper); + switch (type) { + case "n": + appendSql(` IS NULL`, args); + return; + case "nn": + appendSql(` IS NOT NULL`, args); + return; + default: + throw new Error("Invalid filter operation"); + } + } + + // Binary operations + if (operands.length === 2) { + if (["in", "nin"].includes(type)) ; else if (["c", "nc"].includes(type)) { + // TODO: Case (in)sensitive? + appendOperand(operands[0], args, escaper); + switch (type) { + case "c": + appendSql(` LIKE `, args); + break; + case "nc": + appendSql(` NOT LIKE `, args); + break; + } + appendOperand(likeOperand(operands[1]), args, escaper); + return; + } else { + appendOperand(operands[0], args, escaper); + switch (type) { + case "eq": + appendSql(` = `, args); + break; + case "ne": + appendSql(` <> `, args); + break; + case "gt": + appendSql(` > `, args); + break; + case "lt": + appendSql(` < `, args); + break; + case "gte": + appendSql(` >= `, args); + break; + case "lte": + appendSql(` <= `, args); + break; + default: + throw new Error("Invalid filter operation"); + } + appendOperand(operands[1], args, escaper); + return; + } + } + + // List operations + appendOperand(operands[0], args, escaper); + switch (type) { + case "in": + appendSql(` IN (`, args); + break; + case "nin": + appendSql(` NOT IN (`, args); + break; + default: + throw new Error("Invalid filter operation"); + } + appendListOperands(operands.slice(1), args); + appendSql(")", args); +} + +function appendOperand(o, args, escaper) { + if (o.type === "column") { + appendSql(`t.${escaper(o.value)}`, args); + } else { + args.push(o.value); + args[0].push(""); + } +} + +// TODO: Support column operands here? +function appendListOperands(ops, args) { + let first = true; + for (const op of ops) { + if (first) first = false; + else appendSql(",", args); + args.push(op.value); + args[0].push(""); + } +} + +function likeOperand(operand) { + return {...operand, value: `%${operand.value}%`}; +} + +// This function applies table cell operations to an in-memory table (array of +// objects); it should be equivalent to the corresponding SQL query. +function __table(source, operations) { + const input = source; + let {schema, columns} = source; + let primitive = arrayIsPrimitive(source); + if (primitive) source = Array.from(source, (value) => ({value})); + for (const {type, operands} of operations.filter) { + const [{value: column}] = operands; + const values = operands.slice(1).map(({value}) => value); + switch (type) { + case "eq": { + const [value] = values; + if (value instanceof Date) { + const time = +value; // compare as primitive + source = source.filter((d) => +d[column] === time); + } else { + source = source.filter((d) => d[column] === value); + } + break; + } + case "ne": { + const [value] = values; + source = source.filter((d) => d[column] !== value); + break; + } + case "c": { + const [value] = values; + source = source.filter( + (d) => typeof d[column] === "string" && d[column].includes(value) + ); + break; + } + case "nc": { + const [value] = values; + source = source.filter( + (d) => typeof d[column] === "string" && !d[column].includes(value) + ); + break; + } + case "in": { + const set = new Set(values); // TODO support dates? + source = source.filter((d) => set.has(d[column])); + break; + } + case "nin": { + const set = new Set(values); // TODO support dates? + source = source.filter((d) => !set.has(d[column])); + break; + } + case "n": { + source = source.filter((d) => d[column] == null); + break; + } + case "nn": { + source = source.filter((d) => d[column] != null); + break; + } + case "lt": { + const [value] = values; + source = source.filter((d) => d[column] < value); + break; + } + case "lte": { + const [value] = values; + source = source.filter((d) => d[column] <= value); + break; + } + case "gt": { + const [value] = values; + source = source.filter((d) => d[column] > value); + break; + } + case "gte": { + const [value] = values; + source = source.filter((d) => d[column] >= value); + break; + } + default: + throw new Error(`unknown filter type: ${type}`); + } + } + for (const {column, direction} of reverse(operations.sort)) { + const compare = direction === "desc" ? descending : ascending; + if (source === input) source = source.slice(); // defensive copy + source.sort((a, b) => compare(a[column], b[column])); + } + let {from, to} = operations.slice; + from = from == null ? 0 : Math.max(0, from); + to = to == null ? Infinity : Math.max(0, to); + if (from > 0 || to < Infinity) { + source = source.slice(Math.max(0, from), Math.max(0, to)); + } + if (operations.select.columns) { + if (schema) { + const schemaByName = new Map(schema.map((s) => [s.name, s])); + schema = operations.select.columns.map((c) => schemaByName.get(c)); + } + if (columns) { + columns = operations.select.columns; + } + source = source.map((d) => + Object.fromEntries(operations.select.columns.map((c) => [c, d[c]])) + ); + } + if (primitive) source = source.map((d) => d.value); + if (source !== input) { + if (schema) source.schema = schema; + if (columns) source.columns = columns; + } + return source; +} + +const Library = Object.assign(Object.defineProperties(function Library(resolver) { + const require = requirer(resolver); + Object.defineProperties(this, properties({ + FileAttachment: () => NoFileAttachments, + Mutable: () => Mutable, + now, + width, + + // Tagged template literals + dot: () => require(graphviz.resolve()), + htl: () => require(htl.resolve()), + html: () => html$1, + md: () => md(require), + svg: () => svg, + tex: () => tex(require), + + // Recommended libraries + // https://observablehq.com/@observablehq/recommended-libraries + _: () => require(lodash.resolve()), + aq: () => require.alias({"apache-arrow": arrow4.resolve()})(arquero.resolve()), // TODO upgrade to apache-arrow@9 + Arrow: () => require(arrow4.resolve()), // TODO upgrade to apache-arrow@9 + d3: () => require(d3.resolve()), + DuckDBClient: () => DuckDBClient, + Inputs: () => require(inputs.resolve()).then(Inputs => ({...Inputs, file: Inputs.fileOf(AbstractFile)})), + L: () => leaflet(require), + mermaid: () => mermaid(require), + Plot: () => require(plot.resolve()), + __query: () => __query, + require: () => require, + resolve: () => resolve, // deprecated; use async require.resolve instead + SQLite: () => SQLite(require), + SQLiteDatabaseClient: () => SQLiteDatabaseClient, + topojson: () => require(topojson.resolve()), + vl: () => vl(require), + + // Sample datasets + // https://observablehq.com/@observablehq/datasets + aapl: () => new FileAttachment("https://static.observableusercontent.com/files/3ccff97fd2d93da734e76829b2b066eafdaac6a1fafdec0faf6ebc443271cfc109d29e80dd217468fcb2aff1e6bffdc73f356cc48feb657f35378e6abbbb63b9").csv({typed: true}), + alphabet: () => new FileAttachment("https://static.observableusercontent.com/files/75d52e6c3130b1cae83cda89305e17b50f33e7420ef205587a135e8562bcfd22e483cf4fa2fb5df6dff66f9c5d19740be1cfaf47406286e2eb6574b49ffc685d").csv({typed: true}), + cars: () => new FileAttachment("https://static.observableusercontent.com/files/048ec3dfd528110c0665dfa363dd28bc516ffb7247231f3ab25005036717f5c4c232a5efc7bb74bc03037155cb72b1abe85a33d86eb9f1a336196030443be4f6").csv({typed: true}), + citywages: () => new FileAttachment("https://static.observableusercontent.com/files/39837ec5121fcc163131dbc2fe8c1a2e0b3423a5d1e96b5ce371e2ac2e20a290d78b71a4fb08b9fa6a0107776e17fb78af313b8ea70f4cc6648fad68ddf06f7a").csv({typed: true}), + diamonds: () => new FileAttachment("https://static.observableusercontent.com/files/87942b1f5d061a21fa4bb8f2162db44e3ef0f7391301f867ab5ba718b225a63091af20675f0bfe7f922db097b217b377135203a7eab34651e21a8d09f4e37252").csv({typed: true}), + flare: () => new FileAttachment("https://static.observableusercontent.com/files/a6b0d94a7f5828fd133765a934f4c9746d2010e2f342d335923991f31b14120de96b5cb4f160d509d8dc627f0107d7f5b5070d2516f01e4c862b5b4867533000").csv({typed: true}), + industries: () => new FileAttachment("https://static.observableusercontent.com/files/76f13741128340cc88798c0a0b7fa5a2df8370f57554000774ab8ee9ae785ffa2903010cad670d4939af3e9c17e5e18e7e05ed2b38b848ac2fc1a0066aa0005f").csv({typed: true}), + miserables: () => new FileAttachment("https://static.observableusercontent.com/files/31d904f6e21d42d4963ece9c8cc4fbd75efcbdc404bf511bc79906f0a1be68b5a01e935f65123670ed04e35ca8cae3c2b943f82bf8db49c5a67c85cbb58db052").json(), + olympians: () => new FileAttachment("https://static.observableusercontent.com/files/31ca24545a0603dce099d10ee89ee5ae72d29fa55e8fc7c9ffb5ded87ac83060d80f1d9e21f4ae8eb04c1e8940b7287d179fe8060d887fb1f055f430e210007c").csv({typed: true}), + penguins: () => new FileAttachment("https://static.observableusercontent.com/files/715db1223e067f00500780077febc6cebbdd90c151d3d78317c802732252052ab0e367039872ab9c77d6ef99e5f55a0724b35ddc898a1c99cb14c31a379af80a").csv({typed: true}), + weather: () => new FileAttachment("https://static.observableusercontent.com/files/693a46b22b33db0f042728700e0c73e836fa13d55446df89120682d55339c6db7cc9e574d3d73f24ecc9bc7eb9ac9a1e7e104a1ee52c00aab1e77eb102913c1f").csv({typed: true}), + + // Note: these are namespace objects, and thus exposed directly rather than + // being wrapped in a function. This allows library.Generators to resolve, + // rather than needing module.value. + DOM, + Files, + Generators: Generators$1, + Promises + })); +}, { + resolve: { + get: () => requireDefault.resolve, + enumerable: true, + configurable: true + }, + require: { + get: () => requireDefault, + set: setDefaultRequire, + enumerable: true, + configurable: true + } +}), { + resolveFrom, + requireFrom +}); + +function properties(values) { + return Object.fromEntries(Object.entries(values).map(property)); +} + +function property([key, value]) { + return [key, ({value, writable: true, enumerable: true})]; +} + +// src/main.js +class PandocCodeDecorator { + constructor(node) { + this._node = node; + this._spans = []; + this.normalizeCodeRange(); + this.initializeEntryPoints(); + } + normalizeCodeRange() { + const n = this._node; + const lines = n.querySelectorAll("code > span"); + for (const line of lines) { + Array.from(line.childNodes).filter((n2) => n2.nodeType === n2.TEXT_NODE).forEach((n2) => { + const newSpan = document.createElement("span"); + newSpan.textContent = n2.wholeText; + n2.replaceWith(newSpan); + }); + } + } + initializeEntryPoints() { + const lines = this._node.querySelectorAll("code > span"); + let result = []; + let offset = this._node.parentElement.dataset.sourceOffset && -Number(this._node.parentElement.dataset.sourceOffset) || 0; + for (const line of lines) { + let lineNumber = Number(line.id.split("-").pop()); + let column = 1; + Array.from(line.childNodes).filter((n) => n.nodeType === n.ELEMENT_NODE && n.nodeName === "SPAN").forEach((n) => { + result.push({ + offset, + line: lineNumber, + column, + node: n + }); + offset += n.textContent.length; + column += n.textContent.length; + }); + offset += 1; + } + this._elementEntryPoints = result; + } + locateEntry(offset) { + let candidate; + if (offset === Infinity) + return void 0; + for (let i = 0; i < this._elementEntryPoints.length; ++i) { + const entry = this._elementEntryPoints[i]; + if (entry.offset > offset) { + return { entry: candidate, index: i - 1 }; + } + candidate = entry; + } + if (offset < candidate.offset + candidate.node.textContent.length) { + return { entry: candidate, index: this._elementEntryPoints.length - 1 }; + } else { + return void 0; + } + } + offsetToLineColumn(offset) { + let entry = this.locateEntry(offset); + if (entry === void 0) { + const entries = this._elementEntryPoints; + const last = entries[entries.length - 1]; + return { + line: last.line, + column: last.column + Math.min(last.node.textContent.length, offset - last.offset) + }; + } + return { + line: entry.entry.line, + column: entry.entry.column + offset - entry.entry.offset + }; + } + *spanSelection(start, end) { + this.ensureExactSpan(start, end); + const startEntry = this.locateEntry(start); + const endEntry = this.locateEntry(end); + if (startEntry === void 0) { + return; + } + const startIndex = startEntry.index; + const endIndex = endEntry && endEntry.index || this._elementEntryPoints.length; + for (let i = startIndex; i < endIndex; ++i) { + if (this._elementEntryPoints[i] !== void 0) { + yield this._elementEntryPoints[i]; + } + } + } + decorateSpan(start, end, classes) { + for (const entryPoint of this.spanSelection(start, end)) { + for (const cssClass of classes) { + entryPoint.node.classList.add(cssClass); + } + } + } + clearSpan(start, end, classes) { + for (const entryPoint of this.spanSelection(start, end)) { + for (const cssClass of classes) { + entryPoint.node.classList.remove(cssClass); + } + } + } + ensureExactSpan(start, end) { + const splitEntry = (entry, offset) => { + const newSpan = document.createElement("span"); + for (const cssClass of entry.node.classList) { + newSpan.classList.add(cssClass); + } + const beforeText = entry.node.textContent.slice(0, offset - entry.offset); + const afterText = entry.node.textContent.slice(offset - entry.offset); + entry.node.textContent = beforeText; + newSpan.textContent = afterText; + entry.node.after(newSpan); + this._elementEntryPoints.push({ + column: entry.column + offset - entry.offset, + line: entry.line, + node: newSpan, + offset + }); + this._elementEntryPoints.sort((a, b) => a.offset - b.offset); + }; + const startEntry = this.locateEntry(start); + if (startEntry !== void 0 && startEntry.entry !== void 0 && startEntry.entry.offset != start) { + splitEntry(startEntry.entry, start); + } + const endEntry = this.locateEntry(end); + if (endEntry !== void 0 && startEntry.entry !== void 0 && endEntry.entry.offset !== end) { + splitEntry(endEntry.entry, end); + } + } + clearSpan(start, end, classes) { + this.ensureExactSpan(start, end); + const startEntry = this.locateEntry(start); + const endEntry = this.locateEntry(end); + if (startEntry === void 0) { + return; + } + const startIndex = startEntry.index; + const endIndex = endEntry && endEntry.index || this._elementEntryPoints.length; + for (let i = startIndex; i < endIndex; ++i) { + for (const cssClass of classes) { + this._elementEntryPoints[i].node.classList.remove(cssClass); + } + } + } +} + +function dispatch(node, type, detail) { + detail = detail || {}; + var document = node.ownerDocument, event = document.defaultView.CustomEvent; + if (typeof event === "function") { + event = new event(type, {detail: detail}); + } else { + event = document.createEvent("Event"); + event.initEvent(type, false, false); + event.detail = detail; + } + node.dispatchEvent(event); +} + +// TODO https://twitter.com/mbostock/status/702737065121742848 +function isarray(value) { + return Array.isArray(value) + || value instanceof Int8Array + || value instanceof Int16Array + || value instanceof Int32Array + || value instanceof Uint8Array + || value instanceof Uint8ClampedArray + || value instanceof Uint16Array + || value instanceof Uint32Array + || value instanceof Float32Array + || value instanceof Float64Array; +} + +// Non-integer keys in arrays, e.g. [1, 2, 0.5: "value"]. +function isindex(key) { + return key === (key | 0) + ""; +} + +function inspectName(name) { + const n = document.createElement("span"); + n.className = "observablehq--cellname"; + n.textContent = `${name} = `; + return n; +} + +const symbolToString = Symbol.prototype.toString; + +// Symbols do not coerce to strings; they must be explicitly converted. +function formatSymbol(symbol) { + return symbolToString.call(symbol); +} + +const {getOwnPropertySymbols, prototype: {hasOwnProperty: hasOwnProperty$1}} = Object; +const {toStringTag} = Symbol; + +const FORBIDDEN = {}; + +const symbolsof = getOwnPropertySymbols; + +function isown(object, key) { + return hasOwnProperty$1.call(object, key); +} + +function tagof(object) { + return object[toStringTag] + || (object.constructor && object.constructor.name) + || "Object"; +} + +function valueof(object, key) { + try { + const value = object[key]; + if (value) value.constructor; // Test for SecurityError. + return value; + } catch (ignore) { + return FORBIDDEN; + } +} + +const SYMBOLS = [ + { symbol: "@@__IMMUTABLE_INDEXED__@@", name: "Indexed", modifier: true }, + { symbol: "@@__IMMUTABLE_KEYED__@@", name: "Keyed", modifier: true }, + { symbol: "@@__IMMUTABLE_LIST__@@", name: "List", arrayish: true }, + { symbol: "@@__IMMUTABLE_MAP__@@", name: "Map" }, + { + symbol: "@@__IMMUTABLE_ORDERED__@@", + name: "Ordered", + modifier: true, + prefix: true + }, + { symbol: "@@__IMMUTABLE_RECORD__@@", name: "Record" }, + { + symbol: "@@__IMMUTABLE_SET__@@", + name: "Set", + arrayish: true, + setish: true + }, + { symbol: "@@__IMMUTABLE_STACK__@@", name: "Stack", arrayish: true } +]; + +function immutableName(obj) { + try { + let symbols = SYMBOLS.filter(({ symbol }) => obj[symbol] === true); + if (!symbols.length) return; + + const name = symbols.find(s => !s.modifier); + const prefix = + name.name === "Map" && symbols.find(s => s.modifier && s.prefix); + + const arrayish = symbols.some(s => s.arrayish); + const setish = symbols.some(s => s.setish); + + return { + name: `${prefix ? prefix.name : ""}${name.name}`, + symbols, + arrayish: arrayish && !setish, + setish + }; + } catch (e) { + return null; + } +} + +const {getPrototypeOf, getOwnPropertyDescriptors} = Object; +const objectPrototype = getPrototypeOf({}); + +function inspectExpanded(object, _, name, proto) { + let arrayish = isarray(object); + let tag, fields, next, n; + + if (object instanceof Map) { + if (object instanceof object.constructor) { + tag = `Map(${object.size})`; + fields = iterateMap$1; + } else { // avoid incompatible receiver error for prototype + tag = "Map()"; + fields = iterateObject$1; + } + } else if (object instanceof Set) { + if (object instanceof object.constructor) { + tag = `Set(${object.size})`; + fields = iterateSet$1; + } else { // avoid incompatible receiver error for prototype + tag = "Set()"; + fields = iterateObject$1; + } + } else if (arrayish) { + tag = `${object.constructor.name}(${object.length})`; + fields = iterateArray$1; + } else if ((n = immutableName(object))) { + tag = `Immutable.${n.name}${n.name === "Record" ? "" : `(${object.size})`}`; + arrayish = n.arrayish; + fields = n.arrayish + ? iterateImArray$1 + : n.setish + ? iterateImSet$1 + : iterateImObject$1; + } else if (proto) { + tag = tagof(object); + fields = iterateProto; + } else { + tag = tagof(object); + fields = iterateObject$1; + } + + const span = document.createElement("span"); + span.className = "observablehq--expanded"; + if (name) { + span.appendChild(inspectName(name)); + } + const a = span.appendChild(document.createElement("a")); + a.innerHTML = ` + + `; + a.appendChild(document.createTextNode(`${tag}${arrayish ? " [" : " {"}`)); + a.addEventListener("mouseup", function(event) { + event.stopPropagation(); + replace(span, inspectCollapsed(object, null, name, proto)); + }); + + fields = fields(object); + for (let i = 0; !(next = fields.next()).done && i < 20; ++i) { + span.appendChild(next.value); + } + + if (!next.done) { + const a = span.appendChild(document.createElement("a")); + a.className = "observablehq--field"; + a.style.display = "block"; + a.appendChild(document.createTextNode(` … more`)); + a.addEventListener("mouseup", function(event) { + event.stopPropagation(); + span.insertBefore(next.value, span.lastChild.previousSibling); + for (let i = 0; !(next = fields.next()).done && i < 19; ++i) { + span.insertBefore(next.value, span.lastChild.previousSibling); + } + if (next.done) span.removeChild(span.lastChild.previousSibling); + dispatch(span, "load"); + }); + } + + span.appendChild(document.createTextNode(arrayish ? "]" : "}")); + + return span; +} + +function* iterateMap$1(map) { + for (const [key, value] of map) { + yield formatMapField$1(key, value); + } + yield* iterateObject$1(map); +} + +function* iterateSet$1(set) { + for (const value of set) { + yield formatSetField(value); + } + yield* iterateObject$1(set); +} + +function* iterateImSet$1(set) { + for (const value of set) { + yield formatSetField(value); + } +} + +function* iterateArray$1(array) { + for (let i = 0, n = array.length; i < n; ++i) { + if (i in array) { + yield formatField$1(i, valueof(array, i), "observablehq--index"); + } + } + for (const key in array) { + if (!isindex(key) && isown(array, key)) { + yield formatField$1(key, valueof(array, key), "observablehq--key"); + } + } + for (const symbol of symbolsof(array)) { + yield formatField$1( + formatSymbol(symbol), + valueof(array, symbol), + "observablehq--symbol" + ); + } +} + +function* iterateImArray$1(array) { + let i1 = 0; + for (const n = array.size; i1 < n; ++i1) { + yield formatField$1(i1, array.get(i1), true); + } +} + +function* iterateProto(object) { + for (const key in getOwnPropertyDescriptors(object)) { + yield formatField$1(key, valueof(object, key), "observablehq--key"); + } + for (const symbol of symbolsof(object)) { + yield formatField$1( + formatSymbol(symbol), + valueof(object, symbol), + "observablehq--symbol" + ); + } + + const proto = getPrototypeOf(object); + if (proto && proto !== objectPrototype) { + yield formatPrototype(proto); + } +} + +function* iterateObject$1(object) { + for (const key in object) { + if (isown(object, key)) { + yield formatField$1(key, valueof(object, key), "observablehq--key"); + } + } + for (const symbol of symbolsof(object)) { + yield formatField$1( + formatSymbol(symbol), + valueof(object, symbol), + "observablehq--symbol" + ); + } + + const proto = getPrototypeOf(object); + if (proto && proto !== objectPrototype) { + yield formatPrototype(proto); + } +} + +function* iterateImObject$1(object) { + for (const [key, value] of object) { + yield formatField$1(key, value, "observablehq--key"); + } +} + +function formatPrototype(value) { + const item = document.createElement("div"); + const span = item.appendChild(document.createElement("span")); + item.className = "observablehq--field"; + span.className = "observablehq--prototype-key"; + span.textContent = ` `; + item.appendChild(document.createTextNode(": ")); + item.appendChild(inspect(value, undefined, undefined, undefined, true)); + return item; +} + +function formatField$1(key, value, className) { + const item = document.createElement("div"); + const span = item.appendChild(document.createElement("span")); + item.className = "observablehq--field"; + span.className = className; + span.textContent = ` ${key}`; + item.appendChild(document.createTextNode(": ")); + item.appendChild(inspect(value)); + return item; +} + +function formatMapField$1(key, value) { + const item = document.createElement("div"); + item.className = "observablehq--field"; + item.appendChild(document.createTextNode(" ")); + item.appendChild(inspect(key)); + item.appendChild(document.createTextNode(" => ")); + item.appendChild(inspect(value)); + return item; +} + +function formatSetField(value) { + const item = document.createElement("div"); + item.className = "observablehq--field"; + item.appendChild(document.createTextNode(" ")); + item.appendChild(inspect(value)); + return item; +} + +function hasSelection(elem) { + const sel = window.getSelection(); + return ( + sel.type === "Range" && + (sel.containsNode(elem, true) || + sel.anchorNode.isSelfOrDescendant(elem) || + sel.focusNode.isSelfOrDescendant(elem)) + ); +} + +function inspectCollapsed(object, shallow, name, proto) { + let arrayish = isarray(object); + let tag, fields, next, n; + + if (object instanceof Map) { + if (object instanceof object.constructor) { + tag = `Map(${object.size})`; + fields = iterateMap; + } else { // avoid incompatible receiver error for prototype + tag = "Map()"; + fields = iterateObject; + } + } else if (object instanceof Set) { + if (object instanceof object.constructor) { + tag = `Set(${object.size})`; + fields = iterateSet; + } else { // avoid incompatible receiver error for prototype + tag = "Set()"; + fields = iterateObject; + } + } else if (arrayish) { + tag = `${object.constructor.name}(${object.length})`; + fields = iterateArray; + } else if ((n = immutableName(object))) { + tag = `Immutable.${n.name}${n.name === 'Record' ? '' : `(${object.size})`}`; + arrayish = n.arrayish; + fields = n.arrayish ? iterateImArray : n.setish ? iterateImSet : iterateImObject; + } else { + tag = tagof(object); + fields = iterateObject; + } + + if (shallow) { + const span = document.createElement("span"); + span.className = "observablehq--shallow"; + if (name) { + span.appendChild(inspectName(name)); + } + span.appendChild(document.createTextNode(tag)); + span.addEventListener("mouseup", function(event) { + if (hasSelection(span)) return; + event.stopPropagation(); + replace(span, inspectCollapsed(object)); + }); + return span; + } + + const span = document.createElement("span"); + span.className = "observablehq--collapsed"; + if (name) { + span.appendChild(inspectName(name)); + } + const a = span.appendChild(document.createElement("a")); + a.innerHTML = ` + + `; + a.appendChild(document.createTextNode(`${tag}${arrayish ? " [" : " {"}`)); + span.addEventListener("mouseup", function(event) { + if (hasSelection(span)) return; + event.stopPropagation(); + replace(span, inspectExpanded(object, null, name, proto)); + }, true); + + fields = fields(object); + for (let i = 0; !(next = fields.next()).done && i < 20; ++i) { + if (i > 0) span.appendChild(document.createTextNode(", ")); + span.appendChild(next.value); + } + + if (!next.done) span.appendChild(document.createTextNode(", …")); + span.appendChild(document.createTextNode(arrayish ? "]" : "}")); + + return span; +} + +function* iterateMap(map) { + for (const [key, value] of map) { + yield formatMapField(key, value); + } + yield* iterateObject(map); +} + +function* iterateSet(set) { + for (const value of set) { + yield inspect(value, true); + } + yield* iterateObject(set); +} + +function* iterateImSet(set) { + for (const value of set) { + yield inspect(value, true); + } +} + +function* iterateImArray(array) { + let i0 = -1, i1 = 0; + for (const n = array.size; i1 < n; ++i1) { + if (i1 > i0 + 1) yield formatEmpty(i1 - i0 - 1); + yield inspect(array.get(i1), true); + i0 = i1; + } + if (i1 > i0 + 1) yield formatEmpty(i1 - i0 - 1); +} + +function* iterateArray(array) { + let i0 = -1, i1 = 0; + for (const n = array.length; i1 < n; ++i1) { + if (i1 in array) { + if (i1 > i0 + 1) yield formatEmpty(i1 - i0 - 1); + yield inspect(valueof(array, i1), true); + i0 = i1; + } + } + if (i1 > i0 + 1) yield formatEmpty(i1 - i0 - 1); + for (const key in array) { + if (!isindex(key) && isown(array, key)) { + yield formatField(key, valueof(array, key), "observablehq--key"); + } + } + for (const symbol of symbolsof(array)) { + yield formatField(formatSymbol(symbol), valueof(array, symbol), "observablehq--symbol"); + } +} + +function* iterateObject(object) { + for (const key in object) { + if (isown(object, key)) { + yield formatField(key, valueof(object, key), "observablehq--key"); + } + } + for (const symbol of symbolsof(object)) { + yield formatField(formatSymbol(symbol), valueof(object, symbol), "observablehq--symbol"); + } +} + +function* iterateImObject(object) { + for (const [key, value] of object) { + yield formatField(key, value, "observablehq--key"); + } +} + +function formatEmpty(e) { + const span = document.createElement("span"); + span.className = "observablehq--empty"; + span.textContent = e === 1 ? "empty" : `empty × ${e}`; + return span; +} + +function formatField(key, value, className) { + const fragment = document.createDocumentFragment(); + const span = fragment.appendChild(document.createElement("span")); + span.className = className; + span.textContent = key; + fragment.appendChild(document.createTextNode(": ")); + fragment.appendChild(inspect(value, true)); + return fragment; +} + +function formatMapField(key, value) { + const fragment = document.createDocumentFragment(); + fragment.appendChild(inspect(key, true)); + fragment.appendChild(document.createTextNode(" => ")); + fragment.appendChild(inspect(value, true)); + return fragment; +} + +function format(date, fallback) { + if (!(date instanceof Date)) date = new Date(+date); + if (isNaN(date)) return typeof fallback === "function" ? fallback(date) : fallback; + const hours = date.getUTCHours(); + const minutes = date.getUTCMinutes(); + const seconds = date.getUTCSeconds(); + const milliseconds = date.getUTCMilliseconds(); + return `${formatYear(date.getUTCFullYear())}-${pad(date.getUTCMonth() + 1, 2)}-${pad(date.getUTCDate(), 2)}${ + hours || minutes || seconds || milliseconds ? `T${pad(hours, 2)}:${pad(minutes, 2)}${ + seconds || milliseconds ? `:${pad(seconds, 2)}${ + milliseconds ? `.${pad(milliseconds, 3)}` : `` + }` : `` + }Z` : `` + }`; +} + +function formatYear(year) { + return year < 0 ? `-${pad(-year, 6)}` + : year > 9999 ? `+${pad(year, 6)}` + : pad(year, 4); +} + +function pad(value, width) { + return `${value}`.padStart(width, "0"); +} + +function formatDate$1(date) { + return format(date, "Invalid Date"); +} + +var errorToString = Error.prototype.toString; + +function formatError(value) { + return value.stack || errorToString.call(value); +} + +var regExpToString = RegExp.prototype.toString; + +function formatRegExp(value) { + return regExpToString.call(value); +} + +/* eslint-disable no-control-regex */ +const NEWLINE_LIMIT = 20; + +function formatString(string, shallow, expanded, name) { + if (shallow === false) { + // String has fewer escapes displayed with double quotes + if (count(string, /["\n]/g) <= count(string, /`|\${/g)) { + const span = document.createElement("span"); + if (name) span.appendChild(inspectName(name)); + const textValue = span.appendChild(document.createElement("span")); + textValue.className = "observablehq--string"; + textValue.textContent = JSON.stringify(string); + return span; + } + const lines = string.split("\n"); + if (lines.length > NEWLINE_LIMIT && !expanded) { + const div = document.createElement("div"); + if (name) div.appendChild(inspectName(name)); + const textValue = div.appendChild(document.createElement("span")); + textValue.className = "observablehq--string"; + textValue.textContent = "`" + templatify(lines.slice(0, NEWLINE_LIMIT).join("\n")); + const splitter = div.appendChild(document.createElement("span")); + const truncatedCount = lines.length - NEWLINE_LIMIT; + splitter.textContent = `Show ${truncatedCount} truncated line${truncatedCount > 1 ? "s": ""}`; splitter.className = "observablehq--string-expand"; + splitter.addEventListener("mouseup", function (event) { + event.stopPropagation(); + replace(div, inspect(string, shallow, true, name)); + }); + return div; + } + const span = document.createElement("span"); + if (name) span.appendChild(inspectName(name)); + const textValue = span.appendChild(document.createElement("span")); + textValue.className = `observablehq--string${expanded ? " observablehq--expanded" : ""}`; + textValue.textContent = "`" + templatify(string) + "`"; + return span; + } + + const span = document.createElement("span"); + if (name) span.appendChild(inspectName(name)); + const textValue = span.appendChild(document.createElement("span")); + textValue.className = "observablehq--string"; + textValue.textContent = JSON.stringify(string.length > 100 ? + `${string.slice(0, 50)}…${string.slice(-49)}` : string); + return span; +} + +function templatify(string) { + return string.replace(/[\\`\x00-\x09\x0b-\x19]|\${/g, templatifyChar); +} + +function templatifyChar(char) { + var code = char.charCodeAt(0); + switch (code) { + case 0x8: return "\\b"; + case 0x9: return "\\t"; + case 0xb: return "\\v"; + case 0xc: return "\\f"; + case 0xd: return "\\r"; + } + return code < 0x10 ? "\\x0" + code.toString(16) + : code < 0x20 ? "\\x" + code.toString(16) + : "\\" + char; +} + +function count(string, re) { + var n = 0; + while (re.exec(string)) ++n; + return n; +} + +var toString$2 = Function.prototype.toString, + TYPE_ASYNC = {prefix: "async ƒ"}, + TYPE_ASYNC_GENERATOR = {prefix: "async ƒ*"}, + TYPE_CLASS = {prefix: "class"}, + TYPE_FUNCTION = {prefix: "ƒ"}, + TYPE_GENERATOR = {prefix: "ƒ*"}; + +function inspectFunction(f, name) { + var type, m, t = toString$2.call(f); + + switch (f.constructor && f.constructor.name) { + case "AsyncFunction": type = TYPE_ASYNC; break; + case "AsyncGeneratorFunction": type = TYPE_ASYNC_GENERATOR; break; + case "GeneratorFunction": type = TYPE_GENERATOR; break; + default: type = /^class\b/.test(t) ? TYPE_CLASS : TYPE_FUNCTION; break; + } + + // A class, possibly named. + // class Name + if (type === TYPE_CLASS) { + return formatFunction(type, "", name); + } + + // An arrow function with a single argument. + // foo => + // async foo => + if ((m = /^(?:async\s*)?(\w+)\s*=>/.exec(t))) { + return formatFunction(type, "(" + m[1] + ")", name); + } + + // An arrow function with parenthesized arguments. + // (…) + // async (…) + if ((m = /^(?:async\s*)?\(\s*(\w+(?:\s*,\s*\w+)*)?\s*\)/.exec(t))) { + return formatFunction(type, m[1] ? "(" + m[1].replace(/\s*,\s*/g, ", ") + ")" : "()", name); + } + + // A function, possibly: async, generator, anonymous, simply arguments. + // function name(…) + // function* name(…) + // async function name(…) + // async function* name(…) + if ((m = /^(?:async\s*)?function(?:\s*\*)?(?:\s*\w+)?\s*\(\s*(\w+(?:\s*,\s*\w+)*)?\s*\)/.exec(t))) { + return formatFunction(type, m[1] ? "(" + m[1].replace(/\s*,\s*/g, ", ") + ")" : "()", name); + } + + // Something else, like destructuring, comments or default values. + return formatFunction(type, "(…)", name); +} + +function formatFunction(type, args, cellname) { + var span = document.createElement("span"); + span.className = "observablehq--function"; + if (cellname) { + span.appendChild(inspectName(cellname)); + } + var spanType = span.appendChild(document.createElement("span")); + spanType.className = "observablehq--keyword"; + spanType.textContent = type.prefix; + span.appendChild(document.createTextNode(args)); + return span; +} + +const {prototype: {toString: toString$1}} = Object; + +function inspect(value, shallow, expand, name, proto) { + let type = typeof value; + switch (type) { + case "boolean": + case "undefined": { value += ""; break; } + case "number": { value = value === 0 && 1 / value < 0 ? "-0" : value + ""; break; } + case "bigint": { value = value + "n"; break; } + case "symbol": { value = formatSymbol(value); break; } + case "function": { return inspectFunction(value, name); } + case "string": { return formatString(value, shallow, expand, name); } + default: { + if (value === null) { type = null, value = "null"; break; } + if (value instanceof Date) { type = "date", value = formatDate$1(value); break; } + if (value === FORBIDDEN) { type = "forbidden", value = "[forbidden]"; break; } + switch (toString$1.call(value)) { + case "[object RegExp]": { type = "regexp", value = formatRegExp(value); break; } + case "[object Error]": // https://github.com/lodash/lodash/blob/master/isError.js#L26 + case "[object DOMException]": { type = "error", value = formatError(value); break; } + default: return (expand ? inspectExpanded : inspectCollapsed)(value, shallow, name, proto); + } + break; + } + } + const span = document.createElement("span"); + if (name) span.appendChild(inspectName(name)); + const n = span.appendChild(document.createElement("span")); + n.className = `observablehq--${type}`; + n.textContent = value; + return span; +} + +function replace(spanOld, spanNew) { + if (spanOld.classList.contains("observablehq--inspect")) spanNew.classList.add("observablehq--inspect"); + spanOld.parentNode.replaceChild(spanNew, spanOld); + dispatch(spanNew, "load"); +} + +const LOCATION_MATCH = /\s+\(\d+:\d+\)$/m; + +class Inspector { + constructor(node) { + if (!node) throw new Error("invalid node"); + this._node = node; + node.classList.add("observablehq"); + } + pending() { + const {_node} = this; + _node.classList.remove("observablehq--error"); + _node.classList.add("observablehq--running"); + } + fulfilled(value, name) { + const {_node} = this; + if (!isnode(value) || (value.parentNode && value.parentNode !== _node)) { + value = inspect(value, false, _node.firstChild // TODO Do this better. + && _node.firstChild.classList + && _node.firstChild.classList.contains("observablehq--expanded"), name); + value.classList.add("observablehq--inspect"); + } + _node.classList.remove("observablehq--running", "observablehq--error"); + if (_node.firstChild !== value) { + if (_node.firstChild) { + while (_node.lastChild !== _node.firstChild) _node.removeChild(_node.lastChild); + _node.replaceChild(value, _node.firstChild); + } else { + _node.appendChild(value); + } + } + dispatch(_node, "update"); + } + rejected(error, name) { + const {_node} = this; + _node.classList.remove("observablehq--running"); + _node.classList.add("observablehq--error"); + while (_node.lastChild) _node.removeChild(_node.lastChild); + var div = document.createElement("div"); + div.className = "observablehq--inspect"; + if (name) div.appendChild(inspectName(name)); + div.appendChild(document.createTextNode((error + "").replace(LOCATION_MATCH, ""))); + _node.appendChild(div); + dispatch(_node, "error", {error: error}); + } +} + +Inspector.into = function(container) { + if (typeof container === "string") { + container = document.querySelector(container); + if (container == null) throw new Error("container not found"); + } + return function() { + return new Inspector(container.appendChild(document.createElement("div"))); + }; +}; + +// Returns true if the given value is something that should be added to the DOM +// by the inspector, rather than being inspected. This deliberately excludes +// DocumentFragment since appending a fragment “dissolves” (mutates) the +// fragment, and we wish for the inspector to not have side-effects. Also, +// HTMLElement.prototype is an instanceof Element, but not an element! +function isnode(value) { + return (value instanceof Element || value instanceof Text) + && (value instanceof value.constructor); +} + +class RuntimeError extends Error { + constructor(message, input) { + super(message); + this.input = input; + } +} + +RuntimeError.prototype.name = "RuntimeError"; + +function generatorish(value) { + return value + && typeof value.next === "function" + && typeof value.return === "function"; +} + +function load(notebook, library, observer) { + if (typeof library == "function") observer = library, library = null; + if (typeof observer !== "function") throw new Error("invalid observer"); + if (library == null) library = new Library(); + + const {modules, id} = notebook; + const map = new Map; + const runtime = new Runtime(library); + const main = runtime_module(id); + + function runtime_module(id) { + let module = map.get(id); + if (!module) map.set(id, module = runtime.module()); + return module; + } + + for (const m of modules) { + const module = runtime_module(m.id); + let i = 0; + for (const v of m.variables) { + if (v.from) module.import(v.remote, v.name, runtime_module(v.from)); + else if (module === main) module.variable(observer(v, i, m.variables)).define(v.name, v.inputs, v.value); + else module.define(v.name, v.inputs, v.value); + ++i; + } + } + + return runtime; +} + +function constant(x) { + return () => x; +} + +function identity$1(x) { + return x; +} + +function rethrow(error) { + return () => { + throw error; + }; +} + +const prototype = Array.prototype; +const map = prototype.map; + +function noop() {} + +const TYPE_NORMAL = 1; // a normal variable +const TYPE_IMPLICIT = 2; // created on reference +const TYPE_DUPLICATE = 3; // created on duplicate definition + +const no_observer = Symbol("no-observer"); + +function Variable(type, module, observer) { + if (!observer) observer = no_observer; + Object.defineProperties(this, { + _observer: {value: observer, writable: true}, + _definition: {value: variable_undefined, writable: true}, + _duplicate: {value: undefined, writable: true}, + _duplicates: {value: undefined, writable: true}, + _indegree: {value: NaN, writable: true}, // The number of computing inputs. + _inputs: {value: [], writable: true}, + _invalidate: {value: noop, writable: true}, + _module: {value: module}, + _name: {value: null, writable: true}, + _outputs: {value: new Set, writable: true}, + _promise: {value: Promise.resolve(undefined), writable: true}, + _reachable: {value: observer !== no_observer, writable: true}, // Is this variable transitively visible? + _rejector: {value: variable_rejector(this)}, + _type: {value: type}, + _value: {value: undefined, writable: true}, + _version: {value: 0, writable: true} + }); +} + +Object.defineProperties(Variable.prototype, { + _pending: {value: variable_pending, writable: true, configurable: true}, + _fulfilled: {value: variable_fulfilled, writable: true, configurable: true}, + _rejected: {value: variable_rejected, writable: true, configurable: true}, + define: {value: variable_define, writable: true, configurable: true}, + delete: {value: variable_delete, writable: true, configurable: true}, + import: {value: variable_import, writable: true, configurable: true} +}); + +function variable_attach(variable) { + variable._module._runtime._dirty.add(variable); + variable._outputs.add(this); +} + +function variable_detach(variable) { + variable._module._runtime._dirty.add(variable); + variable._outputs.delete(this); +} + +function variable_undefined() { + throw variable_undefined; +} + +function variable_stale() { + throw variable_stale; +} + +function variable_rejector(variable) { + return (error) => { + if (error === variable_stale) throw error; + if (error === variable_undefined) throw new RuntimeError(`${variable._name} is not defined`, variable._name); + if (error instanceof Error && error.message) throw new RuntimeError(error.message, variable._name); + throw new RuntimeError(`${variable._name} could not be resolved`, variable._name); + }; +} + +function variable_duplicate(name) { + return () => { + throw new RuntimeError(`${name} is defined more than once`); + }; +} + +function variable_define(name, inputs, definition) { + switch (arguments.length) { + case 1: { + definition = name, name = inputs = null; + break; + } + case 2: { + definition = inputs; + if (typeof name === "string") inputs = null; + else inputs = name, name = null; + break; + } + } + return variable_defineImpl.call(this, + name == null ? null : String(name), + inputs == null ? [] : map.call(inputs, this._module._resolve, this._module), + typeof definition === "function" ? definition : constant(definition) + ); +} + +function variable_defineImpl(name, inputs, definition) { + const scope = this._module._scope, runtime = this._module._runtime; + + this._inputs.forEach(variable_detach, this); + inputs.forEach(variable_attach, this); + this._inputs = inputs; + this._definition = definition; + this._value = undefined; + + // Is this an active variable (that may require disposal)? + if (definition === noop) runtime._variables.delete(this); + else runtime._variables.add(this); + + // Did the variable’s name change? Time to patch references! + if (name !== this._name || scope.get(name) !== this) { + let error, found; + + if (this._name) { // Did this variable previously have a name? + if (this._outputs.size) { // And did other variables reference this variable? + scope.delete(this._name); + found = this._module._resolve(this._name); + found._outputs = this._outputs, this._outputs = new Set; + found._outputs.forEach(function(output) { output._inputs[output._inputs.indexOf(this)] = found; }, this); + found._outputs.forEach(runtime._updates.add, runtime._updates); + runtime._dirty.add(found).add(this); + scope.set(this._name, found); + } else if ((found = scope.get(this._name)) === this) { // Do no other variables reference this variable? + scope.delete(this._name); // It’s safe to delete! + } else if (found._type === TYPE_DUPLICATE) { // Do other variables assign this name? + found._duplicates.delete(this); // This variable no longer assigns this name. + this._duplicate = undefined; + if (found._duplicates.size === 1) { // Is there now only one variable assigning this name? + found = found._duplicates.keys().next().value; // Any references are now fixed! + error = scope.get(this._name); + found._outputs = error._outputs, error._outputs = new Set; + found._outputs.forEach(function(output) { output._inputs[output._inputs.indexOf(error)] = found; }); + found._definition = found._duplicate, found._duplicate = undefined; + runtime._dirty.add(error).add(found); + runtime._updates.add(found); + scope.set(this._name, found); + } + } else { + throw new Error; + } + } + + if (this._outputs.size) throw new Error; + + if (name) { // Does this variable have a new name? + if (found = scope.get(name)) { // Do other variables reference or assign this name? + if (found._type === TYPE_DUPLICATE) { // Do multiple other variables already define this name? + this._definition = variable_duplicate(name), this._duplicate = definition; + found._duplicates.add(this); + } else if (found._type === TYPE_IMPLICIT) { // Are the variable references broken? + this._outputs = found._outputs, found._outputs = new Set; // Now they’re fixed! + this._outputs.forEach(function(output) { output._inputs[output._inputs.indexOf(found)] = this; }, this); + runtime._dirty.add(found).add(this); + scope.set(name, this); + } else { // Does another variable define this name? + found._duplicate = found._definition, this._duplicate = definition; // Now they’re duplicates. + error = new Variable(TYPE_DUPLICATE, this._module); + error._name = name; + error._definition = this._definition = found._definition = variable_duplicate(name); + error._outputs = found._outputs, found._outputs = new Set; + error._outputs.forEach(function(output) { output._inputs[output._inputs.indexOf(found)] = error; }); + error._duplicates = new Set([this, found]); + runtime._dirty.add(found).add(error); + runtime._updates.add(found).add(error); + scope.set(name, error); + } + } else { + scope.set(name, this); + } + } + + this._name = name; + } + + // If this redefined variable was previously evaluated, invalidate it. (If the + // variable was never evaluated, then the invalidated value could never have + // been exposed and we can avoid this extra work.) + if (this._version > 0) ++this._version; + + runtime._updates.add(this); + runtime._compute(); + return this; +} + +function variable_import(remote, name, module) { + if (arguments.length < 3) module = name, name = remote; + return variable_defineImpl.call(this, String(name), [module._resolve(String(remote))], identity$1); +} + +function variable_delete() { + return variable_defineImpl.call(this, null, [], noop); +} + +function variable_pending() { + if (this._observer.pending) this._observer.pending(); +} + +function variable_fulfilled(value) { + if (this._observer.fulfilled) this._observer.fulfilled(value, this._name); +} + +function variable_rejected(error) { + if (this._observer.rejected) this._observer.rejected(error, this._name); +} + +const variable_variable = Symbol("variable"); +const variable_invalidation = Symbol("invalidation"); +const variable_visibility = Symbol("visibility"); + +function Module(runtime, builtins = []) { + Object.defineProperties(this, { + _runtime: {value: runtime}, + _scope: {value: new Map}, + _builtins: {value: new Map([ + ["@variable", variable_variable], + ["invalidation", variable_invalidation], + ["visibility", variable_visibility], + ...builtins + ])}, + _source: {value: null, writable: true} + }); +} + +Object.defineProperties(Module.prototype, { + _resolve: {value: module_resolve, writable: true, configurable: true}, + redefine: {value: module_redefine, writable: true, configurable: true}, + define: {value: module_define, writable: true, configurable: true}, + derive: {value: module_derive, writable: true, configurable: true}, + import: {value: module_import, writable: true, configurable: true}, + value: {value: module_value, writable: true, configurable: true}, + variable: {value: module_variable, writable: true, configurable: true}, + builtin: {value: module_builtin, writable: true, configurable: true} +}); + +function module_redefine(name) { + const v = this._scope.get(name); + if (!v) throw new RuntimeError(`${name} is not defined`); + if (v._type === TYPE_DUPLICATE) throw new RuntimeError(`${name} is defined more than once`); + return v.define.apply(v, arguments); +} + +function module_define() { + const v = new Variable(TYPE_NORMAL, this); + return v.define.apply(v, arguments); +} + +function module_import() { + const v = new Variable(TYPE_NORMAL, this); + return v.import.apply(v, arguments); +} + +function module_variable(observer) { + return new Variable(TYPE_NORMAL, this, observer); +} + +async function module_value(name) { + let v = this._scope.get(name); + if (!v) throw new RuntimeError(`${name} is not defined`); + if (v._observer === no_observer) { + v = this.variable(true).define([name], identity$1); + try { + return await module_revalue(this._runtime, v); + } finally { + v.delete(); + } + } else { + return module_revalue(this._runtime, v); + } +} + +// If the variable is redefined before its value resolves, try again. +async function module_revalue(runtime, variable) { + await runtime._compute(); + try { + return await variable._promise; + } catch (error) { + if (error === variable_stale) return module_revalue(runtime, variable); + throw error; + } +} + +function module_derive(injects, injectModule) { + const map = new Map(); + const modules = new Set(); + const copies = []; + + // Given a module, derives an alias of that module with an initially-empty + // definition. The variables will be copied later in a second pass below. + function alias(source) { + let target = map.get(source); + if (target) return target; + target = new Module(source._runtime, source._builtins); + target._source = source; + map.set(source, target); + copies.push([target, source]); + modules.add(source); + return target; + } + + // Inject the given variables as reverse imports into the derived module. + const derive = alias(this); + for (const inject of injects) { + const {alias, name} = typeof inject === "object" ? inject : {name: inject}; + derive.import(name, alias == null ? name : alias, injectModule); + } + + // Iterate over all the variables (currently) in this module. If any + // represents an import-with (i.e., an import of a module with a _source), the + // transitive import-with must be copied, too, as direct injections may affect + // transitive injections. Note that an import-with can only be created with + // module.derive and hence it’s not possible for an import-with to be added + // later; therefore we only need to apply this check once, now. + for (const module of modules) { + for (const [name, variable] of module._scope) { + if (variable._definition === identity$1) { // import + if (module === this && derive._scope.has(name)) continue; // overridden by injection + const importedModule = variable._inputs[0]._module; + if (importedModule._source) alias(importedModule); + } + } + } + + // Finally, with the modules resolved, copy the variable definitions. + for (const [target, source] of copies) { + for (const [name, sourceVariable] of source._scope) { + const targetVariable = target._scope.get(name); + if (targetVariable && targetVariable._type !== TYPE_IMPLICIT) continue; // preserve injection + if (sourceVariable._definition === identity$1) { // import + const sourceInput = sourceVariable._inputs[0]; + const sourceModule = sourceInput._module; + target.import(sourceInput._name, name, map.get(sourceModule) || sourceModule); + } else { // non-import + target.define(name, sourceVariable._inputs.map(variable_name), sourceVariable._definition); + } + } + } + + return derive; +} + +function module_resolve(name) { + let variable = this._scope.get(name), value; + if (!variable) { + variable = new Variable(TYPE_IMPLICIT, this); + if (this._builtins.has(name)) { + variable.define(name, constant(this._builtins.get(name))); + } else if (this._runtime._builtin._scope.has(name)) { + variable.import(name, this._runtime._builtin); + } else { + try { + value = this._runtime._global(name); + } catch (error) { + return variable.define(name, rethrow(error)); + } + if (value === undefined) { + this._scope.set(variable._name = name, variable); + } else { + variable.define(name, constant(value)); + } + } + } + return variable; +} + +function module_builtin(name, value) { + this._builtins.set(name, value); +} + +function variable_name(variable) { + return variable._name; +} + +const frame = typeof requestAnimationFrame === "function" ? requestAnimationFrame + : typeof setImmediate === "function" ? setImmediate + : f => setTimeout(f, 0); + +function Runtime(builtins = new Library, global = window_global) { + const builtin = this.module(); + Object.defineProperties(this, { + _dirty: {value: new Set}, + _updates: {value: new Set}, + _precomputes: {value: [], writable: true}, + _computing: {value: null, writable: true}, + _init: {value: null, writable: true}, + _modules: {value: new Map}, + _variables: {value: new Set}, + _disposed: {value: false, writable: true}, + _builtin: {value: builtin}, + _global: {value: global} + }); + if (builtins) for (const name in builtins) { + (new Variable(TYPE_IMPLICIT, builtin)).define(name, [], builtins[name]); + } +} + +Object.defineProperties(Runtime.prototype, { + _precompute: {value: runtime_precompute, writable: true, configurable: true}, + _compute: {value: runtime_compute, writable: true, configurable: true}, + _computeSoon: {value: runtime_computeSoon, writable: true, configurable: true}, + _computeNow: {value: runtime_computeNow, writable: true, configurable: true}, + dispose: {value: runtime_dispose, writable: true, configurable: true}, + module: {value: runtime_module, writable: true, configurable: true}, + fileAttachments: {value: FileAttachments, writable: true, configurable: true}, + load: {value: load, writable: true, configurable: true} +}); + +function runtime_dispose() { + this._computing = Promise.resolve(); + this._disposed = true; + this._variables.forEach(v => { + v._invalidate(); + v._version = NaN; + }); +} + +function runtime_module(define, observer = noop) { + let module; + if (define === undefined) { + if (module = this._init) { + this._init = null; + return module; + } + return new Module(this); + } + module = this._modules.get(define); + if (module) return module; + this._init = module = new Module(this); + this._modules.set(define, module); + try { + define(this, observer); + } finally { + this._init = null; + } + return module; +} + +function runtime_precompute(callback) { + this._precomputes.push(callback); + this._compute(); +} + +function runtime_compute() { + return this._computing || (this._computing = this._computeSoon()); +} + +function runtime_computeSoon() { + return new Promise(frame).then(() => this._disposed ? undefined : this._computeNow()); +} + +async function runtime_computeNow() { + let queue = [], + variables, + variable, + precomputes = this._precomputes; + + // If there are any paused generators, resume them before computing so they + // can update (if synchronous) before computing downstream variables. + if (precomputes.length) { + this._precomputes = []; + for (const callback of precomputes) callback(); + await runtime_defer(3); + } + + // Compute the reachability of the transitive closure of dirty variables. + // Any newly-reachable variable must also be recomputed. + // Any no-longer-reachable variable must be terminated. + variables = new Set(this._dirty); + variables.forEach(function(variable) { + variable._inputs.forEach(variables.add, variables); + const reachable = variable_reachable(variable); + if (reachable > variable._reachable) { + this._updates.add(variable); + } else if (reachable < variable._reachable) { + variable._invalidate(); + } + variable._reachable = reachable; + }, this); + + // Compute the transitive closure of updating, reachable variables. + variables = new Set(this._updates); + variables.forEach(function(variable) { + if (variable._reachable) { + variable._indegree = 0; + variable._outputs.forEach(variables.add, variables); + } else { + variable._indegree = NaN; + variables.delete(variable); + } + }); + + this._computing = null; + this._updates.clear(); + this._dirty.clear(); + + // Compute the indegree of updating variables. + variables.forEach(function(variable) { + variable._outputs.forEach(variable_increment); + }); + + do { + // Identify the root variables (those with no updating inputs). + variables.forEach(function(variable) { + if (variable._indegree === 0) { + queue.push(variable); + } + }); + + // Compute the variables in topological order. + while (variable = queue.pop()) { + variable_compute(variable); + variable._outputs.forEach(postqueue); + variables.delete(variable); + } + + // Any remaining variables are circular, or depend on them. + variables.forEach(function(variable) { + if (variable_circular(variable)) { + variable_error(variable, new RuntimeError("circular definition")); + variable._outputs.forEach(variable_decrement); + variables.delete(variable); + } + }); + } while (variables.size); + + function postqueue(variable) { + if (--variable._indegree === 0) { + queue.push(variable); + } + } +} + +// We want to give generators, if they’re defined synchronously, a chance to +// update before computing downstream variables. This creates a synchronous +// promise chain of the given depth that we’ll await before recomputing +// downstream variables. +function runtime_defer(depth = 0) { + let p = Promise.resolve(); + for (let i = 0; i < depth; ++i) p = p.then(() => {}); + return p; +} + +function variable_circular(variable) { + const inputs = new Set(variable._inputs); + for (const i of inputs) { + if (i === variable) return true; + i._inputs.forEach(inputs.add, inputs); + } + return false; +} + +function variable_increment(variable) { + ++variable._indegree; +} + +function variable_decrement(variable) { + --variable._indegree; +} + +function variable_value(variable) { + return variable._promise.catch(variable._rejector); +} + +function variable_invalidator(variable) { + return new Promise(function(resolve) { + variable._invalidate = resolve; + }); +} + +function variable_intersector(invalidation, variable) { + let node = typeof IntersectionObserver === "function" && variable._observer && variable._observer._node; + let visible = !node, resolve = noop, reject = noop, promise, observer; + if (node) { + observer = new IntersectionObserver(([entry]) => (visible = entry.isIntersecting) && (promise = null, resolve())); + observer.observe(node); + invalidation.then(() => (observer.disconnect(), observer = null, reject())); + } + return function(value) { + if (visible) return Promise.resolve(value); + if (!observer) return Promise.reject(); + if (!promise) promise = new Promise((y, n) => (resolve = y, reject = n)); + return promise.then(() => value); + }; +} + +function variable_compute(variable) { + variable._invalidate(); + variable._invalidate = noop; + variable._pending(); + + const value0 = variable._value; + const version = ++variable._version; + + // Lazily-constructed invalidation variable; only constructed if referenced as an input. + let invalidation = null; + + // If the variable doesn’t have any inputs, we can optimize slightly. + const promise = variable._promise = (variable._inputs.length + ? Promise.all(variable._inputs.map(variable_value)).then(define) + : new Promise(resolve => resolve(variable._definition.call(value0)))) + .then(generate); + + // Compute the initial value of the variable. + function define(inputs) { + if (variable._version !== version) throw variable_stale; + + // Replace any reference to invalidation with the promise, lazily. + for (let i = 0, n = inputs.length; i < n; ++i) { + switch (inputs[i]) { + case variable_invalidation: { + inputs[i] = invalidation = variable_invalidator(variable); + break; + } + case variable_visibility: { + if (!invalidation) invalidation = variable_invalidator(variable); + inputs[i] = variable_intersector(invalidation, variable); + break; + } + case variable_variable: { + inputs[i] = variable; + break; + } + } + } + + return variable._definition.apply(value0, inputs); + } + + // If the value is a generator, then retrieve its first value, and dispose of + // the generator if the variable is invalidated. Note that the cell may + // already have been invalidated here, in which case we need to terminate the + // generator immediately! + function generate(value) { + if (variable._version !== version) throw variable_stale; + if (generatorish(value)) { + (invalidation || variable_invalidator(variable)).then(variable_return(value)); + return variable_generate(variable, version, value); + } + return value; + } + + promise.then((value) => { + variable._value = value; + variable._fulfilled(value); + }, (error) => { + if (error === variable_stale) return; + variable._value = undefined; + variable._rejected(error); + }); +} + +function variable_generate(variable, version, generator) { + const runtime = variable._module._runtime; + let currentValue; // so that yield resolves to the yielded value + + // Retrieve the next value from the generator; if successful, invoke the + // specified callback. The returned promise resolves to the yielded value, or + // to undefined if the generator is done. + function compute(onfulfilled) { + return new Promise(resolve => resolve(generator.next(currentValue))).then(({done, value}) => { + return done ? undefined : Promise.resolve(value).then(onfulfilled); + }); + } + + // Retrieve the next value from the generator; if successful, fulfill the + // variable, compute downstream variables, and schedule the next value to be + // pulled from the generator at the start of the next animation frame. If not + // successful, reject the variable, compute downstream variables, and return. + function recompute() { + const promise = compute((value) => { + if (variable._version !== version) throw variable_stale; + currentValue = value; + postcompute(value, promise).then(() => runtime._precompute(recompute)); + variable._fulfilled(value); + return value; + }); + promise.catch((error) => { + if (error === variable_stale || variable._version !== version) return; + postcompute(undefined, promise); + variable._rejected(error); + }); + } + + // After the generator fulfills or rejects, set its current value, promise, + // and schedule any downstream variables for update. + function postcompute(value, promise) { + variable._value = value; + variable._promise = promise; + variable._outputs.forEach(runtime._updates.add, runtime._updates); + return runtime._compute(); + } + + // When retrieving the first value from the generator, the promise graph is + // already established, so we only need to queue the next pull. + return compute((value) => { + if (variable._version !== version) throw variable_stale; + currentValue = value; + runtime._precompute(recompute); + return value; + }); +} + +function variable_error(variable, error) { + variable._invalidate(); + variable._invalidate = noop; + variable._pending(); + ++variable._version; + variable._indegree = NaN; + (variable._promise = Promise.reject(error)).catch(noop); + variable._value = undefined; + variable._rejected(error); +} + +function variable_return(generator) { + return function() { + generator.return(); + }; +} + +function variable_reachable(variable) { + if (variable._observer !== no_observer) return true; // Directly reachable. + const outputs = new Set(variable._outputs); + for (const output of outputs) { + if (output._observer !== no_observer) return true; + output._outputs.forEach(outputs.add, outputs); + } + return false; +} + +function window_global(name) { + return globalThis[name]; +} + +function renderHtml(string) { + const template = document.createElement("template"); + template.innerHTML = string; + return document.importNode(template.content, true); +} + +function renderSvg(string) { + const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); + g.innerHTML = string; + return g; +} + +const html = Object.assign(hypertext(renderHtml, fragment => { + if (fragment.firstChild === null) return null; + if (fragment.firstChild === fragment.lastChild) return fragment.removeChild(fragment.firstChild); + const span = document.createElement("span"); + span.appendChild(fragment); + return span; +}), {fragment: hypertext(renderHtml, fragment => fragment)}); + +Object.assign(hypertext(renderSvg, g => { + if (g.firstChild === null) return null; + if (g.firstChild === g.lastChild) return g.removeChild(g.firstChild); + return g; +}), {fragment: hypertext(renderSvg, g => { + const fragment = document.createDocumentFragment(); + while (g.firstChild) fragment.appendChild(g.firstChild); + return fragment; +})}); + +const +CODE_TAB = 9, +CODE_LF = 10, +CODE_FF = 12, +CODE_CR = 13, +CODE_SPACE = 32, +CODE_UPPER_A = 65, +CODE_UPPER_Z = 90, +CODE_LOWER_A = 97, +CODE_LOWER_Z = 122, +CODE_LT = 60, +CODE_GT = 62, +CODE_SLASH = 47, +CODE_DASH = 45, +CODE_BANG = 33, +CODE_EQ = 61, +CODE_DQUOTE = 34, +CODE_SQUOTE = 39, +CODE_QUESTION = 63, +STATE_DATA = 1, +STATE_TAG_OPEN = 2, +STATE_END_TAG_OPEN = 3, +STATE_TAG_NAME = 4, +STATE_BOGUS_COMMENT = 5, +STATE_BEFORE_ATTRIBUTE_NAME = 6, +STATE_AFTER_ATTRIBUTE_NAME = 7, +STATE_ATTRIBUTE_NAME = 8, +STATE_BEFORE_ATTRIBUTE_VALUE = 9, +STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED = 10, +STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED = 11, +STATE_ATTRIBUTE_VALUE_UNQUOTED = 12, +STATE_AFTER_ATTRIBUTE_VALUE_QUOTED = 13, +STATE_SELF_CLOSING_START_TAG = 14, +STATE_COMMENT_START = 15, +STATE_COMMENT_START_DASH = 16, +STATE_COMMENT = 17, +STATE_COMMENT_LESS_THAN_SIGN = 18, +STATE_COMMENT_LESS_THAN_SIGN_BANG = 19, +STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH = 20, +STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH = 21, +STATE_COMMENT_END_DASH = 22, +STATE_COMMENT_END = 23, +STATE_COMMENT_END_BANG = 24, +STATE_MARKUP_DECLARATION_OPEN = 25, +STATE_RAWTEXT = 26, +STATE_RAWTEXT_LESS_THAN_SIGN = 27, +STATE_RAWTEXT_END_TAG_OPEN = 28, +STATE_RAWTEXT_END_TAG_NAME = 29, +SHOW_COMMENT = 128, +SHOW_ELEMENT = 1, +TYPE_COMMENT = 8, +TYPE_ELEMENT = 1, +NS_SVG = "http://www.w3.org/2000/svg", +NS_XLINK = "http://www.w3.org/1999/xlink", +NS_XML = "http://www.w3.org/XML/1998/namespace", +NS_XMLNS = "http://www.w3.org/2000/xmlns/"; + +const svgAdjustAttributes = new Map([ + "attributeName", + "attributeType", + "baseFrequency", + "baseProfile", + "calcMode", + "clipPathUnits", + "diffuseConstant", + "edgeMode", + "filterUnits", + "glyphRef", + "gradientTransform", + "gradientUnits", + "kernelMatrix", + "kernelUnitLength", + "keyPoints", + "keySplines", + "keyTimes", + "lengthAdjust", + "limitingConeAngle", + "markerHeight", + "markerUnits", + "markerWidth", + "maskContentUnits", + "maskUnits", + "numOctaves", + "pathLength", + "patternContentUnits", + "patternTransform", + "patternUnits", + "pointsAtX", + "pointsAtY", + "pointsAtZ", + "preserveAlpha", + "preserveAspectRatio", + "primitiveUnits", + "refX", + "refY", + "repeatCount", + "repeatDur", + "requiredExtensions", + "requiredFeatures", + "specularConstant", + "specularExponent", + "spreadMethod", + "startOffset", + "stdDeviation", + "stitchTiles", + "surfaceScale", + "systemLanguage", + "tableValues", + "targetX", + "targetY", + "textLength", + "viewBox", + "viewTarget", + "xChannelSelector", + "yChannelSelector", + "zoomAndPan" +].map(name => [name.toLowerCase(), name])); + +const svgForeignAttributes = new Map([ + ["xlink:actuate", NS_XLINK], + ["xlink:arcrole", NS_XLINK], + ["xlink:href", NS_XLINK], + ["xlink:role", NS_XLINK], + ["xlink:show", NS_XLINK], + ["xlink:title", NS_XLINK], + ["xlink:type", NS_XLINK], + ["xml:lang", NS_XML], + ["xml:space", NS_XML], + ["xmlns", NS_XMLNS], + ["xmlns:xlink", NS_XMLNS] +]); + +function hypertext(render, postprocess) { + return function({raw: strings}) { + let state = STATE_DATA; + let string = ""; + let tagNameStart; // either an open tag or an end tag + let tagName; // only open; beware nesting! used only for rawtext + let attributeNameStart; + let attributeNameEnd; + let nodeFilter = 0; + + for (let j = 0, m = arguments.length; j < m; ++j) { + const input = strings[j]; + + if (j > 0) { + const value = arguments[j]; + switch (state) { + case STATE_RAWTEXT: { + if (value != null) { + const text = `${value}`; + if (isEscapableRawText(tagName)) { + string += text.replace(/[<]/g, entity); + } else if (new RegExp(`/]`, "i").test(string.slice(-tagName.length - 2) + text)) { + throw new Error("unsafe raw text"); // appropriate end tag + } else { + string += text; + } + } + break; + } + case STATE_DATA: { + if (value == null) ; else if (value instanceof Node + || (typeof value !== "string" && value[Symbol.iterator]) + || (/(?:^|>)$/.test(strings[j - 1]) && /^(?:<|$)/.test(input))) { + string += ""; + nodeFilter |= SHOW_COMMENT; + } else { + string += `${value}`.replace(/[<&]/g, entity); + } + break; + } + case STATE_BEFORE_ATTRIBUTE_VALUE: { + state = STATE_ATTRIBUTE_VALUE_UNQUOTED; + let text; + if (/^[\s>]/.test(input)) { + if (value == null || value === false) { + string = string.slice(0, attributeNameStart - strings[j - 1].length); + break; + } + if (value === true || (text = `${value}`) === "") { + string += "''"; + break; + } + const name = strings[j - 1].slice(attributeNameStart, attributeNameEnd); + if ((name === "style" && isObjectLiteral(value)) || typeof value === "function") { + string += "::" + j; + nodeFilter |= SHOW_ELEMENT; + break; + } + } + if (text === undefined) text = `${value}`; + if (text === "") throw new Error("unsafe unquoted empty string"); + string += text.replace(/^['"]|[\s>&]/g, entity); + break; + } + case STATE_ATTRIBUTE_VALUE_UNQUOTED: { + string += `${value}`.replace(/[\s>&]/g, entity); + break; + } + case STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED: { + string += `${value}`.replace(/['&]/g, entity); + break; + } + case STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED: { + string += `${value}`.replace(/["&]/g, entity); + break; + } + case STATE_BEFORE_ATTRIBUTE_NAME: { + if (isObjectLiteral(value)) { + string += "::" + j + "=''"; + nodeFilter |= SHOW_ELEMENT; + break; + } + throw new Error("invalid binding"); + } + case STATE_COMMENT: break; + default: throw new Error("invalid binding"); + } + } + + for (let i = 0, n = input.length; i < n; ++i) { + const code = input.charCodeAt(i); + + switch (state) { + case STATE_DATA: { + if (code === CODE_LT) { + state = STATE_TAG_OPEN; + } + break; + } + case STATE_TAG_OPEN: { + if (code === CODE_BANG) { + state = STATE_MARKUP_DECLARATION_OPEN; + } else if (code === CODE_SLASH) { + state = STATE_END_TAG_OPEN; + } else if (isAsciiAlphaCode(code)) { + tagNameStart = i, tagName = undefined; + state = STATE_TAG_NAME, --i; + } else if (code === CODE_QUESTION) { + state = STATE_BOGUS_COMMENT, --i; + } else { + state = STATE_DATA, --i; + } + break; + } + case STATE_END_TAG_OPEN: { + if (isAsciiAlphaCode(code)) { + state = STATE_TAG_NAME, --i; + } else if (code === CODE_GT) { + state = STATE_DATA; + } else { + state = STATE_BOGUS_COMMENT, --i; + } + break; + } + case STATE_TAG_NAME: { + if (isSpaceCode(code)) { + state = STATE_BEFORE_ATTRIBUTE_NAME; + tagName = lower(input, tagNameStart, i); + } else if (code === CODE_SLASH) { + state = STATE_SELF_CLOSING_START_TAG; + } else if (code === CODE_GT) { + tagName = lower(input, tagNameStart, i); + state = isRawText(tagName) ? STATE_RAWTEXT : STATE_DATA; + } + break; + } + case STATE_BEFORE_ATTRIBUTE_NAME: { + if (isSpaceCode(code)) ; else if (code === CODE_SLASH || code === CODE_GT) { + state = STATE_AFTER_ATTRIBUTE_NAME, --i; + } else if (code === CODE_EQ) { + state = STATE_ATTRIBUTE_NAME; + attributeNameStart = i + 1, attributeNameEnd = undefined; + } else { + state = STATE_ATTRIBUTE_NAME, --i; + attributeNameStart = i + 1, attributeNameEnd = undefined; + } + break; + } + case STATE_ATTRIBUTE_NAME: { + if (isSpaceCode(code) || code === CODE_SLASH || code === CODE_GT) { + state = STATE_AFTER_ATTRIBUTE_NAME, --i; + attributeNameEnd = i; + } else if (code === CODE_EQ) { + state = STATE_BEFORE_ATTRIBUTE_VALUE; + attributeNameEnd = i; + } + break; + } + case STATE_AFTER_ATTRIBUTE_NAME: { + if (isSpaceCode(code)) ; else if (code === CODE_SLASH) { + state = STATE_SELF_CLOSING_START_TAG; + } else if (code === CODE_EQ) { + state = STATE_BEFORE_ATTRIBUTE_VALUE; + } else if (code === CODE_GT) { + state = isRawText(tagName) ? STATE_RAWTEXT : STATE_DATA; + } else { + state = STATE_ATTRIBUTE_NAME, --i; + attributeNameStart = i + 1, attributeNameEnd = undefined; + } + break; + } + case STATE_BEFORE_ATTRIBUTE_VALUE: { + if (isSpaceCode(code)) ; else if (code === CODE_DQUOTE) { + state = STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED; + } else if (code === CODE_SQUOTE) { + state = STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED; + } else if (code === CODE_GT) { + state = isRawText(tagName) ? STATE_RAWTEXT : STATE_DATA; + } else { + state = STATE_ATTRIBUTE_VALUE_UNQUOTED, --i; + } + break; + } + case STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED: { + if (code === CODE_DQUOTE) { + state = STATE_AFTER_ATTRIBUTE_VALUE_QUOTED; + } + break; + } + case STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED: { + if (code === CODE_SQUOTE) { + state = STATE_AFTER_ATTRIBUTE_VALUE_QUOTED; + } + break; + } + case STATE_ATTRIBUTE_VALUE_UNQUOTED: { + if (isSpaceCode(code)) { + state = STATE_BEFORE_ATTRIBUTE_NAME; + } else if (code === CODE_GT) { + state = isRawText(tagName) ? STATE_RAWTEXT : STATE_DATA; + } + break; + } + case STATE_AFTER_ATTRIBUTE_VALUE_QUOTED: { + if (isSpaceCode(code)) { + state = STATE_BEFORE_ATTRIBUTE_NAME; + } else if (code === CODE_SLASH) { + state = STATE_SELF_CLOSING_START_TAG; + } else if (code === CODE_GT) { + state = isRawText(tagName) ? STATE_RAWTEXT : STATE_DATA; + } else { + state = STATE_BEFORE_ATTRIBUTE_NAME, --i; + } + break; + } + case STATE_SELF_CLOSING_START_TAG: { + if (code === CODE_GT) { + state = STATE_DATA; + } else { + state = STATE_BEFORE_ATTRIBUTE_NAME, --i; + } + break; + } + case STATE_BOGUS_COMMENT: { + if (code === CODE_GT) { + state = STATE_DATA; + } + break; + } + case STATE_COMMENT_START: { + if (code === CODE_DASH) { + state = STATE_COMMENT_START_DASH; + } else if (code === CODE_GT) { + state = STATE_DATA; + } else { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT_START_DASH: { + if (code === CODE_DASH) { + state = STATE_COMMENT_END; + } else if (code === CODE_GT) { + state = STATE_DATA; + } else { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT: { + if (code === CODE_LT) { + state = STATE_COMMENT_LESS_THAN_SIGN; + } else if (code === CODE_DASH) { + state = STATE_COMMENT_END_DASH; + } + break; + } + case STATE_COMMENT_LESS_THAN_SIGN: { + if (code === CODE_BANG) { + state = STATE_COMMENT_LESS_THAN_SIGN_BANG; + } else if (code !== CODE_LT) { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT_LESS_THAN_SIGN_BANG: { + if (code === CODE_DASH) { + state = STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH; + } else { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH: { + if (code === CODE_DASH) { + state = STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH; + } else { + state = STATE_COMMENT_END, --i; + } + break; + } + case STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH: { + state = STATE_COMMENT_END, --i; + break; + } + case STATE_COMMENT_END_DASH: { + if (code === CODE_DASH) { + state = STATE_COMMENT_END; + } else { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT_END: { + if (code === CODE_GT) { + state = STATE_DATA; + } else if (code === CODE_BANG) { + state = STATE_COMMENT_END_BANG; + } else if (code !== CODE_DASH) { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_COMMENT_END_BANG: { + if (code === CODE_DASH) { + state = STATE_COMMENT_END_DASH; + } else if (code === CODE_GT) { + state = STATE_DATA; + } else { + state = STATE_COMMENT, --i; + } + break; + } + case STATE_MARKUP_DECLARATION_OPEN: { + if (code === CODE_DASH && input.charCodeAt(i + 1) === CODE_DASH) { + state = STATE_COMMENT_START, ++i; + } else { // Note: CDATA and DOCTYPE unsupported! + state = STATE_BOGUS_COMMENT, --i; + } + break; + } + case STATE_RAWTEXT: { + if (code === CODE_LT) { + state = STATE_RAWTEXT_LESS_THAN_SIGN; + } + break; + } + case STATE_RAWTEXT_LESS_THAN_SIGN: { + if (code === CODE_SLASH) { + state = STATE_RAWTEXT_END_TAG_OPEN; + } else { + state = STATE_RAWTEXT, --i; + } + break; + } + case STATE_RAWTEXT_END_TAG_OPEN: { + if (isAsciiAlphaCode(code)) { + tagNameStart = i; + state = STATE_RAWTEXT_END_TAG_NAME, --i; + } else { + state = STATE_RAWTEXT, --i; + } + break; + } + case STATE_RAWTEXT_END_TAG_NAME: { + if (isSpaceCode(code) && tagName === lower(input, tagNameStart, i)) { + state = STATE_BEFORE_ATTRIBUTE_NAME; + } else if (code === CODE_SLASH && tagName === lower(input, tagNameStart, i)) { + state = STATE_SELF_CLOSING_START_TAG; + } else if (code === CODE_GT && tagName === lower(input, tagNameStart, i)) { + state = STATE_DATA; + } else if (!isAsciiAlphaCode(code)) { + state = STATE_RAWTEXT, --i; + } + break; + } + default: { + state = undefined; + break; + } + } + } + + string += input; + } + + const root = render(string); + + const walker = document.createTreeWalker(root, nodeFilter, null, false); + const removeNodes = []; + while (walker.nextNode()) { + const node = walker.currentNode; + switch (node.nodeType) { + case TYPE_ELEMENT: { + const attributes = node.attributes; + for (let i = 0, n = attributes.length; i < n; ++i) { + const {name, value: currentValue} = attributes[i]; + if (/^::/.test(name)) { + const value = arguments[+name.slice(2)]; + removeAttribute(node, name), --i, --n; + for (const key in value) { + const subvalue = value[key]; + if (subvalue == null || subvalue === false) ; else if (typeof subvalue === "function") { + node[key] = subvalue; + } else if (key === "style" && isObjectLiteral(subvalue)) { + setStyles(node[key], subvalue); + } else { + setAttribute(node, key, subvalue === true ? "" : subvalue); + } + } + } else if (/^::/.test(currentValue)) { + const value = arguments[+currentValue.slice(2)]; + removeAttribute(node, name), --i, --n; + if (typeof value === "function") { + node[name] = value; + } else { // style + setStyles(node[name], value); + } + } + } + break; + } + case TYPE_COMMENT: { + if (/^::/.test(node.data)) { + const parent = node.parentNode; + const value = arguments[+node.data.slice(2)]; + if (value instanceof Node) { + parent.insertBefore(value, node); + } else if (typeof value !== "string" && value[Symbol.iterator]) { + if (value instanceof NodeList || value instanceof HTMLCollection) { + for (let i = value.length - 1, r = node; i >= 0; --i) { + r = parent.insertBefore(value[i], r); + } + } else { + for (const subvalue of value) { + if (subvalue == null) continue; + parent.insertBefore(subvalue instanceof Node ? subvalue : document.createTextNode(subvalue), node); + } + } + } else { + parent.insertBefore(document.createTextNode(value), node); + } + removeNodes.push(node); + } + break; + } + } + } + + for (const node of removeNodes) { + node.parentNode.removeChild(node); + } + + return postprocess(root); + }; +} + +function entity(character) { + return `&#${character.charCodeAt(0).toString()};`; +} + +function isAsciiAlphaCode(code) { + return (CODE_UPPER_A <= code && code <= CODE_UPPER_Z) + || (CODE_LOWER_A <= code && code <= CODE_LOWER_Z); +} + +function isSpaceCode(code) { + return code === CODE_TAB + || code === CODE_LF + || code === CODE_FF + || code === CODE_SPACE + || code === CODE_CR; // normalize newlines +} + +function isObjectLiteral(value) { + return value && value.toString === Object.prototype.toString; +} + +function isRawText(tagName) { + return tagName === "script" || tagName === "style" || isEscapableRawText(tagName); +} + +function isEscapableRawText(tagName) { + return tagName === "textarea" || tagName === "title"; +} + +function lower(input, start, end) { + return input.slice(start, end).toLowerCase(); +} + +function setAttribute(node, name, value) { + if (node.namespaceURI === NS_SVG) { + name = name.toLowerCase(); + name = svgAdjustAttributes.get(name) || name; + if (svgForeignAttributes.has(name)) { + node.setAttributeNS(svgForeignAttributes.get(name), name, value); + return; + } + } + node.setAttribute(name, value); +} + +function removeAttribute(node, name) { + if (node.namespaceURI === NS_SVG) { + name = name.toLowerCase(); + name = svgAdjustAttributes.get(name) || name; + if (svgForeignAttributes.has(name)) { + node.removeAttributeNS(svgForeignAttributes.get(name), name); + return; + } + } + node.removeAttribute(name); +} + +// We can’t use Object.assign because custom properties… +function setStyles(style, values) { + for (const name in values) { + const value = values[name]; + if (name.startsWith("--")) style.setProperty(name, value); + else style[name] = value; + } +} + +function length(x) { + return x == null ? null : typeof x === "number" ? `${x}px` : `${x}`; +} + +const bubbles = {bubbles: true}; + +function preventDefault(event) { + event.preventDefault(); +} + +function dispatchInput({currentTarget}) { + (currentTarget.form || currentTarget).dispatchEvent(new Event("input", bubbles)); +} + +function identity(x) { + return x; +} + +let nextId = 0; + +function newId() { + return `__ns__-${++nextId}`; +} + +function maybeLabel(label, input) { + if (!label) return; + label = html`