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.8.25"> 6 7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 8 9 10<title>Personal â Jun Nguyen</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-html/quarto.js" type="module"></script>
vendor: 1 bytes, line 33
33
34<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
vendor: 1 bytes, line 34
34
35<script src="site_libs/quarto-html/axe/axe-check.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-7b89279ff1a6dce999919e0e67d4d9ec.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles"> 41<link href="site_libs/quarto-html/quarto-syntax-highlighting-dark-707d8167ce6003fca903bfe2be84ab7f.css" rel="stylesheet" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles"> 42<link href="site_libs/quarto-html/quarto-syntax-highlighting-7b89279ff1a6dce999919e0e67d4d9ec.css" rel="stylesheet" class="quarto-color-scheme-extra" id="quarto-text-highlighting-styles">
43<script src="site_libs/bootstrap/bootstrap.min.js"></script>
43 44<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> 45<link href="site_libs/bootstrap/bootstrap-fc7bbb11cac6d7b69550556e10780547.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light"> 46<link href="site_libs/bootstrap/bootstrap-dark-c1a677d7157a83f627c616e58601fb42.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="dark"> 47<link href="site_libs/bootstrap/bootstrap-fc7bbb11cac6d7b69550556e10780547.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme-extra" id="quarto-bootstrap" data-mode="light">
48<script id="quarto-search-options" type="application/json">{ 49 "location": "navbar", 50 "copy-button": false, 51 "collapse-after": 3, 52 "panel-placement": "end", 53 "type": "overlay", 54 "limit": 50, 55 "keyboard-shortcut": [ 56 "f", 57 "/", 58 "s" 59 ], 60 "show-item-context": false, 61 "language": { 62 "search-no-results-text": "No results", 63 "search-matching-documents-text": "matching documents", 64 "search-copy-link-title": "Copy link to search", 65 "search-hide-matches-text": "Hide additional matches", 66 "search-more-match-text": "more match in this document", 67 "search-more-matches-text": "more matches in this document", 68 "search-clear-button-title": "Clear", 69 "search-text-placeholder": "", 70 "search-detached-cancel-button-title": "Cancel", 71 "search-submit-button-title": "Submit", 72 "search-label": "Search" 73 } 74}</script>
74 75<link href="site_libs/htmltools-fill-0.5.9/fill.css" rel="stylesheet">
76<script src="site_libs/htmlwidgets-1.6.4/htmlwidgets.js"></script>
vendor: 1 bytes, line 76
76
77<script src="site_libs/jquery-3.6.0/jquery-3.6.0.min.js"></script>
77 78<link href="site_libs/leaflet-1.3.1/leaflet.css" rel="stylesheet">
79<script src="site_libs/leaflet-1.3.1/leaflet.js"></script>
79 80<link href="site_libs/leafletfix-1.0.0/leafletfix.css" rel="stylesheet">
81<script src="site_libs/proj4-2.6.2/proj4.min.js"></script>
vendor: 1 bytes, line 81
81
82<script src="site_libs/Proj4Leaflet-1.0.1/proj4leaflet.js"></script>
82 83<link href="site_libs/rstudio_leaflet-1.3.1/rstudio_leaflet.css" rel="stylesheet">
84<script src="site_libs/leaflet-binding-2.2.3/leaflet.js"></script>
vendor: 1 bytes, line 84
84
85<script src="site_libs/leaflet-providers-3.0.0/leaflet-providers.js"></script>
vendor: 1 bytes, line 85
85
86<script src="site_libs/leaflet-providers-plugin-2.2.3/leaflet-providers-plugin.js"></script>
86 87<link href="site_libs/leaflet-awesomemarkers-2.0.3/leaflet.awesome-markers.css" rel="stylesheet">
88<script src="site_libs/leaflet-awesomemarkers-2.0.3/leaflet.awesome-markers.min.js"></script>
88 89<link href="site_libs/ionicons-2.0.1/ionicons.min.css" rel="stylesheet"> 90 91 92<link rel="stylesheet" href="styles.css"> 93</head> 94 95<body class="nav-fixed quarto-light">
95<script id="quarto-html-before-body" type="application/javascript"> 96 const toggleBodyColorMode = (bsSheetEl) => { 97 const mode = bsSheetEl.getAttribute("data-mode"); 98 const bodyEl = window.document.querySelector("body"); 99 if (mode === "dark") { 100 bodyEl.classList.add("quarto-dark"); 101 bodyEl.classList.remove("quarto-light"); 102 } else { 103 bodyEl.classList.add("quarto-light"); 104 bodyEl.classList.remove("quarto-dark"); 105 } 106 } 107 const toggleBodyColorPrimary = () => { 108 const bsSheetEl = window.document.querySelector("link#quarto-bootstrap:not([rel=disabled-stylesheet])"); 109 if (bsSheetEl) { 110 toggleBodyColorMode(bsSheetEl); 111 } 112 } 113 const setColorSchemeToggle = (alternate) => { 114 const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle'); 115 for (let i=0; i < toggles.length; i++) { 116 const toggle = toggles[i]; 117 if (toggle) { 118 if (alternate) { 119 toggle.classList.add("alternate"); 120 } else { 121 toggle.classList.remove("alternate"); 122 } 123 } 124 } 125 }; 126 const toggleColorMode = (alternate) => { 127 // Switch the stylesheets 128 const primaryStylesheets = window.document.querySelectorAll('link.quarto-color-scheme:not(.quarto-color-alternate)'); 129 const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate'); 130 manageTransitions('#quarto-margin-sidebar .nav-link', false); 131 if (alternate) { 132 // note: dark is layered on light, we don't disable primary! 133 enableStylesheet(alternateStylesheets); 134 for (const sheetNode of alternateStylesheets) { 135 if (sheetNode.id === "quarto-bootstrap") { 136 toggleBodyColorMode(sheetNode); 137 } 138 } 139 } else { 140 disableStylesheet(alternateStylesheets); 141 enableStylesheet(primaryStylesheets) 142 toggleBodyColorPrimary(); 143 } 144 manageTransitions('#quarto-margin-sidebar .nav-link', true); 145 // Switch the toggles 146 setColorSchemeToggle(alternate) 147 // Hack to workaround the fact that safari doesn't 148 // properly recolor the scrollbar when toggling (#1455) 149 if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) { 150 manageTransitions("body", false); 151 window.scrollTo(0, 1); 152 setTimeout(() => { 153 window.scrollTo(0, 0); 154 manageTransitions("body", true); 155 }, 40); 156 } 157 } 158 const disableStylesheet = (stylesheets) => { 159 for (let i=0; i < stylesheets.length; i++) { 160 const stylesheet = stylesheets[i]; 161 stylesheet.rel = 'disabled-stylesheet'; 162 } 163 } 164 const enableStylesheet = (stylesheets) => { 165 for (let i=0; i < stylesheets.length; i++) { 166 const stylesheet = stylesheets[i]; 167 if(stylesheet.rel !== 'stylesheet') { // for Chrome, which will still FOUC without this check 168 stylesheet.rel = 'stylesheet'; 169 } 170 } 171 } 172 const manageTransitions = (selector, allowTransitions) => { 173 const els = window.document.querySelectorAll(selector); 174 for (let i=0; i < els.length; i++) { 175 const el = els[i]; 176 if (allowTransitions) { 177 el.classList.remove('notransition'); 178 } else { 179 el.classList.add('notransition'); 180 } 181 } 182 } 183 const isFileUrl = () => { 184 return window.location.protocol === 'file:'; 185 } 186 const hasAlternateSentinel = () => { 187 let styleSentinel = getColorSchemeSentinel(); 188 if (styleSentinel !== null) { 189 return styleSentinel === "alternate"; 190 } else { 191 return false; 192 } 193 } 194 const setStyleSentinel = (alternate) => { 195 const value = alternate ? "alternate" : "default"; 196 if (!isFileUrl()) { 197 window.localStorage.setItem("quarto-color-scheme", value); 198 } else { 199 localAlternateSentinel = value; 200 } 201 } 202 const getColorSchemeSentinel = () => { 203 if (!isFileUrl()) { 204 const storageValue = window.localStorage.getItem("quarto-color-scheme"); 205 return storageValue != null ? storageValue : localAlternateSentinel; 206 } else { 207 return localAlternateSentinel; 208 } 209 } 210 const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => { 211 const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light'; 212 const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark'; 213 let newTheme = ''; 214 if(authorPrefersDark) { 215 newTheme = isAlternate ? baseTheme : alternateTheme; 216 } else { 217 newTheme = isAlternate ? alternateTheme : baseTheme; 218 } 219 const changeGiscusTheme = () => { 220 // From: https://github.com/giscus/giscus/issues/336 221 const sendMessage = (message) => { 222 const iframe = document.querySelector('iframe.giscus-frame'); 223 if (!iframe) return; 224 iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); 225 } 226 sendMessage({ 227 setConfig: { 228 theme: newTheme 229 } 230 }); 231 } 232 const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null; 233 if (isGiscussLoaded) { 234 changeGiscusTheme(); 235 } 236 }; 237 const authorPrefersDark = false;
238 const darkModeDefault = authorPrefersDark; 239 document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 240 document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; 241 let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default'; 242 // Dark / light mode switch 243 window.quartoToggleColorScheme = () => { 244 // Read the current dark / light value 245 let toAlternate = !hasAlternateSentinel(); 246 toggleColorMode(toAlternate); 247 setStyleSentinel(toAlternate); 248 toggleGiscusIfUsed(toAlternate, darkModeDefault); 249 window.dispatchEvent(new Event('resize')); 250 }; 251 // Switch to dark mode if need be 252 if (hasAlternateSentinel()) { 253 toggleColorMode(true); 254 } else { 255 toggleColorMode(false); 256 } 257 </script>
257 258 259<div id="quarto-search-results"></div> 260 <header id="quarto-header" class="headroom fixed-top"> 261 <nav class="navbar navbar-expand-lg " data-bs-theme="dark"> 262 <div class="navbar-container container-fluid"> 263 <div class="navbar-brand-container mx-auto"> 264 <a href="./index.html" class="navbar-brand navbar-brand-logo"> 265 </a> 266 <a class="navbar-brand" href="./index.html"> 267 <span class="navbar-title">Jun Nguyen</span> 268 </a> 269 </div> 270 <div id="quarto-search" class="" title="Search"></div> 271 <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(); }"> 272 <span class="navbar-toggler-icon"></span> 273</button> 274 <div class="collapse navbar-collapse" id="navbarCollapse"> 275 <ul class="navbar-nav navbar-nav-scroll ms-auto"> 276 <li class="nav-item"> 277 <a class="nav-link" href="./index.html"> 278<span class="menu-text">Home</span></a> 279 </li> 280 <li class="nav-item"> 281 <a class="nav-link" href="./research.html"> 282<span class="menu-text">Research</span></a> 283 </li> 284 <li class="nav-item"> 285 <a class="nav-link" href="./teaching.html"> 286<span class="menu-text">Teaching</span></a> 287 </li> 288 <li class="nav-item"> 289 <a class="nav-link active" href="./about.html" aria-current="page"> 290<span class="menu-text">Personal</span></a> 291 </li> 292</ul> 293 </div> <!-- /navcollapse --> 294 <div class="quarto-navbar-tools"> 295 <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> 296</div> 297 </div> <!-- /container-fluid --> 298 </nav> 299</header> 300<!-- content --> 301<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-full page-navbar"> 302<!-- sidebar --> 303<!-- margin-sidebar --> 304 <div id="quarto-margin-sidebar" class="sidebar margin-sidebar zindex-bottom"> 305 306 </div> 307<!-- main --> 308<main class="content column-page" id="quarto-document-content"> 309 310 311<header id="title-block-header" class="quarto-title-block default"> 312<div class="quarto-title"> 313<h1 class="title">Personal</h1> 314</div> 315 316 317 318<div class="quarto-title-meta column-page"> 319 320 321 322 323 </div> 324 325 326 327</header> 328 329 330<div class="tabset-margin-container"></div><div class="panel-tabset"> 331<ul class="nav nav-tabs" role="tablist"><li class="nav-item" role="presentation"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" role="tab" aria-controls="tabset-1-1" aria-selected="true" href="">Travel</a></li><li class="nav-item" role="presentation"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" role="tab" aria-controls="tabset-1-2" aria-selected="false" href="">Hobbies</a></li></ul> 332<div class="tab-content"> 333<div id="tabset-1-1" class="tab-pane active" role="tabpanel" aria-labelledby="tabset-1-1-tab"> 334<p>Iâd love to travel and explore the diverse local cultures and cuisines around the world. Being in academia not only enables me to journey across the globe but also give me a chance to meet new people from various countries and cultural backgrounds. Here is an interactive map showing the footprints of my journeys thus far!</p> 335<div class="cell"> 336<div class="cell-output-display"> 337<div class="leaflet html-widget html-fill-item" id="htmlwidget-574e7852d9eb14bd129d" style="width:100%;height:464px;"></div>
338<script type="application/json" data-for="htmlwidget-574e7852d9eb14bd129d">{"x":{"options":{"crs":{"crsClass":"L.CRS.EPSG3857","code":null,"proj4def":null,"projectedBounds":null,"options":{}}},"calls":[{"method":"addProviderTiles","args":["Esri.WorldPhysical",null,null,{"errorTileUrl":"","noWrap":false,"detectRetina":false}]},{"method":"addProviderTiles","args":["CartoDB.PositronOnlyLabels",null,null,{"errorTileUrl":"","noWrap":false,"detectRetina":false}]},{"method":"addAwesomeMarkers","args":[[60.1695,48.1351,52.3676,38.7223,41.3851,41.1167,43.4623,38.3452,42.8782,42.3372,39.9864,37.7749,37.3382,30.2672,29.6516,10.8231,21.0285,16.0544,16.4637,15.8801,20.8449,21.0069,12.2388,10.2899,10.3459,10.933,51.4545,50.0755,29.4241,21.3069,35.2271,41.9028,55.6761],[24.9354,11.582,4.9041,-9.1393,2.1734,1.2494,-3.8104,-0.481,-8.5448,-7.8645,-0.0513,-122.4194,-121.8863,-97.7431,-82.3248,106.6297,105.8542,108.2022,107.5909,108.338,106.6881,107.2925,109.1966,103.984,107.0842,108.1,2.5879,14.4378,-98.4936,-157.8583,-80.84310000000001,12.4964,12.5683],{"icon":"ios-close","markerColor":"green","iconColor":"black","spin":false,"squareMarker":false,"iconRotate":0,"font":"monospace","prefix":"ion"},null,null,{"interactive":true,"draggable":false,"keyboard":true,"title":"","alt":"","zIndexOffset":0,"opacity":1,"riseOnHover":false,"riseOffset":250},null,null,null,null,["Helsinki","Munich","Amsterdam","Lisbon","Barcelona","Tarragona","Santander","Alicante","Santiago","Ourense","Castellón","San Francisco","San Jose","Austin","Gaineville","Ho Chi Minh","Ha Noi","Da Nang","Hue","Hoi An","Hai Phong","Quang Ninh","Nha Trang","Phu Quoc","Vung Tau","Binh Thuan","Bristol","Prague","San Antonio","Honolulu","Charlotte","Rome","Copenhagen"],{"interactive":false,"permanent":false,"direction":"auto","opacity":1,"offset":[0,0],"textsize":"10px","textOnly":false,"className":"","sticky":true},null]}],"limits":{"lat":[10.2899,60.1695],"lng":[-157.8583,109.1966]}},"evals":[],"jsHooks":[]}</script>
338 339</div> 340</div> 341</div> 342<div id="tabset-1-2" class="tab-pane" role="tabpanel" aria-labelledby="tabset-1-2-tab"> 343<p>Can you perceive the aroma of food wafting from these photos? I enjoy cooking and having culinary experiences at various restaurants everywhere I travel with my closed friends. Another hobby I love is creating art in Procreate and watching time-lapse videos to see the process of how things are made. I also make time for Zumba fitness and swimming to maintain a healthy work-life balance.</p> 344<div class="quarto-layout-panel" data-layout-ncol="2"> 345<div class="quarto-layout-row"> 346<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: center;"> 347<p><img src="image/DSC00188.JPG" class="img-fluid"></p> 348</div> 349<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: center;"> 350<p><img src="image/DSC08126.JPG" class="img-fluid"></p> 351</div> 352</div> 353<div class="quarto-layout-row"> 354<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: center;"> 355<p><img src="image/IMG-2239.jpg" class="img-fluid"></p> 356</div> 357<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: center;"> 358<p><img src="image/IMG-3064.JPG" class="img-fluid"></p> 359</div> 360</div> 361<div class="quarto-layout-row"> 362<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: center;"> 363<p><img src="image/DSC08130.JPG" class="img-fluid"></p> 364</div> 365</div> 366</div> 367</div> 368</div> 369</div> 370 371 372 373</main> <!-- /main -->
374<script id="quarto-html-after-body" type="application/javascript"> 375 window.document.addEventListener("DOMContentLoaded", function (event) { 376 // Ensure there is a toggle, if there isn't float one in the top right 377 if (window.document.querySelector('.quarto-color-scheme-toggle') === null) { 378 const a = window.document.createElement('a'); 379 a.classList.add('top-right'); 380 a.classList.add('quarto-color-scheme-toggle'); 381 a.href = ""; 382 a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; }; 383 const i = window.document.createElement("i"); 384 i.classList.add('bi'); 385 a.appendChild(i); 386 window.document.body.appendChild(a); 387 } 388 setColorSchemeToggle(hasAlternateSentinel()) 389 const icon = "î§"; 390 const anchorJS = new window.AnchorJS(); 391 anchorJS.options = { 392 placement: 'right', 393 icon: icon 394 }; 395 anchorJS.add('.anchored'); 396 const isCodeAnnotation = (el) => { 397 for (const clz of el.classList) { 398 if (clz.startsWith('code-annotation-')) { 399 return true; 400 } 401 } 402 return false; 403 } 404 const onCopySuccess = function(e) { 405 // button target 406 const button = e.trigger; 407 // don't keep focus 408 button.blur(); 409 // flash "checked" 410 button.classList.add('code-copy-button-checked'); 411 var currentTitle = button.getAttribute("title"); 412 button.setAttribute("title", "Copied!"); 413 let tooltip; 414 if (window.bootstrap) { 415 button.setAttribute("data-bs-toggle", "tooltip"); 416 button.setAttribute("data-bs-placement", "left"); 417 button.setAttribute("data-bs-title", "Copied!"); 418 tooltip = new bootstrap.Tooltip(button, 419 { trigger: "manual", 420 customClass: "code-copy-button-tooltip", 421 offset: [0, -8]}); 422 tooltip.show(); 423 } 424 setTimeout(function() { 425 if (tooltip) { 426 tooltip.hide(); 427 button.removeAttribute("data-bs-title"); 428 button.removeAttribute("data-bs-toggle"); 429 button.removeAttribute("data-bs-placement"); 430 } 431 button.setAttribute("title", currentTitle); 432 button.classList.remove('code-copy-button-checked'); 433 }, 1000); 434 // clear code selection 435 e.clearSelection(); 436 } 437 const getTextToCopy = function(trigger) { 438 const outerScaffold = trigger.parentElement.cloneNode(true); 439 const codeEl = outerScaffold.querySelector('code'); 440 for (const childEl of codeEl.children) { 441 if (isCodeAnnotation(childEl)) { 442 childEl.remove(); 443 } 444 } 445 return codeEl.innerText; 446 } 447 const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { 448 text: getTextToCopy 449 }); 450 clipboard.on('success', onCopySuccess); 451 if (window.document.getElementById('quarto-embedded-source-code-modal')) { 452 const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { 453 text: getTextToCopy, 454 container: window.document.getElementById('quarto-embedded-source-code-modal') 455 }); 456 clipboardModal.on('success', onCopySuccess); 457 } 458 var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); 459 var mailtoRegex = new RegExp(/^mailto:/); 460 var filterRegex = new RegExp('/' + window.location.host + '/'); 461 var isInternal = (href) => { 462 return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); 463 } 464 // Inspect non-navigation links and adorn them if external 465 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)'); 466 for (var i=0; i<links.length; i++) { 467 const link = links[i]; 468 if (!isInternal(link.href)) { 469 // undo the damage that might have been done by quarto-nav.js in the case of 470 // links that we want to consider external 471 if (link.dataset.originalHref !== undefined) { 472 link.href = link.dataset.originalHref; 473 } 474 } 475 } 476 function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { 477 const config = { 478 allowHTML: true, 479 maxWidth: 500, 480 delay: 100,
481 arrow: false, 482 appendTo: function(el) { 483 return el.parentElement; 484 }, 485 interactive: true, 486 interactiveBorder: 10, 487 theme: 'quarto', 488 placement: 'bottom-start', 489 }; 490 if (contentFn) { 491 config.content = contentFn; 492 } 493 if (onTriggerFn) { 494 config.onTrigger = onTriggerFn; 495 } 496 if (onUntriggerFn) { 497 config.onUntrigger = onUntriggerFn; 498 } 499 window.tippy(el, config); 500 } 501 const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); 502 for (var i=0; i<noterefs.length; i++) { 503 const ref = noterefs[i]; 504 tippyHover(ref, function() { 505 // use id or data attribute instead here 506 let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); 507 try { href = new URL(href).hash; } catch {} 508 const id = href.replace(/^#\/?/, ""); 509 const note = window.document.getElementById(id); 510 if (note) { 511 return note.innerHTML; 512 } else { 513 return ""; 514 } 515 }); 516 } 517 const xrefs = window.document.querySelectorAll('a.quarto-xref'); 518 const processXRef = (id, note) => { 519 // Strip column container classes 520 const stripColumnClz = (el) => { 521 el.classList.remove("page-full", "page-columns"); 522 if (el.children) { 523 for (const child of el.children) { 524 stripColumnClz(child); 525 } 526 } 527 } 528 stripColumnClz(note) 529 if (id === null || id.startsWith('sec-')) { 530 // Special case sections, only their first couple elements 531 const container = document.createElement("div"); 532 if (note.children && note.children.length > 2) { 533 container.appendChild(note.children[0].cloneNode(true)); 534 for (let i = 1; i < note.children.length; i++) { 535 const child = note.children[i]; 536 if (child.tagName === "P" && child.innerText === "") { 537 continue; 538 } else { 539 container.appendChild(child.cloneNode(true)); 540 break; 541 } 542 } 543 if (window.Quarto?.typesetMath) { 544 window.Quarto.typesetMath(container); 545 } 546 return container.innerHTML 547 } else { 548 if (window.Quarto?.typesetMath) { 549 window.Quarto.typesetMath(note); 550 } 551 return note.innerHTML; 552 } 553 } else { 554 // Remove any anchor links if they are present 555 const anchorLink = note.querySelector('a.anchorjs-link'); 556 if (anchorLink) { 557 anchorLink.remove(); 558 } 559 if (window.Quarto?.typesetMath) { 560 window.Quarto.typesetMath(note); 561 } 562 if (note.classList.contains("callout")) { 563 return note.outerHTML; 564 } else { 565 return note.innerHTML; 566 } 567 } 568 } 569 for (var i=0; i<xrefs.length; i++) { 570 const xref = xrefs[i]; 571 tippyHover(xref, undefined, function(instance) { 572 instance.disable(); 573 let url = xref.getAttribute('href'); 574 let hash = undefined; 575 if (url.startsWith('#')) { 576 hash = url; 577 } else { 578 try { hash = new URL(url).hash; } catch {} 579 } 580 if (hash) { 581 const id = hash.replace(/^#\/?/, ""); 582 const note = window.document.getElementById(id); 583 if (note !== null) { 584 try { 585 const html = processXRef(id, note.cloneNode(true)); 586 instance.setContent(html); 587 } finally { 588 instance.enable(); 589 instance.show(); 590 } 591 } else { 592 // See if we can fetch this 593 fetch(url.split('#')[0]) 594 .then(res => res.text()) 595 .then(html => { 596 const parser = new DOMParser(); 597 const htmlDoc = parser.parseFromString(html, "text/html"); 598 const note = htmlDoc.getElementById(id); 599 if (note !== null) { 600 const html = processXRef(id, note); 601 instance.setContent(html); 602 } 603 }).finally(() => { 604 instance.enable(); 605 instance.show(); 606 }); 607 } 608 } else { 609 // See if we can fetch a full url (with no hash to target)
610 // This is a special case and we should probably do some content thinning / targeting 611 fetch(url) 612 .then(res => res.text()) 613 .then(html => { 614 const parser = new DOMParser(); 615 const htmlDoc = parser.parseFromString(html, "text/html"); 616 const note = htmlDoc.querySelector('main.content'); 617 if (note !== null) { 618 // This should only happen for chapter cross references 619 // (since there is no id in the URL) 620 // remove the first header 621 if (note.children.length > 0 && note.children[0].tagName === "HEADER") { 622 note.children[0].remove(); 623 } 624 const html = processXRef(null, note); 625 instance.setContent(html); 626 } 627 }).finally(() => { 628 instance.enable(); 629 instance.show(); 630 }); 631 } 632 }, function(instance) { 633 }); 634 } 635 let selectedAnnoteEl; 636 const selectorForAnnotation = ( cell, annotation) => { 637 let cellAttr = 'data-code-cell="' + cell + '"'; 638 let lineAttr = 'data-code-annotation="' + annotation + '"'; 639 const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; 640 return selector; 641 } 642 const selectCodeLines = (annoteEl) => { 643 const doc = window.document; 644 const targetCell = annoteEl.getAttribute("data-target-cell"); 645 const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); 646 const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); 647 const lines = annoteSpan.getAttribute("data-code-lines").split(","); 648 const lineIds = lines.map((line) => { 649 return targetCell + "-" + line; 650 }) 651 let top = null; 652 let height = null; 653 let parent = null; 654 if (lineIds.length > 0) { 655 //compute the position of the single el (top and bottom and make a div) 656 const el = window.document.getElementById(lineIds[0]); 657 top = el.offsetTop; 658 height = el.offsetHeight; 659 parent = el.parentElement.parentElement; 660 if (lineIds.length > 1) { 661 const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); 662 const bottom = lastEl.offsetTop + lastEl.offsetHeight; 663 height = bottom - top; 664 } 665 if (top !== null && height !== null && parent !== null) { 666 // cook up a div (if necessary) and position it 667 let div = window.document.getElementById("code-annotation-line-highlight"); 668 if (div === null) { 669 div = window.document.createElement("div"); 670 div.setAttribute("id", "code-annotation-line-highlight"); 671 div.style.position = 'absolute'; 672 parent.appendChild(div); 673 } 674 div.style.top = top - 2 + "px"; 675 div.style.height = height + 4 + "px"; 676 div.style.left = 0; 677 let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); 678 if (gutterDiv === null) { 679 gutterDiv = window.document.createElement("div"); 680 gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); 681 gutterDiv.style.position = 'absolute'; 682 const codeCell = window.document.getElementById(targetCell); 683 const gutter = codeCell.querySelector('.code-annotation-gutter'); 684 gutter.appendChild(gutterDiv); 685 } 686 gutterDiv.style.top = top - 2 + "px"; 687 gutterDiv.style.height = height + 4 + "px"; 688 } 689 selectedAnnoteEl = annoteEl; 690 } 691 }; 692 const unselectCodeLines = () => { 693 const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; 694 elementsIds.forEach((elId) => { 695 const div = window.document.getElementById(elId); 696 if (div) { 697 div.remove(); 698 } 699 }); 700 selectedAnnoteEl = undefined; 701 }; 702 // Handle positioning of the toggle 703 window.addEventListener( 704 "resize", 705 throttle(() => { 706 elRect = undefined; 707 if (selectedAnnoteEl) { 708 selectCodeLines(selectedAnnoteEl); 709 } 710 }, 10) 711 ); 712 function throttle(fn, ms) { 713 let throttle = false;
714 let timer; 715 return (...args) => { 716 if(!throttle) { // first call gets through 717 fn.apply(this, args); 718 throttle = true; 719 } else { // all the others get throttled 720 if(timer) clearTimeout(timer); // cancel #2 721 timer = setTimeout(() => { 722 fn.apply(this, args); 723 timer = throttle = false; 724 }, ms); 725 } 726 }; 727 } 728 // Attach click handler to the DT 729 const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); 730 for (const annoteDlNode of annoteDls) { 731 annoteDlNode.addEventListener('click', (event) => { 732 const clickedEl = event.target; 733 if (clickedEl !== selectedAnnoteEl) { 734 unselectCodeLines(); 735 const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); 736 if (activeEl) { 737 activeEl.classList.remove('code-annotation-active'); 738 } 739 selectCodeLines(clickedEl); 740 clickedEl.classList.add('code-annotation-active'); 741 } else { 742 // Unselect the line 743 unselectCodeLines(); 744 clickedEl.classList.remove('code-annotation-active'); 745 } 746 }); 747 } 748 const findCites = (el) => { 749 const parentEl = el.parentElement; 750 if (parentEl) { 751 const cites = parentEl.dataset.cites; 752 if (cites) { 753 return { 754 el, 755 cites: cites.split(' ') 756 }; 757 } else { 758 return findCites(el.parentElement) 759 } 760 } else { 761 return undefined; 762 } 763 }; 764 var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); 765 for (var i=0; i<bibliorefs.length; i++) { 766 const ref = bibliorefs[i]; 767 const citeInfo = findCites(ref); 768 if (citeInfo) { 769 tippyHover(citeInfo.el, function() { 770 var popup = window.document.createElement('div'); 771 citeInfo.cites.forEach(function(cite) { 772 var citeDiv = window.document.createElement('div'); 773 citeDiv.classList.add('hanging-indent'); 774 citeDiv.classList.add('csl-entry'); 775 var biblioDiv = window.document.getElementById('ref-' + cite); 776 if (biblioDiv) { 777 citeDiv.innerHTML = biblioDiv.innerHTML; 778 } 779 popup.appendChild(citeDiv); 780 }); 781 return popup.innerHTML; 782 }); 783 } 784 } 785 }); 786 </script>
786 787</div> <!-- /content --> 788<footer class="footer"> 789 <div class="nav-footer"> 790 <div class="nav-footer-left"> 791<p>Copyright 2023, Jun Nguyen</p> 792</div> 793 <div class="nav-footer-center"> 794 795 </div> 796 <div class="nav-footer-right"> 797 798 </div> 799 </div> 800</footer> 801 802 803 804 805</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.