1 + 1
[1] 2
+diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index e82eb7b..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,25 +0,0 @@ -on: - workflow_dispatch: - push: - branches: main - -name: Quarto Publish - -jobs: - build-deploy: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Set up Quarto - uses: quarto-dev/quarto-actions/setup@v2 - - - name: Render and Publish - uses: quarto-dev/quarto-actions/publish@v2 - with: - target: gh-pages - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c4b7acc..0000000 --- a/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.Rproj.user -.Rhistory -.RData -.Ruserdata - -/.quarto/ -/_site/ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e65046b --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ +e632f536 \ No newline at end of file diff --git a/_extensions/dragonstyle/share-post/_extension.yml b/_extensions/dragonstyle/share-post/_extension.yml deleted file mode 100644 index 5ab3ff3..0000000 --- a/_extensions/dragonstyle/share-post/_extension.yml +++ /dev/null @@ -1,7 +0,0 @@ -title: Share-post -author: Charles Teague -version: 0.1.1 -quarto-required: ">=1.3.0" -contributes: - shortcodes: - - share-post.lua \ No newline at end of file diff --git a/_extensions/dragonstyle/share-post/share-post.lua b/_extensions/dragonstyle/share-post/share-post.lua deleted file mode 100644 index 302800d..0000000 --- a/_extensions/dragonstyle/share-post/share-post.lua +++ /dev/null @@ -1,275 +0,0 @@ -local kAfterBody = "after-body" -local kInHeader = "in-header" -local kBeforeBody = "before-body" - -local kUsePackages = "packages" - -local urlPattern = "(https?://[%w%$%-%_%.%+%!%*%'%(%)%:%%]+/)(.+)" - --- TODO: Support alignment --- margin-left: auto; margin-right: auto; display: block; - --- TODO: Place a link for non-html output - -local alignmentStyles = [[ - -]] - -local function parseUrl(url) - local baseUrl, urlPath = url:match(urlPattern) - return { - url = url, - base = baseUrl, - path = urlPath - } -end - - -local function makeBox(text, url, icon, color) - return pandoc.Div(pandoc.List({ - pandoc.RawInline('latex', '\\begin{centering}\\begin{tcolorbox}[hbox,\ncolframe=lightgray,\ncolback=white]\n'), - pandoc.RawInline('latex', '\\textcolor{' .. color .. '}{{\\Large {' .. icon .. '}}} %'), - pandoc.Link(pandoc.RawInline("latex", '\\raisebox{0.1 em}{' .. text .. '}'),url), - pandoc.RawInline('latex', '\n\\end{tcolorbox}\\end{centering}\n\\vspace{1em}') - })) -end - -local boxPackages = { - "tcolorbox", - "fontawesome5" -} - -local threads = { - canHandle = function(urlData) - return urlData.base:find("threads.net") - end, - handle = { - html = function(urlData) - local iframe = '
' - return { - block = pandoc.RawBlock("html", iframe), - [kAfterBody] = '', - [kInHeader] = alignmentStyles - } - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded Threads post.", urlData.url, "\\faShareSquare", "black"), - [kUsePackages] = boxPackages - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded Threads post.", urlData.url) - } - end - } -} - -local instagram = { - canHandle = function(urlData) - return urlData.base:find("instagram.com") - end, - handle = { - html = function(urlData) - local iframe = '
' - return { - block = pandoc.RawBlock("html", iframe), - [kAfterBody] = '' - } - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded Instagram post.", urlData.url, "\\faInstagram", "RubineRed"), - [kUsePackages] = boxPackages - - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded Instagram post.", urlData.url) - } - end - } -} - -local twitter = { - canHandle = function(urlData) - return urlData.base:find("twitter.com") - end, - handle = { - html = function(urlData) - local iframe = '
' - return { - block = pandoc.RawBlock("html", iframe), - [kAfterBody] = '' - } - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded Twitter post.", urlData.url, "\\faTwitterSquare", "ProcessBlue"), - [kUsePackages] = boxPackages - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded Twitter post.", urlData.url) - } - end - } -} - -local pinterest = { - canHandle = function(urlData) - return urlData.base:find("pinterest.com") - end, - handle = { - html = function(urlData) - local id = urlData.path:gsub("pin/", "") - if id:match("/$") then - id = id:sub(1, -2) - end - local iframe = '' - return { - block = pandoc.RawBlock("html", iframe), - } - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded Pinterest post.", urlData.url, "\\faPinterestSquare", "red"), - [kUsePackages] = boxPackages - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded Pinterest post.", urlData.url) - } - end - } -} - -local linkedin = { - canHandle = function(urlData) - return urlData.base:find("linkedin.com") - end, - handle = { - html = function(urlData) - local pattern = "(%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d+)" - local id = urlData.path:match(pattern) - if (id) then - -- https://www.linkedin.com/posts/posit-software_quarto-quarto-14-activity-7156030921387778049-dHKD?utm_source=share&utm_medium=member_desktop - local iframe = '' - return { - block = pandoc.RawBlock("html", iframe), - [kAfterBody] = '', - [kInHeader] = alignmentStyles - } - else - return nil - end - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded LinkedIn post.", urlData.url, "\\faLinkedin", "RoyalBlue"), - [kUsePackages] = boxPackages - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded LinkedIn post.", urlData.url) - } - end - } -} - -local mastodon = { - canHandle = function(urlData) - return urlData.path:find("@[%w._-]+/%d%d%d%d%d%d*") - end, - handle = { - html = function(urlData) - local iframe = '' - return { - block = pandoc.RawBlock("html", iframe), - [kAfterBody] = '', - [kInHeader] = alignmentStyles - } - end, - latex = function(urlData) - return { - block=makeBox("Click to view embedded Mastodon post.", urlData.url, "\\faMastodon", "Orchid"), - [kUsePackages] = boxPackages - } - end, - other = function(urlData) - return { - block=pandoc.Link("Click to view embedded Mastodon post.", urlData.url) - } - end - } -} - -local handlers = { - threads, - instagram, - twitter, - pinterest, - linkedin, - mastodon -} - -return { - ['share-post'] = function(args, kwargs, meta) - local result_block - local url = args[1] - -- html output - local urlData = parseUrl(url) - for i,handler in ipairs(handlers) do - - if handler.canHandle(urlData) then - - local make_result = handler.handle.other - if quarto.doc.is_format("html") then - make_result = handler.handle.html - elseif quarto.doc.is_format("pdf") then - make_result = handler.handle.latex - end - - -- return the raw html block - local result = make_result(urlData) - result_block = result.block - - -- inject dependencies - if result[kInHeader] ~= nil then - quarto.doc.include_text(kInHeader, result[kInHeader]) - end - if result[kBeforeBody] ~= nil then - quarto.doc.include_text(kBeforeBody, result[kBeforeBody]) - end - if result[kAfterBody] ~= nil then - quarto.doc.include_text(kAfterBody, result[kAfterBody]) - end - if result[kUsePackages] ~= nil then - for _i,v in ipairs(result[kUsePackages]) do - quarto.doc.use_latex_package(v) - end - end - end - end - if result_block == nil then - quarto.log.warning("Unable to resolve post url " .. url .. "\nNo post was embedded.") - end - return result_block or {} - end -} \ No newline at end of file diff --git a/_freeze/about/execute-results/html.json b/_freeze/about/execute-results/html.json deleted file mode 100644 index 8a69473..0000000 --- a/_freeze/about/execute-results/html.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hash": "a754ce02c0472c0b163d8ffb898e69ac", - "result": { - "engine": "knitr", - "markdown": "---\ntitle: \"About\"\n---\n\n\nAbout this site\n\n\n::: {.cell}\n\n```{.r .cell-code}\n1 + 1\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 2\n```\n\n\n:::\n:::\n", - "supporting": [], - "filters": [ - "rmarkdown/pagebreak.lua" - ], - "includes": {}, - "engineDependencies": {}, - "preserve": {}, - "postProcess": true - } -} \ No newline at end of file diff --git a/_freeze/posts/2024-01-29-welcome-to-the-tadaverse/index/execute-results/html.json b/_freeze/posts/2024-01-29-welcome-to-the-tadaverse/index/execute-results/html.json deleted file mode 100644 index d3b4e03..0000000 --- a/_freeze/posts/2024-01-29-welcome-to-the-tadaverse/index/execute-results/html.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hash": "c957672de9a96359580c22623c1d3e12", - "result": { - "engine": "knitr", - "markdown": "---\ntitle: \"Welcome to the tadaโฌขverse\"\ndescription: \"The tadaโฌขverse is a collection of 1 opinionated package for tadaโฌขscience. Developed by the tadaโฌขscience team of ๐ท 1, the tadaโฌขverse is built to flip and spin data ๐ into tada ๐.\"\nauthor:\n - name: Romain Franรงois\n affiliation: tadaโฌขscience\n affiliation-url: https://tada.science\ndate: 2024-01-29\ncategories: [tada, package, R]\ncitation: \n url: https://tada.science/posts/2024-01-29-welcome-to-the-tadaverse\nimage: mini.png\ndraft: false\n---\n\n\nThis is the first article for the tada[โฌข]{style=\"color:pink; font-size: 120%\"}science blog, so before we deep dive into changing the world, let's have some fun ๐.\n\nWhen I [linkedined](https://www.linkedin.com/posts/romain-francois_im-happy-to-share-so-lets-do-some-activity-7142468020257386496-ZjC_) about the *You & R* upcoming podcast ๐๏ธ back in December, I shared some code on [the survey](https://bit.ly/you-and-R) with potential guests.\n\n{fig-align=\"center\"}\n\n... but as I'm getting ready to launch ๐ soon - more on that shortly ๐ฅ ๐ฅ ๐ ๐ - I wanted something a bit more fun, so I wrote the `pkg_roulette()` function this morning and giftwrapped ๐ it up as the [tada](https://tada.tada.science) package that is on its way to CRAN. Over time, [tada](https://tada.tada.science) will get more tools and will serve as a host for all things tada[โฌข]{style=\"color:pink; font-size: 120%\"}science.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(tada)\n```\n\n::: {.cell-output .cell-output-stderr}\n\n```\n\n ๐๐ ๐๐\n ๐๐ ๐๐\n๐๐๐๐๐๐ ๐๐๐๐๐ ๐๐๐๐๐ ๐๐๐๐๐\n ๐๐ ๐๐ ๐๐ ๐๐ ๐๐\n ๐๐ ๐๐๐๐๐๐ ๐๐ ๐๐ ๐๐๐๐๐๐๐\n ๐๐ ๐ ๐๐ ๐๐ ๐๐ ๐๐ ๐๐ ๐๐\n ๐๐๐๐ ๐๐๐๐๐ ๐๐๐๐๐๐ ๐๐๐๐๐๐\n```\n\n\n:::\n:::\n\n\nThe [pkg_roulette()](http://tada.tada.science/reference/pkg_roulette.html) gives you the `time=` and `n=` arguments to control how long the roulette runs and how many packages it shows. It goes increasingly slowly during that time. You can also control the colors it uses with the `cols=` argument. But you don't need to, the defaults are fine.\n\n\n\n[tada](https://tada.tada.science) is on its way to CRAN, but you don't need to wait, and you can start using it right now with:\n\n\n::: {.cell}\n\n```{.r .cell-code}\npak::pak(\"tadascience/tada\")\n```\n:::\n\n\n๐ก You have ideas to improve it, awesome ๐ let's chat about it on [github](https://github.com/tadascience/tada), on [linkedin](https://www.linkedin.com/posts/romain-francois_welcome-to-the-tadaverse-i-played-activity-7157690935936499713-gxoA), on [X](https://x.com/romain_francois/status/1751951394439913520?s=20), on [bluesky](https://bsky.app/profile/romainfrancois.bsky.social/post/3kk4ov2vgs52v), on [mastodon](https://mastodon.social/@romainfrancois/111839335940660715), on [threads](https://www.threads.net/@romain_francois) or however you usually get in touch.\n\n๐ฆ don't go too far, I'll be back in this blog.\n", - "supporting": [], - "filters": [ - "rmarkdown/pagebreak.lua" - ], - "includes": {}, - "engineDependencies": {}, - "preserve": {}, - "postProcess": true - } -} \ No newline at end of file diff --git a/_freeze/posts/2024-02-02-tada-verse-poems/index/execute-results/html.json b/_freeze/posts/2024-02-02-tada-verse-poems/index/execute-results/html.json deleted file mode 100644 index 8199b4f..0000000 --- a/_freeze/posts/2024-02-02-tada-verse-poems/index/execute-results/html.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hash": "0cbf4a20cd71b8613961baf161cc3744", - "result": { - "engine": "knitr", - "markdown": "---\ntitle: \"tada::verse() poetry\"\ndescription: \"The tada::verse() function writes poetry๏ธ ๐ฆ about your R package ๐ฆ. \"\nauthor:\n - name: Romain Franรงois\n affiliation: tadaโฌขscience\n affiliation-url: https://tada.science\ndate: 2024-02-02\ncategories: [R, ai, poetry, tada]\nimage: image.png\ncitation: \n url: https://tada.science/posts/2024-02-02-tada-verse-poetry\ndraft: false\n---\n\n\nI just received the *Thanks, on its way to CRAN* email ๐ง about the [tada](tada.tada.science) package ๐, so it's a good time for a celebration, and what better way to celebrate than with a dash of poetry.\n\nThe `@dev` version gains a `verse()` function to write poetry about R packages, thanks for the heavy lifting of the [mlverse/chattr](https://mlverse.github.io/chattr/) ๐ฆ. We try to maintain a `@main` branch that could be released at any time, and `chattr` is not yet released. We hope it will be for the spring ๐ค๏ธ release of [tada](tada.tada.science), but it will be for the meantime available in the `@dev` branch.\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stderr}\n\n```\n\n```\n\n\n:::\n\n::: {.cell-output .cell-output-stderr}\n\n```\nโโ chattr \n```\n\n\n:::\n\n::: {.cell-output .cell-output-stderr}\n\n```\nโข Provider: Open AI - Chat Completions\n```\n\n\n:::\n\n::: {.cell-output .cell-output-stderr}\n\n```\nโข Path/URL: https://api.openai.com/v1/chat/completions\n```\n\n\n:::\n\n::: {.cell-output .cell-output-stderr}\n\n```\nโข Model: gpt-3.5-turbo\n```\n\n\n:::\n:::\n\n\nSo let's dive right in and do some [ggplot2](https://ggplot2.tidyverse.org) poetry ๐ชถ\n\n{fig-align=\"center\" width=\"692\"}\n\nFor additional fun, we can write some poetry about a random package we discover with [tada::pkg_roulette()](https://tada.tada.science/reference/pkg_roulette.html)\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntada::pkg_roulette() |> tada::verse()\n```\n:::\n\n{{< video poetry.mov >}}\n\n", - "supporting": [], - "filters": [ - "rmarkdown/pagebreak.lua" - ], - "includes": {}, - "engineDependencies": {}, - "preserve": {}, - "postProcess": true - } -} \ No newline at end of file diff --git a/_freeze/posts/2024-02-04-snitch/index/execute-results/html.json b/_freeze/posts/2024-02-04-snitch/index/execute-results/html.json deleted file mode 100644 index 4bd53da..0000000 --- a/_freeze/posts/2024-02-04-snitch/index/execute-results/html.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hash": "278bf1ecd87364ebaaf3d5d2bde49ea7", - "result": { - "engine": "knitr", - "markdown": "---\ntitle: \"snitch\"\ndescription: \"The experimental snitch ๐ฆ spies on functions and packages. The name and logo are inspired from the Harry Potter world. \"\nauthor:\n - name: Romain Franรงois\n affiliation: tadaโฌขscience\n affiliation-url: https://tada.science\ndate: 2024-02-04\ncategories: [R, snitch]\nimage: logo.png\ncitation: \n url: https://tada.science/posts/2024-02-04-snitch\ndraft: false\n---\n\n\n
\n\nWe'll get to *what* it is and what it does soon enough, but *it is*, it exists as a company, where as before it was just a name I used. We might start to *we* more than we I as a consequence, but for now let me wrap what happened in february.\n\n## AI poetry\n\nWe started off by adding the
- -We'll get to *what* it is and what it does soon enough, but *it is*, it exists as a company, where as before it was just a name I used. We might start to *we* more than we I as a consequence, but for now let me wrap what happened in february. - -## AI poetry - -We started off by adding the tada::verse() function to generate [praise poetry](../2024-02-02-tada-verse-poems/) using ChatGPT through the {chattr} ๐ฆ. - -This was fun, but quickly opened a can of worms, because tada::verse() would not work for some packages, because of a bug in {chattr}. At least that's what I initially assumed, and logged [an issue](https://github.com/mlverse/chattr/issues/63) for it. - -
${missingFields[0]}
field.`,
+ message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]}
field or use index-fields
in your _quarto.yml
file to specify the field names.`,
+ };
+ } else if (missingFields.length > 1) {
+ const missingFieldList = missingFields
+ .map((field) => {
+ return `${field}
`;
+ })
+ .join(", ");
+
+ throw {
+ name: `Error: Search index is missing the following fields: ${missingFieldList}.`,
+ message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields
in your _quarto.yml
file to specify the field names.`,
+ };
+ }
+ }
+}
+
+let lastQuery = null;
+function showCopyLink(query, options) {
+ const language = options.language;
+ lastQuery = query;
+ // Insert share icon
+ const inputSuffixEl = window.document.body.querySelector(
+ ".aa-Form .aa-InputWrapperSuffix"
+ );
+
+ if (inputSuffixEl) {
+ let copyButtonEl = window.document.body.querySelector(
+ ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton"
+ );
+
+ if (copyButtonEl === null) {
+ copyButtonEl = window.document.createElement("button");
+ copyButtonEl.setAttribute("class", "aa-CopyButton");
+ copyButtonEl.setAttribute("type", "button");
+ copyButtonEl.setAttribute("title", language["search-copy-link-title"]);
+ copyButtonEl.onmousedown = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ };
+
+ const linkIcon = "bi-clipboard";
+ const checkIcon = "bi-check2";
+
+ const shareIconEl = window.document.createElement("i");
+ shareIconEl.setAttribute("class", `bi ${linkIcon}`);
+ copyButtonEl.appendChild(shareIconEl);
+ inputSuffixEl.prepend(copyButtonEl);
+
+ const clipboard = new window.ClipboardJS(".aa-CopyButton", {
+ text: function (_trigger) {
+ const copyUrl = new URL(window.location);
+ copyUrl.searchParams.set(kQueryArg, lastQuery);
+ copyUrl.searchParams.set(kResultsArg, "1");
+ return copyUrl.toString();
+ },
+ });
+ clipboard.on("success", function (e) {
+ // Focus the input
+
+ // button target
+ const button = e.trigger;
+ const icon = button.querySelector("i.bi");
+
+ // flash "checked"
+ icon.classList.add(checkIcon);
+ icon.classList.remove(linkIcon);
+ setTimeout(function () {
+ icon.classList.remove(checkIcon);
+ icon.classList.add(linkIcon);
+ }, 1000);
+ });
+ }
+
+ // If there is a query, show the link icon
+ if (copyButtonEl) {
+ if (lastQuery && options["copy-button"]) {
+ copyButtonEl.style.display = "flex";
+ } else {
+ copyButtonEl.style.display = "none";
+ }
+ }
+ }
+}
+
+/* Search Index Handling */
+// create the index
+var fuseIndex = undefined;
+var shownWarning = false;
+
+// fuse index options
+const kFuseIndexOptions = {
+ keys: [
+ { name: "title", weight: 20 },
+ { name: "section", weight: 20 },
+ { name: "text", weight: 10 },
+ ],
+ ignoreLocation: true,
+ threshold: 0.1,
+};
+
+async function readSearchData() {
+ // Initialize the search index on demand
+ if (fuseIndex === undefined) {
+ if (window.location.protocol === "file:" && !shownWarning) {
+ window.alert(
+ "Search requires JavaScript features disabled when running in file://... URLs. In order to use search, please run this document in a web server."
+ );
+ shownWarning = true;
+ return;
+ }
+ const fuse = new window.Fuse([], kFuseIndexOptions);
+
+ // fetch the main search.json
+ const response = await fetch(offsetURL("search.json"));
+ if (response.status == 200) {
+ return response.json().then(function (searchDocs) {
+ searchDocs.forEach(function (searchDoc) {
+ fuse.add(searchDoc);
+ });
+ fuseIndex = fuse;
+ return fuseIndex;
+ });
+ } else {
+ return Promise.reject(
+ new Error(
+ "Unexpected status from search index request: " + response.status
+ )
+ );
+ }
+ }
+
+ return fuseIndex;
+}
+
+function inputElement() {
+ return window.document.body.querySelector(".aa-Form .aa-Input");
+}
+
+function focusSearchInput() {
+ setTimeout(() => {
+ const inputEl = inputElement();
+ if (inputEl) {
+ inputEl.focus();
+ }
+ }, 50);
+}
+
+/* Panels */
+const kItemTypeDoc = "document";
+const kItemTypeMore = "document-more";
+const kItemTypeItem = "document-item";
+const kItemTypeError = "error";
+
+function renderItem(
+ item,
+ createElement,
+ state,
+ setActiveItemId,
+ setContext,
+ refresh,
+ quartoSearchOptions
+) {
+ switch (item.type) {
+ case kItemTypeDoc:
+ return createDocumentCard(
+ createElement,
+ "file-richtext",
+ item.title,
+ item.section,
+ item.text,
+ item.href,
+ item.crumbs,
+ quartoSearchOptions
+ );
+ case kItemTypeMore:
+ return createMoreCard(
+ createElement,
+ item,
+ state,
+ setActiveItemId,
+ setContext,
+ refresh
+ );
+ case kItemTypeItem:
+ return createSectionCard(
+ createElement,
+ item.section,
+ item.text,
+ item.href
+ );
+ case kItemTypeError:
+ return createErrorCard(createElement, item.title, item.text);
+ default:
+ return undefined;
+ }
+}
+
+function createDocumentCard(
+ createElement,
+ icon,
+ title,
+ section,
+ text,
+ href,
+ crumbs,
+ quartoSearchOptions
+) {
+ const iconEl = createElement("i", {
+ class: `bi bi-${icon} search-result-icon`,
+ });
+ const titleEl = createElement("p", { class: "search-result-title" }, title);
+ const titleContents = [iconEl, titleEl];
+ const showParent = quartoSearchOptions["show-item-context"];
+ if (crumbs && showParent) {
+ let crumbsOut = undefined;
+ const crumbClz = ["search-result-crumbs"];
+ if (showParent === "root") {
+ crumbsOut = crumbs.length > 1 ? crumbs[0] : undefined;
+ } else if (showParent === "parent") {
+ crumbsOut = crumbs.length > 1 ? crumbs[crumbs.length - 2] : undefined;
+ } else {
+ crumbsOut = crumbs.length > 1 ? crumbs.join(" > ") : undefined;
+ crumbClz.push("search-result-crumbs-wrap");
+ }
+
+ const crumbEl = createElement(
+ "p",
+ { class: crumbClz.join(" ") },
+ crumbsOut
+ );
+ titleContents.push(crumbEl);
+ }
+
+ const titleContainerEl = createElement(
+ "div",
+ { class: "search-result-title-container" },
+ titleContents
+ );
+
+ const textEls = [];
+ if (section) {
+ const sectionEl = createElement(
+ "p",
+ { class: "search-result-section" },
+ section
+ );
+ textEls.push(sectionEl);
+ }
+ const descEl = createElement("p", {
+ class: "search-result-text",
+ dangerouslySetInnerHTML: {
+ __html: text,
+ },
+ });
+ textEls.push(descEl);
+
+ const textContainerEl = createElement(
+ "div",
+ { class: "search-result-text-container" },
+ textEls
+ );
+
+ const containerEl = createElement(
+ "div",
+ {
+ class: "search-result-container",
+ },
+ [titleContainerEl, textContainerEl]
+ );
+
+ const linkEl = createElement(
+ "a",
+ {
+ href: offsetURL(href),
+ class: "search-result-link",
+ },
+ containerEl
+ );
+
+ const classes = ["search-result-doc", "search-item"];
+ if (!section) {
+ classes.push("document-selectable");
+ }
+
+ return createElement(
+ "div",
+ {
+ class: classes.join(" "),
+ },
+ linkEl
+ );
+}
+
+function createMoreCard(
+ createElement,
+ item,
+ state,
+ setActiveItemId,
+ setContext,
+ refresh
+) {
+ const moreCardEl = createElement(
+ "div",
+ {
+ class: "search-result-more search-item",
+ onClick: (e) => {
+ // Handle expanding the sections by adding the expanded
+ // section to the list of expanded sections
+ toggleExpanded(item, state, setContext, setActiveItemId, refresh);
+ e.stopPropagation();
+ },
+ },
+ item.title
+ );
+
+ return moreCardEl;
+}
+
+function toggleExpanded(item, state, setContext, setActiveItemId, refresh) {
+ const expanded = state.context.expanded || [];
+ if (expanded.includes(item.target)) {
+ setContext({
+ expanded: expanded.filter((target) => target !== item.target),
+ });
+ } else {
+ setContext({ expanded: [...expanded, item.target] });
+ }
+
+ refresh();
+ setActiveItemId(item.__autocomplete_id);
+}
+
+function createSectionCard(createElement, section, text, href) {
+ const sectionEl = createSection(createElement, section, text, href);
+ return createElement(
+ "div",
+ {
+ class: "search-result-doc-section search-item",
+ },
+ sectionEl
+ );
+}
+
+function createSection(createElement, title, text, href) {
+ const descEl = createElement("p", {
+ class: "search-result-text",
+ dangerouslySetInnerHTML: {
+ __html: text,
+ },
+ });
+
+ const titleEl = createElement("p", { class: "search-result-section" }, title);
+ const linkEl = createElement(
+ "a",
+ {
+ href: offsetURL(href),
+ class: "search-result-link",
+ },
+ [titleEl, descEl]
+ );
+ return linkEl;
+}
+
+function createErrorCard(createElement, title, text) {
+ const descEl = createElement("p", {
+ class: "search-error-text",
+ dangerouslySetInnerHTML: {
+ __html: text,
+ },
+ });
+
+ const titleEl = createElement("p", {
+ class: "search-error-title",
+ dangerouslySetInnerHTML: {
+ __html: ` ${title}`,
+ },
+ });
+ const errorEl = createElement("div", { class: "search-error" }, [
+ titleEl,
+ descEl,
+ ]);
+ return errorEl;
+}
+
+function positionPanel(pos) {
+ const panelEl = window.document.querySelector(
+ "#quarto-search-results .aa-Panel"
+ );
+ const inputEl = window.document.querySelector(
+ "#quarto-search .aa-Autocomplete"
+ );
+
+ if (panelEl && inputEl) {
+ panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`;
+ if (pos === "start") {
+ panelEl.style.left = `${Math.round(inputEl.left)}px`;
+ } else {
+ panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`;
+ }
+ }
+}
+
+/* Highlighting */
+// highlighting functions
+function highlightMatch(query, text) {
+ if (text) {
+ const start = text.toLowerCase().indexOf(query.toLowerCase());
+ if (start !== -1) {
+ const startMark = "";
+ const endMark = "";
+
+ const end = start + query.length;
+ text =
+ text.slice(0, start) +
+ startMark +
+ text.slice(start, end) +
+ endMark +
+ text.slice(end);
+ const startInfo = clipStart(text, start);
+ const endInfo = clipEnd(
+ text,
+ startInfo.position + startMark.length + endMark.length
+ );
+ text =
+ startInfo.prefix +
+ text.slice(startInfo.position, endInfo.position) +
+ endInfo.suffix;
+
+ return text;
+ } else {
+ return text;
+ }
+ } else {
+ return text;
+ }
+}
+
+function clipStart(text, pos) {
+ const clipStart = pos - 50;
+ if (clipStart < 0) {
+ // This will just return the start of the string
+ return {
+ position: 0,
+ prefix: "",
+ };
+ } else {
+ // We're clipping before the start of the string, walk backwards to the first space.
+ const spacePos = findSpace(text, pos, -1);
+ return {
+ position: spacePos.position,
+ prefix: "",
+ };
+ }
+}
+
+function clipEnd(text, pos) {
+ const clipEnd = pos + 200;
+ if (clipEnd > text.length) {
+ return {
+ position: text.length,
+ suffix: "",
+ };
+ } else {
+ const spacePos = findSpace(text, clipEnd, 1);
+ return {
+ position: spacePos.position,
+ suffix: spacePos.clipped ? "โฆ" : "",
+ };
+ }
+}
+
+function findSpace(text, start, step) {
+ let stepPos = start;
+ while (stepPos > -1 && stepPos < text.length) {
+ const char = text[stepPos];
+ if (char === " " || char === "," || char === ":") {
+ return {
+ position: step === 1 ? stepPos : stepPos - step,
+ clipped: stepPos > 1 && stepPos < text.length,
+ };
+ }
+ stepPos = stepPos + step;
+ }
+
+ return {
+ position: stepPos - step,
+ clipped: false,
+ };
+}
+
+// removes highlighting as implemented by the mark tag
+function clearHighlight(searchterm, el) {
+ const childNodes = el.childNodes;
+ for (let i = childNodes.length - 1; i >= 0; i--) {
+ const node = childNodes[i];
+ if (node.nodeType === Node.ELEMENT_NODE) {
+ if (
+ node.tagName === "MARK" &&
+ node.innerText.toLowerCase() === searchterm.toLowerCase()
+ ) {
+ el.replaceChild(document.createTextNode(node.innerText), node);
+ } else {
+ clearHighlight(searchterm, node);
+ }
+ }
+ }
+}
+
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
+}
+
+// highlight matches
+function highlight(term, el) {
+ const termRegex = new RegExp(term, "ig");
+ const childNodes = el.childNodes;
+
+ // walk back to front avoid mutating elements in front of us
+ for (let i = childNodes.length - 1; i >= 0; i--) {
+ const node = childNodes[i];
+
+ if (node.nodeType === Node.TEXT_NODE) {
+ // Search text nodes for text to highlight
+ const text = node.nodeValue;
+
+ let startIndex = 0;
+ let matchIndex = text.search(termRegex);
+ if (matchIndex > -1) {
+ const markFragment = document.createDocumentFragment();
+ while (matchIndex > -1) {
+ const prefix = text.slice(startIndex, matchIndex);
+ markFragment.appendChild(document.createTextNode(prefix));
+
+ const mark = document.createElement("mark");
+ mark.appendChild(
+ document.createTextNode(
+ text.slice(matchIndex, matchIndex + term.length)
+ )
+ );
+ markFragment.appendChild(mark);
+
+ startIndex = matchIndex + term.length;
+ matchIndex = text.slice(startIndex).search(new RegExp(term, "ig"));
+ if (matchIndex > -1) {
+ matchIndex = startIndex + matchIndex;
+ }
+ }
+ if (startIndex < text.length) {
+ markFragment.appendChild(
+ document.createTextNode(text.slice(startIndex, text.length))
+ );
+ }
+
+ el.replaceChild(markFragment, node);
+ }
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
+ // recurse through elements
+ highlight(term, node);
+ }
+ }
+}
+
+/* Link Handling */
+// get the offset from this page for a given site root relative url
+function offsetURL(url) {
+ var offset = getMeta("quarto:offset");
+ return offset ? offset + url : url;
+}
+
+// read a meta tag value
+function getMeta(metaName) {
+ var metas = window.document.getElementsByTagName("meta");
+ for (let i = 0; i < metas.length; i++) {
+ if (metas[i].getAttribute("name") === metaName) {
+ return metas[i].getAttribute("content");
+ }
+ }
+ return "";
+}
+
+function algoliaSearch(query, limit, algoliaOptions) {
+ const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"];
+
+ const applicationId = algoliaOptions["application-id"];
+ const searchOnlyApiKey = algoliaOptions["search-only-api-key"];
+ const indexName = algoliaOptions["index-name"];
+ const indexFields = algoliaOptions["index-fields"];
+ const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey);
+ const searchParams = algoliaOptions["params"];
+ const searchAnalytics = !!algoliaOptions["analytics-events"];
+
+ return getAlgoliaResults({
+ searchClient,
+ queries: [
+ {
+ indexName: indexName,
+ query,
+ params: {
+ hitsPerPage: limit,
+ clickAnalytics: searchAnalytics,
+ ...searchParams,
+ },
+ },
+ ],
+ transformResponse: (response) => {
+ if (!indexFields) {
+ return response.hits.map((hit) => {
+ return hit.map((item) => {
+ return {
+ ...item,
+ text: highlightMatch(query, item.text),
+ };
+ });
+ });
+ } else {
+ const remappedHits = response.hits.map((hit) => {
+ return hit.map((item) => {
+ const newItem = { ...item };
+ ["href", "section", "title", "text", "crumbs"].forEach(
+ (keyName) => {
+ const mappedName = indexFields[keyName];
+ if (
+ mappedName &&
+ item[mappedName] !== undefined &&
+ mappedName !== keyName
+ ) {
+ newItem[keyName] = item[mappedName];
+ delete newItem[mappedName];
+ }
+ }
+ );
+ newItem.text = highlightMatch(query, newItem.text);
+ return newItem;
+ });
+ });
+ return remappedHits;
+ }
+ },
+ });
+}
+
+let subSearchTerm = undefined;
+let subSearchFuse = undefined;
+const kFuseMaxWait = 125;
+
+async function fuseSearch(query, fuse, fuseOptions) {
+ let index = fuse;
+ // Fuse.js using the Bitap algorithm for text matching which runs in
+ // O(nm) time (no matter the structure of the text). In our case this
+ // means that long search terms mixed with large index gets very slow
+ //
+ // This injects a subIndex that will be used once the terms get long enough
+ // Usually making this subindex is cheap since there will typically be
+ // a subset of results matching the existing query
+ if (subSearchFuse !== undefined && query.startsWith(subSearchTerm)) {
+ // Use the existing subSearchFuse
+ index = subSearchFuse;
+ } else if (subSearchFuse !== undefined) {
+ // The term changed, discard the existing fuse
+ subSearchFuse = undefined;
+ subSearchTerm = undefined;
+ }
+
+ // Search using the active fuse
+ const then = performance.now();
+ const resultsRaw = await index.search(query, fuseOptions);
+ const now = performance.now();
+
+ const results = resultsRaw.map((result) => {
+ const addParam = (url, name, value) => {
+ const anchorParts = url.split("#");
+ const baseUrl = anchorParts[0];
+ const sep = baseUrl.search("\\?") > 0 ? "&" : "?";
+ anchorParts[0] = baseUrl + sep + name + "=" + value;
+ return anchorParts.join("#");
+ };
+
+ return {
+ title: result.item.title,
+ section: result.item.section,
+ href: addParam(result.item.href, kQueryArg, query),
+ text: highlightMatch(query, result.item.text),
+ crumbs: result.item.crumbs,
+ };
+ });
+
+ // If we don't have a subfuse and the query is long enough, go ahead
+ // and create a subfuse to use for subsequent queries
+ if (now - then > kFuseMaxWait && subSearchFuse === undefined) {
+ subSearchTerm = query;
+ subSearchFuse = new window.Fuse([], kFuseIndexOptions);
+ resultsRaw.forEach((rr) => {
+ subSearchFuse.add(rr.item);
+ });
+ }
+ return results;
+}
diff --git a/sitemap.xml b/sitemap.xml
new file mode 100644
index 0000000..2fe037a
--- /dev/null
+++ b/sitemap.xml
@@ -0,0 +1,55 @@
+
+