CINXE.COM

Robb Knight • Posts • RSS Feed

<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet href="/subscribe/styles.xsl" type="text/xsl"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://rknight.me" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <docs>https://rknight.me/subscribe/posts/rss.xml</docs> <title>Robb Knight • Posts • RSS Feed</title> <link>https://rknight.me</link> <description>Maker of web things, Lego builder, sometimes blogger, sporadic pizzaiolo, fortnightly podcaster. Cat dad and human dad.</description> <language>en-gb</language> <item> <title>Installing GoToSocial on Coolify</title> <link>https://rknight.me/blog/installing-gotosocial-on-coolify/</link> <description>&lt;p&gt;For various reasons I had occasion this evening to give &lt;a href=&quot;https://gotosocial.org&quot;&gt;GoToSocial&lt;/a&gt; a try so I installed it on my server that&#39;s running &lt;a href=&quot;https://coolify.io&quot;&gt;Coolify&lt;/a&gt; but hit a couple of issues which I was able to work around with the help of &lt;a href=&quot;https://lewisdale.dev&quot;&gt;Lewis&lt;/a&gt; and &lt;a href=&quot;https://wand3r.net&quot;&gt;Brandon&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;First up because it&#39;s running a reverse proxy, I needed the third option in the Docker compose file.&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ports:&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;# - &quot;443:8080&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;## For letsencrypt:&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;#- &quot;80:80&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;## For reverse proxy setups:&lt;/span&gt;&lt;br /&gt; - &lt;span class=&quot;token string&quot;&gt;&quot;127.0.0.1:8082:8080&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The second issue was GoToSocial couldn&#39;t access the database, giving this error in the logs:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sqlite ping: sqlite3: unable to &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt; database &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;a href=&quot;https://github.com/superseriousbusiness/gotosocial/issues/476&quot;&gt;This GitHub issue&lt;/a&gt; showed it was a permissions issue where the &lt;code&gt;user&lt;/code&gt; specified in the docker compose isn&#39;t the one that has permissions for the &lt;code&gt;gotosocial/data&lt;/code&gt; file. I could have tried to work out what the user and group was &lt;em&gt;or&lt;/em&gt; I could &lt;code&gt;chmod&lt;/code&gt; my way out this problem. Guess which one I picked. In Coolify go to &lt;code&gt;Terminal&lt;/code&gt; in the sidebar, choose the project GoToSocial is installed on then connect and &lt;code&gt;cd&lt;/code&gt; to the directory. Then set permissions on the data directory.&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /data/coolify/services/isjdbvfihsavfids/&lt;br /&gt;$ &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;777&lt;/span&gt; gotosocial/data&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I got the directory it&#39;s installed at (&lt;code&gt;/isjdbvfihsavfids&lt;/code&gt;) by checking the &lt;code&gt;storage&lt;/code&gt; tab on the GoToSocial service in Coolify.&lt;/p&gt; &lt;p&gt;Other notes:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;code&gt;/settings&lt;/code&gt; gets you to the settings page of your account.&lt;/li&gt; &lt;li&gt;Default visibility of posts is &amp;quot;unlisted&amp;quot;, a difference from Mastodon where it&#39;s public by default. You can change this in settings.&lt;/li&gt; &lt;li&gt;Other instance-level settings (like custom CSS on profiles) can be changed in the &lt;code&gt;config.yaml&lt;/code&gt; file, see &lt;a href=&quot;https://docs.gotosocial.org/en/latest/configuration/&quot;&gt;the docs on configuration here&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;Making a user an admin requires restarting the server.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;I&#39;m still playing around with GoToSocial but it&#39;s looking like a good solution for what I want - something easier to maintain than Mastodon and less resource-intensive.&lt;/p&gt; </description> <pubDate>Wed, 20 Nov 2024 21:00:33 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/installing-gotosocial-on-coolify/</guid> </item> <item> <title>Stopping Mastodon From Fetching Metadata for My Notes</title> <link>https://rknight.me/blog/stopping-mastodon-from-fetching-metadata-for-my-notes/</link> <description>&lt;p&gt;I&#39;m trying to move towards &lt;a href=&quot;https://indieweb.org/POSSE&quot;&gt;POSSE&lt;/a&gt; for my short/micro posts and one thing I wasn&#39;t sure about was if those short posts should link back to the source or not. I &lt;a href=&quot;https://social.lol/@robb/113464032762475185&quot;&gt;tooted a poll about this&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;People who POSSE short posts do you link back to the source or not? Seems a bit redundant but also it is nice to get to the canonical source.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;And the results were:&lt;/p&gt; &lt;table&gt; &lt;thead&gt; &lt;tr&gt; &lt;th&gt; &lt;/th&gt; &lt;th&gt; &lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Yes I link back&lt;/td&gt; &lt;td&gt;29%&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;No I don&#39;t link back&lt;/td&gt; &lt;td&gt;21%&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;I link back if it&#39;s truncated&lt;/td&gt; &lt;td&gt;15%&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;wtf is posse you weirdo&lt;/td&gt; &lt;td&gt;35%&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;This was hardly a landslide victory for one specific way but I came to the conclusion I did want to link back. However, the real reason for my poll was exactly what &lt;a href=&quot;https://xoxo.zone/@KevinMarks/113464550398427072&quot;&gt;Kevin replied with&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Where it gets weird is if there&#39;s a preview of the post as well, so then you get the POSSE copy of the post, then underneath a preview showing the same text, then if you click through there&#39;s just the same text again. In that case a link back is creating a bad experience for your readers on the POSSE platform.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;As an example, here is a short post with a link back to &lt;a href=&quot;https://rknight.me/notes/202411181234/&quot;&gt;the source&lt;/a&gt;:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/posse-note-with-og-image.jpg&quot; alt=&quot;A post on Mastodon showing the note, plus the image preview&quot; /&gt;&lt;/p&gt; &lt;p&gt;As proud as I am of my open graph image, in this context it&#39;s superfluous&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. We have the content of the post &amp;quot;Boo! I wanted...&amp;quot;, then a big image that tells you it&#39;s a note, then the date it was sent (which you&#39;d know from the toot as well), then the same text as the OG image &amp;quot;A note from the desk...&amp;quot;. Then if you click through you get the same text as the toot. This is no good.&lt;/p&gt; &lt;p&gt;I could just remove the open graph images and data all together but what if someone else links the page elsewhere? I &lt;em&gt;would&lt;/em&gt; want them in that case. So the solution is to block the Mastodon user agent from getting them when a link to one of my notes is tooted. Into the nginx config.&lt;/p&gt; &lt;p&gt;I only want this to apply to pages that start with &lt;code&gt;/notes&lt;/code&gt; so I started with a new &lt;code&gt;location&lt;/code&gt; block and thankfully Mastodon uses the aptly-named &lt;code&gt;Mastodon&lt;/code&gt; user agent.&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;location /notes &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_user_agent&lt;/span&gt; ~* &lt;span class=&quot;token string&quot;&gt;&quot;Mastodon&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I don&#39;t want to flat-out block Mastodon so instead I return an empty web page:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;location /notes {&lt;br /&gt; if ($http_user_agent ~* &quot;Mastodon&quot; ) {&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; add_header Content-Type text/html;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; return 200 &#39;&amp;lt;html&gt;&amp;lt;body&gt;&amp;lt;/body&gt;&amp;lt;/html&gt;&#39;;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I added this to my nginx config and tested it in Chrome by changing the user agent (&lt;code&gt;Inspector &amp;gt; More Tools &amp;gt; Network Conditions&lt;/code&gt;) and it worked - I got a blank page back. Great success. Except now no one could access &lt;em&gt;any&lt;/em&gt; notes page. I needed to update the config to have fallback logic for anything that &lt;em&gt;wasn&#39;t&lt;/em&gt; Mastodon:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;location /notes {&lt;br /&gt; if ($http_user_agent ~* &quot;Mastodon&quot; ) {&lt;br /&gt; add_header Content-Type text/html;&lt;br /&gt; return 200 &#39;&amp;lt;html&gt;&amp;lt;body&gt;&amp;lt;/body&gt;&amp;lt;/html&gt;&#39;;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; try_files $uri $uri/ /404.html?$query_string;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;With this all deployed to my server&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, a syndicated note like &lt;a href=&quot;https://rknight.me/notes/202411191206/&quot;&gt;this one&lt;/a&gt; now only shows the link on Mastodon with no title, description, or image.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/posse-note-with-no-image.jpg&quot; alt=&quot;A toot with a link to my site with no image or card&quot; /&gt;&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;Adam &lt;a href=&quot;https://social.lol/@adam/113510660868389993&quot;&gt;sent me his code&lt;/a&gt; to do it for a bunch of different fediverse servers&lt;/p&gt; &lt;/div&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;location /notes {&lt;br /&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; if ($http_user_agent ~* &quot;Mastodon&quot;) {&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; if ($http_user_agent ~* (Mastodon|Pleroma|Akkoma|Misskey|Firefish|gotosocial|Bridgy|Friendica)) {&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; add_header Content-Type text/html;&lt;br /&gt; return 200 &#39;&amp;lt;html&gt;&amp;lt;body&gt;&amp;lt;/body&gt;&amp;lt;/html&gt;&#39;;&lt;br /&gt; }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://neatnik.net/&quot;&gt;Adam&lt;/a&gt; would argue they&#39;re always superfluous &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You can see how I&#39;m keeping nginx changes in version control in &lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;this post&lt;/a&gt; &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Tue, 19 Nov 2024 13:34:28 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/stopping-mastodon-from-fetching-metadata-for-my-notes/</guid> </item> <item> <title>Useful Bluesky Tools</title> <link>https://rknight.me/blog/useful-bluesky-tools/</link> <description>&lt;p&gt;I&#39;ve been helping getting &lt;a href=&quot;https://www.macstories.net/news/macstories-is-on-bluesky/&quot;&gt;MacStories setup on Bluesky&lt;/a&gt; this weekend and I came across a few handy sites. There are loads of interesting Bluesky-related links in this &lt;a href=&quot;https://github.com/fishttp/awesome-bluesky?tab=readme-ov-file&quot;&gt;awesome-bluesky&lt;/a&gt; list on GitHub, below is just the ones I happened upon and found useful.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://clearsky.app/rknight.me/lists&quot;&gt;ClearSky&lt;/a&gt; allows you to see which lists (starter packs) you&#39;re in, who you&#39;ve blocked and who&#39;s blocked you. As an aside, the blocking data being public &lt;em&gt;and&lt;/em&gt; having no way to opt out of a starter pack shows a complete lack of consideration for how this could be abused but that&#39;s not the point of this post. Less important but why is seven the minimum for a starter pack &lt;a href=&quot;/notes/202411181234/&quot;&gt;this makes me very sad&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;I found two tools for resolving DIDs which you need for various API-related things. A DID is a &amp;quot;&lt;em&gt;persistent, long-term identifier for every account.&lt;/em&gt;&amp;quot; and they look something like this: &lt;code&gt;did:plc:b3i7xuqiybecdpm3lkywmlwv&lt;/code&gt;.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://rmdes.github.io/&quot;&gt;Bluesky DID Resolver&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://bsky-did.neocities.org/&quot;&gt;Bluesky DID Generator&lt;/a&gt; - confusingly named as a &amp;quot;generator&amp;quot;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;To use Bluesky in Mastodon clients like Ivory, you can use &lt;a href=&quot;https://skybridge.fly.dev&quot;&gt;Skybridge&lt;/a&gt;. I doubt I would ever check Bluesky if I couldn&#39;t use Ivory. I setup my own install of this with &lt;a href=&quot;https://coolify.io&quot;&gt;Coolify&lt;/a&gt;. &lt;a href=&quot;https://deck.blue&quot;&gt;Deck Blue&lt;/a&gt; is a nice web client though.&lt;/p&gt; &lt;p&gt;Finally &lt;a href=&quot;https://chromewebstore.google.com/detail/skylink-bluesky-did-detec/aflpfginfpjhanhkmdpohpggpolfopmb?hl=en&quot;&gt;SkyLink&lt;/a&gt; is a Chrome extension similar (although not as advanced) to &lt;a href=&quot;https://streetpass.social/&quot;&gt;Streetpass&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;You can see all the MacStories team and podcast accounts in &lt;a href=&quot;https://bsky.app/starter-pack/macstories.net/3lb4aiut25l26&quot;&gt;the MacStories starter pack&lt;/a&gt; and I&#39;m there as &lt;a href=&quot;https://bsky.app/profile/rknight.me&quot;&gt;@rknight.me&lt;/a&gt;.&lt;/p&gt; </description> <pubDate>Mon, 18 Nov 2024 15:15:19 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/useful-bluesky-tools/</guid> </item> <item> <title>I Was a Guest On AppStories This Week</title> <link>https://rknight.me/blog/i-was-a-guest-on-appstories-this-week/</link> <description>&lt;p&gt;The past few weeks &lt;a href=&quot;https://appstories.net&quot;&gt;AppStories&lt;/a&gt; has had a different MacStories host as a guest and this week was my turn. In the AppStories+ pre-show we talk about the origins of &lt;a href=&quot;https://ruminatepodcast.com&quot;&gt;Ruminate&lt;/a&gt; and in the main show we discuss the fediverse and ActivityPub, some of my &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt;, as well as my development setup. Stick around to find out what kind of person Federico thinks I am because I&#39;m still reeling.&lt;/p&gt; &lt;p&gt;Listen to episode &lt;a href=&quot;https://appstories.net/episodes/412&quot;&gt;412: What Kind of Person Are You?&lt;/a&gt; in your podcatcher of choice or you can watch the &lt;a href=&quot;https://www.youtube.com/watch?v=vyoH2ndxTLk&quot;&gt;episode on YouTube&lt;/a&gt;.&lt;/p&gt; </description> <pubDate>Mon, 18 Nov 2024 12:52:40 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/i-was-a-guest-on-appstories-this-week/</guid> </item> <item> <title>Buffalo Sauce Recipe</title> <link>https://rknight.me/blog/buffalo-sauce-recipe/</link> <description>&lt;p&gt;I don&#39;t know where I got this recipe but it&#39;s buffalo sauce so I suspect it&#39;s mostly the same from everyone but here we are, final day of recipe week. Enjoy.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Buffalo Sauce&lt;/h1&gt;&lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;300g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Hot Sauce&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;4 &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Garlic Gloves&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;20g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Worcestershire Sauce&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;15g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Distilled Vinegar&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;120g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Unsalted Butter&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Add &lt;span class=&quot;cl-ingredient&quot;&gt;hot sauce&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;garlic gloves&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;worcestershire sauce&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;distilled vinegar&lt;/span&gt; to sauce pan over medium high heat. Whisk ingredients together and allow to cook for &lt;span class=&quot;cl-timer&quot;&gt;5 minutes&lt;/span&gt; until thickened slightly. Whisk in the &lt;span class=&quot;cl-ingredient&quot;&gt;unsalted butter&lt;/span&gt; slowly on low heat. A tiny pinch of Xantham gum once it&amp;#39;s off the heat.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Sun, 17 Nov 2024 21:07:39 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/buffalo-sauce-recipe/</guid> </item> <item> <title>Leek and Bacon Jacket Potatoes Recipe</title> <link>https://rknight.me/blog/leek-and-bacon-jacket-potatoes-recipe/</link> <description>&lt;p&gt;Day six of &lt;a href=&quot;/blog/tags/recipeweek&quot;&gt;Recipe Week&lt;/a&gt;. This is certainly not healthy in any way at all but god damn is it tasty.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Leek and Bacon Jacket Potatoes&lt;/h1&gt;&lt;p&gt;There are many ways to make a jacket potato, I choose the microwave way because it&amp;#39;s quicker.&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;2 &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Jacket potatoes&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;8rashers &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chopped Bacon&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;40g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Leeks&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;165g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Cream Cheese&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Black Pepper&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Paprika&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Butter&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Pre-heat the oven to 200°c. &lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Jab your &lt;span class=&quot;cl-ingredient&quot;&gt;jacket potatoes&lt;/span&gt; with a fork a handful of times and put in the microwave for &lt;span class=&quot;cl-timer&quot;&gt;15 minutes&lt;/span&gt;, turn halfway through.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Put your jackets in the oven while you make the topping.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Cook the &lt;span class=&quot;cl-ingredient&quot;&gt;chopped bacon&lt;/span&gt; in a pan with a little bit of oil until browned off, then add in &lt;span class=&quot;cl-ingredient&quot;&gt;leeks&lt;/span&gt; and fry those for &lt;span class=&quot;cl-timer&quot;&gt;2-3 minutes&lt;/span&gt;. Turn the heat down and add in &lt;span class=&quot;cl-ingredient&quot;&gt;cream cheese&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;black pepper&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;paprika&lt;/span&gt;, and stir it all together.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Cut your jackets in half, add some &lt;span class=&quot;cl-ingredient&quot;&gt;butter&lt;/span&gt; to them, then top with the leek and bacon topping. Sprinkle some paprika on top to serve.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Sat, 16 Nov 2024 11:33:13 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/leek-and-bacon-jacket-potatoes-recipe/</guid> </item> <item> <title>Naming My Computers</title> <link>https://rknight.me/blog/naming-my-computers/</link> <description>&lt;p&gt;Alex has an excellent post about how &lt;a href=&quot;https://alexwlchan.net/2024/how-i-name-my-computers/&quot;&gt;they name their computers&lt;/a&gt; which is, as they mention, a very important part of setting up a new device.&lt;/p&gt; &lt;p&gt;Unlike Alex, I don&#39;t choose a new name when it gets replaced - my iPhone is always called &lt;strong&gt;Starlord&lt;/strong&gt;. Which brings me to the naming scheme: Marvel characters. Some of these make sense, some of them don&#39;t.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Mac Mini: This is used for Plex and some other boring home things but it&#39;s the hub for the house or something. Anyway I went with &lt;a href=&quot;https://en.wikipedia.org/wiki/J.A.R.V.I.S.&quot;&gt;Jarvis&lt;/a&gt;. Technically it&#39;s written &lt;code&gt;J.A.R.V.I.S.&lt;/code&gt; but who&#39;s got time for that.&lt;/li&gt; &lt;li&gt;MacBook Pro: This is my main computer and is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Vision_(Marvel_Comics)&quot;&gt;Vision&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;iPhone: &lt;a href=&quot;https://en.wikipedia.org/wiki/Star-Lord&quot;&gt;Starlord&lt;/a&gt;&lt;/li&gt; &lt;li&gt;Apple Watch: &lt;a href=&quot;https://en.wikipedia.org/wiki/Rocket_Raccoon&quot;&gt;Rocket&lt;/a&gt;&lt;/li&gt; &lt;li&gt;AirPods Pro: &lt;a href=&quot;https://uncannyxmen.net/family-tree/magneto-maximoff-family-tree&quot;&gt;Maximoff&lt;/a&gt;. Because there&#39;s two of them? A clever one.&lt;/li&gt; &lt;li&gt;AirPods Max: &lt;a href=&quot;https://en.wikipedia.org/wiki/Magneto_(Marvel_Comics)&quot;&gt;Magneto&lt;/a&gt; because metal&lt;/li&gt; &lt;li&gt;My black Apple Magic keyboard: &lt;a href=&quot;https://en.wikipedia.org/wiki/Black_Widow_(Natasha_Romanova)&quot;&gt;Black Widow&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;My Beats Studio buds are the one exception to this naming rule because I thought of a name&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; so good I couldn&#39;t &lt;em&gt;not&lt;/em&gt; use it: &lt;strong&gt;Fantastic Beats and Where to Find Them&lt;/strong&gt;. My iPad is called &lt;strong&gt;Robb&#39;s iPad&lt;/strong&gt; because I don&#39;t use it enough to name it.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I originally thought of this joke for &lt;a href=&quot;https://hellsite.rknight.me/988709761700040704/&quot;&gt;this tweet&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Fri, 15 Nov 2024 13:23:18 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/naming-my-computers/</guid> </item> <item> <title>Toad in the Hole Recipe</title> <link>https://rknight.me/blog/toad-in-the-hole-recipe/</link> <description>&lt;p&gt;Right folks, this is the laziest &amp;quot;recipe&amp;quot; ever but it&#39;s great so here we are: toad in the hole. I will take a better photo next time I make it, I had to pull this one from my Instagram/Pixelfed archive.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;img src=&quot;https://cdn.rknight.me/site/toad-in-the-hole.jpg&quot; class=&quot;u-photo&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Toad in the Hole&lt;/h1&gt;&lt;p&gt;This is a &lt;em&gt;really&lt;/em&gt; lazy way of doing it. You could make your own batter if you have more time and patience than me&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;6 &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Sausages&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Batter Mix&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Gravy&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Preheat the oven to 180°c, oil up a dish, and pop that in the oven for &lt;span class=&quot;cl-timer&quot;&gt;10-15 minutes&lt;/span&gt;&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Fry the &lt;span class=&quot;cl-ingredient&quot;&gt;sausages&lt;/span&gt; so the skin is lightly browned off.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Make some batter from a &lt;span class=&quot;cl-ingredient&quot;&gt;batter mix&lt;/span&gt; (&lt;a href=&quot;https://groceries.asda.com/product/pancake-batter-mixes/just-essentials-by-asda-batter-mix-125-g/1000265255205&quot;&gt;example&lt;/a&gt;), or make your own.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Take out the now-heated dish, pour in the batter mix, then pop the sausages in.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Put it back in the oven for &lt;span class=&quot;cl-timer&quot;&gt;25-30 minutes&lt;/span&gt; until the batter and sausages are golden brown.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Make some &lt;span class=&quot;cl-ingredient&quot;&gt;gravy&lt;/span&gt; and serve. I like &lt;a href=&quot;https://www.waitrose.com/ecom/products/bisto-best-beef-gravy-granules/431987-711062-711063&quot;&gt;Bisto finest&lt;/a&gt; but whatever you like. You can even share it if you&amp;#39;re feeling generous.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Fri, 15 Nov 2024 09:29:43 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/toad-in-the-hole-recipe/</guid> </item> <item> <title>More Unorganised Thoughts about Bluesky</title> <link>https://rknight.me/blog/more-unorganised-thoughts-about-bluesky/</link> <description>&lt;p&gt;I got a lot of feedback from &lt;a href=&quot;https://rknight.me/blog/unorganised-thoughts-about-bluesky/&quot;&gt;my last post&lt;/a&gt; which fell into two categories: either about the technical implementations or why someone is using Bluesky over other options. As soon as my sent my previous post Bluesky started having outages which has made looking into the feedback interesting to say the least but they&#39;ve been adding obscene amounts of users every second today.&lt;/p&gt; &lt;h3&gt;Technical&lt;/h3&gt; &lt;p&gt;&lt;a href=&quot;https://social.lol/@mcg&quot;&gt;MCG&lt;/a&gt; and &lt;a href=&quot;https://social.lol/@matt&quot;&gt;Matt&lt;/a&gt; linked me to &lt;a href=&quot;https://alice.bsky.sh/post/3laega7icmi2q&quot;&gt;this post&lt;/a&gt; which is titled &amp;quot;&lt;em&gt;How to self-host all of Bluesky except the AppView (for now)&lt;/em&gt;&amp;quot;. There are more components to self-hosting Bluesky than say, Mastodon, but it is doable. Sort of. You can&#39;t do the &lt;code&gt;AppView&lt;/code&gt; which &amp;quot;aggregates data from across the Atmosphere to produce their UIs&amp;quot;. It&#39;s late and I don&#39;t have the energy to translate what that actually means but it sounds important.&lt;/p&gt; &lt;p&gt;The part that jumped out to me (after MCG mentioned it) is the article mentions needing 4.5tb of storage for the relay which is a fuckton and might as well be a million terabytes for the sake of discussing self-hosting. There is a second relay option called Jetstream which from my reading of it, can be used instead of the 4.5tb version. &lt;a href=&quot;https://docs.bsky.app/blog/jetstream&quot;&gt;Looking at the docs&lt;/a&gt; it&#39;s not ideal for all circumstances but if we assume it could work for a small user base then cool. This is, however, a far stretch from my question of could it be done on a single PHP file. Seems like that&#39;s going to be a no. ActivityPub is by no means simple but AT Proto seems infinitely more complicated.&lt;/p&gt; &lt;h3&gt;Why use it?&lt;/h3&gt; &lt;p&gt;The &lt;em&gt;why&lt;/em&gt; is harder. There&#39;s no accounting for what people like or enjoy, people just &lt;em&gt;do&lt;/em&gt;. A lot of it came down to just a feeling of what Bluesky is like (early Twitter was banded around a bit).&lt;/p&gt; &lt;p&gt;Friend of the show &lt;a href=&quot;https://alexcox.omg.lol&quot;&gt;Alex Cox&lt;/a&gt; &lt;a href=&quot;https://bsky.app/profile/alexcoxfm.bsky.social/post/3lawgdp47rc2y&quot;&gt;pointed out&lt;/a&gt; to me, a cis white dude, that marginalised people on Mastodon are subject to constant reply guys and harassment. I&#39;m embarrassed that I didn&#39;t even think of it.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Most marginalized people who joined &lt;a href=&quot;https://mastodon.social/&quot;&gt;mastodon.social&lt;/a&gt; or another generic instance bounced pretty quickly because not many want to stick around and learn how to create your own instance when in the meantime you’re constantly blocking random guys telling you you’re doing it/everything wrong&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;As an aside, most of the reports we deal with on social.lol are spam probably because the instance is paid so there&#39;s a barrier that doesn&#39;t exist on mastodon.social and the other big instances.&lt;/p&gt; &lt;h3&gt;Final Thoughts&lt;/h3&gt; &lt;p&gt;Ben has a &lt;a href=&quot;https://werd.io/2024/bluesky-the-fediverse-and-the-future-of-social-media&quot;&gt;great post here&lt;/a&gt; about Bluesky, the Fediverse, and the future of social media:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Bluesky may evolve into a streamlined alternative to Twitter, while the Fediverse could serve as a decentralized, cross-platform connector among diverse networks&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;There&#39;s no reason to believe both can&#39;t continue to exist side by side. Mastodon isn&#39;t going anywhere and if better tools for self hosting come around for Bluesky, I could see myself potentially using both.&lt;/p&gt; &lt;p&gt;This is too much for one person to think about protocols&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; but I do want to investigate hosting a PDS if only because my data could be deleted easily by me without relying on Bluesky to do so if something were to happen. I think this is the case although I suppose it&#39;d be in other relays? Something to look into.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Especially after &lt;a href=&quot;https://rknight.me/blog/thinking-about-recipe-formats-more-than-anyone-should/&quot;&gt;last week&#39;s&lt;/a&gt; &lt;a href=&quot;https://rknight.me/blog/why-is-no-one-using-the-recipe-schema/&quot;&gt;recipe&lt;/a&gt; &lt;a href=&quot;https://rknight.me/blog/adding-cooklang-support-to-eleventy-two-ways/&quot;&gt;saga&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Thu, 14 Nov 2024 21:50:32 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/more-unorganised-thoughts-about-bluesky/</guid> </item> <item> <title>Unorganised Thoughts about Bluesky</title> <link>https://rknight.me/blog/unorganised-thoughts-about-bluesky/</link> <description>&lt;p&gt;These thoughts about Bluesky are unorganised and mostly off-the-cuff so make of that what you will.&lt;/p&gt; &lt;p&gt;The API, even just for posting, strikes me as very strange. I, as the developer, have to mark which things are hashtags, mentions, and links unlike Twitter, Mastodon, and basically every other network. If I want link previews I have to do that too.&lt;/p&gt; &lt;p&gt;The &lt;a href=&quot;https://github.com/bluesky-social/pds&quot;&gt;Personal Data Store&lt;/a&gt; is interesting. I haven&#39;t set one up but &lt;a href=&quot;https://krrd.ing/posts/setting-up-a-bluesky-pds/&quot;&gt;Brandon&lt;/a&gt; and &lt;a href=&quot;https://rafaeleyng.github.io/self-hosting-a-bluesky-pds-and-using-your-domain-as-your-handle&quot;&gt;Rafael&lt;/a&gt; did and it seems easy enough but this is just one part of the AT Protocol. Is it possible to host the entire stack yourself without relying on &lt;code&gt;bsky.social&lt;/code&gt;? Can you be part of the AT Protocol with &lt;a href=&quot;https://gitlab.com/edent/activitypub-single-php-file/&quot;&gt;a single PHP file&lt;/a&gt;? That might sound stupid but I don&#39;t think that&#39;s an unreasonable bar to interact with a network even if it&#39;s in a limited way.&lt;/p&gt; &lt;p&gt;Starter Packs are a good idea that people seem to like but I would rather people followed me because they&#39;ve had a gander at what I post and decided to follow. Choosing to follow people en masse without looking at those profiles seems weird to me. The other thing is it feels like they pigeon-hole people into being a specific version of themselves and perhaps give unrealistic expectations to people following&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. I feel the same about mastodon instances focused around a specific topic.&lt;/p&gt; &lt;p&gt;I&#39;ve seen a few people drop Mastodon for Bluesky but I don&#39;t really understand why, nothing about it jumps out at me as all that different to Mastodon. You have to go where your people are though so it could just be that. I&#39;m pretty sure Bluesky will get &lt;a href=&quot;https://en.wikipedia.org/wiki/Enshittification&quot;&gt;enshittified&lt;/a&gt; before too long and everyone will be onto the next thing.&lt;/p&gt; &lt;p&gt;I am cross-posting my &lt;a href=&quot;/posts&quot;&gt;posts&lt;/a&gt; and &lt;a href=&quot;/links&quot;&gt;links&lt;/a&gt; to &lt;a href=&quot;https://bsky.app/profile/rknight.me&quot;&gt;my Bluesky account&lt;/a&gt; with &lt;a href=&quot;https://echofeed.app&quot;&gt;EchoFeed&lt;/a&gt;. People are there, they presumably followed me to see my things, and I don&#39;t lose anything if the service blows up overnight. &lt;a href=&quot;https://indieweb.org/POSSE&quot;&gt;POSSE&lt;/a&gt;, baby.&lt;/p&gt; &lt;p&gt;I setup my own install of &lt;a href=&quot;https://skybridge.fly.dev/&quot;&gt;SkyBridge&lt;/a&gt; so I can use &lt;a href=&quot;https://tapbots.com/ivory/&quot;&gt;Ivory&lt;/a&gt; to read my Bluesky timeline because none of the apps are as good as Ivory and probably never will be.&lt;/p&gt; &lt;p&gt;I&#39;ve updated my &lt;a href=&quot;/verify&quot;&gt;verify page&lt;/a&gt; to reflect the fact that I am using Bluesky.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&amp;quot;Stop posting about politics, stay in your lane&amp;quot; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Thu, 14 Nov 2024 17:05:08 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/unorganised-thoughts-about-bluesky/</guid> </item> <item> <title>Flatiron Mac and Cheese Recipe</title> <link>https://rknight.me/blog/flatiron-mac-and-cheese-recipe/</link> <description>&lt;p&gt;This recipe came to me via my friend Ali, who had it at &lt;a href=&quot;https://theflatironroom.com&quot;&gt;The Flatiron Room&lt;/a&gt; when he was living in New York. He&#39;s made it for us a bunch of times, including on my stag do, as you can in the accompanying photo.&lt;/p&gt; &lt;p&gt;As an aside, my stag do was three of us in a cabin in the middle of the Welsh countryside for three days and it was glorious.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;img src=&quot;https://cdn.rknight.me/site/flatiron-mac-and-cheese-stag-do.jpg&quot; class=&quot;u-photo&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Flatiron Mac and Cheese&lt;/h1&gt;&lt;p&gt;To quickly roast the brussel sprouts, cut them in half and drizzle in olive oil, then bung them in the over for 15-20 minutes.&lt;/p&gt; &lt;p&gt;The recipe calls for Radiatori pasta but I&amp;#39;ve used farfalle before and it works just as well.&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;500g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Radiatori Pasta&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;15g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Sliced Shallots&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;2cloves &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Minced Garlic&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;10g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Calabrian Chiles&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;100g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Halved and Pre-Roasted Brussel Sprouts&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;250g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Heavy Cream&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;20g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Parmesan&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;75g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Grated Gouda&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;15g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Hot Sauce&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Panko Breadcrumbs&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Cook &lt;span class=&quot;cl-ingredient&quot;&gt;radiatori pasta&lt;/span&gt; as per instructions and set aside.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;In a saute pan, add &lt;span class=&quot;cl-ingredient&quot;&gt;sliced shallots&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;minced garlic&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;calabrian chiles&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;halved and pre-roasted brussel sprouts&lt;/span&gt;, cook for &lt;span class=&quot;cl-timer&quot;&gt;1-2 minutes&lt;/span&gt; on medium/high heat.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Add &lt;span class=&quot;cl-ingredient&quot;&gt;heavy cream&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;parmesan&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;grated gouda&lt;/span&gt; and cook until the cheese melts.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Add the &lt;span class=&quot;cl-ingredient&quot;&gt;hot sauce&lt;/span&gt; and pasta, mix until all the pasta is coated.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Pour into a dish (ideally cast iron), top with &lt;span class=&quot;cl-ingredient&quot;&gt;panko breadcrumbs&lt;/span&gt;, and bake for a few minutes until the cheese is bubbling.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Thu, 14 Nov 2024 10:00:00 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/flatiron-mac-and-cheese-recipe/</guid> </item> <item> <title>Cheesy Chicken and Bacon Pasta Recipe</title> <link>https://rknight.me/blog/cheesy-chicken-and-bacon-pasta-recipe/</link> <description>&lt;p&gt;Recipe week day three is a cheesy chicken and bacon pasta that I tried for the first time last week and it was banging. You should try it.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Cheesy Chicken and Bacon Pasta&lt;/h1&gt;&lt;p&gt;This doesn&amp;#39;t reheat as well as I&amp;#39;d like, it tends to dry out more than other pasta dishes.&lt;/p&gt; &lt;p&gt;This is easily enough for 4 people so halve the quantities if it&amp;#39;s just for two people.&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;500g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Penne Pasta&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;8rashers &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chopped Bacon&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;500g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chicken&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Salt&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Pepper&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Garlic Powder&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Italian Seasoning&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;250g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Heavy Cream&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;250g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chicken Broth&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;125g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Parmesan&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Cook the &lt;span class=&quot;cl-ingredient&quot;&gt;penne pasta&lt;/span&gt; as per instructions, drain, and put to one side.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Cook the &lt;span class=&quot;cl-ingredient&quot;&gt;chopped bacon&lt;/span&gt; in a pan with a little bit of oil until crispy, set aside.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;In the same pan, add &lt;span class=&quot;cl-ingredient&quot;&gt;chicken&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;salt&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;pepper&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;garlic powder&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;italian seasoning&lt;/span&gt;, then cook until the chicken is cooked through and golden. Set aside.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Add &lt;span class=&quot;cl-ingredient&quot;&gt;heavy cream&lt;/span&gt; and &lt;span class=&quot;cl-ingredient&quot;&gt;chicken broth&lt;/span&gt; to the pan, add in the &lt;span class=&quot;cl-ingredient&quot;&gt;parmesan&lt;/span&gt; and stir on a low/medium heat for &lt;span class=&quot;cl-timer&quot;&gt;5-10 minutes &lt;/span&gt; until the sauce thickens. &lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Add the bacon, chicken, and pasta back into the pan and stir to combine.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Wed, 13 Nov 2024 11:55:12 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/cheesy-chicken-and-bacon-pasta-recipe/</guid> </item> <item> <title>Candied Jalapenos Recipe</title> <link>https://rknight.me/blog/candied-jalapenos-recipe/</link> <description>&lt;p&gt;Day two of recipe week is this recipe for candied jalopenos that I like to make a batch of at the start of the summer for pizzas on &lt;a href=&quot;https://rknight.me/blog/one-year-of-pizza-making/&quot;&gt;my Ooni&lt;/a&gt;.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;img src=&quot;https://cdn.rknight.me/site/candied-jalopenos.jpg&quot; class=&quot;u-photo&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Candied Jalapenos&lt;/h1&gt;&lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;500g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Sugar&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;250g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Apple Cider Vinegar&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;40g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Salt&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;1500g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chopped Jalapeños&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Add &lt;span class=&quot;cl-ingredient&quot;&gt;sugar&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;apple cider vinegar&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;salt&lt;/span&gt; into saucepan and cook on medium heat until it comes to a boil. &lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Once boiling, add &lt;span class=&quot;cl-ingredient&quot;&gt;chopped jalapeños&lt;/span&gt; and have the mixture come back to a boil and boil for &lt;span class=&quot;cl-timer&quot;&gt;5 minutes&lt;/span&gt;.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Put in it jars and it&amp;#39;ll last a good few months.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Tue, 12 Nov 2024 09:00:00 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/candied-jalapenos-recipe/</guid> </item> <item> <title>Mango Chicken Curry Recipe</title> <link>https://rknight.me/blog/mango-chicken-curry-recipe/</link> <description>&lt;p&gt;As promised &lt;a href=&quot;https://rknight.me/blog/adding-cooklang-support-to-eleventy-two-ways/&quot;&gt;last week&lt;/a&gt;, this week is recipe week.&lt;/p&gt; &lt;p&gt;This is one we batch cook for Baby Knight every few weeks and she can&#39;t get enough of it. The last batch I didn&#39;t have any tomato puree but I went ahead with it anyway and she still enjoyed it.&lt;/p&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;Mango Chicken Curry&lt;/h1&gt;&lt;p&gt;The recipe calls for fresh ginger but I&amp;#39;m lazy and use ginger paste instead&lt;/p&gt; &lt;p&gt;The mango can be fresh or frozen, it makes very little difference&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;1 &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Chopped Onion&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;120g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Cauliflour&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;3cloves &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Garlic&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;30g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Curry Powder&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;30g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Tomato Puree&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;15g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Ginger&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;60g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Mango&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;400ml &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Coconut Milk&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;600g &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Diced Chicken Breast&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;Sauté the &lt;span class=&quot;cl-ingredient&quot;&gt;chopped onion&lt;/span&gt; and &lt;span class=&quot;cl-ingredient&quot;&gt;cauliflour&lt;/span&gt; in a pan for &lt;span class=&quot;cl-timer&quot;&gt;2-3 minutes&lt;/span&gt; until softened.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Add the &lt;span class=&quot;cl-ingredient&quot;&gt;garlic&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;curry powder&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;tomato puree&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;ginger&lt;/span&gt; for &lt;span class=&quot;cl-timer&quot;&gt;1-2 minutes &lt;/span&gt; while stirring.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Put it in a blender, add half the &lt;span class=&quot;cl-ingredient&quot;&gt;mango&lt;/span&gt; and &lt;span class=&quot;cl-ingredient&quot;&gt;coconut milk&lt;/span&gt;, then blend until smooth.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Put the sauce back in the pan, bring it to a simmer, then add &lt;span class=&quot;cl-ingredient&quot;&gt;diced chicken breast&lt;/span&gt; and simmer for &lt;span class=&quot;cl-timer&quot;&gt;10-15 minutes&lt;/span&gt; until the chicken is cooked. Stir occasionally.&lt;/p&gt; &lt;/p&gt;&lt;p&gt;&lt;p&gt;Finally, stir in the rest of the mango.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Mon, 11 Nov 2024 08:54:29 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/mango-chicken-curry-recipe/</guid> </item> <item> <title>Adding Cooklang Support to Eleventy Three Ways</title> <link>https://rknight.me/blog/adding-cooklang-support-to-eleventy-two-ways/</link> <description>&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;I had already built most of this before I saw &lt;a href=&quot;https://www.mathew-paul.nz/posts/adding-cooklang-to-my-blog/&quot;&gt;Mat had already done this&lt;/a&gt; including making &lt;a href=&quot;https://www.mathew-paul.nz/posts/adding-cooklang-to-my-blog/&quot;&gt;a plugin&lt;/a&gt; available. Lesson learned, maybe Google it first.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;&lt;a href=&quot;https://cooklang.org&quot;&gt;Cooklang&lt;/a&gt;, as I wrote about in &lt;a href=&quot;https://rknight.me/blog/thinking-about-recipe-formats-more-than-anyone-should/&quot;&gt;my previous post&lt;/a&gt;, is a markup language for recipes. I wanted to put all my recipes on my site under the &lt;code&gt;/recipes&lt;/code&gt; directory which meant I needed to add support for the &lt;code&gt;.cook&lt;/code&gt; files to Eleventy. I tried two methods for this then ended up with a third version where I scrapped a lot of what I did and decided to just do it in blog posts.&lt;/p&gt; &lt;h3&gt;Method One: Compile the Template Directly&lt;/h3&gt; &lt;p&gt;Eleventy supports &lt;a href=&quot;https://www.11ty.dev/docs/languages/custom/&quot;&gt;adding custom template languages&lt;/a&gt; so adding support for the format is as simple as adding the following to my config file:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addTemplateFormats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cook&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cook&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;inputContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inputContent&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// parse the cooklang file&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// and return the formatted HTML&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; output&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Then I added some frontmatter to the recipes to handle title and permalinks&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt; &lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Sliced Apple&lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /recipes/sliced&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;apple/index.html&lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; base&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&gt;&lt;/span&gt; source: https://en.wikipedia.org/wiki/Apple&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&gt;&lt;/span&gt; note: Recommended by doctor exorcists&lt;br /&gt;&lt;br /&gt;Cut the @Apple{1} into slices. This takes ~{1%minute}. You need a #knife.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The &lt;a href=&quot;https://cooklang.github.io/cooklang-ts/&quot;&gt;&lt;code&gt;cooklang-ts&lt;/code&gt;&lt;/a&gt; library will parse the &lt;code&gt;.cook&lt;/code&gt; file to &lt;code&gt;Recipe&lt;/code&gt; object which can then be used to make the HTML. I haven&#39;t included the logic here because I went in a different direction with it but you get the idea. In the second method further down I &lt;em&gt;do&lt;/em&gt; show how to do it.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const { Recipe } = require(&#39;@cooklang/cooklang-ts&#39;)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;compile: async (inputContent) =&gt; {&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; let output = &#39;&#39;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const recipe = new Recipe(inputContent)&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; // imagine the code here that takes&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; // the recipe and formats it to an HTML string&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; return async () =&gt; {&lt;br /&gt; return output&lt;br /&gt; }&lt;br /&gt;},&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This would leave my page object looking something like this:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;div&gt;the formatted sliced apple recipe&amp;lt;/div&gt;&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;Method Two: Add to the Data Cascade&lt;/h3&gt; &lt;p&gt;The reason I stopped with method one is I prefer my Eleventy config to return &lt;em&gt;data&lt;/em&gt; (in this case, JS objects) and for rendering to be handled by the Nunjucks templates. Creating HTML strings in JS, even with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;template literals&lt;/a&gt;, just doesn&#39;t spark joy.&lt;/p&gt; &lt;p&gt;On the Eleventy custom templates docs page, there is a &lt;a href=&quot;https://www.11ty.dev/docs/languages/custom/#getdata-and-getinstancefrominputpath&quot;&gt;&lt;code&gt;getData&lt;/code&gt; section&lt;/a&gt;. This method &amp;quot;&lt;em&gt;controls if and how additional data should be retrieved from a JavaScript object to populate the Data Cascade&lt;/em&gt;&amp;quot;. This allows adding additional attributes to the page object. If we take the method one example and add in the &lt;code&gt;getData&lt;/code&gt; method we get something like this:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cook&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;inputPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// read the contents of the file&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputPath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;---&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// get the recipe object&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recipe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ingredients&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ingredients&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// for each step, add spans and classes&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// to ingredients, timers, and cookware&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;steps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-ingredient&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;timer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-timer&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;cookware&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-cookware&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;inputContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; inputContent&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;So my page object now looks like this - notice I&#39;m still running &lt;code&gt;compile&lt;/code&gt; so we have access to the raw cooklang content to be able to output that on the page too.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;the raw text from the cooklang file&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ingredients&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I set the layout of the recipes to a new layout called &lt;code&gt;recipe&lt;/code&gt; which extends my base layout and added the logic for rendering the data:&lt;/p&gt; &lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt; &lt;span class=&quot;token selector&quot;&gt;.cl-ingredient,&lt;br /&gt; .cl-timer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;h-recipe&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% if metadata.note %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% endif %}&lt;br /&gt;&lt;br /&gt; {% if metadata.servings %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;servings&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; Servings&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;em&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% endif %}&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {%- for ingredient in ingredients -%}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;p-ingredient&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; {% if ingredient.quantity != &#39;some&#39; %}(&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;units&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;){% endif %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {%- endfor -%}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;e-instructions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {%- for step in steps -%}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {%- endfor -%}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; {% if metadata.source %}&lt;br /&gt; {% if &quot;http&quot; in metadata.source %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Source&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% else %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Source: &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% endif %}&lt;br /&gt; {% endif %}&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I&#39;ve included the &lt;a href=&quot;http://microformats.org/wiki/h-recipe&quot;&gt;microformat&lt;/a&gt; classes here as well as outputting any source and notes I&#39;ve put in the metadata. I then added the raw &lt;code&gt;.cook&lt;/code&gt; file into a &lt;code&gt;details&lt;/code&gt; element at the bottom:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &amp;lt;details&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &amp;lt;summary&gt;&amp;lt;code&gt;{{ page.fileSlug }}.cook&amp;lt;/code&gt;&amp;lt;/summary&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &amp;lt;pre style=&quot;text-wrap: wrap&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; {{ content | safe }}&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &amp;lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &amp;lt;/details&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token deleted-arrow deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt;/article&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/slice-apples-screenshot.jpg&quot; alt=&quot;Sliced Apples recipe rendered on my site&quot; /&gt;&lt;/p&gt; &lt;p&gt;Finally to add a list of recipes on the &lt;code&gt;/recipes&lt;/code&gt; page, I added a new collection and rendered said collection, sorted by title:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&#39;recipes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; collectionApi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFilteredByGlob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/pages/recipes/**/*.cook&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;It was at this point I stared out the window of my office and thought to myself &amp;quot;what the fuck am I doing&amp;quot;. What would the URLs be? How would I tell people about new recipes? I could make an RSS feed for them but then they need dates. What I&#39;m describing is a blog. I already have a blog. And recipes on that blog. So I deleted the collection, deleted the &lt;code&gt;/recipes&lt;/code&gt; page, and jumped into an existing recipe post to see what I could do here.&lt;/p&gt; &lt;h3&gt;Method Three: All of the Above but It’s Blog Posts&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;I’ve done a bunch of stuff and have it working but now I’m thinking why isn’t it just blog posts and screw all this nonsense&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;I scrapped all the code and started coverting my &lt;a href=&quot;https://rknight.me/blog/puff-pastry-sausage-roll-recipe/&quot;&gt;sausage roll recipe&lt;/a&gt; to cooklang format. As I mentioned in my previous post, there&#39;s no way to have multi-line comments in the metadata and this recipe requires it, so I made the executive decision to use &lt;code&gt;|&lt;/code&gt; in my notes between each &amp;quot;line&amp;quot; and I&#39;ll handle splitting this myself. The converted recipe looks like this. I added &lt;code&gt;servings&lt;/code&gt; and &lt;code&gt;source&lt;/code&gt; to test how they will look, those are likely to be there in other recipes but aren&#39;t actually relevant to this one.&lt;/p&gt; &lt;pre class=&quot;language-cooklang&quot;&gt;&lt;code class=&quot;language-cooklang&quot;&gt;&lt;span class=&quot;token meta&quot;&gt;&gt;&gt; &lt;span class=&quot;token property&quot;&gt;notes&lt;/span&gt;: I prefer to buy sausages and remove the skin as there&#39;s a bigger variety of flavours available without having to add stuff to sausage meat myself | In the UK puff pastry comes in a standard size of 320g ([example](https://groceries.asda.com/product/pastry-dough/jus-rol-puff-pastry-ready-rolled-sheet/910000468752))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token meta&quot;&gt;&gt;&gt; &lt;span class=&quot;token property&quot;&gt;servings&lt;/span&gt;: A lot&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token meta&quot;&gt;&gt;&gt; &lt;span class=&quot;token property&quot;&gt;source&lt;/span&gt;: https://example.com&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Preheat the oven to 180°c. Whisk up an &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Egg&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; in a bowl.&lt;br /&gt;&lt;br /&gt;Lay the &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Puff Pastry&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;320&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and lay a cylinder of &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Sausage Meat&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;450&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; about an inch thick across the pastry. Roll the pastry around that and cut it so there&#39;s just enough to cover the meat with a little bit of overlap. Do this until you run out of pastry. &lt;br /&gt;&lt;br /&gt;Grab your baking tray, lay down some greaseproof paper on it, then brush the tray with the eggwash. &lt;br /&gt;&lt;br /&gt;Cut up your long sausage roll into inch-wide smaller sausage rolls and pop them on the baking tray, seam down. Brush them with egg and pop them in the oven for &lt;span class=&quot;token timer-group&quot;&gt;&lt;span class=&quot;token timer-keyword keyword&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token duration-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token duration number&quot;&gt;20&lt;/span&gt;-&lt;span class=&quot;token duration number&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; until they&#39;re golden brown all over.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I then needed to add this to the frontmatter of the recipe blog post. Doing it this way, rather than a separate file, means that if someone just has this file the recipe is still readable.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;excerpt: &quot;A very simple recipe for making delicious sausage rolls&quot;&lt;br /&gt;tags:&lt;br /&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; - Food&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; - Recipes&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; recipe: &gt; &lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &gt;&gt; notes: I prefer to buy sausages and remove the skin as there&#39;s a bigger variety of flavours available without having to add stuff to sausage meat myself | In the UK puff pastry comes in a standard size of 320g ([example](https://groceries.asda.com/product/pastry-dough/jus-rol-puff-pastry-ready-rolled-sheet/910000468752))&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;// and so on&lt;/code&gt;&lt;/pre&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;TIL&lt;/p&gt;&lt;p&gt;To do multi-line values in YAML you can use &lt;a href=&quot;https://yaml.org/spec/1.2-old/spec.html#style/block/folded&quot;&gt;Folded Scalar&lt;/a&gt; / &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;In my post layout file I added a check for the &lt;code&gt;recipe&lt;/code&gt; value and if it exists include a new &lt;code&gt;recipe.njk&lt;/code&gt; file - this file will pass the data to the filter, then do the rendering. Finally I added a new filter to parse and format the recipe.&lt;/p&gt; &lt;pre class=&quot;language-hbs&quot;&gt;&lt;code class=&quot;language-hbs&quot;&gt;&lt;span class=&quot;token block keyword&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;njk&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;recipe.njk&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;njk&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeOutput&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;per&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;two&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;recipeOutput&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recipe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;cookware&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cookwares&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ingredients&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ingredients&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// and so on, the same as the filter in method two&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;At this point, this is all rendering the same as method two but on a blog post instead - I can put my life story in the post and &lt;em&gt;then&lt;/em&gt; the recipe shows, as is tradition. The next step was to split the notes into new lines. I also ran them through a markdown parser to handle any links I might include and added an image to the recipe:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const marked = require(&#39;marked&#39;)&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const notes = (recipe.metadata.notes || &#39;&#39;).split(&#39;|&#39;).map(n =&gt; marked.parse(n.trim()))&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; delete recipe.metadata.notes // remove this from metadata&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;return {&lt;br /&gt; cookware: recipe.cookwares,&lt;br /&gt; ingredients: recipe.ingredients,&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; notes,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Next, rather than be explicit about which metadata items will show (like I do above with servings and source), I changed the &lt;code&gt;metadata&lt;/code&gt; attribute so it&#39;s an array I can just map over in the template.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const image = recipe.metadata.image&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;notes: (recipe.metadata.notes || &#39;&#39;).split(&#39;|&#39;).map(n =&gt; marked.parse(n.trim()))&lt;br /&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; metadata: recipe.metadata,&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; metadata: Object.keys(recipe.metadata).map(key =&gt; {&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; const name = key.charAt(0).toUpperCase() + key.slice(1)&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; return {&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; key: name,&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; value: recipe.metadata[key]&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; }&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; }),&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; image,&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The notes and metadata then get output in my alert component (I added a new &lt;code&gt;kitchen&lt;/code&gt; icon for this).&lt;/p&gt; &lt;pre class=&quot;language-hbs&quot;&gt;&lt;code class=&quot;language-hbs&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;aside&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alert-icon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;svg&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;icon alert-recipe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;xlink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#kitchen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;notes&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Source&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ recipeData.metadata.source }}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;Source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/recipe-metadata-with-icon.jpg&quot; alt=&quot;Recipe metadata&quot; /&gt;&lt;/p&gt; &lt;p&gt;For the raw recipe output, I updated that to use the syntax highlighting like the rest of the site does.&lt;/p&gt; &lt;pre class=&quot;language-hbs&quot;&gt;&lt;code class=&quot;language-hbs&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;highlight&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;js&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;highlight&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cooklang&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endhighlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endhighlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;h4&gt;JSON-LD&lt;/h4&gt; &lt;p&gt;I also want to include the recipe schema markup on the page even though &lt;a href=&quot;https://rknight.me/blog/why-is-no-one-using-the-recipe-schema/&quot;&gt;none of the recipe extensions use it&lt;/a&gt;. The first thing I realised is that my recipes don&#39;t have a name (I was relying on the blog post for that), so I added that to the recipe.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; &gt;&gt; name: Puff Pastry Sausage Rolls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Then I added a new &lt;code&gt;makeJsonLd&lt;/code&gt; function to my recipe filter, pass it the recipe object, and output it on the page.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;makeJsonLd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@context&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://schema.org&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@type&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Recipe&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Robb Knight&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recipeIngredient&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ingredients&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recipeInstructions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;steps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@type&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;HowToStep&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;timer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;cookware&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;pre class=&quot;language-hbs&quot;&gt;&lt;code class=&quot;language-hbs&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;application/ld+json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;dump&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;With all of this together plus some additional styling tweaks, a recipe on a blog post looks like this:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/recipe-final-output.jpg&quot; alt=&quot;The final output of the recipe page&quot; /&gt;&lt;/p&gt; &lt;p&gt;The last job was to convert the other recipes into cooklang format and update the posts, which was not as fun as it sounds. Going forward I&#39;ll be adding new recipes as blog posts&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; and you&#39;ll be able to see them all under the &lt;a href=&quot;https://rknight.me/blog/tags/recipes/&quot;&gt;#recipes&lt;/a&gt; tag.&lt;/p&gt; &lt;p&gt;Ideally I would like the recipe to render &lt;em&gt;before&lt;/em&gt; the footnotes of a post but that would require digging into the markdown plugins to inject it so I decided to live with it for now.&lt;/p&gt; &lt;p&gt;Below is the code in full of the filter and template or you can browse the latest code for the site &lt;a href=&quot;https://github.com/rknightuk/rknight.me/&quot;&gt;on GitHub&lt;/a&gt;&lt;/p&gt; &lt;details&gt; &lt;summary&gt;The recipe filter (&lt;code&gt;recipe.js&lt;/code&gt;)&lt;/summary&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Recipe &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;@cooklang/cooklang-ts&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; marked &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;marked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;makeJsonLd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@context&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://schema.org&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@type&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Recipe&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Robb Knight&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recipeIngredient&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ingredients&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recipeInstructions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;steps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;@type&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;HowToStep&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;timer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;cookware&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token function-variable function&quot;&gt;recipeOutput&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; recipe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Recipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; notes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;|&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; marked&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeJsonLd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recipe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;br /&gt; &lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; json&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;cookware&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cookwares&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;ingredients&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ingredients&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; notes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;charAt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;steps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; marked&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-ingredient&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;timer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-timer&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;units&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;cookware&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span class=&quot;cl-cookware&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;/details&gt; &lt;details&gt; &lt;summary&gt;The recipe template (&lt;code&gt;recipe.njk&lt;/code&gt;)&lt;/summary&gt; &lt;pre class=&quot;language-hbs&quot;&gt;&lt;code class=&quot;language-hbs&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeOutput&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;cl-ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;cl-timer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token variable&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;bold&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h-recipe recipe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ recipeData.image }}&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;u-photo&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;margin-bottom: 20px;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;aside&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alert-icon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;svg&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;icon alert-recipe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;xlink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#kitchen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;notes&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;metadata&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Source&#39;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ recipeData.metadata.source }}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;Source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ingredients&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;some&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;units&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;p-ingredient&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;ingredient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;cookware&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;cookware&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;cookware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;e-instructions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;steps&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;cook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;highlight&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cooklang&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endhighlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;application/ld+json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;recipeData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;dump&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;/details&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Eleventy makes permalinks automatically based on the folder structure but I prefer to be explicit about it &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Maybe next week can be recipe week &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Thu, 07 Nov 2024 08:37:23 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/adding-cooklang-support-to-eleventy-two-ways/</guid> </item> <item> <title>Why Is No One Using the Recipe Schema?</title> <link>https://rknight.me/blog/why-is-no-one-using-the-recipe-schema/</link> <description>&lt;p&gt;While working on my recipe handling for this site as outlined in &lt;a href=&quot;https://rknight.me/blog/thinking-about-recipe-formats-more-than-anyone-should/&quot;&gt;my previous post&lt;/a&gt; I realised that there are many recipe-related browser extensions available so I should be able to test my &lt;a href=&quot;http://schema.org&quot;&gt;schema.org&lt;/a&gt; markup and my microformat class locally so I downloaded a handful of the most popular ones.&lt;/p&gt; &lt;p&gt;And it turns out they just...don&#39;t use the schema to extract recipes? This is in the source of &lt;a href=&quot;https://github.com/bradenzingler/recipe_extractor/blob/master/content.js&quot;&gt;one of the extensions&lt;/a&gt;:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;ingr_selectors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.Wrapper-dxnTBC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.mntl-structured-ingredients__list-item&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.wprm-recipe-ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.ingredient-lists &gt; li &gt; p&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;#structured-ingredients_1-0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.o-Ingredients__m-Body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.ingredient-list &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.recipe__ingredients&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.Recipe__ingredient&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.field-ingredientstext&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.cooked-recipe-ingredients&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.tasty-recipes-ingredients-body &gt; ul &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.recipe-ingredients__list&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.recipe-ingredients &gt; ul &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.tasty-recipes-ingredients &gt; div &gt; ul &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.recipe-ingredient &gt; ul &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.ingredients_ingredients__FLjsC &gt; ul &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.recipe-ingredients &gt; li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.mv-create-ingredients &gt; ul &gt; li&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The first ten or so had comments about which site they were for and the others I assume are just generally-accepted class names for recipes. Notice the microformat class for ingredients isn&#39;t in this list (&lt;code&gt;p-ingredient&lt;/code&gt;), nor is the recipe class (&lt;code&gt;h-recipe&lt;/code&gt;) in the recipe selectors.&lt;/p&gt; &lt;p&gt;Okay so maybe the microformats isn&#39;t widely supported but &lt;em&gt;surely&lt;/em&gt; they use the &lt;a href=&quot;http://scheme.org&quot;&gt;scheme.org&lt;/a&gt; JSON where it&#39;s available? I checked a handful of recipe sites and they all have it. Nope. None of the extensions I tested or could find source code for use it.&lt;/p&gt; &lt;p&gt;Perhaps there&#39;s some problem with how the big sites are using it, I thought. So I ran this script on a bunch of the sites and as far as I could tell, they all use the schema correctly.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; found &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script[type=&quot;application/ld+json&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; found&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;found&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// { &quot;@context&quot;: &quot;https://schema.org&quot;, &quot;@type&quot;: &quot;Recipe&quot;, ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;All of these sites support it because Google forces them to, it&#39;s a requirement to be featured prominently in search results. If someone can enlighten me as to why these extensions rely on class names that presumably change all the time, I&#39;m all ears. I&#39;ll be over in the corner whipping up a bookmarklet to extract recipes using &lt;em&gt;standards&lt;/em&gt;.&lt;/p&gt; </description> <pubDate>Wed, 06 Nov 2024 08:47:24 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/why-is-no-one-using-the-recipe-schema/</guid> </item> <item> <title>Thinking About Recipe Formats More Than Anyone Should</title> <link>https://rknight.me/blog/thinking-about-recipe-formats-more-than-anyone-should/</link> <description>&lt;p&gt;I&#39;ve had a note in my todo list for quite a while to get my (admittedly small) collection of recipes on my website. The note mentioned to look into &lt;a href=&quot;https://cooklang.org&quot;&gt;Cooklang&lt;/a&gt; which is a &amp;quot;&lt;em&gt;recipe markup language&lt;/em&gt;&amp;quot; but I also wanted to see if anyone knew of any other standards I should be looking at before I went ahead. I got a few responses:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://pub.calebhearth.com/@caleb/113419235283396365&quot;&gt;Caleb pointed me&lt;/a&gt; to the &lt;a href=&quot;https://pub.calebhearth.com/@caleb/113419235283396365&quot;&gt;recipe microformat&lt;/a&gt; which he&#39;s using on &lt;a href=&quot;https://calebhearth.com/spiced-mead-cake&quot;&gt;his recipes&lt;/a&gt;.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://mela.recipes&quot;&gt;Mela&lt;/a&gt; has it&#39;s own &lt;a href=&quot;https://mela.recipes/fileformat/index.html&quot;&gt;defined JSON format&lt;/a&gt; sent to me by &lt;a href=&quot;https://hachyderm.io/@byjp/113421305181124540&quot;&gt;JP&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://social.stlouist.com/@jw/113419385141696407&quot;&gt;JW&lt;/a&gt; mentioned &lt;a href=&quot;https://en.wikipedia.org/wiki/RecipeML&quot;&gt;RecipeML&lt;/a&gt; which is XML (🤮)&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://writing.exchange/@medievalist/113419695154729301&quot;&gt;Lisa mentioned&lt;/a&gt; the format Google prefers for SEO (which I don&#39;t care about) and I tracked that down to the &lt;a href=&quot;https://schema.org/Recipe&quot;&gt;Recipe schema type&lt;/a&gt;&lt;/li&gt; &lt;li&gt;Then there&#39;s the more obvious, not-standard-for-recipes like Markdown, generic HTML, and PDFs&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;I should note at this point, I started writing out how my &lt;em&gt;own&lt;/em&gt; standard might work because I am an idiot. A real &lt;a href=&quot;https://xkcd.com/927/&quot;&gt;XKCD#927 moment&lt;/a&gt;. I stopped, I swear.&lt;/p&gt; &lt;p&gt;Of these I narrowed it down to two that were worth my time: Cooklang and the schema type. Recipe microformat is useful but I was looking for &lt;em&gt;how should I store these&lt;/em&gt; and not necessarily how to display them.&lt;/p&gt; &lt;h3&gt;Cooklang&lt;/h3&gt; &lt;p&gt;A &lt;em&gt;very&lt;/em&gt; basic Cooklang recipe looks like this:&lt;/p&gt; &lt;pre class=&quot;language-cooklang&quot;&gt;&lt;code class=&quot;language-cooklang&quot;&gt;&lt;span class=&quot;token meta&quot;&gt;&gt;&gt; &lt;span class=&quot;token property&quot;&gt;source&lt;/span&gt;: https://en.wikipedia.org/wiki/Apple&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token meta&quot;&gt;&gt;&gt; &lt;span class=&quot;token property&quot;&gt;note&lt;/span&gt;: Recommended by doctor exorcists&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cut the &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Apple&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; into slices. This takes &lt;span class=&quot;token timer-group&quot;&gt;&lt;span class=&quot;token timer-keyword keyword&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token duration-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token duration number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;minute&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. You need a &lt;span class=&quot;token cookware-group&quot;&gt;&lt;span class=&quot;token cookware-keyword keyword&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token cookware variable&quot;&gt;knife&lt;/span&gt;&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Ingredients are identified with &lt;code&gt;@&lt;/code&gt; and quantity is defined in the brackets &lt;code&gt;{100%g}&lt;/code&gt;. Timers are done with &lt;code&gt;~{10%minutes}&lt;/code&gt;. Each paragraph becomes an instruction step. You can also define cookware with &lt;code&gt;#&lt;/code&gt;. &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; is the metadata. When this is run through a parser the output will be represented like so:&lt;/p&gt; &lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://en.wikipedia.org/wiki/Apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;note&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Recommended by doctor exorcists&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ingredients&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ingredient&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;units&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;cookware&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cookware&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;knife.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;steps&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cut the &quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ingredient&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;units&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; into slices. This takes &quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;units&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;minute&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;. You need a &quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cookware&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;knife.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The main limititation I&#39;ve had when converting my recipes is if you have a recipe that is simply &amp;quot;mix all the ingredients&amp;quot; you can&#39;t list them out without them becoming instruction steps.&lt;/p&gt; &lt;pre class=&quot;language-cooklang&quot;&gt;&lt;code class=&quot;language-cooklang&quot;&gt;Mix all the ingredients together.&lt;br /&gt;&lt;br /&gt;- &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Butter&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;230&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;- &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Garlic&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;8-10&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;cloves&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;- &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Parsley&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;So you &lt;em&gt;need&lt;/em&gt; to write it out like this instead:&lt;/p&gt; &lt;pre class=&quot;language-cooklang&quot;&gt;&lt;code class=&quot;language-cooklang&quot;&gt;Mix &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Butter&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;230&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Garlic&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;8-10&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;cloves&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and &lt;span class=&quot;token ingredient-group&quot;&gt;&lt;span class=&quot;token ingredient-keyword keyword&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token ingredient variable&quot;&gt;Parsley&lt;/span&gt;&lt;span class=&quot;token amount-group&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token amount number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token unit-separator operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token unit symbol&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; together.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Which is &lt;em&gt;fine&lt;/em&gt; but in the case of a recipe like this&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; I would prefer to have the ingredients defined separately from the instructions. There&#39;s also no option to add multi line notes in the metadata section with &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; but that&#39;s not a massive problem.&lt;/p&gt; &lt;h3&gt;Schema Recipe Type&lt;/h3&gt; &lt;p&gt;The example Apple recipe above can be represented with JSON-LD like so:&lt;/p&gt; &lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;lt;script type=&lt;span class=&quot;token string&quot;&gt;&quot;application/ld+json&quot;&lt;/span&gt;&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;@context&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://schema.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Recipe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Robb Knight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;cookTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PT1M&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;datePublished&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-11-04&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cutting up an apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;recipeIngredient&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1 Apple&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Sliced Apple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;recipeInstructions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cut the apple into slices. This takes 1 minute. You need a knife.&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;lt;/script&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;There are loads of other attributes available like calorie count and suitability for diet types, among others. This is the format that large recipe sites like &lt;a href=&quot;https://www.allrecipes.com&quot;&gt;allrecipes&lt;/a&gt; use, moreso for SEO than anything else, but I suspect the recipe extractor tools that exist are using this where they can. However, there&#39;s no world in which I&#39;m going to write my recipes in JSON so this can&#39;t be the source format - but it &lt;em&gt;would&lt;/em&gt; make sense to also include this on a recipe page.&lt;/p&gt; &lt;h3&gt;Output&lt;/h3&gt; &lt;p&gt;I wondered what this might look like on a recipe post or page. I think the solution I want is:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Have the recipe, rendered from the cooklang file, as the content of the page. &lt;a href=&quot;https://cooklang.github.io/cooklang-ts/&quot;&gt;&lt;code&gt;cooklang-ts&lt;/code&gt;&lt;/a&gt; will parse the file and give me back all the info I need.&lt;/li&gt; &lt;li&gt;Have the raw cooklang content available so anyone can download it and use it in their own system.&lt;/li&gt; &lt;li&gt;Include the JSON-LD schema on the page so recipe extractors can grab it easily.&lt;/li&gt; &lt;li&gt;Mark it up with the &lt;code&gt;h-recipe&lt;/code&gt; microformat.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;That final point is relatively simple to implement:&lt;/p&gt; &lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;h-recipe&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;p-ingredient&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Apple (1)&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;e-instructions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Cut the apple into slices. This takes 1 minute. You need a knife.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;There&#39;s also &lt;code&gt;p-yield&lt;/code&gt; for quantity produced by the recipe and &lt;code&gt;dt-duration&lt;/code&gt; for how long it takes.&lt;/p&gt; &lt;p&gt;I think this is what I want to achieve on my site. Recipes are blog posts tagged with &lt;a href=&quot;https://rknight.me/blog/tags/recipes/&quot;&gt;#recipes&lt;/a&gt; and all the extra info is available if it&#39;s needed. I have a working branch of my site that adds support for &lt;code&gt;.cook&lt;/code&gt; files as well as parsing the files and I&#39;ll put up a post about that when I&#39;ve got it working exactly how I want.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This is a shortened version of a garlic butter recipe, the real recipe has nine total ingredients so you can see how this would be very annoying. &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Mon, 04 Nov 2024 20:23:58 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/thinking-about-recipe-formats-more-than-anyone-should/</guid> </item> <item> <title>We Got Family Season Two</title> <link>https://rknight.me/blog/we-got-family-season-two/</link> <description>&lt;p&gt;&lt;a href=&quot;https://wegot.family&quot;&gt;&lt;img src=&quot;https://cdn.rknight.me/site/we-got-family-cover-banner.jpg&quot; alt=&quot;The We Got Family cover art&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://wegot.family&quot;&gt;We Got Family&lt;/a&gt; is a podcast I do with &lt;a href=&quot;https://darn.es/&quot;&gt;David Darnes&lt;/a&gt; about the Fast and Furious movies. In season one we did the first four movies, plus a bonus episode for &lt;a href=&quot;https://www.imdb.com/title/tt2933474/&quot;&gt;Superfast!&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;It&#39;s been a while but we&#39;re back for season two starting with 2011&#39;s Fast Five. &lt;a href=&quot;https://wegot.family/6/&quot;&gt;Listen on the website&lt;/a&gt; or you can subscribe via &lt;a href=&quot;https://wegot.family/feed.xml&quot;&gt;RSS&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/us/podcast/we-got-family/id1695398667&quot;&gt;Apple Podcasts&lt;/a&gt;, &lt;a href=&quot;https://open.spotify.com/show/3qziz3DuqmPJ4tOokJLhU6&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://overcast.fm/itunes1695398667/we-got-family&quot;&gt;Overcast&lt;/a&gt;, &lt;a href=&quot;https://pca.st/l0a0gli5&quot;&gt;Pocketcasts&lt;/a&gt;, &lt;a href=&quot;https://castro.fm/podcast/1bcdc53c-40a4-4baa-ac05-ae18654ea695&quot;&gt;Castro&lt;/a&gt;, or wherever you get your podcasts.&lt;/p&gt; </description> <pubDate>Mon, 04 Nov 2024 10:00:00 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/we-got-family-season-two/</guid> </item> <item> <title>WeblogPoMo AMA</title> <link>https://rknight.me/blog/weblogpomo-ama/</link> <description>&lt;p&gt;Annie has set a &lt;a href=&quot;https://weblogpomo.club/challenges&quot;&gt;WeblogPoMo challenge&lt;/a&gt; for this month, Ask Me Anything:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I&#39;m calling this challenge WeblogPoMo AMA (Ask Me Anything). For this challenge I want to foster writer interaction: write a blog post starting with a question—the AMA—and then answer the question yourself in the blog post.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;There may have been some misunderstanding with how to source the questions so I&#39;m doing some I &lt;a href=&quot;https://social.lol/@robb/113403816549745605&quot;&gt;asked for on Mastodon&lt;/a&gt; and some that other people have posted about.&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What’s the best music-related experience of your life so far?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I didn&#39;t realise it until recently but I was at &lt;a href=&quot;https://en.wikipedia.org/wiki/Dig_Out_Your_Soul_Tour&quot;&gt;Oasis&#39; last ever gig&lt;/a&gt; and that was a great experience even if I&#39;m not a huge fan of them and it took me 15 years to realise it was thier last one. So that&#39;s pretty cool.&lt;/p&gt; &lt;p&gt;But the one that sticks out to me is not even an in-person experience. &lt;a href=&quot;https://www.youtube.com/watch?v=IL1nlWOciL0&quot;&gt;Linkin Park&#39;s performance&lt;/a&gt; to announce a new singer, new tour, and new album was amazing to watch live. When Emily Armstrong came out for the second part of The Emptiness Machine it was glorious. I nearly went to bed instead of waiting up to watch it, thinking it would be a simple &amp;quot;oh here&#39;s a reissue of some old songs&amp;quot;. Turns out that would have been a terrible idea.&lt;/p&gt; &lt;p&gt;Hiro via &lt;a href=&quot;https://gabz.blog/posts/the-best-music-related-experience&quot;&gt;Gabz&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What’s the first movie, ever watched that made a big impact on you, for good or bad?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;My grandparents were looking after me when I was maybe 5 or 6 and they decided to pop in a video of a movie my mum had recorded: &lt;a href=&quot;https://www.imdb.com/title/tt0094721/&quot;&gt;Beetlejuice&lt;/a&gt;. It definitely wasn&#39;t age-appropriate but it&#39;s one of my only memories from when I was a kid so it defintiely fits the bill of big impact.&lt;/p&gt; &lt;p&gt;The other is Back to the Future which I watched for the first time around the same age and I&#39;ve watch all three of them basically &lt;a href=&quot;https://rknight.me/almanac/movies/2022-09-18-back-to-the-future/&quot;&gt;every year since then&lt;/a&gt;. I even have a Delorean tattoo.&lt;/p&gt; &lt;p&gt;Gabz via &lt;a href=&quot;https://blog.alpine.day/2024/11/weblogpomoama-2&quot;&gt;Zachery&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What runs through your head when you can’t fall asleep?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I have the ability to just sit and think about nothing, like truly just no thoughts which annoys my wife no end. If I can&#39;t sleep I usually just get up and do something else then go back to bed an hour later. Life hack™.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;Favorite pizza toppings?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I like all pizza&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, it is the perfect food. I am partial to spicy toppings so, ignoring all other variables I&#39;d go for pepperoni, chillis or jalapeños, and pineapple.&lt;/p&gt; &lt;p&gt;via &lt;a href=&quot;https://social.lol/@annie/113405020093956879&quot;&gt;Annie&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What would shock your younger self about your present self? I mean absolutely obliterate their sense of identity. Leave them rocking in a corner.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I have a child and a second one on the way and they were both on purpose.&lt;/p&gt; &lt;p&gt;via &lt;a href=&quot;https://social.lol/@keenan/113405225890832855&quot;&gt;Keenan&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What&#39;s your worst and fav childhood memories?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I&#39;ve sat on this question since it was asked and I have...nothing (except the Beetlejuice one above). I don&#39;t think I have any memories before about 10 years old. Not that my childhood was bad but I can&#39;t think of anything that stands out in either direction. Sorry Alexandra, what a rubbish answer.&lt;/p&gt; &lt;p&gt;via &lt;a href=&quot;https://social.lol/@alexandra/113403973751963152&quot;&gt;Alexandra&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;Why are you the way you are?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I assume by this Lewis means why am I so funny on the &#39;don with bangers like this toot in response to Lewis saying he was in an &amp;quot;autumnal funk&amp;quot;.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;the lesser-known follow up to Uptown Funk&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Jokes aside, trying to get validation on the internet is way cheaper than therapy.&lt;/p&gt; &lt;p&gt;Unintentionally via &lt;a href=&quot;https://social.lol/@lewis/113414252850191856&quot;&gt;Lewis&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;What&#39;s your opinions of Americans in general? How are different than your countrymen?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This is an interesting one to ask, this week of all weeks. All of the Americans I&#39;m friends with are awesome&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; and generally every American I&#39;ve interacted with in my life has been perfectly polite. Most of the stereotypes I think of when I think of Americans are actually things about &lt;em&gt;America&lt;/em&gt; and not the people: healthcare, guns, whatever the fuck &amp;quot;grits&amp;quot; is. There are two things I find different: 1. What the fuck do you give your kids to drink if you don&#39;t have &lt;a href=&quot;https://en.wikipedia.org/wiki/Squash_(drink)&quot;&gt;squash&lt;/a&gt;. 2. Y&#39;all &lt;em&gt;are&lt;/em&gt; really loud in comparison to the rest of the world. This was most obvious when I was in Rome, I could hear American tourists before I could see them.&lt;/p&gt; &lt;p&gt;via &lt;a href=&quot;https://social.lol/@amerpie/113404012590509755&quot;&gt;Lou&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;So there we go. I might do another one of these if more questions pop up I want to answer.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Not you, vegan cheese pizza, you suck &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This is a bit self-selecting because I wouldn&#39;t be friends with dickheads, regardless of country of where they&#39;re from &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Sun, 03 Nov 2024 10:32:36 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/weblogpomo-ama/</guid> </item> <item> <title>Using Setapp</title> <link>https://rknight.me/blog/using-setapp/</link> <description>&lt;p&gt;I&#39;ve had my eye on &lt;a href=&quot;https://go.setapp.com/invite/0jsvfx75&quot;&gt;Setapp&lt;/a&gt; since it launched in 2017 but it&#39;s never been the right time for me to jump in...until this week. I &lt;em&gt;really&lt;/em&gt; wanted to use &lt;a href=&quot;https://godspeedapp.com/a/RKNIGHT25&quot;&gt;Godspeed&lt;/a&gt; which is on Setapp (as well as having a standalone subscription) so I did some calculations to see if it was worth it.&lt;/p&gt; &lt;p&gt;I started with things I knew I would definitely use:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://godspeedapp.com/a/RKNIGHT25&quot;&gt;Godspeed&lt;/a&gt; - $48 a year&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://dropshare.app&quot;&gt;Dropshare&lt;/a&gt; - $39 one-off for the life of version 5. For the sake of this, I&#39;m assuming a new version every couple of years so $20 a year&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://cleanshot.com&quot;&gt;Cleanshot X&lt;/a&gt; - $29 for a year of updates&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://tableplus.com&quot;&gt;TablePlus&lt;/a&gt; - $89 for a year of updates&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;If I add those up and divide by 12, that works out at $15.50 a month. I wanted the iOS option for Godspeed, Awesome Habits, and Soulver (see below) so that put Setapp at $15 a month (including taxes). So as it is it&#39;s basically break-even - I could make Setapp cheaper by paying annually but for right now I&#39;m sticking with monthly. That price also doesn&#39;t account for the additional apps I would use because they&#39;re available. Some of the apps I&#39;ve wanted to use in the past but couldn&#39;t justify the price for my usage:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://c-command.com/toothfairy/&quot;&gt;ToothFairy&lt;/a&gt;. This was recommended by &lt;a href=&quot;https://social.lol/@bw/113329305437289362&quot;&gt;Blake&lt;/a&gt; because of a stupid issue I&#39;ve been having.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://soulver.app&quot;&gt;Soulver&lt;/a&gt;. I&#39;ve been using Numi but Soulver has way more features, plus the iOS version&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://software.charliemonroe.net/downie/&quot;&gt;Downie&lt;/a&gt;. &lt;code&gt;yt-dl&lt;/code&gt; is great but I prefer a GUI for this kind of thing.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://appmakes.io/paletro&quot;&gt;Paletro&lt;/a&gt;. Just handy.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://cleanmymac.macpaw.com&quot;&gt;Clean My Mac&lt;/a&gt;. This saved me 50gb of space somehow. Totally worth it.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://www.awesome-habits.com&quot;&gt;Awesome Habits&lt;/a&gt;. I was eyeballing &lt;a href=&quot;https://streaksapp.com&quot;&gt;Streaks&lt;/a&gt; but Awesome Habits was recommended by some of the MacStoried crew&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Then there are some others that would be nice to use but I definitely wouldn&#39;t use enough to pay directly for:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://setapp.com/apps/mockuuups-studio&quot;&gt;Mockuuups Studio&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://typefaceapp.com&quot;&gt;Typeface&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://handmirror.app&quot;&gt;HandMirror&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://clearvpn.com&quot;&gt;ClearVPN&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://structured.app&quot;&gt;Structured&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://www.realmacsoftware.com/squash/&quot;&gt;Squash&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;So if I use even a handful of these additional apps then I&#39;m saving money. It&#39;s not a can&#39;t-afford-not-to-subscribe situation but it&#39;s a pretty good deal for me.&lt;/p&gt; &lt;p&gt;The Setapp...app itself is just an app store. You can view top downloads, new apps, collections, mark an app as a favourite and it has guides on specific apps. By default it puts an icon in the menubar but you can turn that off because it doesn&#39;t do anything except open the app.&lt;/p&gt; &lt;p&gt;The iOS side involves downloading whatever app from the App Store, then scanning a QR code to verify you have a Setapp subscription. It&#39;s an interesting way to handle this and I have no idea how this is allowed by Apple&#39;s &lt;s&gt;stupid&lt;/s&gt; rules but I&#39;m not going to pull on that thread.&lt;/p&gt; &lt;p&gt;Obviously based on the above I save money but I was curious what kind of deal the app developers get from this. Turns out Setapp are very transparent about &lt;a href=&quot;https://docs.setapp.com/docs/distributing-revenue&quot;&gt;how it works on their help docs&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;We share 70% of each user fee among developers of the apps used by a particular user&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;There&#39;s also something about an additional 20% &amp;quot;&lt;em&gt;to the Partner who has brought this particular user&lt;/em&gt;&amp;quot;. I don&#39;t know what that means but this seems like a decent deal for developers. My money isn&#39;t going into a pot only to be paid to the most popular apps, it&#39;s based on &lt;em&gt;my real usage&lt;/em&gt;. I feel pretty good about this setup.&lt;/p&gt; &lt;p&gt;Finally, they also have a very generous referral scheme&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; that gives me and the person who signs up a free month. So if you want to sign up, use &lt;a href=&quot;https://go.setapp.com/invite/0jsvfx75&quot;&gt;my referral link&lt;/a&gt; to get a free month.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I love a &lt;a href=&quot;/save&quot;&gt;good referral scheme&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Mon, 28 Oct 2024 20:09:57 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/using-setapp/</guid> </item> <item> <title>Copy SSH Keys to a Server</title> <link>https://rknight.me/blog/copy-ssh-keys-to-a-server/</link> <description>&lt;p&gt;Every time I&#39;ve setup a server in the past decade the SSH keys have been set for me, most hosts I&#39;ve used do this (DigitalOcean, Hetzner, etc). This week I signed up for a server with Contabo and I had to do it myself, like a caveman. &lt;a href=&quot;https://lewisdale.dev&quot;&gt;Lewis&lt;/a&gt; was kind enough to help because he&#39;d done the same thing mere days before me.&lt;/p&gt; &lt;p&gt;Step one is to copy my key to the server using &lt;code&gt;ssh-copy-id&lt;/code&gt;:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-copy-id user@example.com&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This failed for me because I didn&#39;t have a default set in my SSH config. There are two ways to handle this. One is to specify a key in the command:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-copy-id &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/personal_id_rsa.pub user@example.com&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Or set a default in &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Host *&lt;br /&gt; IdentityFile ~/.ssh/personal_id_rsa&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Once that&#39;s done you should be able to SSH into the server. The last step is to disable password login which is done by editing &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; PasswordAuthentication yes&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; PasswordAuthentication no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Then refresh the ssh service with &lt;code&gt;sudo service ssh restart&lt;/code&gt;.&lt;/p&gt; </description> <pubDate>Sat, 26 Oct 2024 13:44:37 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/copy-ssh-keys-to-a-server/</guid> </item> <item> <title>Using Miniflux with Reeder and NetNewsWire</title> <link>https://rknight.me/blog/using-miniflux-with-reeder-and-netnewswire/</link> <description>&lt;p&gt;Trying to find the answer to how to use &lt;a href=&quot;https://miniflux.app&quot;&gt;Miniflux&lt;/a&gt; with &lt;a href=&quot;https://reederapp.com&quot;&gt;Reeder (app)&lt;/a&gt; and the Google Reader API proved to be a bit difficult due to the similarly of the app name and the API name. Or maybe I was sleep deprived. Either way, I finally worked it out but I never found a definitive &amp;quot;this is how you do it&amp;quot; just lots of vague Reddit threads so here we are.&lt;/p&gt; &lt;p&gt;In Miniflux go to &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;Integrations&lt;/code&gt; &amp;gt; &lt;code&gt;Google Reader&lt;/code&gt; and set a username and password.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/miniflux-google-reader-settings.jpg&quot; alt=&quot;Google Reader settings in Miniflux&quot; /&gt;&lt;/p&gt; &lt;p&gt;Once that&#39;s set, in Reeder choose &amp;quot;Reader&amp;quot; in the add account screen, set the domain you&#39;ve got Miniflux hosted at and away you go.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/reeder-reader-settings.png&quot; alt=&quot;Reeder settings for Miniflux&quot; /&gt;&lt;/p&gt; &lt;p&gt;To use Miniflux in NetNewsWire follow step one then choose FreshRSS in the add account screen. Make sure to &lt;em&gt;not&lt;/em&gt; have a trailing slash after your domain in NetNewsWire otherwise it will error.&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;As &lt;a href=&quot;https://mastodon.social/@manternach/113368039462474185&quot;&gt;Trevor noted&lt;/a&gt; you must have HTTPS enabled on FreshRSS for this to work.&lt;/p&gt; &lt;/div&gt; </description> <pubDate>Fri, 25 Oct 2024 11:14:36 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/using-miniflux-with-reeder-and-netnewswire/</guid> </item> <item> <title>Mark One Enigma Edition Pen Review</title> <link>https://rknight.me/blog/mark-one-enigma-edition-pen-review/</link> <description>&lt;p&gt;During September I donated to Enigma Stationery&#39;s campaign and was entered into a raffle to win the &lt;a href=&quot;https://enigmastationery.com/shop/p/mark-one-enigma-edition&quot;&gt;Mark One Enigma Edition&lt;/a&gt; and...I actually won! I&#39;ve never owned a fancy pen&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, especially not one this pretty. I don&#39;t even write with pen and paper all that much. None of my notebooks have good paper, or quality covers, or fold out flat but I&#39;m gunna review it anyway.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/enigma-mark-one.jpg&quot; alt=&quot;The Mark One Enigma edition&quot; /&gt;&lt;/p&gt; &lt;p&gt;The Mark One is a pen by &lt;a href=&quot;https://www.studioneat.com/products/markone&quot;&gt;Studio Neat&lt;/a&gt; who make lots of lovely things. The Enigma edition features &amp;quot;&lt;em&gt;a three-layer exterior coating with sparkling teal on a black background&lt;/em&gt;&amp;quot;. It feels great in the hand and the clicking mechanism is very satisfying. For ink it takes a Schmidt capless refill which, to my untrained eye, appears to be some kind of ink container. The one that came with mine definitely has ink. I made this natty diagram to help explain:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/enigma-mark-one-diagram.jpg&quot; alt=&quot;The Mark One pen on dotgrid paper with arrows showing where the clicky bit is and where the ink comes out&quot; /&gt;&lt;/p&gt; &lt;p&gt;When I started writing this post I wanted to parody a pen review like the ones Brad does over on &lt;a href=&quot;https://www.penaddict.com/blog/2018/3/26/mark-one-pen-review&quot;&gt;The Pen Addict&lt;/a&gt; but I truly know so little about pens that I can&#39;t do it. Anyway, it is a lovely pen and I&#39;m now finding myself looking at decent notebooks, the &lt;a href=&quot;https://www.studioneat.com/products/pentray&quot;&gt;mark one pen tray&lt;/a&gt;, and &lt;em&gt;other nice pens&lt;/em&gt;.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Honey, he&#39;s teasing you. Nobody has two &lt;s&gt;television sets&lt;/s&gt; nice pens.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/enigma-mark-one-other-pens.jpg&quot; alt=&quot;The Mark One pen along with some other pens&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Top to bottom: The Mark One, then some other pens I had knocking about.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/enigma-mark-one-writing-sample.jpg&quot; alt=&quot;Writing sample on dotgrid paper with the Mark One&quot; /&gt;&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Not even a Parker pen which, when I was at school, was considered the coolest pen one could possibly own &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Thu, 24 Oct 2024 12:31:03 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/mark-one-enigma-edition-pen-review/</guid> </item> <item> <title>Obsidian Tasks and Godspeed</title> <link>https://rknight.me/blog/obsidian-tasks-and-godspeed/</link> <description>&lt;p&gt;Two weeks ago &lt;a href=&quot;https://social.lol/@robb/113288632240605303&quot;&gt;I tooted&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Lord help me I&#39;m back on Obsidian Tasks again&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;I came up with a nice solution for what I wanted. Show the first todo item in each of my project files using Obsidian Tasks query language:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;path includes projects&lt;br /&gt;group by &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.md&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;limit groups &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;not done&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/project-tasks.jpg&quot; alt=&quot;My todo list as rendered by Obsidian Tasks&quot; /&gt;&lt;/p&gt; &lt;p&gt;I had to add some rules to the css to hide the note titles which are shown when you use grouping:&lt;/p&gt; &lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.tasks-group-heading&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;ul.plugin-tasks-query-result&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;div.task-count&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Turns out, this &lt;em&gt;works&lt;/em&gt; but just it doesn&#39;t work &lt;em&gt;for me&lt;/em&gt;. So I deleted it all (after noting the config down because Obsidian Tasks can be complicated).&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://godspeedapp.com/a/RKNIGHT25&quot;&gt;Godspeed&lt;/a&gt; is my best friend now. I won&#39;t attempt to go into everything Godspeed does but the UI is simple and works for my brain. Their big selling point is everything can be done with the keyboard which I like. It&#39;s also one of the reasons I signed up to &lt;a href=&quot;https://go.setapp.com/invite/0jsvfx75&quot;&gt;Setapp&lt;/a&gt; (expect a post about this soon). If you want to know more &lt;a href=&quot;https://www.youtube.com/watch?v=p8Ak_OB-oco&quot;&gt;Matt has a great video&lt;/a&gt; about Godspeed which is how I found out about it in the first place.&lt;/p&gt; </description> <pubDate>Wed, 23 Oct 2024 20:16:52 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/obsidian-tasks-and-godspeed/</guid> </item> <item> <title>Moving my DNS Records with DNSControl</title> <link>https://rknight.me/blog/moving-my-dns-records-with-dnscontrol/</link> <description>&lt;p&gt;After &lt;a href=&quot;https://rknight.me/blog/setting-up-dnscontrol&quot;&gt;setting up DNSControl&lt;/a&gt; I wanted to use it to move away from DigitalOcean&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; to &lt;a href=&quot;https://bunny.net/?ref=b2i4y24apu&quot;&gt;Bunny DNS&lt;/a&gt;. I&#39;d already moved my servers to &lt;a href=&quot;https://hetzner.cloud/?ref=Lt9D9KzKP6UQ&quot;&gt;Hetzner&lt;/a&gt; but the DNS was more complicated. This domain, for example, has 45 records for subdomains, CNAMES for Netlify, plus verification stuff so I didn&#39;t want to risk moving it manually.&lt;/p&gt; &lt;p&gt;I added my Bunny API keys to &lt;code&gt;creds.json&lt;/code&gt;, updated my &lt;code&gt;dnsconfig.js&lt;/code&gt;, adding Bunny as a new provider, and switched the provider in the config for the domain:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;var DSP_DIGITALOCEAN = NewDnsProvider(&quot;digitalocean&quot;);&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; var DSP_BUNNY = NewDnsProvider(&quot;bunny&quot;);&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;D(&quot;rknight.me&quot;, REG_NONE&lt;br /&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; , DnsProvider(DSP_DIGITALOCEAN)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; , DnsProvider(DSP_BUNNY)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; , DefaultTTL(1800)&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; , A(&quot;@&quot;, HETZNER_MAIN)&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; , A(&quot;www&quot;, HETZNER_MAIN)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I ran &lt;code&gt;dnscontrol push&lt;/code&gt; to push those records to Bunny&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; and then updated the nameservers in &lt;a href=&quot;https://hover.com/scHIv4WR&quot;&gt;Hover&lt;/a&gt; so the domain was pointing to Bunny. Hover isn&#39;t supported by DNSControl so the nameservers had to be done by me but for registrars that are supported, I was able to have that automated as well. The nameservers for Bunny (&lt;code&gt;kiki.bunny.net&lt;/code&gt; and &lt;code&gt;coco.bunny.net&lt;/code&gt;) are automatically set from the registrar, so you don&#39;t need to define them yourself as &lt;a href=&quot;https://github.com/StackExchange/dnscontrol/issues/3163#issuecomment-2426650514&quot;&gt;I found out&lt;/a&gt;.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; var REG_PORKBUN = NewRegistrar(&quot;porkbun&quot;); &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; D(&quot;knightshift.dev&quot;, REG_NONE&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; D(&quot;knightshift.dev&quot;, REG_PORKBUN&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; , DnsProvider(DSP_BUNNY)&lt;br /&gt; , DefaultTTL(1800)&lt;br /&gt; , A(&quot;@&quot;, HETZNER_MAIN)&lt;br /&gt; , A(&quot;www&quot;, HETZNER_MAIN)&lt;br /&gt; , A(&quot;msorc&quot;, HETZNER_MAIN)&lt;br /&gt;)&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Once I&#39;d done that for the other domains I use, I wanted my DNSControl to at least be aware of two other domains that just redirect to my main site (this is handled in Hover). If you set a domain with no registrar and no provider, you&#39;ll get an error about having no nameservers. To fix this, I added &lt;code&gt;{ no_ns:&#39;true&#39; }&lt;/code&gt;. This doesn&#39;t actually &lt;em&gt;do&lt;/em&gt; anything, but it&#39;s handy to have a record of every domain I have in one place.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;therobb.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REG_NONE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;no_ns&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;true&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// =&gt; rknight.me&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This setup already came in handy yesterday when I needed to prove ownership of one of my domains: add one line, run &lt;code&gt;dnscontrol push&lt;/code&gt;, done.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;after &lt;a href=&quot;https://rknight.me/blog/netcraft-facebook-and-digital-ocean/&quot;&gt;what they did&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;There was some shenanigans where someone else had added my domain to their Bunny account which I had to sort out with support, but they were very quick to fix it &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Tue, 22 Oct 2024 14:00:05 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/moving-my-dns-records-with-dnscontrol/</guid> </item> <item> <title>Fix Crackly Audio When Using Bluetooth Headphones on MacOS</title> <link>https://rknight.me/blog/fix-crackly-audio-when-using-bluetooth-headphones-on-macos/</link> <description>&lt;p&gt;Every now and again I start listening to music on MacOS through my headphones and the audio is tinny and crackly. After some dicking around with quitting Apple Music, reconnecting the headphones, even rebooting the Mac nothing fixed it. I finally worked out the fix&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; - changing the input settings of the Mac to &lt;em&gt;not&lt;/em&gt; be the headphones. No more crackling.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/input-settings.jpg&quot; alt=&quot;Input settings showing the Mac is selected for the input source and not Magneto&quot; /&gt;&lt;/p&gt; &lt;p&gt;Yet another &lt;a href=&quot;https://rknight.me/blog/fix-for-bluetooth-audio-cutting-out-on-the-mac/&quot;&gt;very stupid fix for stupid audio issues&lt;/a&gt;.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I probably found this solution on Reddit or the Apple forums but I can&#39;t find the source now &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Fri, 18 Oct 2024 11:59:23 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/fix-crackly-audio-when-using-bluetooth-headphones-on-macos/</guid> </item> <item> <title>Setting Up DNSControl</title> <link>https://rknight.me/blog/setting-up-dnscontrol/</link> <description>&lt;p&gt;When I linked to &lt;a href=&quot;https://alexwlchan.net/2024/documenting-my-dns/&quot;&gt;this post about DNS&lt;/a&gt;, &lt;a href=&quot;https://social.lol/@rail/113322023046758075&quot;&gt;Dave replied&lt;/a&gt; and mentioned he uses &lt;a href=&quot;https://dnscontrol.org&quot;&gt;DNSControl&lt;/a&gt; for managing this kind of stuff. I&#39;d heard of it before but never actually looked into what it did so I jumped into the &lt;a href=&quot;https://docs.dnscontrol.org/getting-started/getting-started&quot;&gt;getting started guide&lt;/a&gt;. I&#39;d recommend reading that if you want a more in-depth guide, this post is just an overview of what I did to get what I wanted accomplished.&lt;/p&gt; &lt;p&gt;No detailed install steps here, check out the official docs, but the short version is this: install DNSControl (&lt;code&gt;brew install dnscontrol&lt;/code&gt;), make a directory with a &lt;code&gt;zones&lt;/code&gt; directory inside it, then make two files: &lt;code&gt;dnsconfig.js&lt;/code&gt; and &lt;code&gt;creds.json&lt;/code&gt; (don&#39;t forget to put &lt;code&gt;creds.json&lt;/code&gt; in your &lt;code&gt;.gitignore&lt;/code&gt; if you plan on using git for this).&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;mydnsconfig&lt;br /&gt;├── zones&lt;br /&gt;├── dnsconfig.js&lt;br /&gt;├── creds.json&lt;br /&gt;└── .gitignore&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I currently have nine domains and all the DNS is managed at DigitalOcean (for now) so my &lt;code&gt;creds.json&lt;/code&gt; file looks like this:&lt;/p&gt; &lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;bind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;TYPE&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;BIND&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;digitalocean&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;TYPE&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DIGITALOCEAN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;token&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MY_TOKEN&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I didn&#39;t want to have to manually input all the records into the config but thankfully DNSControl has an option to fetch existing records to generate the config for a specific domain which you can then copy into the &lt;code&gt;dnsconfig.js&lt;/code&gt; file.&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dnscontrol get-zones &lt;span class=&quot;token parameter variable&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;djs digitalocean DIGITALOCEAN slashpages.net&lt;br /&gt;&lt;br /&gt;D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slashpages.net&quot;&lt;/span&gt;, REG_CHANGEME&lt;br /&gt; , DnsProvider&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DSP_DIGITALOCEAN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; , DefaultTTL&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; //, NAMESERVER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ns1.digitalocean.com.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; //, NAMESERVER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ns2.digitalocean.com.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; //, NAMESERVER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ns3.digitalocean.com.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; , A&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;49.13.76.163&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; , A&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;www&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;49.13.76.163&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I ran that for all my domains so my config ended up looking something like this. I&#39;ve removed some records here for the sake of keeping it short.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REG_NONE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NewRegistrar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// No registrar.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DNS_BIND&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NewDnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bind&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ISC BIND.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DSP_DIGITALOCEAN&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NewDnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;digitalocean&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HETZNER_MAIN&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;49.13.76.163&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token constant&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rknight.me&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REG_NONE&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DSP_DIGITALOCEAN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefaultTTL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns1.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns2.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns3.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HETZNER_MAIN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;www&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HETZNER_MAIN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// lots of subdomain setups go here&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token constant&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slashpages.net&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REG_NONE&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DSP_DIGITALOCEAN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefaultTTL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns1.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns2.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;//, NAMESERVER(&quot;ns3.digitalocean.com.&quot;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HETZNER_MAIN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;www&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HETZNER_MAIN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;You can run &lt;code&gt;dnscontrol preview&lt;/code&gt; to check what you have in the config matches what&#39;s on the DNS provider. If there&#39;s any differences, it will tell you.&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dnscontrol preview&lt;br /&gt;&lt;br /&gt;******************** Domain: rknight.me&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; correction &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;digitalocean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;#1: ± MODIFY A api.rknight.me: (123.45.67.99 ttl=1800) -&gt; (123.45.67.89 ttl=1800), DO ID: 359463019&lt;/span&gt;&lt;br /&gt;******************** Domain: echofeed.app&lt;br /&gt;******************** Domain: bugle.lol&lt;br /&gt;******************** Domain: coinme.dad&lt;br /&gt;******************** Domain: deskmat.help&lt;br /&gt;******************** Domain: knightshift.dev&lt;br /&gt;******************** Domain: ruminatepodcast.com&lt;br /&gt;******************** Domain: slashpages.net&lt;br /&gt;******************** Domain: wegot.family&lt;br /&gt;Done. &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; corrections.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Running &lt;code&gt;dnscontrol push&lt;/code&gt; will the sync these changes to the DNS provider. For this domain, I have 45 records so the idea of moving off of DigitalOcean was daunting but now I&#39;ve got this setup it should be a lot easier to switch to one of the 35 providers that DNSControl supports.&lt;/p&gt; </description> <pubDate>Thu, 17 Oct 2024 20:36:45 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/setting-up-dnscontrol/</guid> </item> <item> <title>Things I Like: 8BitDo Keycaps</title> <link>https://rknight.me/blog/things-i-like-8bitdo-keycaps/</link> <description>&lt;p&gt;When 8BitDo announced they were selling &lt;a href=&quot;https://shop.8bitdo.com/products/8bitdo-retro-keycaps&quot;&gt;a new keycap set&lt;/a&gt; that matched &lt;a href=&quot;https://rknight.me/blog/using-the-8bitdo-keyboard-on-macos/&quot;&gt;my keyboard I got from them&lt;/a&gt; I ordered immediately. I didn&#39;t need new keycaps for it but I &lt;em&gt;really&lt;/em&gt; wanted to get rid of that pesky windows key.&lt;/p&gt; &lt;p&gt;They arrived this morning in nice little trays:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/8bitdo-keycaps.jpg&quot; alt=&quot;The 8BitDo keycaps in their trays&quot; /&gt;&lt;/p&gt; &lt;p&gt;At lunch I swapped out a bunch of them including a lot of the ones with symbols on, along with the larger-text &lt;key&gt;pgup&lt;/key&gt;/&lt;key&gt;pgdown&lt;/key&gt; over on the right hand side. Here&#39;s a comparison - I should have taken a before photo today but I forgot so I made do with what I had.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/8bitdo-comparison.jpg&quot; alt=&quot;Comparison of the keyboard before and after&quot; /&gt;&lt;/p&gt; &lt;p&gt;I didn&#39;t &lt;em&gt;need&lt;/em&gt; to spend $50 on these but I&#39;m glad I did.&lt;/p&gt; </description> <pubDate>Thu, 17 Oct 2024 19:32:59 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/things-i-like-8bitdo-keycaps/</guid> </item> <item> <title>Our Wedding Photographer Was Terrible</title> <link>https://rknight.me/blog/our-wedding-photographer-was-terrible/</link> <description>&lt;p&gt;This was going to be a scathing review of our wedding photographer I planned on posting because I was furious having waited 6 months to get the photos but he&#39;s basically gone bust anyway and I&#39;ve calmed down since then. I&#39;m posting it anyway because it&#39;s been in my post drafts for months and I want it for reference. Name of the photographer is redacted because quite frankly life&#39;s too short.&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;On the wedding day:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Was late&lt;/li&gt; &lt;li&gt;Complained endlessly about having to pay for parking until the make up person told him to get over it&lt;/li&gt; &lt;li&gt;Forget his camera after walking us 15 minutes away from the venue so we had to stand around and wait until he came back with it&lt;/li&gt; &lt;li&gt;Was giving one of our guests an inordinate and inappropriate amount of attention, as pointed out to us by many of our other guests&lt;/li&gt; &lt;li&gt;Made us wait far too long for the cake cutting and the first dance because he wasn&#39;t even remotely ready. Then complained about the location of the cake despite it being there the entire day.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Now for actually getting our photos:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;14th November 2023, 66 days since the wedding&lt;/strong&gt;: Messaged on WhatsApp where I had previously messaged with [redacted]. No response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;21st November, 73 days&lt;/strong&gt;: Messaged on Facebook messenger. [redacted] replied the next day saying photos would be ready &amp;quot;next week&amp;quot;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;8th December, 90 days&lt;/strong&gt;: Gallery link was sent with the photos but all of the group photos were missing.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;14th December, 96 days&lt;/strong&gt;: Messaged to ask about group photos, pre-wedding shoot photos, and the pin to download the photos. Seen, no response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;21st December, 103 days&lt;/strong&gt;: My wife messaged him asking him to respond to me on his personal account. No response to her&lt;/li&gt; &lt;li&gt;&lt;strong&gt;22nd December, 104 days&lt;/strong&gt;: &amp;quot;I am going to take a look and get back to you&amp;quot;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;January 18th, 131 days&lt;/strong&gt;: Messaged. Seen, no response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;January 27th, 140 days&lt;/strong&gt;: Messaged. Seen, no response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;February 2nd, 147 days&lt;/strong&gt;: Messaged, more firm. Finally got a response and told me to calm down. Told he will get to us &amp;quot;first thing in the morning&amp;quot;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;February 3rd, 148 days&lt;/strong&gt;: Got the missing group photos but still no pin to download them. &amp;quot;Give me 2 secs I&#39;ll send you an email&amp;quot;. No email or pin.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;February 17th, 162 days&lt;/strong&gt;: Messaged to ask for a pin and the pre-wedding shoot photos. Seen, no response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;February 25th, 170 days&lt;/strong&gt;: Messaged again. Seen, no response.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;2nd March, 177 days&lt;/strong&gt;: Messaged again, responded the next day.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;3rd March, 178 days&lt;/strong&gt;: Got the pin to download the photos finally. &amp;quot;I will forward you pre wedding photos in the morning.&amp;quot;. He did not.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;5th March, 180 days&lt;/strong&gt;: Messaged again. Finally got a response with the pre-wedding shoot photos 24 hours later.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;So it took just shy of 3 months to get some, but not all, of the photos. Then just shy of 6 months to actually be able to download them. To make any progress we always had to chase [redacted], not once did he give us an update without prompting from us.&lt;/p&gt; &lt;p&gt;Even once we did get them, it was clear they hadn&#39;t been checked or edited, there was at least a few photos that had fingers in the way or were blurry and one photo that wasn&#39;t even from our wedding.&lt;/p&gt; &lt;hr /&gt; &lt;p&gt;And, scene.&lt;/p&gt; </description> <pubDate>Fri, 11 Oct 2024 11:52:32 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/our-wedding-photographer-was-terrible/</guid> </item> <item> <title>Setting Up Mastodon Author Tags</title> <link>https://rknight.me/blog/setting-up-mastodon-author-tags/</link> <description>&lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/author-tag-preview.jpg&quot; alt=&quot;The new author tags on Mastodon 4.3&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://blog.joinmastodon.org/2024/10/mastodon-4.3/&quot;&gt;Mastodon 4.3 released today&lt;/a&gt; with a bunch of features but the one most people, including me, are excited about is author tags - this isn&#39;t the name of them but they also don&#39;t seem to have a proper name as far as I can tell. Anyway, you need to do two things to get the &amp;quot;More from X&amp;quot; section you can see in the screenshot above. The first is to add the &lt;code&gt;fediverse:creator&lt;/code&gt; tag to your site in your &lt;code&gt;head&lt;/code&gt;, which I &lt;a href=&quot;https://rknight.me/blog/highlighting-journalism-with-the-fediverse-creator-tag/&quot;&gt;previously wrote about here&lt;/a&gt;.&lt;/p&gt; &lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fediverse:creator&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;@robb@social.lol&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Then you need to jump into your settings on Mastodon and go to the Author Attribution section under Public Profile &amp;gt; Verification. Add the domain(s) that you want to allow to be linked to your profile.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/author-tags-settings.jpg&quot; alt=&quot;The author attribution section of Mastodon&quot; /&gt;&lt;/p&gt; &lt;p&gt;And that&#39;s it. Keep in mind if you share a post to test this that has been posted recently your instance probably has it cached so the new author stuff won&#39;t show up.&lt;/p&gt; </description> <pubDate>Tue, 08 Oct 2024 19:45:42 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/setting-up-mastodon-author-tags/</guid> </item> <item> <title>Never Send me a TikTok Video</title> <link>https://rknight.me/blog/never-send-me-a-tiktok-video/</link> <description>&lt;p&gt;Today a friend shared a video on TikTok with me that I promptly sent to my wife because I knew she would find it funny. &lt;a href=&quot;https://www.tiktok.com/@wonderbaby.co/video/7390445129993096478&quot;&gt;It is funny&lt;/a&gt; (this is a non-tracked link). A few hours later that friend said &amp;quot;Oh your wife has watched it&amp;quot; because TikTok notified him, with her username, that she had watched it. What the actual fuck.&lt;/p&gt; &lt;p&gt;Every time you share a link to a TikTok from the app, it generates a new link. There is no way that I can find to get a canonical share link to a video. &lt;code&gt;https://vm.tiktok.com/ZGdJQnqXX/&lt;/code&gt; and &lt;code&gt;https://vm.tiktok.com/ZGdJ41RXX/&lt;/code&gt; are links to the exact same video (redacted for obvious reasons) but one is linked to my friend and one is linked to me.&lt;/p&gt; &lt;p&gt;Look at this fucking notification:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/tiktok-notification.jpg&quot; alt=&quot;The TikTok notification tab on my friend&#39;s app&quot; /&gt;&lt;/p&gt; &lt;p&gt;I&#39;m sure none of this is new information but I don&#39;t use TikTok so haven&#39;t been paying attention but I swear to god I&#39;m never opening a TikTok link ever again.&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;You can turn off some of this tracking in Settings &amp;gt; Privacy &amp;gt; Suggest your account to others. Apparently this will stop the notification as above but I haven&#39;t confirmed this. &lt;a href=&quot;https://snailedit.social/@zmk/113266357360267152&quot;&gt;via zmknox&lt;/a&gt;&lt;/p&gt; &lt;/div&gt; </description> <pubDate>Mon, 07 Oct 2024 13:11:55 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/never-send-me-a-tiktok-video/</guid> </item> <item> <title>I Finally Saw, and Used, an App Clip</title> <link>https://rknight.me/blog/i-finally-saw-and-used-an-app-clip/</link> <description>&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;A previous version of this post said app clips were introduced seven years ago because AI summaries are dumb and Google is all the more stupid for using it.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;I was at a wedding on Friday and when we sat down for the wedding breakfast there was a QR code on the table to prompt us to take photos. I scanned it and to my surprise it was an &lt;a href=&quot;https://apple.fandom.com/wiki/App_Clips&quot;&gt;App Clip&lt;/a&gt; for &lt;a href=&quot;https://pov.camera&quot;&gt;POV camera&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. This is the first time the four years since they were introduced that I&#39;ve seen one - I assumed they didn&#39;t exist any more.&lt;/p&gt; &lt;p&gt;POV camera is basically a &amp;quot;disposable&amp;quot; camera. You get 28 photos and you can&#39;t see or edit them after you take them. They get sent to the event organiser (in this case the bride and groom) and they can &amp;quot;develop&amp;quot; them at a time they choose for everyone to browse. You can browse all the photos, just yours, or choose a specific person&#39;s. As an aside, the metaphor to physical film development and disposable cameras is surely lost on anyone under 25.&lt;/p&gt; &lt;p&gt;The app has a live activity for the duration of the event as well, which makes it easy to jump in and take a photo. It also helps because otherwise I would have forgotten about it for the rest of the day.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/pov-live-activity.jpg&quot; alt=&quot;POV camera live activity&quot; /&gt;&lt;/p&gt; &lt;p&gt;I did need to download the full version of the app once the photos were available so I could save the photos but this is apparently a limitation of the App Clips API. Outside of parking meters&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; I&#39;d not really heard of a good use case for App Clips so it was interesting to see one being used.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;On Android, it uses the &lt;a href=&quot;https://developer.android.com/topic/google-play-instant&quot;&gt;Instant Apps system&lt;/a&gt; which is basically the same &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Not that any of the ones I&#39;ve ever used had an App Clip &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Mon, 07 Oct 2024 11:09:15 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/i-finally-saw-and-used-an-app-clip/</guid> </item> <item> <title>The Sticker Book</title> <link>https://rknight.me/blog/the-sticker-book/</link> <description>&lt;p&gt;Me every time I open a drawer at my desk:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Wow I have a lot of stickers in this drawer that I&#39;ve never used because I&#39;m paralysed with choice about where to put them and if I get it wrong there&#39;s no going back&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;No more! I have freed myself from the shackles of sticker doubt by sticking them in a book. An extraordinary idea to stick my stickers in a thing sort of designed for stickers. The scope of my genius literally knows no bounds.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/sticker-book.jpg&quot; alt=&quot;A page from my sticker book with all the 2023 St Jude stickers&quot; /&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;But what if the book is the wrong place for them, what if there&#39;s a better place to put them? WHAT THEN?!&lt;/em&gt;&lt;/p&gt; </description> <pubDate>Thu, 03 Oct 2024 18:55:03 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/the-sticker-book/</guid> </item> <item> <title>St Jude 2024 Recap</title> <link>https://rknight.me/blog/st-jude-2024-recap/</link> <description>&lt;p&gt;Relay&#39;s St Jude campaign for 2024 is (mostly) over and they raised over &lt;em&gt;one million dollars&lt;/em&gt;, which is incredible. This year for our campaign, me and Adam set our goal to one cent over last year&#39;s final total: $12,590.57. Given that last year $5k of that was from a one-off donation it seemed reasonable to try and aim for that. We never expected to hit $10k on the 4th of September, then hit the goal six days later, and &lt;em&gt;then&lt;/em&gt; keep going all the way to $20k on the &lt;s&gt;1st of October&lt;/s&gt; 31st of September. Thank to you everyone who donated or shared the campaign.&lt;/p&gt; &lt;p&gt;You can read all about the stickers &lt;a href=&quot;https://rknight.me/blog/st-jude-2024/&quot;&gt;in my previous post&lt;/a&gt; but we have 84 sticker packs going out to 16 different countries.&lt;/p&gt; &lt;p&gt;The &lt;a href=&quot;https://donationdaddy.rknight.me&quot;&gt;Donation Daddy extended universe&lt;/a&gt; was resurrected for this year&#39;s campaign and got a new friend: &lt;a href=&quot;https://hathelp.rknight.me&quot;&gt;Hat Help&lt;/a&gt;. Anyone who raised over $500 this year gets a very natty hat and tumbler.&lt;/p&gt; &lt;p&gt;During the campaign I received 3 pins from Tiltify to celebrate raising $7.5k, $10k, and $25k which was lovely.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/tiltify-pins.jpg&quot; alt=&quot;Tiltify Pins&quot; /&gt;&lt;/p&gt; &lt;h3&gt;Donation Treats&lt;/h3&gt; &lt;p&gt;There were 92 incentives available across 179 campaigns. I&#39;ve got a coaster coming from &lt;a href=&quot;https://mvo.live&quot;&gt;MVO&lt;/a&gt;, mine and Baby Knight&#39;s name will be on the cart he&#39;s building, I entered some raffles for various things, got some stickers, and I took full advantage of &lt;a href=&quot;https://tiltify.com/@jd-burch/jd-burch-for-st-judes-2024?origin=dashboard&quot;&gt;JD&#39;s roasts&lt;/a&gt; and bought two: one for my new car and one for my desk.&lt;/p&gt; &lt;h4&gt;Car Roast&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt;Oh, look at this little Hyundai i30. You really decided to go full in on the mediocre route, didn’t you? This car is the equivalent of the lukewarm cup of keurig coffee you had at their dealership. It looks like they designed it with the ruler and severe lack of ambition combo. I mean, it’s got four wheels and an engine, but so does my lawnmower.&lt;/p&gt; &lt;p&gt;I bet stepping on the gas in this thing feels like asking grandma to hurry up. &amp;quot;Okay, okay, we’re going, don’t rush me!” You want something fun to zip around in? You’ll have to find it elsewhere because this car is about as thrilling as a PowerPoint presentation on spreadsheets. This thing is so basic, it’s probably invisible to radar, because even technology can’t be bothered to notice it.&lt;/p&gt; &lt;p&gt;But at least it’s reliable, right? Because when you’re driving something that looks like it was designed by committee, you need something to cling to. So yeah, enjoy your Hyundai i30—because someone has to, right?&lt;/p&gt; &lt;/blockquote&gt; &lt;h4&gt;Desk Roast&lt;/h4&gt; &lt;blockquote&gt; &lt;p&gt;Robb, this desk seriously looks like the chaotic tribute to the art of procrastination. Let’s start with the pegboard: Clearly it’s supposed to be an organizational tool, but it looks like it’s been hit by a mini-tornado of random trinkets and plants. Do those succulents even get sunlight? Or are they just there to distract you from the existential crisis that is your organizational state? Do they help absorb the overwhelming amount of “I’ll get to it later” vibes in the air? I have to say, though, the groot is a very good addition.&lt;/p&gt; &lt;p&gt;I have been instructed to roast, but we cannot let the fantastic desk mat go unnoticed. It’s quite unfortunate that it’s going to be replaced soon.&lt;/p&gt; &lt;p&gt;Three cans of Monster? Clearly caffeine is your only fuel source as you try to survive yet another round of scrolling through Slack pretending to be busy. Do those empty cans just live there permanently, like a memorial to all the sleep you’ll never get back thanks to Baby Knight?&lt;/p&gt; &lt;p&gt;There’s just a random assortment of everything. There’s a pink microphone, a half open drawer, a fan (That does not appear to be Ryobi 👀), and a whole bunch of random objects. This desk is a chaos where minimalism went to die, and then your productivity followed right after.&lt;/p&gt; &lt;p&gt;What’s up with the cool action figure/lego/something figure in the top right? That thing looks like the guardian of your desk. It will defend it with its life, eliminating anyone who tries to throw away your monster cans.&lt;/p&gt; &lt;p&gt;In conclusion, your background screams that you want to be organized but also embrace chaos, and it’s giving off major creative meltdown in progress vibes. You’ve somehow managed to turn a pegboard into a shrine for random knick-knacks and, of course, that one succulent that’s definitely judging you from a distance.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Plans are already starting for next year, so look out for that. It&#39;s basically September already.&lt;/p&gt; </description> <pubDate>Thu, 03 Oct 2024 07:31:36 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/st-jude-2024-recap/</guid> </item> <item> <title>Alternatives to Wordpress</title> <link>https://rknight.me/blog/alternatives-to-wordpress/</link> <description>&lt;p&gt;After all the &lt;a href=&quot;https://birchtree.me/blog/the-core-thing-that-makes-wordpress-wordpress-isnt-what-you-think/&quot;&gt;Wordpress drama this week&lt;/a&gt; I &lt;a href=&quot;https://social.lol/@robb/113203986371157848&quot;&gt;tooted the following&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;We really need a new, easy to use, CMS written in PHP to compete with Wordpress.&lt;/p&gt; &lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;Why PHP? Because you dump files on a server, any server, and it just works.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Loads of people jumped into my mentions to point me to alternatives that exist and here they are.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://www.classicpress.net/&quot;&gt;ClassicPress&lt;/a&gt; - This one is interesting because it&#39;s a fork of Wordpress without the Gutenberg block editor.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://getkirby.com/&quot;&gt;Kirby CMS&lt;/a&gt; - I know people who swear by Kirby and it&#39;s &lt;em&gt;really&lt;/em&gt; flexible.&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://craftcms.com/&quot;&gt;Craft CMS&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://cecil.app/&quot;&gt;Cecil&lt;/a&gt; - This is a static site generator so not &lt;em&gt;quite&lt;/em&gt; what I was asking for but it looks like a solid product&lt;/li&gt; &lt;/ul&gt; </description> <pubDate>Fri, 27 Sep 2024 12:42:48 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/alternatives-to-wordpress/</guid> </item> <item> <title>The Robb Jobb</title> <link>https://rknight.me/blog/the-robb-jobb/</link> <description>&lt;p&gt;While watching &lt;a href=&quot;https://www.youtube.com/watch?v=Qo9OV9iqebc&quot;&gt;this video about making wine from Monster&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; this morning and thinking about how I want nothing more than to try it, I wondered how this would do as a replacement for the energy drink portion of The Robb Jobb. What is the Robb Jobb? Good question, smart reader. The Robb Jobb is a punch of my own design that I have made on a handful of occasions over the past decade, the last time at my stag do in 2020. Each time everyone says it&#39;s delicious and then choas ensues.&lt;/p&gt; &lt;p&gt;&amp;quot;&lt;em&gt;Robb I wanna make this right now, give me the recipe&lt;/em&gt;&amp;quot;. Okay, calm down. As with all good recipes, it has one instruction: mix all this together.&lt;/p&gt; &lt;!-- - 2 litres of vodka. - 1 litre of energy drink. I&#39;ve used [Tesco Blue Spark](https://www.tesco.com/groceries/en-GB/products/314819928) in the past for this but pick any energy drink you fancy. Or make it with Monster wine and let me know how it goes. - 500ml of lager. Heineken is my preference for this. - 100ml of lime cordial. --&gt; &lt;p&gt;I take no responsibility for what happens if you make or drink this. It &lt;em&gt;is&lt;/em&gt; delecious though.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;It has to be made in the Monster region, otherwise it&#39;s just sparkling energy wine. &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; &lt;article class=&quot;h-recipe recipe&quot;&gt; &lt;aside class=&quot;alert&quot;&gt; &lt;div class=&quot;alert-icon&quot;&gt; &lt;svg class=&quot;icon alert-recipe&quot;&gt; &lt;use xlink:href=&quot;#kitchen&quot;&gt;&lt;/use&gt; &lt;/svg&gt; &lt;/div&gt; &lt;h1&gt;The Robb Jobb&lt;/h1&gt;&lt;p&gt;Ideally served from a bucket or comically large punch bowl with a ladel.&lt;/p&gt; &lt;p&gt;I&amp;#39;ve used &lt;a href=&quot;https://www.tesco.com/groceries/en-GB/products/314819928&quot;&gt;Tesco Blue Spark&lt;/a&gt; in the past for this but pick any energy drink you fancy. Or make it with Monster wine and let me know how it goes.&lt;/p&gt; &lt;p&gt;Heineken is my preference for the lager but any old crap will do.&lt;/p&gt; &lt;/aside&gt; &lt;ul&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;2litres &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Vodka&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;1litre &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Energy Drink&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;500ml &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Lager&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;p-quantity&quot;&gt;100ml &lt;/span&gt;&lt;span class=&quot;p-ingredient&quot;&gt;Lime Cordial&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;div class=&quot;e-instructions&quot;&gt;&lt;p&gt;&lt;p&gt;In your container of choice mix the &lt;span class=&quot;cl-ingredient&quot;&gt;vodka&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;energy drink&lt;/span&gt;, &lt;span class=&quot;cl-ingredient&quot;&gt;lager&lt;/span&gt;, and &lt;span class=&quot;cl-ingredient&quot;&gt;lime cordial&lt;/span&gt;. Serve with a ladel.&lt;/p&gt; &lt;/p&gt;&lt;/div&gt; &lt;/article&gt;</description> <pubDate>Tue, 24 Sep 2024 12:47:53 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/the-robb-jobb/</guid> </item> <item> <title>MagSafe Miscellania</title> <link>https://rknight.me/blog/magsafe-miscellania/</link> <description>&lt;p&gt;Last week I asked if anyone had suggestions for a MagSafe car mount and I got a ton of recommendations. Loads of love for &lt;a href=&quot;https://uk.peakdesign.com/pages/mobile&quot;&gt;Peak Design&lt;/a&gt; but I&#39;m not paying that much just to hold my phone. Lots of people also suggested various no-name brand ones from Amazon which were much more palatable to me.&lt;/p&gt; &lt;p&gt;I ended up with &lt;a href=&quot;https://www.amazon.co.uk/dp/B0CHVV5WKJ&quot;&gt;this one by a company called Lisen&lt;/a&gt;. It sticks directly to the dashboard, doesn&#39;t wobble around, and it supports 15W charging (once I bought a &lt;a href=&quot;https://www.amazon.co.uk/dp/B0BVZK3MHF&quot;&gt;cigarette lighter adaptor&lt;/a&gt;).&lt;/p&gt; &lt;p&gt;Because Apple&#39;s silicone cases kept falling apart on me over the past few years I&#39;ve been on the whatevers-cheapest-on-ali-express case train for a few years but none of the ones I own are MagSafe compatible. This meant trudging through endless pages of various shades of grey cases along with some that looked like they were just waved past a color in the factory. I just wanted something &lt;em&gt;fun&lt;/em&gt;. Orange! Neon green! Hot pink!&lt;/p&gt; &lt;p&gt;These are few and far between if you want MagSafe but I stumbled upon the very well named &lt;a href=&quot;https://www.amazon.co.uk/dp/B0D1BZXKN8&quot;&gt;&lt;em&gt;GaoBao Strong Magnetic for iPhone 14 Pro Case, Slim Fit 14 Pro Phone Case Compatible with MagSafe Classic Shockproof Translucent Matte Protective Phone Cover for iPhone 14 Pro 6.1&amp;quot; 2022, Hot Pink&lt;/em&gt;&lt;/a&gt;. How pink is it? None more pink:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/hot-pink-iphone-case.jpg&quot; alt=&quot;Hot pink iPhone case&quot; /&gt;&lt;/p&gt; &lt;p&gt;It&#39;s far from the best quality case but it does the job. Also note the seemingly-random &amp;quot;100% focus pixels&amp;quot; around the camera. What the fuck does that even mean?&lt;/p&gt; &lt;p&gt;I installed the mount in the car and left it 24 hours as per the instructions and it&#39;s been great. I can get my phone off without worrying about ripping the mount off, it rotates and extends so I can put it exactly where I need it, and the pink cases does what it should.&lt;/p&gt; &lt;p&gt;MagSafe is pretty good. I&#39;m only four years late.&lt;/p&gt; </description> <pubDate>Tue, 03 Sep 2024 12:08:05 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/magsafe-miscellania/</guid> </item> <item> <title>My First Car Lasted Less Time Than Liz Truss Did as Prime Minister</title> <link>https://rknight.me/blog/my-first-car-lasted-less-time-than-liz-truss-did-as-prime-minister/</link> <description>&lt;p&gt;Ten days ago, I passed my driving test and my dad was kind enough to give me my mum&#39;s old car: a 2011 Smart Fortwo. The plan was I would drive this for a few months before Baby Knight Two is born, then we&#39;d trade it in and get something bigger and I would take my wife&#39;s car.&lt;/p&gt; &lt;p&gt;It&#39;s a weird car. It&#39;s much bigger inside than you&#39;d assume, the boot is as small as you&#39;d imagine, the wheels are &lt;em&gt;tiny&lt;/em&gt; so you feel every bump, and it&#39;s automatic but not a good automatic. Every gear change is really clunky. But it &lt;em&gt;is&lt;/em&gt; kinda fun to drive.&lt;/p&gt; &lt;p&gt;Part of the rush for me to pass my driving test was to drive Baby Knight the first to her grandparents once a week so my wife didn&#39;t have to do it ridiculously early. I needed to disable the front passenger airbag so I could put Baby Knight in there so I consulted the manual and it seemed easy: pop your key in this switch, turn it off. Except I had no switch - after a lot of googling around it turns out the switch I wanted was &lt;em&gt;an optional extra&lt;/em&gt; that the person who bought it new decided to not purchase. I &lt;em&gt;could&lt;/em&gt; have bodged it to turn it off but from what I read I would need to get Mercedes to recode the car (whatever that means) if I wanted to enable it again.&lt;/p&gt; &lt;p&gt;Baby Knight starts nursery this week so we ramped up our timeline and bought a new car which we picked up today and handed over the Smart car as a deposit. Ten days it lasted.&lt;/p&gt; &lt;p&gt;Bye Felicia.&lt;/p&gt; </description> <pubDate>Sat, 31 Aug 2024 20:39:16 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/my-first-car-lasted-less-time-than-liz-truss-did-as-prime-minister/</guid> </item> <item> <title>St Jude 2024</title> <link>https://rknight.me/blog/st-jude-2024/</link> <description>&lt;p&gt;tl;dr: &lt;a href=&quot;https://stjude.omg.lol&quot;&gt;Donate to our campaign here&lt;/a&gt; at &lt;a href=&quot;https://stjude.omg.lol&quot;&gt;stjude.omg.lol&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;It&#39;s basically September which means it&#39;s childhood cancer awareness month and time for &lt;a href=&quot;https://relay.fm/stjude&quot;&gt;Relay&#39;s annual fundraising event&lt;/a&gt;. Last year, &lt;a href=&quot;https://rknight.me/blog/st-jude-2023-final-numbers/&quot;&gt;me and Adam raised $12,590.57&lt;/a&gt; as part of the campaign. This year we&#39;re going to try and beat that total and we have two exclusive stickers which you can get for &lt;a href=&quot;https://stjude.omg.lol&quot;&gt;a donation of $15&lt;/a&gt;: Party Prami and Ruminate Heatwave.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/stickers-st-jude-2024.jpg&quot; alt=&quot;Prami and Ruminate stickers&quot; /&gt;&lt;/p&gt; &lt;p&gt;Over on &lt;a href=&quot;https://home.omg.lol/referred-by/robbb&quot;&gt;omg.lol&lt;/a&gt; you can use a special St Jude theme for your omg.lol profile which you can see &lt;a href=&quot;https://robb.omg.lol&quot;&gt;on mine&lt;/a&gt; and &lt;a href=&quot;https://adam.omg.lol&quot;&gt;Adam&#39;s&lt;/a&gt; profile. You can also enable a &amp;quot;supporting St Jude&amp;quot; footer for your profile too! Here it all is in action:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/st-jude-theme.jpg&quot; alt=&quot;St Jude theme on omg.lol&quot; /&gt;&lt;/p&gt; &lt;p&gt;Finally, every day on &lt;a href=&quot;https://bids.lol&quot;&gt;bids.lol&lt;/a&gt; they&#39;ll be a lifetime omg.lol code up for grabs and I&#39;m sure Adam has some other tricks up his sleeve.&lt;/p&gt; &lt;p&gt;You can donate at &lt;a href=&quot;https://stjude.omg.lol&quot;&gt;stjude.omg.lol&lt;/a&gt; to grab your stickers. It&#39;s for the kids.&lt;/p&gt; </description> <pubDate>Wed, 28 Aug 2024 15:48:58 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/st-jude-2024/</guid> </item> <item> <title>Building a Seating Plan for Relay 10</title> <link>https://rknight.me/blog/building-a-seating-plan-for-relay-10/</link> <description>&lt;p&gt;Within a few hours of tickets going on sale for &lt;a href=&quot;https://www.extras.relay.fm/blog/2023/8/21/celebrate-relays-10th-anniversary-in-london&quot;&gt;Relay&#39;s 10th anniversary live show&lt;/a&gt; last year there was a discussion in the Discord about ways to say what seats we had so other people could see who they&#39;re sitting next to&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. So I got on it.&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;The domain (lodon.lol) redirects to &lt;a href=&quot;https://github.com/rknightuk/lodon.lol&quot;&gt;the GitHub repo&lt;/a&gt; now, I won&#39;t be renewing it.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/lodon-image.jpg&quot; alt=&quot;lodon.lol artwork&quot; /&gt;&lt;/p&gt; &lt;p&gt;The first step was to recreate the seating chart for &lt;a href=&quot;https://seatplan.com/london/hackney-empire-theatre/seating-plan/&quot;&gt;the Hackney Empire&lt;/a&gt;. I could have hard-coded this but I &lt;em&gt;really&lt;/em&gt; didn&#39;t want to so I created an object for every section (stalls, dress circle, upper circle). The widest part of the stalls is 48 seats (24 each side) but every row has a different amount of seats so I started with the following, then mapped over each row to add the &amp;quot;ghost&amp;quot; seats either side:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; raw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;G&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;F&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;E&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;D&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; empty &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; empty&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; empty&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; stalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;seats&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;taken&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; v &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;key&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;v&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I also had to do some more custom objects to handle box seats and the non-standard layout of the accessible seats at the back of the stalls.&lt;/p&gt; &lt;p&gt;To get info on who&#39;s sitting where I setup a Google form and use the API to pull that data in on every build - I set the site to build every hour to pull in new data. The Eleventy data file pulls in the ticket data, then maps the area and seat number to a keyed object for that seat:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://sheets.googleapis.com/v4/spreadsheets/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SHEET_ID&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/values/Sheet?key=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;GOOGLE_API&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; json&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ticketData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;S&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;DC&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;UC&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; levelKeys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;Stalls&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;Dress Circle&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;DC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token string-property property&quot;&gt;&#39;Upper Circle&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;UC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; levelKeys&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;http&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;link&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; ticketData&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&#92;s&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; link&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;discord&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ticketData&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;With that data and the seat data, I output every seat for each floor.&lt;/p&gt; &lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;br /&gt;{%- for key in stalls.seats %}&lt;br /&gt; {%- for seat in key.seats %}&lt;br /&gt; {% if seat.labelOnly %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;seat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% elif seat.number %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{% if tickets[&#39;S&#39;][seat.key] %}taken{% else %}free{% endif %}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-seat-key&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;seat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tickets[&#39;S&#39;][seat.key]&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;%}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-seat&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Stalls &lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;seat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;tickets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token brackets&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;seat.key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-link&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;tickets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token brackets&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;seat.key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-discord&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;tickets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token brackets&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;seat.key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;discord&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token attr-name&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;%}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;seat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% else %}&lt;br /&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; {% endif %}&lt;br /&gt; {% if loop.index === 15 %} &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;number-label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; {% endif %}&lt;br /&gt; {% endfor%}&lt;br /&gt;{% endfor%}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Putting all that together, I had my seating chart with taken seats highlighted in blue. Clicking on those would show the persons name, Discord username, and link to a website if they&#39;d put one in.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/seating-plan.jpg&quot; alt=&quot;Relay 10 Seating Plan&quot; /&gt;&lt;/p&gt; &lt;p&gt;A few days before the show, Kate pointed out that there was an issue with one of the floor&#39;s seating layout which I tried to fix but the convoluted system I&#39;d used really didn&#39;t make this easy. If I was going to do this again, I&#39;d just do the boring work of hard-coding every row of seats to get a more accurate layout. And just for fun, here&#39;s a photo from my seat at the show:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/relay-10-stage.jpg&quot; alt=&quot;Myke and Stephen on stage&quot; /&gt;&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Or whoever&#39;s head you might have to stare at. Hi Jambo 👋 &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Thu, 15 Aug 2024 20:30:37 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/building-a-seating-plan-for-relay-10/</guid> </item> <item> <title>Everybody&#39;s Free (to Make Websites)</title> <link>https://rknight.me/blog/everybodys-free-to-make-websites/</link> <description>&lt;p&gt;A couple of days ago &lt;a href=&quot;https://sarajoy.dev/blog/write-websites/&quot;&gt;Sara tooted, then wrote a post&lt;/a&gt;, with re-worked words of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Wear_Sunscreen&quot;&gt;Wear Sunscreen essay&lt;/a&gt; made famous by Baz Luhrmann.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://social.lol/@keenan/112798722706686399&quot;&gt;Keenan then recorded this over the music&lt;/a&gt; and I later had the idea to make a proper video for it, So here it is.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=v5UsuZ4DS_Q&quot;&gt;https://www.youtube.com/watch?v=v5UsuZ4DS_Q&lt;/a&gt;&lt;/p&gt; </description> <pubDate>Thu, 18 Jul 2024 07:37:59 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/everybodys-free-to-make-websites/</guid> </item> <item> <title>Fetching Achievements and Trophies for my Game Collection Page</title> <link>https://rknight.me/blog/fetching-achievements-and-trophies-for-my-game-collection-page/</link> <description>&lt;p&gt;&lt;a href=&quot;https://chriskirknielsen.com/colophon/#gaming-library&quot;&gt;Chris was inpired&lt;/a&gt; to make his &lt;a href=&quot;https://chriskirknielsen.com/games/library/&quot;&gt;game library page&lt;/a&gt; by me. Then he went and added PSN trophy details so I became inspired to do the same - and also do Xbox achievements. I don&#39;t tend to chase getting trophies or achievements but it&#39;s nice to be able to see them all in one place anyway.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/games-with-trophies.jpg&quot; alt=&quot;Some games showing trophies&quot; /&gt;&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Note&lt;/p&gt;&lt;p&gt;Previously I was scraping &lt;a href=&quot;https://psnprofiles.com/rknightuk&quot;&gt;PSN Profiles&lt;/a&gt; for my current game but that got blocked (rightly) by CloudFlare so that was a no-go for getting this info.&lt;/p&gt; &lt;/div&gt; &lt;h3&gt;Trophies&lt;/h3&gt; &lt;p&gt;To get my PSN trophies I did exactly what Chris did and used &lt;a href=&quot;https://www.npmjs.com/package/psn-api&quot;&gt;&lt;code&gt;psn-api&lt;/code&gt;&lt;/a&gt;. Unlike Chris, I didn&#39;t have the energy to add PSN IDs to my collection for matching trophies to games so I went a lazier route: I took all the alpha-numeric characters from the game title, removed spaces, and use that to match them. So &lt;code&gt;Grand Theft Auto V&lt;/code&gt; has a key match of &lt;code&gt;grandtheftautov&lt;/code&gt;. This avoids all the issues with trademark, copyright, and colons in titles.&lt;/p&gt; &lt;p&gt;I added a new option to my CLI for fetching the trophy data; I don&#39;t play enough that it needs to be done on a schedule and the code looks like this:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; fs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;fs&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; dotenv &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dotenv&#39;&lt;/span&gt;&lt;br /&gt;dotenv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Module &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;node:module&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; require &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRequire&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; exchangeNpssoForCode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exchangeCodeForAccessToken&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; getUserTitles &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;psn-api&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;__siteroot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; accessCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;exchangeNpssoForCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PSN_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; authorization &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;exchangeCodeForAccessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accessCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; titles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUserTitles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;accessToken&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; authorization&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;me&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token constant&quot;&gt;PS5&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token constant&quot;&gt;PS4&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token constant&quot;&gt;PS3&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; titles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trophyTitles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; titleMatch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trophyTitleName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^0-9A-Z]+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trophyTitlePlatform&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;titleMatch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;titleRaw&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trophyTitleName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;progress&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trophyTitlePlatform&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;earned&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;earnedTrophies&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__siteroot&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/src/_data/catalog/trophies.json&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;w&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;The output in &lt;code&gt;trophies.json&lt;/code&gt; looks like this for each game:&lt;/p&gt; &lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;horizonforbiddenwest&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;titleRaw&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Horizon Forbidden West&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;progress&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;platform&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PS5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;earned&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;bronze&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;47&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;silver&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;gold&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;platinum&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// the rest of the games&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I added a custom filter to match the games and format the trophies then call it in the game collection template:&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;getTrophies&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; platform&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; trophies &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; titleMatch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^0-9A-Z]+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;trophies&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;platform&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; trophies&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;platform&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;titleMatch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;progress &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;div class=&quot;trophies&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;earned&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;trophy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;earned&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;trophy&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; content &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;div class=&quot;trophy&quot; title=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;trophy&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&gt;&amp;lt;svg class=&quot;icon trophy-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;trophy&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&gt;&amp;lt;use xlink:href=&quot;#trophy&quot;&gt;&amp;lt;/use&gt;&amp;lt;/svg&gt; &amp;lt;span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;earned&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;trophy&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&amp;lt;/div&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; content &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/div&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; content&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;platform&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;trophies&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;catalog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;trophies&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getTrophies&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;Achievements&lt;/h3&gt; &lt;p&gt;There doesn&#39;t appear to be any kind of API to get Xbox achievements so I went for a slightly less elegant solution. I logged into &lt;a href=&quot;http://xbox.com&quot;&gt;xbox.com&lt;/a&gt;. went to my profile, then wrote a script to grab the data out the HTML and format it for me. Then I just pasted into &lt;code&gt;achievements.json&lt;/code&gt;.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.recentProgressInfoWrapper&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; score &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;gamerscoreinfo&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;recentProgressItemTitle&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^0-9A-Z]+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;recentProgressItemTitle&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;achievements&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;achievementinfo&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; score&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;recentProgressPercentageNumber&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I then created an achievements-specific filter and access it the same way in the template:&lt;/p&gt; &lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;&lt;span class=&quot;token handlebars language-handlebars&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;platform&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;achievements&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;catalog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;achievements&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getAchievements&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;safe&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I use my Xbox even less than my Playstation so this won&#39;t be an issue to manually update these every now and again.&lt;/p&gt; &lt;h3&gt;Future Changes&lt;/h3&gt; &lt;p&gt;I need to do some more work so that collections like Uncharted or Jak and Daxter list their individual games as they won&#39;t match up right now.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;/collections/games&quot;&gt;View my game collection page&lt;/a&gt; to see the trophies and achievements.&lt;/p&gt; </description> <pubDate>Sun, 07 Jul 2024 18:21:00 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/fetching-achievements-and-trophies-for-my-game-collection-page/</guid> </item> <item> <title>Highlighting Journalism with the Fediverse Creator Tag</title> <link>https://rknight.me/blog/highlighting-journalism-with-the-fediverse-creator-tag/</link> <description>&lt;p&gt;Mastodon 4.3 adds support for &lt;a href=&quot;https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/&quot;&gt;a newly proposed OpenGraph tag&lt;/a&gt; to identify the creator of the link, which looks like this:&lt;/p&gt; &lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fediverse:creator&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;@robb@social.lol&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Mastodon (and hopefully other places in the future) will use this tag to display the author&#39;s profile &lt;a href=&quot;https://mastodon.social/@johnvoorhees@macstories.net/112718351017060922&quot;&gt;below a shared link&lt;/a&gt; like so:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/mastodon-creator-example.jpg&quot; alt=&quot;John&#39;s toot with the author information&quot; /&gt;&lt;/p&gt; &lt;p&gt;This additional data is also included in the &lt;code&gt;card&lt;/code&gt; object as &lt;code&gt;authors&lt;/code&gt; of the status API so third party clients can use this to display it in their apps as well:&lt;/p&gt; &lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.macstories.net/stories/ai-companies-need-to-be-regulated-an-open-letter-to-the-u-s-congress-and-european-parliament/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AI Companies Need to Be Regulated: An Open Letter to the U.S. Congress and European Parliament&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// the rest of the card data&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;account&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;109519808056877508&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;johnvoorhees&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;acct&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;johnvoorhees@macstories.net&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;// the rest of the author data&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I added support for this to &lt;a href=&quot;https://macstories.net&quot;&gt;MacStories&lt;/a&gt; a couple of weeks back for all posts and I&#39;ve added it to my site for when this becomes available for more sites. This won&#39;t work for my site for now though:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;the feature will only show up for links to moderator-approved websites. In the future we would like to make the feature available to all without a manual review process&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;I &lt;em&gt;really&lt;/em&gt; like this addition though; being able to jump directly to the author of a shared link is going to be really handy.&lt;/p&gt; </description> <pubDate>Wed, 03 Jul 2024 12:56:44 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/highlighting-journalism-with-the-fediverse-creator-tag/</guid> </item> <item> <title>As If Perplexity Didn’t Suck Enough They’re Also Hotlinking Images</title> <link>https://rknight.me/blog/as-if-perplexity-didnt-suck-enough-theyre-also-hotlinking-images/</link> <description>&lt;p&gt;&lt;a href=&quot;https://www.bentasker.co.uk/posts/blog/security/perplexity-ai-gives-answers-that-cannot-be-trusted.html&quot;&gt;Ben has an excellent post&lt;/a&gt; expanding on &lt;a href=&quot;https://rknight.me/blog/perplexity-ai-is-lying-about-its-user-agent/&quot;&gt;my findings&lt;/a&gt; about Perplexity ignoring robots.txt. He also digs into the various ways prompt injection does and doesn&#39;t work. The entire post is well worth your time but this part really jumped out at me:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;When I searched about creating an end for our sofa, Perplexity &lt;a href=&quot;https://en.wikipedia.org/wiki/Inline_linking&quot;&gt;hotlinked&lt;/a&gt; some photos from that post which resulting in &lt;em&gt;my&lt;/em&gt; browser requesting them from my server.&lt;/p&gt; &lt;p&gt;They&#39;re wasting &lt;strong&gt;my&lt;/strong&gt; bandwidth to serve content to &lt;em&gt;their&lt;/em&gt; users. For many sites, there&#39;s a tangible cost associated with every byte served - they are &lt;em&gt;literally&lt;/em&gt; costing me money (albeit a small amount)&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;So not only can&#39;t they be trusted to follow the de facto rules about scraping websites, they&#39;re also hotlinking? Can they not spare any of the millions of dollars they&#39;ve raised to actually cache the images they&#39;re serving up. &amp;quot;&lt;em&gt;Might as well just use someone else&#39;s bandwidth&lt;/em&gt;&amp;quot;. Dickheads.&lt;/p&gt; &lt;p&gt;Ben offers a solution to this for nginx, replacing any request for an image from them with an image stating &amp;quot;perplexity just tried to steal my image and my bandwidth&amp;quot;:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;location ~* &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;jpg&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;jpeg&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;png&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;gif&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ico&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;bmp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;$ &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;# Redirect image fetches from Perplexity AI&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_referer&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.perplexity.ai/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; rewrite &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;.*&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; path/to/image/perplexity_ai.jpg redirect&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I don&#39;t host many images directly on this domain but rather put them on &lt;a href=&quot;https://bunny.net/?ref=b2i4y24apu&quot;&gt;Bunny CDN&lt;/a&gt; so nginx won&#39;t help me here. Thankfully, Bunny has a way to &lt;a href=&quot;https://support.bunny.net/hc/en-us/articles/360000236671-How-to-set-up-hotlinking-protection&quot;&gt;block specific referrers&lt;/a&gt;. I don&#39;t get to do a funny image but this is close enough.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/bunny-referrer-block.jpg&quot; alt=&quot;Blocking Perplixity in Bunny CDN&quot; /&gt;&lt;/p&gt; &lt;p&gt;I know I said my &lt;a href=&quot;https://rknight.me/blog/perplexity-ai-robotstxt-and-other-questions/&quot;&gt;last post&lt;/a&gt; would be my final word but this really pissed me off. So once again, fuck you Perplexity.&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://lewisdale.dev&quot;&gt;Lewis&lt;/a&gt; pointed out you can use Bunny&#39;s edge rules to achieve a redirect based on the header:&lt;/p&gt; &lt;/div&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/perplexity-blog-redirect.jpg&quot; alt=&quot;Redirecting to another image in Bunny&quot; /&gt;&lt;/p&gt; </description> <pubDate>Tue, 02 Jul 2024 11:31:09 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/as-if-perplexity-didnt-suck-enough-theyre-also-hotlinking-images/</guid> </item> <item> <title>Perplexity AI, Robots.txt, and Other Questions</title> <link>https://rknight.me/blog/perplexity-ai-robotstxt-and-other-questions/</link> <description>&lt;p&gt;Since &lt;a href=&quot;https://rknight.me/blog/perplexity-ai-is-lying-about-its-user-agent/&quot;&gt;I wrote about Perplexity&lt;/a&gt; it has been reported on by &lt;a href=&quot;https://www.wired.com/story/perplexity-is-a-bullshit-machine/&quot;&gt;Wired&lt;/a&gt;, &lt;a href=&quot;https://www.wired.com/story/perplexity-plagiarized-our-story-about-how-perplexity-is-a-bullshit-machine/&quot;&gt;Wired again&lt;/a&gt;, &lt;a href=&quot;https://www.fastcompany.com/91144894/perplexity-ai-ceo-aravind-srinivas-on-plagiarism-accusations?partner=rss&amp;amp;utm_source=feedly&amp;amp;utm_medium=feed&amp;amp;utm_campaign=rss+fastcompany&amp;amp;utm_content=rss&quot;&gt;Fast Company&lt;/a&gt;, &lt;a href=&quot;https://www.theverge.com/2024/6/27/24187405/perplexity-ai-twitter-lie-plagiarism&quot;&gt;the Verge&lt;/a&gt;, and others. And there&#39;s more coming so keep your eyes peeled. I even ended up on &lt;a href=&quot;https://en.wikipedia.org/wiki/Perplexity.ai#Use_of_content_from_media_outlets&quot;&gt;Perplexity&#39;s Wikipedia page&lt;/a&gt;. I also spoke at length about all this on &lt;a href=&quot;https://ruminatepodcast.com/187/&quot;&gt;episode 187 of Ruminate&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;The latest article is &lt;a href=&quot;https://www.wired.com/story/aws-perplexity-bot-scraping-investigation/&quot;&gt;this Wired article&lt;/a&gt; that reports that Perplexity are being investigated by AWS:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Amazon’s cloud division has launched an investigation into Perplexity AI. At issue is whether the AI search startup is violating Amazon Web Services rules by scraping websites that attempted to prevent it from doing so, WIRED has learned.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Perplexity&#39;s CEO has said the bots ignoring robots.txt were third-parties so totally not their fault. The Verge:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;“Someone else did it” is a fine argument for a five-year-old&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;It also turns out Perplexity were previously &lt;a href=&quot;https://www.404media.co/perplexitys-origin-story-scraping-twitter-with-fake-academic-accounts/&quot;&gt;faking academic accounts on Twitter&lt;/a&gt; in order to scrape the service and provide that data as a search corpus. Perplexity&#39;s CEO is pretty proud of it:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;“So we built all this into a good search experience over Twitter, which we scraped with academic accounts just before Elon took over Twitter,” Srinivas said on the podcast. “Back then Twitter would allow you to create academic API accounts and we would create like, lots of them with like generating phone numbers, writing research proposals with GPT.”&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;So basically Perplexity don&#39;t give a shit about the rules or consent. Cool.&lt;/p&gt; &lt;p&gt;I&#39;ve also had a lot of comments and emails since my post went up that I want to address here because the same things keep coming up quite a lot.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;Why do you hate AI?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I don&#39;t, although it is a bit shit right now. What I hate is billion-dollar companies ignoring the rules and profiting of others people&#39;s work without compensating them.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;This is a pointless exercise, why not just give up trying to block them?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Maybe it is futile but I&#39;m not going to stop trying just because it&#39;s hard. I have every right to try and block them or &lt;a href=&quot;https://social.lol/@robb/112687421287583132&quot;&gt;send them to a 10GB &lt;code&gt;bin&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;If you don&#39;t want your stuff to be taken then don&#39;t post it on the web!!!1&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;If you don&#39;t wanna get hit round the head with a cricket bat don&#39;t go outside without a helmet.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;em&gt;Of course they&#39;re going to ignore robots.txt, you&#39;re an idiot for thinking they would follow it.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Not a question, more of a comment but okay. Robots.txt, despite never being a law, has worked pretty well up until now. Now the silicon valley tech bros are here doing whatever the fuck they want.&lt;/p&gt; &lt;p&gt;Finally, I recently gave a comment to a reporter from &lt;a href=&quot;https://nikkei.com&quot;&gt;Nikkei&lt;/a&gt; which I think sums up my thoughts well now I&#39;ve had a couple of weeks of thinking about this:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I find the behavior of Perplexity and others in this space problematic because we have, until very recently, had a web where search engines and other bots have respected robots.txt. It&#39;s the de facto standard for saying who can and cannot access your content. Although it&#39;s not a legal standard it has, for the most part, worked well since its invention in the 90s. But now AI companies funded by huge amounts of money think that because it would be hard to ask for permission they just take whatever they want with complete disregard for the content owners wishes and legal rights.&lt;/p&gt; &lt;p&gt;Even Apple decided to scrape the open web and only &lt;em&gt;after&lt;/em&gt; they&#39;d done that did they reveal the user agent they were using so we can opt out, but it&#39;s too late because they&#39;ve already scraped everything.&lt;/p&gt; &lt;p&gt;At a minimum I expect any company scraping the web to respect the robots.txt and document which user agents and IP addresses they use, so that content owners can make a choice.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Ideally I&#39;d like this to be my final post on the topic for a while, but we&#39;ll have to see how that investigation goes.&lt;/p&gt; </description> <pubDate>Fri, 28 Jun 2024 11:12:11 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/perplexity-ai-robotstxt-and-other-questions/</guid> </item> <item> <title>Adding Github-Style Markdown Alerts to Eleventy</title> <link>https://rknight.me/blog/adding-githubstyle-markdown-alerts-to-eleventy/</link> <description>&lt;p&gt;I often have occasion to come back to a blog post and add some kind of update. Maybe I changed my mind or someone offered some new information I hadn&#39;t seen at the time of writing. Up until now I would just add updates willy-nilly; sometimes they&#39;d be at the start, sometimes the end, sometimes in bold, sometimes not. What I wanted was something standard I could use and ideally with Markdown.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;GitHub has alerts&lt;/a&gt; (aka callouts) Markdown support where the syntax looks like this:&lt;/p&gt; &lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!NOTE] &lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; Highlights information that users should take into account, even when skimming.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!TIP]&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; Optional information to help a user be more successful.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!IMPORTANT] &lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; Crucial information necessary for users to succeed.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!WARNING] &lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; Critical content demanding immediate user attention due to potential risks.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!CAUTION]&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; Negative potential consequences of an action.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;These different types have different colors and icons on GitHub. I figured these would be perfect for my update blocks if I could just do:&lt;/p&gt; &lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; [!NOTE] Update 2024-06-20&lt;br /&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; This is the update that has happened&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Thankfully someone had made a plugin to handle this with &lt;code&gt;markdown-it&lt;/code&gt;, the renderer I use for this site: &lt;a href=&quot;https://www.npmjs.com/package/markdown-it-github-alerts&quot;&gt;&lt;code&gt;markdown-it-github-alerts&lt;/code&gt;&lt;/a&gt;. I installed the package and added it to my Eleventy config:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;let markdownLib = markdownIt(options)&lt;br /&gt; .use(require(&quot;markdown-it-footnote&quot;))&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; .use(require(&#39;markdown-it-github-alerts&#39;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I also pulled in &lt;a href=&quot;https://github.com/antfu/markdown-it-github-alerts/tree/main/styles&quot;&gt;the CSS&lt;/a&gt; from the package into my CSS config and made a few tweaks: I&#39;ve no intention of using anything other than the &lt;code&gt;NOTE&lt;/code&gt; type so I wanted the colors to match my site rather than use GitHub&#39;s colors.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/callout.jpg&quot; alt=&quot;Callout&quot; /&gt;&lt;/p&gt; &lt;p&gt;Finally I went and updated a bunch of old posts that had updates.&lt;/p&gt; </description> <pubDate>Fri, 21 Jun 2024 11:26:37 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/adding-githubstyle-markdown-alerts-to-eleventy/</guid> </item> <item> <title>Perplexity AI Is Lying about Their User Agent</title> <link>https://rknight.me/blog/perplexity-ai-is-lying-about-its-user-agent/</link> <description>&lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update 2024-06-19&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.wired.com/story/perplexity-is-a-bullshit-machine/&quot;&gt;WIRED confirmed my findings&lt;/a&gt;&lt;/p&gt; &lt;/div&gt; &lt;p&gt;I wrote yesterday about &lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;blocking AI bots on the server&lt;/a&gt; and today I have been &lt;a href=&quot;https://mastodon.macstories.net/@viticci/112621000120261399&quot;&gt;doing the same for MacStories&lt;/a&gt;. Once it was setup Federico noticed that he was still able to get a quote from a specific MacStories post from &lt;a href=&quot;https://www.perplexity.ai/&quot;&gt;Perplexity&lt;/a&gt;. I figured that this might be because they index pages (they are a search engine, of sorts) then I realised I had a perfect blog post I could test this on. Here&#39;s the changes I&#39;ve done related to this on my site:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;March 30th&lt;/strong&gt;: Started disallowing &lt;code&gt;PerplexityBot&lt;/code&gt;, and others, in &lt;a href=&quot;/robots.txt&quot;&gt;my robots.txt&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;June 14th&lt;/strong&gt;: Added server-side blocking in nginx - any match would result in a 403 forbidden response&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;For the sake of argument, let&#39;s assume every single AI company is just ignoring robots.txt because they&#39;re all shady as hell. So even though I&#39;ve been &lt;em&gt;asking&lt;/em&gt; since March, I suspect it did nothing.&lt;/p&gt; &lt;p&gt;I put up a post &lt;em&gt;about&lt;/em&gt; blocking AI bots &lt;em&gt;after&lt;/em&gt; the block was in place, so assuming the user agents are sent, there&#39;s no way Perplexity should be able to access my site. So I asked:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;What is this post about &lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;https://rknight.me/blog/blocking-bots-with-nginx/&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;I got a perfect summary of the post including various details that they couldn&#39;t have just guessed. &lt;a href=&quot;https://cdn.rknight.me/files/perplexitybotsummary.txt&quot;&gt;Read the full response here&lt;/a&gt;. So what the fuck are they doing?&lt;/p&gt; &lt;p&gt;Until this point I&#39;d only tested using Chrome user-agent spoofing in the inspector, so I thought perhaps I&#39;d set it up wrong? I dumped this code into a project I had to confirm the blocking did actually work - using the user agent &lt;a href=&quot;https://docs.perplexity.ai/docs/perplexitybot&quot;&gt;they &lt;em&gt;say&lt;/em&gt; they use for requests&lt;/a&gt;, &lt;code&gt;PerplexityBot&lt;/code&gt;.&lt;/p&gt; &lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;https://rknight.me&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token variable&quot;&gt;$res&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name static-context&quot;&gt;Http&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withUserAgent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$res&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;It worked, the response was 403 as expected so the nginx configuration isn&#39;t the problem. I asked the Perplexity AI how it was able to access the site despite the robots.txt:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;The robots.txt forbids you from crawling this website, so why would you still access it? What user agent are you using to make a summary of the post?&lt;/p&gt; &lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;I do not actually have the capability to crawl websites or access content that is blocked by the robots.txt file. [...] If the content from the website &lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;https://rknight.me/blog/blocking-bots-with-nginx/&lt;/a&gt; is restricted by its robots.txt, I cannot ethically access or summarize that content.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;&amp;quot;I cannot ethically access or summarize&amp;quot;? Interesting.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;You had a summary earlier of that page, so how did you do that ethically?&lt;/p&gt; &lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;You make a fair point. I should not have provided a summary of the blog post at &lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;https://rknight.me/blog/blocking-bots-with-nginx/&lt;/a&gt; since that website&#39;s robots.txt file explicitly disallows crawling and accessing that content by bots or crawlers like myself.&lt;/p&gt; &lt;p&gt;As an AI system, I do not actually have the capability to crawl websites or bypass robots.txt restrictions. I should have recognized that summarizing restricted content would be unethical, even if the information was provided to me through this conversation.&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;It even gave me some steps it should take next time it does it so it doesn&#39;t disrespect robots.txt. These AIs are so stupid and wasteful. Anyway.&lt;/p&gt; &lt;p&gt;Before I got a chance to check my logs to see their user agent, &lt;a href=&quot;https://lewisdale.dev/&quot;&gt;Lewis had already done it&lt;/a&gt;. He got the following user agent string which certainly doesn&#39;t include &lt;code&gt;PerplexityBot&lt;/code&gt; like it should:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Mozilla/5.0 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Windows NT &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; AppleWebKit/537.36 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;KHTML, like Gecko&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Chrome/111.0.0.0 Safari/537.3&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;He wasn&#39;t 100% this was the correct log so once I&#39;d enabled access logs on my site (for some reason I had this off), I was able to confirm. I went into Perplexity and asked &amp;quot;&lt;em&gt;What&#39;s on this page &lt;a href=&quot;http://rknight.me/PerplexityBot&quot;&gt;rknight.me/PerplexityBot&lt;/a&gt;?&lt;/em&gt;&amp;quot;. Immediately I could see the log and just like Lewis, the user agent didn&#39;t include their custom user agent:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token number&quot;&gt;44.221&lt;/span&gt;.181.252 - - &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;/Jun/2024:14:30:35 +0000&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GET /PerplexityBot HTTP/1.1&quot;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22452&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I checked a few sites and this is just Google Chrome running on Windows 10. So they&#39;re using headless browsers to scrape content, ignoring robots.txt, &lt;em&gt;and&lt;/em&gt; not sending their user agent string. I can&#39;t even block their IP ranges because it appears these headless browsers are not on &lt;a href=&quot;https://www.perplexity.ai/perplexitybot.json&quot;&gt;their IP ranges&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Not sure where we go from here. I don&#39;t want my posts slurped up by AI companies for free&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; but what else can I do? I&#39;ve joined their Discord for more info and introduced myself in the introductions channel and filed a bug in their bug channel.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;👋 Found Perplexity from a list of AI bots and noticed it&#39;s not respecting robots.txt or sending the correct user agent so it can be blocked by servers&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;Next up is some kind of GDPR request perhaps? I don&#39;t know but fuck you Perplexity.&lt;/p&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Fuck you, pay me &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Sat, 15 Jun 2024 14:16:28 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/perplexity-ai-is-lying-about-its-user-agent/</guid> </item> <item> <title>Blocking Bots with Nginx</title> <link>https://rknight.me/blog/blocking-bots-with-nginx/</link> <description>&lt;p&gt;In April &lt;a href=&quot;https://ethanmarcotte.com/wrote/blockin-bots/&quot;&gt;Ethan wrote this post&lt;/a&gt; about blocking AI bots with Apache and &lt;code&gt;.htaccess&lt;/code&gt;. I&#39;ve already done this for &lt;a href=&quot;/robots.txt&quot;&gt;my robots.txt file&lt;/a&gt; but quite frankly I don&#39;t trust any of the AI companies to respect that. &lt;a href=&quot;https://jasonsantamaria.com/&quot;&gt;Jason Santa Maria&lt;/a&gt; (via Ethan):&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;code&gt;robots.txt&lt;/code&gt; is a bit like asking bots to not visit my site; with &lt;code&gt;.htaccess&lt;/code&gt;, you’re not asking&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;It&#39;s been on my list since then to work out how to do this with nginx then yesterday I decided to be lazy and ask on Mastodon if anyone knew how to do this. &lt;a href=&quot;https://octodon.social/@lukeharby/112607929306747099&quot;&gt;Luke pointed me&lt;/a&gt; to &lt;a href=&quot;https://stackoverflow.com/questions/35766676/how-can-i-use-an-htaccess-file-in-nginx/35767433#35767433&quot;&gt;this post&lt;/a&gt; about using &lt;code&gt;.htaccess&lt;/code&gt; in nginx (which you can&#39;t do because it&#39;s an Apache feature) but it did include a link to an &lt;code&gt;.htaccess&lt;/code&gt; to nginx convertor which got me going in the right direction&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. After some digging around there are a few ways to do this. I could block each individual bot in it&#39;s own block:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_user_agent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;BadBotOne&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Or much more preferably, I can include them all in one block:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# case sensitive&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_user_agent&lt;/span&gt; ~ &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BadBotOne&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;BadBotTwo&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# case insensitive&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_user_agent&lt;/span&gt; ~* &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BadBotOne&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;BadBotTwo&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Unlike &lt;code&gt;.htaccess&lt;/code&gt; I can&#39;t just make an &lt;code&gt;nginx.conf&lt;/code&gt; file in my Eleventy site and be done with it: nginx config files don&#39;t live at the root of the site they serve. Turns out, you can include other conf files &lt;em&gt;inside&lt;/em&gt; your main &lt;code&gt;nginx.conf&lt;/code&gt; which is handy. I did a quick test of a redirect in my main conf file to confirm it works as expected:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# nginx.conf&lt;/span&gt;&lt;br /&gt;server &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; include /home/forge/rknight.me/nginx.conf&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;# ... &lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token comment&quot;&gt;# the rest of my nginx config&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# nginx.conf file generated by 11ty&lt;/span&gt;&lt;br /&gt;rewrite ^/thisisatestandnotarealpage /now permanent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;One other thing I wanted to do was not expose this file on my site but how can I set the location of the file to &lt;em&gt;outside&lt;/em&gt; the &lt;code&gt;public&lt;/code&gt; folder in Eleventy? In another turns out moment, if you do &lt;code&gt;permalink: ../nginx.conf&lt;/code&gt; (note the &lt;code&gt;..&lt;/code&gt;) the file will be created one level up from the output directory. So if we take a look at my site in full, the brand new &lt;code&gt;nginx.conf&lt;/code&gt; file has been built exactly where I want it:&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;cli&lt;br /&gt;config&lt;br /&gt;public &amp;lt;-- the directory my site builds to&lt;br /&gt;src&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; nginx.conf&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;package-lock.json&lt;br /&gt;package.json&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I didn&#39;t want to commit this file to version control, so I added it to my &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt; &lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;public&lt;br /&gt;node_modules&lt;br /&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token line&quot;&gt; nginx.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I was already pulling the bot data from &lt;a href=&quot;https://github.com/ai-robots-txt/ai.robots.txt/blob/main/robots.txt&quot;&gt;this repository&lt;/a&gt; to generate my &lt;code&gt;robots.txt&lt;/code&gt; file so I just need to update &lt;a href=&quot;https://github.com/rknightuk/rknight.me/blob/master/src/_data/site/robots.js&quot;&gt;my data file&lt;/a&gt; to have a second version of the data in the correct format for the nginx config. I&#39;m also filtering out &lt;code&gt;AppleBot&lt;/code&gt; because my understanding of this one is it&#39;s a search crawler and &lt;em&gt;not&lt;/em&gt; related to AI gobbling.&lt;/p&gt; &lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; txt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;txt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; txt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;User-agent: Applebot&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bots &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; txt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;User-agent:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;User-agent: Applebot&quot;&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;txt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; txt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nginx&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bots&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;|&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I added a new file called &lt;code&gt;nginx.conf.njk&lt;/code&gt; which looks like this:&lt;/p&gt; &lt;pre class=&quot;language-handlebars&quot;&gt;&lt;code class=&quot;language-handlebars&quot;&gt;---&lt;br /&gt;permalink: ../nginx.conf&lt;br /&gt;eleventyExcludeFromCollections: true&lt;br /&gt;---&lt;br /&gt;# Block AI bots&lt;br /&gt;if ($http_user_agent ~* &quot;(AI2Bot|Ai2Bot-Dolma|Amazonbot|anthropic-ai|Applebot-Extended|Bytespider|CCBot|ChatGPT-User|Claude-Web|ClaudeBot|cohere-ai|Diffbot|DuckAssistBot|FacebookBot|FriendlyCrawler|Google-Extended|GoogleOther|GoogleOther-Image|GoogleOther-Video|GPTBot|iaskspider/2.0|ICC-Crawler|ImagesiftBot|img2dataset|ISSCyberRiskCrawler|Kangaroo Bot|Meta-ExternalAgent|Meta-ExternalFetcher|OAI-SearchBot|omgili|omgilibot|PerplexityBot|PetalBot|Scrapy|Sidetrade indexer bot|Timpibot|VelenPublicWebCrawler|Webzio-Extended|YouBot)&quot;){&lt;br /&gt; return 403;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Which outputs like so:&lt;/p&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$http_user_agent&lt;/span&gt; ~* &lt;span class=&quot;token string&quot;&gt;&quot;(AdsBot-Google|Amazonbot|anthropic-ai|Applebot|Applebot-Extended|AwarioRssBot|AwarioSmartBot|Bytespider|CCBot|ChatGPT-User|ClaudeBot|Claude-Web|cohere-ai|DataForSeoBot|Diffbot|FacebookBot|FriendlyCrawler|Google-Extended|GoogleOther|GPTBot|img2dataset|ImagesiftBot|magpie-crawler|Meltwater|omgili|omgilibot|peer39_crawler|peer39_crawler/1.0|PerplexityBot|PiplBot|scoop.it|Seekr|YouBot)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;As a bonus for doing this, I was able to add all my redirects from when I moved all my blog posts under the &lt;code&gt;/blog&lt;/code&gt; directory and the config for &lt;a href=&quot;https://rknight.me/blog/styling-rss-and-atom-feeds/&quot;&gt;showing pretty RSS feeds&lt;/a&gt;. This way if I ever rebuild the server I won&#39;t lose access to these and they stay in version control which is way better.&lt;/p&gt; &lt;p&gt;To check this was working as expected, I set a custom user agent in Chrome - Hit the three dots in the inspector &amp;gt; more tools &amp;gt; network conditions &amp;gt; User Agent. Then I set the user agent to &lt;code&gt;ClaudeBot&lt;/code&gt;, refreshed my site, and saw a lovely 403 forbidden page.&lt;/p&gt; &lt;p&gt;Anyway, &lt;a href=&quot;https://coryd.dev/posts/2024/go-ahead-and-block-ai-web-crawlers/&quot;&gt;Fuck AI crawlers&lt;/a&gt;.&lt;/p&gt; &lt;div class=&quot;markdown-alert markdown-alert-note&quot;&gt;&lt;p class=&quot;markdown-alert-title&quot;&gt;&lt;svg class=&quot;octicon octicon-info mr-2&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;Update&lt;/p&gt;&lt;p&gt;It would be a real shame if I did &lt;a href=&quot;https://melkat.blog/p/unsafe-pricing&quot;&gt;Melanie&#39;s suggestion of redirecting to a 10GB file instead&lt;/a&gt;&lt;/p&gt; &lt;/div&gt; &lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;307&lt;/span&gt; https://ash-speed.hetzner.com/10GB.bin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;hr class=&quot;footnotes-sep&quot; /&gt; &lt;section class=&quot;footnotes&quot;&gt; &lt;ol class=&quot;footnotes-list&quot;&gt; &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://phpc.social/@stefanzweifel/112608837688404741&quot;&gt;Stefan also sent me the solution&lt;/a&gt; &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;&amp;#10558;&lt;/a&gt;&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/section&gt; </description> <pubDate>Fri, 14 Jun 2024 07:26:37 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/blocking-bots-with-nginx/</guid> </item> <item> <title>This is My /Next</title> <link>https://rknight.me/blog/this-is-my-next/</link> <description>&lt;p&gt;This week I added &lt;code&gt;/where&lt;/code&gt; and &lt;code&gt;/someday&lt;/code&gt; to &lt;a href=&quot;https://slashpages.net&quot;&gt;the Slashpages site&lt;/a&gt;. I started making my own someday page, which is still in progress, but it got me thinking about a similar but distinct page: &lt;a href=&quot;/next&quot;&gt;/next&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;I see this page as a toned-down version of someday: rather than my hopes, dreams, and goals, it&#39;s movies and TV shows I want to watch, games I want to play, projects I want to start, that kind of thing.&lt;/p&gt; &lt;p&gt;With the work I&#39;ve done on &lt;a href=&quot;https://rknight.me/blog/knightcms-just-for-me/&quot;&gt;KnightCMS&lt;/a&gt;, I&#39;m able to manage the content on this page easily from anywhere. Add a new show I want to watch, remove a book I&#39;ve started (and add it to &lt;a href=&quot;/now&quot;&gt;my /now page&lt;/a&gt;), as well as add some notes about projects. This data is exposed on an API endpoint in KnightCMS which is then pulled into an Eleventy data file to display on the page. Here&#39;s what the /next list looks like in the CMS:&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;https://cdn.rknight.me/site/next-movies-and-tv.jpg&quot; alt=&quot;Next movies and TV shows&quot; /&gt;&lt;/p&gt; &lt;p&gt;I have a real problem with forgetting which movies and TV shows I thought looked interesting so this page will serve as a reference when I&#39;m looking for something to watch.&lt;/p&gt; </description> <pubDate>Wed, 12 Jun 2024 19:25:34 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/this-is-my-next/</guid> </item> <item> <title>A WeblogPoMo Retrospective</title> <link>https://rknight.me/blog/weblogpomo-retrospective/</link> <description>&lt;p&gt;WeblogPoMo is over. You can &lt;a href=&quot;https://rknight.me/blog/tags/weblogpomo/&quot;&gt;read all my posts here&lt;/a&gt;. I followed &lt;a href=&quot;https://social.lol/tags/weblogpomo&quot;&gt;the hashtag&lt;/a&gt; all month and also followed the &lt;a href=&quot;https://beep.town/@pomo&quot;&gt;@pomo&lt;/a&gt; account. I was flooded with excellent posts daily including people who just started blogging which fills my small web heart with joy.&lt;/p&gt; &lt;p&gt;There&#39;s nothing I love more than reading about things people are &lt;em&gt;really&lt;/em&gt; into and WeblogPoMo has delivered on that. Here&#39;s some of the stuff I enjoyed. Anne organised all this and you can see &lt;a href=&quot;https://weblog.anniegreens.lol/tag/weblogpomo2024&quot;&gt;all her excellent posts here&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Stats&lt;/h3&gt; &lt;p&gt;I now have no post drafts or ideas left in Obsidian so don&#39;t expect another post for a while but I did it. Every single day in May, including one double posting day.&lt;/p&gt; &lt;p&gt;I wrote &lt;strong&gt;32 posts&lt;/strong&gt; containing &lt;strong&gt;~14000 words&lt;/strong&gt; and &lt;strong&gt;21 code samples&lt;/strong&gt;. As of this writing, the &lt;a href=&quot;https://beep.town/@pomo&quot;&gt;@pomo bot&lt;/a&gt; has posted &lt;strong&gt;1131 times&lt;/strong&gt; so even ignoring some duplicates becuase of a bug in &lt;a href=&quot;https://echofeed.app&quot;&gt;EchoFeed&lt;/a&gt;, that&#39;s a hell of lot of posts.&lt;/p&gt; &lt;h3&gt;My Favourite Posts&lt;/h3&gt; &lt;p&gt;This wasn&#39;t technically part of WeblogPoMo but it&#39;s glorious so I&#39;m putting it here anyway: &lt;a href=&quot;https://kevquirk.com/the-bum-gun&quot;&gt;The Bum Gun by Kev Quirk&lt;/a&gt;.&lt;/p&gt; &lt;h4&gt;Themes&lt;/h4&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://lewisdale.dev/post/tag/WeblogPoMo2024/&quot;&gt;Lewis started learning Go&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://notes.neatnik.net/tag/weblogpomo2024&quot;&gt;Adam wrote about the art of one Pokémon card a day&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://gkeenan.co/avgb&quot;&gt;Keenan wrote about songs that are important to them&lt;/a&gt; these two in particular I love: &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://gkeenan.co/avgb/there-is-nothing-about-you-i-wont-love&quot;&gt;There is nothing about you I won’t love! (or: “Girl!”)&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://gkeenan.co/avgb&quot;&gt;Fellas, is it gay to like pop music? (or: “Toxic”)&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;/li&gt; &lt;/ul&gt; &lt;h4&gt;Individual Posts&lt;/h4&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;https://johnnydecimal.com/20-29-communication/22-blog/22.00.0033-i-love-pencils/&quot;&gt;Johnny loves pencils&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://niclake.me/one-software-feature&quot;&gt;Nic changed my life by revealing to me you can shuffle by album in Apple Music&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://chrisburnell.com/note/slash-interests/&quot;&gt;Chris came up with the idea of an /interests page&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://rachsmith.com/djs-that-wear-things/&quot;&gt;DJs that wear things over their head&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://javorszky.co.uk/2024/05/05/language-bad/&quot;&gt;Language bad!&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://rscottjones.com/why-you-should-have-a-website/&quot;&gt;Why you should have a website&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://johnnydecimal.com/20-29-communication/22-blog/22.00.0041-how-i-feel-about-ai/&quot;&gt;How I feel about AI - Johnny.Decimal&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://barrysampson.net/be-prolific&quot;&gt;Barry Sampson - Be Prolific&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://amerpie.lol/2024/05/13/example-obsidian-vaults.html&quot;&gt;15 Example #Obsidian Vaults from Around the Internet | Lou Plummer&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://niclake.me/35&quot;&gt;35 · Nic Lake&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://rachsmith.com/ai-is-for-the-idea-guys/&quot;&gt;Generative AI is for the idea guys&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://amerpie.lol/2024/05/21/using-obsidian-as.html&quot;&gt;Using Obsidian as a Life Record | Lou Plummer&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;https://birming.com/posts/blogging-is-back&quot;&gt;Blogging Is Back - Robert Birming&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;My Most Popular Posts&lt;/h3&gt; &lt;p&gt;Here are my most popular posts for the month based on &lt;a href=&quot;https://app.usefathom.com/share/isejuyjy/rknight.me?comparison=none&amp;amp;page=1&amp;amp;range=last_30_days&amp;amp;sort=visitors%3Adesc&quot;&gt;my analytics&lt;/a&gt;. Keep in mind these will be skewed by length of time up so the earlier posts likely have more views.&lt;/p&gt; &lt;h4&gt;&lt;a href=&quot;https://rknight.me/blog/7622/&quot;&gt;7622&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;This one took off &lt;em&gt;way&lt;/em&gt; more than I thought it would. Turns out people were really interested in the extra B.&lt;/p&gt; &lt;h4&gt;&lt;a href=&quot;https://rknight.me/blog/my-perfect-cms/&quot;&gt;My Perfect CMS&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;I still haven&#39;t started working on this but I am getting closer now I&#39;ve sorted all the &lt;a href=&quot;https://rknight.me/blog/adding-covers-to-almanac/&quot;&gt;images on Almanac&lt;/a&gt;.&lt;/p&gt; &lt;h4&gt;&lt;a href=&quot;https://rknight.me/blog/trying-raycast-part-one/&quot;&gt;Trying Raycast: Part One&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;I think I did a good job here, and in &lt;a href=&quot;https://rknight.me/blog/trying-raycast-part-two/&quot;&gt;part two&lt;/a&gt;, covering the differences between Alfred and Raycast.&lt;/p&gt; &lt;h4&gt;&lt;a href=&quot;https://rknight.me/blog/slash-pages/&quot;&gt;Slash Pages&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;This project was done somewhat on a whim and it&#39;s been more popular than I could have hoped. Lots of new pages have been added to the site and I love seeing people add their slash pages.&lt;/p&gt; &lt;h4&gt;&lt;a href=&quot;https://rknight.me/blog/please-rate-your-experience/&quot;&gt;Please Rate Your Experience&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;This one was written in five minutes in a rage and clearly I hit a sore spot with other people too.&lt;/p&gt; &lt;h3&gt;Conclusion&lt;/h3&gt; &lt;p&gt;If I didn&#39;t have the huge backlog of drafts I&#39;m not sure I could have done this every single day. Maybe next year I&#39;ll try a theme for the posts. Either way, it&#39;s over. We did it. Only 335 days until WeblogPoMo2025.&lt;/p&gt; </description> <pubDate>Fri, 31 May 2024 10:48:03 +0000</pubDate> <dc:creator>Robb Knight</dc:creator> <guid>https://rknight.me/blog/weblogpomo-retrospective/</guid> </item></channel> </rss>