PageSourceSearch

https://mavrxlab.org/projects

html mavrxlab.org collected 2026-10-06 13:17:25 UTC 26,886 bytes, 724 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.6.40">
6
7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
9
10<title>Projects – MA{VR}X Lab</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<script src="site_libs/quarto-listing/list.min.js"></script>
vendor: 1 bytes, line 33
33
34<script src="site_libs/quarto-listing/quarto-listing.js"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/quarto.js"></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-549806ee2085284f45b00abea8c6df48.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-d83fba8907f73068b64e07941be842b2.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
44<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/all.css" rel="stylesheet">
45<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/latex-fontsize.css" rel="stylesheet">
46<script id="quarto-search-options" type="application/json">{
47  "location": "navbar",
48  "copy-button": false,
49  "collapse-after": 3,
50  "panel-placement": "end",
51  "type": "overlay",
52  "limit": 50,
53  "keyboard-shortcut": [
54    "f",
55    "/",
56    "s"
57  ],
58  "show-item-context": false,
59  "language": {
60    "search-no-results-text": "No results",
61    "search-matching-documents-text": "matching documents",
62    "search-copy-link-title": "Copy link to search",
63    "search-hide-matches-text": "Hide additional matches",
64    "search-more-match-text": "more match in this document",
65    "search-more-matches-text": "more matches in this document",
66    "search-clear-button-title": "Clear",
67    "search-text-placeholder": "",
68    "search-detached-cancel-button-title": "Cancel",
69    "search-submit-button-title": "Submit",
70    "search-label": "Search"
71  }
72}</script>
vendor: 1 bytes, line 72
72
73<script>
74
75  window.document.addEventListener("DOMContentLoaded", function (_event) {
76    const listingTargetEl = window.document.querySelector('#listing-project-list .list');
77    if (!listingTargetEl) {
78      // No listing discovered, do not attach.
79      return; 
80    }
81
82    const options = {
83      valueNames: ['listing-image','listing-title','listing-description',{ data: ['index'] },{ data: ['categories'] },{ data: ['listing-date-sort'] },{ data: ['listing-file-modified-sort'] }],
84      
85      searchColumns: ["listing-title","listing-author","listing-image","listing-description"],
86    };
87
88    window['quarto-listings'] = window['quarto-listings'] || {};
89    window['quarto-listings']['listing-project-list'] = new List('listing-project-list', options);
90
91    if (window['quarto-listing-loaded']) {
92      window['quarto-listing-loaded']();
93    }
94  });
95
96  window.addEventListener('hashchange',() => {
97    if (window['quarto-listing-loaded']) {
98      window['quarto-listing-loaded']();
99    }
100  })
101  </script>
101
102<!-- Proxima Nova reference. -->
103<link href="https://use.typekit.net/emv3zbo.css" rel="stylesheet" crossorigin="anonymous">
104<!-- Arizona Bootstrap reference. -->
105<link rel="stylesheet" href="https://cdn.digital.arizona.edu/lib/arizona-bootstrap/2.0.19/css/arizona-bootstrap.min.css" crossorigin="anonymous">
106
107  
107<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
107
108  
108<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
108
109
110<script type="text/javascript">
111const typesetMath = (el) => {
112  if (window.MathJax) {
113    // MathJax Typeset
114    window.MathJax.typeset([el]);
115  } else if (window.katex) {
116    // KaTeX Render
117    var mathElements = el.getElementsByClassName("math");
118    var macros = [];
119    for (var i = 0; i < mathElements.length; i++) {
120      var texText = mathElements[i].firstChild;
121      if (mathElements[i].tagName == "SPAN") {
122        window.katex.render(texText.data, mathElements[i], {
123          displayMode: mathElements[i].classList.contains('display'),
124          throwOnError: false,
125          macros: macros,
126          fleqn: false
127        });
128      }
129    }
130  }
131}
132window.Quarto = {
133  typesetMath
134};
135</script>
135
136
137<link rel="stylesheet" href="styles.css">
138<meta property="og:title" content="Projects – MA{VR}X Lab">
139<meta property="og:description" content="Official site for the University of Arizona’s MA{VR}X Lab">
140<meta property="og:image" content="https://mavrxlab.org/projects/ed3/featured.jpeg">
141<meta property="og:site_name" content="MA{VR}X Lab">
142</head>
143
144<body class="nav-fixed">
145
146<div id="quarto-search-results"></div>
147  <header id="quarto-header" class="headroom fixed-top quarto-banner">
148    <nav class="navbar navbar-expand-lg " data-bs-theme="dark">
149      <div class="navbar-container container-fluid">
150      <div class="navbar-brand-container mx-auto">
151    <a class='navbar-brand navbar-brand-logo' href='/'>
152    <img src="./assets/images/big-banner-white.png" alt="MA{VR}X Lab" class="navbar-logo">
153    </a>
154  </div>
155            <div id="quarto-search" class="" title="Search"></div>
156          <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(); }">
157  <span class="navbar-toggler-icon"></span>
158</button>
159          <div class="collapse navbar-collapse" id="navbarCollapse">
160            <ul class="navbar-nav navbar-nav-scroll me-auto">
161  <li class="nav-item">
162    <a class='nav-link' href='/'> 
163<span class="menu-text">Home</span></a>
164  </li>  
165  <li class="nav-item">
166    <a class="nav-link" href="./about/"> 
167<span class="menu-text">About</span></a>
168  </li>  
169  <li class="nav-item">
170    <a class='nav-link' href='/news'> 
171<span class="menu-text">News</span></a>
172  </li>  
173  <li class="nav-item">
174    <a aria-current='page' class='nav-link active' href='/projects'> 
175<span class="menu-text">Projects</span></a>
176  </li>  
177  <li class="nav-item">
178    <a class="nav-link" href="./team/"> 
179<span class="menu-text">Team</span></a>
180  </li>  
181  <li class="nav-item">
182    <a class="nav-link" href="./resources/"> 
183<span class="menu-text">Resources</span></a>
184  </li>  
185</ul>
186            <ul class="navbar-nav navbar-nav-scroll ms-auto">
187  <li class="nav-item compact">
188    <a class="nav-link" href="./index.xml"> <i class="bi bi-rss" role="img">
189</i> 
190<span class="menu-text"></span></a>
191  </li>  
192</ul>
193          </div> <!-- /navcollapse -->
194            <div class="quarto-navbar-tools">
195</div>
196      </div> <!-- /container-fluid -->
197    </nav>
198</header>
199<!-- content -->
200<header id="title-block-header" class="quarto-title-block default page-columns page-full">
201  <div class="quarto-title-banner page-columns page-full">
202    <div class="quarto-title column-page">
203      <h1 class="title">Projects</h1>
204                      </div>
205  </div>
206    
207  
208  <div class="quarto-title-meta column-page">
209
210      
211    
212      
213    </div>
214    
215  
216  </header><div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-full page-navbar">
217<!-- sidebar -->
218<!-- margin-sidebar -->
219    <div id="quarto-margin-sidebar" class="sidebar margin-sidebar zindex-bottom">
220        
221    </div>
222<!-- main -->
223<main class="content quarto-banner-title-block column-page" id="quarto-document-content">
224
225
226
227
228
229<p>Current projects going on in the lab. Dig into each project to learn more and see related posts, public scholarship, and academic output.</p>
230<div id="listing-project-list" class="quarto-listing quarto-listing-container-grid">
231<div class="list grid quarto-listing-cols-3">
232<div class="g-col-1" data-index="0" data-listing-file-modified-sort="1738692796139" data-listing-reading-time-sort="1" data-listing-word-count-sort="97">
233<a class='quarto-grid-link' href='/projects/ed3/'>
234<div class="quarto-grid-item card h-100 card-left">
235<p class="card-img-top">
236<img loading="lazy" src="./projects/ed3/featured.jpeg" class="thumbnail-image card-img" style="height: 150px;">
237</p>
238<div class="card-body post-contents">
239<h5 class="no-anchor card-title listing-title">
240Ed3: Web3 and Education
241</h5>
242<div class="card-text listing-description">
243<p>This project focuses on so-called Web3 technologies and their influence on and use in education.</p>
244</div>
245</div>
246</div>
247</a>
248</div>
249<div class="g-col-1" data-index="1" data-listing-file-modified-sort="1738692796143" data-listing-reading-time-sort="1" data-listing-word-count-sort="33">
250<a class='quarto-grid-link' href='/projects/parasocial/'>
251<div class="quarto-grid-item card h-100 card-left">
252<p class="card-img-top">
253<img loading="lazy" src="./projects/parasocial/featured.jpeg" class="thumbnail-image card-img" style="height: 150px;">
254</p>
255<div class="card-body post-contents">
256<h5 class="no-anchor card-title listing-title">
257Extended Reality Parasocial Interaction
258</h5>
259<div class="card-text listing-description">
260<p>A study undertaken to explore the nuanced parasocial interaction and relationships when in extended reality environments.</p>
261</div>
262</div>
263</div>
264</a>
265</div>
266</div>
267<div class="listing-no-matching d-none">
268No matching items
269</div>
270</div>
271
272
273
274
275</main> <!-- /main -->
276<script id="quarto-html-after-body" type="application/javascript">
277window.document.addEventListener("DOMContentLoaded", function (event) {
278  const toggleBodyColorMode = (bsSheetEl) => {
279    const mode = bsSheetEl.getAttribute("data-mode");
280    const bodyEl = window.document.querySelector("body");
281    if (mode === "dark") {
282      bodyEl.classList.add("quarto-dark");
283      bodyEl.classList.remove("quarto-light");
284    } else {
285      bodyEl.classList.add("quarto-light");
286      bodyEl.classList.remove("quarto-dark");
287    }
288  }
289  const toggleBodyColorPrimary = () => {
290    const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
291    if (bsSheetEl) {
292      toggleBodyColorMode(bsSheetEl);
293    }
294  }
295  toggleBodyColorPrimary();  
296  const icon = "";
297  const anchorJS = new window.AnchorJS();
298  anchorJS.options = {
299    placement: 'right',
300    icon: icon
301  };
302  anchorJS.add('.anchored');
303  const isCodeAnnotation = (el) => {
304    for (const clz of el.classList) {
305      if (clz.startsWith('code-annotation-')) {                     
306        return true;
307      }
308    }
309    return false;
310  }
311  const onCopySuccess = function(e) {
312    // button target
313    const button = e.trigger;
314    // don't keep focus
315    button.blur();
316    // flash "checked"
317    button.classList.add('code-copy-button-checked');
318    var currentTitle = button.getAttribute("title");
319    button.setAttribute("title", "Copied!");
320    let tooltip;
321    if (window.bootstrap) {
322      button.setAttribute("data-bs-toggle", "tooltip");
323      button.setAttribute("data-bs-placement", "left");
324      button.setAttribute("data-bs-title", "Copied!");
325      tooltip = new bootstrap.Tooltip(button, 
326        { trigger: "manual", 
327          customClass: "code-copy-button-tooltip",
328          offset: [0, -8]});
329      tooltip.show();    
330    }
331    setTimeout(function() {
332      if (tooltip) {
333        tooltip.hide();
334        button.removeAttribute("data-bs-title");
335        button.removeAttribute("data-bs-toggle");
336        button.removeAttribute("data-bs-placement");
337      }
338      button.setAttribute("title", currentTitle);
339      button.classList.remove('code-copy-button-checked');
340    }, 1000);
341    // clear code selection
342    e.clearSelection();
343  }
344  const getTextToCopy = function(trigger) {
345      const codeEl = trigger.previousElementSibling.cloneNode(true);
346      for (const childEl of codeEl.children) {
347        if (isCodeAnnotation(childEl)) {
348          childEl.remove();
349        }
350      }
351      return codeEl.innerText;
352  }
353  const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
354    text: getTextToCopy
355  });
356  clipboard.on('success', onCopySuccess);
357  if (window.document.getElementById('quarto-embedded-source-code-modal')) {
358    const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
359      text: getTextToCopy,
360      container: window.document.getElementById('quarto-embedded-source-code-modal')
361    });
362    clipboardModal.on('success', onCopySuccess);
363  }
364    var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
365    var mailtoRegex = new RegExp(/^mailto:/);
366      var filterRegex = new RegExp("https:\/\/mavrxlab\.org");
367    var isInternal = (href) => {
368        return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
369    }
370    // Inspect non-navigation links and adorn them if external
371 	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)');
372    for (var i=0; i<links.length; i++) {
373      const link = links[i];
374      if (!isInternal(link.href)) {
375        // undo the damage that might have been done by quarto-nav.js in the case of
376        // links that we want to consider external
377        if (link.dataset.originalHref !== undefined) {
378          link.href = link.dataset.originalHref;
379        }
380      }
381    }
382  function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
383    const config = {
384      allowHTML: true,
385      maxWidth: 500,
386      delay: 100,
387      arrow: false,
388      appendTo: function(el) {
389          return el.parentElement;
390      },
391      interactive: true,
392      interactiveBorder: 10,
393      theme: 'quarto',
394      placement: 'bottom-start',
395    };
396    if (contentFn) {
397      config.content = contentFn;
398    }
399    if (onTriggerFn) {
400      config.onTrigger = onTriggerFn;
401    }
402    if (onUntriggerFn) {
403      config.onUntrigger = onUntriggerFn;
404    }
405    window.tippy(el, config); 
406  }
407  const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
408  for (var i=0; i<noterefs.length; i++) {
409    const ref = noterefs[i];
410    tippyHover(ref, function() {
411      // use id or data attribute instead here
412      let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
413      try { href = new URL(href).hash; } catch {}
414      const id = href.replace(/^#\/?/, "");
415      const note = window.document.getElementById(id);
416      if (note) {
417        return note.innerHTML;
418      } else {
419        return "";
420      }
421    });
422  }
423  const xrefs = window.document.querySelectorAll('a.quarto-xref');
424  const processXRef = (id, note) => {
425    // Strip column container classes
426    const stripColumnClz = (el) => {
427      el.classList.remove("page-full", "page-columns");
428      if (el.children) {
429        for (const child of el.children) {
430          stripColumnClz(child);
431        }
432      }
433    }
434    stripColumnClz(note)
435    if (id === null || id.startsWith('sec-')) {
436      // Special case sections, only their first couple elements
437      const container = document.createElement("div");
438      if (note.children && note.children.length > 2) {
439        container.appendChild(note.children[0].cloneNode(true));
440        for (let i = 1; i < note.children.length; i++) {
441          const child = note.children[i];
442          if (child.tagName === "P" && child.innerText === "") {
443            continue;
444          } else {
445            container.appendChild(child.cloneNode(true));
446            break;
447          }
448        }
449        if (window.Quarto?.typesetMath) {
450          window.Quarto.typesetMath(container);
451        }
452        return container.innerHTML
453      } else {
454        if (window.Quarto?.typesetMath) {
455          window.Quarto.typesetMath(note);
456        }
457        return note.innerHTML;
458      }
459    } else {
460      // Remove any anchor links if they are present
461      const anchorLink = note.querySelector('a.anchorjs-link');
462      if (anchorLink) {
463        anchorLink.remove();
464      }
465      if (window.Quarto?.typesetMath) {
466        window.Quarto.typesetMath(note);
467      }
468      if (note.classList.contains("callout")) {
469        return note.outerHTML;
470      } else {
471        return note.innerHTML;
472      }
473    }
474  }
475  for (var i=0; i<xrefs.length; i++) {
476    const xref = xrefs[i];
477    tippyHover(xref, undefined, function(instance) {
478      instance.disable();
479      let url = xref.getAttribute('href');
480      let hash = undefined; 
481      if (url.startsWith('#')) {
482        hash = url;
483      } else {
484        try { hash = new URL(url).hash; } catch {}
485      }
486      if (hash) {
487        const id = hash.replace(/^#\/?/, "");
488        const note = window.document.getElementById(id);
489        if (note !== null) {
490          try {
491            const html = processXRef(id, note.cloneNode(true));
492            instance.setContent(html);
493          } finally {
494            instance.enable();
495            instance.show();
496          }
497        } else {
498          // See if we can fetch this
499          fetch(url.split('#')[0])
500          .then(res => res.text())
501          .then(html => {
502            const parser = new DOMParser();
503            const htmlDoc = parser.parseFromString(html, "text/html");
504            const note = htmlDoc.getElementById(id);
505            if (note !== null) {
506              const html = processXRef(id, note);
507              instance.setContent(html);
508            } 
509          }).finally(() => {
510            instance.enable();
511            instance.show();
512          });
513        }
514      } else {
515        // See if we can fetch a full url (with no hash to target)
516        // This is a special case and we should probably do some content thinning / targeting
517        fetch(url)
518        .then(res => res.text())
519        .then(html => {
520          const parser = new DOMParser();
521          const htmlDoc = parser.parseFromString(html, "text/html");
522          const note = htmlDoc.querySelector('main.content');
523          if (note !== null) {
524            // This should only happen for chapter cross references
525            // (since there is no id in the URL)
526            // remove the first header
527            if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
528              note.children[0].remove();
529            }
530            const html = processXRef(null, note);
531            instance.setContent(html);
532          } 
533        }).finally(() => {
534          instance.enable();
535          instance.show();
536        });
537      }
538    }, function(instance) {
539    });
540  }
541      let selectedAnnoteEl;
542      const selectorForAnnotation = ( cell, annotation) => {
543        let cellAttr = 'data-code-cell="' + cell + '"';
544        let lineAttr = 'data-code-annotation="' +  annotation + '"';
545        const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
546        return selector;
547      }
548      const selectCodeLines = (annoteEl) => {
549        const doc = window.document;
550        const targetCell = annoteEl.getAttribute("data-target-cell");
551        const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
552        const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
553        const lines = annoteSpan.getAttribute("data-code-lines").split(",");
554        const lineIds = lines.map((line) => {
555          return targetCell + "-" + line;
556        })
557        let top = null;
558        let height = null;
559        let parent = null;
560        if (lineIds.length > 0) {
561            //compute the position of the single el (top and bottom and make a div)
562            const el = window.document.getElementById(lineIds[0]);
563            top = el.offsetTop;
564            height = el.offsetHeight;
565            parent = el.parentElement.parentElement;
566          if (lineIds.length > 1) {
567            const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
568            const bottom = lastEl.offsetTop + lastEl.offsetHeight;
569            height = bottom - top;
570          }
571          if (top !== null && height !== null && parent !== null) {
572            // cook up a div (if necessary) and position it 
573            let div = window.document.getElementById("code-annotation-line-highlight");
574            if (div === null) {
575              div = window.document.createElement("div");
576              div.setAttribute("id", "code-annotation-line-highlight");
577              div.style.position = 'absolute';
578              parent.appendChild(div);
579            }
580            div.style.top = top - 2 + "px";
581            div.style.height = height + 4 + "px";
582            div.style.left = 0;
583            let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
584            if (gutterDiv === null) {
585              gutterDiv = window.document.createElement("div");
586              gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
587              gutterDiv.style.position = 'absolute';
588              const codeCell = window.document.getElementById(targetCell);
589              const gutter = codeCell.querySelector('.code-annotation-gutter');
590              gutter.appendChild(gutterDiv);
591            }
592            gutterDiv.style.top = top - 2 + "px";
593            gutterDiv.style.height = height + 4 + "px";
594          }
595          selectedAnnoteEl = annoteEl;
596        }
597      };
598      const unselectCodeLines = () => {
599        const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
600        elementsIds.forEach((elId) => {
601          const div = window.document.getElementById(elId);
602          if (div) {
603            div.remove();
604          }
605        });
606        selectedAnnoteEl = undefined;
607      };
608        // Handle positioning of the toggle
609    window.addEventListener(
610      "resize",
611      throttle(() => {
612        elRect = undefined;
613        if (selectedAnnoteEl) {
614          selectCodeLines(selectedAnnoteEl);
615        }
616      }, 10)
617    );
618    function throttle(fn, ms) {
619    let throttle = false;
620    let timer;
621      return (...args) => {
622        if(!throttle) { // first call gets through
623            fn.apply(this, args);
624            throttle = true;
625        } else { // all the others get throttled
626            if(timer) clearTimeout(timer); // cancel #2
627            timer = setTimeout(() => {
628              fn.apply(this, args);
629              timer = throttle = false;
630            }, ms);
631        }
632      };
633    }
634      // Attach click handler to the DT
635      const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
636      for (const annoteDlNode of annoteDls) {
637        annoteDlNode.addEventListener('click', (event) => {
638          const clickedEl = event.target;
639          if (clickedEl !== selectedAnnoteEl) {
640            unselectCodeLines();
641            const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
642            if (activeEl) {
643              activeEl.classList.remove('code-annotation-active');
644            }
645            selectCodeLines(clickedEl);
646            clickedEl.classList.add('code-annotation-active');
647          } else {
648            // Unselect the line
649            unselectCodeLines();
650            clickedEl.classList.remove('code-annotation-active');
651          }
652        });
653      }
654  const findCites = (el) => {
655    const parentEl = el.parentElement;
656    if (parentEl) {
657      const cites = parentEl.dataset.cites;
658      if (cites) {
659        return {
660          el,
661          cites: cites.split(' ')
662        };
663      } else {
664        return findCites(el.parentElement)
665      }
666    } else {
667      return undefined;
668    }
669  };
670  var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
671  for (var i=0; i<bibliorefs.length; i++) {
672    const ref = bibliorefs[i];
673    const citeInfo = findCites(ref);
674    if (citeInfo) {
675      tippyHover(citeInfo.el, function() {
676        var popup = window.document.createElement('div');
677        citeInfo.cites.forEach(function(cite) {
678          var citeDiv = window.document.createElement('div');
679          citeDiv.classList.add('hanging-indent');
680          citeDiv.classList.add('csl-entry');
681          var biblioDiv = window.document.getElementById('ref-' + cite);
682          if (biblioDiv) {
683            citeDiv.innerHTML = biblioDiv.innerHTML;
684          }
685          popup.appendChild(citeDiv);
686        });
687        return popup.innerHTML;
688      });
689    }
690  }
691});
692</script>
692
693</div> <!-- /content -->
694<footer class="footer">
695  <div class="nav-footer">
696    <div class="nav-footer-left">
697<p><i class="fa-regular fa-copyright" aria-label="copyright"></i> Ryan Straight, 2024<br> All content licensed under <i class="fa-brands fa-creative-commons" aria-label="creative-commons"></i> <i class="fa-brands fa-creative-commons-by" aria-label="creative-commons-by"></i> <i class="fa-brands fa-creative-commons-sa" aria-label="creative-commons-sa"></i> <i class="fa-brands fa-creative-commons-nc" aria-label="creative-commons-nc"></i> <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">(CC BY-NC-SA 4.0)</a></p>
698</div>   
699    <div class="nav-footer-center">
700      <ul class="footer-items list-unstyled">
701    <li class="nav-item compact">
702    <a class="nav-link" href="https://github.com/mavrxlab/">
703      <i class="bi bi-github" role="img" aria-label="GitHub">
704</i> 
705    </a>
706  </li>  
707    <li class="nav-item compact">
708    <a class="nav-link" href="https://hci.social/@mavrxlab/">
709      <i class="bi bi-mastodon" role="img" aria-label="Mastodon">
710</i> 
711    </a>
712  </li>  
713</ul>
714    </div>
715    <div class="nav-footer-right">
716<p>Made with <i class="fa-brands fa-r-project" aria-label="r-project"></i> and <a href="https://quarto.org/">Quarto</a><br> with much inspiration from <a href="https://github.com/andreashandel/andreashandelwebsite">Andreas Handel</a>.</p>
717</div>
718  </div>
719</footer>
720
721
722
723
724</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.