PageSourceSearch

https://xpsong.com/

html xpsong.com collected 2026-10-09 22:09:13 UTC 24,146 bytes, 619 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.27">
6
7<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
9
10<title>Dr.&nbsp;Xiao Ping Song – XP Song</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="./images/icon.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>
37
38<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
39<link href="site_libs/quarto-html/quarto-syntax-highlighting-985aa47af68dae11cd4d235c71fb941e.css" rel="stylesheet" id="quarto-text-highlighting-styles">
40<script src="site_libs/bootstrap/bootstrap.min.js"></script>
40
41<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
42<link href="site_libs/bootstrap/bootstrap-352d2168f5014ef2ecf06eb4ef66f56e.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
43<link href="site_libs/quarto-contrib/academicons-1.9.2/all.css" rel="stylesheet">
44<link href="site_libs/quarto-contrib/academicons-1.9.2/size.css" rel="stylesheet">
45<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/all.css" rel="stylesheet">
46<link href="site_libs/quarto-contrib/fontawesome6-0.1.0/latex-fontsize.css" rel="stylesheet">
47<script src="site_libs/quarto-contrib/iconify-1.0.7/iconify-icon.min.js"></script>
vendor: 1 bytes, line 47
47
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  "language": {
61    "search-no-results-text": "No results",
62    "search-matching-documents-text": "matching documents",
63    "search-copy-link-title": "Copy link to search",
64    "search-hide-matches-text": "Hide additional matches",
65    "search-more-match-text": "more match in this document",
66    "search-more-matches-text": "more matches in this document",
67    "search-clear-button-title": "Clear",
68    "search-text-placeholder": "",
69    "search-detached-cancel-button-title": "Cancel",
70    "search-submit-button-title": "Submit",
71    "search-label": "Search"
72  }
73}</script>
vendor: 67 bytes, lines 73-74
73
74<script async="" src="https://www.googletagmanager.com/gtag/js?id=
74G-WS5CZJ06W0
vendor: 13 bytes, lines 74-75
74"></script>
75
76<script type="text/javascript">
77
vendor: 127 bytes, lines 78-81
78window.dataLayer = window.dataLayer || [];
79function gtag(){dataLayer.push(arguments);}
80gtag('js', new Date());
81gtag('config', '
81G-WS5CZJ06W0
vendor: 29 bytes, line 81
81', { 'anonymize_ip': true});
82</script>
82
83
84
85<meta property="og:title" content="Dr.&nbsp;Xiao Ping Song">
86<meta property="og:description" content="Xiao Ping’s Website">
87<meta property="og:image" content="https://xpsong.com/images/profile.jpg">
88<meta property="og:site_name" content="XP's Website">
89<meta name="twitter:title" content="Dr.&nbsp;Xiao Ping Song">
90<meta name="twitter:description" content="Xiao Ping’s Website">
91<meta name="twitter:image" content="https://xpsong.com/images/profile.jpg">
92<meta name="twitter:creator" content="@dr_watchnlearn">
93<meta name="twitter:card" content="summary_large_image">
94</head>
95
96<body class="nav-fixed fullcontent quarto-light">
97
98<div id="quarto-search-results"></div>
99  <header id="quarto-header" class="headroom fixed-top">
100    <nav class="navbar navbar-expand-lg " data-bs-theme="dark">
101      <div class="navbar-container container-fluid">
102      <div class="navbar-brand-container mx-auto">
103    <a href="./index.html" class="navbar-brand navbar-brand-logo">
104    <img src="./images/icon.png" alt="XP's Website" class="navbar-logo">
105    </a>
106  </div>
107            <div id="quarto-search" class="" title="Search"></div>
108          <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(); }">
109  <span class="navbar-toggler-icon"></span>
110</button>
111          <div class="collapse navbar-collapse" id="navbarCollapse">
112            <ul class="navbar-nav navbar-nav-scroll ms-auto">
113  <li class="nav-item">
114    <a class="nav-link" href="./courses.html"> 
115<span class="menu-text">Courses</span></a>
116  </li>  
117  <li class="nav-item">
118    <a class="nav-link" href="./blog.html"> 
119<span class="menu-text">Blog</span></a>
120  </li>  
121  <li class="nav-item">
122    <a class="nav-link" href="./academia.html"> 
123<span class="menu-text">Academia</span></a>
124  </li>  
125  <li class="nav-item">
126    <a class="nav-link" href="./music.html"> 
127<span class="menu-text">Music</span></a>
128  </li>  
129</ul>
130          </div> <!-- /navcollapse -->
131            <div class="quarto-navbar-tools">
132</div>
133      </div> <!-- /container-fluid -->
134    </nav>
135</header>
136<!-- content -->
137<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
138<!-- sidebar -->
139<!-- margin-sidebar -->
140    
141<!-- main -->
142<main class="content page-columns page-full" id="quarto-document-content">
143
144
145
146
147<style>
148
149#quarto-content {
150  background-color: #dce1e3;
151}
152
153h1.title {
154  text-transform: uppercase;
155}
156
157p.subtitle {
158  font-size: 1.02em;
159}
160
161div.quarto-about-solana {
162  padding-top: 0em !important;
163}
164
165</style>
166<div class="quarto-about-solana column-body">
167  <div class="about-entity">
168    <div class="entity-contents">
169      <header id="title-block-header" class="quarto-title-block default">
170<div class="quarto-title">
171<h1 class="title">Dr.&nbsp;Xiao Ping Song</h1>
172</div>
173<div class="quarto-title-meta">
174  </div>
175</header> 
176      <div class="about-contents"><div id="links">
177<p><a href="https://www.linkedin.com/in/xpsong"><i class="bi-linkedin"></i></a> &nbsp; <a href="https://scholar.google.com.sg/citations?user=_ZlnqLoAAAAJ"><i class="ai  ai-google-scholar"></i></a> &nbsp; <a href="https://github.com/xp-song"><i class="bi-github"></i></a> &nbsp; <a href="https://www.youtube.com/@dr.watchnlearn"><i class="fa-brands fa-youtube fa-m" aria-label="youtube"></i></a> &nbsp; <a href="https://www.instagram.com/dr.watchnlearn/"><i class="fa-brands fa-instagram fa-m" aria-label="instagram"></i></a> &nbsp; <a href="https://twitter.com/dr_watchnlearn"><i class="bi-twitter"></i></a> &nbsp; <a href="https://bit.ly/geospatial-datascience-r_udemy"><iconify-icon inline="" icon="logos:udemy"></iconify-icon></a> &nbsp; <a href="resources/resume_xpsong.pdf"><i class="ai  ai-cv ai-lg"></i></a></p>
178<p>Hello, I’m Xiao Ping — most people call me XP. This corner of the internet predates AI-generated content, so what you’re reading was typed by actual human fingers. Yes, including the em-dashes, which unfortunately I can no longer use without a disclaimer.</p>
179<p>I lead Data Engineering at Esri Singapore, with a past life as a postdoc researching and teaching applied machine learning and geospatial programming. Music and watch modding are my creative outlets; feel free to explore the blog and social channels for more.</p>
180<p>
180If you’d rather talk to an AI version of me, that’s at <a href="https://xpstudios.ai/about">xpstudios.ai</a>.</p>
181</div></div>
182    </div>
183    <img src="images/profile.jpg" class="about-image
184  round " style="height: 15em; width: 15em;">
185  </div>
186</div>
187
188
189
190
191
192</main> <!-- /main -->
193<script id="quarto-html-after-body" type="application/javascript">
194  window.document.addEventListener("DOMContentLoaded", function (event) {
195    const isCodeAnnotation = (el) => {
196      for (const clz of el.classList) {
197        if (clz.startsWith('code-annotation-')) {                     
198          return true;
199        }
200      }
201      return false;
202    }
203    const onCopySuccess = function(e) {
204      // button target
205      const button = e.trigger;
206      // don't keep focus
207      button.blur();
208      // flash "checked"
209      button.classList.add('code-copy-button-checked');
210      var currentTitle = button.getAttribute("title");
211      button.setAttribute("title", "Copied!");
212      let tooltip;
213      if (window.bootstrap) {
214        button.setAttribute("data-bs-toggle", "tooltip");
215        button.setAttribute("data-bs-placement", "left");
216        button.setAttribute("data-bs-title", "Copied!");
217        tooltip = new bootstrap.Tooltip(button, 
218          { trigger: "manual", 
219            customClass: "code-copy-button-tooltip",
220            offset: [0, -8]});
221        tooltip.show();    
222      }
223      setTimeout(function() {
224        if (tooltip) {
225          tooltip.hide();
226          button.removeAttribute("data-bs-title");
227          button.removeAttribute("data-bs-toggle");
228          button.removeAttribute("data-bs-placement");
229        }
230        button.setAttribute("title", currentTitle);
231        button.classList.remove('code-copy-button-checked');
232      }, 1000);
233      // clear code selection
234      e.clearSelection();
235    }
236    const getTextToCopy = function(trigger) {
237        const codeEl = trigger.previousElementSibling.cloneNode(true);
238        for (const childEl of codeEl.children) {
239          if (isCodeAnnotation(childEl)) {
240            childEl.remove();
241          }
242        }
243        return codeEl.innerText;
244    }
245    const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
246      text: getTextToCopy
247    });
248    clipboard.on('success', onCopySuccess);
249    if (window.document.getElementById('quarto-embedded-source-code-modal')) {
250      const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
251        text: getTextToCopy,
252        container: window.document.getElementById('quarto-embedded-source-code-modal')
253      });
254      clipboardModal.on('success', onCopySuccess);
255    }
256      var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
257      var mailtoRegex = new RegExp(/^mailto:/);
258        var filterRegex = new RegExp("https:\/\/xpsong\.com");
259      var isInternal = (href) => {
260          return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
261      }
262      // Inspect non-navigation links and adorn them if external
263     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)');
264      for (var i=0; i<links.length; i++) {
265        const link = links[i];
266        if (!isInternal(link.href)) {
267          // undo the damage that might have been done by quarto-nav.js in the case of
268          // links that we want to consider external
269          if (link.dataset.originalHref !== undefined) {
270            link.href = link.dataset.originalHref;
271          }
272        }
273      }
274    function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
275      const config = {
276        allowHTML: true,
277        maxWidth: 500,
278        delay: 100,
279        arrow: false,
280        appendTo: function(el) {
281            return el.parentElement;
282        },
283        interactive: true,
284        interactiveBorder: 10,
285        theme: 'quarto',
286        placement: 'bottom-start',
287      };
288      if (contentFn) {
289        config.content = contentFn;
290      }
291      if (onTriggerFn) {
292        config.onTrigger = onTriggerFn;
293      }
294      if (onUntriggerFn) {
295        config.onUntrigger = onUntriggerFn;
296      }
297      window.tippy(el, config); 
298    }
299    const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
300    for (var i=0; i<noterefs.length; i++) {
301      const ref = noterefs[i];
302      tippyHover(ref, function() {
303        // use id or data attribute instead here
304        let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
305        try { href = new URL(href).hash; } catch {}
306        const id = href.replace(/^#\/?/, "");
307        const note = window.document.getElementById(id);
308        if (note) {
309          return note.innerHTML;
310        } else {
311          return "";
312        }
313      });
314    }
315    const xrefs = window.document.querySelectorAll('a.quarto-xref');
316    const processXRef = (id, note) => {
317      // Strip column container classes
318      const stripColumnClz = (el) => {
319        el.classList.remove("page-full", "page-columns");
320        if (el.children) {
321          for (const child of el.children) {
322            stripColumnClz(child);
323          }
324        }
325      }
326      stripColumnClz(note)
327      if (id === null || id.startsWith('sec-')) {
328        // Special case sections, only their first couple elements
329        const container = document.createElement("div");
330        if (note.children && note.children.length > 2) {
331          container.appendChild(note.children[0].cloneNode(true));
332          for (let i = 1; i < note.children.length; i++) {
333            const child = note.children[i];
334            if (child.tagName === "P" && child.innerText === "") {
335              continue;
336            } else {
337              container.appendChild(child.cloneNode(true));
338              break;
339            }
340          }
341          if (window.Quarto?.typesetMath) {
342            window.Quarto.typesetMath(container);
343          }
344          return container.innerHTML
345        } else {
346          if (window.Quarto?.typesetMath) {
347            window.Quarto.typesetMath(note);
348          }
349          return note.innerHTML;
350        }
351      } else {
352        // Remove any anchor links if they are present
353        const anchorLink = note.querySelector('a.anchorjs-link');
354        if (anchorLink) {
355          anchorLink.remove();
356        }
357        if (window.Quarto?.typesetMath) {
358          window.Quarto.typesetMath(note);
359        }
360        if (note.classList.contains("callout")) {
361          return note.outerHTML;
362        } else {
363          return note.innerHTML;
364        }
365      }
366    }
367    for (var i=0; i<xrefs.length; i++) {
368      const xref = xrefs[i];
369      tippyHover(xref, undefined, function(instance) {
370        instance.disable();
371        let url = xref.getAttribute('href');
372        let hash = undefined; 
373        if (url.startsWith('#')) {
374          hash = url;
375        } else {
376          try { hash = new URL(url).hash; } catch {}
377        }
378        if (hash) {
379          const id = hash.replace(/^#\/?/, "");
380          const note = window.document.getElementById(id);
381          if (note !== null) {
382            try {
383              const html = processXRef(id, note.cloneNode(true));
384              instance.setContent(html);
385            } finally {
386              instance.enable();
387              instance.show();
388            }
389          } else {
390            // See if we can fetch this
391            fetch(url.split('#')[0])
392            .then(res => res.text())
393            .then(html => {
394              const parser = new DOMParser();
395              const htmlDoc = parser.parseFromString(html, "text/html");
396              const note = htmlDoc.getElementById(id);
397              if (note !== null) {
398                const html = processXRef(id, note);
399                instance.setContent(html);
400              } 
401            }).finally(() => {
402              instance.enable();
403              instance.show();
404            });
405          }
406        } else {
407          // See if we can fetch a full url (with no hash to target)
408          // This is a special case and we should probably do some content thinning / targeting
409          fetch(url)
410          .then(res => res.text())
411          .then(html => {
412            const parser = new DOMParser();
413            const htmlDoc = parser.parseFromString(html, "text/html");
414            const note = htmlDoc.querySelector('main.content');
415            if (note !== null) {
416              // This should only happen for chapter cross references
417              // (since there is no id in the URL)
418              // remove the first header
419              if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
420                note.children[0].remove();
421              }
422              const html = processXRef(null, note);
423              instance.setContent(html);
424            } 
425          }).finally(() => {
426            instance.enable();
427            instance.show();
428          });
429        }
430      }, function(instance) {
431      });
432    }
433        let selectedAnnoteEl;
434        const selectorForAnnotation = ( cell, annotation) => {
435          let cellAttr = 'data-code-cell="' + cell + '"';
436          let lineAttr = 'data-code-annotation="' +  annotation + '"';
437          const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
438          return selector;
439        }
440        const selectCodeLines = (annoteEl) => {
441          const doc = window.document;
442          const targetCell = annoteEl.getAttribute("data-target-cell");
443          const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
444          const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
445          const lines = annoteSpan.getAttribute("data-code-lines").split(",");
446          const lineIds = lines.map((line) => {
447            return targetCell + "-" + line;
448          })
449          let top = null;
450          let height = null;
451          let parent = null;
452          if (lineIds.length > 0) {
453              //compute the position of the single el (top and bottom and make a div)
454              const el = window.document.getElementById(lineIds[0]);
455              top = el.offsetTop;
456              height = el.offsetHeight;
457              parent = el.parentElement.parentElement;
458            if (lineIds.length > 1) {
459              const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
460              const bottom = lastEl.offsetTop + lastEl.offsetHeight;
461              height = bottom - top;
462            }
463            if (top !== null && height !== null && parent !== null) {
464              // cook up a div (if necessary) and position it 
465              let div = window.document.getElementById("code-annotation-line-highlight");
466              if (div === null) {
467                div = window.document.createElement("div");
468                div.setAttribute("id", "code-annotation-line-highlight");
469                div.style.position = 'absolute';
470                parent.appendChild(div);
471              }
472              div.style.top = top - 2 + "px";
473              div.style.height = height + 4 + "px";
474              div.style.left = 0;
475              let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
476              if (gutterDiv === null) {
477                gutterDiv = window.document.createElement("div");
478                gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
479                gutterDiv.style.position = 'absolute';
480                const codeCell = window.document.getElementById(targetCell);
481                const gutter = codeCell.querySelector('.code-annotation-gutter');
482                gutter.appendChild(gutterDiv);
483              }
484              gutterDiv.style.top = top - 2 + "px";
485              gutterDiv.style.height = height + 4 + "px";
486            }
487            selectedAnnoteEl = annoteEl;
488          }
489        };
490        const unselectCodeLines = () => {
491          const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
492          elementsIds.forEach((elId) => {
493            const div = window.document.getElementById(elId);
494            if (div) {
495              div.remove();
496            }
497          });
498          selectedAnnoteEl = undefined;
499        };
500          // Handle positioning of the toggle
501      window.addEventListener(
502        "resize",
503        throttle(() => {
504          elRect = undefined;
505          if (selectedAnnoteEl) {
506            selectCodeLines(selectedAnnoteEl);
507          }
508        }, 10)
509      );
510      function throttle(fn, ms) {
511      let throttle = false;
512      let timer;
513        return (...args) => {
514          if(!throttle) { // first call gets through
515              fn.apply(this, args);
516              throttle = true;
517          } else { // all the others get throttled
518              if(timer) clearTimeout(timer); // cancel #2
519              timer = setTimeout(() => {
520                fn.apply(this, args);
521                timer = throttle = false;
522              }, ms);
523          }
524        };
525      }
526        // Attach click handler to the DT
527        const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
528        for (const annoteDlNode of annoteDls) {
529          annoteDlNode.addEventListener('click', (event) => {
530            const clickedEl = event.target;
531            if (clickedEl !== selectedAnnoteEl) {
532              unselectCodeLines();
533              const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
534              if (activeEl) {
535                activeEl.classList.remove('code-annotation-active');
536              }
537              selectCodeLines(clickedEl);
538              clickedEl.classList.add('code-annotation-active');
539            } else {
540              // Unselect the line
541              unselectCodeLines();
542              clickedEl.classList.remove('code-annotation-active');
543            }
544          });
545        }
546    const findCites = (el) => {
547      const parentEl = el.parentElement;
548      if (parentEl) {
549        const cites = parentEl.dataset.cites;
550        if (cites) {
551          return {
552            el,
553            cites: cites.split(' ')
554          };
555        } else {
556          return findCites(el.parentElement)
557        }
558      } else {
559        return undefined;
560      }
561    };
562    var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
563    for (var i=0; i<bibliorefs.length; i++) {
564      const ref = bibliorefs[i];
565      const citeInfo = findCites(ref);
566      if (citeInfo) {
567        tippyHover(citeInfo.el, function() {
568          var popup = window.document.createElement('div');
569          citeInfo.cites.forEach(function(cite) {
570            var citeDiv = window.document.createElement('div');
571            citeDiv.classList.add('hanging-indent');
572            citeDiv.classList.add('csl-entry');
573            var biblioDiv = window.document.getElementById('ref-' + cite);
574            if (biblioDiv) {
575              citeDiv.innerHTML = biblioDiv.innerHTML;
576            }
577            popup.appendChild(citeDiv);
578          });
579          return popup.innerHTML;
580        });
581      }
582    }
583  });
584  </script>
584
585</div> <!-- /content -->
586<footer class="footer">
587  <div class="nav-footer">
588    <div class="nav-footer-left">
589<p>© 2026 XP Song. Built with <a href="https://quarto.org/">Quarto</a>.</p>
590</div>   
591    <div class="nav-footer-center">
592      &nbsp;
593    </div>
594    <div class="nav-footer-right">
595      <ul class="footer-items list-unstyled">
596    <li class="nav-item">
597    <a class="nav-link" href="mailto:[email protected]">
598<p>Contact</p>
599</a>
600  </li>  
601    <li class="nav-item">
602    <a class="nav-link" href="https://creativecommons.org/licenses/by-sa/4.0/">
603<p>License</p>
604</a>
605  </li>  
606    <li class="nav-item">
607    <a class="nav-link" href="./blog.xml">
608<p>RSS</p>
609</a>
610  </li>  
611</ul>
612    </div>
613  </div>
614</footer>
615
616
617
618
619</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.