PageSourceSearch

https://jongerhardson.github.io/work_portfolio/

html jongerhardson.github.io collected 2026-10-03 09:24:36 UTC 28,103 bytes, 702 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5    <meta charset="UTF-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <title>Jonathan Gerhardson — Work Portfolio</title>
8    <meta name="description"
9        content="Investigative journalism, data reporting, and open-source tools by Jonathan Gerhardson.">
10    <meta property="og:title" content="Jonathan Gerhardson — Work Portfolio">
11    <meta property="og:description" content="Investigative journalism, data reporting, and open-source tools.">
12    <meta property="og:type" content="website">
13    <meta name="twitter:card" content="summary">
14    <link rel="icon" type="image/jpeg" href="119974184.jpeg">
15
16    <style>
17        *,
18        *::before,
19        *::after {
20            box-sizing: border-box;
21            margin: 0;
22            padding: 0;
23        }
24
25        :root {
26            --serif: Georgia, 'Times New Roman', serif;
27            --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
28            --mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
29            --bg: #fafaf8;
30            --surface: #fff;
31            --text: #1a1a1a;
32            --text-2: #4a4a4a;
33            --text-3: #777;
34            --border: #e0ddd8;
35            --border-light: #eeece7;
36            --accent: #b42318;
37            --accent-dark: #8c1d15;
38            --link: #1a5276;
39            --max-w: 960px;
40        }
41
42        html {
43            scroll-behavior: smooth;
44        }
45
46        body {
47            font-family: var(--sans);
48            background: var(--bg);
49            color: var(--text);
50            line-height: 1.65;
51            -webkit-font-smoothing: antialiased;
52        }
53
54        a {
55            color: var(--link);
56            text-decoration: none;
57        }
58
59        a:hover {
60            text-decoration: underline;
61        }
62
63        a:focus-visible {
64            outline: 2px solid var(--accent);
65            outline-offset: 2px;
66        }
67
68        img {
69            max-width: 100%;
70            display: block;
71        }
72
73        /* ---- Header ---- */
74        header {
75            max-width: var(--max-w);
76            margin: 0 auto;
77            padding: 3rem 1.5rem 2rem;
78            border-bottom: 2px solid var(--text);
79        }
80
81        header h1 {
82            font-family: var(--serif);
83            font-size: 2.25rem;
84            font-weight: 700;
85            line-height: 1.15;
86            margin-bottom: 0.5rem;
87        }
88
89        header p {
90            color: var(--text-2);
91            font-size: 0.95rem;
92            max-width: 540px;
93        }
94
95        header nav {
96            margin-top: 1rem;
97            display: flex;
98            gap: 1.5rem;
99            font-size: 0.85rem;
100        }
101
102        header nav a {
103            color: var(--text-3);
104            text-transform: uppercase;
105            letter-spacing: 0.06em;
106            font-weight: 500;
107        }
108
109        header nav a:hover {
110            color: var(--text);
111            text-decoration: none;
112        }
113
114        /* ---- Main ---- */
115        main {
116            max-width: var(--max-w);
117            margin: 0 auto;
118            padding: 0 1.5rem;
119        }
120
121        /* ---- Section ---- */
122        .section {
123            padding: 3rem 0;
124            border-bottom: 1px solid var(--border);
125        }
126
127        .section:last-child {
128            border-bottom: none;
129        }
130
131        .section-head {
132            margin-bottom: 2rem;
133        }
134
135        .section-head h2 {
136            font-family: var(--serif);
137            font-size: 1.1rem;
138            font-weight: 600;
139            color: var(--accent);
140            text-transform: uppercase;
141            letter-spacing: 0.08em;
142        }
143
144
145
146        /* ---- Article list ---- */
147        .article-list {
148            list-style: none;
149        }
150
151        .article-list li {
152            padding: 1.25rem 0;
153            border-bottom: 1px solid var(--border-light);
154            display: grid;
155            grid-template-columns: 1fr auto;
156            gap: 1.5rem;
157            align-items: start;
158        }
159
160        .article-list li:last-child {
161            border-bottom: none;
162        }
163
164        .article-list h3 {
165            font-family: var(--serif);
166            font-size: 1.15rem;
167            font-weight: 600;
168            line-height: 1.3;
169            margin-bottom: 0.3rem;
170        }
171
172        .article-list h3 a {
173            color: var(--text);
174        }
175
176        .article-list h3 a:hover {
177            color: var(--accent);
178            text-decoration: none;
179        }
180
181        .article-list p {
182            font-size: 0.9rem;
183            color: var(--text-2);
184            line-height: 1.55;
185        }
186
187        .article-meta {
188            font-size: 0.78rem;
189            color: var(--text-3);
190            white-space: nowrap;
191            padding-top: 0.15rem;
192            text-align: right;
193        }
194
195        .pub-name {
196            font-weight: 600;
197            display: block;
198        }
199
200        /* ---- Data project ---- */
201        .data-layout {
202            display: grid;
203            grid-template-columns: 1fr 1fr;
204            gap: 2rem;
205            align-items: start;
206        }
207
208        .screenshot-grid {
209            display: grid;
210            grid-template-columns: 1fr 1fr;
211            gap: 0.5rem;
212            max-width: 80%;
213        }
214
215        .screenshot-grid .lb-wrap > a:not(.lb-close) {
216            display: block;
217            overflow: hidden;
218        }
219
220        .screenshot-grid img {
221            border: 1px solid var(--border);
222            width: 100%;
223            aspect-ratio: 4/3;
224            object-fit: cover;
225            transition: box-shadow 0.2s ease;
226        }
227
228        .screenshot-grid img:hover {
229            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
230        }
231
232        .data-body h3 {
233            font-family: var(--serif);
234            font-size: 1.4rem;
235            font-weight: 700;
236            line-height: 1.25;
237            margin-bottom: 0.75rem;
238        }
239
240        .data-body p {
241            font-size: 0.9rem;
242            color: var(--text-2);
243            margin-bottom: 0.75rem;
244            line-height: 1.6;
245        }
246
247        .data-body ul {
248            padding-left: 1.1rem;
249            margin-bottom: 1rem;
250        }
251
252        .data-body li {
253            font-size: 0.88rem;
254            color: var(--text-2);
255            margin-bottom: 0.3rem;
256        }
257
258
259
260        /* ---- Tools ---- */
261        .tools-list {
262            display: grid;
263            grid-template-columns: 1fr;
264            gap: 0;
265        }
266
267        .tool-item {
268            display: grid;
269            grid-template-columns: minmax(200px, 280px) 1fr;
270            gap: 1.5rem;
271            padding: 1.5rem 0;
272            border-bottom: 1px solid var(--border-light);
273            align-items: start;
274        }
275
276        .tool-item:last-child {
277            border-bottom: none;
278        }
279
280        .tool-visual {
281            display: block;
282            border: 1px solid var(--border);
283            cursor: pointer;
284            overflow: hidden;
285            transition: box-shadow 0.2s ease;
286        }
287
288        .tool-visual:hover {
289            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
290        }
291
292        .tool-visual img {
293            width: 100%;
294        }
295
296        .tool-visual.empty {
297            display: flex;
298            align-items: center;
299            justify-content: center;
300            background: #f3f1ec;
301            min-height: 120px;
302            font-family: var(--mono);
303            font-size: 0.8rem;
304            color: var(--text-3);
305        }
306
307        .tool-info h3 {
308            font-size: 1rem;
309            font-weight: 600;
310            margin-bottom: 0.15rem;
311        }
312
313        .tool-info h3 a {
314            color: var(--text);
315        }
316
317        .tool-info h3 a:hover {
318            color: var(--accent);
319            text-decoration: none;
320        }
321
322        .tool-sub {
323            font-family: var(--mono);
324            font-size: 0.72rem;
325            color: var(--text-3);
326            margin-bottom: 0.65rem;
327        }
328
329        .tool-info p {
330            font-size: 0.88rem;
331            color: var(--text-2);
332            line-height: 1.55;
333            margin-bottom: 0.6rem;
334        }
335
336        .tool-tags {
337            display: flex;
338            flex-wrap: wrap;
339            gap: 0.35rem;
340        }
341
342        .tool-tags span {
343            font-family: var(--mono);
344            font-size: 0.68rem;
345            padding: 0.15rem 0.45rem;
346            border: 1px solid var(--border);
347            color: var(--text-3);
348        }
349
350        /* ---- Footer ---- */
351        footer {
352            max-width: var(--max-w);
353            margin: 0 auto;
354            padding: 2rem 1.5rem 3rem;
355            border-top: 2px solid var(--text);
356            font-size: 0.82rem;
357            color: var(--text-3);
358            display: flex;
359            justify-content: space-between;
360        }
361
362        footer a {
363            color: var(--text-2);
364        }
365
366        /* ---- Lightbox (CSS-only via :target) ---- */
367        .lb-wrap {
368            position: relative;
369            min-width: 0;
370        }
371
372        .lb-wrap .lb-close {
373            position: fixed;
374            inset: 0;
375            z-index: 1000;
376            background: rgba(0, 0, 0, 0.85);
377            cursor: zoom-out;
378            opacity: 0;
379            visibility: hidden;
380            transition: opacity 0.25s ease, visibility 0.25s ease;
381        }
382
383        .lb-wrap:target .lb-close {
384            opacity: 1;
385            visibility: visible;
386        }
387
388        .lb-wrap:target > img,
389        .lb-wrap:target > a > img {
390            position: fixed;
391            z-index: 1001;
392            top: 50%;
393            left: 50%;
394            transform: translate(-50%, -50%);
395            max-width: 92vw;
396            max-height: 92vh;
397            width: auto;
398            height: auto;
399            object-fit: contain;
400            box-shadow: 0 4px 40px rgba(0, 0, 0, 0.4);
401            aspect-ratio: auto;
402        }
403
404        .lb-wrap video { pointer-events: none; }
405        .lb-wrap:target > a > video {
406            position: fixed;
407            z-index: 1001;
408            top: 50%;
409            left: 50%;
410            transform: translate(-50%, -50%);
411            max-width: 92vw;
412            max-height: 92vh;
413            width: auto;
414            height: auto;
415            object-fit: contain;
416            box-shadow: 0 4px 40px rgba(0, 0, 0, 0.4);
417            pointer-events: auto;
418        }
419
420/* ---- Responsive ---- */
421        @media (max-width: 768px) {
422
423            .data-layout {
424                grid-template-columns: 1fr;
425            }
426
427            .tool-item {
428                grid-template-columns: 1fr;
429            }
430
431            .article-list li {
432                grid-template-columns: 1fr;
433                gap: 0.25rem;
434            }
435
436            .article-meta {
437                text-align: left;
438            }
439
440            header h1 {
441                font-size: 1.75rem;
442            }
443
444            footer {
445                flex-direction: column;
446                gap: 0.5rem;
447            }
448        }
449    </style>
450</head>
451
452<body>
453
454    <header>
455        <h1>Jonathan Gerhardson</h1>
456        <p>
456I use public records, data analysis, and open-source tools to help me write stories about people and governments. Based in western Massachusetts.</p>
457        <nav>
458            <a href="#reporting">Reporting</a>
459            <a href="#data">Data Projects</a>
460            <a href="#tools">Code</a>
461        </nav>
462    </header>
463
464    <main>
465
466        <!-- Reporting -->
467        <div class="section" id="reporting">
468            <div class="section-head">
469                <h2>Selected Reporting</h2>
470            </div>
471            <ul class="article-list">
472                <li>
473                    <div>
474                        <h3><a href="https://binj.news/2026/02/11/millions-in-opioid-settlement-funds-are-still-sitting-idle-in-mass-municipalities/"
475                                target="_blank" rel="noopener">Millions in opioid settlement funds are still sitting
476                                idle in Mass municipalities</a></h3>
477                        <p>Of $113.7 million disbursed for opioid abatement, cities and towns spent 17%. Nearly half
478                            reported zero expenditures in FY25, during which 1,763 opioid-related deaths occurred
479                            statewide.</p>
480                    </div>
481                    <div class="article-meta">
482                        <span class="pub-name">BINJ</span>
483                        Feb 2026
484                    </div>
485                </li>
486                <li>
487                    <div>
488                        <h3><a href="https://theshoestring.org/2025/12/30/ai-hallucination-proposed-westfield-data-center-appears-abandoned-by-developers/"
489                                target="_blank" rel="noopener">AI Hallucination? Proposed Westfield data center appears
490                                abandoned by developers</a></h3>
491                        <p>A proposed &ldquo;hyper-scale&rdquo; data center in Westfield would have drawn 10&times; more power than the state's
492                            largest existing facility, but the project appears to be abandoned. In 2021, developers refused delivery of their permit and
493                            cut off contact with the city; news outlets continued to report on the forthcoming project through 2025.
494                        </p>
495                    </div>
496                    <div class="article-meta">
497                        <span class="pub-name">The Shoestring</span>
498                        Dec 2025
499                    </div>
500                </li>
501                <li>
502                    <div>
503                        <h3><a href="https://theshoestring.org/2025/12/06/records-west-springfield-police-partnered-with-ice-division/"
504                                target="_blank" rel="noopener">West Springfield police partnered with ICE division</a>
505                        </h3>
506                        <p>Public records revealed that West Springfield police signed an MOU with Homeland Security
507                            Investigations, one of ICE's two divisions. The city is among the most diverse in the state,
508                            with students speaking over 50 languages.</p>
509                    </div>
510                    <div class="article-meta">
511                        <span class="pub-name">The Shoestring</span>
512                        Dec 2025
513                    </div>
514                </li>
515                <li>
516                    <div>
517                        <h3><a href="https://theshoestring.org/2025/10/28/theres-a-lot-of-money-in-death-funeral-home-consolidation-hits-western-mass/"
518                                target="_blank" rel="noopener">Funeral home consolidation hits western Mass</a></h3>
519                        <p>A private equity-backed firm quietly acquired more than 10% of western Mass funeral homes. A
520                            quarter of the region's homes are now chains, and 46% of directors nationwide plan to retire
521                            within five years.</p>
522                    </div>
523                    <div class="article-meta">
524                        <span class="pub-name">The Shoestring</span>
525                        Oct 2025
526                    </div>
527                </li>
528                <li>
529                    <div>
530                        <h3><a href="https://theshoestring.org/2025/07/24/surveillance-state-comes-to-chicopee/"
531                                target="_blank" rel="noopener">Surveillance state comes to Chicopee</a></h3>
532                        <p>A network of hundreds of cameras, accessible to police at any time for any reason, is concentrated in the city’s poorest areas. 
533                                <a href="https://jongerhardson.github.io/irene/" target="_blank" rel="noopener">View the
534                                interactive map →</a></p>
535                    </div>
536                    <div class="article-meta">
537                        <span class="pub-name">The Shoestring</span>
538                        Jul 2025
539                    </div>
540                </li>
541                <li>
542                    <div>
543                        <h3><a href="https://theshoestring.org/2025/06/09/doxing-death-threats-deportation-how-the-far-right-stifled-campus-activism-and-sent-ice-after-a-local-student/"
544                                target="_blank" rel="noopener">How the far right stifled campus activism and sent ICE
545                                after a local student</a></h3>
546                        <p>A right-wing organization publicly called for a Hampshire College student's deportation. One
547                            day later, the government revoked his visa. A federal judge later found the warrant was
548                            backdated and the arrest attempt unlawful.</p>
549                    </div>
550                    <div class="article-meta">
551                        <span class="pub-name">The Shoestring</span>
552                        Jun 2025<br>
553                        w/ Dan McGlynn
554                    </div>
555                </li>
556                <li>
557                    <div>
558                        <h3><a href="https://binj.news/2025/04/15/mass-municipalities-are-sitting-on-millions-meant-to-mitigate-the-opioid-scourge/"
559                                target="_blank" rel="noopener">Mass municipalities are sitting on millions meant to
560                                mitigate the opioid scourge</a></h3>
561                        <p>Massachusetts will receive around a billion dollars for opioid abatement efforts. Here is how
562                            cities and towns are spending so far.</p>
563                    </div>
564                    <div class="article-meta">
565                        <span class="pub-name">BINJ</span>
566                        Apr 2025
567                    </div>
568                </li>
569            </ul>
570        </div>
571
572        <!-- Data Projects -->
573        <div class="section" id="data">
574            <div class="section-head">
575                <h2>Data Projects</h2>
576            </div>
577            <div class="data-layout">
578                <!-- Chicopee Surveillance Map -->
579                <div>
580                    <div class="screenshot-grid" style="margin-bottom: 1rem;">
581                        <div class="lb-wrap" id="lb-1"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-1"><img src="surveillance_chicopee/Screenshot from 2026-02-15 14-46-11.png"
582                            alt="Heatmap of surveillance cameras overlaid on median household income"></a></div>
583                        <div class="lb-wrap" id="lb-2"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-2"><img src="surveillance_chicopee/Screenshot from 2026-02-15 14-48-03.png"
584                            alt="Interactive map popup showing camera location and embedded video"></a></div>
585                        <div class="lb-wrap" id="lb-vid"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-vid"><video src="slideshow_60s.mp4" controls muted style="border-radius: 6px; width: 100%; height: 100%; object-fit: cover;"></video></a></div>
586                    </div>
587                    <h3><a href="https://jongerhardson.github.io/irene/" target="_blank" rel="noopener">Chicopee
588                            Surveillance Map</a> <span class="article-meta" style="display:inline; white-space:nowrap;">Jul 2025</span></h3>
589                    <p>An interactive map of hundreds of surveillance cameras deployed by Chicopee Police using the Axon Fusus network, overlaid with
590                        Census income data. Built from audit logs obtained through a public records request. Accompanies
591                        <a href="https://theshoestring.org/2025/07/24/surveillance-state-comes-to-chicopee/"
592                            target="_blank" rel="noopener">reporting for The Shoestring</a>. Camera locations were confirmed via in-person observation (see video). 
593                    </p>
594                </div>
595                <!-- Opioid Settlement Dashboard -->
596                <div>
597                    <div class="screenshot-grid" style="margin-bottom: 1rem;">
598                        <div class="lb-wrap" id="lb-3"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-3"><img src="orrf/Screenshot from 2026-02-15 14-53-06.png"
599                            alt="Choropleth map of Massachusetts opioid settlement spending by municipality"></a></div>
600                        <div class="lb-wrap" id="lb-4"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-4"><img src="orrf/Screenshot from 2026-02-15 14-50-46.png"
601                            alt="Entity explorer with sortable municipal spending data"></a></div>
602                        <div class="lb-wrap" id="lb-5"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-5"><img src="orrf/Screenshot from 2026-02-15 14-52-16.png"
603                            alt="Full-text search across settlement expenditures"></a></div>
604                        <div class="lb-wrap" id="lb-6"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-6"><img src="orrf/Screenshot from 2026-02-15 14-51-36.png"
605                            alt="Expenditure detail view with program descriptions"></a></div>
606                    </div>
607                    <h3><a href="https://jongerhardson.github.io/mass_opioid_settlement_data/#statewide" target="_blank"
608                            rel="noopener">Opioid Settlement Dashboard</a> <span class="article-meta" style="display:inline; white-space:nowrap;">Feb 2026</span></h3>
609                    <p>An interactive dashboard tracking reported expenditures for Opioid Remediation and Recovery settlement funds across municipalities and the state executive branch. Includes data for FY2023 throughg FY2025, with full-text search, sortable tables, and spending breakdowns, and a choropleth map. Created for the Boston Institute for Nonprofit Journalism as part of my ongoing coverage of how this settlement money is being used. My initial reporting on this topic helped <a href="https://binj.news/author/jonathan-gerhardson/" target="_blank" rel="noopener">BINJ</a> secure a grant from the Data-Driven Reporting Project. I also appeared on MuckRock's <a href="https://www.youtube.com/watch?v=YIGfHBJLLzo" target="_blank" rel="noopener">FOIA Friday</a>
609 series to discuss some challenges I faced in obtaining records from Care Mass, the public-private partnership that held these records last year.</p>
610                </div>
611            </div>
612        </div>
613
614
615
616        <!-- Code & tools -->
617        <div class="section" id="tools">
618            <div class="section-head">
619                <h2>Code & Tools</h2>
620            </div>
621            <div class="tools-list">
622
623                <div class="tool-item">
624                    <div class="lb-wrap" id="lb-7"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-7" class="tool-visual"><img src="code/federal_agent_screenshot.png"
625                            alt="federal-agent querying DoD ice cream spending via Claude Code"></a></div>
626                    <div class="tool-info">
627                        <h3><a href="https://github.com/JonGerhardson/federal-agent" target="_blank"
628                                rel="noopener">federal-agent</a></h3>
629                        <div class="tool-sub">Claude Code skill · Python</div>
630                        <p>A skill for Claude Code that queries federal procurement data from FPDS, USAspending.gov, and
631                            SAM.gov. Lets you search contracts by agency, vendor, or NAICS code, analyze spending
632                            patterns, and cross-reference sources through natural language.</p>
633                    </div>
634                </div>
635
636                <div class="tool-item">
637                    <div class="lb-wrap" id="lb-8"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-8" class="tool-visual"><img src="code/Screenshot from 2026-02-15 19-20-25.png"
638                            alt="Terminal showing cthru spending and commbuys_cli vendor search results"></a></div>
639                    <div class="tool-info">
640                        <h3><a href="https://github.com/JonGerhardson/commbuys_cli" target="_blank"
641                                rel="noopener">commbuys_cli</a> &amp; <a
642                                href="https://github.com/JonGerhardson/cthru_cli" target="_blank"
643                                rel="noopener">cthru_cli</a></h3>
644                        <div class="tool-sub">CLI tools · Python</div>
645                        <p>Two command-line tools for querying state financial data in Massachusetts. commbuys_cli
646                            searches bid solicitations, contracts, and vendors on the COMMBUYS procurement portal.
647                            cthru_cli queries spending, payroll, and retirement data from CTHRUspending.mass.gov. Both
648                            support filtering, multiple output formats, and JSON export.</p>
649                    </div>
650                </div>
651
652                <div class="tool-item">
653                    <div class="lb-wrap" id="lb-9"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-9" class="tool-visual"><img src="code/Screenshot from 2026-02-15 15-26-55.png"
654                            alt="Mass.gov update bot Bluesky profile with daily posts"></a></div>
655                    <div class="tool-info">
656                        <h3><a href="https://bsky.app/profile/massgovupdatesbot.bsky.social" target="_blank" rel="noopener">Mass.gov
657                                Update Bot</a></h3>
658                        <div class="tool-sub">@massgovupdatesbot.bsky.social · Python</div>
659                        <p>Scrapes mass.gov/sitemap.xml daily and posts a summary of updated pages to Bluesky. Tracks
660                            hundreds of state government website changes per day, and logs each day's changes to a csv
661                            file.</p>
662                        <p>This is part of a larger pipeline for discovering potential news leads beyond agency press
663                            releases, that is still a work
664                            in progress.</p>
665                    </div>
666                </div>
667
668                <div class="tool-item">
669                    <div class="lb-wrap" id="lb-10"><a href="#_" class="lb-close" aria-label="Close"></a><a href="#lb-10" class="tool-visual"><img src="code/Screenshot from 2026-02-15 19-36-21.png"
670                            alt="reccomend_from_archive web interface showing playlist recommendations"></a></div>
671                    <div class="tool-info">
672                        <h3><a href="https://github.com/JonGerhardson/reccomend_from_archive" target="_blank"
673                                rel="noopener">reccomend_from_archive</a></h3>
674                        <div class="tool-sub">Web app &amp; CLI · Python</div>
675                        <p>(Personal/for fun project) A music recommender that analyzes your Spotify streaming history
676                            against scraped Spotify
677                            metadata for over 250 million tracks released by Anna's Archive
678                            and finds tracks you'll like based on your listening history, using an algorithm you
679                            control.
680                            <br> Note: no music is streamed or stored, only metadata.
681                        </p>
682                    </div>
683                </div>
684
685            </div>
686        </div>
687
688    </main>
689
690    <footer>
691        <div>
692            <a href="mailto:[email protected]">[email protected]</a>
692 ·
693            <a href="https://github.com/JonGerhardson" target="_blank" rel="noopener">GitHub</a> ·
694            <a href="https://bsky.app/profile/jongerhardson.bsky.social" target="_blank" rel="noopener">Bluesky</a>
695        </div>
696        <div>© 2026</div>
697    </footer>
698
699
700</body>
701
702</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.