1<!DOCTYPE html> 2<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> 3 4<meta charset="utf-8"> 5<meta name="generator" content="quarto-1.9.38"> 6 7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 8 9 10<title>Posts â danton.codes</title> 11<style> 12/* Default styles provided by pandoc. 13** See https://pandoc.org/MANUAL.html#variables-for-html for config info. 14*/ 15code{white-space: pre-wrap;} 16span.smallcaps{font-variant: small-caps;} 17div.columns{display: flex; gap: min(4vw, 1.5em);} 18div.column{flex: auto; overflow-x: auto;} 19div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} 20ul.task-list{list-style: none;} 21ul.task-list li input[type="checkbox"] { 22 width: 0.8em; 23 margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 24 vertical-align: middle; 25} 26</style> 27 28
29<script src="site_libs/quarto-nav/quarto-nav.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-nav/headroom.min.js"></script>
vendor: 1 bytes, line 30
30
31<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 31
31
32<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 32
32
33<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 33
33
34<script src="site_libs/quarto-search/quarto-search.js"></script>
34 35<meta name="quarto:offset" content="./"> 36<link href="./favicon.ico" rel="icon">
37<script src="site_libs/quarto-listing/list.min.js"></script>
vendor: 1 bytes, line 37
37
38<script src="site_libs/quarto-listing/quarto-listing.js"></script>
vendor: 1 bytes, line 38
38
39<script src="site_libs/quarto-html/quarto.js" type="module"></script>
vendor: 1 bytes, line 39
39
40<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
vendor: 1 bytes, line 40
40
41<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 41
41
42<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
vendor: 1 bytes, line 42
42
43<script src="site_libs/quarto-html/anchor.min.js"></script>
43 44<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> 45<link href="site_libs/quarto-html/quarto-syntax-highlighting-15634bcf2e68342d4ad2dfa704d543f6.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles"> 46<link href="site_libs/quarto-html/quarto-syntax-highlighting-dark-0a6b7249c26820e032cb0bd839ff02b1.css" rel="stylesheet" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles"> 47<link href="site_libs/quarto-html/quarto-syntax-highlighting-15634bcf2e68342d4ad2dfa704d543f6.css" rel="stylesheet" class="quarto-color-scheme-extra" id="quarto-text-highlighting-styles">
48<script src="site_libs/bootstrap/bootstrap.min.js"></script>
48 49<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> 50<link href="site_libs/bootstrap/bootstrap-85545d89869a7d03b8d8b22d16f33e0b.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light"> 51<link href="site_libs/bootstrap/bootstrap-dark-f7fba41c1ef1477727021bb8767eabf3.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="dark"> 52<link href="site_libs/bootstrap/bootstrap-85545d89869a7d03b8d8b22d16f33e0b.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme-extra" id="quarto-bootstrap" data-mode="light">
53<script id="quarto-search-options" type="application/json">{ 54 "location": "navbar", 55 "copy-button": false, 56 "collapse-after": 3, 57 "panel-placement": "end", 58 "type": "overlay", 59 "limit": 50, 60 "keyboard-shortcut": [ 61 "f", 62 "/", 63 "s" 64 ], 65 "show-item-context": false, 66 "language": { 67 "search-no-results-text": "No results", 68 "search-matching-documents-text": "matching documents", 69 "search-copy-link-title": "Copy link to search", 70 "search-hide-matches-text": "Hide additional matches", 71 "search-more-match-text": "more match in this document", 72 "search-more-matches-text": "more matches in this document", 73 "search-clear-button-title": "Clear", 74 "search-text-placeholder": "", 75 "search-detached-cancel-button-title": "Cancel", 76 "search-submit-button-title": "Submit", 77 "search-label": "Search" 78 } 79}</script>
vendor: 1 bytes, line 79
79
80<script> 81 82 window.document.addEventListener("DOMContentLoaded", function (_event) { 83 const listingTargetEl = window.document.querySelector('#listing-listing .list'); 84 if (!listingTargetEl) { 85 // No listing discovered, do not attach. 86 return; 87 } 88 89 const options = { 90 valueNames: ['listing-date','listing-title','listing-author',{ data: ['index'] },{ data: ['categories'] },{ data: ['listing-date-sort'] }], 91 92 searchColumns: ["listing-date","listing-title","listing-author","listing-image","listing-description"], 93 }; 94 95 window['quarto-listings'] = window['quarto-listings'] || {}; 96 window['quarto-listings']['listing-listing'] = new List('listing-listing', options); 97 98 if (window['quarto-listing-loaded']) { 99 window['quarto-listing-loaded'](); 100 } 101 }); 102 103 window.addEventListener('hashchange',() => { 104 if (window['quarto-listing-loaded']) { 105 window['quarto-listing-loaded'](); 106 } 107 }) 108 </script>
108 109 110
110<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
110 111
111<script defer="" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
111 112
113<script type="text/javascript"> 114const typesetMath = (el) => { 115 if (window.MathJax) { 116 // MathJax Typeset 117 window.MathJax.typeset([el]); 118 } else if (window.katex) { 119 // KaTeX Render 120 var mathElements = el.getElementsByClassName("math"); 121 var macros = []; 122 for (var i = 0; i < mathElements.length; i++) { 123 var texText = mathElements[i].firstChild; 124 if (mathElements[i].tagName == "SPAN" && texText && texText.data) { 125 window.katex.render(texText.data, mathElements[i], { 126 displayMode: mathElements[i].classList.contains('display'), 127 throwOnError: false, 128 macros: macros, 129 fleqn: false 130 }); 131 } 132 } 133 } 134} 135window.Quarto = { 136 typesetMath 137}; 138</script>
138 139 140<link rel="stylesheet" href="styles.css"> 141<meta property="og:title" content="Posts â danton.codes"> 142<meta property="og:image" content="https://danton.codes/images/profile.jpeg"> 143<meta property="og:site_name" content="danton.codes"> 144<meta name="twitter:title" content="Posts â danton.codes"> 145<meta name="twitter:image" content="https://danton.codes/images/profile.jpeg"> 146<meta name="twitter:card" content="summary_large_image"> 147</head> 148 149<body class="nav-fixed fullcontent quarto-light">
149<script id="quarto-html-before-body" type="application/javascript"> 150 const toggleBodyColorMode = (bsSheetEl) => { 151 const mode = bsSheetEl.getAttribute("data-mode"); 152 const bodyEl = window.document.querySelector("body"); 153 if (mode === "dark") { 154 bodyEl.classList.add("quarto-dark"); 155 bodyEl.classList.remove("quarto-light"); 156 } else { 157 bodyEl.classList.add("quarto-light"); 158 bodyEl.classList.remove("quarto-dark"); 159 } 160 } 161 const toggleBodyColorPrimary = () => { 162 const bsSheetEl = window.document.querySelector("link#quarto-bootstrap:not([rel=disabled-stylesheet])"); 163 if (bsSheetEl) { 164 toggleBodyColorMode(bsSheetEl); 165 } 166 } 167 const setColorSchemeToggle = (alternate) => { 168 const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle'); 169 for (let i=0; i < toggles.length; i++) { 170 const toggle = toggles[i]; 171 if (toggle) { 172 if (alternate) { 173 toggle.classList.add("alternate"); 174 } else { 175 toggle.classList.remove("alternate"); 176 } 177 } 178 } 179 }; 180 const toggleColorMode = (alternate) => { 181 // Switch the stylesheets 182 const primaryStylesheets = window.document.querySelectorAll('link.quarto-color-scheme:not(.quarto-color-alternate)'); 183 const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate'); 184 manageTransitions('#quarto-margin-sidebar .nav-link', false); 185 if (alternate) { 186 // note: dark is layered on light, we don't disable primary! 187 enableStylesheet(alternateStylesheets); 188 for (const sheetNode of alternateStylesheets) { 189 if (sheetNode.id === "quarto-bootstrap") { 190 toggleBodyColorMode(sheetNode); 191 } 192 } 193 } else { 194 disableStylesheet(alternateStylesheets); 195 enableStylesheet(primaryStylesheets) 196 toggleBodyColorPrimary(); 197 } 198 manageTransitions('#quarto-margin-sidebar .nav-link', true); 199 // Switch the toggles 200 setColorSchemeToggle(alternate) 201 // Hack to workaround the fact that safari doesn't 202 // properly recolor the scrollbar when toggling (#1455) 203 if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) { 204 manageTransitions("body", false); 205 window.scrollTo(0, 1); 206 setTimeout(() => { 207 window.scrollTo(0, 0); 208 manageTransitions("body", true); 209 }, 40); 210 } 211 } 212 const disableStylesheet = (stylesheets) => { 213 for (let i=0; i < stylesheets.length; i++) { 214 const stylesheet = stylesheets[i]; 215 stylesheet.rel = 'disabled-stylesheet'; 216 } 217 } 218 const enableStylesheet = (stylesheets) => { 219 for (let i=0; i < stylesheets.length; i++) { 220 const stylesheet = stylesheets[i]; 221 if(stylesheet.rel !== 'stylesheet') { // for Chrome, which will still FOUC without this check 222 stylesheet.rel = 'stylesheet'; 223 } 224 } 225 } 226 const manageTransitions = (selector, allowTransitions) => { 227 const els = window.document.querySelectorAll(selector); 228 for (let i=0; i < els.length; i++) { 229 const el = els[i]; 230 if (allowTransitions) { 231 el.classList.remove('notransition'); 232 } else { 233 el.classList.add('notransition'); 234 } 235 } 236 } 237 const isFileUrl = () => { 238 return window.location.protocol === 'file:'; 239 } 240 const hasAlternateSentinel = () => { 241 let styleSentinel = getColorSchemeSentinel(); 242 if (styleSentinel !== null) { 243 return styleSentinel === "alternate"; 244 } else { 245 return false; 246 } 247 } 248 const setStyleSentinel = (alternate) => { 249 const value = alternate ? "alternate" : "default"; 250 if (!isFileUrl()) { 251 window.localStorage.setItem("quarto-color-scheme", value); 252 } else { 253 localAlternateSentinel = value; 254 } 255 } 256 const getColorSchemeSentinel = () => { 257 if (!isFileUrl()) { 258 const storageValue = window.localStorage.getItem("quarto-color-scheme"); 259 return storageValue != null ? storageValue : localAlternateSentinel; 260 } else { 261 return localAlternateSentinel; 262 } 263 } 264 const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => { 265 const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light'; 266 const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark'; 267 let newTheme = ''; 268 if(authorPrefersDark) { 269 newTheme = isAlternate ? baseTheme : alternateTheme; 270 } else { 271 newTheme = isAlternate ? alternateTheme : baseTheme; 272 } 273 const changeGiscusTheme = () => { 274 // From: https://github.com/giscus/giscus/issues/336 275 const sendMessage = (message) => { 276 const iframe = document.querySelector('iframe.giscus-frame'); 277 if (!iframe) return; 278 iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); 279 } 280 sendMessage({ 281 setConfig: { 282 theme: newTheme 283 } 284 }); 285 } 286 const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null; 287 if (isGiscussLoaded) { 288 changeGiscusTheme(); 289 } 290 }; 291 const authorPrefersDark = false;
292 const darkModeDefault = authorPrefersDark; 293 document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 294 document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 295 let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default'; 296 // Dark / light mode switch 297 window.quartoToggleColorScheme = () => { 298 // Read the current dark / light value 299 let toAlternate = !hasAlternateSentinel(); 300 toggleColorMode(toAlternate); 301 setStyleSentinel(toAlternate); 302 toggleGiscusIfUsed(toAlternate, darkModeDefault); 303 window.dispatchEvent(new Event('resize')); 304 }; 305 // Switch to dark mode if need be 306 if (hasAlternateSentinel()) { 307 toggleColorMode(true); 308 } else { 309 toggleColorMode(false); 310 } 311 </script>
311 312 313<div id="quarto-search-results"></div> 314 <header id="quarto-header" class="headroom fixed-top"> 315 <nav class="navbar navbar-expand-lg " data-bs-theme="dark"> 316 <div class="navbar-container container-fluid"> 317 <div class="navbar-brand-container mx-auto"> 318 <a class="navbar-brand" href="./index.html"> 319 <span class="navbar-title">danton.codes</span> 320 </a> 321 </div> 322 <div id="quarto-search" class="" title="Search"></div> 323 <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> 324 <span class="navbar-toggler-icon"></span> 325</button> 326 <div class="collapse navbar-collapse" id="navbarCollapse"> 327 <ul class="navbar-nav navbar-nav-scroll me-auto"> 328 <li class="nav-item"> 329 <a class="nav-link" href="./index.html"> 330<span class="menu-text">About Me</span></a> 331 </li> 332 <li class="nav-item"> 333 <a class="nav-link" href="./resume.html"> 334<span class="menu-text">Resume</span></a> 335 </li> 336 <li class="nav-item"> 337 <a class="nav-link active" href="./posts.html" aria-current="page"> 338<span class="menu-text">Posts</span></a> 339 </li> 340 <li class="nav-item"> 341 <a class="nav-link" href="https://dantonnoriega.github.io/SR3TuringQuarto.jl/"> 342<span class="menu-text">SR3TuringQuarto.jl</span></a> 343 </li> 344</ul> 345 </div> <!-- /navcollapse --> 346 <div class="quarto-navbar-tools"> 347 <a href="https://gitlab.com/dantonnoriega/dantonnoriega.gitlab.io" title="Source" class="quarto-navigation-tool px-1" aria-label="Source"><i class="bi bi-gitlab"></i></a> 348 <a href="" class="quarto-color-scheme-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleColorScheme(); return false;" title="Toggle dark mode"><i class="bi"></i></a> 349</div> 350 </div> <!-- /container-fluid --> 351 </nav> 352</header> 353<!-- content --> 354<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> 355<!-- sidebar --> 356<!-- margin-sidebar --> 357 358<!-- main --> 359<main class="content" id="quarto-document-content"> 360 361 362<header id="title-block-header" class="quarto-title-block default"> 363<div class="quarto-title"> 364<h1 class="title">Posts</h1> 365</div> 366 367 368 369<div class="quarto-title-meta"> 370 371 372 373 374 </div> 375 376 377 378</header> 379 380 381 382 383 384 385<div class="quarto-listing quarto-listing-container-default" id="listing-listing"> 386<div class="listing-actions-group"> 387 <div class="input-group input-group-sm quarto-listing-sort"> 388 <span class="input-group-text"><i class="bi bi-sort-down"></i></span> 389 <select id="listing-listing-sort" class="form-select" aria-label="Order By" onchange="window['quarto-listings']['listing-listing'].sort(this.options[this.selectedIndex].value, { order: this.options[this.selectedIndex].getAttribute('data-direction')})"> 390 <option value="" disabled="" selected="" hidden="">Order By</option> 391 <option value="index" data-direction="asc">Default</option> 392 <option value="listing-date-sort" data-direction="asc"> 393 Date - Oldest 394 </option> 395 <option value="listing-date-sort" data-direction="desc"> 396 Date - Newest 397 </option> 398 </select> 399 </div> 400 <div class="input-group input-group-sm quarto-listing-filter"> 401 <span class="input-group-text"><i class="bi bi-search"></i></span> 402 <input type="text" class="search form-control" placeholder="Filter"> 403 </div> 404</div> 405<div class="list quarto-listing-default"> 406<div class="quarto-post image-right" data-index="0" data-categories="UiUyQ1N0YW4=" data-listing-date-sort="1561359600000" data-listing-file-modified-sort="1694941493631" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="1" data-listing-word-count-sort="11"> 407<div class="body"> 408<h3 class="no-anchor listing-title"> 409<a href="./posts/2019-06-24-brief-introduction-to-stan-and-multilevel-models.html" class="no-external">A Brief Introduction to Multilevel Models and Stan with R: rstanarm, brms, and rethinking</a> 410</h3> 411</div> 412<div class="metadata"> 413<a href="./posts/2019-06-24-brief-introduction-to-stan-and-multilevel-models.html" class="no-external"> 414<div class="listing-date"> 415Jun 24, 2019 416</div> 417<div class="listing-author"> 418Danton Noriega-Goodwin 419</div> 420</a> 421</div> 422</div> 423<div class="quarto-post image-right" data-index="1" data-categories="Y29tbWFuZCUyMGxpbmU=" data-listing-date-sort="1500620400000" data-listing-file-modified-sort="1695059899994" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="2" data-listing-word-count-sort="350"> 424<div class="body"> 425<h3 class="no-anchor listing-title"> 426<a href="./posts/2017-07-21-cropping-pdfs.html" class="no-external">Cropping a Multiple Page PDF Using Command Line (macOS)</a> 427</h3> 428</div> 429<div class="metadata"> 430<a href="./posts/2017-07-21-cropping-pdfs.html" class="no-external"> 431<div class="listing-date"> 432Jul 21, 2017 433</div> 434<div class="listing-author"> 435Danton Noriega-Goodwin 436</div> 437</a> 438</div> 439</div> 440<div class="quarto-post image-right" data-index="2" data-categories="UiUyQ1hNTA==" data-listing-date-sort="1492498800000" data-listing-file-modified-sort="1694941493631" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="1" data-listing-word-count-sort="100"> 441<div class="body"> 442<h3 class="no-anchor listing-title"> 443<a href="./posts/2017-04-18-xmltools-package.html" class="no-external">xmltools package to help convert XML data to tidy data frames</a> 444</h3> 445</div> 446<div class="metadata"> 447<a href="./posts/2017-04-18-xmltools-package.html" class="no-external"> 448<div class="listing-date"> 449Apr 18, 2017 450</div> 451<div class="listing-author"> 452Danton Noriega-Goodwin 453</div> 454</a> 455</div> 456</div> 457<div class="quarto-post image-right" data-index="3" data-categories="UiUyQ2hpZ2hjaGFydGVy" data-listing-date-sort="1491375600000" data-listing-file-modified-sort="1694941493631" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="23" data-listing-word-count-sort="4491"> 458<div class="body"> 459<h3 class="no-anchor listing-title"> 460<a href="./posts/2017-04-05-highcharter-explainer.html" class="no-external">Thinking in <code>highcharter</code> - How to build any Highcharts plot in R</a> 461</h3> 462</div> 463<div class="metadata"> 464<a href="./posts/2017-04-05-highcharter-explainer.html" class="no-external"> 465<div class="listing-date"> 466Apr 5, 2017 467</div> 468<div class="listing-author"> 469Danton Noriega-Goodwin 470</div> 471</a> 472</div> 473</div> 474<div class="quarto-post image-right" data-index="4" data-listing-date-sort="1460617200000" data-listing-file-modified-sort="1694941493631" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="3" data-listing-word-count-sort="538"> 475<div class="body"> 476<h3 class="no-anchor listing-title"> 477<a href="./posts/2016-04-14-rmarkdown-to-docx.html" class="no-external">RMarkdown (.Rmd) to MS Word (.docx) aka rmarkdown2docx</a> 478</h3> 479</div> 480<div class="metadata"> 481<a href="./posts/2016-04-14-rmarkdown-to-docx.html" class="no-external"> 482<div class="listing-date"> 483Apr 14, 2016 484</div> 485<div class="listing-author"> 486Danton Noriega-Goodwin 487</div> 488</a> 489</div> 490</div> 491<div class="quarto-post image-right" data-index="5" data-listing-date-sort="1459234800000" data-listing-file-modified-sort="1694941493631" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="4" data-listing-word-count-sort="682"> 492<div class="body"> 493<h3 class="no-anchor listing-title"> 494<a href="./posts/2016-03-29-pdf-text-convert-ocr-tesseract.html" class="no-external">Converting Unsearchable PDF Files (aka PDF scans) to Raw Text Using Command Line Tools <code>convert</code> and <code>tesseract</code></a> 495</h3> 496</div> 497<div class="metadata"> 498<a href="./posts/2016-03-29-pdf-text-convert-ocr-tesseract.html" class="no-external"> 499<div class="listing-date"> 500Mar 29, 2016 501</div> 502<div class="listing-author"> 503Danton Noriega-Goodwin 504</div> 505</a> 506</div> 507</div> 508</div> 509<div class="listing-no-matching d-none">No matching items</div> 510</div></main> <!-- /main -->
511<script id="quarto-html-after-body" type="application/javascript"> 512 window.document.addEventListener("DOMContentLoaded", function (event) { 513 // Ensure there is a toggle, if there isn't float one in the top right 514 if (window.document.querySelector('.quarto-color-scheme-toggle') === null) { 515 const a = window.document.createElement('a'); 516 a.classList.add('top-right'); 517 a.classList.add('quarto-color-scheme-toggle'); 518 a.href = ""; 519 a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; }; 520 const i = window.document.createElement("i"); 521 i.classList.add('bi'); 522 a.appendChild(i); 523 window.document.body.appendChild(a); 524 } 525 setColorSchemeToggle(hasAlternateSentinel()) 526 const icon = "î§"; 527 const anchorJS = new window.AnchorJS(); 528 anchorJS.options = { 529 placement: 'right', 530 icon: icon 531 }; 532 anchorJS.add('.anchored'); 533 const isCodeAnnotation = (el) => { 534 for (const clz of el.classList) { 535 if (clz.startsWith('code-annotation-')) { 536 return true; 537 } 538 } 539 return false; 540 } 541 const onCopySuccess = function(e) { 542 // button target 543 const button = e.trigger; 544 // don't keep focus 545 button.blur(); 546 // flash "checked" 547 button.classList.add('code-copy-button-checked'); 548 var currentTitle = button.getAttribute("title"); 549 button.setAttribute("title", "Copied!"); 550 let tooltip; 551 if (window.bootstrap) { 552 button.setAttribute("data-bs-toggle", "tooltip"); 553 button.setAttribute("data-bs-placement", "left"); 554 button.setAttribute("data-bs-title", "Copied!"); 555 tooltip = new bootstrap.Tooltip(button, 556 { trigger: "manual", 557 customClass: "code-copy-button-tooltip", 558 offset: [0, -8]}); 559 tooltip.show(); 560 } 561 setTimeout(function() { 562 if (tooltip) { 563 tooltip.hide(); 564 button.removeAttribute("data-bs-title"); 565 button.removeAttribute("data-bs-toggle"); 566 button.removeAttribute("data-bs-placement"); 567 } 568 button.setAttribute("title", currentTitle); 569 button.classList.remove('code-copy-button-checked'); 570 }, 1000); 571 // clear code selection 572 e.clearSelection(); 573 } 574 const getTextToCopy = function(trigger) { 575 const outerScaffold = trigger.parentElement.cloneNode(true); 576 const codeEl = outerScaffold.querySelector('code'); 577 for (const childEl of codeEl.children) { 578 if (isCodeAnnotation(childEl)) { 579 childEl.remove(); 580 } 581 } 582 return codeEl.innerText; 583 } 584 const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { 585 text: getTextToCopy 586 }); 587 clipboard.on('success', onCopySuccess); 588 if (window.document.getElementById('quarto-embedded-source-code-modal')) { 589 const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { 590 text: getTextToCopy, 591 container: window.document.getElementById('quarto-embedded-source-code-modal') 592 }); 593 clipboardModal.on('success', onCopySuccess); 594 } 595 var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); 596 var mailtoRegex = new RegExp(/^mailto:/); 597 var filterRegex = new RegExp("https:\/\/danton\.codes"); 598 var isInternal = (href) => { 599 return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); 600 } 601 // Inspect non-navigation links and adorn them if external 602 var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)'); 603 for (var i=0; i<links.length; i++) { 604 const link = links[i]; 605 if (!isInternal(link.href)) { 606 // undo the damage that might have been done by quarto-nav.js in the case of 607 // links that we want to consider external 608 if (link.dataset.originalHref !== undefined) { 609 link.href = link.dataset.originalHref; 610 } 611 } 612 } 613 function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { 614 const config = { 615 allowHTML: true, 616 maxWidth: 500, 617 delay: 100,
618 arrow: false, 619 appendTo: function(el) { 620 return el.parentElement; 621 }, 622 interactive: true, 623 interactiveBorder: 10, 624 theme: 'quarto', 625 placement: 'bottom-start', 626 }; 627 if (contentFn) { 628 config.content = contentFn; 629 } 630 if (onTriggerFn) { 631 config.onTrigger = onTriggerFn; 632 } 633 if (onUntriggerFn) { 634 config.onUntrigger = onUntriggerFn; 635 } 636 window.tippy(el, config); 637 } 638 const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); 639 for (var i=0; i<noterefs.length; i++) { 640 const ref = noterefs[i]; 641 tippyHover(ref, function() { 642 // use id or data attribute instead here 643 let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); 644 try { href = new URL(href).hash; } catch {} 645 const id = href.replace(/^#\/?/, ""); 646 const note = window.document.getElementById(id); 647 if (note) { 648 return note.innerHTML; 649 } else { 650 return ""; 651 } 652 }); 653 } 654 const xrefs = window.document.querySelectorAll('a.quarto-xref'); 655 const processXRef = (id, note) => { 656 // Strip column container classes 657 const stripColumnClz = (el) => { 658 el.classList.remove("page-full", "page-columns"); 659 if (el.children) { 660 for (const child of el.children) { 661 stripColumnClz(child); 662 } 663 } 664 } 665 stripColumnClz(note) 666 if (id === null || id.startsWith('sec-')) { 667 // Special case sections, only their first couple elements 668 const container = document.createElement("div"); 669 if (note.children && note.children.length > 2) { 670 container.appendChild(note.children[0].cloneNode(true)); 671 for (let i = 1; i < note.children.length; i++) { 672 const child = note.children[i]; 673 if (child.tagName === "P" && child.innerText === "") { 674 continue; 675 } else { 676 container.appendChild(child.cloneNode(true)); 677 break; 678 } 679 } 680 if (window.Quarto?.typesetMath) { 681 window.Quarto.typesetMath(container); 682 } 683 return container.innerHTML 684 } else { 685 if (window.Quarto?.typesetMath) { 686 window.Quarto.typesetMath(note); 687 } 688 return note.innerHTML; 689 } 690 } else { 691 // Remove any anchor links if they are present 692 const anchorLink = note.querySelector('a.anchorjs-link'); 693 if (anchorLink) { 694 anchorLink.remove(); 695 } 696 if (window.Quarto?.typesetMath) { 697 window.Quarto.typesetMath(note); 698 } 699 if (note.classList.contains("callout")) { 700 return note.outerHTML; 701 } else { 702 return note.innerHTML; 703 } 704 } 705 } 706 for (var i=0; i<xrefs.length; i++) { 707 const xref = xrefs[i]; 708 tippyHover(xref, undefined, function(instance) { 709 instance.disable(); 710 let url = xref.getAttribute('href'); 711 let hash = undefined; 712 if (url.startsWith('#')) { 713 hash = url; 714 } else { 715 try { hash = new URL(url).hash; } catch {} 716 } 717 if (hash) { 718 const id = hash.replace(/^#\/?/, ""); 719 const note = window.document.getElementById(id); 720 if (note !== null) { 721 try { 722 const html = processXRef(id, note.cloneNode(true)); 723 instance.setContent(html); 724 } finally { 725 instance.enable(); 726 instance.show(); 727 } 728 } else { 729 // See if we can fetch this 730 fetch(url.split('#')[0]) 731 .then(res => res.text()) 732 .then(html => { 733 const parser = new DOMParser(); 734 const htmlDoc = parser.parseFromString(html, "text/html"); 735 const note = htmlDoc.getElementById(id); 736 if (note !== null) { 737 const html = processXRef(id, note); 738 instance.setContent(html); 739 } 740 }).finally(() => { 741 instance.enable(); 742 instance.show(); 743 }); 744 } 745 } else { 746 // See if we can fetch a full url (with no hash to target)
747 // This is a special case and we should probably do some content thinning / targeting 748 fetch(url) 749 .then(res => res.text()) 750 .then(html => { 751 const parser = new DOMParser(); 752 const htmlDoc = parser.parseFromString(html, "text/html"); 753 const note = htmlDoc.querySelector('main.content'); 754 if (note !== null) { 755 // This should only happen for chapter cross references 756 // (since there is no id in the URL) 757 // remove the first header 758 if (note.children.length > 0 && note.children[0].tagName === "HEADER") { 759 note.children[0].remove(); 760 } 761 const html = processXRef(null, note); 762 instance.setContent(html); 763 } 764 }).finally(() => { 765 instance.enable(); 766 instance.show(); 767 }); 768 } 769 }, function(instance) { 770 }); 771 } 772 let selectedAnnoteEl; 773 const selectorForAnnotation = ( cell, annotation) => { 774 let cellAttr = 'data-code-cell="' + cell + '"'; 775 let lineAttr = 'data-code-annotation="' + annotation + '"'; 776 const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; 777 return selector; 778 } 779 const selectCodeLines = (annoteEl) => { 780 const doc = window.document; 781 const targetCell = annoteEl.getAttribute("data-target-cell"); 782 const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); 783 const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); 784 const lines = annoteSpan.getAttribute("data-code-lines").split(","); 785 const lineIds = lines.map((line) => { 786 return targetCell + "-" + line; 787 }) 788 let top = null; 789 let height = null; 790 let parent = null; 791 if (lineIds.length > 0) { 792 //compute the position of the single el (top and bottom and make a div) 793 const el = window.document.getElementById(lineIds[0]); 794 top = el.offsetTop; 795 height = el.offsetHeight; 796 parent = el.parentElement.parentElement; 797 if (lineIds.length > 1) { 798 const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); 799 const bottom = lastEl.offsetTop + lastEl.offsetHeight; 800 height = bottom - top; 801 } 802 if (top !== null && height !== null && parent !== null) { 803 // cook up a div (if necessary) and position it 804 let div = window.document.getElementById("code-annotation-line-highlight"); 805 if (div === null) { 806 div = window.document.createElement("div"); 807 div.setAttribute("id", "code-annotation-line-highlight"); 808 div.style.position = 'absolute'; 809 parent.appendChild(div); 810 } 811 div.style.top = top - 2 + "px"; 812 div.style.height = height + 4 + "px"; 813 div.style.left = 0; 814 let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); 815 if (gutterDiv === null) { 816 gutterDiv = window.document.createElement("div"); 817 gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); 818 gutterDiv.style.position = 'absolute'; 819 const codeCell = window.document.getElementById(targetCell); 820 const gutter = codeCell.querySelector('.code-annotation-gutter'); 821 gutter.appendChild(gutterDiv); 822 } 823 gutterDiv.style.top = top - 2 + "px"; 824 gutterDiv.style.height = height + 4 + "px"; 825 } 826 selectedAnnoteEl = annoteEl; 827 } 828 }; 829 const unselectCodeLines = () => { 830 const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; 831 elementsIds.forEach((elId) => { 832 const div = window.document.getElementById(elId); 833 if (div) { 834 div.remove(); 835 } 836 }); 837 selectedAnnoteEl = undefined; 838 }; 839 // Handle positioning of the toggle 840 window.addEventListener( 841 "resize", 842 throttle(() => { 843 elRect = undefined; 844 if (selectedAnnoteEl) { 845 selectCodeLines(selectedAnnoteEl); 846 } 847 }, 10) 848 ); 849 function throttle(fn, ms) { 850 let throttle = false;
851 let timer; 852 return (...args) => { 853 if(!throttle) { // first call gets through 854 fn.apply(this, args); 855 throttle = true; 856 } else { // all the others get throttled 857 if(timer) clearTimeout(timer); // cancel #2 858 timer = setTimeout(() => { 859 fn.apply(this, args); 860 timer = throttle = false; 861 }, ms); 862 } 863 }; 864 } 865 // Attach click handler to the DT 866 const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); 867 for (const annoteDlNode of annoteDls) { 868 annoteDlNode.addEventListener('click', (event) => { 869 const clickedEl = event.target; 870 if (clickedEl !== selectedAnnoteEl) { 871 unselectCodeLines(); 872 const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); 873 if (activeEl) { 874 activeEl.classList.remove('code-annotation-active'); 875 } 876 selectCodeLines(clickedEl); 877 clickedEl.classList.add('code-annotation-active'); 878 } else { 879 // Unselect the line 880 unselectCodeLines(); 881 clickedEl.classList.remove('code-annotation-active'); 882 } 883 }); 884 } 885 const findCites = (el) => { 886 const parentEl = el.parentElement; 887 if (parentEl) { 888 const cites = parentEl.dataset.cites; 889 if (cites) { 890 return { 891 el, 892 cites: cites.split(' ') 893 }; 894 } else { 895 return findCites(el.parentElement) 896 } 897 } else { 898 return undefined; 899 } 900 }; 901 var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); 902 for (var i=0; i<bibliorefs.length; i++) { 903 const ref = bibliorefs[i]; 904 const citeInfo = findCites(ref); 905 if (citeInfo) { 906 tippyHover(citeInfo.el, function() { 907 var popup = window.document.createElement('div'); 908 citeInfo.cites.forEach(function(cite) { 909 var citeDiv = window.document.createElement('div'); 910 citeDiv.classList.add('hanging-indent'); 911 citeDiv.classList.add('csl-entry'); 912 var biblioDiv = window.document.getElementById('ref-' + cite); 913 if (biblioDiv) { 914 citeDiv.innerHTML = biblioDiv.innerHTML; 915 } 916 popup.appendChild(citeDiv); 917 }); 918 return popup.innerHTML; 919 }); 920 } 921 } 922 }); 923 </script>
923 924</div> <!-- /content --> 925<footer class="footer"> 926 <div class="nav-footer"> 927 <div class="nav-footer-left"> 928 929 </div> 930 <div class="nav-footer-center"> 931<p>âï¸ copyright © 2026. made with â¤ï¸ by danton.</p> 932</div> 933 <div class="nav-footer-right"> 934 935 </div> 936 </div> 937</footer> 938 939 940 941 942</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.