<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Justin Miller</title>
    <description>Maker, programmer, photographer, and traveler in Portland, Oregon, USA.
</description>
    <link>https://justinmiller.io/</link>
    <atom:link href="https://justinmiller.io/index.xml" rel="self" type="application/rss+xml" />
    <image>
        <url>https://justinmiller.io/apple-touch-icon-144-precomposed.png</url>
        <title>Justin Miller</title>
        <link>https://justinmiller.io/</link>
    </image>
    <lastBuildDate>Wed, 29 Apr 2026 12:21:00 -0700</lastBuildDate>
    <generator>Hugo 0.147.8 (https://gohugo.io)</generator>
      <item>
        <title>Ten Years Gone</title>
        <description>&lt;p&gt;Though it&amp;rsquo;s not the day that I want to most remember her by, I can&amp;rsquo;t let today go by without noting that &lt;a href=&#34;https://standstrongwithus.justinmiller.io/2016-04-30/&#34;&gt;it&amp;rsquo;s been ten years since Michelle passed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you didn&amp;rsquo;t know her, or maybe even if you did, you can read &lt;a href=&#34;https://standstrongwithus.justinmiller.io/2016-05-03/&#34;&gt;her obituary&lt;/a&gt; or &lt;a href=&#34;https://standstrongwithus.justinmiller.io/2016-05-30/&#34;&gt;the eulogy that I gave at her funeral&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Instead, I choose to remember her by her adventures, by her unbridled enthusiasm for life and fun activities, by her generosity of her time to friends and strangers alike, and by her instigation of all of those things in others. Michelle was the ultimate instigator.&lt;/p&gt;
&lt;p&gt;I think about Michelle every day, and while I miss her very much, the thing that still hits me the hardest is the fact that the world is missing out on having her in it.&lt;/p&gt;
&lt;figure&gt;
    &lt;img src=&#34;https://justinmiller.io/img/20170618.jpg&#34;/&gt;
    &lt;figcaption&gt;&lt;em&gt;Her first big run, the Sauvie Island half marathon; cuddling sled dog pups in Skagway, Alaska; visiting &lt;a href=&#34;https://en.wikipedia.org/wiki/Slappy_Cakes&#34;&gt;Slappy Cakes&lt;/a&gt;; enjoying a beer in the sun&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Although it caused some difficulty at first, I consider it a testamant &lt;em&gt;to&lt;/em&gt; Michelle that I was able to move on and continue a normal life relatively soon after she passed. Amazing support from family, friends, and my employer at the time was also a huge factor in this. I always heard Michelle&amp;rsquo;s voice in my ear, telling me to get out there and to keep soaking life in. I&amp;rsquo;m also very thankful for our house family, our cat Macy and our dog Ronny, both passed now, who helped me in that transition. There were days of just lying on the floor, crying with them, mourning.&lt;/p&gt;
&lt;figure&gt;
    &lt;img src=&#34;https://justinmiller.io/img/album_cover.jpg&#34;/&gt;
    &lt;figcaption&gt;&lt;em&gt;Lying around, 2014. We always said this would make a good album cover.&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I was very involved &lt;em&gt;publicly&lt;/em&gt; with &lt;a href=&#34;https://pancan.org&#34;&gt;PanCAN&lt;/a&gt; right after Michelle died, even &lt;a href=&#34;https://justinmiller.io/img/wyden.jpg&#34;&gt;meeting with my senator in DC&lt;/a&gt; and &lt;a href=&#34;https://justinmiller.io/talks/#PurpleStride-Portland-2016-KATU-TV-AM-Northwest-Show-2016&#34;&gt;being interviewed on live TV&lt;/a&gt;. But after a couple years, I found it difficult to continue this public outreach. I was very good at it — I was a top fundraiser and was recognized on stage, and the second year, I was the head of the Oregon delegation in DC. But doing that required that I keep the wounds very fresh, that I bring Michelle to life &lt;em&gt;as&lt;/em&gt; my wife and to emphasize the hole left behind in my life. Maybe it could be done another way, but for me, it&amp;rsquo;s what felt right in that circumstance. But I found that I couldn&amp;rsquo;t continue doing that year after year. I support efforts in my own way now, but this public chapter has long been closed for me.&lt;/p&gt;
&lt;p&gt;I have been so incredibly lucky to have &lt;em&gt;two&lt;/em&gt; loves in my life, Michelle and now Jessica. Some days I can&amp;rsquo;t even believe the fortune with which I have been gifted. In a sense, Michelle and I grew into adults together, and the life we led with each other put me in a place where I was much more prepared to move on when she was gone. I am somewhat conflicted in saying that, but it&amp;rsquo;s how I feel, and I am incredibly thankful. You always hear as much, but I discovered firsthand that there is no right way to mourn, or to recover, or to move on. You have to do what it takes — for you — to keep yourself from unraveling entirely when such a tragedy hits.&lt;/p&gt;
&lt;p&gt;They say that we have two deaths, one when we die physically and the other the last time there is someone alive who remembers us. I consider it my sacred duty to keep Michelle alive for as long as I can. If &lt;em&gt;you&lt;/em&gt; ever want to talk, or to share — reach out. I am always here, remembering.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Changes fill my time, baby, that&amp;rsquo;s all right with me&lt;br/&gt;
In the midst I think of you, and how it used to be&lt;/p&gt;
&lt;p&gt;Led Zeppelin, Ten Years Gone&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;</description>
        <pubDate>Wed, 29 Apr 2026 12:21:00 -0700</pubDate>
        <link>https://justinmiller.io/posts/2026/04/29/ten-years-gone/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2026/04/29/ten-years-gone/</guid>
      </item>
      <item>
        <title>Supercon 2025 Badge Hack</title>
        <description>&lt;p&gt;I greatly enjoyed &lt;a href=&#34;https://hackaday.io/superconference/&#34;&gt;Hackaday Supercon&lt;/a&gt; again this year after attending for the first time in 2023. Why did I miss last year? I don&amp;rsquo;t have a good reason, but it&amp;rsquo;s not happening again!&lt;/p&gt;
&lt;p&gt;One of my favorite parts, and probably of many attendees, is the badge hacking. This year&amp;rsquo;s badge (&lt;a href=&#34;https://hackaday.com/2025/10/27/the-supercon-2025-badge-is-built-to-be-customized/&#34;&gt;announcement&lt;/a&gt;, &lt;a href=&#34;https://github.com/Hack-a-Day/2025-Communicator_Badge&#34;&gt;GitHub&lt;/a&gt;, &lt;a href=&#34;https://github.com/Hack-a-Day/2025-Communicator_Badge/blob/main/hardware/communicator_pcb/communicator_pcb.pdf&#34;&gt;schematic&lt;/a&gt;) was an extra bonus as &lt;em&gt;I love small handheld computers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;badge.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I spent a lot of Saturday in and around conference sessions thinking about possible hacks. Nothing was really jumping out at me other than maybe a tiny language interpreter, but I didn&amp;rsquo;t feel like that made for a compelling demo (watch me program on a tiny keyboard!)&lt;/p&gt;
&lt;p&gt;When I got up on Sunday, I had a strong idea: using the &lt;del&gt;Shitty&lt;/del&gt; Standard Add-On port &lt;a href=&#34;https://hackaday.com/2019/03/20/introducing-the-shitty-add-on-v1-69bis-standard/&#34;&gt;which is on the front of Supercon badges&lt;/a&gt; to add a quick bit of hardware and write a graphical synthesizer keyboard. We&amp;rsquo;ve got PWM-capable GPIO, we&amp;rsquo;ve got graphics, we&amp;rsquo;ve got a keyboard. And serendipitously, the diagonal spacing on the SAO header between GPIO pin 1 and a ground is pretty close to the pin spacing of a &lt;a href=&#34;https://www.adafruit.com/product/160&#34;&gt;simple piezo buzzer&lt;/a&gt; with minimal bending.&lt;/p&gt;
&lt;p&gt;Thus was born &lt;em&gt;Synthy Add-On&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my presentation of the hack at the closing session, about eight hours of attempted normal conference attendance after I hatched the idea:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;hack.mp4&#34;&gt;&lt;img src=&#34;hack.png&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also watch &lt;a href=&#34;https://www.youtube.com/watch?v=21uoyTfOWQw&#34;&gt;the video of everyone&amp;rsquo;s hacks&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;My code is &lt;a href=&#34;https://github.com/incanus/synthy-add-on&#34;&gt;over on GitHub&lt;/a&gt;. True to the spirit, it&amp;rsquo;s pretty hacky, especially the graphics drawing placement, but the core of things, the synthesizing, is pretty simple and clean.&lt;/p&gt;
&lt;p&gt;Basically I&amp;rsquo;m just using &lt;a href=&#34;https://docs.micropython.org/en/latest/esp32/quickref.html#pwm-pulse-width-modulation&#34;&gt;pulse width modulation&lt;/a&gt; on GPIO pin 1 (which corresponds to the top right pin on the SAO header) to configure and create a square wave. The frequency corresponds exactly to the musical note frequency (since that&amp;rsquo;s how sound works) and the duty cycle can be used for either a normal 50% square wave — 512 (half of the 10-bit max) corresponds to &lt;em&gt;note on&lt;/em&gt; — or by setting it to zero (unlike a &lt;em&gt;frequency&lt;/em&gt; of zero, which has unexpected noise) you can get a &lt;em&gt;note off&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I edited things right on the badge using &lt;a href=&#34;https://thonny.org&#34;&gt;Thonny&lt;/a&gt; on my laptop, which bills itself as a &amp;ldquo;Python IDE for beginners&amp;rdquo; but I find really nice even for complicated on-device MicroPython work (which this isn&amp;rsquo;t, really).&lt;/p&gt;
&lt;p&gt;A couple other implementation notes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I grabbed the note frequencies from a standard chart that I found online.
&lt;img src=&#34;frequencies.png&#34; style=&#34;margin: 10px;&#34;/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I modeled the keyboard after that of Apple&amp;rsquo;s GarageBand.
&lt;img src=&#34;keyboard.png&#34;/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I made a note auto-off of 250ms, but interruptible by continued user action. That way, if you tap a note, it will play for a short time, but if you tap a number of notes in succession, it will switch the pin output to play the new note right away. I do the auto-off by keeping track of when the last note started, then each pass of the main program loop, checking if 250ms have passed yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tested things around the conference using my &lt;a href=&#34;https://www.seeedstudio.com/DSO-Nano-v3.html&#34;&gt;pocket oscilliscope&lt;/a&gt; instead of audio output, which was both fun and, I&amp;rsquo;m sure, appreciated by those around me trying to get their own work done.
&lt;img src=&#34;scope.jpg&#34; style=&#34;margin: 10px;&#34;/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;One of the trickier bits was figuring out the API for the &lt;a href=&#34;https://github.com/lvgl/lv_binding_micropython&#34;&gt;LVGL MicroPython bindings&lt;/a&gt;. While I appreciate the work put into them, it&amp;rsquo;s one thing to have docs for the C API, but another entirely to then have to mentally figure out how constants, function names, and other structures have been ported to MicroPython. I&amp;rsquo;m sure it&amp;rsquo;s easy for anyone immersed in LVGL already or who knows the library backwards and forwards, but for someone trying to build something new, it&amp;rsquo;s a &lt;em&gt;lot&lt;/em&gt; of work. Some of the links that I found helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://deepwiki.com/lvgl/lv_binding_micropython/5.2-advanced-demos&#34;&gt;advanced demos on DeepWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ndrogness/lvgl_micropython_examples&#34;&gt;these examples&lt;/a&gt;, especially &lt;a href=&#34;https://github.com/ndrogness/lvgl_micropython_examples/blob/master/widgets/lv_canvas/lv_canvas.py&#34;&gt;&lt;code&gt;lv_canvas.py&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://forum.lvgl.io/t/need-guidance-with-lvgl9-canvas-in-micropython/17522/2&#34;&gt;this LVGL forum post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://baxterbuilds.com/micropython-lvgl-canvas-example/&#34;&gt;these canvas examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Given more time, I would have done more and cooler sound synth such as some of David Johnson-Davies&amp;rsquo; projects like his &lt;a href=&#34;http://www.technoblogy.com/show?2E6L&#34;&gt;Tiny MIDI Player&lt;/a&gt;. I&amp;rsquo;ve played with some of his ideas before and was greatly inspired by them for my &lt;a href=&#34;https://justinmiller.io/posts/2020/12/23/ornament/&#34;&gt;PCB Christmas tree ornament&lt;/a&gt; among other projects.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Special thanks also to &lt;a href=&#34;https://www.devstuff.com&#34;&gt;John Bates&lt;/a&gt; from here in Portland who was also down at the conference and who I just &lt;em&gt;knew&lt;/em&gt; would have a piezo lying around that I could use (he gave me five, and also had both 3.3V and 5V available).&lt;/p&gt;
&lt;p&gt;Lastly, unrelated to my badge, I also gave a seven-minute lightning talk about &lt;a href=&#34;https://justinmiller.io/projects/catchthewave&#34;&gt;&lt;em&gt;Catch the Wave!&lt;/em&gt;&lt;/a&gt; which you can find &lt;a href=&#34;https://justinmiller.io/talks/#Using-Abusing-Microcontrollers-Chromebooks-and-Electromagnetism-for-Science-Education-Fun-and-No-Profit-Hackaday-Supercon-2025&#34;&gt;on my talks page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;</description>
        <pubDate>Mon, 01 Dec 2025 15:15:49 -0800</pubDate>
        <link>https://justinmiller.io/posts/2025/12/01/supercon-2025-badge-hack/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2025/12/01/supercon-2025-badge-hack/</guid>
      </item>
      <item>
        <title>When Having a Computer Was Weird</title>
        <description>&lt;p&gt;I just finished up the first weekend of my vintage computer exhibit for &lt;a href=&#34;https://www.pdxdesignmonth.com&#34;&gt;Portland Design Month&lt;/a&gt; entitled &lt;a href=&#34;https://justinmiller.io/projects/weirdcomputer&#34;&gt;When Having a Computer Was Weird: A showcase of early personal computers&lt;/a&gt;. I had two fun groups of visitors and I plan to run another date on &lt;a href=&#34;https://calendly.com/fusionindustries/weirdcomputer?month=2024-10&#34;&gt;October 18&lt;/a&gt;, plus others as time permits and interest demands.&lt;/p&gt;
&lt;p&gt;I have eight vintage computers from &lt;a href=&#34;https://justinmiller.io/projects/retrocomputing&#34;&gt;my collection&lt;/a&gt; on display, working and ready for people to try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Atari Video Computer System (a.k.a. Atari 2600, 1977)&lt;/li&gt;
&lt;li&gt;Texas Instruments TI-99/4A (1981)&lt;/li&gt;
&lt;li&gt;Commodore 64 (1982)&lt;/li&gt;
&lt;li&gt;Commodore 128 (1985)&lt;/li&gt;
&lt;li&gt;Radio Shack TRS-80 Model 100 (1983)&lt;/li&gt;
&lt;li&gt;Dolch PAC 386-25 clone (1989)&lt;/li&gt;
&lt;li&gt;Macintosh Plus (1986)&lt;/li&gt;
&lt;li&gt;Power Macintosh 8500 (1995)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the machines are kitted out with various accessories such as game cartridges, CRT displays, cassette tape program loading and saving, disk drives and floppies, joysticks, musical keyboards, manuals, and contemporary books and magazines. Visitors can play games, write documents, try applications, or craft programs.&lt;/p&gt;
&lt;h3 id=&#34;a-computer-museum&#34;&gt;A computer museum&lt;/h3&gt;
&lt;p&gt;This exhibit is a stab in the direction of something I&amp;rsquo;ve wanted to do for a while, which is to create a space locally where people of all ages can experience yesterday&amp;rsquo;s computing technologies firsthand. Eventually I would love to see a space like this with many more examples, staffed by local volunteers, experts, and enthusiasts.&lt;/p&gt;
&lt;p&gt;Aside from my own experience with this era of computing, I intend this as an homage as well to the old, old Powell&amp;rsquo;s Tech bookstore, back when it was on the North Park Blocks here in Portland.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/the_impression_that_i_get/944305699/&#34;&gt;&lt;img src=&#34;https://live.staticflickr.com/1321/944305699_c136328daa_c_d.jpg&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Circa 2007 (Flickr user &lt;code&gt;the_impression_that_i_get&lt;/code&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;While the computers there were merely decoration around the shelves, seeing them in person evoked a strong sense of technological history when I first experienced it over twenty years ago.&lt;/p&gt;
&lt;p&gt;These days, Powell&amp;rsquo;s Tech is folded into the main site on West Burnside and these computers have scattered to the wind, like so many before them. We are only ever seeing less and less of these older computers, especially in their full usable glory.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/caseorganic/4492681634/&#34;&gt;&lt;img src=&#34;caseorganic1.jpg&#34;/&gt;&lt;/a&gt;
&lt;a href=&#34;https://www.flickr.com/photos/caseorganic/4492681894/&#34;&gt;&lt;img src=&#34;caseorganic2.jpg&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Some Powell&amp;rsquo;s Tech interior photos from 2010 (Flickr user &lt;code&gt;caseorganic&lt;/code&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;right-at-home&#34;&gt;Right at home&lt;/h3&gt;
&lt;p&gt;I decided to host this event at home, having moved earlier this year and now having a large garage workshop for this sort of thing. I used some hanging drop cloths to block out the distracting parts of the building and I setup table displays around the room.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;cloth1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;cloth2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;m pretty happy with the end results.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;result1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;result2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Being at home, I was also able to make some last-minute repairs and tweaks on various machines as needed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;macplusfix.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;gallery&#34;&gt;Gallery&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve leave you with some closeup photos of things setup and running, along with their rough thematic groups from &lt;a href=&#34;https://justinmiller.io/projects/weirdcomputer&#34;&gt;the original exhibit proposal&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;on-the-living-room-tv&#34;&gt;On The Living Room TV&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;tv.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;atari.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ti.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;the-rise-of-commodore&#34;&gt;The Rise of Commodore&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;commodore.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;c64.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;c128.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;going-mobile-walk-before-you-run&#34;&gt;Going Mobile: Walk Before You Run&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;mobile.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;model100.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;386.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;the-ascent-of-apple&#34;&gt;The Ascent of Apple&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;apple.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;macplus.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;powermac.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;special-thanks&#34;&gt;Special thanks&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;d like to give a shout out to &lt;a href=&#34;https://www.haikusoftware.com&#34;&gt;Tyler Morrison&lt;/a&gt; for table, chair, and &lt;a href=&#34;https://bluescsi.com&#34;&gt;BlueSCSI&lt;/a&gt; lending, &lt;a href=&#34;https://www.sharebrained.com&#34;&gt;Jared Boone&lt;/a&gt; for CRT TV lending, &lt;a href=&#34;https://www.linkedin.com/in/andrew-kreps-a3a2b193?lipi=urn%3Ali%3Apage%3Ad_flagship3_profile_view_base_contact_details%3BWuF%2BVI5CT%2BKQbPCS%2FqEVZA%3D%3D&#34;&gt;Andrew Kreps&lt;/a&gt; for late-game 3D printing, &lt;a href=&#34;http://sensoriumembedded.com&#34;&gt;Travis Smith&lt;/a&gt; for his excellent &lt;a href=&#34;https://www.tindie.com/products/travissmith/teensyrom-cartridge-for-c64128/&#34;&gt;TeensyROM&lt;/a&gt; and its prompt delivery, and my peeps at NSPDX for moral support, ideas, and general hilarity during projects.&lt;/p&gt;
&lt;h3 id=&#34;the-exhibit-is-ongoing&#34;&gt;The exhibit is ongoing&lt;/h3&gt;
&lt;p&gt;If this is something that interests you or someone you know, there&amp;rsquo;s still time to see it. I have one other definitive day of exhibit groups on &lt;a href=&#34;https://calendly.com/fusionindustries/weirdcomputer?month=2024-10&#34;&gt;October 18&lt;/a&gt;, plus could add more if there is interest. Please spread the word.&lt;/p&gt;</description>
        <pubDate>Wed, 09 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://justinmiller.io/posts/2024/10/09/weird-computer/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2024/10/09/weird-computer/</guid>
      </item>
      <item>
        <title>Creating an electromagnet and sound wave learning environment</title>
        <description>&lt;p&gt;I&amp;rsquo;ve been meaning for a while to write more about one of my recent projects, &lt;a href=&#34;https://justinmiller.io/projects/catchthewave&#34;&gt;&lt;em&gt;Catch the Wave!&lt;/em&gt;&lt;/a&gt;. Originally it was made for last year&amp;rsquo;s &lt;a href=&#34;https://omsi.edu/events/oregon-science-festival-2024/&#34;&gt;Oregon Science Festival&lt;/a&gt; and since I&amp;rsquo;m exhibiting again at the festival this year (&lt;strong&gt;this weekend&lt;/strong&gt;, in fact!) I thought now was as good a time as any.&lt;/p&gt;
&lt;h3 id=&#34;what-is-it&#34;&gt;What is it?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Catch the Wave!&lt;/em&gt; is a public science education project, with the side goal of bettering my own ability to make a museum-caliber interactive experience.&lt;/p&gt;
&lt;p&gt;The project is a series of four small, colorful, table-top wooden cabinets with physical controls and screens, each of which explores a concept related to electromagnets and sound waves and how they are used for audio recording and playback.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ctw_all.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Catch the Wave!&lt;/em&gt; has been a personal challenge and a labor of love. Aside from the building of it, I&amp;rsquo;ve staffed several full days&amp;rsquo; worth of events at multiple locations in order to benefit the community at large in an educational way.&lt;/p&gt;
&lt;h3 id=&#34;why&#34;&gt;Why?&lt;/h3&gt;
&lt;p&gt;The main prompt for this project was an opportunity to submit a proposal for my local science museum&amp;rsquo;s inaugural STEM event — the &lt;a href=&#34;https://www.portlandtribune.com/lifestyle/omsi-science-extravaganza-caps-inaugural-oregon-science-festival/article_0ad879a8-4dd6-11ee-9758-bf8bed1ed28c.html&#34;&gt;Oregon Science Festival&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Beyond the initial event, I&amp;rsquo;ve been wanting to work on something for the public that is more portable than, say, &lt;a href=&#34;https://justinmiller.io/projects/chromakey/&#34;&gt;an eight-foot xylophone&lt;/a&gt;, more directly learning-oriented, and something in line with my continued interest in synthesized audio and waveforms.&lt;/p&gt;
&lt;h3 id=&#34;the-four-stations&#34;&gt;The four stations&lt;/h3&gt;
&lt;p&gt;The exhibit is meant to be approached in order, each station building upon previous stations&amp;rsquo; concepts.&lt;/p&gt;
&lt;h4 id=&#34;station-1-what-is-an-electromagnet&#34;&gt;Station 1: What is an electromagnet?&lt;/h4&gt;
&lt;p&gt;What is an electromagnet? Turns out, if you wrap some lightly-insulated wire around a metal core and then run electrical current through it, you create a magnet. Turn the current on, it&amp;rsquo;s a magnet. Turn it off, it&amp;rsquo;s just a coil of wire. You can directly experience the connection between electrical current and magnetism.&lt;/p&gt;
&lt;p&gt;Participants can push a button to run current through a professionally-wound electromagnet and get paper clips to stick when it&amp;rsquo;s on. Jaws typically drop when this is demonstrated and it&amp;rsquo;s begging for hands-on fun as people attempt to see how many they can get to stick.&lt;/p&gt;
&lt;video style=&#34;max-width: 100%;&#34; preload=&#34;metadata&#34; x-webkit-airplay=&#34;allow&#34; webkit-playsinline=&#34;&#34; src=&#34;ctw1_electromagnets.mp4&#34; controls poster=&#34;ctw1_poster.png&#34;&gt;
    Sorry, your browser doesn&#39;t support this embedded video, but you can &lt;a href=&#34;./ctw1_electromagnets.mp4&#34;&gt;download it directly&lt;/a&gt;.
&lt;/video&gt;
&lt;p&gt;&lt;a href=&#34;ctw1_handout.pdf&#34;&gt;&lt;em&gt;Download the handout PDF&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;station-2-changing-magnetic-polarity&#34;&gt;Station 2: Changing magnetic polarity&lt;/h4&gt;
&lt;p&gt;If you run current through the coil in one direction, the magnet&amp;rsquo;s polarity is aligned a certain way (you can read more about the &lt;a href=&#34;https://en.wikipedia.org/wiki/Right-hand_rule#Amp%C3%A8re&#39;s_right-hand_grip_rule&#34;&gt;right-hand rule&lt;/a&gt;). If you reverse the current, you reverse this alignment. So the second station is a larger version of the first station&amp;rsquo;s electromagnet hooked up to a two-way toggle switch. Suspended above the electromagnet is a permanent, regular magnet on a swing which can be attracted and repelled as the magnetic forces change. So now you can see how electrical current and physical motion are related! Folks seem to also have a lot of fun with this one as they attempt to get the swing to move the most distance or to see how fast they can switch the current&amp;rsquo;s direction.&lt;/p&gt;
&lt;video style=&#34;max-width: 100%;&#34; preload=&#34;metadata&#34; x-webkit-airplay=&#34;allow&#34; webkit-playsinline=&#34;&#34; src=&#34;ctw2_polarity.mp4&#34; controls poster=&#34;ctw2_poster.png&#34;&gt;
    Sorry, your browser doesn&#39;t support this embedded video, but you can &lt;a href=&#34;./ctw2_polarity.mp4&#34;&gt;download it directly&lt;/a&gt;.
&lt;/video&gt;
&lt;p&gt;&lt;a href=&#34;ctw2_handout.pdf&#34;&gt;&lt;em&gt;Download the handout PDF&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;station-3-fast-changes-make-sound&#34;&gt;Station 3: Fast changes make sound&lt;/h4&gt;
&lt;p&gt;Imagine if you could flip that switch, as well as the magnetic polarity, hundreds or even thousands of times per second. Or imagine it more like a slider, controlling how much current flows in a direction. A computer or a synthesizer is able to do this electronically. If you then have a thin membrane like paper or plastic that can be moved by this physical interaction between the permanent magnet and the electromagnet, the vibrations of the membrane vibrate the air around it. If your ear is close enough, and the number of vibrations is in a certain range, the vibrating air also vibrates your eardrum and you can hear a sound! This is what we call the &lt;em&gt;frequency&lt;/em&gt; of a sound.&lt;/p&gt;
&lt;p&gt;The station lets you play with a knob to adjust the frequency in the audible range, as well as the waveform.&lt;/p&gt;
&lt;video style=&#34;max-width: 100%;&#34; preload=&#34;metadata&#34; x-webkit-airplay=&#34;allow&#34; webkit-playsinline=&#34;&#34; src=&#34;ctw3_sound.mp4&#34; controls poster=&#34;ctw3_poster.png&#34;&gt;
    Sorry, your browser doesn&#39;t support this embedded video, but you can &lt;a href=&#34;./ctw3_sound.mp4&#34;&gt;download it directly&lt;/a&gt;.
&lt;/video&gt;
&lt;p&gt;&lt;a href=&#34;ctw3_handout.pdf&#34;&gt;&lt;em&gt;Download the handout PDF&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can think of the waveform as the pattern of movement of the membrane. Quickly switching between fully one direction and fully the other is a square wave. Switching more slowly in one direction, but quickly in the other could be described as a sawtooth wave, rising before sharply dropping.&lt;/p&gt;
&lt;p&gt;These waveforms sound different to our ear. And you can even feel the sound by touching the center of the speaker at the lower frequencies, much like how you can feel a subwoofer&amp;rsquo;s sound. This is because the membrane vibrations are moving the tissue in your body as well as the air around you.&lt;/p&gt;
&lt;p&gt;Even at its most basic level, people have fun with this station since it makes noise and has very hands-on controls.&lt;/p&gt;
&lt;h4 id=&#34;station-4-complex-waves&#34;&gt;Station 4: Complex waves&lt;/h4&gt;
&lt;p&gt;The last station lets you record your own voice into a microphone, then play it back, optionally with effects applied like pitch shifting, reversing, and echoing. The same electromagnetic principles are at work in this system, but here you can just focus on the fun of sound.&lt;/p&gt;
&lt;video style=&#34;max-width: 100%;&#34; preload=&#34;metadata&#34; x-webkit-airplay=&#34;allow&#34; webkit-playsinline=&#34;&#34; src=&#34;ctw4_complex.mp4&#34; controls poster=&#34;ctw4_poster.png&#34;&gt;
    Sorry, your browser doesn&#39;t support this embedded video, but you can &lt;a href=&#34;./ctw4_complex.mp4&#34;&gt;download it directly&lt;/a&gt;.
&lt;/video&gt;
&lt;p&gt;&lt;a href=&#34;ctw4_handout.pdf&#34;&gt;&lt;em&gt;Download the handout PDF&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The everyday sounds around us like speech, music, or nature rarely sound just like synthesized sound coming from a computer. This is because they are formed of many overlapping and interacting waves to add richness to the patterns. Using electromagnets, we can record the electrical signals made by sound and then computers can alter these signals before playing them back.&lt;/p&gt;
&lt;p&gt;People love hearing their own voice in &amp;ldquo;chipmunk style&amp;rdquo; or a lot higher or lower frequency than their normal speech. It&amp;rsquo;s a very concrete way to see how these concepts apply to everyday life and to practical effects.&lt;/p&gt;
&lt;h3 id=&#34;reactions-to-the-project&#34;&gt;Reactions to the project&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve gotten a lot of feedback from kids and adults alike about how much they like the progression of concepts in the project. People range from having no idea about how any of this worked to being involved directly with some of the concepts — musicians, equipment builders, teachers, and others — but still taking something away from the stations&amp;rsquo; hands-on nature. It&amp;rsquo;s been very gratifying for me to give something to people in this way.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;ctw_stemday.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;future-installments&#34;&gt;Future installments&lt;/h3&gt;
&lt;p&gt;In future posts, I&amp;rsquo;d like to talk about some of the build details as well as some of the educational considerations and takeaways that went into and resulted from this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chromebooks are amazingly hackable!&lt;/li&gt;
&lt;li&gt;They don&amp;rsquo;t have to even look like Chromebooks!&lt;/li&gt;
&lt;li&gt;Table saws are wonderful tools for repetitive work!&lt;/li&gt;
&lt;li&gt;Sanding, priming, painting, and clearcoating is a laborious process!&lt;/li&gt;
&lt;li&gt;Some kids have never seen an audio speaker!&lt;/li&gt;
&lt;li&gt;Kids can have fun with tech that isn&amp;rsquo;t a touchscreen!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And speaking of kids and having fun, I knew this already in the abstract, but kids can always educate you very directly when it comes to user interfaces and the gulf between their intended and real-world uses. I feel like as with many projects, I&amp;rsquo;ve learned a lot myself even with this project that was intended as a teaching experience.&lt;/p&gt;
&lt;p&gt;As with all of my projects, please &lt;a href=&#34;https://justinmiller.io/contact&#34;&gt;get in touch&lt;/a&gt; if you&amp;rsquo;d like to talk about &lt;em&gt;Catch the Wave!&lt;/em&gt; or get more info.&lt;/p&gt;</description>
        <pubDate>Wed, 11 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://justinmiller.io/posts/2024/09/11/catch-wave-overview/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2024/09/11/catch-wave-overview/</guid>
      </item>
      <item>
        <title>fari: fast Safari tab browsing</title>
        <description>&lt;p&gt;I&amp;rsquo;ve been hacking on and off for a few years on a little open source side project, &lt;a href=&#34;https://github.com/incanus/fari&#34;&gt;fari&lt;/a&gt;. It&amp;rsquo;s a terminal-based utility for the Mac for quickly zipping through the tabs that you&amp;rsquo;ve got open in Safari.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;fari.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Recently, I started picking it back up again as I have been meaning to apply some research into getting at Safari&amp;rsquo;s iCloud Tabs and even Tab Groups.&lt;/p&gt;
&lt;p&gt;iCloud Tabs are a way to see — and open locally — any browser tabs that you might have open on another iCloud-enabled device — including an iPhone or iPad. This is nice if you start reading in one place and want to continue somewhere else later, or if you&amp;rsquo;ve got a machine physically elsewhere and want to get at its tabs. This feature has been around in Safari for a few years.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;icloud_tabs.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Safari Tab Groups are a bit newer and are a way to create and manage named groups of tabs that are easily accessible to all of your devices. They&amp;rsquo;re meant to be more project-based, where you can open a window for a group and work with it, then put it away for another time — on this device or any other.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;tab_groups.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;While I haven&amp;rsquo;t released it yet, I&amp;rsquo;ve been hacking on improvements to fari to handle both of these types of cloud-based tabs quickly and efficiently.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quick overview video of the features fari has now, as well as how iCloud Tabs are coming:&lt;/p&gt;
&lt;div style=&#34;margin: 20px auto;&#34;&gt;
&lt;div style=&#34;padding:65.03% 0 0 0;position:relative;&#34;&gt;&lt;iframe src=&#34;https://player.vimeo.com/video/905059924?badge=0&amp;amp;autopause=0&amp;amp;player_id=0&amp;amp;app_id=58479&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; fullscreen; picture-in-picture&#34; style=&#34;position:absolute;top:0;left:0;width:100%;height:100%;&#34; title=&#34;fari: fast safari tab browsing&#34;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;script src=&#34;https://player.vimeo.com/api/player.js&#34;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;ll likely post here when a new release happens or you can just watch &lt;a href=&#34;https://github.com/incanus/fari&#34;&gt;the GitHub project&lt;/a&gt; for progress.&lt;/p&gt;</description>
        <pubDate>Sun, 21 Jan 2024 21:11:42 -0800</pubDate>
        <link>https://justinmiller.io/posts/2024/01/21/fari/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2024/01/21/fari/</guid>
      </item>
      <item>
        <title>Winter Walk</title>
        <description>&lt;p&gt;Took a ~4 mile walk in the newly-snowy neighborhood this afternoon. For the &lt;a href=&#34;https://justinmiller.io/projects/photography/&#34;&gt;first time in years&lt;/a&gt;, I grabbed my camera to go along.&lt;/p&gt;
&lt;p&gt;I need to retrain my eye to look for photo opportunities. Feeling a little rusty so far.&lt;/p&gt;
&lt;img src=&#34;winter_walk_1.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;img src=&#34;winter_walk_2.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;img src=&#34;winter_walk_3.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;img src=&#34;winter_walk_4.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;img src=&#34;winter_walk_5.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;img src=&#34;winter_walk_6.jpg&#34; style=&#34;box-shadow: 5px 5px 10px lightgray;&#34;/&gt;
&lt;p&gt;You can read a bit more about Futel and the payphone &lt;a href=&#34;https://futelco.tumblr.com/post/717954542749286401/new-public-phone-at-ghost-mountain-se-40th-and&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
        <pubDate>Sun, 14 Jan 2024 16:43:50 -0800</pubDate>
        <link>https://justinmiller.io/posts/2024/01/14/winter-walk/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2024/01/14/winter-walk/</guid>
      </item>
      <item>
        <title>How my link blog works</title>
        <description>&lt;p&gt;Despite not posting stuff as much as I&amp;rsquo;d like to get around to on this site, I do keep my &lt;a href=&#34;https://justinmiller.io/links/&#34;&gt;link blog&lt;/a&gt; pretty active. It lets me share publicly some links to things on the web, sometimes with commentary.&lt;/p&gt;
&lt;p&gt;I run the &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; content management system, but the generalities could apply to a lot of systems if this is something that you&amp;rsquo;d like to replicate.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an overview of how I use it and how it works. The moving parts are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Saving links while browsing&lt;/li&gt;
&lt;li&gt;Bringing content into Hugo&lt;/li&gt;
&lt;li&gt;Displaying content in Hugo&lt;/li&gt;
&lt;li&gt;Creating an RSS feed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;saving-links&#34;&gt;Saving links&lt;/h3&gt;
&lt;p&gt;While I&amp;rsquo;ve technically got content currently from four places — &lt;a href=&#34;https://pinboard.in/u:incanus&#34;&gt;Pinboard&lt;/a&gt; (my account is private by default on that site), &lt;a href=&#34;https://github.com/incanus?tab=stars&#34;&gt;GitHub starred repositories&lt;/a&gt;, and &lt;a href=&#34;https://www.thingiverse.com/incanus/likes&#34;&gt;Thingiverse&lt;/a&gt; and &lt;a href=&#34;https://cults3d.com/en/users/incanus77/likes&#34;&gt;Cults&lt;/a&gt; likes of 3D printed designs, only the first two are really active, so I&amp;rsquo;ll focus on those as examples in case they might serve as inspiration for your own sort of system.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll start with GitHub. All I do is press the star button on a repository. Easy. Something I was doing already anyway.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;github_star.gif#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;For Pinboard, I use one of the &lt;a href=&#34;https://pinboard.in/howto&#34;&gt;bookmarklets&lt;/a&gt;, which is way of using a bit of JavaScript code as a browser bookmark that, when visited, will capture information about the current page and turn it around into a Pinboard posting popup window.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;safari_bookmarks.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The bookmarklet code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;javascript&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSelection&lt;/span&gt;){&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSelection&lt;/span&gt;();}&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;;};&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;document.&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://pinboard.in/add?url=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;encodeURIComponent(&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;amp;description=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;encodeURIComponent(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;amp;title=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;encodeURIComponent(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Pinboard&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;toolbar=no,width=700,height=350&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to streamline this, I made a Safari-specific keyboard shortcut, &lt;strong&gt;⌘B&lt;/strong&gt; (hat tip to &lt;a href=&#34;https://apple.stackexchange.com/questions/4074/what-do-i-type-to-produce-the-command-symbol-in-mac-os-x&#34;&gt;this StackExchange post&lt;/a&gt; for info on producing the ⌘ symbol).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;mac_shortcut.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This works because you can setup keyboard shortcuts system-wide in any app by menu item name and I&amp;rsquo;ve appropriately named the bookmarklet, which shows up in Safari&amp;rsquo;s &lt;strong&gt;Bookmarks&lt;/strong&gt; menu, even though I never use it there. Just having it buried somewhere in the Mac menu system for Safari is enough for the shortcut to be able to access it.&lt;/p&gt;
&lt;p&gt;For Pinboard, there&amp;rsquo;s also a &lt;a href=&#34;https://pinboard.in/resources/&#34;&gt;page of posting clients&lt;/a&gt;, so you do you. I actually used to work on my own Mac-native posting client, &lt;a href=&#34;https://justinmiller.io/#pukka&#34;&gt;Pukka&lt;/a&gt;, but it is, alas, no more. It was part of what got me interested in Pinboard in the first place.&lt;/p&gt;
&lt;p&gt;When posting a link to Pinboard, there are five things that I do specifically for my system.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I might highlight some page content before using the bookmarklet, which gets transferred into the description field as a starting point (&lt;code&gt;document.getSelection()&lt;/code&gt; takes care of this above).&lt;/li&gt;
&lt;li&gt;I remove any tracking or other query string crap from the URL so that it is clean for the next person.&lt;/li&gt;
&lt;li&gt;I edit out the oft-added site name at the end of the page title.&lt;/li&gt;
&lt;li&gt;Alongside my normal tags, I add a special tag (&lt;code&gt;links&lt;/code&gt;) if it&amp;rsquo;s something that I want to show up on this site.&lt;/li&gt;
&lt;li&gt;Optionally, I add or edit the commentary, possibly with quoting (using Markdown&amp;rsquo;s &lt;code&gt;&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;pinboard_posting.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&#34;https://daringfireball.net/projects/markdown/&#34;&gt;Markdown&lt;/a&gt; in the description since this will eventually get piped through to my site and rendered by Hugo. I like sparing use of italics (&lt;code&gt;_foo_&lt;/code&gt;) or bold (&lt;code&gt;**bar**&lt;/code&gt;) and sometimes bullet lists (&lt;code&gt;- baz&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With both GitHub and Pinboard, I can bookmark while I&amp;rsquo;m browsing, not have to think about it very much, and move on.&lt;/p&gt;
&lt;h3 id=&#34;bringing-content-into-hugo&#34;&gt;Bringing content into Hugo&lt;/h3&gt;
&lt;p&gt;The next part of the system is something that I&amp;rsquo;ll either do manually on a fairly regular basis or as part of my deployment of other new content (like this post) on the site.&lt;/p&gt;
&lt;p&gt;Basically, for each link source, I&amp;rsquo;ve written a Python script to use its API to download content. There is a lot of potential for reuse between them still, and I&amp;rsquo;m not proud of the code, but it&amp;rsquo;s for me and it works. I&amp;rsquo;d consider releasing them, but this does not come without the possibility of support. I&amp;rsquo;d rather this post serve as an inspiration for similar systems.&lt;/p&gt;
&lt;p&gt;For GitHub, I use their stars endpoint, which doesn&amp;rsquo;t even require authentication, since this is public data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;USERNAME &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;incanus&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;STORE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./data/links/github_stars.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PER_PAGE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;URL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api.github.com/users/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;USERNAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/starred?per_page=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;PER_PAGE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEADERS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Accept&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;application/vnd.github.v3.star+json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The paging allows my script to compare results with what it has on disk and only grab recent pages of results as needed.&lt;/p&gt;
&lt;p&gt;After some munging, I store things into the JSON file in &lt;a href=&#34;https://gohugo.io/templates/data-templates/&#34;&gt;the sort of place where Hugo likes data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For Pinboard, I use my account username and password and their API.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;STORE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./data/links/pinboard_public.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TAG &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;links&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PER_PAGE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;URL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;USERNAME&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;PASSWORD&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api.pinboard.in/v1/posts/recent&amp;#34;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;?tag=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;TAG&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;amp;format=json&amp;amp;count=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;PER_PAGE&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similar sort of thing here — munge the various fields in the JSON received from Pinboard into a common format for Hugo in &lt;em&gt;its&lt;/em&gt; JSON on disk.&lt;/p&gt;
&lt;h3 id=&#34;displaying-content-in-hugo&#34;&gt;Displaying content in Hugo&lt;/h3&gt;
&lt;p&gt;I feel like &lt;a href=&#34;https://gohugo.io/templates/data-templates/&#34;&gt;Hugo&amp;rsquo;s page on data templates&lt;/a&gt; does a pretty good job of explaining how it works. In my case, an individual entry in a link data file (regardless of source) looks something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The Un-Brie-Lievable History of Tyromancy&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;gt; Predicting the future using cheese is something I do as a side business, and from what I can tell, there aren\u2019t very many of us doing this anymore.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://www.saveur.com/culture/tyromancy-cheese-divination/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2024-01-11T19:07:39Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pinboard_public&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing that I don&amp;rsquo;t bring through is my Pinboard tags, since sometimes these refer to private projects or I otherwise don&amp;rsquo;t want to post what I&amp;rsquo;m tagging things under.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s the &lt;code&gt;kind&lt;/code&gt; field that I use to distinguish in my rendering code how things are displayed.&lt;/p&gt;
&lt;p&gt;An entry on the &lt;a href=&#34;https://justinmiller.io/links/&#34;&gt;links page&lt;/a&gt; looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;pinboard_entry.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;I like a terse version of the domain right after the title, and at the bottom, a permalink and bookmark date.&lt;/p&gt;
&lt;p&gt;For GitHub stars, I pull the repository description if it exists so that things look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;github_entry.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what&amp;rsquo;s in my &lt;code&gt;layouts/section/links.html&lt;/code&gt; to accomplish this, broken down a little.&lt;/p&gt;
&lt;p&gt;First, start off the page by pulling a parameter from my &lt;code&gt;config.yaml&lt;/code&gt; related to how many links I want to show per page.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;posts&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; (.&lt;span style=&#34;color:#a6e22e&#34;&gt;Paginate&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Site&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Counts&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LinksPage&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Pages&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ByDate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reverse&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, output the title linking to the URL and munge the link domain a bit to clean it up.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;article&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h2&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;post-title&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .Params.target }}&amp;#34;&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h2&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;domain&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;urls&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Parse&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Host&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;replaceRE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^www.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;font-size: 0.75em; color: gray;&amp;#34;&lt;/span&gt;&amp;gt;{{ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;domain&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the main body of the entry, depending on what type of link it is, I&amp;rsquo;ll do some processing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For GitHub stars, fill in a default description (since a lot of repos don&amp;rsquo;t have one) and display that description as if it were quoted content.&lt;/li&gt;
&lt;li&gt;For Thingiverse or Cults likes, include a thumbnail image of the model.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Content&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;chomp&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_no description_&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github_star&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;gt; %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thingiverse_like&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cults_like&amp;#34;&lt;/span&gt;)) (&lt;span style=&#34;color:#a6e22e&#34;&gt;delimit&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;a href=\&amp;#34;&amp;#34;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\&amp;#34;&amp;gt;&amp;lt;img src=\&amp;#34;&amp;#34;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;thumbnail&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\&amp;#34; style=\&amp;#34;width: 350px; margin: 20px 0px 25px 0px; box-shadow: 5px 5px 10px lightgray;\&amp;#34;/&amp;gt;&amp;lt;/a&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s what a Thingiverse entry looks like.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;thingiverse_thumbnail.png#bordered&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;In all cases, I run the resulting description through a few Hugo filters to render it safely.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&amp;gt;{{ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;markdownify&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;emojify&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;safeHTML&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lastly, I add the permalink and date and close out the entry.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;datetime&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .Date.Local.Format &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2006&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;02&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T15&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;04&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;05&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;post-date&amp;#34;&lt;/span&gt;&amp;gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;🔗&lt;/span&gt; {{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Date&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Local&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Format&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mon, Jan 2, 2006 at 3:04pm&amp;#34;&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;article&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;end&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Individual link pages (something I added fairly recently, after a few years with this system) are more or less the same, just in &lt;code&gt;layouts/links/single.html&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;The link pages themselves have permalinks, so that each link that I&amp;rsquo;ve put on my site has a permanent page on which to live, allowing anyone else to link to &lt;em&gt;that&lt;/em&gt; if they like. Is anyone doing that? I don&amp;rsquo;t know. I&amp;rsquo;d just like to give them the option. At the very least, it lets me link to my link-of-a-link, in case I want to pass my version (and commentary) of the link to someone else. And most importantly, I have my own links backed up, locally, in my website code. Combined with a paid Pinboard account&amp;rsquo;s &lt;a href=&#34;https://pinboard.in/tour/#archive&#34;&gt;archival service&lt;/a&gt;, this is a pretty good personal copy of my stuff.&lt;/p&gt;
&lt;p&gt;The permalinks and the pages they link to get generated by a little &lt;code&gt;links.py&lt;/code&gt; that I run. They look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jstasiak/python-zeroconf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;date&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;2020-05-02T19:38:41&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;target&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;https://github.com/jstasiak/python-zeroconf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;github_star&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;A pure python implementation of multicast DNS service discovery&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This file, as an example, lives forever at &lt;code&gt;content/links/07bsoxfTSm.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The one thing that took some puzzling here (most of it is mungy-munge on the &lt;code&gt;data&lt;/code&gt; JSON into the Markdown file) is the unique URL string (&lt;code&gt;07bsoxfTSm&lt;/code&gt; above). I landed on the &lt;a href=&#34;https://sqids.org&#34;&gt;Sqids&lt;/a&gt; library for this, using it like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sq &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Sqids(min_length&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; kind &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; kinds&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;keys():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	l &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; run(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ls content/links/*.md&amp;#39;&lt;/span&gt;, shell&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;, capture_output&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	l &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; l&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stdout&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;data/links/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;kind&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.json&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		schema &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; kinds[kind]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;load(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; b &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; j[schema[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;container&amp;#39;&lt;/span&gt;]]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			d1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; int(datetime&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;fromisoformat(b[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;date&amp;#39;&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;])&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;timestamp())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			d2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; len(b[schema[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;metadata&amp;#39;&lt;/span&gt;]] &lt;span style=&#34;color:#f92672&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			h &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sq&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode([d1, d2])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;content/links/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;h&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.md&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; l:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script will, for each kind of link, compare the &lt;code&gt;data&lt;/code&gt; file with the existing links files on disk in &lt;code&gt;content/links&lt;/code&gt; to see if any links need a page generated for them. They then spit out the above content stub pages for Hugo to pickup and render according to the &lt;code&gt;layouts/links/single.html&lt;/code&gt; template.&lt;/p&gt;
&lt;p&gt;The Sqids-generated ID is based on a combination of the bookmark date (&lt;code&gt;d1&lt;/code&gt;) and the &amp;ldquo;metadata&amp;rdquo; of the bookmark (&lt;code&gt;d2&lt;/code&gt;) which is either the description text or, for the thumbnail links, the thumbnail URL. I&amp;rsquo;ve got to commit to a certain description before publishing the final version if I don&amp;rsquo;t want the &amp;ldquo;permalink&amp;rdquo; to change.&lt;/p&gt;
&lt;p&gt;I realize that I am skipping a &lt;em&gt;lot&lt;/em&gt; of functionality here, as well as assuming a large amount of familiarity with Hugo and its usage. Again, I hope this gives you some ideas on &lt;em&gt;a way&lt;/em&gt; (not the best way! not necessarily the way for your site!) that you could accomplish such a thing.&lt;/p&gt;
&lt;p&gt;This is very much a hacker&amp;rsquo;s way of jamming things together to just barely work, but it does the job for me. I&amp;rsquo;m fully aware that this is not for the average writer on their site. And it saddens me quite a bit to consider that in the past 15 or 20 years, instead of bringing this sort of functionality to everyone, instead we have giant data silos like Facebook or unprogrammable-but-nice site management solutions like Squarespace. The best I can hope for right now is to maybe show other hackers how I did this. I like sharing (and reading!) glimpses of others&amp;rsquo; techniques as much as I like reading everything else on the web.&lt;/p&gt;
&lt;h3 id=&#34;creating-an-rss-feed&#34;&gt;Creating an RSS feed&lt;/h3&gt;
&lt;p&gt;Speaking of nerds, the last bit of this system is an RSS feed. At this point, you&amp;rsquo;d probably not be surprised (or you know already) that Hugo makes RSS feeds quite easy.&lt;/p&gt;
&lt;p&gt;There is a page stub at &lt;code&gt;content/pages/links.xml.md&lt;/code&gt; that puts the feed in the right place.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;layout: links
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title: Links
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;url: /links.xml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;outputs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;-&lt;/span&gt; rss
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And there is a layout template at &lt;code&gt;layouts/pages/links.xml&lt;/code&gt; that builds up the feed XML.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;?xml version=\&amp;#34;1.0\&amp;#34; encoding=\&amp;#34;utf-8\&amp;#34; standalone=\&amp;#34;yes\&amp;#34;?&amp;gt;&amp;#34;&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;safeHTML&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;rss&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;atom&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.w3.org/2005/Atom&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;channel&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Site&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Author&lt;/span&gt; }} &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Links&lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Site&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Description&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;&amp;gt;{{ &lt;span style=&#34;color:#a6e22e&#34;&gt;ref&lt;/span&gt; . &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;links.md&amp;#34;&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is perhaps the most concise example of how Hugo combines &lt;em&gt;content&lt;/em&gt; files and &lt;em&gt;layout&lt;/em&gt; files in order to create the final rendered pages. Sometimes the content is in the actual page, but oftentimes, like this, it&amp;rsquo;s all in the layout (combined with data files) instead.&lt;/p&gt;
&lt;p&gt;Once again we&amp;rsquo;re looping through the site content, with &lt;code&gt;LinksFeed&lt;/code&gt; as the item count so that it can potentially be different than the HTML version.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;first&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Site&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Counts&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LinksFeed&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;where&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Site&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RegularPages&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Section&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;links&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;ByDate&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reverse&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And an individual link RSS entry looks like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;domain&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;urls&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Parse&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Host&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;replaceRE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^www.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;{{ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;domain&lt;/span&gt; }}&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Content&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_no description_&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github_star&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;gt; %s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;kind&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thingiverse_like&amp;#34;&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;delimit&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;a href=\&amp;#34;&amp;#34;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\&amp;#34;&amp;gt;&amp;lt;img src=\&amp;#34;&amp;#34;&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;thumbnail&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\&amp;#34; style=\&amp;#34;width: 350px;\&amp;#34;/&amp;gt;&amp;lt;/a&amp;gt;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;desc&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;markdownify&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;emojify&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;🔗&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lt&lt;/span&gt;;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gt&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pubDate&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Date&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Format&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mon, 02 Jan 2006 15:04:05 -0700&amp;#34;&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;safeHTML&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pubDate&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Permalink&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;guid&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;isPermaLink&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;guid&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A lot of this is a variation on the HTML version, so I won&amp;rsquo;t cover much of it. I just wanted to show some of the RSS/XML-specific tweaks needed to make this all work.&lt;/p&gt;
&lt;h3 id=&#34;wrapping-up&#34;&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;I do feel like I moved through this rather quickly (and it&amp;rsquo;s &lt;em&gt;still&lt;/em&gt; long!) and again, it is admittedly Hugo-specific in its code content. I hope that it can be useful, though, to see how to build up such a system, as well as to highlight the fact that it takes an experienced programmer and somewhat half-assed blog author at least a dozen programming languages and/or data formats to put something like this together 30+ years into the web. I guess I started out enthusiastic about sharing some useful technical bits, and ended up rather pensive about an end result that I feel should be available to more people.&lt;/p&gt;
&lt;p&gt;However, I think that this shows another good reason to blog, which is to actually take a moment to reflect on it all and assess the state of things. In that vein, I&amp;rsquo;d be curious to hear what other folks think about this or what they use for similar systems.&lt;/p&gt;
</description>
        <pubDate>Thu, 11 Jan 2024 11:46:34 -0800</pubDate>
        <link>https://justinmiller.io/posts/2024/01/11/link-blog/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2024/01/11/link-blog/</guid>
      </item>
      <item>
        <title>Repurposing Hugo as a wiki</title>
        <description>&lt;p&gt;As part of a project that I&amp;rsquo;m working on, I decided to see if I could repurpose the excellent &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; website framework (which also powers this very site) as a single-user wiki of sorts.&lt;/p&gt;
&lt;p&gt;Short version: &lt;strong&gt;yes&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;site.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;requirements&#34;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;The main features that I wanted were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The ability to, while writing a page, &lt;strong&gt;freely link&lt;/strong&gt; to other topic pages that I know will (or at least plan to make) exist &lt;em&gt;in future&lt;/em&gt;, without having to worry about if they exist &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An automatically-updating &lt;strong&gt;visual indication&lt;/strong&gt; of whether a linked-to page does or does not exist yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A common &lt;strong&gt;&amp;ldquo;coming soon&amp;rdquo; page&lt;/strong&gt; that the missing links will land on (i.e. no actual &lt;a href=&#34;https://en.wikipedia.org/wiki/HTTP_404&#34;&gt;404&amp;rsquo;s&lt;/a&gt; for content linked in this manner; normal site 404 functionality is untouched).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;strong&gt;simplicity of writing&lt;/strong&gt; in &lt;a href=&#34;https://daringfireball.net/projects/markdown/&#34;&gt;Markdown&lt;/a&gt; that I am so used to already, especially because this is a technical project featuring lots of code syntax highlighting in the content.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;why-not-wiki-software-x&#34;&gt;Why not &amp;lt;wiki software X&amp;gt;?&lt;/h3&gt;
&lt;p&gt;The main reason that I didn&amp;rsquo;t want to use an established wiki package like &lt;a href=&#34;https://www.mediawiki.org/wiki/MediaWiki&#34;&gt;MediaWiki&lt;/a&gt;, the software behind Wikipedia, was that it seemed like overkill. For this project, I don&amp;rsquo;t need separate authors, I don&amp;rsquo;t need revisions of pages, and I &lt;em&gt;certainly&lt;/em&gt; don&amp;rsquo;t need a database server.&lt;/p&gt;
&lt;p&gt;Hugo exists to create static HTML websites, supports Markdown formatting, is fast, and has a powerful &lt;a href=&#34;https://gohugo.io/content-management/shortcodes/&#34;&gt;shortcode system&lt;/a&gt; which can be extended.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s make it happen. But first, before I get too far into the weeds, let&amp;rsquo;s take a look at the end result and how simple it is to use while writing.&lt;/p&gt;
&lt;h3 id=&#34;using-the-custom-shortcode&#34;&gt;Using the custom shortcode&lt;/h3&gt;
&lt;p&gt;I created a &lt;a href=&#34;https://gohugo.io/templates/shortcode-templates/&#34;&gt;custom shortcode&lt;/a&gt; called &lt;code&gt;link&lt;/code&gt;. Here&amp;rsquo;s how you use it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For linking to a page where the &lt;a href=&#34;https://gohugo.io/content-management/urls/#slug&#34;&gt;page slug&lt;/a&gt; is the same as the word you want clickable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;other&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will produce the link text &lt;u&gt;other&lt;/u&gt; linking to &lt;code&gt;/pages/other/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For linking to a page where you want to make clickable some custom text:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;my text here&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;other2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will produce the link text &lt;u&gt;my text here&lt;/u&gt; linking to &lt;code&gt;/pages/other2/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s it. &lt;strong&gt;But critically&lt;/strong&gt;: if in the above examples the pages &lt;code&gt;other&lt;/code&gt; or &lt;code&gt;other2&lt;/code&gt; don&amp;rsquo;t exist, the link will be styled in a noticeable way (in my case, red instead of blue) and will link to (also, in my case) &lt;code&gt;/pages/missing/&lt;/code&gt;. Whenever I get around to adding said page, all existing links to it will auto-update and become blue in future.&lt;/p&gt;
&lt;h3 id=&#34;overview-of-components&#34;&gt;Overview of components&lt;/h3&gt;
&lt;p&gt;A few things need to happen to bring this configuration together.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Enable Goldmark renderer &lt;a href=&#34;https://gohugo.io/getting-started/configuration-markup/&#34;&gt;&amp;ldquo;unsafe&amp;rdquo; mode&lt;/a&gt;. This allows rendering of inline HTML in shortcodes. A reason why you would &lt;em&gt;not&lt;/em&gt; want this enabled is if you have untrusted users and/or untrusted content. For me and this project, neither of these apply.&lt;/p&gt;
&lt;p&gt;In your &lt;code&gt;hugo.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;markup&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;goldmark&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;renderer&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;unsafe&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create and configure the common &amp;ldquo;missing&amp;rdquo; page and &lt;a href=&#34;https://gohugo.io/content-management/cross-references/#ref-and-relref-configuration&#34;&gt;make it so that unreachable-by-Hugo pages are not fatal errors&lt;/a&gt; in the rendering process.&lt;/p&gt;
&lt;p&gt;In your &lt;code&gt;hugo.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;refLinksErrorLevel&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;WARNING&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;refLinksNotFoundURL&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/pages/missing/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the shortcode. As per above, I used the name &lt;code&gt;link&lt;/code&gt;, which means I created a &lt;code&gt;layouts/shortcodes/link.html&lt;/code&gt; containing the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;urls&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RelRef&lt;/span&gt; . (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) (.&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) (.&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $link }}&amp;#34;&lt;/span&gt;{{ &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;relref&lt;/span&gt; . &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;missing&amp;#34;&lt;/span&gt;) }} &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;missing&amp;#34;&lt;/span&gt;{{ &lt;span style=&#34;color:#a6e22e&#34;&gt;end&lt;/span&gt; }}&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Please forgive the line wrapping. Since a shortcode gets replaced inline in your content, and since I didn&amp;rsquo;t want to add extra spacing or linebreaks in my content, the shortcode is just two (long-ish) lines.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the &lt;code&gt;missing&lt;/code&gt; class in your theme&amp;rsquo;s CSS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;main&lt;/span&gt;#content &lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;missing&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;#f00&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;how-the-shortcode-works&#34;&gt;How the shortcode works&lt;/h3&gt;
&lt;p&gt;The shortcode took the most work, as the other bits were just a little configuration tweaking and some strategic web searching in order to puzzle through some minor issues. Here&amp;rsquo;s how it works.&lt;/p&gt;
&lt;h4 id=&#34;line-1-resolve-destination&#34;&gt;Line 1: Resolve destination&lt;/h4&gt;
&lt;p&gt;In the first line, a &lt;code&gt;$link&lt;/code&gt; variable is created which benefits from the flexibility of specifying either one or two arguments to the shortcode — one if the page slug and linked text are the same, and two if they differ.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;urls&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RelRef&lt;/span&gt; . (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt; .&lt;span style=&#34;color:#a6e22e&#34;&gt;Params&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) (.&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) (.&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I will add that spending a lot of time recently in Lisp and other similar languages which are composed of &lt;a href=&#34;https://en.wikipedia.org/wiki/S-expression&#34;&gt;S-expressions&lt;/a&gt; has made Go syntax like &lt;code&gt;(cond (eq (len .Params) 2)...&lt;/code&gt; much more natural to me.&lt;/p&gt;
&lt;p&gt;The best part about the use of &lt;a href=&#34;https://gohugo.io/functions/urls/relref/&#34;&gt;&lt;code&gt;urls.RelRef&lt;/code&gt;&lt;/a&gt; in the link buildup is that the links are filename- and reorganization-independent. If you use a destination page filename of &lt;code&gt;other.md&lt;/code&gt;, a shortcode argument of &lt;code&gt;other&lt;/code&gt; will find it. If you use a filename of &lt;code&gt;other-page.md&lt;/code&gt; but a &lt;code&gt;slug&lt;/code&gt; within its front matter of &lt;code&gt;other&lt;/code&gt;, it will also work. If you change the location of resources but keep either of these the same, it will be found. And finally, if the page cannot be found (likely because it doesn&amp;rsquo;t exist yet, one of the requirements of tolerance in this system), the &amp;ldquo;missing&amp;rdquo; common page will be linked (in my configuration above, &lt;code&gt;/pages/missing/&lt;/code&gt;).&lt;/p&gt;
&lt;h4 id=&#34;line-2-conditionally-style-link-text&#34;&gt;Line 2: Conditionally style link text&lt;/h4&gt;
&lt;p&gt;Moving on from the &lt;code&gt;$link&lt;/code&gt; setup, the other line of the shortcode sets up a standard HTML anchor link &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag highlighting the shortcode&amp;rsquo;s first argument as the link text. Most importantly, if the link resolves to the common missing page, this can be detected and the custom &amp;ldquo;doesn&amp;rsquo;t exist yet&amp;rdquo; CSS is applied to the link.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{ $link }}&amp;#34;&lt;/span&gt;{{ &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;urls&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RelRef&lt;/span&gt; . &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;missing&amp;#34;&lt;/span&gt;) }} &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;missing&amp;#34;&lt;/span&gt;{{ &lt;span style=&#34;color:#a6e22e&#34;&gt;end&lt;/span&gt; }}&amp;gt;{{ .&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; }}&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Astute readers and/or optimization nerds will notice that this technically relies on duplication of the &lt;code&gt;missing&lt;/code&gt; term — once here and once in the &lt;code&gt;hugo.yaml&lt;/code&gt; part which sets up the missing page for failed &lt;code&gt;urls.RelRef&lt;/code&gt; resolution. While I would have liked to avoid this, no Hugo function exists to get at the same of the &lt;code&gt;refLinksNotFoundURL&lt;/code&gt; variable specified in the site configuration. The closest I got was &lt;a href=&#34;https://gohugo.io/methods/site/config/&#34;&gt;&lt;code&gt;.Site.Config&lt;/code&gt;&lt;/a&gt;, but that only exposes the &lt;code&gt;services&lt;/code&gt; and &lt;code&gt;privacy&lt;/code&gt; keys as a subset of the configuration. Argh, code duplication.&lt;/p&gt;
&lt;h3 id=&#34;exciting-conclusion&#34;&gt;Exciting conclusion&lt;/h3&gt;
&lt;p&gt;All in all, I&amp;rsquo;m quite happy with this. While I&amp;rsquo;ve only really begun the actual buildout of the site for which this system was contrived, it&amp;rsquo;s already reducing mental overhead and allowing me to see some structure to the site without having to worry about writing it all or even creating placeholder page files for now.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s definitely a case of &lt;a href=&#34;https://xkcd.com/974/&#34;&gt;The General Problem&lt;/a&gt;, though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://xkcd.com/974/&#34;&gt;&lt;img src=&#34;https://imgs.xkcd.com/comics/the_general_problem.png&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What can I say? I&amp;rsquo;m most certainly a developer and &lt;a href=&#34;https://two-wrongs.com/john-the-toolmaker&#34;&gt;toolmaker&lt;/a&gt; at heart. I prefer to take inspiration here from Abraham Lincoln as quoted in the previous link:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I had six hours to chop down a tree, I would spend the first four sharpening the axe.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;bonus-visual-studio-code-snippets&#34;&gt;Bonus: Visual Studio Code snippets&lt;/h3&gt;
&lt;p&gt;Not content with a mere single level of &lt;a href=&#34;https://www.wordnik.com/words/yak%20shaving&#34;&gt;yak shaving&lt;/a&gt;, and in keeping with the spirit of the preceding section, I also wanted a quick way to insert these shortcode-based links into my writing. I learned about &lt;a href=&#34;https://code.visualstudio.com/docs/editor/userdefinedsnippets&#34;&gt;VS Code snippets&lt;/a&gt; which are both easy and powerful, and I was able to create a project-specific &lt;code&gt;.vscode/snippets.code-snippets&lt;/code&gt; file with the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;Insert wiki page link&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scope&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;markdown&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;prefix&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{{% link ${1:linked text} ${2:slug} %}}&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, in my project, whenever I type &lt;code&gt;link&lt;/code&gt;, I can &lt;code&gt;Tab&lt;/code&gt; to get a popup suggestion with tab-completion into the two fields for easy fill-out. And if I only want one shortcode argument, I can easily delete the second tabbed-to argument.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;tab.gif&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;bonus-2-extra-meta&#34;&gt;Bonus 2: Extra-meta&lt;/h3&gt;
&lt;p&gt;In the process of writing this post in Hugo and about Hugo, I discovered a puzzler of a problem with including the example shortcode in the usage and snippets examples — the shortcode doesn&amp;rsquo;t actually exist on &lt;em&gt;this&lt;/em&gt; site, but was still being interpreted by Hugo as a shortcode in this post&amp;rsquo;s content, causing the page render to fail. Bless &lt;a href=&#34;https://liatas.com/posts/escaping-hugo-shortcodes/&#34;&gt;this kind soul, Chris Liatas&lt;/a&gt;, for writing about a technique to work around this using C-style code comments, thereby allowing me to display unparsed Hugo code in a post about Hugo code within a system running Hugo code.&lt;/p&gt;
&lt;hr/&gt;
&lt;div style=&#34;font-size: 0.7em;&#34; id=&#34;lobsters&#34;&gt;
See the &lt;a href=&#34;https://lobste.rs/s/i8qnvf&#34;&gt;discussion&lt;/a&gt; about this post on Lobsters.
&lt;/div&gt;</description>
        <pubDate>Wed, 27 Dec 2023 16:04:34 -0800</pubDate>
        <link>https://justinmiller.io/posts/2023/12/27/hugo-as-wiki/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2023/12/27/hugo-as-wiki/</guid>
      </item>
      <item>
        <title>Now page year-end 2023</title>
        <description>&lt;p&gt;I just updated my &lt;a href=&#34;https://justinmiller.io/now&#34;&gt;now page&lt;/a&gt;. I like it because it&amp;rsquo;s something I can do three or four times a year, pretty casually, and feel like I&amp;rsquo;m not so behind in talking about WTF I&amp;rsquo;m actually doing with my time.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s a nice way to reflect a bit and regroup.&lt;/p&gt;</description>
        <pubDate>Fri, 22 Dec 2023 11:35:48 -0800</pubDate>
        <link>https://justinmiller.io/posts/2023/12/22/now-2023-end/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2023/12/22/now-2023-end/</guid>
      </item>
      <item>
        <title>The wave&#39;s been caught</title>
        <description>&lt;p&gt;I successfully finished and &amp;ldquo;shipped&amp;rdquo; my booth, &lt;em&gt;&lt;a href=&#34;https://justinmiller.io/projects/catchthewave/&#34;&gt;Catch the Wave!&lt;/a&gt;&lt;/em&gt;, at the inaugural &lt;a href=&#34;https://omsi.edu/events/oregon-science-festival/&#34;&gt;OMSI Oregon Science Festival&lt;/a&gt; this past weekend.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t have a good sense of how many people I interacted with over the course of the two days, but I would guess somewhere in the mid- to high-hundreds. There was very little downtime from 9:30-5:30 both days, and because my experiment stations were setup in an ordered way, I don&amp;rsquo;t think I could have handled any more people than I did.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;wave1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Broadly, my personal goals for this project, aside from obviously making a compelling booth, were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;trying my hand at a science museum-caliber build&lt;/li&gt;
&lt;li&gt;getting better at my planning and execution process&lt;/li&gt;
&lt;li&gt;making something more transportable and reusable in future&lt;/li&gt;
&lt;li&gt;exercising some educational concepts I&amp;rsquo;ve been working on in another project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope to write up more soon about what I made, as well as the multi-month process leading up to it, but for the next few days at least, I&amp;rsquo;m taking a bit of a break — still with other projects I need to work on, though. I always have intentions of writing things up more, and this time I am taking them very seriously as a way to continue using this project in other contexts. I am trying to see the &lt;em&gt;after&lt;/em&gt; part of the project as just as important as the &lt;em&gt;making&lt;/em&gt; and &lt;em&gt;showing&lt;/em&gt; parts.&lt;/p&gt;
&lt;p&gt;Roughly, the work on this project involved:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;researching electromagnetic concepts&lt;/li&gt;
&lt;li&gt;designing fun and compelling hands-on demos for a variety of ages&lt;/li&gt;
&lt;li&gt;acquiring, re-flashing, and repurposing second-hand Chromebooks&lt;/li&gt;
&lt;li&gt;designing, building, painting, finishing, and securing wooden enclosures&lt;/li&gt;
&lt;li&gt;sourcing electronic components&lt;/li&gt;
&lt;li&gt;3D printing enclosure and experiment parts&lt;/li&gt;
&lt;li&gt;designing, laying out, soldering, and enclosing electronics&lt;/li&gt;
&lt;li&gt;writing microcontroller firmware&lt;/li&gt;
&lt;li&gt;writing apps for the display screens to interact with the electronics&lt;/li&gt;
&lt;li&gt;designing, laying out, printing, and laminating accompanying visual guides&lt;/li&gt;
&lt;li&gt;designing and ordering stickers&lt;/li&gt;
&lt;li&gt;designing, setting up, and hosting a &lt;a href=&#34;https://wavecatchers.club&#34;&gt;web-based discussion forum&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can only seem to do one of these types of projects every year or two, as they are mentally and, near the end, very physically exhausting. While I have detailed planning and concepting stages throughout, I always seem to be very deadline-driven when it comes to putting on the final touches to what becomes the eventual project. I&amp;rsquo;m going to spend some time reflecting on that, as I always do, and see what I can learn about myself and my process. I will say that this time only involved a few hours at the end of &amp;ldquo;wow, I&amp;rsquo;m desperate for this project to be over so I can get off this ride&amp;rdquo;, rather than days or weeks.&lt;/p&gt;
&lt;p&gt;All of the toil to ship a physical thing that is used by the public is worth it, though, for moments like these.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;wave2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Special thanks to Jessica for support, staffing help, and last-minute laminating, and to &lt;a href=&#34;https://samgrover.com&#34;&gt;Sam&lt;/a&gt; and &lt;a href=&#34;https://www.jennijelsing.com&#34;&gt;Jenni&lt;/a&gt; for stopping by and giving me a bit of a break.&lt;/p&gt;</description>
        <pubDate>Mon, 18 Sep 2023 11:19:24 -0700</pubDate>
        <link>https://justinmiller.io/posts/2023/09/18/wave-caught/</link>
        <guid isPermaLink="true">https://justinmiller.io/posts/2023/09/18/wave-caught/</guid>
      </item>
  </channel>
</rss>