<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>Blogccasion</title>
	<subtitle>A look inside the think tank</subtitle>
	<link href="https://blog.tomayac.com/feed/feed.xml" rel="self"/>
	<link href="https://blog.tomayac.com"/>
	<link href="https://ilp.gatehub.net/348218105/eur" rel="monetization"/>
	<updated>2026-01-12T09:21:24Z</updated>
	<id>https://blog.tomayac.com/</id>
	<author>
		<name>Thomas Steiner</name>
		<email>steiner.thomas@gmail.com</email>
	</author>
	
	
	
	
	<entry>
		<title>A polyfill for the HTML switch element</title>
		<link href="https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/"/>
		<updated>2026-01-12T09:21:24Z</updated>
		<id>https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/</id>
		<content type="html">
			&lt;p&gt;In Safari 17.4, the WebKit team at Apple
&lt;a href=&quot;https://webkit.org/blog/15054/an-html-switch-control/&quot;&gt;shipped a native HTML switch element&lt;/a&gt;.
The core idea is that an &lt;code&gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot;&amp;gt;&lt;/code&gt; can progressively be enhanced
to become a switch by adding the &lt;code&gt;switch&lt;/code&gt; attribute. Browsers that don&#39;t support
the &lt;code&gt;switch&lt;/code&gt; attribute will just silently ignore it and render the switch as a
regular checkbox. At the time of this writing, Safari version 17.4 and later is
the only browser to support the new switch element natively. This blog post
introduces a &lt;strong&gt;polyfill&lt;/strong&gt; that brings &lt;em&gt;almost&lt;/em&gt; native support to browsers that
lack it.&lt;/p&gt;
&lt;p&gt;The markup below shows you how you use the switch element. If your browser
doesn&#39;t support the element natively and you view this page on my blog directly
(that is, not in your feed reader), the polyfill should have already kicked in
and you should see two switch controls below the code sample: one regular
switch, and one with a red
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/accent-color&quot;&gt;&lt;code&gt;accent-color&lt;/code&gt;&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;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Toggle me &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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;checked&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;label&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;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;span class=&quot;token selector&quot;&gt;.special&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;accent-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&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 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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Toggle me, I&#39;m special &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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;checked&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;special&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&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;style&gt;
  @keyframes hideBriefly {
    0%,
    100% {
      visibility: hidden;
    }
  }

  label:has(input[switch]),
  input[switch] {
    animation: hideBriefly 2s;
  }

  label {
    font-weight: bold;
    user-select: none;
  }
&lt;/style&gt;
&lt;noscript&gt;
  &lt;style&gt;
    label:has(input[switch]),
    input[switch] {
      animation: none;
    }
  &lt;/style&gt;
&lt;/noscript&gt;
&lt;script type=&quot;module&quot;&gt;
  if (!(&#39;switch&#39; in HTMLInputElement.prototype))
    await import(&#39;/js/input-switch-polyfill.js&#39;);
  else 
    document.head.insertAdjacentHTML(&#39;beforeend&#39;, &#39;&lt;style&gt;label:has(input[switch]),input[switch]{animation:none!important}&lt;/style&gt;&#39;);
&lt;/script&gt;
&lt;label&gt;Toggle me &lt;input type=&quot;checkbox&quot; switch=&quot;&quot; checked=&quot;&quot; /&gt;&lt;/label&gt;
&lt;style&gt;
  .special {
    accent-color: red;
  }
&lt;/style&gt;
&lt;p&gt;&lt;label&gt;Toggle me, I&#39;m special
&lt;input type=&quot;checkbox&quot; switch=&quot;&quot; checked=&quot;&quot; class=&quot;special&quot; /&gt;&lt;/label&gt;&lt;/p&gt;
&lt;h2 id=&quot;accessibility&quot; tabindex=&quot;-1&quot;&gt;Accessibility &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/#accessibility&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a checkbox becomes a switch, the browser automatically applies the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/switch_role&quot;&gt;ARIA &lt;code&gt;switch&lt;/code&gt;&lt;/a&gt;
role. This role is functionally identical to the &lt;code&gt;checkbox&lt;/code&gt; role, except that
instead of representing &amp;quot;checked&amp;quot; and &amp;quot;unchecked&amp;quot; states, which are fairly
generic in meaning, the switch role represents the states &amp;quot;on&amp;quot; and &amp;quot;off&amp;quot;. The
polyfill does this for you. Also another exception is that switches don&#39;t
support an indeterminate/mixed state that checkboxes support.&lt;/p&gt;
&lt;p&gt;When your users have the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-contrast&quot;&gt;&lt;code&gt;prefers-contrast&lt;/code&gt;&lt;/a&gt;
setting enabled to convey that they prefer more contrast, the polyfill adds more
visible borders. Some operating systems like Windows or browsers like Firefox
additionally support a high contrast mode. The polyfill also has support for
that.&lt;/p&gt;
&lt;p&gt;The macOS operating system additionally has an accessibility setting to
&lt;a href=&quot;https://developer.apple.com/help/app-store-connect/manage-app-accessibility/differentiate-without-color-alone-evaluation-criteria/&quot;&gt;Differentiate without color&lt;/a&gt;,
which causes switch controls to get rendered with additional visual on/off
indicators. Since there is currently no direct CSS media query for this specific
preference, I opted to display these indicators whenever a high-contrast
preference is detected, ensuring maximum clarity for those who need it.&lt;/p&gt;
&lt;p&gt;A common accessibility challenge with switches
&lt;a href=&quot;https://www.cs.umd.edu/hcil/trs/90-08/90-08.pdf&quot;&gt;identified in research&lt;/a&gt; (that
predates the HTML switch control) is an uncertainty whether the user should tap
or slide the switch to change its state. The polyfill, like the native
counterpart in Safari, supports both. Another challenge is whether the label
&amp;quot;on&amp;quot; indicates the current state of the switch or the resulting state after
interacting with it. I personally think smartphones—most notably the iPhone—have
taught people how to use switches, but I still recommend you do your own
usability research before adding a switch to your site.&lt;/p&gt;
&lt;h2 id=&quot;internationalization-and-styling&quot; tabindex=&quot;-1&quot;&gt;Internationalization and styling &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/#internationalization-and-styling&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The polyfill supports the various
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/writing-mode&quot;&gt;&lt;code&gt;writing-mode&lt;/code&gt;&lt;/a&gt;
options, like &lt;code&gt;&amp;quot;vertical-lr&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;label style=&quot;writing-mode: vertical-lr&quot;&gt;I&#39;m vertical
&lt;input type=&quot;checkbox&quot; switch=&quot;&quot; checked=&quot;&quot; /&gt;&lt;/label&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s also aware of the directionality of text via the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir&quot;&gt;&lt;code&gt;dir&lt;/code&gt;&lt;/a&gt;
attribute.&lt;/p&gt;
&lt;p&gt;&lt;label dir=&quot;rtl&quot;&gt;I go from right to left
&lt;input type=&quot;checkbox&quot; switch=&quot;&quot; checked=&quot;&quot; /&gt;&lt;/label&gt;&lt;/p&gt;
&lt;h2 id=&quot;status-in-html&quot; tabindex=&quot;-1&quot;&gt;Status in HTML &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/#status-in-html&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The switch element was proposed to be included in HTML in
&lt;a href=&quot;https://github.com/whatwg/html/issues/4180&quot;&gt;Issue #4180&lt;/a&gt; filed in
November 2018. &lt;a href=&quot;https://github.com/whatwg/html/pull/9546&quot;&gt;PR #9546&lt;/a&gt; (opened in
July 2023) proposed a fix and was
&lt;a href=&quot;https://github.com/whatwg/html/pull/9546#pullrequestreview-1584169867&quot;&gt;approved&lt;/a&gt;
by &lt;a href=&quot;https://annevankesteren.nl/&quot;&gt;Anne van Kesteren&lt;/a&gt; in August 2023. At the time
of this writing, the PR to the HTML spec is still open, with concerns from
several stakeholders, including from Google.&lt;/p&gt;
&lt;p&gt;I am not and was not part of the standardization discussion around the element,
I just personally like the progressive enhancement pattern that reminds me of
the pattern used in
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Customizable_select&quot;&gt;customizable &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; elements&lt;/a&gt;
that in the case of non-support just get rendered as regular selects.&lt;/p&gt;
&lt;h2 id=&quot;get-the-polyfill&quot; tabindex=&quot;-1&quot;&gt;Get the polyfill &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/#get-the-polyfill&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can
&lt;a href=&quot;https://www.npmjs.com/package/input-switch-polyfill&quot;&gt;get the polyfill from npm&lt;/a&gt;
and &lt;a href=&quot;https://github.com/tomayac/input-switch-polyfill&quot;&gt;find the code on GitHub&lt;/a&gt;.
The
&lt;a href=&quot;https://github.com/tomayac/input-switch-polyfill/blob/main/README.md&quot;&gt;&lt;code&gt;README&lt;/code&gt;&lt;/a&gt;
has detailed usage instructions that I won&#39;t repeat here, including &lt;strong&gt;important
tips on how to avoid FOUC&lt;/strong&gt; (Flash of Unstyled Content). You can also play with
a &lt;a href=&quot;https://tomayac.github.io/input-switch-polyfill/&quot;&gt;demo&lt;/a&gt; of the polyfill that
shows off more features of the polyfill, like all the various writing modes, and
the different ways to style the switch. And with that: happy switching!&lt;/p&gt;
&lt;h2 id=&quot;thank-you&quot; tabindex=&quot;-1&quot;&gt;Thank you &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/#thank-you&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I would like to wholeheartedly thank
&lt;a href=&quot;https://fed.interfree.ca/@fastfinge&quot;&gt;Samuel Proulx&lt;/a&gt; and
&lt;a href=&quot;https://c.im/@cwilcox808&quot;&gt;Curtis Wilcox&lt;/a&gt; for their accessibility advice and
testing. I&#39;m also grateful to
&lt;a href=&quot;https://mastodon.social/@pepelsbey&quot;&gt;Vadim Makeev&lt;/a&gt;,
&lt;a href=&quot;https://toot.wales/@Lukew&quot;&gt;Luke Warlow&lt;/a&gt;, and
&lt;a href=&quot;https://hachyderm.io/@jyasskin&quot;&gt;Jeffrey Yasskin&lt;/a&gt; for their technical and
non-technical feedback. &lt;a href=&quot;https://piaille.fr/@tbroyer&quot;&gt;Thomas Broyer&lt;/a&gt; has been
crucial for improving support on Firefox.
&lt;a href=&quot;https://front-end.social/@bramus&quot;&gt;Bramus Van Damme&lt;/a&gt; pointed me at Richard
Keizer&#39;s &lt;a href=&quot;https://codepen.io/rakeizer/pen/QQRBoZ&quot;&gt;CodePen&lt;/a&gt; that helped me
bootstrap the CSS foundations of the polyfill. Finally, huge props to
&lt;a href=&quot;https://mastodon.social/@tunetheweb&quot;&gt;Barry Pollard&lt;/a&gt; for the performance tweaks
to avoid FOUC.&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2026%2F01%2F12%2Fa-polyfill-for-the-html-switch-element%2F&amp;dp=%2F2026%2F01%2F12%2Fa-polyfill-for-the-html-switch-element%2F&amp;dt=A%20polyfill%20for%20the%20HTML%20switch%20element&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/&quot;&gt;https://blog.tomayac.com/2026/01/12/a-polyfill-for-the-html-switch-element/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Using the Web Monetization API for fun and profit</title>
		<link href="https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/"/>
		<updated>2025-11-07T22:10:50Z</updated>
		<id>https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/</id>
		<content type="html">
			&lt;p&gt;I recently &lt;a href=&quot;https://jsconfmx.org/speaker/W3Eio&quot;&gt;spoke at JSConf Mexico&lt;/a&gt;, where I
spent a lot of time with the &lt;a href=&quot;https://interledger.org/&quot;&gt;Interledger Foundation&lt;/a&gt;
folks in the hallway track and at the after party events, namely with
&lt;a href=&quot;https://www.linkedin.com/in/ioanachiorean/&quot;&gt;Ioana&lt;/a&gt; (Engineering Manager) and
&lt;a href=&quot;https://www.linkedin.com/in/marianvilla/&quot;&gt;Marian&lt;/a&gt; (DevRel) to talk about
&lt;a href=&quot;https://webmonetization.org/&quot;&gt;Web Monetization&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Web Monetization gives publishers more revenue options and audiences more ways
to sustain the content they love. Support can take many forms: from a one-time
contribution to a continuous, pay-as-you-browse model. It all flows seamlessly
while people engage with the content they love. Publishers earn the moment
someone engages, while audiences contribute in real time, using a balance they
control.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I encourage you all to give it a try! Install the
&lt;a href=&quot;https://chromewebstore.google.com/detail/web-monetization/oiabcfomehhigdepbbclppomkhlknpii&quot;&gt;extension&lt;/a&gt;
that polyfills the proposed Web standard, get a wallet (I went with
&lt;a href=&quot;https://gatehub.net/&quot;&gt;GateHub&lt;/a&gt;, which works in US Dollars and Euros), and then
connect it to the extension.&lt;/p&gt;
&lt;p&gt;You need to have funds in EUR (€) or USD ($). If you have crypto, it won&#39;t work,
which I&#39;ve found out by trial and error, as I was part of
&lt;a href=&quot;https://coil.com/&quot;&gt;Coil&lt;/a&gt;, the Web Monetization predecessor, which paid out in
XRP.&lt;/p&gt;
&lt;p&gt;Just to clarify, while you need a wallet—that typically is used for crypto—the
actual transactions are all in real fiat money, Euro in my case.&lt;/p&gt;
&lt;h2 id=&quot;as-an-extension-user&quot; tabindex=&quot;-1&quot;&gt;As an extension user &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/#as-an-extension-user&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Connect your wallet and browse to a page that supports Web Monetization. You
will notice whether a page is monetized when the extension has a green
checkmark. My blog happens to be monetized.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/web-monetization-extension.png&quot; alt=&quot;The Web Monetization extensions&#39;s popup window.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can adjust how much you want to pay the site per hour and also send one-time
payments. The money is &amp;quot;streamed&amp;quot; every minute, which you can observe in
DevTools.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/web-monetization-post-request.png&quot; alt=&quot;Chrome DevTools Network tab showing a POST request for a payment.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We actually have
&lt;a href=&quot;https://groups.google.com/a/chromium.org/d/msgid/blink-dev/d91487a5-108c-46e7-accd-d44b734a0b34%40igalia.com&quot;&gt;code in Chromium&lt;/a&gt;
to make native Web Monetization happen, implemented by Igalia and funded by the
Interledger Foundation. I hope they can share the experiment results soon.&lt;/p&gt;
&lt;h2 id=&quot;as-a-publisher&quot; tabindex=&quot;-1&quot;&gt;As a publisher &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/#as-a-publisher&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On your page, add a
&lt;a href=&quot;https://webmonetization.org/developers/link-element/&quot;&gt;payment link&lt;/a&gt;. You get
the personalized payment pointer from your wallet. The following snippet shows
mine.&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&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;monetization&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;https://ilp.gatehub.net/348218105/eur&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&#39;re ready to receive payments. Here&#39;s me browsing my blog and seeing
payments go out from and come in to my GateHub wallet. This is of course
effectively a zero sum game, me paying myself. The 0.01 cent are the streamed
payments that go out and then come in again. I tested a one-time payment as
well. The 0.50 cents (not shown) was a successful one-time payment.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/web-monetization-wallet.png&quot; alt=&quot;The GateHub wallet showing incoming and outgoing transactions.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There&#39;s also a
&lt;a href=&quot;https://webmonetization.org/developers/interfaces/&quot;&gt;JavaScript API&lt;/a&gt;, so you can
adjust the content of your page when your page notices that the user is paying.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;monetization&#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;event&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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currency &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amountSent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&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;&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;Browser sent &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;currency&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;value&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 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 punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; linkElem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&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;&lt;span class=&quot;token string&quot;&gt;&#39;for link element:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; linkElem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; linkElem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;For testing purposes, you can observe these &lt;code&gt;monetization&lt;/code&gt; events in Chrome
DevTools by pasting in the snippet above in the Console.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/web-monetization-devtools.png&quot; alt=&quot;Chrome DevTools Console showing a  event.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This way you could, for example, remove ads, or unlock an article when you
notice a one-time payment. On my blog, I just show a &amp;quot;thank you&amp;quot; message for
now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/web-monetization-thank-you.png&quot; alt=&quot;Thank you message in the footer of my blog showing how much the user has paid.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m really bulli$h on this proposed standard. Hopefully someone else will try it
and let me know how it goes. I truly and honestly believe that this could be the
future for making the Web of tomorrow financially sustainable for publishers,
big and small.&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F11%2F07%2Fusing-the-web-monetization-api-for-fun-and-profit%2F&amp;dp=%2F2025%2F11%2F07%2Fusing-the-web-monetization-api-for-fun-and-profit%2F&amp;dt=Using%20the%20Web%20Monetization%20API%20for%20fun%20and%20profit&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/&quot;&gt;https://blog.tomayac.com/2025/11/07/using-the-web-monetization-api-for-fun-and-profit/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Running Node.js in a Hugging Face Space</title>
		<link href="https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/"/>
		<updated>2025-11-03T06:19:54Z</updated>
		<id>https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/</id>
		<content type="html">
			&lt;p&gt;Like many developers, I was bummed when I learned about the
&lt;a href=&quot;https://blog.glitch.com/post/changes-are-coming-to-glitch&quot;&gt;shutdown of Glitch&lt;/a&gt;.
While &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; works great for web apps that
don&#39;t need a server, I struggled with finding a drop-in replacement for hosting
server-based apps, and specifically apps using Node.js. Until I found out about
&lt;a href=&quot;https://huggingface.co/docs/hub/spaces&quot;&gt;Hugging Face Spaces&lt;/a&gt; and that it
supports Docker, which allowed me to create an &lt;strong&gt;evergreen template for running
Node.js in a Hugging Face Space&lt;/strong&gt;.&lt;/p&gt;
&lt;div style=&quot;text-align: center&quot;&gt;
  &lt;img src=&quot;https://blog.tomayac.com/images/huggingface-logo.svg&quot; width=&quot;95&quot; height=&quot;88&quot; alt=&quot;Hugging Face&quot; /&gt;
  &lt;span style=&quot;font-size: 4rem; transform: translateY(-10px); display: inline-block;&quot;&gt;♥️&lt;/span&gt;
  &lt;img src=&quot;https://blog.tomayac.com/images/nodejs-mascot.svg&quot; width=&quot;680&quot; height=&quot;800&quot; style=&quot;height: 88px; width: auto;&quot; alt=&quot;Node.js&quot; /&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;If all you want is a quick way to fire up your own Space-hosted Node.js
server, click
&lt;a href=&quot;https://huggingface.co/spaces/tomayac/nodejs-template?duplicate=true&quot;&gt;Duplicate this Space&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you want to know how the sausage is made or create your own template, read
on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;create-a-hugging-face-space&quot; tabindex=&quot;-1&quot;&gt;Create a Hugging Face Space &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#create-a-hugging-face-space&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This assumes that you have a (free or paid)
&lt;a href=&quot;https://huggingface.co/join&quot;&gt;account on Hugging Face&lt;/a&gt;. Go to your profile and
&lt;a href=&quot;https://huggingface.co/new-space&quot;&gt;create a new Hugging Face Space&lt;/a&gt; using
&lt;strong&gt;Docker&lt;/strong&gt; as the Space SDK. Go for the &lt;strong&gt;Blank&lt;/strong&gt; Docker template. Leave all the
other settings unchanged, so you end up on the free tier. Choose if your Space
should be private or public.&lt;/p&gt;
&lt;h2 id=&quot;an-evergreen-template&quot; tabindex=&quot;-1&quot;&gt;An evergreen template &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#an-evergreen-template&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The objective is to make this template evergreen, so no concrete version numbers
are hardwired. Instead, the idea is to hardwire the version numbers when you
duplicate the template to create a permanent Space.&lt;/p&gt;
&lt;h3 id=&quot;create-a-package-json-file&quot; tabindex=&quot;-1&quot;&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#create-a-package-json-file&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, create the &lt;code&gt;package.json&lt;/code&gt; file that your template should use. Note that
this uses &lt;code&gt;&amp;quot;latest&amp;quot;&lt;/code&gt; as the Express.js version, as the template is meant to stay
evergreen.&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;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;nodejs-template&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;A template for running Node.js in a Hugging Face Space.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;keywords&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;span class=&quot;token string&quot;&gt;&quot;Node&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Node.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hugging Face Space&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 property&quot;&gt;&quot;repository&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;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;git&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;git@hf.co:spaces/tomayac/nodejs-template&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 property&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Apache-2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;Thomas Steiner (tomac@google.com)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;module&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;index.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&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;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;node index.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;span class=&quot;token property&quot;&gt;&quot;dependencies&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;span class=&quot;token property&quot;&gt;&quot;express&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;latest&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;create-a-dockerfile&quot; tabindex=&quot;-1&quot;&gt;Create a &lt;code&gt;Dockerfile&lt;/code&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#create-a-dockerfile&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As the next step, create a &lt;code&gt;Dockerfile&lt;/code&gt; for your template. Again I&#39;m using an
evergreen approach here with a Node.js Docker tag of &lt;code&gt;lts-alpine&lt;/code&gt;, which means I
always get the LTS release of Node.js running on the lightweight Alpine Linux.&lt;/p&gt;
&lt;pre class=&quot;language-docker&quot;&gt;&lt;code class=&quot;language-docker&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Node base image&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; node:lts-alpine&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Switch to the &quot;node&quot; user&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;USER&lt;/span&gt; node&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Set home to the user&#39;s home directory&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENV&lt;/span&gt; HOME=/home/node PATH=/home/node/.local/bin:&lt;span class=&quot;token variable&quot;&gt;$PATH&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Set the working directory to the user&#39;s home directory&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WORKDIR&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$HOME&lt;/span&gt;/app&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Moving file to user&#39;s home directory&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ADD&lt;/span&gt; . &lt;span class=&quot;token variable&quot;&gt;$HOME&lt;/span&gt;/app&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Copy the current directory contents into the container at $HOME/app setting the owner to the user&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; &lt;span class=&quot;token options&quot;&gt;&lt;span class=&quot;token property&quot;&gt;--chown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;node&lt;/span&gt;&lt;/span&gt; . &lt;span class=&quot;token variable&quot;&gt;$HOME&lt;/span&gt;/app&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Loading Dependencies&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;RUN&lt;/span&gt; npm install&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Expose application&#39;s default port&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;EXPOSE&lt;/span&gt; 7860&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Entry Point&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ENTRYPOINT&lt;/span&gt; [&lt;span class=&quot;token string&quot;&gt;&quot;nodejs&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;./index.js&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;create-an-index-js-file&quot; tabindex=&quot;-1&quot;&gt;Create an &lt;code&gt;index.js&lt;/code&gt; file &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#create-an-index-js-file&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Up next, create your default &lt;code&gt;index.js&lt;/code&gt; file that your template should use when
the Node.js server starts. I went with the battle-proven Express.js server
framework. Note that the port needs to be &lt;code&gt;7860&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the smart part: The code dynamically reads out the used Express.js and
Node.js version, so when you duplicate the template, you can hard-wire these
versions. After duplicating the template, in your code, update the highlighted
parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In your &lt;code&gt;Dockerfile&lt;/code&gt;, replace &lt;code&gt;node:&lt;strong&gt;lts&lt;/strong&gt;-alpine&lt;/code&gt;
with, for example, &lt;code&gt;node:&lt;strong&gt;24&lt;/strong&gt;-alpine&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In your &lt;code&gt;package.json&lt;/code&gt; file, replace &lt;code&gt;&amp;quot;express&amp;quot;:
&amp;quot;&lt;strong&gt;latest&lt;/strong&gt;&amp;quot;&lt;/code&gt; with, for example, &lt;code&gt;&amp;quot;express&amp;quot;:
&amp;quot;^&lt;strong&gt;5.1.0&lt;/strong&gt;&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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; express &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;express&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&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 keyword&quot;&gt;const&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7860&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&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 string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&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;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&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;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&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;Running Express.js &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation 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;await&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;&lt;span class=&quot;token string&quot;&gt;&#39;express/package.json&#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 keyword&quot;&gt;with&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 literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;json&#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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;version
    &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; on Node.js &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;version&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;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;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;v&#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;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;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;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;port&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;
  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;&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;Example app listening on port &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;port&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;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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;create-a-reamde-md-file&quot; tabindex=&quot;-1&quot;&gt;Create a &lt;code&gt;REAMDE.md&lt;/code&gt; file &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#create-a-reamde-md-file&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To set some metadata for your template, create a &lt;code&gt;README.md&lt;/code&gt; file with YAML
front matter at the beginning. Hugging Face makes this easy via its Web
interface for the standard parameters, but you can modify
&lt;a href=&quot;https://huggingface.co/docs/hub/spaces-config-reference&quot;&gt;many more parameters&lt;/a&gt;
as per the documentation.&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;license: apache-2.0
title: Node.js template
sdk: docker
emoji: 🐢
colorFrom: green
colorTo: green
short_description: A template for running Node.js in a Hugging Face Space&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;whats-missing&quot; tabindex=&quot;-1&quot;&gt;What&#39;s missing? &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#whats-missing&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While you can edit files individually on Hugging Face&#39;s Space
&lt;a href=&quot;https://huggingface.co/spaces/tomayac/nodejs-template/tree/main&quot;&gt;Files&lt;/a&gt; view
with syntax highlighting and editing support, it&#39;s not a full-blown IDE, but you
can clone your Space with &lt;code&gt;git&lt;/code&gt; and work on it locally (or with an online IDE
like &lt;a href=&quot;https://vscode.dev/&quot;&gt;VS Code&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone git@hf.co:spaces/tomayac/nodejs-template&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;see-it-live-and-bonus&quot; tabindex=&quot;-1&quot;&gt;See it live and bonus &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/#see-it-live-and-bonus&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And this is it really. Now you have a running Node.js app that you can
&lt;a href=&quot;https://huggingface.co/spaces/tomayac/nodejs-template?duplicate=true&quot;&gt;duplicate&lt;/a&gt;
whenever you need to spin up a Node.js server. The best is that this Space runs
in its own main browser context,
&lt;a href=&quot;https://tomayac-nodejs-template.hf.space/&quot;&gt;&lt;code&gt;https://tomayac-nodejs-template.hf.space/&lt;/code&gt;&lt;/a&gt;
in the concrete case, not somewhere in an iframe, which means you can set
headers like
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Opener-Policy&quot;&gt;&lt;code&gt;COOP&lt;/code&gt;&lt;/a&gt;
or
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy&quot;&gt;&lt;code&gt;COEP&lt;/code&gt;&lt;/a&gt;
to get access to powerful features like
&lt;a href=&quot;https://web.dev/articles/why-coop-coep&quot;&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt; and friends&lt;/a&gt;. In
fact, Hugging Face even allows you to set these
&lt;a href=&quot;https://huggingface.co/docs/hub/spaces-config-reference#:~:text=)%20is%20acceptable.-,custom_headers,-%3A%20Dict%5Bstring&quot;&gt;&lt;code&gt;custom_headers&lt;/code&gt;&lt;/a&gt;
by default in the YAML front matter config at the beginning of the &lt;code&gt;README.md&lt;/code&gt;.
Note, though, that adding these headers means your app will only run in
standalone mode, but no longer in the default Space iframed view.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;custom_headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;cross-origin-embedder-policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; require&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;corp
  &lt;span class=&quot;token key atrule&quot;&gt;cross-origin-opener-policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; same&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;origin
  &lt;span class=&quot;token key atrule&quot;&gt;cross-origin-resource-policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cross&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;origin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F11%2F03%2Frunning-nodejs-in-a-hugging-face-space%2F&amp;dp=%2F2025%2F11%2F03%2Frunning-nodejs-in-a-hugging-face-space%2F&amp;dt=Running%20Node.js%20in%20a%20Hugging%20Face%20Space&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/&quot;&gt;https://blog.tomayac.com/2025/11/03/running-nodejs-in-a-hugging-face-space/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Prompt API color sensitivity</title>
		<link href="https://blog.tomayac.com/2025/09/16/prompt-api-color-sensitivity/"/>
		<updated>2025-09-09T16:37:09Z</updated>
		<id>https://blog.tomayac.com/2025/09/16/prompt-api-color-sensitivity/</id>
		<content type="html">
			&lt;p&gt;I was playing with stress-testing the
&lt;a href=&quot;https://developer.chrome.com/docs/ai/prompt-api#multimodal_capabilities&quot;&gt;multimodal capabilities of the Prompt API&lt;/a&gt;
and thought a nice test case might be to have the model read the current time
painted on a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;. As with my
&lt;a href=&quot;https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/#bonus&quot;&gt;last Prompt API exploration&lt;/a&gt;,
I&#39;m again using a response constraint, the &lt;code&gt;HH:mm:ss&lt;/code&gt; regular expression
&lt;code&gt;/^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/&lt;/code&gt;. The prompt is &lt;em&gt;&amp;quot;Read the
time that you can see in this image and print it in HH:mm:ss format.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To my surprise, the model (Gemini Nano in Chrome) seems to be quite
color-sensitive. I found that the model often gets the time wrong in dark mode
when a red font is used to paint on the canvas. (The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/system-color#:~:text=color%20of%20controls.-,Canvas,-Background%20of%20application&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt; CSS system color&lt;/a&gt;
is &lt;code&gt;#121212&lt;/code&gt; in Chrome in dark mode.) I
&lt;a href=&quot;https://webaim.org/resources/contrastchecker/?fcolor=FF0000&amp;amp;bcolor=121212&quot;&gt;checked the contrast&lt;/a&gt;
between CSS &lt;code&gt;#ff0000&lt;/code&gt; (that is, red) and CSS &lt;code&gt;#121212&lt;/code&gt; (that is, black-ish) and
it&#39;s &lt;code&gt;4.68:1&lt;/code&gt;, which for large text passes both WCAG AA and WCAG  AAA.&lt;/p&gt;
&lt;p&gt;Not something really super actionable, other than maybe a heads up to play with
color-preprocessing if the model&#39;s recognition performance is poorer than you
expected.&lt;/p&gt;
&lt;p&gt;Oh, and almost forgot the results of my stress test: on my MacBook Pro 16-inch,
Nov 2024 with an Apple M4 Pro and 48 GB of RAM, the model was able to keep
up with about one complete (but not necessarily correct) prompt response per
second. (Yes, I know that this machine is not what the average user has.)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/canvas-prompt-api.png&quot; alt=&quot;Test case showing the model gets the time wrong in dark mode when a red font is used to paint on the canvas.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can play with the
&lt;a href=&quot;https://tomayac.github.io/blogccasion-demos/canvas-prompt-api/&quot;&gt;demo&lt;/a&gt; embedded
below, or check out the
&lt;a href=&quot;https://github.com/tomayac/blogccasion-demos/tree/main/canvas-prompt-api&quot;&gt;source code&lt;/a&gt;
on GitHub. Toggle between light mode and dark mode and choose red or
&lt;code&gt;CanvasText&lt;/code&gt; as the font color.&lt;/p&gt;
&lt;iframe src=&quot;https://tomayac.github.io/blogccasion-demos/canvas-prompt-api/&quot; allow=&quot;language-model&quot; style=&quot;border: none; width: 100%; height: 600px;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; It&#39;s a lot worse if the canvas background color is pure black
&lt;code&gt;#000000&lt;/code&gt;. I&#39;ve updated the demo to use pure black, and have filed a
&lt;a href=&quot;https://crbug.com/443950694&quot;&gt;Chromium bug&lt;/a&gt;.&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F09%2F16%2Fprompt-api-color-sensitivity%2F&amp;dp=%2F2025%2F09%2F16%2Fprompt-api-color-sensitivity%2F&amp;dt=Prompt%20API%20color%20sensitivity&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/09/16/prompt-api-color-sensitivity/&quot;&gt;https://blog.tomayac.com/2025/09/16/prompt-api-color-sensitivity/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>For all that&#39;s holy, can you just leverage the Web, please?</title>
		<link href="https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/"/>
		<updated>2025-09-03T09:59:24Z</updated>
		<id>https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/</id>
		<content type="html">
			&lt;p&gt;When I moved in with my wife Laura in 2005, we lived in a shared apartment in
Barcelona that had an ancient washing machine that was just there already, no
idea who initially bought it. I managed to break the washing machine door&#39;s
closing mechanism some time in 2006, so for a few weeks, whenever we did the
washing, we had to lean a chair against the door so it wouldn&#39;t open. At the
time, we were both students and living on a small budget.&lt;/p&gt;
&lt;p&gt;Eventually, later in the same year, we bought an Electrolux machine that has
accompanied us ever since. First on our move to Hamburg, then there through
three apartments, and finally back to Spain, where we live now in the Catalonian
countryside. Anyway, the washing machine had a motor damage last week, so after
almost 20 years, it was time for a new one. I ordered it online (another
Electrolux, &lt;em&gt;without&lt;/em&gt; Internet nor WiFi), it was delivered swiftly, and I
installed it hopefully correctly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/electrolux.png&quot; alt=&quot;Our new Electrolux washing machine.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The washing machine came with a voluntary 10 year warranty if you registered it.
The brochure where this offer was announced featured a free telephone number and
a QR code that pointed at the number (in plain text, not making use of the
&lt;code&gt;tel:&lt;/code&gt; protocol). I called the number, and to my &lt;em&gt;absolute surprise&lt;/em&gt; there were
currently more callers than usual. After about 20 minutes, I had an agent on the
phone, but after saying what I wanted, they just hung up on me (or the
connection cut, whatever). Fine, I called again, but now, the call center was
over capacity and they didn&#39;t even let me enter in the wait loop.&lt;/p&gt;
&lt;p&gt;They did offer to send me a link to a chat service on their website via SMS,
though, so I went for that option. The SMS literally pointed me at something
like &lt;code&gt;https://www.&lt;/code&gt; broken up by a space and then &lt;code&gt;example.com/gc/&lt;/code&gt;. When I
clicked the linkified &lt;code&gt;example.com/gc/&lt;/code&gt;, I ended up on a broken site whose
certificate wasn&#39;t trusted. After fixing the link manually and prepending the
&lt;code&gt;https://www.&lt;/code&gt; part, the page didn&#39;t load.&lt;/p&gt;
&lt;p&gt;At this point I was close to giving up, but I had one last card that I wanted to
play: I searched Google for &amp;quot;electrolux warranty register&amp;quot;, and it pointed me at
a site &lt;code&gt;https://www.example.com/mypages/register-a-product/&lt;/code&gt; as the first
result. This looked promising. The &lt;code&gt;mypages&lt;/code&gt; already suggested that this was
gated behind a login, so I created an account, which was painless. (Turns out,
after having an account and being logged in, the chat URL also worked—what an
oversight on their part.) On the page, they had a field where you could enter
the washing machine&#39;s product number from the identification plate on the door
of the washing machine, together with helpful information where to find the
data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/find-pnc-description-electrolux-serialplate.avif&quot; alt=&quot;Annotated Electrolux identification plate.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But even better, they offered a service where you could just upload a picture of
the identification plate, and some AI on their server then extracted the product
number and let you register the product with two clicks. What a fantastic
experience compared to the crappy (and likely for the operator way more
expensive) call center experience.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/electrolux-plate.jpg&quot; alt=&quot;Electrolux identification plate cell phone photo.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Why they didn&#39;t just put this URL on the brochure and the QR code is beyond me.
As the title suggests: &lt;strong&gt;For all that&#39;s holy, can you just leverage the Web,
please?&lt;/strong&gt; Don&#39;t make me talk to people! They could still offer to register the
machine by telephone as an alternative, but in 2025, the default for such things
should just be the Web.&lt;/p&gt;
&lt;h2 id=&quot;bonus&quot; tabindex=&quot;-1&quot;&gt;Bonus &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/#bonus&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since I work on &lt;a href=&quot;https://developer.chrome.com/docs/ai/built-in&quot;&gt;built-in AI&lt;/a&gt; as
my day job in the Chrome team at Google, I could not &lt;em&gt;not&lt;/em&gt; notice this &lt;em&gt;&amp;quot;extract
the product number from this identification plate&amp;quot;&lt;/em&gt; use case for client-side AI.
I coded up a quick
&lt;a href=&quot;https://tomayac.github.io/blogccasion-demos/built-in-ai-product-number-ocr/&quot;&gt;demo&lt;/a&gt;
using the &lt;a href=&quot;https://developer.chrome.com/docs/ai/prompt-api&quot;&gt;Prompt API&lt;/a&gt; embedded
below that shows this in action. Here&#39;s a quick walkthrough of the code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a session with the &lt;code&gt;LanguageModel&lt;/code&gt;, informing the user of download
progress if the model needs to be downloaded, and telling the model about the
to-be-expected inputs (English texts and images) and outputs (English texts).
In the system prompt, I tell the model what its overall task is (identify
product numbers from photos of identification plates).&lt;/li&gt;
&lt;li&gt;Prompt the model using the &lt;code&gt;promptStreaming()&lt;/code&gt; method with a multimodal
prompt, one textual and one image. The Prompt API supports
&lt;a href=&quot;https://developer.chrome.com/docs/ai/structured-output-for-prompt-api?hl=en&quot;&gt;structured output&lt;/a&gt;
in the form of a JSON Schema or regular expression. Product numbers have nine
digits, so I pass the regular expression &lt;code&gt;/&#92;d{9}/&lt;/code&gt; as the
&lt;code&gt;responseConstraint&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Iterate over the chunks of the response. Since I&#39;m just expecting nine
digits, this is probably a bit overkill, but, hey…&lt;/li&gt;
&lt;li&gt;(Not shown) On the server, verify that the recognized product number actually
exist. Companies typically have some sort of verification rules like
checksums, or washing machine product numbers always start with &lt;code&gt;91&lt;/code&gt; or
something. If you know those rules, you can of course make them part of the
&lt;code&gt;responseConstraint&lt;/code&gt;, but you always need to verify untrusted user input
(which the output of an LLM counts as) on the server.&lt;/li&gt;
&lt;/ol&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; session &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; LanguageModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&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;monitor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;m&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;
    m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;downloadprogress&#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;e&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;
      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;&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;Downloaded &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loaded &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&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;%.&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 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 punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;expectedInputs&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 literal-property property&quot;&gt;type&lt;/span&gt;&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 literal-property property&quot;&gt;languages&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 string&quot;&gt;&#39;en&#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 literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;image&#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 literal-property property&quot;&gt;expectedOutputs&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 literal-property property&quot;&gt;type&lt;/span&gt;&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 literal-property property&quot;&gt;languages&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 string&quot;&gt;&#39;en&#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 literal-property property&quot;&gt;initialPrompts&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 literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;system&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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;Your task is to identify product numbers from photos of identification plates.&#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 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 keyword&quot;&gt;const&lt;/span&gt; stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; session&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promptStreaming&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;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;user&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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 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;type&lt;/span&gt;&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 literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&#39;Extract the product number from this identification plate. It has nine digits and appears after the text &quot;Prod.No.&quot;.&#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 literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;image&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&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; image &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 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 literal-property property&quot;&gt;responseConstraint&lt;/span&gt;&lt;span class=&quot;token operator&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;d{9}&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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 keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; chunk &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&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;chunk&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;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://tomayac.github.io/blogccasion-demos/built-in-ai-product-number-ocr/&quot; allow=&quot;language-model&quot; style=&quot;border: none; width: 100%; height: 600px;&quot;&gt;&lt;/iframe&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F09%2F03%2Ffor-all-thats-holy-can-you-just-leverage-the-web-please%2F&amp;dp=%2F2025%2F09%2F03%2Ffor-all-thats-holy-can-you-just-leverage-the-web-please%2F&amp;dt=For%20all%20that&#39;s%20holy%2C%20can%20you%20just%20leverage%20the%20Web%2C%20please%3F&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/&quot;&gt;https://blog.tomayac.com/2025/09/03/for-all-thats-holy-can-you-just-leverage-the-web-please/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>What a diff&#39;rence a semicolon makes</title>
		<link href="https://blog.tomayac.com/2025/07/26/what-a-difference-a-semicolon-makes/"/>
		<updated>2025-07-26T00:32:20Z</updated>
		<id>https://blog.tomayac.com/2025/07/26/what-a-difference-a-semicolon-makes/</id>
		<content type="html">
			&lt;p&gt;The other day, I was hit by a baffling
&lt;code&gt;TypeError: console.log(...) is not a function&lt;/code&gt;. Like, WTF 🤔? Turns out, I was
sloppily adding a quick &lt;code&gt;console.log(&#39;here&#39;)&lt;/code&gt; statement for debugging purposes
(as one does 🙈), which happened to be right before an
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IIFE&quot;&gt;IIFE&lt;/a&gt;. I didn&#39;t put a
&lt;code&gt;;&lt;/code&gt;, as it was a throwaway statement I&#39;d remove after finding the bug, but turns
out that&#39;s the issue. StackOverflow contributor
&lt;a href=&quot;https://stackoverflow.com/users/4642212/sebastian-simon&quot;&gt;Sebastian Simon&lt;/a&gt; had
the &lt;a href=&quot;https://stackoverflow.com/a/31013390&quot;&gt;explanation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&#39;s trying to pass &lt;code&gt;function(){}&lt;/code&gt; as an argument to the return value of
&lt;code&gt;console.log()&lt;/code&gt; which itself is not a function but actually undefined (check
&lt;code&gt;typeof console.log();&lt;/code&gt;). This is because JavaScript interprets this as
&lt;code&gt;console.log()(function(){})&lt;/code&gt;. &lt;code&gt;console.log&lt;/code&gt; however is a function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Minimal repro:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&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;&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;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;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://fedi.jaenis.ch/@andre&quot;&gt;Andre&lt;/a&gt; on Mastodon
&lt;a href=&quot;https://fedi.jaenis.ch/@andre/statuses/01K10C5PY7JBYVXYG8T6J4SP4B&quot;&gt;reminded me&lt;/a&gt;
of &lt;a href=&quot;https://front-end.social/@chriscoyier&quot;&gt;Chris Coyier&lt;/a&gt;&#39;s excellent
&lt;a href=&quot;https://css-tricks.com/web-development-merit-badges/&quot;&gt;Web Development Merit Badges&lt;/a&gt;,
so I&#39;m now proudly wearing mine: &lt;em&gt;&amp;quot;Debugged something for over one hour where
the fix was literally one character&amp;quot;&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/merit-badge-onechar.svg&quot; alt=&quot;Debugged something for over one hour where the fix was literally one character&quot; /&gt;&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F07%2F26%2Fwhat-a-difference-a-semicolon-makes%2F&amp;dp=%2F2025%2F07%2F26%2Fwhat-a-difference-a-semicolon-makes%2F&amp;dt=What%20a%20diff&#39;rence%20a%20semicolon%20makes&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/07/26/what-a-difference-a-semicolon-makes/&quot;&gt;https://blog.tomayac.com/2025/07/26/what-a-difference-a-semicolon-makes/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Setting the COOP and COEP headers on static hosting like GitHub Pages</title>
		<link href="https://blog.tomayac.com/2025/03/08/setting-coop-coep-headers-on-static-hosting-like-github-pages/"/>
		<updated>2025-03-08T20:39:51Z</updated>
		<id>https://blog.tomayac.com/2025/03/08/setting-coop-coep-headers-on-static-hosting-like-github-pages/</id>
		<content type="html">
			&lt;p&gt;Remember the Cross-Origin-Embedder-Policy
(&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy&quot;&gt;COEP&lt;/a&gt;)
and the Cross-Origin-Opener-Policy
(&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy&quot;&gt;COOP&lt;/a&gt;)
headers for making your site
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated&quot;&gt;cross-origin isolated&lt;/a&gt;?
If not, here&#39;s my colleague
&lt;a href=&quot;https://www.linkedin.com/in/agektmr&quot;&gt;Eiji Kitamura&lt;/a&gt;&#39;s article
&lt;a href=&quot;https://web.dev/articles/coop-coep&quot;&gt;Making your website &amp;quot;cross-origin isolated&amp;quot; using COOP and COEP &lt;/a&gt;.
To be effective, they need to be sent as in the example below.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cross-origin-embedder-policy: credentialless
cross-origin-opener-policy: same-origin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cross-origin isolated documents operate with fewer restrictions when using the
following APIs:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer&quot;&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt;&lt;/a&gt;
can be created and sent via a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage&quot;&gt;&lt;code&gt;Window.postMessage()&lt;/code&gt;&lt;/a&gt;
or a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/postMessage&quot;&gt;&lt;code&gt;MessagePort.postMessage()&lt;/code&gt;&lt;/a&gt;
call.
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Performance/now&quot;&gt;&lt;code&gt;Performance.now()&lt;/code&gt;&lt;/a&gt;
offers better precision.
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory&quot;&gt;&lt;code&gt;Performance.measureUserAgentSpecificMemory()&lt;/code&gt;&lt;/a&gt;
can be called.&lt;/p&gt;
&lt;p&gt;Typically, sending non-default HTTP headers like COOP and COEP means controlling
the server so you can configure it to send them. I recently learned that they
are also honored if set through a service worker 🤯! This means you can make
apps on static hosting like on GitHub Pages cross-origin isolated!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blog post by stefnotch:
&lt;a href=&quot;https://dev.to/stefnotch/enabling-coop-coep-without-touching-the-server-2d3n&quot;&gt;Enabling COOP/COEP without touching the server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Library by Guido Zuidhof:
&lt;a href=&quot;https://github.com/gzuidhof/coi-serviceworker&quot;&gt;coi-serviceworker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Demo:
&lt;a href=&quot;https://tomayac.github.io/blogccasion-demos/coi-serviceworker/&quot;&gt;Are we cross-origin isolated?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One example where cross-origin isolating your site is needed is with
&lt;a href=&quot;https://github.com/sqlite/sqlite-wasm/&quot;&gt;SQLite Wasm&lt;/a&gt; when you want to use
persistent storage with the origin private file system virtual file system
called
&lt;a href=&quot;https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep&quot;&gt;OPFS sqlite3_vfs&lt;/a&gt;.
I&#39;m glad to have this coi-serviceworker trick up my sleeve now, and you do, too!&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F03%2F08%2Fsetting-coop-coep-headers-on-static-hosting-like-github-pages%2F&amp;dp=%2F2025%2F03%2F08%2Fsetting-coop-coep-headers-on-static-hosting-like-github-pages%2F&amp;dt=Setting%20the%20COOP%20and%20COEP%20headers%20on%20static%20hosting%20like%20GitHub%20Pages&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/03/08/setting-coop-coep-headers-on-static-hosting-like-github-pages/&quot;&gt;https://blog.tomayac.com/2025/03/08/setting-coop-coep-headers-on-static-hosting-like-github-pages/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Playing with AI inference in Firefox Web extensions</title>
		<link href="https://blog.tomayac.com/2025/02/07/playing-with-ai-inference-in-firefox-web-extensions/"/>
		<updated>2025-02-07T17:15:43Z</updated>
		<id>https://blog.tomayac.com/2025/02/07/playing-with-ai-inference-in-firefox-web-extensions/</id>
		<content type="html">
			&lt;p&gt;Recently, in a blog post titled
&lt;a href=&quot;https://blog.mozilla.org/en/products/firefox/firefox-ai/running-inference-in-web-extensions/&quot;&gt;Running inference in web extensions&lt;/a&gt;,
Mozilla announced a pretty interesting experiment on their blog:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We&#39;ve recently shipped a new
&lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/&quot;&gt;component&lt;/a&gt;
inside of Firefox that leverages
&lt;a href=&quot;https://huggingface.co/docs/transformers.js/index&quot;&gt;Transformers.js&lt;/a&gt; […] and
the underlying &lt;a href=&quot;https://onnxruntime.ai/&quot;&gt;ONNX runtime engine&lt;/a&gt;. This component
lets you run any machine learning model that is compatible with
Transformers.js in the browser, with no server-side calls beyond the initial
download of the models. This means Firefox can run everything on your device
and avoid sending your data to third parties.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They expose this component to Web extensions under the &lt;code&gt;browser.trial.ml&lt;/code&gt;
namespace. Where it gets really juicy is at the detail how models are stored
(emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Model files are stored using IndexedDB and &lt;strong&gt;shared across origins&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Typically when you develop an app with Transformers.js, the model needs to be
cached for each
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Origin&quot;&gt;origin&lt;/a&gt; separately,
so if two apps on different origins end up using the same model, the model needs
to be downloaded and stored redundantly. (Together with
&lt;a href=&quot;https://christianliebel.com/&quot;&gt;Chris&lt;/a&gt; and
&lt;a href=&quot;https://github.com/beaufortfrancois&quot;&gt;François&lt;/a&gt;, I have
&lt;a href=&quot;https://github.com/tomayac/cross-origin-storage/&quot;&gt;thought about this problem&lt;/a&gt;,
too, but that&#39;s not the topic of this blog post.)&lt;/p&gt;
&lt;p&gt;To get a feeling for the platform, I extracted their
&lt;a href=&quot;https://searchfox.org/mozilla-central/source/toolkit/components/ml/docs/extensions-api-example&quot;&gt;example extension&lt;/a&gt;
from the Firefox source tree and put it separately
&lt;a href=&quot;https://github.com/tomayac/firefox-ml-extension&quot;&gt;in a GitHub repository&lt;/a&gt;, so
you can more easily test it on your own.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make sure that the following flags are toggled to &lt;code&gt;true&lt;/code&gt; on the special
&lt;code&gt;about:config&lt;/code&gt; page:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;browser.ml.enable
extensions.ml.enabled&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check out the source code.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone git@github.com:tomayac/firefox-ml-extension.git&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Load the extension as a temporary extension on the &lt;strong&gt;This Nightly&lt;/strong&gt; tab of
the special &lt;code&gt;about:debugging&lt;/code&gt; page. It&#39;s important to actually use
&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly&quot;&gt;Firefox Nightly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--eu7b4fay57d.png&quot; alt=&quot;Special about:debugging page in Firefox Nightly.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After loading the extension, you&#39;re brought to the welcome page, where you
need to grant the ML permission. The permission reads &lt;em&gt;&amp;quot;Example extension
requests additional permissions. It wants to: Download and run AI models on
your device&amp;quot;&lt;/em&gt;. In the &lt;code&gt;manifest.json&lt;/code&gt;, it 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;span class=&quot;token property&quot;&gt;&quot;optional_permissions&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;span class=&quot;token string&quot;&gt;&quot;trialML&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--6y4beuzmiwp.png&quot; alt=&quot;Permission dialog that reads &amp;quot;Example extension requests additional permissions. It wants to: Download and run AI models on your device&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After granting permission, right-click any image on a page, for example,
&lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;. In the context menu, select &lt;strong&gt;✨ Generate
Alt Text&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--p5tcfscpym.png&quot; alt=&quot;Context menu with the &amp;quot;✨ Generate Alt Text&amp;quot; option.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If this was the first time, this triggers the download of the model. On the
JavaScript code side, this is the relevant part:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Initialize the event listener&lt;/span&gt;
browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onProgress&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addListener&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;progressData&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;
  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;progressData&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 comment&quot;&gt;// Create the inference engine. This may trigger model downloads.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createEngine&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;modelHub&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mozilla&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;taskName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;image-to-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;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;You can see the extension display download progress in the lower left corner.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--70ltkwwvhze.png&quot; alt=&quot;Model download progress as an injected overlay on the Unsplash homepage.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the model download is complete, the inference engine is ready to run.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Call the engine.&lt;/span&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; browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runEngine&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;args&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;imageUrl&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;
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;res&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;generated_text&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&#39;s not the most detailed description, but &amp;quot;A computer desk with a monitor,
keyboard, and a plant&amp;quot; definitely isn&#39;t wrong.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--3z49xb3ae7f.png&quot; alt=&quot;Injected overlay with an accurate image description on the Unsplash homepage.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you click &lt;strong&gt;Inspect&lt;/strong&gt; on the extension debugging page, you can play with
the
&lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/extensions.html&quot;&gt;WebExtensions AI APIs&lt;/a&gt;
directly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--2z5827cdx7b.png&quot; alt=&quot;Special about:debugging page with the Inspect button highlighted.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;browser.trial.ml&lt;/code&gt; namespace exposes the following functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;createEngine()&lt;/code&gt;: creates an inference engine.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;runEngine()&lt;/code&gt;: runs an inference engine.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onProgress()&lt;/code&gt;: listener for engine events&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCachedModels()&lt;/code&gt;: delete model(s) files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--j43wjeiu9m.png&quot; alt=&quot;Firefox DevTools window shown inspecting the  namespace.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I played with various tasks, and initially, I had some trouble getting
translation to run, so I hopped on the &lt;code&gt;firefox-ai&lt;/code&gt; channel on the
&lt;a href=&quot;https://discord.gg/Jmmq9mGwy7&quot;&gt;Mozilla AI Discord&lt;/a&gt;, where
&lt;a href=&quot;https://fr.linkedin.com/in/tarekziade&quot;&gt;Tarek Ziade&lt;/a&gt; from the Firefox team
&lt;a href=&quot;https://discord.com/channels/1089876418936180786/1329145280838500475/1336387543490494534&quot;&gt;helped me out&lt;/a&gt;
and also pointed me at &lt;code&gt;about:inference&lt;/code&gt;, another cool special page in
Firefox Nightly where you can manage the installed AI models. If you want to
delete models from JavaScript, it seems like it&#39;s all or nothing, as the
&lt;code&gt;deleteCachedModels()&lt;/code&gt; function doesn&#39;t seem to take an argument. (It also
threw a &lt;code&gt;DOMException&lt;/code&gt; when I tried to run it on Firefox Nightly &lt;code&gt;137.0a1&lt;/code&gt;.)&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Delete all AI models.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;trial&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deleteCachedModels&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--dowi2w6wu1m.png&quot; alt=&quot;Inference manager on about:inference special page with overview of downloaded models.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;about:inference&lt;/code&gt; page also lets you play directly with many AI tasks
supported by Transformers.js and hence Firefox WebExtensions AI APIs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/testingaiinfer--1bso1w4u01n.png&quot; alt=&quot;Inference manager on about:inference special page with options to test the available models.&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Concluding, I think this is a very interesting way of working with AI inference
in the browser. The obvious downside is that you need to convince your users to
download an extension, but the obvious upside is that you possibly can save them
from having to download a model they may already have downloaded and stored on
their disk. When you experiment with AI models a bit, disk space can definitely
become a problem, especially on smaller SSDs, which led me to a
&lt;a href=&quot;https://toot.cafe/@tomayac/113958051687160248&quot;&gt;fun random discovery&lt;/a&gt; the other
day, when I was trying to free up some disk space for Gemini Nano…&lt;/p&gt;
&lt;p&gt;As teased before, Chris, François, and I have some
&lt;a href=&quot;https://github.com/tomayac/cross-origin-storage/&quot;&gt;ideas&lt;/a&gt; around cross-origin
storage in general, but the Firefox WebExtensions AI APIs definitely solve the
problem for AI models. Be sure to read their
&lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/extensions.html&quot;&gt;documentation&lt;/a&gt;
and play with their
&lt;a href=&quot;https://github.com/tomayac/firefox-ml-extension/&quot;&gt;demo extension&lt;/a&gt;! On the
Chrome team, we&#39;re experimenting with
&lt;a href=&quot;https://developer.chrome.com/docs/ai/built-in&quot;&gt;built-in AI APIs in Chrome&lt;/a&gt;.
It&#39;s a very exciting space for sure! Special thanks again to
&lt;a href=&quot;https://fr.linkedin.com/in/tarekziade&quot;&gt;Tarek Ziade&lt;/a&gt; on the
&lt;a href=&quot;https://discord.gg/Jmmq9mGwy7&quot;&gt;Mozilla AI Discord&lt;/a&gt; for his help in getting me
started.&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F02%2F07%2Fplaying-with-ai-inference-in-firefox-web-extensions%2F&amp;dp=%2F2025%2F02%2F07%2Fplaying-with-ai-inference-in-firefox-web-extensions%2F&amp;dt=Playing%20with%20AI%20inference%20in%20Firefox%20Web%20extensions&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/02/07/playing-with-ai-inference-in-firefox-web-extensions/&quot;&gt;https://blog.tomayac.com/2025/02/07/playing-with-ai-inference-in-firefox-web-extensions/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Testing browser-use, a scriptable AI browser agent</title>
		<link href="https://blog.tomayac.com/2025/02/05/testing-browser-use-a-scriptable-ai-browser-agent/"/>
		<updated>2025-02-05T13:56:27Z</updated>
		<id>https://blog.tomayac.com/2025/02/05/testing-browser-use-a-scriptable-ai-browser-agent/</id>
		<content type="html">
			&lt;p&gt;I&#39;m not a big LinkedIn user, but the other day, my Google colleague Franziska
Hinkelmann
&lt;a href=&quot;https://www.linkedin.com/posts/fhinkel_got-low-stakes-repetitive-tasks-in-the-browser-activity-7291114697339068419-rd3R?utm_source=share&amp;amp;utm_medium=member_desktop&quot;&gt;posted something&lt;/a&gt;
about a project called
&lt;a href=&quot;https://github.com/browser-use/browser-use/&quot;&gt;browser-use&lt;/a&gt; that caught my eye:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Got low stakes repetitive tasks in the browser? Playwright + LLMs (Gemini 2.0)
to the rescue! Super easy to make somebody else &lt;em&gt;cough&lt;/em&gt; agents &lt;em&gt;cough&lt;/em&gt; do the
work for you, especially if you have to repeat a task for many rows in a
Google Sheet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After seeing her demo, I went and tried it out myself. Here are the steps that
worked for me on macOS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;code&gt;uv&lt;/code&gt; following their
&lt;a href=&quot;https://docs.astral.sh/uv/getting-started/installation/#standalone-installer&quot;&gt;installation instructions&lt;/a&gt;.
(The usual caveat of first checking the source code before pasting anything
in the Terminal applies.)&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-LsSf&lt;/span&gt; https://astral.sh/uv/install.sh &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;less&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new Python environment and activate it. This is from browser-use&#39;s
&lt;a href=&quot;https://docs.browser-use.com/quickstart&quot;&gt;quickstart&lt;/a&gt; instructions.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;uv venv &lt;span class=&quot;token parameter variable&quot;&gt;--python&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.11&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; .venv/bin/activate&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the dependencies and &lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;uv pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; browser-use
playwright &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file and add your OpenAI API key in the form
&lt;code&gt;OPENAI_API_KEY=abc123&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create an &lt;code&gt;agent.py&lt;/code&gt; file with the source code of your agent. Here&#39;s the one
I tried. As you can see, I&#39;m tasking the agent with the following job: &lt;em&gt;&amp;quot;Go
to &lt;a href=&quot;http://developer.chrome.com/&quot;&gt;developer.chrome.com&lt;/a&gt; and find out what built-in AI APIs Chrome supports&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; langchain_openai &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ChatOpenAI
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; browser_use &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Agent
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; asyncio
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; dotenv &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; load_dotenv
load_dotenv&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;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&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;
    agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        task&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Go to developer.chrome.com and find out what built-in AI APIs Chrome supports.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        llm&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;ChatOpenAI&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4o&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 punctuation&quot;&gt;)&lt;/span&gt;
    result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&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;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

asyncio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;main&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;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The coolest thing is that you can watch the agent do its job in real time and
see the reasoning steps in the command line.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.tomayac.com/images/browser-use.png&quot; alt=&quot;Headless browser window with all UI elements annotated.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s an excerpt of the logs.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;INFO     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;agent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; 🚀 Starting task: Go to developer.chrome.com and &lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; out what built-in AI APIs Chrome supports.
INFO     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;agent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; 📍 Step &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
INFO     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;agent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; 🤷 Eval: Unknown - It&lt;span class=&quot;token string&quot;&gt;&#39;s the starting state.
INFO     [agent] 🧠 Memory: Start searching for built-in AI APIs supported by Chrome on developer.chrome.com.
INFO     [agent] 🎯 Next goal: Navigate to developer.chrome.com
INFO     [agent] 🛠️  Action 1/1: {&quot;go_to_url&quot;:{&quot;url&quot;:&quot;https://developer.chrome.com&quot;}}
INFO     [controller] 🔗  Navigated to https://developer.chrome.com
INFO     [agent] 📍 Step 2
INFO     [agent] 👍 Eval: Success - Navigated to the correct URL.
INFO     [agent] 🧠 Memory: Visited developer.chrome.com. Need to search for information on built-in AI APIs supported by Chrome.
INFO     [agent] 🎯 Next goal: Use search input to find information on AI APIs.
INFO     [agent] 🛠️  Action 1/1: {&quot;click_element&quot;:{&quot;index&quot;:9}}
INFO     [controller] 🖱️  Clicked button with index 9:
INFO     [agent] 📍 Step 3
INFO     [agent] 👍 Eval: Success - The search bar was clicked but no input was entered yet.
INFO     [agent] 🧠 Memory: Need to input search query about AI APIs in Chrome using the search bar.
INFO     [agent] 🎯 Next goal: Enter &#39;&lt;/span&gt;AI APIs&#39; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; the search input to &lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; relevant information.
INFO     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;agent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; 🛠️  Action &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;/1: &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;input_text&quot;&lt;/span&gt;:&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;index&quot;&lt;/span&gt;:4,&lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AI APIs&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;
INFO     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;controller&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; ⌨️  Input AI APIs into index &lt;span class=&quot;token number&quot;&gt;4&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;At the end of the log messages is the agent&#39;s full response to your task,
formatted in Markdown. FWIW, the answer is exactly correct:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chrome supports several built-in AI APIs, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Translator API&lt;/strong&gt; - Available in origin trial for early preview
participants. Use cases include on-demand translation and supporting
multi-language communication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Detector API&lt;/strong&gt; - Available in Chrome origin trial. It helps
detect languages without user input and can label texts for better screen
reader pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Summarizer API&lt;/strong&gt; - Allows for local experimentation to preview program
participants. It can summarize meeting transcripts, articles, and forum
questions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writer and Rewriter APIs&lt;/strong&gt; - Experimental status in early preview
program, used for creating and refining text content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt API&lt;/strong&gt; - Allows natural language requests to Gemini Nano in Chrome,
in an experimental early stage.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Visit &lt;a href=&quot;http://developer.chrome.com/&quot;&gt;developer.chrome.com&lt;/a&gt; for complete details and participation in early
trials.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s pretty wild what this scriptable agent is capable of doing today. Be sure
to check out some of the other
&lt;a href=&quot;https://github.com/browser-use/browser-use?tab=readme-ov-file#demos&quot;&gt;demos&lt;/a&gt; and
also try the browser-use &lt;a href=&quot;https://github.com/browser-use/web-ui&quot;&gt;web-ui&lt;/a&gt;, which
adds a nice UI on top.&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2025%2F02%2F05%2Ftesting-browser-use-a-scriptable-ai-browser-agent%2F&amp;dp=%2F2025%2F02%2F05%2Ftesting-browser-use-a-scriptable-ai-browser-agent%2F&amp;dt=Testing%20browser-use%2C%20a%20scriptable%20AI%20browser%20agent&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2025/02/05/testing-browser-use-a-scriptable-ai-browser-agent/&quot;&gt;https://blog.tomayac.com/2025/02/05/testing-browser-use-a-scriptable-ai-browser-agent/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
	
	
	<entry>
		<title>Eleventy (11ty) year, year-month, and year-month-day indexes</title>
		<link href="https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/"/>
		<updated>2024-11-02T21:52:06Z</updated>
		<id>https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/</id>
		<content type="html">
			&lt;p&gt;I love hackable URLs. A hackable URL is a URL that makes sense to a human
reader, and where the human reader can guess what to change to get to another
page. For example, if you look at the URL of this very blog post,
&lt;a href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/&quot;&gt;&lt;code&gt;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/&lt;/code&gt;&lt;/a&gt;,
what would you expect happens if you hack the URL to any of the following
values?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.tomayac.com/2024/11/02/&quot;&gt;&lt;code&gt;https://blog.tomayac.com/2024/11/02/&lt;/code&gt;&lt;/a&gt; lists all posts that
were published on November 2, 2024.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.tomayac.com/2024/11/&quot;&gt;&lt;code&gt;https://blog.tomayac.com/2024/11/&lt;/code&gt;&lt;/a&gt; lists all posts that were
published in November, 2024.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.tomayac.com/2024/&quot;&gt;&lt;code&gt;https://blog.tomayac.com/2024/&lt;/code&gt;&lt;/a&gt; lists all posts that were published
in 2024.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.tomayac.com/&quot;&gt;&lt;code&gt;https://blog.tomayac.com/&lt;/code&gt;&lt;/a&gt; leads to this blog&#39;s home.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;eleventy-js&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;.eleventy.js&lt;/code&gt; &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#eleventy-js&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have a URL structure that&#39;s similar to mine, feel free to copy the
relevant excerpts quoted in the following snippet from
&lt;a href=&quot;https://github.com/tomayac/blogccasion/blob/main/.eleventy.js&quot;&gt;my &lt;code&gt;.eleventy.js&lt;/code&gt;&lt;/a&gt;
and add them to your &lt;code&gt;.eleventy.js&lt;/code&gt;. The &lt;code&gt;_.chain()&lt;/code&gt; function is from the
&lt;a href=&quot;https://lodash.com/docs/4.17.15#chain&quot;&gt;lodash&lt;/a&gt; library.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Year collection&lt;/span&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;&lt;span class=&quot;token string&quot;&gt;&#39;postsByYear&#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;collection&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAllSorted&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 function&quot;&gt;filter&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;item&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 string&quot;&gt;&#39;tags&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;posts&#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;groupBy&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;post&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; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&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 function&quot;&gt;toPairs&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;reverse&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;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;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 comment&quot;&gt;// Year / Month collection&lt;/span&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;&lt;span class=&quot;token string&quot;&gt;&#39;postsByYearMonth&#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;collection&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAllSorted&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 function&quot;&gt;filter&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;item&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 string&quot;&gt;&#39;tags&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;posts&#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;groupBy&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;post&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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&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 keyword&quot;&gt;const&lt;/span&gt; month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMonth&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;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;padStart&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 string&quot;&gt;&#39;0&#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 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;year&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;month&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;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;toPairs&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;reverse&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;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;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 comment&quot;&gt;// Year / Month / Day collection&lt;/span&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;&lt;span class=&quot;token string&quot;&gt;&#39;postsByYearMonthDay&#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;collection&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAllSorted&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 function&quot;&gt;filter&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;item&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 string&quot;&gt;&#39;tags&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;posts&#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;groupBy&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;post&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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&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 keyword&quot;&gt;const&lt;/span&gt; month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMonth&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;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;padStart&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 string&quot;&gt;&#39;0&#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 keyword&quot;&gt;const&lt;/span&gt; day &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getDate&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 function&quot;&gt;padStart&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 string&quot;&gt;&#39;0&#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 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;year&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;month&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;day&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;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;toPairs&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;reverse&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;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;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 comment&quot;&gt;// Helper filter to format month names&lt;/span&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;monthName&#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;monthNum&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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; date &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;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;monthNum&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 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 keyword&quot;&gt;return&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLocaleString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;en-US&#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;month&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;long&#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 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;// Helper filters for parsing date parts&lt;/span&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;getYear&#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;dateStr&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; dateStr&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;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 punctuation&quot;&gt;;&lt;/span&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;getMonth&#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;dateStr&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; dateStr&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 punctuation&quot;&gt;;&lt;/span&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;getDay&#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;dateStr&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; dateStr&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;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;h2 id=&quot;nunjucks-templates&quot; tabindex=&quot;-1&quot;&gt;Nunjucks templates &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#nunjucks-templates&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Then, in your blog&#39;s root, add three files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;year-index.njk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;year-month-index.njk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;year-month-day-index.njk&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They&#39;re all three pretty similar, but for the sake of completeness, here are all
three.&lt;/p&gt;
&lt;h3 id=&quot;year-index-njk&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;year-index.njk&lt;/code&gt;: &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#year-index-njk&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-nunjucks&quot;&gt;&lt;code class=&quot;language-nunjucks&quot;&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 operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYear&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;size&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 variable&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;year&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;layouts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;home&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;span class=&quot;token variable&quot;&gt;permalink&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;span class=&quot;token variable&quot;&gt;year&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 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 operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;year&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 punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;Archive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearPosts&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYear&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYear&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 variable&quot;&gt;year&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 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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;reverse&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-item{% if post.url == url %} postlist-item-active{% endif %}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&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 operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.url | url }}&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-link&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&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;data&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 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;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;data&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 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 keyword&quot;&gt;else&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token punctuation&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;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;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-date&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.date | htmlDateString }}&quot;&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;span class=&quot;token punctuation&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;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;readableDate&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;year-month-index-njk&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;year-month-index.njk&lt;/code&gt;: &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#year-month-index-njk&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-nunjucks&quot;&gt;&lt;code class=&quot;language-nunjucks&quot;&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 operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYearMonth&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;size&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 variable&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearMonth&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;layouts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;home&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;span class=&quot;token variable&quot;&gt;permalink&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;span class=&quot;token variable&quot;&gt;yearMonth&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 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 operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearMonth&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 operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getMonth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;monthName&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;yearMonth&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 operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getYear&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;Archive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYearMonth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;monthPosts&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYearMonth&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYearMonth&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 variable&quot;&gt;yearMonth&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 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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;monthPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;reverse&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-item{% if post.url == url %} postlist-item-active{% endif %}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&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 operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.url | url }}&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-link&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&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;data&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 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;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;data&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 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 keyword&quot;&gt;else&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token punctuation&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;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;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-date&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.date | htmlDateString }}&quot;&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;span class=&quot;token punctuation&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;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;readableDate&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;year-month-day-index-njk&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;year-month-day-index.njk&lt;/code&gt;: &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#year-month-day-index-njk&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-nunjucks&quot;&gt;&lt;code class=&quot;language-nunjucks&quot;&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 operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYearMonthDay&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;size&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 variable&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearMonthDay&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;layouts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;home&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;span class=&quot;token variable&quot;&gt;permalink&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;span class=&quot;token variable&quot;&gt;yearMonthDay&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 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 operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;yearMonthDay&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 operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getMonth&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;monthName&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;yearMonthDay&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 operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getDay&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;yearMonthDay&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 operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;getYear&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;Archive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;h2&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYearMonthDay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;dayPosts&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;postsByYearMonthDay&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;postedYearMonthDay&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 variable&quot;&gt;yearMonthDay&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 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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;dayPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;reverse&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-item{% if post.url == url %} postlist-item-active{% endif %}&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&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 operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.url | url }}&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-link&quot;&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&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;data&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 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;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;data&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 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 keyword&quot;&gt;else&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token punctuation&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;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;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;code&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postlist-date&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;{{ post.date | htmlDateString }}&quot;&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;span class=&quot;token punctuation&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;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;readableDate&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;li&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;ul&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;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endif&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 operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;endfor&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;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;helped-by-ai&quot; tabindex=&quot;-1&quot;&gt;Helped by AI &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#helped-by-ai&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And here&#39;s my dirty, little secret 🤫: I only actually coded &lt;code&gt;year-index.njk&lt;/code&gt;
myself, and then asked &lt;a href=&quot;https://claude.ai/&quot;&gt;Claude&lt;/a&gt; to code the rest for me.&lt;/p&gt;
&lt;h3 id=&quot;initial-prompt&quot; tabindex=&quot;-1&quot;&gt;Initial prompt &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#initial-prompt&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;I have a blog built with Eleventy. It uses a URL structure
that is https://blog.tomayac.com/$year/$month/$day/$title/.
For example, https://blog.tomayac.com/2024/08/26/my-response-to-the-cma/.

I already have a way to list all posts published in a year by
navigating to https://blog.tomayac.com/$year/. Now I want two
levels deeper and get first https://blog.tomayac.com/$year/$month/,
that is, all posts published in a given month, and
https://blog.tomayac.com/$year/$month/$day/, that is, all posts
published on a given year.

For the year index, this is how I got it to work:

In .eleventy.js:
eleventyConfig.addCollection(&#39;postsByYear&#39;, (collection) =&amp;gt; {
    return _.chain(collection.getAllSorted())
      .filter((item) =&amp;gt; &#39;tags&#39; in item.data &amp;amp;&amp;amp; item.data.tags.includes(&#39;posts&#39;))
      .groupBy((post) =&amp;gt; post.date.getFullYear())
      .toPairs()
      .reverse()
      .value();
  });

And then a Nunjucks file year-index.njk:

---
pagination:
  data: collections.postsByYear
  size: 1
  alias: year
layout: layouts/home.njk
permalink: /{{ year[0] }}/
---
&amp;lt;h2&amp;gt;{{ year[0] }} Archive&amp;lt;/h2&amp;gt;
{% for postedYear, yearPosts in collections.postsByYear %}
  {% if postedYear === year[0] %}
  &amp;lt;ul class=&amp;quot;postlist&amp;quot;&amp;gt;
    {% for post in yearPosts | reverse %}
      &amp;lt;li class=&amp;quot;postlist-item{% if post.url == url %} postlist-item-active{% endif %}&amp;quot;&amp;gt;
        &amp;lt;a href=&amp;quot;{{ post.url | url }}&amp;quot; class=&amp;quot;postlist-link&amp;quot;&amp;gt;{% if post.data.title %}{{ post.data.title }}{% else %}&amp;lt;code&amp;gt;{{ post.url }}&amp;lt;/code&amp;gt;{% endif %}&amp;lt;/a&amp;gt;
        &amp;lt;time class=&amp;quot;postlist-date&amp;quot; datetime=&amp;quot;{{ post.date | htmlDateString }}&amp;quot;&amp;gt;{{ post.date | readableDate }}&amp;lt;/time&amp;gt;
      &amp;lt;/li&amp;gt;
    {% endfor %}
  &amp;lt;/ul&amp;gt;
  {% endif %}
{% endfor %}

Can you create the rest?
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;correcting-prompt&quot; tabindex=&quot;-1&quot;&gt;Correcting prompt &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#correcting-prompt&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It worked on the second attempt. In the first attempt, it invented a &lt;code&gt;split&lt;/code&gt;
Nunjucks filter, so I just told it about the error, and after that it just
worked.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This fails now:
Error: filter not found: split (via Template render error)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;direct-link&quot; href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/#conclusion&quot; aria-hidden=&quot;true&quot;&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There may be more elegant ways to achieve this, but this approach is what worked
for me, and, hey, it all happens on the server at build time, so you, dear
reader, get just the optimized HTML. Happy URL hacking! Oh, and whatever
happened on &lt;a href=&quot;https://blog.tomayac.com/2009/03/03&quot;&gt;March 3, 2009&lt;/a&gt;?&lt;/p&gt;

			&lt;p&gt;
				&lt;img alt=&quot;Thomas Steiner&quot; width=&quot;32&quot; height=&quot;32&quot; src=&quot;https://blog.tomayac.com/feed.php?dl=https%3A%2F%2Fblog.tomayac.com%2F2024%2F11%2F02%2Feleventy-11ty-year-year-month-and-year-month-day-indexes%2F&amp;dp=%2F2024%2F11%2F02%2Feleventy-11ty-year-year-month-and-year-month-day-indexes%2F&amp;dt=Eleventy%20(11ty)%20year%2C%20year-month%2C%20and%20year-month-day%20indexes&quot; alt=&quot;&quot;&gt;
				&lt;br/&gt;This post appeared first on &lt;a href=&quot;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/&quot;&gt;https://blog.tomayac.com/2024/11/02/eleventy-11ty-year-year-month-and-year-month-day-indexes/&lt;/a&gt;.
			&lt;/p&gt;
		</content>
	</entry>
</feed>
