PageSourceSearch

https://walker-data.com/workshops.html

html walker-data.com collected 2026-10-02 10:03:59 UTC 34,089 bytes, 766 lines download raw bytes

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.7.33">
6
7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
9
10<title>Workshops – WALKER DATA</title>
11<style>
12code{white-space: pre-wrap;}
13span.smallcaps{font-variant: small-caps;}
14div.columns{display: flex; gap: min(4vw, 1.5em);}
15div.column{flex: auto; overflow-x: auto;}
16div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
17ul.task-list{list-style: none;}
18ul.task-list li input[type="checkbox"] {
19  width: 0.8em;
20  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 
21  vertical-align: middle;
22}
23</style>
24
25
26<script src="site_libs/quarto-nav/quarto-nav.js"></script>
vendor: 1 bytes, line 26
26
27<script src="site_libs/quarto-nav/headroom.min.js"></script>
vendor: 1 bytes, line 27
27
28<script src="site_libs/clipboard/clipboard.min.js"></script>
vendor: 1 bytes, line 28
28
29<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
vendor: 1 bytes, line 29
29
30<script src="site_libs/quarto-search/fuse.min.js"></script>
vendor: 1 bytes, line 30
30
31<script src="site_libs/quarto-search/quarto-search.js"></script>
31
32<meta name="quarto:offset" content="./">
33<link href="./favicon.png" rel="icon" type="image/png">
34<script src="site_libs/quarto-html/quarto.js" type="module"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
vendor: 1 bytes, line 35
35
36<script src="site_libs/quarto-html/popper.min.js"></script>
vendor: 1 bytes, line 36
36
37<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
vendor: 1 bytes, line 37
37
38<script src="site_libs/quarto-html/anchor.min.js"></script>
38
39<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
40<link href="site_libs/quarto-html/quarto-syntax-highlighting-ea385d0e468b0dd5ea5bf0780b1290d9.css" rel="stylesheet" id="quarto-text-highlighting-styles">
41<script src="site_libs/bootstrap/bootstrap.min.js"></script>
41
42<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
43<link href="site_libs/bootstrap/bootstrap-c1fac2584b48ed01fb6e278e36375074.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
44<script id="quarto-search-options" type="application/json">{
45  "location": "navbar",
46  "copy-button": false,
47  "collapse-after": 3,
48  "panel-placement": "end",
49  "type": "overlay",
50  "limit": 50,
51  "keyboard-shortcut": [
52    "f",
53    "/",
54    "s"
55  ],
56  "show-item-context": false,
57  "language": {
58    "search-no-results-text": "No results",
59    "search-matching-documents-text": "matching documents",
60    "search-copy-link-title": "Copy link to search",
61    "search-hide-matches-text": "Hide additional matches",
62    "search-more-match-text": "more match in this document",
63    "search-more-matches-text": "more matches in this document",
64    "search-clear-button-title": "Clear",
65    "search-text-placeholder": "",
66    "search-detached-cancel-button-title": "Cancel",
67    "search-submit-button-title": "Submit",
68    "search-label": "Search"
69  }
70}</script>
70
71
72
73<link rel="stylesheet" href="styles.css">
74<meta name="twitter:title" content="Workshops – WALKER DATA">
75<meta name="twitter:description" content="GIS, demographics, and data science consulting">
76<meta name="twitter:image" content="https://walker-data.com/img/dfw_3d.png">
77<meta name="twitter:image-height" content="965">
78<meta name="twitter:image-width" content="1893">
79<meta name="twitter:card" content="summary_large_image">
80</head>
81
82<body class="nav-fixed quarto-light">
83
84<div id="quarto-search-results"></div>
85  <header id="quarto-header" class="headroom fixed-top">
86    <nav class="navbar navbar-expand-lg " data-bs-theme="dark">
87      <div class="navbar-container container-fluid">
88      <div class="navbar-brand-container mx-auto">
89    <a class="navbar-brand" href="./index.html">
90    <span class="navbar-title">WALKER DATA</span>
91    </a>
92  </div>
93            <div id="quarto-search" class="" title="Search"></div>
94          <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(); }">
95  <span class="navbar-toggler-icon"></span>
96</button>
97          <div class="collapse navbar-collapse" id="navbarCollapse">
98            <ul class="navbar-nav navbar-nav-scroll ms-auto">
99  <li class="nav-item">
100    <a class="nav-link" href="./about.html"> 
101<span class="menu-text">About</span></a>
102  </li>  
103  <li class="nav-item">
104    <a class="nav-link" href="./blog.html"> 
105<span class="menu-text">Blog</span></a>
106  </li>  
107  <li class="nav-item">
108    <a class="nav-link active" href="./workshops.html" aria-current="page"> 
109<span class="menu-text">Workshops</span></a>
110  </li>  
111  <li class="nav-item compact">
112    <a class="nav-link" href="https://github.com/walkerke"> <i class="bi bi-github" role="img">
113</i> 
114<span class="menu-text"></span></a>
115  </li>  
116  <li class="nav-item compact">
117    <a class="nav-link" href="https://twitter.com/kyle_e_walker"> <i class="bi bi-twitter" role="img">
118</i> 
119<span class="menu-text"></span></a>
120  </li>  
121</ul>
122          </div> <!-- /navcollapse -->
123            <div class="quarto-navbar-tools">
124</div>
125      </div> <!-- /container-fluid -->
126    </nav>
127</header>
128<!-- content -->
129<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
130<!-- sidebar -->
131<!-- margin-sidebar -->
132    <div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
133        <nav id="TOC" role="doc-toc" class="toc-active">
134    <h2 id="toc-title">On this page</h2>
135   
136  <ul>
137  <li><a href="#mapgl-workshop-series" id="toc-mapgl-workshop-series" class="nav-link active" data-scroll-target="#mapgl-workshop-series">mapgl Workshop Series</a></li>
138  <li><a href="#location-intelligence-and-web-apps-with-shiny-workshops" id="toc-location-intelligence-and-web-apps-with-shiny-workshops" class="nav-link" data-scroll-target="#location-intelligence-and-web-apps-with-shiny-workshops">Location Intelligence and Web Apps with Shiny Workshops</a></li>
139  <li><a href="#gis-and-interactive-mapping-workshops" id="toc-gis-and-interactive-mapping-workshops" class="nav-link" data-scroll-target="#gis-and-interactive-mapping-workshops">GIS and Interactive Mapping Workshops</a></li>
140  <li><a href="#census-workshops" id="toc-census-workshops" class="nav-link" data-scroll-target="#census-workshops">2020 Census workshops</a></li>
141  </ul>
142</nav>
143    </div>
144<!-- main -->
145<main class="content page-columns page-full" id="quarto-document-content">
146
147<header id="title-block-header" class="quarto-title-block default">
148<div class="quarto-title">
149<h1 class="title">Workshops</h1>
150</div>
151
152
153
154<div class="quarto-title-meta">
155
156    
157  
158    
159  </div>
160  
161
162
163</header>
164
165
166<p><strong>WALKER DATA</strong> offers custom data science workshops tailored to the needs of your organization as well as online workshops available for purchase.</p>
167<p>Check out these testimonials from workshop participants:</p>
168<blockquote class="blockquote">
169<p>I wanted to thank you for the amazing R mapping trainings you provided. They were extremely helpful and sparked some very exciting ideas about how our 
169center can use these resources.</p>
170</blockquote>
171<blockquote class="blockquote">
172<p>One thing that really stood out was how you shared your own workflow through real-life examples. Seeing the direct application of tidycensus to our day-to-day tasks was a game-changer. It’s safe to say that we’re all feeling a lot more confident about integrating these techniques into our work.</p>
173</blockquote>
174<blockquote class="blockquote">
175<p>Your assistance in streamlining some of our existing workflows was a huge bonus. It’s not just the “how-to” that’s valuable, but also the practical insights you provided.</p>
176</blockquote>
177<blockquote class="blockquote">
178<p>Your excitement about the whole topic was infectious. It’s not easy to keep a group engaged all day, but you nailed it. Your enthusiasm made a huge difference.</p>
179</blockquote>
180<p>Reach out to <a href="mailto:[email protected]" class="email">[email protected]</a> to discuss your workshop needs today, or purchase a recorded workshop from the links below.</p>
181<section id="mapgl-workshop-series" class="level2">
182<h2 class="anchored" data-anchor-id="mapgl-workshop-series">mapgl Workshop Series</h2>
183<p>The brand-new <strong>mapgl</strong> package brings the powerful web mapping libraries Mapbox GL JS and MapLibre GL JS to R - and this workshop series is the best place to learn it. Buy the workshop bundle for 7.5 hours of workshop recordings and three step-by-step annotated tutorials to help you make stunning interactive maps with your data in R.</p>
184<p><img src="img/dfw_3d.png" class="img-fluid"></p>
185<p>You’ll get the following three workshops:</p>
186<ul>
187<li>Make Stunning Web Maps in R with the mapgl Package</li>
188<li>Dynamic Business Intelligence Apps in R with Shiny and mapgl</li>
189<li>Visualize US Census Data in R with tidycensus and mapgl</li>
190</ul>
191<script src="https://gumroad.com/js/gumroad.js"></script>
191
192
193<div class="center">
194    <a href="https://walkerdata.gumroad.com/l/mapgl-bundle"><button class="custom-button">Buy the bundle on Gumroad</button></a>
195</div>
196<br>
197<p>Don’t need all three? Each individual workshop is available for purchase as well.</p>
198</section>
199<section id="location-intelligence-and-web-apps-with-shiny-workshops" class="level2 page-columns page-full">
200<h2 class="anchored" data-anchor-id="location-intelligence-and-web-apps-with-shiny-workshops">Location Intelligence and Web Apps with Shiny Workshops</h2>
201<p>Learn essential location intelligence skills like geocoding, routing, and travel-time analytics in R, and display your results in a dynamic web mapping application! This bundle gets you five hours of custom workshops and two annotated tutorials not found anywhere else.</p>
202<script src="https://gumroad.com/js/gumroad.js"></script>
202
203
204<div class="center">
205    <a href="https://walkerdata.gumroad.com/l/li-shiny-bundle"><button class="custom-button">Buy the bundle on Gumroad</button></a>
206</div>
207<br>
208<p><br></p>
209<p><strong>Workshop 1: Location Intelligence with R and Mapbox</strong></p>
210
211<div class="no-row-height column-margin column-container"><div class="">
212<div class="quarto-figure quarto-figure-center">
213<figure class="figure">
214<p><img src="img/isochrones2.gif" class="img-fluid figure-img"></p>
215<figcaption>Animated isochrones around Nationals Park in Washington, DC</figcaption>
216</figure>
217</div>
218</div></div><p>This 2.5 hour workshop is designed to help you build skills in location intelligence to benefit your business or organization. You’ll use analytical tools like R and Mapbox to identify customer and store locations, perform travel-time analytics, build sales territories, and much more.</p>
219<div class="center">
220    <a href="https://walkerdata.gumroad.com/l/location-intelligence"><button class="custom-button">Buy on Gumroad</button></a>
221</div>
222<br>
223<p><br></p>
224<p><strong>Workshop 2: Building Web Mapping Applications with R and Shiny</strong></p>
225
226<div class="no-row-height column-margin column-container"><div class="">
227<div class="quarto-figure quarto-figure-center">
228<figure class="figure">
229<p><img src="img/geocoding_app.png" class="img-fluid figure-img"></p>
230<figcaption>A geocoding app you’ll learn to build</figcaption>
231</figure>
232</div>
233</div></div><p>This 2.5 hour workshop will teach you the fundamentals of building interactive web mapping applications using R and Shiny, R’s powerful framework for app development. By the end of the workshop, you’ll have the skills to create your own reactive mapping applications that include charts, custom design components, and more.</p>
234<div class="center">
235    <a href="https://walkerdata.gumroad.com/l/web-mapping-shiny"><button class="custom-button">Buy on Gumroad</button></a>
236</div>
237<br>
238<p><br></p>
239</section>
240<section id="gis-and-interactive-mapping-workshops" class="level2 page-columns page-full">
241<h2 class="anchored" data-anchor-id="gis-and-interactive-mapping-workshops">GIS and Interactive Mapping Workshops</h2>
242<p>Get started with Geographic Infomation Systems, spatial data analysis, and interactive mapping in R in 5 hours of custom workshops. The workshops are available for purchase separately or as a bundle for a $100 discount!</p>
243<script src="https://gumroad.com/js/gumroad.js"></script>
243
244
245<div class="center">
246    <a href="https://walkerdata.gumroad.com/l/spatial-workshop-bundle"><button class="custom-button">Buy the bundle on Gumroad</button></a>
247</div>
248<br>
249<p><br></p>
250<p><strong>Workshop 1: Getting Started With Geographic Information Systems in R</strong></p>
251
252<div class="no-row-height column-margin column-container"><div class="">
253<div class="quarto-figure quarto-figure-center">
254<figure class="figure">
255<p><img src="img/arcgis.jpeg" class="img-fluid figure-img"></p>
256<figcaption>Census data from R shown in ArcGIS Pro</figcaption>
257</figure>
258</div>
259</div></div><p>In this 2.5 hour workshop, you will gain the skills you need to get started with Geographic Information Systems using the R programming language. You’ll learn the fundamentals of doing GIS in R, gain experience with R’s powerful toolset for spatial data analysis, and learn how to connect R to desktop GIS tools like ArcGIS and QGIS.</p>
260<div class="center">
261    <a href="https://walkerdata.gumroad.com/l/gis_in_r"><button class="custom-button">Buy on Gumroad</button></a>
262</div>
263<br>
264<p><br></p>
265<p><strong>Workshop 2: Interactive Mapping with R</strong></p>
266
267<div class="no-row-height column-margin column-container"><div class="">
268<div class="quarto-figure quarto-figure-center">
269<figure class="figure">
270<p><img src="img/linked_brushing_724.gif" class="img-fluid figure-img"></p>
271<figcaption>A linked interactive map and chart with ggiraph - no Shiny required!</figcaption>
272</figure>
273</div>
274</div></div><p>In this workshop, you will learn how to make elegant interactive maps with minimal code using the R programming language. You’ll gain experience with a range of libraries for interactive mapping in R; learn how to customize and share interactive maps; and dynamically link maps and charts using R.</p>
275<div class="center">
276    <a href="https://walkerdata.gumroad.com/l/interactive-mapping"><button class="custom-button">Buy on Gumroad</button></a>
277</div>
278<br>
279<p><br></p>
280</section>
281<section id="census-workshops" class="level2 page-columns page-full">
282<h2 class="anchored" data-anchor-id="census-workshops">2020 Census workshops</h2>
283<p>Learn all about using the new 2020 Decennial Census data with R and tidycensus in 5 hours of custom workshops. You can purchase each workshop separately, or buy the workshop bundle and save $100!</p>
284<div class="center">
285    <a href="https://walkerdata.gumroad.com/l/census-workshop-bundle"><button class="custom-button">Buy the bundle on Gumroad</button></a>
286</div>
287<br>
288<p><br></p>
289<p>Workshop 1: <strong>Access and Analyze the New 2020 Decennial Census Data</strong></p>
290
291<div class="no-row-height column-margin column-container"><div class="">
292<div class="quarto-figure quarto-figure-center">
293<figure class="figure">
294<p><img src="img/image1.png" class="img-fluid figure-img"></p>
295<figcaption>Population pyramid for Lane County, OR</figcaption>
296</figure>
297</div>
298</div></div><p>In this workshop, you’ll learn how to analyze the 2020 Decennial Census’s Demographic and Housing Characteristics file using R and the tidycensus R package. Topics covered will include brand-new functionality in tidycensus to acquire and process data from the 2020 DHC file to help you analyze the data right away. You’ll gain experience with the tidyverse ecosystem of tools to reveal insights in the new data, and you’ll learn how to create stunning data visualizations to communicate those insights.</p>
299<div class="center">
300    <a href="https://walkerdata.gumroad.com/l/analyze-2020-census"><button class="custom-button">Buy on Gumroad</button></a>
301</div>
302<br>
303<p><br></p>
304<p>Workshop 2: <strong>Mapping and Spatial Analysis with the 2020 Decennial Census</strong></p>
305
306<div class="no-row-height column-margin column-container"><div class="">
307<div class="quarto-figure quarto-figure-center">
308<figure class="figure">
309<p><img src="img/image2.png" class="img-fluid figure-img"></p>
310<figcaption>Map of same-sex households in San Francisco</figcaption>
311</figure>
312</div>
313</div></div><p>Maps are powerful tools for communicating insights in the 2020 DHC data. In this workshop, you’ll learn how to use R and tidycensus to get spatial Census data seamlessly, and visualize the new data with a range of cartographic tools. You’ll also learn all about Census geography and how to perform powerful spatial analyses with 2020 Census data.</p>
314<div class="center">
315    <a href="https://walkerdata.gumroad.com/l/mapping-2020-census"><button class="custom-button">Buy on Gumroad</button></a>
316</div>
317<br>
318<p><br></p>
319<p>You get the following materials with your workshop purchase:</p>
320<ul>
321<li><p>Unlimited access to the workshop videos</p></li>
322<li><p>Custom tutorials on working with Census data not posted anywhere else</p></li>
323</ul>
324<p>For updates on these workshops and more data analysis content, subscribe to the Walker Data mailing list:</p>
325<!-- Begin MailChimp Signup Form -->
326<link href="https://cdn-images.mailchimp.com/embedcode/slim-10_7.css" rel="stylesheet" type="text/css">
327<style type="text/css">
328#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
329/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
330We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
331</style>
332<div id="mc_embed_signup">
333<form action="https://github.us15.list-manage.com/subscribe/post?u=1829a68a5eda3d301119fdcd6&amp;id=c4a53d2961" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate="">
334<div id="mc_embed_signup_scroll">
335
336<input type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required="">
337<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
338<div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_1829a68a5eda3d301119fdcd6_c4a53d2961" tabindex="-1" value=""></div>
339<div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
340</div>
341</form>
342</div>
343
344
345<!--End mc_embed_signup-->
346<style>
347 a {
348   color: #1a730f; 
349 }
350
351 .btn-outline-dark:hover {
352     color: #fff;
353     background-color: #1a730f;
354     border-color: #343a40;
355 }
356</style>
357
358
359</section>
360
361</main> <!-- /main -->
362<script id="quarto-html-after-body" type="application/javascript">
363  window.document.addEventListener("DOMContentLoaded", function (event) {
364    const icon = "";
365    const anchorJS = new window.AnchorJS();
366    anchorJS.options = {
367      placement: 'right',
368      icon: icon
369    };
370    anchorJS.add('.anchored');
371    const isCodeAnnotation = (el) => {
372      for (const clz of el.classList) {
373        if (clz.startsWith('code-annotation-')) {                     
374          return true;
375        }
376      }
377      return false;
378    }
379    const onCopySuccess = function(e) {
380      // button target
381      const button = e.trigger;
382      // don't keep focus
383      button.blur();
384      // flash "checked"
385      button.classList.add('code-copy-button-checked');
386      var currentTitle = button.getAttribute("title");
387      button.setAttribute("title", "Copied!");
388      let tooltip;
389      if (window.bootstrap) {
390        button.setAttribute("data-bs-toggle", "tooltip");
391        button.setAttribute("data-bs-placement", "left");
392        button.setAttribute("data-bs-title", "Copied!");
393        tooltip = new bootstrap.Tooltip(button, 
394          { trigger: "manual", 
395            customClass: "code-copy-button-tooltip",
396            offset: [0, -8]});
397        tooltip.show();    
398      }
399      setTimeout(function() {
400        if (tooltip) {
401          tooltip.hide();
402          button.removeAttribute("data-bs-title");
403          button.removeAttribute("data-bs-toggle");
404          button.removeAttribute("data-bs-placement");
405        }
406        button.setAttribute("title", currentTitle);
407        button.classList.remove('code-copy-button-checked');
408      }, 1000);
409      // clear code selection
410      e.clearSelection();
411    }
412    const getTextToCopy = function(trigger) {
413        const codeEl = trigger.previousElementSibling.cloneNode(true);
414        for (const childEl of codeEl.children) {
415          if (isCodeAnnotation(childEl)) {
416            childEl.remove();
417          }
418        }
419        return codeEl.innerText;
420    }
421    const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
422      text: getTextToCopy
423    });
424    clipboard.on('success', onCopySuccess);
425    if (window.document.getElementById('quarto-embedded-source-code-modal')) {
426      const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
427        text: getTextToCopy,
428        container: window.document.getElementById('quarto-embedded-source-code-modal')
429      });
430      clipboardModal.on('success', onCopySuccess);
431    }
432      var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
433      var mailtoRegex = new RegExp(/^mailto:/);
434        var filterRegex = new RegExp("https:\/\/walker-data\.com");
435      var isInternal = (href) => {
436          return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
437      }
438      // Inspect non-navigation links and adorn them if external
439     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)');
440      for (var i=0; i<links.length; i++) {
441        const link = links[i];
442        if (!isInternal(link.href)) {
443          // undo the damage that might have been done by quarto-nav.js in the case of
444          // links that we want to consider external
445          if (link.dataset.originalHref !== undefined) {
446            link.href = link.dataset.originalHref;
447          }
448        }
449      }
450    function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
451      const config = {
452        allowHTML: true,
453        maxWidth: 500,
454        delay: 100,
455        arrow: false,
456        appendTo: function(el) {
457            return el.parentElement;
458        },
459        interactive: true,
460        interactiveBorder: 10,
461        theme: 'quarto',
462        placement: 'bottom-start',
463      };
464      if (contentFn) {
465        config.content = contentFn;
466      }
467      if (onTriggerFn) {
468        config.onTrigger = onTriggerFn;
469      }
470      if (onUntriggerFn) {
471        config.onUntrigger = onUntriggerFn;
472      }
473      window.tippy(el, config); 
474    }
475    const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
476    for (var i=0; i<noterefs.length; i++) {
477      const ref = noterefs[i];
478      tippyHover(ref, function() {
479        // use id or data attribute instead here
480        let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
481        try { href = new URL(href).hash; } catch {}
482        const id = href.replace(/^#\/?/, "");
483        const note = window.document.getElementById(id);
484        if (note) {
485          return note.innerHTML;
486        } else {
487          return "";
488        }
489      });
490    }
491    const xrefs = window.document.querySelectorAll('a.quarto-xref');
492    const processXRef = (id, note) => {
493      // Strip column container classes
494      const stripColumnClz = (el) => {
495        el.classList.remove("page-full", "page-columns");
496        if (el.children) {
497          for (const child of el.children) {
498            stripColumnClz(child);
499          }
500        }
501      }
502      stripColumnClz(note)
503      if (id === null || id.startsWith('sec-')) {
504        // Special case sections, only their first couple elements
505        const container = document.createElement("div");
506        if (note.children && note.children.length > 2) {
507          container.appendChild(note.children[0].cloneNode(true));
508          for (let i = 1; i < note.children.length; i++) {
509            const child = note.children[i];
510            if (child.tagName === "P" && child.innerText === "") {
511              continue;
512            } else {
513              container.appendChild(child.cloneNode(true));
514              break;
515            }
516          }
517          if (window.Quarto?.typesetMath) {
518            window.Quarto.typesetMath(container);
519          }
520          return container.innerHTML
521        } else {
522          if (window.Quarto?.typesetMath) {
523            window.Quarto.typesetMath(note);
524          }
525          return note.innerHTML;
526        }
527      } else {
528        // Remove any anchor links if they are present
529        const anchorLink = note.querySelector('a.anchorjs-link');
530        if (anchorLink) {
531          anchorLink.remove();
532        }
533        if (window.Quarto?.typesetMath) {
534          window.Quarto.typesetMath(note);
535        }
536        if (note.classList.contains("callout")) {
537          return note.outerHTML;
538        } else {
539          return note.innerHTML;
540        }
541      }
542    }
543    for (var i=0; i<xrefs.length; i++) {
544      const xref = xrefs[i];
545      tippyHover(xref, undefined, function(instance) {
546        instance.disable();
547        let url = xref.getAttribute('href');
548        let hash = undefined; 
549        if (url.startsWith('#')) {
550          hash = url;
551        } else {
552          try { hash = new URL(url).hash; } catch {}
553        }
554        if (hash) {
555          const id = hash.replace(/^#\/?/, "");
556          const note = window.document.getElementById(id);
557          if (note !== null) {
558            try {
559              const html = processXRef(id, note.cloneNode(true));
560              instance.setContent(html);
561            } finally {
562              instance.enable();
563              instance.show();
564            }
565          } else {
566            // See if we can fetch this
567            fetch(url.split('#')[0])
568            .then(res => res.text())
569            .then(html => {
570              const parser = new DOMParser();
571              const htmlDoc = parser.parseFromString(html, "text/html");
572              const note = htmlDoc.getElementById(id);
573              if (note !== null) {
574                const html = processXRef(id, note);
575                instance.setContent(html);
576              } 
577            }).finally(() => {
578              instance.enable();
579              instance.show();
580            });
581          }
582        } else {
583          // See if we can fetch a full url (with no hash to target)
584          // This is a special case and we should probably do some content thinning / targeting
585          fetch(url)
586          .then(res => res.text())
587          .then(html => {
588            const parser = new DOMParser();
589            const htmlDoc = parser.parseFromString(html, "text/html");
590            const note = htmlDoc.querySelector('main.content');
591            if (note !== null) {
592              // This should only happen for chapter cross references
593              // (since there is no id in the URL)
594              // remove the first header
595              if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
596                note.children[0].remove();
597              }
598              const html = processXRef(null, note);
599              instance.setContent(html);
600            } 
601          }).finally(() => {
602            instance.enable();
603            instance.show();
604          });
605        }
606      }, function(instance) {
607      });
608    }
609        let selectedAnnoteEl;
610        const selectorForAnnotation = ( cell, annotation) => {
611          let cellAttr = 'data-code-cell="' + cell + '"';
612          let lineAttr = 'data-code-annotation="' +  annotation + '"';
613          const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
614          return selector;
615        }
616        const selectCodeLines = (annoteEl) => {
617          const doc = window.document;
618          const targetCell = annoteEl.getAttribute("data-target-cell");
619          const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
620          const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
621          const lines = annoteSpan.getAttribute("data-code-lines").split(",");
622          const lineIds = lines.map((line) => {
623            return targetCell + "-" + line;
624          })
625          let top = null;
626          let height = null;
627          let parent = null;
628          if (lineIds.length > 0) {
629              //compute the position of the single el (top and bottom and make a div)
630              const el = window.document.getElementById(lineIds[0]);
631              top = el.offsetTop;
632              height = el.offsetHeight;
633              parent = el.parentElement.parentElement;
634            if (lineIds.length > 1) {
635              const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
636              const bottom = lastEl.offsetTop + lastEl.offsetHeight;
637              height = bottom - top;
638            }
639            if (top !== null && height !== null && parent !== null) {
640              // cook up a div (if necessary) and position it 
641              let div = window.document.getElementById("code-annotation-line-highlight");
642              if (div === null) {
643                div = window.document.createElement("div");
644                div.setAttribute("id", "code-annotation-line-highlight");
645                div.style.position = 'absolute';
646                parent.appendChild(div);
647              }
648              div.style.top = top - 2 + "px";
649              div.style.height = height + 4 + "px";
650              div.style.left = 0;
651              let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
652              if (gutterDiv === null) {
653                gutterDiv = window.document.createElement("div");
654                gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
655                gutterDiv.style.position = 'absolute';
656                const codeCell = window.document.getElementById(targetCell);
657                const gutter = codeCell.querySelector('.code-annotation-gutter');
658                gutter.appendChild(gutterDiv);
659              }
660              gutterDiv.style.top = top - 2 + "px";
661              gutterDiv.style.height = height + 4 + "px";
662            }
663            selectedAnnoteEl = annoteEl;
664          }
665        };
666        const unselectCodeLines = () => {
667          const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
668          elementsIds.forEach((elId) => {
669            const div = window.document.getElementById(elId);
670            if (div) {
671              div.remove();
672            }
673          });
674          selectedAnnoteEl = undefined;
675        };
676          // Handle positioning of the toggle
677      window.addEventListener(
678        "resize",
679        throttle(() => {
680          elRect = undefined;
681          if (selectedAnnoteEl) {
682            selectCodeLines(selectedAnnoteEl);
683          }
684        }, 10)
685      );
686      function throttle(fn, ms) {
687      let throttle = false;
688      let timer;
689        return (...args) => {
690          if(!throttle) { // first call gets through
691              fn.apply(this, args);
692              throttle = true;
693          } else { // all the others get throttled
694              if(timer) clearTimeout(timer); // cancel #2
695              timer = setTimeout(() => {
696                fn.apply(this, args);
697                timer = throttle = false;
698              }, ms);
699          }
700        };
701      }
702        // Attach click handler to the DT
703        const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
704        for (const annoteDlNode of annoteDls) {
705          annoteDlNode.addEventListener('click', (event) => {
706            const clickedEl = event.target;
707            if (clickedEl !== selectedAnnoteEl) {
708              unselectCodeLines();
709              const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
710              if (activeEl) {
711                activeEl.classList.remove('code-annotation-active');
712              }
713              selectCodeLines(clickedEl);
714              clickedEl.classList.add('code-annotation-active');
715            } else {
716              // Unselect the line
717              unselectCodeLines();
718              clickedEl.classList.remove('code-annotation-active');
719            }
720          });
721        }
722    const findCites = (el) => {
723      const parentEl = el.parentElement;
724      if (parentEl) {
725        const cites = parentEl.dataset.cites;
726        if (cites) {
727          return {
728            el,
729            cites: cites.split(' ')
730          };
731        } else {
732          return findCites(el.parentElement)
733        }
734      } else {
735        return undefined;
736      }
737    };
738    var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
739    for (var i=0; i<bibliorefs.length; i++) {
740      const ref = bibliorefs[i];
741      const citeInfo = findCites(ref);
742      if (citeInfo) {
743        tippyHover(citeInfo.el, function() {
744          var popup = window.document.createElement('div');
745          citeInfo.cites.forEach(function(cite) {
746            var citeDiv = window.document.createElement('div');
747            citeDiv.classList.add('hanging-indent');
748            citeDiv.classList.add('csl-entry');
749            var biblioDiv = window.document.getElementById('ref-' + cite);
750            if (biblioDiv) {
751              citeDiv.innerHTML = biblioDiv.innerHTML;
752            }
753            popup.appendChild(citeDiv);
754          });
755          return popup.innerHTML;
756        });
757      }
758    }
759  });
760  </script>
760
761</div> <!-- /content -->
762
763
764
765
766</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.